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-2005 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 as
16 published by the Free Software Foundation; either version 2 of
17 the License, or (at your option) any later version.
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 GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public
25 License along with this program; if not, write to the Free
26 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
31 #include "bacula.h" /* pull in global headers */
32 #include "stored.h" /* pull in Storage Deamon headers */
34 static bool double_jcr_wait_time(JCR *jcr);
38 * Wait for SysOp to mount a tape on a specific device
40 * Returns: status from pthread_cond_timedwait()
42 int wait_for_sysop(DCR *dcr)
46 struct timespec timeout;
47 time_t last_heartbeat = 0;
48 time_t first_start = time(NULL);
52 DEVICE *dev = dcr->dev;
56 unmounted = (dev->dev_blocked == BST_UNMOUNTED) ||
57 (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
61 * Wait requested time (dev->rem_wait_sec). However, we also wake up every
62 * HB_TIME seconds and send a heartbeat to the FD and the Director
63 * to keep stateful firewalls from closing them down while waiting
66 add_wait = dev->rem_wait_sec;
67 if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
68 add_wait = me->heartbeat_interval;
70 /* If the user did not unmount the tape and we are polling, ensure
71 * that we poll at the correct interval.
73 if (!unmounted && dev->vol_poll_interval && add_wait > dev->vol_poll_interval) {
74 add_wait = dev->vol_poll_interval;
78 dev->dev_prev_blocked = dev->dev_blocked;
79 dev->dev_blocked = BST_WAITING_FOR_SYSOP; /* indicate waiting for mount */
82 for ( ; !job_canceled(jcr); ) {
85 gettimeofday(&tv, &tz);
86 timeout.tv_nsec = tv.tv_usec * 1000;
87 timeout.tv_sec = tv.tv_sec + add_wait;
89 Dmsg3(400, "I'm going to sleep on device %s. HB=%d wait=%d\n", dev->print_name(),
90 (int)me->heartbeat_interval, dev->wait_sec);
92 /* Wait required time */
93 stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->mutex, &timeout);
94 Dmsg1(400, "Wokeup from sleep on device stat=%d\n", stat);
97 dev->rem_wait_sec -= (now - start);
99 /* Note, this always triggers the first time. We want that. */
100 if (me->heartbeat_interval) {
101 if (now - last_heartbeat >= me->heartbeat_interval) {
102 /* send heartbeats */
103 if (jcr->file_bsock) {
104 bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
105 Dmsg0(400, "Send heartbeat to FD.\n");
107 if (jcr->dir_bsock) {
108 bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
110 last_heartbeat = now;
115 * Check if user unmounted the device while we were waiting
117 unmounted = (dev->dev_blocked == BST_UNMOUNTED) ||
118 (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
120 if (stat != ETIMEDOUT) { /* we blocked the device */
121 break; /* on error return */
123 if (dev->rem_wait_sec <= 0) { /* on exceeding wait time return */
124 Dmsg0(400, "Exceed wait time.\n");
128 if (!unmounted && dev->vol_poll_interval &&
129 (now - first_start >= dev->vol_poll_interval)) {
130 Dmsg1(400, "In wait blocked=%s\n", edit_blocked_reason(dev));
131 dev->poll = true; /* returning a poll event */
135 * Check if user mounted the device while we were waiting
137 if (dev->dev_blocked == BST_MOUNT) { /* mount request ? */
142 add_wait = dev->wait_sec - (now - start);
146 if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
147 add_wait = me->heartbeat_interval;
152 dev->dev_blocked = dev->dev_prev_blocked; /* restore entry state */
160 * Wait for Device to be released
163 bool wait_for_device(DCR *dcr, const char *msg, bool first)
167 struct timespec timeout;
168 // time_t last_heartbeat = 0;
171 DEVICE *dev = dcr->dev;
175 P(device_release_mutex);
178 Jmsg(jcr, M_MOUNT, 0, msg);
182 * Wait requested time (dev->rem_wait_sec). However, we also wake up every
183 * HB_TIME seconds and send a heartbeat to the FD and the Director
184 * to keep stateful firewalls from closing them down while waiting
187 add_wait = jcr->rem_wait_sec;
188 if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
189 add_wait = me->heartbeat_interval;
192 for ( ; !job_canceled(jcr); ) {
195 gettimeofday(&tv, &tz);
196 timeout.tv_nsec = tv.tv_usec * 1000;
197 timeout.tv_sec = tv.tv_sec + add_wait;
199 Dmsg3(000, "I'm going to sleep on device %s. HB=%d wait=%d\n", dev->print_name(),
200 (int)me->heartbeat_interval, dev->wait_sec);
202 /* Wait required time */
203 stat = pthread_cond_timedwait(&wait_device_release, &device_release_mutex, &timeout);
204 Dmsg1(000, "Wokeup from sleep on device stat=%d\n", stat);
207 jcr->rem_wait_sec -= (now - start);
210 /* Note, this always triggers the first time. We want that. */
211 if (me->heartbeat_interval) {
212 if (now - last_heartbeat >= me->heartbeat_interval) {
213 /* send heartbeats */
214 if (jcr->file_bsock) {
215 bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
216 Dmsg0(400, "Send heartbeat to FD.\n");
218 if (jcr->dir_bsock) {
219 bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
221 last_heartbeat = now;
226 if (stat != ETIMEDOUT) { /* if someone woke us up */
228 break; /* allow caller to examine device */
230 if (jcr->rem_wait_sec <= 0) { /* on exceeding wait time return */
231 Dmsg0(400, "Exceed wait time.\n");
232 if (!double_jcr_wait_time(jcr)) {
235 Jmsg(jcr, M_MOUNT, 0, msg);
238 add_wait = jcr->wait_sec - (now - start);
242 if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
243 add_wait = me->heartbeat_interval;
247 V(device_release_mutex);
248 Dmsg1(000, "Return from wait_device ok=%d\n", ok);
253 * The jcr timers are used for waiting on any device
255 * Returns: true if time doubled
256 * false if max time expired
258 static bool double_jcr_wait_time(JCR *jcr)
260 jcr->wait_sec *= 2; /* double wait time */
261 if (jcr->wait_sec > jcr->max_wait) { /* but not longer than maxtime */
262 jcr->wait_sec = jcr->max_wait;
265 jcr->rem_wait_sec = jcr->wait_sec;
266 if (jcr->num_wait >= jcr->max_num_wait) {