]> git.sur5r.net Git - bacula/bacula/commitdiff
- Add wait.c (oops forgot previously).
authorKern Sibbald <kern@sibbald.com>
Sat, 26 Mar 2005 14:53:13 +0000 (14:53 +0000)
committerKern Sibbald <kern@sibbald.com>
Sat, 26 Mar 2005 14:53:13 +0000 (14:53 +0000)
- Move all the reserve/acquire_device_for_read/append to have
  only a DCR as the argument.
- Rework the reserve_device_for_append() in stored to wait
  if the drive is not available.  Note! This is a short
  term solution.

git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1900 91ce42f0-d328-0410-95d8-f526ca767f89

12 files changed:
bacula/src/stored/acquire.c
bacula/src/stored/append.c
bacula/src/stored/bcopy.c
bacula/src/stored/btape.c
bacula/src/stored/butil.c
bacula/src/stored/dircmd.c
bacula/src/stored/job.c
bacula/src/stored/mount.c
bacula/src/stored/protos.h
bacula/src/stored/read.c
bacula/src/stored/wait.c [new file with mode: 0644]
bacula/src/version.h

index 83ce8d80a677ec43cd63994d445a9866037aece0..64053c7e566f3a83d862f1cb2e3baead5fab55e4 100644 (file)
@@ -28,6 +28,8 @@
 #include "bacula.h"                   /* pull in global headers */
 #include "stored.h"                   /* pull in Storage Deamon headers */
 
+static int can_reserve_drive(DCR *dcr);
+
 /*
  * Create a new Device Control Record and attach
  *   it to the device (if this is a real job).
@@ -53,8 +55,8 @@ DCR *new_dcr(JCR *jcr, DEVICE *dev)
    dcr->max_spool_size = dev->device->max_spool_size;
    /* Attach this dcr only if dev is initialized */
    if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
-      dev->attached_dcrs->append(dcr);
-//    jcr->dcrs->append(dcr);
+      dev->attached_dcrs->append(dcr); /* attach dcr to device */
+//    jcr->dcrs->append(dcr);        /* put dcr in list for Job */
    }
    return dcr;
 }
@@ -111,8 +113,8 @@ void free_dcr(DCR *dcr)
 
    /* Detach this dcr only if the dev is initialized */
    if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
-      dev->attached_dcrs->remove(dcr);
-//    remove_dcr_from_dcrs(dcr);
+      dev->attached_dcrs->remove(dcr); /* detach dcr from device */
+//    remove_dcr_from_dcrs(dcr);      /* remove dcr from jcr list */
    }
    if (dcr->block) {
       free_block(dcr->block);
@@ -134,9 +136,10 @@ void free_dcr(DCR *dcr)
  *  starting the job. If the device is not available, the DIR
  *  can wait (to be implemented 1/05).
  */
-bool reserve_device_for_read(JCR *jcr, DEVICE *dev)
+bool reserve_device_for_read(DCR *dcr)
 {
-   DCR *dcr = jcr->dcr;
+   DEVICE *dev = dcr->dev;
+   JCR *jcr = dcr->jcr;
    bool first;
 
    ASSERT(dcr);
@@ -179,26 +182,20 @@ bool reserve_device_for_read(JCR *jcr, DEVICE *dev)
  *  Returns: NULL if failed for any reason
  *          dcr  if successful
  */
-DCR *acquire_device_for_read(JCR *jcr, DEVICE *dev)
+DCR *acquire_device_for_read(DCR *dcr)
 {
+   DEVICE *dev = dcr->dev;
+   JCR *jcr = dcr->jcr;
    bool vol_ok = false;
    bool tape_previously_mounted;
    bool tape_initially_mounted;
    VOL_LIST *vol;
    bool try_autochanger = true;
    int i;
-   DCR *dcr = jcr->dcr;
    int vol_label_status;
    
    dev->block(BST_DOING_ACQUIRE);
 
-   init_device_wait_timers(dcr);
-
-   tape_previously_mounted = dev->can_read() ||
-                            dev->can_append() ||
-                            dev->is_labeled();
-   tape_initially_mounted = tape_previously_mounted;
-
    if (dev->num_writers > 0) {
       Jmsg2(jcr, M_FATAL, 0, _("Num_writers=%d not zero. Job %d canceled.\n"), 
         dev->num_writers, jcr->JobId);
@@ -215,8 +212,19 @@ DCR *acquire_device_for_read(JCR *jcr, DEVICE *dev)
    for (i=1; i<jcr->CurVolume; i++) {
       vol = vol->next;
    }
+   if (!vol) {
+      goto get_out;                  /* should not happen */   
+   }
    bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
 
+   init_device_wait_timers(dcr);
+
+   tape_previously_mounted = dev->can_read() ||
+                            dev->can_append() ||
+                            dev->is_labeled();
+   tape_initially_mounted = tape_previously_mounted;
+
+
    /* Volume info is always needed because of VolParts */
    Dmsg0(200, "dir_get_volume_info\n");
    if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
@@ -355,24 +363,71 @@ get_out:
  *  the first tor reserve the device, we put the pool
  *  name and pool type in the device record.
  */
-bool reserve_device_for_append(JCR *jcr, DEVICE *dev)
+bool reserve_device_for_append(DCR *dcr)
 {
-   DCR *dcr = jcr->dcr;
+   JCR *jcr = dcr->jcr;
+   DEVICE *dev = dcr->dev;
    bool ok = false;
+   bool first;
 
    ASSERT(dcr);
-
    dev->block(BST_DOING_ACQUIRE);
-   if (dev->can_read()) {
-      Jmsg(jcr, M_WARNING, 0, _("Device %s is busy reading.\n"), dev->print_name());
-      goto bail_out;
+
+   Mmsg2(jcr->errmsg, _("Device %s is busy reading. Job %d canceled.\n"),
+        dev->print_name(), jcr->JobId);
+   for (first=true; dev->can_read(); first=false) {
+      dev->unblock();
+      if (!wait_for_device(dcr, jcr->errmsg, first)) {
+        return false;
+      }
+      dev->block(BST_DOING_ACQUIRE);
    }
-   if (device_is_unmounted(dev)) {
-      Jmsg(jcr, M_WARNING, 0, _("device %s is BLOCKED due to user unmount.\n"),
-        dev->print_name());
-      goto bail_out;
+
+
+   Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"),
+       dev->print_name());
+   for (first=true; device_is_unmounted(dev); first=false) {
+      dev->unblock();
+      if (!wait_for_device(dcr, jcr->errmsg, first))  {
+        return false;
+      }
+     dev->block(BST_DOING_ACQUIRE);
    }
+
    Dmsg1(190, "reserve_append device is %s\n", dev_is_tape(dev)?"tape":"disk");
+
+   for ( ;; ) {
+      switch (can_reserve_drive(dcr)) {
+      case 0:
+        /* ****FIXME**** Make wait */
+        goto bail_out;
+      case -1:
+        goto bail_out;               /* error */
+      default:
+        break;                       /* OK, reserve drive */
+      }
+      break;
+   }
+
+
+   dev->reserved_device++;
+   dcr->reserved_device = true;
+   ok = true;
+
+bail_out:
+   dev->unblock();
+   return ok;
+}
+
+/*
+ * Returns: 1 if drive can be reserved
+ *         0 if we should wait
+ *        -1 on error
+ */
+static int can_reserve_drive(DCR *dcr) 
+{
+   DEVICE *dev = dcr->dev;
+   JCR *jcr = dcr->jcr;
    /*
     * First handle the case that the drive is not yet in append mode
     */
@@ -386,7 +441,7 @@ bool reserve_device_for_append(JCR *jcr, DEVICE *dev)
         } else {
            /* Drive not suitable for us */
             Jmsg(jcr, M_WARNING, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
-           goto bail_out;
+           return 0;                 /* wait */
         }
       } else {
         /* Device is available but not yet reserved, reserve it for us */
@@ -394,7 +449,7 @@ bool reserve_device_for_append(JCR *jcr, DEVICE *dev)
         bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
         dev->PoolId = dcr->PoolId;
       }
-      goto do_reserve;
+      return 1;                      /* reserve drive */
    }
 
    /*
@@ -409,21 +464,14 @@ bool reserve_device_for_append(JCR *jcr, DEVICE *dev)
       } else {
         /* Drive not suitable for us */
          Jmsg(jcr, M_WARNING, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
-        goto bail_out;
+        return 0;                    /* wait */
       }
    } else {
       Pmsg0(000, "Logic error!!!! Should not get here.\n");
-      goto bail_out;                 /* should not get here */
+      Jmsg0(jcr, M_FATAL, 0, _("Logic error!!!! Should not get here.\n"));
+      return -1;                     /* error, should not get here */
    }
-
-do_reserve:
-   dev->reserved_device++;
-   dcr->reserved_device = true;
-   ok = true;
-
-bail_out:
-   dev->unblock();
-   return ok;
+   return 1;                         /* reserve drive */
 }
 
 /*
@@ -435,16 +483,14 @@ bail_out:
  *   Note, normally reserve_device_for_append() is called
  *   before this routine.
  */
-DCR *acquire_device_for_append(JCR *jcr, DEVICE *dev)
+DCR *acquire_device_for_append(DCR *dcr)
 {
    bool release = false;
    bool recycle = false;
    bool do_mount = false;
-   DCR *dcr = jcr->dcr;
+   DEVICE *dev = dcr->dev;
+   JCR *jcr = dcr->jcr;
 
-   if (!dcr) {
-      dcr = new_dcr(jcr, dev);
-   }
    dev->block(BST_DOING_ACQUIRE);
    Dmsg1(190, "acquire_append device is %s\n", dev_is_tape(dev)?"tape":"disk");
 
index 877c0a671c8a23c719484ef731d01d7a58cdcce4..40db5cd2bbc993c687292650aacad6f0fb04dc62 100644 (file)
@@ -61,7 +61,7 @@ bool do_append_data(JCR *jcr)
       return false;
    }
 
-   if (!acquire_device_for_append(jcr, dev)) {
+   if (!acquire_device_for_append(dcr)) {
       set_jcr_job_status(jcr, JS_ErrorTerminated);
       return false;
    }
index 8a6b7bd35c6a33b444675bcd9d09f51db87f905a..74ef4b640c75cec253b289ef5b14d0a8ed33ca3f 100644 (file)
@@ -172,7 +172,7 @@ int main (int argc, char *argv[])
       exit(1);
    }
    unlock_device(out_dev);
-   if (!acquire_device_for_append(out_jcr, out_dev)) {
+   if (!acquire_device_for_append(out_jcr->dcr)) {
       free_jcr(in_jcr);
       exit(1);
    }
index 72baeb5ec58c6437237f894671692e0d86b31059..b1e257489b8a8f25a15cc2a0faaead389ff83cb9 100644 (file)
@@ -336,7 +336,7 @@ static bool open_the_device()
       }
    }
    Pmsg1(000, "open_dev %s OK\n", dev->print_name());
-   dev->state |= ST_APPEND;
+   dev->set_append();                /* put volume in append mode */
    unlock_device(dev);
    free_block(block);
    return true;
@@ -1794,7 +1794,7 @@ static void fillcmd()
     *  subroutine.
     */
    Dmsg0(100, "just before acquire_device\n");
-   if (!acquire_device_for_append(jcr, dev)) {
+   if (!acquire_device_for_append(dcr)) {
       set_jcr_job_status(jcr, JS_ErrorTerminated);
       return;
    }
@@ -2058,7 +2058,7 @@ static void do_unfill()
       close_dev(dev);
       dev->state &= ~(ST_READ|ST_APPEND);
       dev->num_writers = 0;
-      if (!acquire_device_for_read(jcr, dev)) {
+      if (!acquire_device_for_read(dcr)) {
          Pmsg1(-1, "%s", dev->errmsg);
         goto bail_out;
       }
@@ -2118,8 +2118,8 @@ static void do_unfill()
       get_cmd(_("Mount second tape. Press enter when ready: "));
    }
 
-   dev->state &= ~ST_READ;
-   if (!acquire_device_for_read(jcr, dev)) {
+   dev->clear_read();
+   if (!acquire_device_for_read(dcr)) {
       Pmsg1(-1, "%s", dev->errmsg);
       goto bail_out;
    }
@@ -2697,8 +2697,8 @@ static bool my_mount_next_read_volume(DCR *dcr)
    jcr->bsr = NULL;
    create_vol_list(jcr);
    close_dev(dev);
-   dev->state &= ~ST_READ;
-   if (!acquire_device_for_read(jcr, dev)) {
+   dev->clear_read();
+   if (!acquire_device_for_read(dcr)) {
       Pmsg2(0, "Cannot open Dev=%s, Vol=%s\n", dev->print_name(), dcr->VolumeName);
       return false;
    }
index 619e69909ccd654050cc0bb52e97d6b4f0063118..47b42a51468e1c802b693419d9e6973fadb7eac3 100644 (file)
@@ -171,7 +171,7 @@ static DCR *setup_to_access_device(JCR *jcr, char *dev_name, const char *VolumeN
    create_vol_list(jcr);
 
    if (mode) {                       /* read only access? */
-      if (!acquire_device_for_read(jcr, dev)) {
+      if (!acquire_device_for_read(dcr)) {
         return NULL;
       }
    }
index 356f12d8836c808fa2b7cf5de9570a594b5d91e7..da15d3f943e1d936b6a8071518e9f1e1b49c0b9f 100644 (file)
@@ -452,7 +452,7 @@ static bool read_label(DCR *dcr)
    steal_device_lock(dev, &hold, BST_DOING_ACQUIRE);
 
    dcr->VolumeName[0] = 0;
-   dev->state &= ~ST_LABEL;          /* force read of label */
+   dev->clear_labeled();             /* force read of label */
    switch (read_dev_volume_label(dcr)) {
    case VOL_OK:
       bnet_fsend(dir, _("3001 Mounted Volume: %s\n"), dev->VolHdr.VolName);
@@ -878,7 +878,7 @@ static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot)
       goto bail_out;                 /* error */
    }
 
-   dev->state &= ~ST_LABEL;          /* force read of label */
+   dev->clear_labeled();             /* force read of label */
    switch (read_dev_volume_label(dcr)) {
    case VOL_OK:
       /* DO NOT add quotes around the Volume name. It is scanned in the DIR */
index a6600c2ab16a2ef6282af8642a0262920b65a1f5..6c2ae1a454d64cf9862f353f5aba986ec33ca14a 100644 (file)
@@ -311,9 +311,9 @@ static bool use_device_cmd(JCR *jcr)
            dcr->PoolId = PoolId;
            jcr->dcr = dcr;
            if (append == SD_APPEND) {
-              ok = reserve_device_for_append(jcr, device->dev);
+              ok = reserve_device_for_append(dcr);
            } else {
-              ok = reserve_device_for_read(jcr, device->dev);
+              ok = reserve_device_for_read(dcr);
            }
            if (!ok) {
                bnet_fsend(dir, _("3927 Could not reserve device: %s\n"), dev_name.c_str());
@@ -364,9 +364,9 @@ static bool use_device_cmd(JCR *jcr)
               bstrncpy(dcr->dev_name, dev_name, name_len);
               jcr->dcr = dcr;
               if (append == SD_APPEND) {
-                 ok = reserve_device_for_append(jcr, device->dev);
+                 ok = reserve_device_for_append(dcr);
               } else {
-                 ok = reserve_device_for_read(jcr, device->dev);
+                 ok = reserve_device_for_read(dcr);
               }
               if (!ok) {
                   Jmsg(jcr, M_WARNING, 0, _("Could not reserve device: %s\n"), dev_name.c_str());
index 7b0c0e672d2bb369c64a1644b6a76a9a7a808d86..0cf2ce80a4ab0515071fb2f4f2ae7138ba53b8b5 100644 (file)
@@ -407,7 +407,7 @@ bool mount_next_read_volume(DCR *dcr)
    if (jcr->NumVolumes > 1 && jcr->CurVolume < jcr->NumVolumes) {
       close_dev(dev);
       dev->clear_read();
-      if (!acquire_device_for_read(jcr, dev)) {
+      if (!acquire_device_for_read(dcr)) {
          Jmsg2(jcr, M_FATAL, 0, "Cannot open Dev=%s, Vol=%s\n", dev->print_name(),
               dcr->VolumeName);
         return false;
index fc3b9999e4a0e5a64afcb80a8f84cb6a68d9b982..4e64cc54c71a0a9122ebed9832ec16660ec182c5 100644 (file)
 uint32_t new_VolSessionId();
 
 /* From acquire.c */
-bool     reserve_device_for_append(JCR *jcr, DEVICE *dev);
-DCR     *acquire_device_for_append(JCR *jcr, DEVICE *dev);
-bool     reserve_device_for_read(JCR *jcr, DEVICE *dev);
-DCR     *acquire_device_for_read(JCR *jcr, DEVICE *dev);
+bool     reserve_device_for_append(DCR *dcr);
+DCR     *acquire_device_for_append(DCR *dcr);
+bool     reserve_device_for_read(DCR *dcr);
+DCR     *acquire_device_for_read(DCR *dcr);
 bool     release_device(DCR *dcr);
 DCR     *new_dcr(JCR *jcr, DEVICE *dev);
 void     free_dcr(DCR *dcr);
index b6f5525c07eea1215cb05fa3bea84c97aad21107..7b3569d6051c0acec5f62066098b6a1638767890 100644 (file)
@@ -67,7 +67,7 @@ bool do_read_data(JCR *jcr)
       jcr->VolList->VolumeName);
 
    /* Ready device for reading */
-   if (!acquire_device_for_read(jcr, dcr->dev)) {
+   if (!acquire_device_for_read(dcr)) {
       free_vol_list(jcr);
       bnet_fsend(fd, FD_error);
       return false;
diff --git a/bacula/src/stored/wait.c b/bacula/src/stored/wait.c
new file mode 100644 (file)
index 0000000..92d7fd0
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ *  Subroutines to handle waiting for operator intervention
+ *   or waiting for a Device to be released
+ *
+ *  Code for wait_for_sysop() pulled from askdir.c
+ *
+ *   Kern Sibbald, March 2005
+ *
+ *   Version $Id$
+ */
+/*
+   Copyright (C) 2000-2005 Kern Sibbald
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   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 along with this program; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.
+
+ */
+
+#include "bacula.h"                   /* pull in global headers */
+#include "stored.h"                   /* pull in Storage Deamon headers */
+
+static bool double_jcr_wait_time(JCR *jcr);
+
+
+/*
+ * Wait for SysOp to mount a tape on a specific device
+ *
+ *   Returns: status from pthread_cond_timedwait() 
+ */
+int wait_for_sysop(DCR *dcr)
+{
+   struct timeval tv;
+   struct timezone tz;
+   struct timespec timeout;
+   time_t last_heartbeat = 0;
+   time_t first_start = time(NULL);
+   int stat = 0;
+   int add_wait;
+   bool unmounted;
+   DEVICE *dev = dcr->dev;
+   JCR *jcr = dcr->jcr;
+
+   P(dev->mutex);
+   unmounted = (dev->dev_blocked == BST_UNMOUNTED) ||
+               (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
+
+   dev->poll = false;
+   /*
+    * Wait requested time (dev->rem_wait_sec). However, we also wake up every
+    *   HB_TIME seconds and send a heartbeat to the FD and the Director
+    *   to keep stateful firewalls from closing them down while waiting
+    *   for the operator.
+    */
+   add_wait = dev->rem_wait_sec;
+   if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
+      add_wait = me->heartbeat_interval;
+   }
+   /* If the user did not unmount the tape and we are polling, ensure
+    *  that we poll at the correct interval.
+    */
+   if (!unmounted && dev->vol_poll_interval && add_wait > dev->vol_poll_interval) {
+      add_wait = dev->vol_poll_interval;
+   }
+
+   if (!unmounted) {
+      dev->dev_prev_blocked = dev->dev_blocked;
+      dev->dev_blocked = BST_WAITING_FOR_SYSOP; /* indicate waiting for mount */
+   }
+
+   for ( ; !job_canceled(jcr); ) {
+      time_t now, start;
+
+      gettimeofday(&tv, &tz);
+      timeout.tv_nsec = tv.tv_usec * 1000;
+      timeout.tv_sec = tv.tv_sec + add_wait;
+
+      Dmsg3(400, "I'm going to sleep on device %s. HB=%d wait=%d\n", dev->print_name(),
+        (int)me->heartbeat_interval, dev->wait_sec);
+      start = time(NULL);
+      /* Wait required time */
+      stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->mutex, &timeout);
+      Dmsg1(400, "Wokeup from sleep on device stat=%d\n", stat);
+
+      now = time(NULL);
+      dev->rem_wait_sec -= (now - start);
+
+      /* Note, this always triggers the first time. We want that. */
+      if (me->heartbeat_interval) {
+        if (now - last_heartbeat >= me->heartbeat_interval) {
+           /* send heartbeats */
+           if (jcr->file_bsock) {
+              bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
+               Dmsg0(400, "Send heartbeat to FD.\n");
+           }
+           if (jcr->dir_bsock) {
+              bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
+           }
+           last_heartbeat = now;
+        }
+      }
+
+      /*
+       * Check if user unmounted the device while we were waiting
+       */
+      unmounted = (dev->dev_blocked == BST_UNMOUNTED) ||
+                  (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
+
+      if (stat != ETIMEDOUT) {    /* we blocked the device */
+        break;                    /* on error return */
+      }
+      if (dev->rem_wait_sec <= 0) {  /* on exceeding wait time return */
+         Dmsg0(400, "Exceed wait time.\n");
+        break;
+      }
+
+      if (!unmounted && dev->vol_poll_interval &&
+         (now - first_start >= dev->vol_poll_interval)) {
+         Dmsg1(400, "In wait blocked=%s\n", edit_blocked_reason(dev));
+        dev->poll = true;            /* returning a poll event */
+        break;
+      }
+      /*
+       * Check if user mounted the device while we were waiting
+       */
+      if (dev->dev_blocked == BST_MOUNT) {   /* mount request ? */
+        stat = 0;
+        break;
+      }
+
+      add_wait = dev->wait_sec - (now - start);
+      if (add_wait < 0) {
+        add_wait = 0;
+      }
+      if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
+        add_wait = me->heartbeat_interval;
+      }
+   }
+
+   if (!unmounted) {
+      dev->dev_blocked = dev->dev_prev_blocked;    /* restore entry state */
+   }
+   V(dev->mutex);
+   return stat;
+}
+
+
+/*
+ * Wait for Device to be released
+ *
+ */
+bool wait_for_device(DCR *dcr, const char *msg, bool first)
+{
+   struct timeval tv;
+   struct timezone tz;
+   struct timespec timeout;
+// time_t last_heartbeat = 0;
+   int stat = 0;
+   int add_wait;
+   DEVICE *dev = dcr->dev;
+   JCR *jcr = dcr->jcr;
+   bool ok = false;
+
+   P(device_release_mutex);
+
+   if (first) {
+      Jmsg(jcr, M_MOUNT, 0, msg);
+   }
+
+   /*
+    * Wait requested time (dev->rem_wait_sec). However, we also wake up every
+    *   HB_TIME seconds and send a heartbeat to the FD and the Director
+    *   to keep stateful firewalls from closing them down while waiting
+    *   for the operator.
+    */
+   add_wait = jcr->rem_wait_sec;
+   if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
+      add_wait = me->heartbeat_interval;
+   }
+
+   for ( ; !job_canceled(jcr); ) {
+      time_t now, start;
+
+      gettimeofday(&tv, &tz);
+      timeout.tv_nsec = tv.tv_usec * 1000;
+      timeout.tv_sec = tv.tv_sec + add_wait;
+
+      Dmsg3(000, "I'm going to sleep on device %s. HB=%d wait=%d\n", dev->print_name(),
+        (int)me->heartbeat_interval, dev->wait_sec);
+      start = time(NULL);
+      /* Wait required time */
+      stat = pthread_cond_timedwait(&wait_device_release, &device_release_mutex, &timeout);
+      Dmsg1(000, "Wokeup from sleep on device stat=%d\n", stat);
+
+      now = time(NULL);
+      jcr->rem_wait_sec -= (now - start);
+
+#ifdef needed
+      /* Note, this always triggers the first time. We want that. */
+      if (me->heartbeat_interval) {
+        if (now - last_heartbeat >= me->heartbeat_interval) {
+           /* send heartbeats */
+           if (jcr->file_bsock) {
+              bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
+               Dmsg0(400, "Send heartbeat to FD.\n");
+           }
+           if (jcr->dir_bsock) {
+              bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
+           }
+           last_heartbeat = now;
+        }
+      }
+#endif
+
+      if (stat != ETIMEDOUT) {    /* if someone woke us up */
+        ok = true;
+        break;                    /* allow caller to examine device */
+      }
+      if (jcr->rem_wait_sec <= 0) {  /* on exceeding wait time return */
+         Dmsg0(400, "Exceed wait time.\n");
+        if (!double_jcr_wait_time(jcr)) {
+           break;                 /* give up */
+        }
+        Jmsg(jcr, M_MOUNT, 0, msg);
+      }
+
+      add_wait = jcr->wait_sec - (now - start);
+      if (add_wait < 0) {
+        add_wait = 0;
+      }
+      if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
+        add_wait = me->heartbeat_interval;
+      }
+   }
+
+   V(device_release_mutex);
+   Dmsg1(000, "Return from wait_device ok=%d\n", ok);
+   return ok;
+}
+
+/*
+ * The jcr timers are used for waiting on any device
+ *
+ * Returns: true if time doubled
+ *         false if max time expired
+ */
+static bool double_jcr_wait_time(JCR *jcr)
+{
+   jcr->wait_sec *= 2;              /* double wait time */
+   if (jcr->wait_sec > jcr->max_wait) {   /* but not longer than maxtime */
+      jcr->wait_sec = jcr->max_wait;
+   }
+   jcr->num_wait++;
+   jcr->rem_wait_sec = jcr->wait_sec;
+   if (jcr->num_wait >= jcr->max_num_wait) {
+      return false;
+   }
+   return true;
+}
index c855e405c7cbed27956cf92e4469c0b9d0d9326b..78b66093c2752e0dcef3dd67bffeecd42fe26bee 100644 (file)
@@ -1,8 +1,8 @@
 /* */
 #undef  VERSION
 #define VERSION "1.37.8"
-#define BDATE   "25 March 2005"
-#define LSMDATE "25Mar05"
+#define BDATE   "26 March 2005"
+#define LSMDATE "26Mar05"
 
 /* Debug flags */
 #undef  DEBUG