]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/wait.c
Fix automatic labeling of File volumes, which was broken by new
[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    Bacula® - The Network Backup Solution
13
14    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
15
16    The main author of Bacula is Kern Sibbald, with contributions from
17    many others, a complete list can be found in the file AUTHORS.
18    This program is Free Software; you can redistribute it and/or
19    modify it under the terms of version two of the GNU General Public
20    License as published by the Free Software Foundation plus additions
21    that are listed in the file LICENSE.
22
23    This program is distributed in the hope that it will be useful, but
24    WITHOUT ANY WARRANTY; without even the implied warranty of
25    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26    General Public License for more details.
27
28    You should have received a copy of the GNU General Public License
29    along with this program; if not, write to the Free Software
30    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31    02110-1301, USA.
32
33    Bacula® is a registered trademark of John Walker.
34    The licensor of Bacula is the Free Software Foundation Europe
35    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
36    Switzerland, email:ftf@fsfeurope.org.
37 */
38
39
40 #include "bacula.h"                   /* pull in global headers */
41 #include "stored.h"                   /* pull in Storage Deamon headers */
42
43 //static bool double_jcr_wait_time(JCR *jcr);
44
45
46 /*
47  * Wait for SysOp to mount a tape on a specific device
48  *
49  *   Returns: W_ERROR, W_TIMEOUT, W_POLL, W_MOUNT, or W_WAKE 
50  */
51 int wait_for_sysop(DCR *dcr)
52 {
53    struct timeval tv;
54    struct timezone tz;
55    struct timespec timeout;
56    time_t last_heartbeat = 0;
57    time_t first_start = time(NULL);
58    int stat = 0;
59    int add_wait;
60    bool unmounted;
61    DEVICE *dev = dcr->dev;
62    JCR *jcr = dcr->jcr;
63
64    P(dev->mutex);
65    Dmsg1(100, "Enter blocked=%s\n", dev->print_blocked());
66    unmounted = is_device_unmounted(dev);
67
68    dev->poll = false;
69    /*
70     * Wait requested time (dev->rem_wait_sec).  However, we also wake up every
71     *    HB_TIME seconds and send a heartbeat to the FD and the Director
72     *    to keep stateful firewalls from closing them down while waiting
73     *    for the operator.
74     */
75    add_wait = dev->rem_wait_sec;
76    if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
77       add_wait = me->heartbeat_interval;
78    }
79    /* If the user did not unmount the tape and we are polling, ensure
80     *  that we poll at the correct interval.
81     */
82    if (!unmounted && dev->vol_poll_interval && add_wait > dev->vol_poll_interval) {
83       add_wait = dev->vol_poll_interval;
84    }
85
86    if (!unmounted) {
87       Dmsg1(400, "blocked=%s\n", dev->print_blocked());
88       dev->dev_prev_blocked = dev->dev_blocked;
89       dev->set_blocked(BST_WAITING_FOR_SYSOP); /* indicate waiting for mount */
90    }
91
92    for ( ; !job_canceled(jcr); ) {
93       time_t now, start;
94
95       gettimeofday(&tv, &tz);
96       timeout.tv_nsec = tv.tv_usec * 1000;
97       timeout.tv_sec = tv.tv_sec + add_wait;
98
99       Dmsg4(400, "I'm going to sleep on device %s. HB=%d wait=%d add_wait=%d\n", 
100          dev->print_name(), (int)me->heartbeat_interval, dev->wait_sec, add_wait);
101       start = time(NULL);
102       /* Wait required time */
103       stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->mutex, &timeout);
104       Dmsg2(400, "Wokeup from sleep on device stat=%d blocked=%s\n", stat,
105          dev->print_blocked());
106
107       now = time(NULL);
108       dev->rem_wait_sec -= (now - start);
109
110       /* Note, this always triggers the first time. We want that. */
111       if (me->heartbeat_interval) {
112          if (now - last_heartbeat >= me->heartbeat_interval) {
113             /* send heartbeats */
114             if (jcr->file_bsock) {
115                bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
116                Dmsg0(400, "Send heartbeat to FD.\n");
117             }
118             if (jcr->dir_bsock) {
119                bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
120             }
121             last_heartbeat = now;
122          }
123       }
124
125       if (stat == EINVAL) {
126          berrno be;
127          Dmsg1(000, "pthread stat=%d\n", stat);
128          Jmsg1(jcr, M_FATAL, 0, _("pthread timedwait error. ERR=%s\n"), be.strerror(stat));
129          stat = W_ERROR;               /* error */
130          break;
131       }
132
133
134       if (dev->rem_wait_sec <= 0) {  /* on exceeding wait time return */
135          Dmsg0(400, "Exceed wait time.\n");
136          stat = W_TIMEOUT;
137          break;
138       }
139
140       /*
141        * Check if user unmounted the device while we were waiting
142        */
143       unmounted = is_device_unmounted(dev);
144
145       if (!unmounted && dev->vol_poll_interval &&
146           (now - first_start >= dev->vol_poll_interval)) {
147          Dmsg1(400, "In wait blocked=%s\n", dev->print_blocked());
148          dev->poll = true;            /* returning a poll event */
149          stat = W_POLL;
150          break;
151       }
152       /*
153        * Check if user mounted the device while we were waiting
154        */
155       if (dev->get_blocked() == BST_MOUNT) {   /* mount request ? */
156          stat = W_MOUNT;
157          break;
158       }
159
160       /*
161        * If we did not timeout, then some event happened, so
162        *   return to check if state changed.   
163        */
164       if (stat != 0) {
165          stat = W_WAKE;          /* someone woke us */
166          break;
167       }
168
169       /* 
170        * At this point, we know we woke up because of a timeout,
171        *   that was due to a heartbeat, so we just update
172        *   the wait counters and continue.
173        */
174       add_wait = dev->wait_sec - (now - start);
175       if (add_wait < 0) {
176          add_wait = 0;
177       }
178       if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
179          add_wait = me->heartbeat_interval;
180       }
181    }
182
183    if (!unmounted) {
184       dev->set_blocked(dev->dev_prev_blocked);    /* restore entry state */
185       Dmsg1(400, "set %s\n", dev->print_blocked());
186    }
187    Dmsg1(400, "Exit blocked=%s\n", dev->print_blocked());
188    V(dev->mutex);
189    return stat;
190 }
191
192
193 /*
194  * Wait for any device to be released, then we return, so 
195  *  higher level code can rescan possible devices.
196  * 
197  * Returns: true  if a device has changed state
198  *          false if the total wait time has expired.
199  */
200 bool wait_for_device(JCR *jcr, bool first)
201 {
202    struct timeval tv;
203    struct timezone tz;
204    struct timespec timeout;
205    int stat = 0;
206    bool ok = true;
207    const int wait_time = 5 * 60;       /* wait 5 minutes */
208
209    Dmsg0(100, "Enter wait_for_device\n");
210    P(device_release_mutex);
211
212    if (first) {
213       Jmsg(jcr, M_MOUNT, 0, _("Job %s waiting to reserve a device.\n"), jcr->Job);
214    }
215
216    gettimeofday(&tv, &tz);
217    timeout.tv_nsec = tv.tv_usec * 1000;
218    timeout.tv_sec = tv.tv_sec + wait_time;
219
220    Dmsg0(100, "I'm going to wait for a device.\n");
221
222    /* Wait required time */
223    stat = pthread_cond_timedwait(&wait_device_release, &device_release_mutex, &timeout);
224    Dmsg1(100, "Wokeup from sleep on device stat=%d\n", stat);
225
226
227    V(device_release_mutex);
228    Dmsg1(100, "Return from wait_device ok=%d\n", ok);
229    return ok;
230 }
231
232 #ifdef xxx
233 /*
234  * The jcr timers are used for waiting on any device *
235  * Returns: true if time doubled
236  *          false if max time expired
237  */
238 static bool double_jcr_wait_time(JCR *jcr)
239 {
240    jcr->wait_sec *= 2;               /* double wait time */
241    if (jcr->wait_sec > jcr->max_wait) {   /* but not longer than maxtime */
242       jcr->wait_sec = jcr->max_wait;
243    }
244    jcr->num_wait++;
245    jcr->rem_wait_sec = jcr->wait_sec;
246    if (jcr->num_wait >= jcr->max_num_wait) {
247       return false;
248    }
249    return true;
250 }
251 #endif