]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/mount.c
Backport new lock calls + debug for SD
[bacula/bacula] / bacula / src / stored / mount.c
index 8b8b27bded16206ad2b5440e58ca10e6de13be78..dc1f38bc1927d543d64b4b373caf0cdc37b9c2a8 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2002-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2002-2012 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
    This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
+   modify it under the terms of version three of the GNU Affero General Public
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
@@ -15,7 +15,7 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Affero General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
  *
  *   Kern Sibbald, August MMII
  *
- *   Version $Id$
  */
 
 #include "bacula.h"                   /* pull in global headers */
 #include "stored.h"                   /* pull in Storage Deamon headers */
 
-
 enum {
    try_next_vol = 1,
    try_read_vol,
@@ -64,12 +62,14 @@ enum {
  * This routine returns a 0 only if it is REALLY
  *  impossible to get the requested Volume.
  *
+ * This routine is entered with the device blocked, but not
+ *   locked.
+ *
  */
 bool DCR::mount_next_write_volume()
 {
    int retry = 0;
    bool ask = false, recycle, autochanger;
-   bool do_find = true;
    int mode;
    DCR *dcr = this;
 
@@ -77,17 +77,18 @@ bool DCR::mount_next_write_volume()
       dev->print_name());
 
    init_device_wait_timers(dcr);
-   lock_volumes();
    
    /*
     * Attempt to mount the next volume. If something non-fatal goes
     *  wrong, we come back here to re-try (new op messages, re-read
     *  Volume, ...)
     */
+   lock_volumes();
+
 mount_next_vol:
    Dmsg1(150, "mount_next_vol retry=%d\n", retry);
    /* Ignore retry if this is poll request */
-   if (!dev->poll && retry++ > 4) {
+   if (retry++ > 4) {
       /* Last ditch effort before giving up, force operator to respond */
       VolCatInfo.Slot = 0;
       unlock_volumes();
@@ -105,25 +106,22 @@ mount_next_vol:
    }
    recycle = false;
 
-   if (retry >= 2) {
-      do_find = false; 
-   }
-
    if (dev->must_unload()) {
       ask = true;                     /* ask operator to mount tape */
-      do_find = true;                 /* re-find a volume after unload */
    }
-   do_swapping(true /*writing*/);
+   do_unload();
+   do_swapping(true /*is_writing*/);
+   do_load(true /*is_writing*/);
 
-   if (do_find && !find_a_volume()) {
-      goto no_lock_bail_out;
+   if (!find_a_volume()) {
+      goto bail_out;
    }
 
    if (job_canceled(jcr)) {
       goto bail_out;
    }
    Dmsg3(150, "After find_next_append. Vol=%s Slot=%d Parts=%d\n",
-         VolCatInfo.VolCatName, VolCatInfo.Slot, VolCatInfo.VolCatParts);
+         getVolCatName(), VolCatInfo.Slot, VolCatInfo.VolCatParts);
    
    /*
     * Get next volume and ready it for append
@@ -136,6 +134,7 @@ mount_next_vol:
     * and move the tape to the end of data.
     *
     */
+   dcr->setVolCatInfo(false);   /* out of date when Vols unlocked */
    if (autoload_device(dcr, true/*writing*/, NULL) > 0) {
       autochanger = true;
       ask = false;
@@ -164,6 +163,7 @@ mount_next_vol:
 
    if (ask) {
       unlock_volumes();
+      dcr->setVolCatInfo(false);   /* out of date when Vols unlocked */
       if (!dir_ask_sysop_to_mount_volume(dcr, ST_APPEND)) {
          Dmsg0(150, "Error return ask_sysop ...\n");
          goto no_lock_bail_out;
@@ -178,6 +178,7 @@ mount_next_vol:
 
    if (dev->poll && dev->has_cap(CAP_CLOSEONPOLL)) {
       dev->close();
+      free_volume(dev);
    }
 
    /* Ensure the device is open */
@@ -187,10 +188,10 @@ mount_next_vol:
       mode = OPEN_READ_WRITE;
    }
    /* Try autolabel if enabled */
-   if (dev->open(dcr, mode) < 0) {
+   if (!dev->open(dcr, mode)) {
       try_autolabel(false);      /* try to create a new volume label */
    }
-   while (dev->open(dcr, mode) < 0) {
+   while (!dev->open(dcr, mode)) {
       Dmsg1(150, "open_device failed: ERR=%s\n", dev->bstrerror());
       if ((dev->is_file() && dev->is_removable()) || dev->is_dvd()) {
          bool ok = true;
@@ -201,7 +202,7 @@ mount_next_vol:
             }
          }
          if (ok && dev->scan_dir_for_volume(dcr)) {
-            if (dev->open(dcr, mode) >= 0) {
+            if (dev->open(dcr, mode)) {
                break;                    /* got a valid volume */
             }
          }
@@ -212,6 +213,8 @@ mount_next_vol:
       if (try_autolabel(false) == try_read_vol) {
          break;                       /* created a new volume label */
       }
+      Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
+            dev->print_name(), dcr->VolumeName, dev->bstrerror());
       Dmsg0(50, "set_unload\n");
       dev->set_unload();              /* force ask sysop */
       ask = true;
@@ -236,6 +239,16 @@ read_volume:
    case check_ok:
       break;
    }
+   /*
+    * Check that volcatinfo is good   
+    */
+   if (!dev->haveVolCatInfo()) {
+      Dmsg0(210, "Do not have volcatinfo\n");
+      if (!find_a_volume()) {
+         goto mount_next_vol;
+      }
+      dev->VolCatInfo = VolCatInfo;      /* structure assignment */
+   }
 
    /*
     * See if we have a fresh tape or a tape with data.
@@ -252,7 +265,7 @@ read_volume:
     */
    recycle = strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0;
    if (dev->VolHdr.LabelType == PRE_LABEL || recycle) {
-      if (!rewrite_volume_label(dcr, recycle)) {
+      if (!dcr->rewrite_volume_label(recycle)) {
          mark_volume_in_error();
          goto mount_next_vol;
       }
@@ -262,18 +275,21 @@ read_volume:
        * we need to position to the end of the volume, since we are
        * just now putting it into append mode.
        */
-      Dmsg0(200, "Device previously written, moving to end of data\n");
+      Dmsg1(100, "Device previously written, moving to end of data. Expect %lld bytes\n",
+           dev->VolCatInfo.VolCatBytes);
       Jmsg(jcr, M_INFO, 0, _("Volume \"%s\" previously written, moving to end of data.\n"),
          VolumeName);
 
       if (!dev->eod(dcr)) {
+         Dmsg2(050, "Unable to position to end of data on device %s: ERR=%s\n", 
+            dev->print_name(), dev->bstrerror());
          Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data on device %s: ERR=%s\n"),
             dev->print_name(), dev->bstrerror());
          mark_volume_in_error();
          goto mount_next_vol;
       }
       if (!is_eod_valid()) {
-         Dmsg0(150, "goto mount_next_vol\n");
+         Dmsg0(100, "goto mount_next_vol\n");
          goto mount_next_vol;
       }
 
@@ -304,10 +320,12 @@ no_lock_bail_out:
  * This routine is meant to be called once the first pass
  *   to ensure that we have a candidate volume to mount.
  *   Otherwise, we ask the sysop to created one.
+ * Note, the the Volumes are locked on entry and exit.
  */
-bool DCR::find_a_volume()  
+bool DCR::find_a_volume()
 {
    DCR *dcr = this;
+
    if (!is_suitable_volume_mounted()) {
       bool have_vol = false;
       /* Do we have a candidate volume? */
@@ -324,19 +342,25 @@ bool DCR::find_a_volume()
          while (!dir_find_next_appendable_volume(dcr)) {
             Dmsg0(200, "not dir_find_next\n");
             if (job_canceled(jcr)) {
-               unlock_volumes();
                return false;
             }
             unlock_volumes();
             if (!dir_ask_sysop_to_create_appendable_volume(dcr)) {
+               lock_volumes();
                return false;
              }
              lock_volumes();
+             if (job_canceled(jcr)) {
+                return false;
+             }
              Dmsg0(150, "Again dir_find_next_append...\n");
          }
       }
    }
-   return true;
+   if (dcr->haveVolCatInfo()) {
+      return true;
+   }
+   return dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE);
 }
 
 int DCR::check_volume_label(bool &ask, bool &autochanger)
@@ -359,6 +383,7 @@ int DCR::check_volume_label(bool &ask, bool &autochanger)
 
    Dmsg2(150, "Want dirVol=%s dirStat=%s\n", VolumeName,
       VolCatInfo.VolCatStatus);
+
    /*
     * At this point, dev->VolCatInfo has what is in the drive, if anything,
     *          and   dcr->VolCatInfo has what the Director wants.
@@ -435,6 +460,8 @@ int DCR::check_volume_label(bool &ask, bool &autochanger)
          Jmsg2(jcr, M_WARNING, 0, _("Could not reserve volume %s on %s\n"),
             dev->VolHdr.VolumeName, dev->print_name());
          ask = true;
+         dev->setVolCatInfo(false);
+         setVolCatInfo(false);
          goto check_next_volume;
       }
       break;                /* got a Volume */
@@ -459,7 +486,6 @@ int DCR::check_volume_label(bool &ask, bool &autochanger)
       case try_default:
          break;
       }
-
       /* NOTE! Fall-through wanted. */
    case VOL_NO_MEDIA:
    default:
@@ -473,12 +499,15 @@ int DCR::check_volume_label(bool &ask, bool &autochanger)
       /* Needed, so the medium can be changed */
       if (dev->requires_mount()) {
          dev->close();
+         free_volume(dev);
       }
       goto check_next_volume;
    }
    return check_ok;
 
 check_next_volume:
+   dev->setVolCatInfo(false);
+   setVolCatInfo(false);
    return check_next_vol;
 
 check_bail_out:
@@ -500,12 +529,30 @@ bool DCR::is_suitable_volume_mounted()
    return dir_get_volume_info(this, GET_VOL_INFO_FOR_WRITE);
 }
 
-void DCR::do_swapping(bool is_writing)
+bool DCR::do_unload()
 {
    if (dev->must_unload()) {
       Dmsg1(100, "must_unload release %s\n", dev->print_name());
       release_volume();
    }
+   return false;
+}
+
+bool DCR::do_load(bool is_writing)
+{
+   if (dev->must_load()) {
+      Dmsg1(100, "Must load %s\n", dev->print_name());
+      if (autoload_device(this, is_writing, NULL) > 0) {
+         dev->clear_load();
+         return true;
+      }
+      return false;
+   }
+   return true;
+}
+
+void DCR::do_swapping(bool is_writing)
+{
    /*
     * See if we are asked to swap the Volume from another device
     *  if so, unload the other device here, and attach the
@@ -525,14 +572,18 @@ void DCR::do_swapping(bool is_writing)
          Dmsg1(100, "=== set in_use vol=%s\n", dev->vol->vol_name);
          dev->vol->set_in_use();
          dev->VolHdr.VolumeName[0] = 0;  /* don't yet have right Volume */
+      } else {
+         Dmsg1(100, "No vol on dev=%s\n", dev->print_name());
       }
-      dev->swap_dev = NULL;
-   }
-   if (dev->must_load()) {
-      Dmsg1(100, "Must load %s\n", dev->print_name());
-      if (autoload_device(this, is_writing, NULL) > 0) {
-         dev->clear_load();
+      if (dev->swap_dev->vol) {
+         Dmsg2(100, "Vol=%s on dev=%s\n", dev->swap_dev->vol->vol_name,
+              dev->swap_dev->print_name());
       }
+      Dmsg2(100, "Set swap_dev=NULL for dev=%s swap_dev=%s\n",
+         dev->print_name(), dev->swap_dev->print_name());
+      dev->swap_dev = NULL;
+   } else {
+      Dmsg0(100, "No swap_dev set\n");
    }
 }
 
@@ -566,6 +617,18 @@ bool DCR::is_eod_valid()
       if (dev->VolCatInfo.VolCatFiles == dev->get_file()) {
          Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\" at file=%d.\n"),
               VolumeName, dev->get_file());
+      } else if (dev->get_file() > dev->VolCatInfo.VolCatFiles) {
+         Jmsg(jcr, M_WARNING, 0, _("For Volume \"%s\":\n"
+              "The number of files mismatch! Volume=%u Catalog=%u\n"
+              "Correcting Catalog\n"),
+              VolumeName, dev->get_file(), dev->VolCatInfo.VolCatFiles);
+         dev->VolCatInfo.VolCatFiles = dev->get_file();
+         dev->VolCatInfo.VolCatBlocks = dev->get_block_num();
+         if (!dir_update_volume_info(this, false, true)) {
+            Jmsg(jcr, M_WARNING, 0, _("Error updating Catalog\n"));
+            mark_volume_in_error();
+            return false;
+         }
       } else {
          Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on tape Volume \"%s\" because:\n"
               "The number of files mismatch! Volume=%u Catalog=%u\n"),
@@ -581,12 +644,27 @@ bool DCR::is_eod_valid()
          Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\""
               " size=%s\n"), VolumeName, 
               edit_uint64(dev->VolCatInfo.VolCatBytes, ed1));
+      } else if ((uint64_t)pos > dev->VolCatInfo.VolCatBytes) {
+         Jmsg(jcr, M_WARNING, 0, _("For Volume \"%s\":\n"
+              "The sizes do not match! Volume=%s Catalog=%s\n"
+              "Correcting Catalog\n"),
+              VolumeName, edit_uint64(pos, ed1), 
+              edit_uint64(dev->VolCatInfo.VolCatBytes, ed2));
+         dev->VolCatInfo.VolCatBytes = (uint64_t)pos;
+         dev->VolCatInfo.VolCatFiles = (uint32_t)(pos >> 32);
+         if (!dir_update_volume_info(this, false, true)) {
+            Jmsg(jcr, M_WARNING, 0, _("Error updating Catalog\n"));
+            mark_volume_in_error();
+            return false;
+         }
       } else {
-         Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on disk Volume \"%s\" because: "
+         Mmsg(jcr->errmsg, _("Bacula cannot write on disk Volume \"%s\" because: "
               "The sizes do not match! Volume=%s Catalog=%s\n"),
               VolumeName,
               edit_uint64(pos, ed1),
               edit_uint64(dev->VolCatInfo.VolCatBytes, ed2));
+         Jmsg(jcr, M_ERROR, 0, jcr->errmsg);
+         Dmsg0(050, jcr->errmsg);
          mark_volume_in_error();
          return false;
       }
@@ -686,7 +764,7 @@ void DCR::mark_volume_not_inchanger()
 {
    Jmsg(jcr, M_ERROR, 0, _("Autochanger Volume \"%s\" not found in slot %d.\n"
 "    Setting InChanger to zero in catalog.\n"),
-        VolCatInfo.VolCatName, VolCatInfo.Slot);
+        getVolCatName(), VolCatInfo.Slot);
    dev->VolCatInfo = VolCatInfo;    /* structure assignment */
    VolCatInfo.InChanger = false;
    dev->VolCatInfo.InChanger = false;
@@ -729,8 +807,6 @@ void DCR::release_volume()
    if (dev->is_open()) {
       dev->offline_or_rewind();
    }
-// Dmsg0(50, "set_unload\n");
-// dev->set_unload();
    Dmsg0(190, "release_volume\n");
 }
 
@@ -787,7 +863,11 @@ bool mount_next_read_volume(DCR *dcr)
     * End Of Tape -- mount next Volume (if another specified)
     */
    if (jcr->NumReadVolumes > 1 && jcr->CurReadVolume < jcr->NumReadVolumes) {
+      dev->Lock();
       dev->close();
+      dev->set_read();
+      dcr->set_reserved();
+      dev->Unlock();
       if (!acquire_device_for_read(dcr)) {
          Jmsg2(jcr, M_FATAL, 0, _("Cannot open Dev=%s, Vol=%s\n"), dev->print_name(),
                dcr->VolumeName);