]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/dev.c
Backport new lock calls + debug for SD
[bacula/bacula] / bacula / src / stored / dev.c
index e40948d538a10cfae88c8552d31c09b562a4e876..3d4e44bc584ef0230f16f9f5177c647020798318 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-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.
@@ -32,7 +32,7 @@
  *              Kern Sibbald, MM
  *
  *     NOTE!!!! None of these routines are reentrant. You must
- *        use dev->r_dlock() and dev->unlock() at a higher level,
+ *        use dev->rLock() and dev->Unlock() at a higher level,
  *        or use the xxx_device() equivalents.  By moving the
  *        thread synchronization to a higher level, we permit
  *        the higher level routines to "seize" the device and
@@ -89,6 +89,7 @@
 void set_os_device_parameters(DCR *dcr);   
 static bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat);
 static const char *mode_to_str(int mode);
+static DEVICE *m_init_dev(JCR *jcr, DEVRES *device, bool new_init);
 
 /*
  * Allocate and initialize the DEVICE structure
@@ -103,6 +104,13 @@ static const char *mode_to_str(int mode);
  */
 DEVICE *
 init_dev(JCR *jcr, DEVRES *device)
+{
+   DEVICE *dev = m_init_dev(jcr, device, false);
+   return dev;
+}
+
+static DEVICE *
+m_init_dev(JCR *jcr, DEVRES *device, bool new_init)
 {
    struct stat statp;
    int errstat;
@@ -196,6 +204,7 @@ init_dev(JCR *jcr, DEVRES *device)
    dev->drive_index = device->drive_index;
    dev->autoselect = device->autoselect;
    dev->dev_type = device->dev_type;
+   dev->device = device;
    if (dev->is_tape()) { /* No parts on tapes */
       dev->max_part_size = 0;
    } else {
@@ -205,8 +214,6 @@ init_dev(JCR *jcr, DEVRES *device)
    if (dev->vol_poll_interval && dev->vol_poll_interval < 60) {
       dev->vol_poll_interval = 60;
    }
-   /* Link the dev and device structures together */
-   dev->device = device;
    device->dev = dev;
 
    if (dev->is_fifo()) {
@@ -246,18 +253,18 @@ init_dev(JCR *jcr, DEVRES *device)
       dev->max_block_size = 0;
    }
    if (dev->max_block_size % TAPE_BSIZE != 0) {
-      Jmsg2(jcr, M_WARNING, 0, _("Max block size %u not multiple of device %s block size.\n"),
-         dev->max_block_size, dev->print_name());
+      Jmsg3(jcr, M_WARNING, 0, _("Max block size %u not multiple of device %s block size=%d.\n"),
+         dev->max_block_size, dev->print_name(), TAPE_BSIZE);
    }
    if (dev->max_volume_size != 0 && dev->max_volume_size < (dev->max_block_size << 4)) {
-      Jmsg(jcr, M_ERROR_TERM, 0, _("Max Vol Size < 8 * Max Block Size on device %s\n"), 
+      Jmsg(jcr, M_ERROR_TERM, 0, _("Max Vol Size < 8 * Max Block Size for device %s\n"), 
            dev->print_name());
    }
 
    dev->errmsg = get_pool_memory(PM_EMSG);
    *dev->errmsg = 0;
 
-   if ((errstat = pthread_mutex_init(&dev->m_mutex, NULL)) != 0) {
+   if ((errstat = dev->init_mutex()) != 0) {
       berrno be;
       dev->dev_errno = errstat;
       Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
@@ -278,19 +285,25 @@ init_dev(JCR *jcr, DEVRES *device)
    if ((errstat = pthread_mutex_init(&dev->spool_mutex, NULL)) != 0) {
       berrno be;
       dev->dev_errno = errstat;
-      Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
+      Mmsg1(dev->errmsg, _("Unable to init spool mutex: ERR=%s\n"), be.bstrerror(errstat));
       Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
    }
-   if ((errstat = pthread_mutex_init(&dev->acquire_mutex, NULL)) != 0) {
+   if ((errstat = dev->init_acquire_mutex()) != 0) {
       berrno be;
       dev->dev_errno = errstat;
-      Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
+      Mmsg1(dev->errmsg, _("Unable to init acquire mutex: ERR=%s\n"), be.bstrerror(errstat));
+      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
+   }
+   if ((errstat = dev->init_read_acquire_mutex()) != 0) {
+      berrno be;
+      dev->dev_errno = errstat;
+      Mmsg1(dev->errmsg, _("Unable to init read acquire 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);
+
+   dev->set_mutex_priorities();
+
+
 #ifdef xxx
    if ((errstat = rwl_init(&dev->lock)) != 0) {
       berrno be;
@@ -338,8 +351,8 @@ ssize_t DEVICE::d_write(int fd, const void *buffer, size_t count)
  * Open the device with the operating system and
  * initialize buffer pointers.
  *
- * Returns:  -1  on error
- *           fd  on success
+ * Returns:  true on success
+ *           false on error
  *
  * Note, for a tape, the VolName is the name we give to the
  *    volume (not really used here), but for a file, the
@@ -347,13 +360,13 @@ ssize_t DEVICE::d_write(int fd, const void *buffer, size_t count)
  *    In the case of a file, the full name is the device name
  *    (archive_name) with the VolName concatenated.
  */
-int
+bool
 DEVICE::open(DCR *dcr, int omode)
 {
    int preserve = 0;
    if (is_open()) {
       if (openmode == omode) {
-         return m_fd;
+         return true;
       } else {
          d_close(m_fd);
          clear_opened();
@@ -381,7 +394,7 @@ DEVICE::open(DCR *dcr, int omode)
    }
    state |= preserve;                 /* reset any important state info */
    Dmsg2(100, "preserve=0x%x fd=%d\n", preserve, m_fd);
-   return m_fd;
+   return m_fd >= 0;
 }
 
 void DEVICE::set_mode(int new_mode) 
@@ -515,7 +528,7 @@ void DEVICE::open_device(DCR *dcr, int omode)
 }
 
 /*
- * Open a file device
+ * Open a file device.
  */
 void DEVICE::open_file_device(DCR *dcr, int omode) 
 {
@@ -561,8 +574,8 @@ void DEVICE::open_file_device(DCR *dcr, int omode)
       Mmsg2(errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(), 
             be.bstrerror());
       Dmsg1(100, "open failed: %s", errmsg);
-//    Jmsg1(NULL, M_WARNING, 0, "%s", errmsg);
-   } else {
+   }
+   if (m_fd >= 0) {
       dev_errno = 0;
       file = 0;
       file_addr = 0;
@@ -1401,6 +1414,7 @@ void DEVICE::lock_door()
 {
 #ifdef MTLOCK
    struct mtop mt_com;
+   if (!is_tape()) return;
    mt_com.mt_op = MTLOCK;
    mt_com.mt_count = 1;
    d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com);
@@ -1411,6 +1425,7 @@ void DEVICE::unlock_door()
 {
 #ifdef MTUNLOCK
    struct mtop mt_com;
+   if (!is_tape()) return;
    mt_com.mt_op = MTUNLOCK;
    mt_com.mt_count = 1;
    d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com);
@@ -1491,7 +1506,7 @@ bool DEVICE::reposition(DCR *dcr, uint32_t rfile, uint32_t rblock)
       return fsr(rblock-block_num);
    } else {
       while (rblock > block_num) {
-         if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) {
+         if (!dcr->read_block_from_dev(NO_BLOCK_NUMBER_CHECK)) {
             berrno be;
             dev_errno = errno;
             Dmsg2(30, "Failed to find requested block on %s: ERR=%s",
@@ -1741,7 +1756,8 @@ void DEVICE::close()
    case B_VTL_DEV:
    case B_VTAPE_DEV:
    case B_TAPE_DEV:
-      unlock_door(); 
+      unlock_door();
+      /* Fall through wanted */
    default:
       d_close(m_fd);
       break;
@@ -1806,10 +1822,13 @@ boffset_t DEVICE::lseek(DCR *dcr, boffset_t offset, int whence)
    return -1;
 }
 
-
+/*
+ * Truncate a volume.
+ */
 bool DEVICE::truncate(DCR *dcr) /* We need the DCR for DVD-writing */
 {
    struct stat st;
+   DEVICE *dev = this;
 
    Dmsg1(100, "truncate %s\n", print_name());
    switch (dev_type) {
@@ -1819,62 +1838,64 @@ bool DEVICE::truncate(DCR *dcr) /* We need the DCR for DVD-writing */
       /* maybe we should rewind and write and eof ???? */
       return true;                    /* we don't really truncate tapes */
    case B_FILE_DEV:
-      if (ftruncate(m_fd, 0) != 0) {
-         berrno be;
-         Mmsg2(errmsg, _("Unable to truncate device %s. ERR=%s\n"), 
-               print_name(), be.bstrerror());
-         return false;
-      }
-          
-      /*
-       * Check for a successful ftruncate() and issue a work-around for devices 
-       * (mostly cheap NAS) that don't support truncation. 
-       * Workaround supplied by Martin Schmid as a solution to bug #1011.
-       * 1. close file
-       * 2. delete file
-       * 3. open new file with same mode
-       * 4. change ownership to original
-       */
-
-      if (fstat(m_fd, &st) != 0) {
-         berrno be;
-         Mmsg2(errmsg, _("Unable to stat device %s. ERR=%s\n"), 
-               print_name(), be.bstrerror());
-         return false;
-      }
-          
-      if (st.st_size != 0) {             /* ftruncate() didn't work */
-         POOL_MEM archive_name(PM_FNAME);
-                
-         pm_strcpy(archive_name, dev_name);
-         if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) {
-            pm_strcat(archive_name, "/");
+      for ( ;; ) {
+         if (ftruncate(dev->m_fd, 0) != 0) {
+            berrno be;
+            Mmsg2(errmsg, _("Unable to truncate device %s. ERR=%s\n"), 
+                  print_name(), be.bstrerror());
+            return false;
          }
-         pm_strcat(archive_name, dcr->VolumeName);
-                   
-         Mmsg2(errmsg, _("Device %s doesn't support ftruncate(). Recreating file %s.\n"), 
-               print_name(), archive_name.c_str());
 
-         /* Close file and blow it away */
-         ::close(m_fd);
-         ::unlink(archive_name.c_str());
-                   
-         /* Recreate the file -- of course, empty */
-         set_mode(CREATE_READ_WRITE);
-         if ((m_fd = ::open(archive_name.c_str(), mode, st.st_mode)) < 0) {
+         /*
+          * Check for a successful ftruncate() and issue a work-around for devices 
+          * (mostly cheap NAS) that don't support truncation. 
+          * Workaround supplied by Martin Schmid as a solution to bug #1011.
+          * 1. close file
+          * 2. delete file
+          * 3. open new file with same mode
+          * 4. change ownership to original
+          */
+
+         if (fstat(dev->m_fd, &st) != 0) {
             berrno be;
-            dev_errno = errno;
-            Mmsg2(errmsg, _("Could not reopen: %s, ERR=%s\n"), archive_name.c_str(), 
-                  be.bstrerror());
-            Dmsg1(100, "reopen failed: %s", errmsg);
-            Emsg0(M_FATAL, 0, errmsg);
+            Mmsg2(errmsg, _("Unable to stat device %s. ERR=%s\n"), 
+                  print_name(), be.bstrerror());
             return false;
          }
+             
+         if (st.st_size != 0) {             /* ftruncate() didn't work */
+            POOL_MEM archive_name(PM_FNAME);
                    
-         /* Reset proper owner */
-         chown(archive_name.c_str(), st.st_uid, st.st_gid);  
+            pm_strcpy(archive_name, dev_name);
+            if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) {
+               pm_strcat(archive_name, "/");
+            }
+            pm_strcat(archive_name, dcr->VolumeName);
+                      
+            Mmsg2(errmsg, _("Device %s doesn't support ftruncate(). Recreating file %s.\n"), 
+                  print_name(), archive_name.c_str());
+
+            /* Close file and blow it away */
+            ::close(dev->m_fd);
+            ::unlink(archive_name.c_str());
+                      
+            /* Recreate the file -- of course, empty */
+            dev->set_mode(CREATE_READ_WRITE);
+            if ((dev->m_fd = ::open(archive_name.c_str(), mode, st.st_mode)) < 0) {
+               berrno be;
+               dev_errno = errno;
+               Mmsg2(errmsg, _("Could not reopen: %s, ERR=%s\n"), archive_name.c_str(), 
+                     be.bstrerror());
+               Dmsg1(100, "reopen failed: %s", errmsg);
+               Emsg0(M_FATAL, 0, errmsg);
+               return false;
+            }
+                      
+            /* Reset proper owner */
+            chown(archive_name.c_str(), st.st_uid, st.st_gid);  
+         }
+         break;
       }
-          
       return true;
    }
    return false;
@@ -1958,7 +1979,7 @@ bool DEVICE::do_tape_mount(int mount, int dotimeout)
    int status, tries;
    berrno be;
 
-   Dsm_check(1);
+   Dsm_check(200);
    if (mount) {
       icmd = device->mount_command;
    } else {
@@ -1992,7 +2013,7 @@ bool DEVICE::do_tape_mount(int mount, int dotimeout)
       set_mounted(false);
       free_pool_memory(results);
       Dmsg0(200, "============ mount=0\n");
-      Dsm_check(1);
+      Dsm_check(200);
       return false;
    }
 
@@ -2015,7 +2036,7 @@ bool DEVICE::do_file_mount(int mount, int dotimeout)
    int status, tries, name_max, count;
    berrno be;
 
-   Dsm_check(1);
+   Dsm_check(200);
    if (mount) {
       icmd = device->mount_command;
    } else {
@@ -2115,7 +2136,7 @@ get_out:
       set_mounted(false);
       free_pool_memory(results);
       Dmsg0(200, "============ mount=0\n");
-      Dsm_check(1);
+      Dsm_check(200);
       return false;
    }
    
@@ -2284,6 +2305,7 @@ dev_vol_name(DEVICE *dev)
  */
 void DEVICE::term(void)
 {
+   DEVICE *dev = NULL;
    Dmsg1(900, "term dev: %s\n", print_name());
    close();
    if (dev_name) {
@@ -2311,6 +2333,9 @@ void DEVICE::term(void)
       device->dev = NULL;
    }
    delete this;
+   if (dev) {
+      dev->term();
+   }
 }
 
 /*