]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/wait.c
- This version has a new DIR -- SD protocol. Both
[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    Dmsg0(100, "Enter wait_for_device\n");
176    P(device_release_mutex);
177
178    if (first) {
179       Jmsg(jcr, M_MOUNT, 0, msg);
180    }
181
182    /*
183     * Wait requested time (dev->rem_wait_sec).  However, we also wake up every
184     *    HB_TIME seconds and send a heartbeat to the FD and the Director
185     *    to keep stateful firewalls from closing them down while waiting
186     *    for the operator.
187     */
188    add_wait = jcr->rem_wait_sec;
189    if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
190       add_wait = me->heartbeat_interval;
191    }
192
193    for ( ; !job_canceled(jcr); ) {
194       time_t now, start;
195
196       gettimeofday(&tv, &tz);
197       timeout.tv_nsec = tv.tv_usec * 1000;
198       timeout.tv_sec = tv.tv_sec + add_wait;
199
200       Dmsg4(100, "I'm going to sleep on device %s. HB=%d wait=%d remwait=%d\n", dev->print_name(),
201          (int)me->heartbeat_interval, jcr->wait_sec, jcr->rem_wait_sec);
202       start = time(NULL);
203       /* Wait required time */
204       stat = pthread_cond_timedwait(&wait_device_release, &device_release_mutex, &timeout);
205       Dmsg1(100, "Wokeup from sleep on device stat=%d\n", stat);
206
207       now = time(NULL);
208       jcr->rem_wait_sec -= (now - start);
209
210 #ifdef needed
211       /* Note, this always triggers the first time. We want that. */
212       if (me->heartbeat_interval) {
213          if (now - last_heartbeat >= me->heartbeat_interval) {
214             /* send heartbeats */
215             if (jcr->file_bsock) {
216                bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
217                Dmsg0(400, "Send heartbeat to FD.\n");
218             }
219             if (jcr->dir_bsock) {
220                bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
221             }
222             last_heartbeat = now;
223          }
224       }
225 #endif
226
227       if (stat != ETIMEDOUT) {     /* if someone woke us up */
228          ok = true;
229          break;                    /* allow caller to examine device */
230       }
231       if (jcr->rem_wait_sec <= 0) {  /* on exceeding wait time return */
232          Dmsg0(400, "Exceed wait time.\n");
233          if (!double_jcr_wait_time(jcr)) {
234             break;                 /* give up */
235          }
236          Jmsg(jcr, M_MOUNT, 0, msg);
237       }
238
239       add_wait = jcr->wait_sec - (now - start);
240       if (add_wait < 0) {
241          add_wait = 0;
242       }
243       if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
244          add_wait = me->heartbeat_interval;
245       }
246    }
247
248    V(device_release_mutex);
249    Dmsg1(100, "Return from wait_device ok=%d\n", ok);
250    return ok;
251 }
252
253 /*
254  * The jcr timers are used for waiting on any device
255  *
256  * Returns: true if time doubled
257  *          false if max time expired
258  */
259 static bool double_jcr_wait_time(JCR *jcr)
260 {
261    jcr->wait_sec *= 2;               /* double wait time */
262    if (jcr->wait_sec > jcr->max_wait) {   /* but not longer than maxtime */
263       jcr->wait_sec = jcr->max_wait;
264    }
265    jcr->num_wait++;
266    jcr->rem_wait_sec = jcr->wait_sec;
267    if (jcr->num_wait >= jcr->max_num_wait) {
268       return false;
269    }
270    return true;
271 }