]> 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 462b9b5b4f8f2a994903fc0ef6e5113b21c08ffe..dc1f38bc1927d543d64b4b373caf0cdc37b9c2a8 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2002-2009 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,27 +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_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
@@ -138,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;
@@ -145,7 +142,6 @@ mount_next_vol:
       autochanger = false;
       VolCatInfo.Slot = 0;
       ask = retry >= 2;
-      do_find = true;           /* do find_a_volume if we retry */
    }
    Dmsg1(150, "autoload_dev returns %d\n", autochanger);
    /*
@@ -167,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;
@@ -191,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;
@@ -205,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 */
             }
          }
@@ -242,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.
@@ -258,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;
       }
@@ -268,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;
       }
 
@@ -310,13 +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.
- *   They are unlocked on failure and remain locked on
- *   success.  The caller must know this!!!
+ * 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? */
@@ -333,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)
@@ -368,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.
@@ -444,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 */
@@ -488,6 +506,8 @@ int DCR::check_volume_label(bool &ask, bool &autochanger)
    return check_ok;
 
 check_next_volume:
+   dev->setVolCatInfo(false);
+   setVolCatInfo(false);
    return check_next_vol;
 
 check_bail_out:
@@ -559,7 +579,11 @@ void DCR::do_swapping(bool is_writing)
          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");
    }
 }
 
@@ -593,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"),
@@ -608,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;
       }
@@ -713,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;
@@ -756,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");
 }
 
@@ -814,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);