]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/device.c
bacula-web: Changed header.tpl design and links
[bacula/bacula] / bacula / src / stored / device.c
index c57b9151dc24ecb0e04952b1b27632bbf7e01a84..7cee4a049cda5120a55f5117954fa12aa3e8677b 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 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.
    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.
 
    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.
 
-   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.
 #include "bacula.h"                   /* pull in global headers */
 #include "stored.h"                   /* pull in Storage Deamon headers */
 
-#ifdef SD_DEBUG_LOCK
-const int dbglvl = 0;
-#else
-const int dbglvl = 500;
-#endif
-
-
 /* Forward referenced functions */
 
 /*
@@ -89,7 +82,7 @@ const int dbglvl = 500;
  *  Returns: true  on success
  *           false on failure
  */
-bool fixup_device_block_write_error(DCR *dcr)
+bool fixup_device_block_write_error(DCR *dcr, int retries)
 {
    char PrevVolName[MAX_NAME_LENGTH];
    DEV_BLOCK *label_blk;
@@ -99,16 +92,25 @@ bool fixup_device_block_write_error(DCR *dcr)
    char dt[MAX_TIME_LENGTH];
    JCR *jcr = dcr->jcr;
    DEVICE *dev = dcr->dev;
+   int blocked = dev->blocked();         /* save any previous blocked status */
+   bool ok = false;
 
    wait_time = time(NULL);
 
-   Dmsg0(100, "Enter fixup_device_block_write_error\n");
+   Dmsg0(100, "=== Enter fixup_device_block_write_error\n");
 
+   /*
+    * If we are blocked at entry, unblock it, and set our own block status
+    */
+   if (blocked != BST_NOT_BLOCKED) {
+      unblock_device(dev);
+   }
    block_device(dev, BST_DOING_ACQUIRE);
-   /* Unlock, but leave BLOCKED */
+
+   /* Continue unlocked, but leave BLOCKED */
    dev->dunlock();
 
-   bstrncpy(PrevVolName, dev->VolCatInfo.VolCatName, sizeof(PrevVolName));
+   bstrncpy(PrevVolName, dev->getVolCatName(), sizeof(PrevVolName));
    bstrncpy(dev->VolHdr.PrevVolumeName, PrevVolName, sizeof(dev->VolHdr.PrevVolumeName));
 
    label_blk = new_block(dev);
@@ -120,17 +122,19 @@ bool fixup_device_block_write_error(DCR *dcr)
         edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2),
         bstrftime(dt, sizeof(dt), time(NULL)));
 
-   if (!mount_next_write_volume(dcr, 1)) {
+   Dmsg0(050, "set_unload\n");
+   dev->set_unload();
+   if (!dcr->mount_next_write_volume()) {
       free_block(label_blk);
       dcr->block = block;
       dev->dlock();  
-      unblock_device(dev);
-      return false;                /* device locked */
+      goto bail_out;
    }
+   Dmsg1(050, "must_unload=%d\n", dev->must_unload());
    dev->dlock();                    /* lock again */
 
    dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
-   dir_update_volume_info(dcr, false);        /* send Volume info to Director */
+   dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
 
    Jmsg(jcr, M_INFO, 0, _("New volume \"%s\" mounted on device %s at %s.\n"),
       dcr->VolumeName, dev->print_name(), bstrftime(dt, sizeof(dt), time(NULL)));
@@ -148,8 +152,7 @@ bool fixup_device_block_write_error(DCR *dcr)
         be.bstrerror(dev->dev_errno));
       free_block(label_blk);
       dcr->block = block;
-      unblock_device(dev);
-      return false;                /* device locked */
+      goto bail_out;
    }
    free_block(label_blk);
    dcr->block = block;
@@ -157,7 +160,7 @@ bool fixup_device_block_write_error(DCR *dcr)
    /*
     * Walk through all attached jcrs indicating the volume has changed
     */
-   Dmsg1(100, "Walk attached dcrs. Volume=%s\n", dev->VolCatInfo.VolCatName);
+   Dmsg1(100, "Notify vol change. Volume=%s\n", dev->getVolCatName());
    DCR *mdcr;
    foreach_dlist(mdcr, dev->attached_dcrs) {
       JCR *mjcr = mdcr->jcr;
@@ -180,14 +183,42 @@ bool fixup_device_block_write_error(DCR *dcr)
    Dmsg0(190, "Write overflow block to dev\n");
    if (!write_block_to_dev(dcr)) {
       berrno be;
-      Pmsg1(0, _("write_block_to_device overflow block failed. ERR=%s"),
+      Dmsg1(0, _("write_block_to_device overflow block failed. ERR=%s"),
         be.bstrerror(dev->dev_errno));
-      unblock_device(dev);
-      return false;                /* device locked */
+      /* Note: recursive call */
+      if (retries-- <= 0 || !fixup_device_block_write_error(dcr, retries)) {
+         Jmsg2(jcr, M_FATAL, 0, 
+              _("Catastrophic error. Cannot write overflow block to device %s. ERR=%s"),
+              dev->print_name(), be.bstrerror(dev->dev_errno));
+         goto bail_out;
+      }
    }
+   ok = true;
 
+bail_out:
+   /*
+    * At this point, the device is locked and blocked.
+    * Unblock the device, restore any entry blocked condition, then
+    *   return leaving the device locked (as it was on entry).
+    */
    unblock_device(dev);
-   return true;                             /* device locked */
+   if (blocked != BST_NOT_BLOCKED) {
+      block_device(dev, blocked);
+   }
+   return ok;                               /* device locked */
+}
+
+void set_start_vol_position(DCR *dcr)
+{
+   DEVICE *dev = dcr->dev;
+   /* Set new start position */
+   if (dev->is_tape()) {
+      dcr->StartBlock = dev->block_num;
+      dcr->StartFile = dev->file;
+   } else {
+      dcr->StartBlock = (uint32_t)dev->file_addr;
+      dcr->StartFile  = (uint32_t)(dev->file_addr >> 32);
+   }
 }
 
 /*
@@ -198,24 +229,12 @@ bool fixup_device_block_write_error(DCR *dcr)
 void set_new_volume_parameters(DCR *dcr)
 {
    JCR *jcr = dcr->jcr;
-   DEVICE *dev = dcr->dev;
    if (dcr->NewVol && !dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE)) {
       Jmsg1(jcr, M_ERROR, 0, "%s", jcr->errmsg);
    }
-   /* Set new start/end positions */
-   if (dev->is_tape()) {
-      dcr->StartBlock = dev->block_num;
-      dcr->StartFile = dev->file;
-   } else {
-      dcr->StartBlock = (uint32_t)dev->file_addr;
-      dcr->StartFile  = (uint32_t)(dev->file_addr >> 32);
-   }
-   /* Reset indicies */
-   dcr->VolFirstIndex = 0;
-   dcr->VolLastIndex = 0;
+   set_new_file_parameters(dcr);
    jcr->NumWriteVolumes++;
    dcr->NewVol = false;
-   dcr->WroteVol = false;
 }
 
 /*
@@ -225,16 +244,8 @@ void set_new_volume_parameters(DCR *dcr)
  */
 void set_new_file_parameters(DCR *dcr)
 {
-   DEVICE *dev = dcr->dev;
+   set_start_vol_position(dcr);
 
-   /* Set new start/end positions */
-   if (dev->is_tape()) {
-      dcr->StartBlock = dev->block_num;
-      dcr->StartFile = dev->file;
-   } else {
-      dcr->StartBlock = (uint32_t)dev->file_addr;
-      dcr->StartFile  = (uint32_t)(dev->file_addr >> 32);
-   }
    /* Reset indicies */
    dcr->VolFirstIndex = 0;
    dcr->VolLastIndex = 0;
@@ -322,155 +333,3 @@ bool open_device(DCR *dcr)
    }
    return true;
 }
-
-
-/*
- * Check if the device is blocked or not
- */
-bool is_device_unmounted(DEVICE *dev)
-{
-   bool stat;
-   int blocked = dev->blocked();
-   stat = (blocked == BST_UNMOUNTED) ||
-          (blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
-   return stat;
-}
-
-#ifdef SD_DEBUG_LOCK
-void DEVICE::_dlock(const char *file, int line)
-{
-   Dmsg4(sd_dbglvl, "dlock from %s:%d precnt=%d JobId=%u\n", file, line,
-         m_count, get_jobid_from_tid()); 
-   /* Note, this *really* should be protected by a mutex, but
-    *  since it is only debug code we don't worry too much.  
-    */
-   if (m_count > 0 && pthread_equal(m_pid, pthread_self())) {
-      Dmsg5(sd_dbglvl, "Possible DEADLOCK!! lock held by JobId=%u from %s:%d m_count=%d JobId=%u\n", 
-            get_jobid_from_tid(m_pid),
-            file, line, m_count, get_jobid_from_tid());
-   }
-   P(m_mutex);
-   m_pid = pthread_self();
-   m_count++; 
-}
-
-void DEVICE::_dunlock(const char *file, int line)
-{
-   m_count--; 
-   Dmsg4(sd_dbglvl+1, "dunlock from %s:%d postcnt=%d JobId=%u\n", file, line,
-         m_count, get_jobid_from_tid()); 
-   V(m_mutex);   
-}
-
-void DEVICE::_r_dunlock(const char *file, int line)
-{
-   this->_dunlock(file, line);
-}
-
-#endif
-
-
-/*
- * This is a recursive lock that checks if the device is blocked.
- *
- * When blocked is set, all threads EXCEPT thread with id no_wait_id
- * must wait. The no_wait_id thread is out obtaining a new volume
- * and preparing the label.
- */
-#ifdef SD_DEBUG_LOCK
-void DEVICE::_r_dlock(const char *file, int line)
-#else
-void DEVICE::r_dlock()
-#endif
-{
-   int stat;
-#ifdef SD_DEBUG_LOCK
-   Dmsg4(sd_dbglvl+1, "r_dlock blked=%s from %s:%d JobId=%u\n", this->print_blocked(),
-         file, line, get_jobid_from_tid());
-#else
-   Dmsg1(sd_dbglvl, "reclock blked=%s\n", this->print_blocked());
-#endif
-   this->dlock();   
-   if (this->blocked() && !pthread_equal(this->no_wait_id, pthread_self())) {
-      this->num_waiting++;             /* indicate that I am waiting */
-      while (this->blocked()) {
-         Dmsg3(sd_dbglvl, "r_dlock blked=%s no_wait=%p me=%p\n", this->print_blocked(),
-               this->no_wait_id, pthread_self());
-         if ((stat = pthread_cond_wait(&this->wait, &m_mutex)) != 0) {
-            berrno be;
-            this->dunlock();
-            Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
-               be.bstrerror(stat));
-         }
-      }
-      this->num_waiting--;             /* no longer waiting */
-   }
-}
-
-/*
- * Block all other threads from using the device
- *  Device must already be locked.  After this call,
- *  the device is blocked to any thread calling dev->r_lock(),
- *  but the device is not locked (i.e. no P on device).  Also,
- *  the current thread can do slip through the dev->r_lock()
- *  calls without blocking.
- */
-void _block_device(const char *file, int line, DEVICE *dev, int state)
-{
-   ASSERT(dev->blocked() == BST_NOT_BLOCKED);
-   dev->set_blocked(state);           /* make other threads wait */
-   dev->no_wait_id = pthread_self();  /* allow us to continue */
-   Dmsg3(sd_dbglvl, "set blocked=%s from %s:%d\n", dev->print_blocked(), file, line);
-}
-
-/*
- * Unblock the device, and wake up anyone who went to sleep.
- * Enter: device locked
- * Exit:  device locked
- */
-void _unblock_device(const char *file, int line, DEVICE *dev)
-{
-   Dmsg3(sd_dbglvl, "unblock %s from %s:%d\n", dev->print_blocked(), file, line);
-   ASSERT(dev->blocked());
-   dev->set_blocked(BST_NOT_BLOCKED);
-   dev->no_wait_id = 0;
-   if (dev->num_waiting > 0) {
-      pthread_cond_broadcast(&dev->wait); /* wake them up */
-   }
-}
-
-/*
- * Enter with device locked and blocked
- * Exit with device unlocked and blocked by us.
- */
-void _steal_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state)
-{
-
-   Dmsg3(sd_dbglvl, "steal lock. old=%s from %s:%d\n", dev->print_blocked(),
-      file, line);
-   hold->dev_blocked = dev->blocked();
-   hold->dev_prev_blocked = dev->dev_prev_blocked;
-   hold->no_wait_id = dev->no_wait_id;
-   dev->set_blocked(state);
-   Dmsg1(sd_dbglvl, "steal lock. new=%s\n", dev->print_blocked());
-   dev->no_wait_id = pthread_self();
-   dev->dunlock();
-}
-
-/*
- * Enter with device blocked by us but not locked
- * Exit with device locked, and blocked by previous owner
- */
-void _give_back_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold)
-{
-   Dmsg3(sd_dbglvl, "return lock. old=%s from %s:%d\n",
-      dev->print_blocked(), file, line);
-   dev->dlock();
-   dev->set_blocked(hold->dev_blocked);
-   dev->dev_prev_blocked = hold->dev_prev_blocked;
-   dev->no_wait_id = hold->no_wait_id;
-   Dmsg1(sd_dbglvl, "return lock. new=%s\n", dev->print_blocked());
-   if (dev->num_waiting > 0) {
-      pthread_cond_broadcast(&dev->wait); /* wake them up */
-   }
-}