X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fstored%2Facquire.c;h=2aba36809223d54a9cf23ea2b29688d2f05d3eec;hb=36b40d5c7f3ff90565ab73ac75f0dc4f6660ff37;hp=e6ff34b5d7a90f26b90521500cb556b77a301d65;hpb=dbd25d74c7863398d4f7f9179aafc5cfbf2b39a5;p=bacula%2Fbacula diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index e6ff34b5d7..2aba368092 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Bacula® is a registered trademark of John Walker. + Bacula® is a registered trademark of Kern Sibbald. The licensor of Bacula is the Free Software Foundation Europe (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. @@ -38,7 +38,7 @@ /* Forward referenced functions */ static void attach_dcr_to_dev(DCR *dcr); -static bool is_suitable_volume_mounted(DCR *dcr); +static void set_dcr_from_vol(DCR *dcr, VOL_LIST *vol); /********************************************************************* @@ -89,9 +89,9 @@ bool acquire_device_for_read(DCR *dcr) jcr->NumReadVolumes, jcr->CurReadVolume); goto get_out; /* should not happen */ } - bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName)); - bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type)); - dcr->VolCatInfo.Slot = vol->Slot; + set_dcr_from_vol(dcr, vol); + + Dmsg2(100, "Want Vol=%s Slot=%d\n", vol->VolumeName, vol->Slot); /* * If the MediaType requested for this volume is not the @@ -152,8 +152,10 @@ bool acquire_device_for_read(DCR *dcr) Dmsg1(50, "Media Type change. New device %s chosen.\n", dev->print_name()); bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName)); + bstrncpy(dcr->VolCatInfo.VolCatName, vol->VolumeName, sizeof(dcr->VolCatInfo.VolCatName)); bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type)); dcr->VolCatInfo.Slot = vol->Slot; + dcr->VolCatInfo.InChanger = vol->Slot > 0; bstrncpy(dcr->pool_name, store->pool_name, sizeof(dcr->pool_name)); bstrncpy(dcr->pool_type, store->pool_type, sizeof(dcr->pool_type)); } else { @@ -165,6 +167,13 @@ bool acquire_device_for_read(DCR *dcr) } } + dev->clear_unload(); + + if (dev->vol && dev->vol->is_swapping()) { + dev->vol->set_slot(vol->Slot); + Dmsg3(100, "swapping: slot=%d Vol=%s dev=%s\n", dev->vol->get_slot(), + dev->vol->vol_name, dev->print_name()); + } init_device_wait_timers(dcr); @@ -174,10 +183,13 @@ bool acquire_device_for_read(DCR *dcr) /* Volume info is always needed because of VolParts */ - Dmsg0(200, "dir_get_volume_info\n"); + Dmsg1(150, "dir_get_volume_info vol=%s\n", dcr->VolumeName); if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) { + Dmsg2(150, "dir_get_vol_info failed for vol=%s: %s\n", + dcr->VolumeName, jcr->errmsg); Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg); } + dev->set_load(); /* set to load volume */ for ( ;; ) { /* If not polling limit retries */ @@ -192,7 +204,10 @@ bool acquire_device_for_read(DCR *dcr) goto get_out; /* error return */ } - autoload_device(dcr, 0, NULL); + dcr->do_unload(); + dcr->do_swapping(false/*!is_writing*/); + dcr->do_load(false /*!is_writing*/); + set_dcr_from_vol(dcr, vol); /* refresh dcr with desired volume info */ /* * This code ensures that the device is ready for @@ -201,8 +216,10 @@ bool acquire_device_for_read(DCR *dcr) */ Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName); if (dev->open(dcr, OPEN_READ_ONLY) < 0) { - Jmsg3(jcr, M_WARNING, 0, _("Read open device %s Volume \"%s\" failed: ERR=%s\n"), - dev->print_name(), dcr->VolumeName, dev->bstrerror()); + if (!dev->poll) { + Jmsg3(jcr, M_WARNING, 0, _("Read open device %s Volume \"%s\" failed: ERR=%s\n"), + dev->print_name(), dcr->VolumeName, dev->bstrerror()); + } goto default_path; } Dmsg1(50, "opened dev %s OK\n", dev->print_name()); @@ -212,10 +229,12 @@ bool acquire_device_for_read(DCR *dcr) vol_label_status = read_dev_volume_label(dcr); switch (vol_label_status) { case VOL_OK: + Dmsg0(50, "Got correct volume.\n"); ok = true; - memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo)); + dev->VolCatInfo = dcr->VolCatInfo; /* structure assignment */ break; /* got it */ case VOL_IO_ERROR: + Dmsg0(50, "IO Error\n"); /* * Send error message generated by read_dev_volume_label() * only we really had a tape mounted. This supresses superfluous @@ -226,20 +245,21 @@ bool acquire_device_for_read(DCR *dcr) } goto default_path; case VOL_NAME_ERROR: - if (tape_initially_mounted) { - tape_initially_mounted = false; + Dmsg0(50, "Vol name error.\n"); + if (dev->is_volume_to_unload()) { goto default_path; } - /* If polling and got a previous bad name, ignore it */ - if (dev->poll && strcmp(dev->BadVolName, dev->VolHdr.VolumeName) == 0) { - goto default_path; - } else { - bstrncpy(dev->BadVolName, dev->VolHdr.VolumeName, sizeof(dev->BadVolName)); + dev->set_unload(); /* force unload of unwanted tape */ + if (!unload_autochanger(dcr, -1)) { + /* at least free the device so we can re-open with correct volume */ + dev->close(); } + dev->set_load(); /* Fall through */ default: Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg); default_path: + Dmsg0(50, "default path\n"); tape_previously_mounted = true; /* @@ -266,11 +286,12 @@ default_path: if (!dir_ask_sysop_to_mount_volume(dcr, ST_READ)) { goto get_out; /* error return */ } - try_autochanger = true; /* permit using autochanger again */ + try_autochanger = true; /* permit trying the autochanger again */ continue; /* try reading again */ } /* end switch */ break; } /* end for loop */ + if (!ok) { Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s for reading.\n"), dev->print_name()); @@ -286,11 +307,7 @@ default_path: get_out: dev->dlock(); - if (dcr && dcr->reserved_device) { - dev->reserved_device--; - Dmsg2(50, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name()); - dcr->reserved_device = false; - } + dcr->clear_reserved(); /* * Normally we are blocked, but in at least one error case above * we are not blocked because we unsuccessfully tried changing @@ -298,6 +315,8 @@ get_out: */ if (dev->is_blocked()) { dev->dunblock(DEV_LOCKED); + } else { + dev->dunlock(); /* dunblock() unlock the device too */ } Dmsg1(950, "jcr->dcr=%p\n", jcr->dcr); return ok; @@ -315,11 +334,10 @@ get_out: */ DCR *acquire_device_for_append(DCR *dcr) { - bool do_mount = false; - bool release = false; - bool have_vol; - DEVICE * volatile dev = dcr->dev; + DEVICE *dev = dcr->dev; JCR *jcr = dcr->jcr; + bool ok = false; + bool have_vol = false; init_device_wait_timers(dcr); @@ -336,102 +354,35 @@ DCR *acquire_device_for_append(DCR *dcr) goto get_out; } + dev->clear_unload(); + /* * have_vol defines whether or not mount_next_write_volume should * ask the Director again about what Volume to use. */ - have_vol = is_suitable_volume_mounted(dcr); - if (dev->can_append()) { - Dmsg0(100, "device already in append.\n"); + if (dev->can_append() && dcr->is_suitable_volume_mounted() && + strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") != 0) { + Dmsg0(190, "device already in append.\n"); /* - * Device already in append mode - * - * Check if we have the right Volume mounted - * OK if current volume info OK - * OK if next volume matches current volume - * otherwise mount desired volume obtained from - * dir_find_next_appendable_volume - * dev->VolHdr.VolumeName is what is in the drive - * dcr->VolumeName is what we pass into the routines, or - * get back from the subroutines. + * At this point, the correct tape is already mounted, so + * we do not need to do mount_next_write_volume(), unless + * we need to recycle the tape. */ - /* If we do not have a volume, see if we can find one */ - if (!have_vol) { - Dmsg0(100, "call dir_find_next_appendable_volume\n"); - have_vol = dir_find_next_appendable_volume(dcr); - dev = dcr->dev; - Dmsg2(100, "devVol=%s dcrVol=%s\n", dev->VolHdr.VolumeName, dcr->VolumeName); - } - if (have_vol) { - do_mount = true; - /* Make sure it is what we we have on the drive */ - if (dev->VolHdr.VolumeName[0]) { - Dmsg2(100, "devVol=%s dcrVol=%s\n", dev->VolHdr.VolumeName, dcr->VolumeName); - /* If we already have the volume, mount/release are not needed */ - do_mount = strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) != 0; - if (do_mount) { - release = true; - Dmsg0(100, "Set release\n"); - } - } - } - if (have_vol && !do_mount) { - /* - * At this point, the correct tape is already mounted, so - * we do not need to do mount_next_write_volume(), unless - * we need to recycle the tape. - */ - Dmsg2(100, "devVol=%s dcrVol=%s\n", dev->VolHdr.VolumeName, dcr->VolumeName); - do_mount = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0; - Dmsg2(190, "jid=%u Correct tape mounted. recycle=%d\n", - (uint32_t)jcr->JobId, do_mount); - if (dev->num_writers == 0) { - memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo)); - } - - /* - * Insanity check - * - * Check to see if the tape position as defined by the OS is - * the same as our concept. If it is not, we bail out, because - * it means the user has probably manually rewound the tape. - * Note, we check only if num_writers == 0, but this code will - * also work fine for any number of writers. If num_writers > 0, - * we probably should cancel all jobs using this device, or - * perhaps even abort the SD, or at a minimum, mark the tape - * in error. Another strategy with num_writers == 0, would be - * to rewind the tape and do a new eod() request. - */ - if (dev->is_tape() && dev->num_writers == 0) { - int32_t file = dev->get_os_tape_file(); - if (file >= 0 && file != (int32_t)dev->get_file()) { - Jmsg(jcr, M_FATAL, 0, _("Invalid tape position on volume \"%s\"" - " on device %s. Expected %d, got %d\n"), - dev->VolHdr.VolumeName, dev->print_name(), dev->get_file(), file); - goto get_out; - } - } - } - } else { - /* Not already in append mode, so mount the device */ - Dmsg2(190, "jid=%u Not in append mode, try mount have_vol=%d\n", - (uint32_t)jcr->JobId, have_vol); - - ASSERT(dev->num_writers == 0); - do_mount = true; + if (dev->num_writers == 0) { + memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo)); + } + have_vol = dcr->is_tape_position_ok(); } - if (do_mount || !have_vol) { + if (!have_vol) { Dmsg1(190, "jid=%u Do mount_next_write_vol\n", (uint32_t)jcr->JobId); - Dmsg2(100, "devVol=%s dcrVol=%s\n", dev->VolHdr.VolumeName, dcr->VolumeName); - bool mounted = mount_next_write_volume(dcr, have_vol, release); - if (!mounted) { + if (!dcr->mount_next_write_volume()) { if (!job_canceled(jcr)) { /* Reduce "noise" -- don't print if job canceled */ Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"), dev->print_name()); - Dmsg2(200, "jid=%u Could not ready device %s for append.\n", - (uint32_t)jcr->JobId, dev->print_name()); + Dmsg1(200, "Could not ready device %s for append.\n", + dev->print_name()); } goto get_out; } @@ -444,42 +395,13 @@ DCR *acquire_device_for_append(DCR *dcr) } dev->VolCatInfo.VolCatJobs++; /* increment number of jobs on vol */ dir_update_volume_info(dcr, false, false); /* send Volume info to Director */ - dev->dlock(); - if (dcr->reserved_device) { - dev->reserved_device--; - Dmsg3(100, "jid=%u Dec reserve=%d dev=%s\n", (uint32_t)jcr->JobId, - dev->reserved_device, dev->print_name()); - dcr->reserved_device = false; - } - dev->dunblock(DEV_LOCKED); - return dcr; + ok = true; -/* - * Error return - */ get_out: dev->dlock(); - if (dcr->reserved_device) { - dev->reserved_device--; - Dmsg3(100, "jid=%u Dec reserve=%d dev=%s\n", (uint32_t)jcr->JobId, - dev->reserved_device, dev->print_name()); - dcr->reserved_device = false; - } + dcr->clear_reserved(); dev->dunblock(DEV_LOCKED); - return NULL; -} - - -static bool is_suitable_volume_mounted(DCR *dcr) -{ - DEVICE *dev = dcr->dev; - - /* Volume mounted? */ - if (dev->VolHdr.VolumeName[0] == 0) { - return false; /* no */ - } - bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName)); - return dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE); + return ok ? dcr : NULL; } /* @@ -495,19 +417,17 @@ bool release_device(DCR *dcr) JCR *jcr = dcr->jcr; DEVICE *dev = dcr->dev; bool ok = true; + char tbuf[100]; /* lock only if not already locked by this thread */ if (!dcr->is_dev_locked()) { dev->r_dlock(); } + lock_volumes(); Dmsg2(100, "release_device device %s is %s\n", dev->print_name(), dev->is_tape()?"tape":"disk"); /* if device is reserved, job never started, so release the reserve here */ - if (dcr->reserved_device) { - dev->reserved_device--; - Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name()); - dcr->reserved_device = false; - } + dcr->clear_reserved(); if (dev->can_read()) { dev->clear_read(); /* clear read bit */ @@ -525,22 +445,26 @@ bool release_device(DCR *dcr) dev->num_writers--; Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers); if (dev->is_labeled()) { - Dmsg0(100, "dir_create_jobmedia_record. Release\n"); + Dmsg2(200, "dir_create_jobmedia. Release vol=%s dev=%s\n", + dev->VolCatInfo.VolCatName, dev->print_name()); if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) { Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), dcr->VolCatInfo.VolCatName, jcr->Job); } - /* If no more writers, write an EOF */ + /* If no more writers, and no errors, and wrote something, write an EOF */ if (!dev->num_writers && dev->can_write() && dev->block_num > 0) { dev->weof(1); write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName); - volume_unused(dcr); } if (!dev->at_weot()) { dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */ /* Note! do volume update before close, which zaps VolCatInfo */ - Dmsg0(100, "dir_update_vol_info. Release0\n"); dir_update_volume_info(dcr, false, false); /* send Volume info to Director */ + Dmsg2(200, "dir_update_vol_info. Release vol=%s dev=%s\n", + dev->VolCatInfo.VolCatName, dev->print_name()); + } + if (dev->num_writers == 0) { /* if not being used */ + volume_unused(dcr); /* we obviously are not using the volume */ } } @@ -552,6 +476,11 @@ bool release_device(DCR *dcr) */ volume_unused(dcr); } + unlock_volumes(); + Dmsg3(100, "%d writers, %d reserve, dev=%s\n", dev->num_writers, dev->num_reserved(), + dev->print_name()); + debug_list_volumes("acquire:release_device()"); + /* If no writers, close if file or !CAP_ALWAYS_OPEN */ if (dev->num_writers == 0 && (!dev->is_tape() || !dev->has_cap(CAP_ALWAYSOPEN))) { @@ -586,7 +515,8 @@ bool release_device(DCR *dcr) free_pool_memory(alert); } pthread_cond_broadcast(&dev->wait_next_vol); - Dmsg1(100, "JobId=%u broadcast wait_device_release\n", (uint32_t)jcr->JobId); + Dmsg2(100, "JobId=%u broadcast wait_device_release at %s\n", + (uint32_t)jcr->JobId, bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL))); pthread_cond_broadcast(&wait_device_release); dev->dunlock(); if (dcr->keep_dcr) { @@ -700,7 +630,7 @@ static void attach_dcr_to_dev(DCR *dcr) JCR *jcr = dcr->jcr; if (jcr) Dmsg1(500, "JobId=%u enter attach_dcr_to_dev\n", (uint32_t)jcr->JobId); - if (!dcr->attached_to_dev && dev->initiated && jcr && jcr->JobType != JT_SYSTEM) { + if (!dcr->attached_to_dev && dev->initiated && jcr && jcr->get_JobType() != JT_SYSTEM) { dev->attached_dcrs->append(dcr); /* attach dcr to device */ dcr->attached_to_dev = true; Dmsg1(500, "JobId=%u attach_dcr_to_dev\n", (uint32_t)jcr->JobId); @@ -710,12 +640,12 @@ static void attach_dcr_to_dev(DCR *dcr) void detach_dcr_from_dev(DCR *dcr) { DEVICE *dev = dcr->dev; - Dmsg1(500, "JobId=%u enter detach_dcr_from_dev\n", (uint32_t)dcr->jcr->JobId); + Dmsg0(500, "Enter detach_dcr_from_dev\n"); /* jcr is NULL in some cases */ /* Detach this dcr only if attached */ if (dcr->attached_to_dev && dev) { dev->dlock(); - unreserve_device(dcr); + dcr->unreserve_device(); dcr->dev->attached_dcrs->remove(dcr); /* detach dcr from device */ dcr->attached_to_dev = false; // remove_dcr_from_dcrs(dcr); /* remove dcr from jcr list */ @@ -744,3 +674,16 @@ void free_dcr(DCR *dcr) } free(dcr); } + +static void set_dcr_from_vol(DCR *dcr, VOL_LIST *vol) +{ + /* + * Note, if we want to be able to work from a .bsr file only + * for disaster recovery, we must "simulate" reading the catalog + */ + bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName)); + bstrncpy(dcr->VolCatInfo.VolCatName, vol->VolumeName, sizeof(dcr->VolCatInfo.VolCatName)); + bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type)); + dcr->VolCatInfo.Slot = vol->Slot; + dcr->VolCatInfo.InChanger = vol->Slot > 0; +}