2 * Subroutines to handle waiting for operator intervention
3 * or waiting for a Device to be released
5 * Code for wait_for_sysop() pulled from askdir.c
7 * Kern Sibbald, March 2005
12 Copyright (C) 2000-2006 Kern Sibbald
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License
16 version 2 as amended with additional clauses defined in the
17 file LICENSE in the main source directory.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 the file LICENSE for additional details.
26 #include "bacula.h" /* pull in global headers */
27 #include "stored.h" /* pull in Storage Deamon headers */
29 //static bool double_jcr_wait_time(JCR *jcr);
33 * Wait for SysOp to mount a tape on a specific device
35 * Returns: W_ERROR, W_TIMEOUT, W_POLL, W_MOUNT, or W_WAKE
37 int wait_for_sysop(DCR *dcr)
41 struct timespec timeout;
42 time_t last_heartbeat = 0;
43 time_t first_start = time(NULL);
47 DEVICE *dev = dcr->dev;
51 Dmsg1(100, "Enter blocked=%s\n", dev->print_blocked());
52 unmounted = is_device_unmounted(dev);
56 * Wait requested time (dev->rem_wait_sec). However, we also wake up every
57 * HB_TIME seconds and send a heartbeat to the FD and the Director
58 * to keep stateful firewalls from closing them down while waiting
61 add_wait = dev->rem_wait_sec;
62 if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
63 add_wait = me->heartbeat_interval;
65 /* If the user did not unmount the tape and we are polling, ensure
66 * that we poll at the correct interval.
68 if (!unmounted && dev->vol_poll_interval && add_wait > dev->vol_poll_interval) {
69 add_wait = dev->vol_poll_interval;
73 Dmsg1(400, "blocked=%s\n", dev->print_blocked());
74 dev->dev_prev_blocked = dev->dev_blocked;
75 dev->set_blocked(BST_WAITING_FOR_SYSOP); /* indicate waiting for mount */
78 for ( ; !job_canceled(jcr); ) {
81 gettimeofday(&tv, &tz);
82 timeout.tv_nsec = tv.tv_usec * 1000;
83 timeout.tv_sec = tv.tv_sec + add_wait;
85 Dmsg4(400, "I'm going to sleep on device %s. HB=%d wait=%d add_wait=%d\n",
86 dev->print_name(), (int)me->heartbeat_interval, dev->wait_sec, add_wait);
88 /* Wait required time */
89 stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->mutex, &timeout);
90 Dmsg2(400, "Wokeup from sleep on device stat=%d blocked=%s\n", stat,
91 dev->print_blocked());
94 dev->rem_wait_sec -= (now - start);
96 /* Note, this always triggers the first time. We want that. */
97 if (me->heartbeat_interval) {
98 if (now - last_heartbeat >= me->heartbeat_interval) {
100 if (jcr->file_bsock) {
101 bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
102 Dmsg0(400, "Send heartbeat to FD.\n");
104 if (jcr->dir_bsock) {
105 bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
107 last_heartbeat = now;
111 if (stat == EINVAL) {
113 Dmsg1(000, "pthread stat=%d\n", stat);
114 Jmsg1(jcr, M_FATAL, 0, _("pthread timedwait error. ERR=%s\n"), be.strerror(stat));
115 stat = W_ERROR; /* error */
120 if (dev->rem_wait_sec <= 0) { /* on exceeding wait time return */
121 Dmsg0(400, "Exceed wait time.\n");
127 * Check if user unmounted the device while we were waiting
129 unmounted = is_device_unmounted(dev);
131 if (!unmounted && dev->vol_poll_interval &&
132 (now - first_start >= dev->vol_poll_interval)) {
133 Dmsg1(400, "In wait blocked=%s\n", dev->print_blocked());
134 dev->poll = true; /* returning a poll event */
139 * Check if user mounted the device while we were waiting
141 if (dev->get_blocked() == BST_MOUNT) { /* mount request ? */
147 * If we did not timeout, then some event happened, so
148 * return to check if state changed.
151 stat = W_WAKE; /* someone woke us */
156 * At this point, we know we woke up because of a timeout,
157 * that was due to a heartbeat, so we just update
158 * the wait counters and continue.
160 add_wait = dev->wait_sec - (now - start);
164 if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
165 add_wait = me->heartbeat_interval;
170 dev->set_blocked(dev->dev_prev_blocked); /* restore entry state */
171 Dmsg1(400, "set %s\n", dev->print_blocked());
173 Dmsg1(400, "Exit blocked=%s\n", dev->print_blocked());
180 * Wait for any device to be released, then we return, so
181 * higher level code can rescan possible devices.
183 * Returns: true if a device has changed state
184 * false if the total wait time has expired.
186 bool wait_for_device(JCR *jcr, bool first)
190 struct timespec timeout;
193 const int wait_time = 5 * 60; /* wait 5 minutes */
195 Dmsg0(100, "Enter wait_for_device\n");
196 P(device_release_mutex);
199 Jmsg(jcr, M_MOUNT, 0, _("Job %s waiting to reserve a device.\n"), jcr->Job);
202 gettimeofday(&tv, &tz);
203 timeout.tv_nsec = tv.tv_usec * 1000;
204 timeout.tv_sec = tv.tv_sec + wait_time;
206 Dmsg0(100, "I'm going to wait for a device.\n");
208 /* Wait required time */
209 stat = pthread_cond_timedwait(&wait_device_release, &device_release_mutex, &timeout);
210 Dmsg1(100, "Wokeup from sleep on device stat=%d\n", stat);
213 V(device_release_mutex);
214 Dmsg1(100, "Return from wait_device ok=%d\n", ok);
220 * The jcr timers are used for waiting on any device *
221 * Returns: true if time doubled
222 * false if max time expired
224 static bool double_jcr_wait_time(JCR *jcr)
226 jcr->wait_sec *= 2; /* double wait time */
227 if (jcr->wait_sec > jcr->max_wait) { /* but not longer than maxtime */
228 jcr->wait_sec = jcr->max_wait;
231 jcr->rem_wait_sec = jcr->wait_sec;
232 if (jcr->num_wait >= jcr->max_num_wait) {