]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/dev.c
update version
[bacula/bacula] / bacula / src / stored / dev.c
index 2e63db01c8f1d6737267632297ddcdc05f441b6c..5ce5712eff40713d4a985f8252e2262ed28f7322 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2010 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.
@@ -47,7 +47,6 @@
  *     daemon. More complicated coding (double buffering, writer
  *     thread, ...) is left for a later version.
  *
- *   Version $Id$
  */
 
 /*
@@ -169,7 +168,6 @@ init_dev(JCR *jcr, DEVRES *device)
    dev->max_spool_size = device->max_spool_size;
    dev->drive_index = device->drive_index;
    dev->autoselect = device->autoselect;
-   dev->truncate_on_purge = device->truncate_on_purge;
    dev->dev_type = device->dev_type;
    dev->init_backend();
    if (dev->is_tape()) { /* No parts on tapes */
@@ -200,11 +198,12 @@ init_dev(JCR *jcr, DEVRES *device)
          Jmsg2(jcr, M_ERROR_TERM, 0, _("Unable to stat mount point %s: ERR=%s\n"), 
             device->mount_point, be.bstrerror());
       }
-   }
-   if (dev->is_dvd()) {
+   
       if (!device->mount_command || !device->unmount_command) {
          Jmsg0(jcr, M_ERROR_TERM, 0, _("Mount and unmount commands must defined for a device which requires mount.\n"));
       }
+   }
+   if (dev->is_dvd()) {
       if (!device->write_part_command) {
          Jmsg0(jcr, M_ERROR_TERM, 0, _("Write part command must be defined for a device which requires mount.\n"));
       }
@@ -267,6 +266,10 @@ init_dev(JCR *jcr, DEVRES *device)
       Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
       Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
    }
+   /* Ensure that we respect this order in P/V operations */
+   bthread_mutex_set_priority(&dev->m_mutex,       PRIO_SD_DEV_ACCESS);
+   bthread_mutex_set_priority(&dev->spool_mutex,   PRIO_SD_DEV_SPOOL);
+   bthread_mutex_set_priority(&dev->acquire_mutex, PRIO_SD_DEV_ACQUIRE);
 #ifdef xxx
    if ((errstat = rwl_init(&dev->lock)) != 0) {
       berrno be;
@@ -350,11 +353,12 @@ DEVICE::open(DCR *dcr, int omode)
       }
    }
    if (dcr) {
-      bstrncpy(VolCatInfo.VolCatName, dcr->VolumeName, sizeof(VolCatInfo.VolCatName));
+      dcr->setVolCatName(dcr->VolumeName);
+      VolCatInfo = dcr->VolCatInfo;    /* structure assign */
    }
 
    Dmsg4(100, "open dev: type=%d dev_name=%s vol=%s mode=%s\n", dev_type,
-         print_name(), VolCatInfo.VolCatName, mode_to_str(omode));
+         print_name(), getVolCatName(), mode_to_str(omode));
    state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
    label_type = B_BACULA_LABEL;
    if (is_tape() || is_fifo()) {
@@ -402,6 +406,7 @@ void DEVICE::open_tape_device(DCR *dcr, int omode)
    utime_t start_time = time(NULL);
 #endif
 
+   mount(1);                          /* do mount if required */
 
    Dmsg0(100, "Open dev: device is tape\n");
 
@@ -526,7 +531,7 @@ void DEVICE::open_file_device(DCR *dcr, int omode)
       if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) {
          pm_strcat(archive_name, "/");
       }
-      pm_strcat(archive_name, VolCatInfo.VolCatName);
+      pm_strcat(archive_name, getVolCatName());
    }
 
    mount(1);                          /* do mount if required */
@@ -554,8 +559,8 @@ void DEVICE::open_file_device(DCR *dcr, int omode)
 }
 
 /*
- * Open a DVD device. N.B. at this point, dcr->VolCatInfo.VolCatName 
- *  (NB:??? I think it's VolCatInfo.VolCatName that is right)
+ * Open a DVD device. N.B. at this point, dcr->getVolCatName() 
+ *  (NB:??? I think it's getVolCatName() that is right)
  *  has the desired Volume name, but there is NO assurance that
  *  any other field of VolCatInfo is correct.
  */
@@ -579,7 +584,7 @@ void DEVICE::open_dvd_device(DCR *dcr, int omode)
     *  copy here, when opening.
     */
    VolCatInfo = dcr->VolCatInfo;         /* structure assignment */
-   Dmsg1(100, "Volume=%s\n", VolCatInfo.VolCatName);
+   Dmsg1(100, "Volume=%s\n", getVolCatName());
 
    if (VolCatInfo.VolCatName[0] == 0) {
       Dmsg1(10,  "Could not open DVD device %s. No Volume name given.\n",
@@ -888,7 +893,7 @@ bool DEVICE::eod(DCR *dcr)
    return fsf(VolCatInfo.VolCatFiles);
 #endif
 
-   Dmsg0(100, "eod\n");
+   Dmsg0(100, "Enter eod\n");
    if (at_eot()) {
       return true;
    }
@@ -901,7 +906,7 @@ bool DEVICE::eod(DCR *dcr)
    }
    if (!is_tape()) {
       pos = lseek(dcr, (boffset_t)0, SEEK_END);
-//    Dmsg1(100, "====== Seek to %lld\n", pos);
+      Dmsg1(200, "====== Seek to %lld\n", pos);
       if (pos >= 0) {
          update_pos(dcr);
          set_eot();
@@ -911,6 +916,7 @@ bool DEVICE::eod(DCR *dcr)
       berrno be;
       Mmsg2(errmsg, _("lseek error on %s. ERR=%s.\n"),
              print_name(), be.bstrerror());
+      Dmsg0(100, errmsg);
       return false;
    }
 #ifdef MTEOM
@@ -919,6 +925,7 @@ bool DEVICE::eod(DCR *dcr)
       /* If unknown position, rewind */
       if (get_os_tape_file() < 0) {
         if (!rewind(NULL)) {
+          Dmsg0(100, "Rewind error\n");
           return false;
         }
       }
@@ -947,6 +954,7 @@ bool DEVICE::eod(DCR *dcr)
          update_pos(dcr);
          Mmsg2(errmsg, _("ioctl MTEOM error on %s. ERR=%s.\n"),
             print_name(), be.bstrerror());
+         Dmsg0(100, errmsg);
          return false;
       }
 
@@ -956,6 +964,7 @@ bool DEVICE::eod(DCR *dcr)
          clrerror(-1);
          Mmsg2(errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
             print_name(), be.bstrerror());
+         Dmsg0(100, errmsg);
          return false;
       }
       Dmsg1(100, "EOD file=%d\n", os_file);
@@ -969,6 +978,7 @@ bool DEVICE::eod(DCR *dcr)
        * Rewind then use FSF until EOT reached
        */
       if (!rewind(NULL)) {
+         Dmsg0(100, "Rewind error.\n");
          return false;
       }
       /*
@@ -978,7 +988,7 @@ bool DEVICE::eod(DCR *dcr)
       for (file_num=file; !at_eot(); file_num++) {
          Dmsg0(200, "eod: doing fsf 1\n");
          if (!fsf(1)) {
-            Dmsg0(200, "fsf error.\n");
+            Dmsg0(100, "fsf error.\n");
             return false;
          }
          /*
@@ -1903,6 +1913,7 @@ void DEVICE::clear_volhdr()
 {
    Dmsg1(100, "Clear volhdr vol=%s\n", VolHdr.VolumeName);
    memset(&VolHdr, 0, sizeof(VolHdr));
+   setVolCatInfo(false);
 }
 
 
@@ -1912,9 +1923,7 @@ void DEVICE::clear_volhdr()
 void DEVICE::close()
 {
    Dmsg1(100, "close_dev %s\n", print_name());
-   if (has_cap(CAP_OFFLINEUNMOUNT)) {
-      offline();
-   }
+   offline_or_rewind();
 
    if (!is_open()) {
       Dmsg2(100, "device %s already closed vol=%s\n", print_name(),
@@ -1929,8 +1938,11 @@ void DEVICE::close()
       unlock_door(); 
    default:
       d_close(m_fd);
+      break;
    }
 
+   unmount(1);                        /* do unmount if required */
+
    /* Clean up device packet so it can be reused */
    clear_opened();
    /*
@@ -2066,74 +2078,165 @@ bool DEVICE::truncate(DCR *dcr) /* We need the DCR for DVD-writing */
    return false;
 }
 
-/* Mount the device.
+/*
+ * Mount the device.
  * If timeout, wait until the mount command returns 0.
  * If !timeout, try to mount the device only once.
  */
 bool DEVICE::mount(int timeout) 
 {
    Dmsg0(190, "Enter mount\n");
+
    if (is_mounted()) {
       return true;
-   } else if (requires_mount()) {
-      return do_mount(1, timeout);
-   }       
+   }
+
+   switch (dev_type) {
+   case B_VTL_DEV:
+   case B_VTAPE_DEV:
+   case B_TAPE_DEV:
+      if (device->mount_command) {
+         return do_tape_mount(1, timeout);
+      }
+      break;
+   case B_FILE_DEV:
+   case B_DVD_DEV:
+      if (requires_mount() && device->mount_command) {
+         return do_file_mount(1, timeout);
+      }
+      break;
+   default:
+      break;
+   }
+
    return true;
 }
 
-/* Unmount the device
+/*
+ * Unmount the device
  * If timeout, wait until the unmount command returns 0.
  * If !timeout, try to unmount the device only once.
  */
 bool DEVICE::unmount(int timeout) 
 {
    Dmsg0(100, "Enter unmount\n");
-   if (is_mounted()) {
-      return do_mount(0, timeout);
+
+   if (!is_mounted()) {
+      return true;
    }
+
+   switch (dev_type) {
+   case B_VTL_DEV:
+   case B_VTAPE_DEV:
+   case B_TAPE_DEV:
+      if (device->unmount_command) {
+         return do_tape_mount(0, timeout);
+      }
+      break;
+   case B_FILE_DEV:
+   case B_DVD_DEV:
+      if (requires_mount() && device->unmount_command) {
+         return do_file_mount(0, timeout);
+      }
+      break;
+   default:
+      break;
+   }
+
    return true;
 }
 
-/* (Un)mount the device */
-bool DEVICE::do_mount(int mount, int dotimeout) 
+/*
+ * (Un)mount the device (for tape devices)
+ */
+bool DEVICE::do_tape_mount(int mount, int dotimeout)
 {
    POOL_MEM ocmd(PM_FNAME);
    POOLMEM *results;
    char *icmd;
-   int status, timeout;
-   
+   int status, tries;
+   berrno be;
+
    Dsm_check(1);
    if (mount) {
-      if (is_mounted()) {
-         Dmsg0(200, "======= mount=1\n");
-         return true;
-      }
       icmd = device->mount_command;
    } else {
-      if (!is_mounted()) {
-         Dmsg0(200, "======= mount=0\n");
-         return true;
+      icmd = device->unmount_command;
+   }
+
+   edit_mount_codes(ocmd, icmd);
+
+   Dmsg2(100, "do_tape_mount: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted());
+
+   if (dotimeout) {
+      /* Try at most 10 times to (un)mount the device. This should perhaps be configurable. */
+      tries = 10;
+   } else {
+      tries = 1;
+   }
+   results = get_memory(4000);
+
+   /* If busy retry each second */
+   Dmsg1(100, "do_tape_mount run_prog=%s\n", ocmd.c_str());
+   while ((status = run_program_full_output(ocmd.c_str(), max_open_wait/2, results)) != 0) {
+      if (tries-- > 0) {
+         continue;
       }
+
+      Dmsg5(100, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", print_name(),
+           (mount ? "" : "un"), status, results, be.bstrerror(status));
+      Mmsg(errmsg, _("Device %s cannot be %smounted. ERR=%s\n"),
+           print_name(), (mount ? "" : "un"), be.bstrerror(status));
+
+      set_mounted(false);
+      free_pool_memory(results);
+      Dmsg0(200, "============ mount=0\n");
+      Dsm_check(1);
+      return false;
+   }
+
+   set_mounted(mount);              /* set/clear mounted flag */
+   free_pool_memory(results);
+   Dmsg1(200, "============ mount=%d\n", mount);
+   return true;
+}
+
+/*
+ * (Un)mount the device (either a FILE or DVD device)
+ */
+bool DEVICE::do_file_mount(int mount, int dotimeout) 
+{
+   POOL_MEM ocmd(PM_FNAME);
+   POOLMEM *results;
+   DIR* dp;
+   char *icmd;
+   struct dirent *entry, *result;
+   int status, tries, name_max, count;
+   berrno be;
+
+   Dsm_check(1);
+   if (mount) {
+      icmd = device->mount_command;
+   } else {
       icmd = device->unmount_command;
    }
    
    clear_freespace_ok();
    edit_mount_codes(ocmd, icmd);
    
-   Dmsg2(100, "do_mount: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted());
+   Dmsg2(100, "do_file_mount: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted());
 
    if (dotimeout) {
       /* Try at most 10 times to (un)mount the device. This should perhaps be configurable. */
-      timeout = 10;
+      tries = 10;
    } else {
-      timeout = 0;
+      tries = 1;
    }
    results = get_memory(4000);
 
    /* If busy retry each second */
-   Dmsg1(100, "do_mount run_prog=%s\n", ocmd.c_str());
-   while ((status = run_program_full_output(ocmd.c_str(), 
-                       max_open_wait/2, results)) != 0) {
+   Dmsg1(100, "do_file_mount run_prog=%s\n", ocmd.c_str());
+   while ((status = run_program_full_output(ocmd.c_str(), max_open_wait/2, results)) != 0) {
       /* Doesn't work with internationalization (This is not a problem) */
       if (mount && fnmatch("*is already mounted on*", results, 0) == 0) {
          break;
@@ -2141,37 +2244,24 @@ bool DEVICE::do_mount(int mount, int dotimeout)
       if (!mount && fnmatch("* not mounted*", results, 0) == 0) {
          break;
       }
-      if (timeout-- > 0) {
+      if (tries-- > 0) {
          /* Sometimes the device cannot be mounted because it is already mounted.
           * Try to unmount it, then remount it */
          if (mount) {
             Dmsg1(400, "Trying to unmount the device %s...\n", print_name());
-            do_mount(0, 0);
+            do_file_mount(0, 0);
          }
          bmicrosleep(1, 0);
          continue;
       }
-      if (status != 0) {
-         berrno be;
-         Dmsg5(100, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", print_name(),
-              (mount ? "" : "un"), status, results, be.bstrerror(status));
-         Mmsg(errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), 
-              print_name(), (mount ? "" : "un"), be.bstrerror(status));
-      } else {
-         Dmsg4(100, "Device %s cannot be %smounted. stat=%d ERR=%s\n", print_name(),
-              (mount ? "" : "un"), status, results);
-         Mmsg(errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), 
-              print_name(), (mount ? "" : "un"), results);
-      }
+      Dmsg5(100, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", print_name(),
+           (mount ? "" : "un"), status, results, be.bstrerror(status));
+      Mmsg(errmsg, _("Device %s cannot be %smounted. ERR=%s\n"),
+           print_name(), (mount ? "" : "un"), be.bstrerror(status));
+
       /*
-       * Now, just to be sure it is not mounted, try to read the
-       *  filesystem.
+       * Now, just to be sure it is not mounted, try to read the filesystem.
        */
-      DIR* dp;
-      struct dirent *entry, *result;
-      int name_max;
-      int count;
-      
       name_max = pathconf(".", _PC_NAME_MAX);
       if (name_max < 1024) {
          name_max = 1024;
@@ -2180,7 +2270,7 @@ bool DEVICE::do_mount(int mount, int dotimeout)
       if (!(dp = opendir(device->mount_point))) {
          berrno be;
          dev_errno = errno;
-         Dmsg3(100, "do_mount: failed to open dir %s (dev=%s), ERR=%s\n", 
+         Dmsg3(100, "do_file_mount: failed to open dir %s (dev=%s), ERR=%s\n", 
                device->mount_point, print_name(), be.bstrerror());
          goto get_out;
       }
@@ -2190,7 +2280,7 @@ bool DEVICE::do_mount(int mount, int dotimeout)
       while (1) {
          if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
             dev_errno = EIO;
-            Dmsg2(129, "do_mount: failed to find suitable file in dir %s (dev=%s)\n", 
+            Dmsg2(129, "do_file_mount: failed to find suitable file in dir %s (dev=%s)\n", 
                   device->mount_point, print_name());
             break;
          }
@@ -2198,13 +2288,13 @@ bool DEVICE::do_mount(int mount, int dotimeout)
             count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
             break;
          } else {
-            Dmsg2(129, "do_mount: ignoring %s in %s\n", result->d_name, device->mount_point);
+            Dmsg2(129, "do_file_mount: ignoring %s in %s\n", result->d_name, device->mount_point);
          }
       }
       free(entry);
       closedir(dp);
       
-      Dmsg1(100, "do_mount: got %d files in the mount point (not counting ., .. and .keep)\n", count);
+      Dmsg1(100, "do_file_mount: got %d files in the mount point (not counting ., .. and .keep)\n", count);
       
       if (count > 0) {
          /* If we got more than ., .. and .keep */
@@ -2384,7 +2474,7 @@ int32_t DEVICE::get_os_tape_file()
 char *
 dev_vol_name(DEVICE *dev)
 {
-   return dev->VolCatInfo.VolCatName;
+   return dev->getVolCatName();
 }