]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/wait.c
- Add wait.c (oops forgot previously).
[bacula/bacula] / bacula / src / stored / wait.c
1 /*
2  *  Subroutines to handle waiting for operator intervention
3  *   or waiting for a Device to be released
4  *
5  *  Code for wait_for_sysop() pulled from askdir.c
6  *
7  *   Kern Sibbald, March 2005
8  *
9  *   Version $Id$
10  */
11 /*
12    Copyright (C) 2000-2005 Kern Sibbald
13
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.
18
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.
23
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,
27    MA 02111-1307, USA.
28
29  */
30
31 #include "bacula.h"                   /* pull in global headers */
32 #include "stored.h"                   /* pull in Storage Deamon headers */
33
34 static bool double_jcr_wait_time(JCR *jcr);
35
36
37 /*
38  * Wait for SysOp to mount a tape on a specific device
39  *
40  *   Returns: status from pthread_cond_timedwait() 
41  */
42 int wait_for_sysop(DCR *dcr)
43 {
44    struct timeval tv;
45    struct timezone tz;
46    struct timespec timeout;
47    time_t last_heartbeat = 0;
48    time_t first_start = time(NULL);
49    int stat = 0;
50    int add_wait;
51    bool unmounted;
52    DEVICE *dev = dcr->dev;
53    JCR *jcr = dcr->jcr;
54
55    P(dev->mutex);
56    unmounted = (dev->dev_blocked == BST_UNMOUNTED) ||
57                 (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
58
59    dev->poll = false;
60    /*
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
64     *    for the operator.
65     */
66    add_wait = dev->rem_wait_sec;
67    if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
68       add_wait = me->heartbeat_interval;
69    }
70    /* If the user did not unmount the tape and we are polling, ensure
71     *  that we poll at the correct interval.
72     */
73    if (!unmounted && dev->vol_poll_interval && add_wait > dev->vol_poll_interval) {
74       add_wait = dev->vol_poll_interval;
75    }
76
77    if (!unmounted) {
78       dev->dev_prev_blocked = dev->dev_blocked;
79       dev->dev_blocked = BST_WAITING_FOR_SYSOP; /* indicate waiting for mount */
80    }
81
82    for ( ; !job_canceled(jcr); ) {
83       time_t now, start;
84
85       gettimeofday(&tv, &tz);
86       timeout.tv_nsec = tv.tv_usec * 1000;
87       timeout.tv_sec = tv.tv_sec + add_wait;
88
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);
91       start = time(NULL);
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);
95
96       now = time(NULL);
97       dev->rem_wait_sec -= (now - start);
98
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");
106             }
107             if (jcr->dir_bsock) {
108                bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
109             }
110             last_heartbeat = now;
111          }
112       }
113
114       /*
115        * Check if user unmounted the device while we were waiting
116        */
117       unmounted = (dev->dev_blocked == BST_UNMOUNTED) ||
118                    (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
119
120       if (stat != ETIMEDOUT) {     /* we blocked the device */
121          break;                    /* on error return */
122       }
123       if (dev->rem_wait_sec <= 0) {  /* on exceeding wait time return */
124          Dmsg0(400, "Exceed wait time.\n");
125          break;
126       }
127
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 */
132          break;
133       }
134       /*
135        * Check if user mounted the device while we were waiting
136        */
137       if (dev->dev_blocked == BST_MOUNT) {   /* mount request ? */
138          stat = 0;
139          break;
140       }
141
142       add_wait = dev->wait_sec - (now - start);
143       if (add_wait < 0) {
144          add_wait = 0;
145       }
146       if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
147          add_wait = me->heartbeat_interval;
148       }
149    }
150
151    if (!unmounted) {
152       dev->dev_blocked = dev->dev_prev_blocked;    /* restore entry state */
153    }
154    V(dev->mutex);
155    return stat;
156 }
157
158
159 /*
160  * Wait for Device to be released
161  *
162  */
163 bool wait_for_device(DCR *dcr, const char *msg, bool first)
164 {
165    struct timeval tv;
166    struct timezone tz;
167    struct timespec timeout;
168 // time_t last_heartbeat = 0;
169    int stat = 0;
170    int add_wait;
171    DEVICE *dev = dcr->dev;
172    JCR *jcr = dcr->jcr;
173    bool ok = false;
174
175    P(device_release_mutex);
176
177    if (first) {
178       Jmsg(jcr, M_MOUNT, 0, msg);
179    }
180
181    /*
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
185     *    for the operator.
186     */
187    add_wait = jcr->rem_wait_sec;
188    if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
189       add_wait = me->heartbeat_interval;
190    }
191
192    for ( ; !job_canceled(jcr); ) {
193       time_t now, start;
194
195       gettimeofday(&tv, &tz);
196       timeout.tv_nsec = tv.tv_usec * 1000;
197       timeout.tv_sec = tv.tv_sec + add_wait;
198
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);
201       start = time(NULL);
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);
205
206       now = time(NULL);
207       jcr->rem_wait_sec -= (now - start);
208
209 #ifdef needed
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");
217             }
218             if (jcr->dir_bsock) {
219                bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
220             }
221             last_heartbeat = now;
222          }
223       }
224 #endif
225
226       if (stat != ETIMEDOUT) {     /* if someone woke us up */
227          ok = true;
228          break;                    /* allow caller to examine device */
229       }
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)) {
233             break;                 /* give up */
234          }
235          Jmsg(jcr, M_MOUNT, 0, msg);
236       }
237
238       add_wait = jcr->wait_sec - (now - start);
239       if (add_wait < 0) {
240          add_wait = 0;
241       }
242       if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
243          add_wait = me->heartbeat_interval;
244       }
245    }
246
247    V(device_release_mutex);
248    Dmsg1(000, "Return from wait_device ok=%d\n", ok);
249    return ok;
250 }
251
252 /*
253  * The jcr timers are used for waiting on any device
254  *
255  * Returns: true if time doubled
256  *          false if max time expired
257  */
258 static bool double_jcr_wait_time(JCR *jcr)
259 {
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;
263    }
264    jcr->num_wait++;
265    jcr->rem_wait_sec = jcr->wait_sec;
266    if (jcr->num_wait >= jcr->max_num_wait) {
267       return false;
268    }
269    return true;
270 }