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
16 version 2 as ammended 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: status from pthread_cond_timedwait()
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 unmounted = (dev->dev_blocked == BST_UNMOUNTED) ||
52 (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
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 dev->dev_prev_blocked = dev->dev_blocked;
74 dev->set_blocked(BST_WAITING_FOR_SYSOP); /* indicate waiting for mount */
77 for ( ; !job_canceled(jcr); ) {
80 gettimeofday(&tv, &tz);
81 timeout.tv_nsec = tv.tv_usec * 1000;
82 timeout.tv_sec = tv.tv_sec + add_wait;
84 Dmsg3(400, "I'm going to sleep on device %s. HB=%d wait=%d\n", dev->print_name(),
85 (int)me->heartbeat_interval, dev->wait_sec);
87 /* Wait required time */
88 stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->mutex, &timeout);
89 Dmsg1(400, "Wokeup from sleep on device stat=%d\n", stat);
92 dev->rem_wait_sec -= (now - start);
94 /* Note, this always triggers the first time. We want that. */
95 if (me->heartbeat_interval) {
96 if (now - last_heartbeat >= me->heartbeat_interval) {
98 if (jcr->file_bsock) {
99 bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
100 Dmsg0(400, "Send heartbeat to FD.\n");
102 if (jcr->dir_bsock) {
103 bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
105 last_heartbeat = now;
110 * Check if user unmounted the device while we were waiting
112 unmounted = (dev->dev_blocked == BST_UNMOUNTED) ||
113 (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
115 if (stat != ETIMEDOUT) { /* we blocked the device */
116 break; /* on error return */
118 if (dev->rem_wait_sec <= 0) { /* on exceeding wait time return */
119 Dmsg0(400, "Exceed wait time.\n");
123 if (!unmounted && dev->vol_poll_interval &&
124 (now - first_start >= dev->vol_poll_interval)) {
125 Dmsg1(400, "In wait blocked=%s\n", edit_blocked_reason(dev));
126 dev->poll = true; /* returning a poll event */
130 * Check if user mounted the device while we were waiting
132 if (dev->dev_blocked == BST_MOUNT) { /* mount request ? */
137 add_wait = dev->wait_sec - (now - start);
141 if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
142 add_wait = me->heartbeat_interval;
147 dev->set_blocked(dev->dev_prev_blocked); /* restore entry state */
155 * Wait for any device to be released, then we return, so
156 * higher level code can rescan possible devices.
158 * Returns: true if a device has changed state
159 * false if the total wait time has expired.
161 bool wait_for_device(JCR *jcr, bool first)
165 struct timespec timeout;
166 // time_t last_heartbeat = 0;
171 Dmsg0(100, "Enter wait_for_device\n");
172 P(device_release_mutex);
175 Jmsg(jcr, M_MOUNT, 0, _("Job %s waiting to reserve a device.\n"), jcr->Job);
179 * Wait requested time (dev->rem_wait_sec). However, we also wake up every
180 * HB_TIME seconds and send a heartbeat to the FD and the Director
181 * to keep stateful firewalls from closing them down while waiting
184 add_wait = jcr->rem_wait_sec;
185 if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
186 add_wait = me->heartbeat_interval;
189 for ( ; !job_canceled(jcr); ) {
192 gettimeofday(&tv, &tz);
193 timeout.tv_nsec = tv.tv_usec * 1000;
194 timeout.tv_sec = tv.tv_sec + add_wait;
196 Dmsg3(100, "I'm going to wait for a device. HB=%d wait=%d remwait=%d\n",
197 (int)me->heartbeat_interval, jcr->wait_sec, jcr->rem_wait_sec);
199 /* Wait required time */
200 stat = pthread_cond_timedwait(&wait_device_release, &device_release_mutex, &timeout);
201 Dmsg1(100, "Wokeup from sleep on device stat=%d\n", stat);
204 jcr->rem_wait_sec -= (now - start);
207 /* Note, this always triggers the first time. We want that. */
208 if (me->heartbeat_interval) {
209 if (now - last_heartbeat >= me->heartbeat_interval) {
210 /* send heartbeats */
211 if (jcr->file_bsock) {
212 bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
213 Dmsg0(400, "Send heartbeat to FD.\n");
215 if (jcr->dir_bsock) {
216 bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
218 last_heartbeat = now;
223 if (stat != ETIMEDOUT) { /* if someone woke us up */
225 break; /* allow caller to examine device */
227 if (jcr->rem_wait_sec <= 0) { /* on exceeding wait time return */
228 Dmsg0(400, "Exceed wait time.\n");
229 if (!double_jcr_wait_time(jcr)) {
232 Jmsg(jcr, M_MOUNT, 0, _("Job %s waiting to reserve a device.\n"), jcr->Job);
235 add_wait = jcr->wait_sec - (now - start);
239 if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
240 add_wait = me->heartbeat_interval;
244 V(device_release_mutex);
245 Dmsg1(100, "Return from wait_device ok=%d\n", ok);
250 * The jcr timers are used for waiting on any device *
251 * Returns: true if time doubled
252 * false if max time expired
254 static bool double_jcr_wait_time(JCR *jcr)
256 jcr->wait_sec *= 2; /* double wait time */
257 if (jcr->wait_sec > jcr->max_wait) { /* but not longer than maxtime */
258 jcr->wait_sec = jcr->max_wait;
261 jcr->rem_wait_sec = jcr->wait_sec;
262 if (jcr->num_wait >= jcr->max_num_wait) {