]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/acquire.c
kes Define a machine dependent ioctl request type for use with
[bacula/bacula] / bacula / src / stored / acquire.c
index 58ed74db62c0d7486f2ed562f21952065fc5b996..2aba36809223d54a9cf23ea2b29688d2f05d3eec 100644 (file)
@@ -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_tape_position_ok(JCR *jcr, DEVICE *dev);
+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;
@@ -317,6 +336,8 @@ DCR *acquire_device_for_append(DCR *dcr)
 {
    DEVICE *dev = dcr->dev;
    JCR *jcr = dcr->jcr;
+   bool ok = false;
+   bool have_vol = false;
 
    init_device_wait_timers(dcr);
 
@@ -333,6 +354,8 @@ 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.
@@ -348,18 +371,18 @@ DCR *acquire_device_for_append(DCR *dcr)
        if (dev->num_writers == 0) {
           memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
        }
-       if (!is_tape_position_ok(jcr, dev)) {
-          goto get_out;
-       }
-   } else {
+       have_vol = dcr->is_tape_position_ok();
+   }
+
+   if (!have_vol) {
       Dmsg1(190, "jid=%u Do mount_next_write_vol\n", (uint32_t)jcr->JobId);
       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;
       }
@@ -372,59 +395,15 @@ 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;
+   return ok ? dcr : NULL;
 }
 
-/*
- *      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.
- */
-static bool is_tape_position_ok(JCR *jcr, DEVICE *dev)
-{
-   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);
-         return false;
-      }
-   }
-   return true;
-}
-
-
 /*
  * This job is done, so release the device. From a Unix standpoint,
  *  the device remains open.
@@ -438,6 +417,7 @@ 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()) {
@@ -447,11 +427,7 @@ bool release_device(DCR *dcr)
    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 */
@@ -487,7 +463,7 @@ bool release_device(DCR *dcr)
             Dmsg2(200, "dir_update_vol_info. Release vol=%s dev=%s\n", 
                   dev->VolCatInfo.VolCatName, dev->print_name());
          }
-         if (!dev->num_writers) {             /* if no more writers */
+         if (dev->num_writers == 0) {         /* if not being used */
             volume_unused(dcr);               /*  we obviously are not using the volume */
          }
       }
@@ -501,6 +477,10 @@ 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))) {
@@ -535,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) {
@@ -649,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);
@@ -664,7 +645,7 @@ void detach_dcr_from_dev(DCR *dcr)
    /* 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 */
@@ -693,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; 
+}