]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/reserve.c
Add stored/reserve.c
[bacula/bacula] / bacula / src / stored / reserve.c
1 /*
2  *   Drive reservation functions for Storage Daemon
3  *
4  *   Kern Sibbald, MM
5  *
6  *   Split from job.c and acquire.c June 2005
7  *
8  *   Version $Id$
9  *
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
16    version 2 as ammended with additional clauses defined in the
17    file LICENSE in the main source directory.
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 
22    the file LICENSE for additional details.
23
24  */
25
26 #include "bacula.h"
27 #include "stored.h"
28
29 /*
30  *   Use Device command from Director
31  *   He tells is what Device Name to use, the Media Type,
32  *      the Pool Name, and the Pool Type.
33  *
34  *    Ensure that the device exists and is opened, then store
35  *      the media and pool info in the JCR.  This class is used
36  *      only temporarily in this file.
37  */
38 class DIRSTORE {
39 public:
40    alist *device;
41    bool append;
42    char name[MAX_NAME_LENGTH];
43    char media_type[MAX_NAME_LENGTH];
44    char pool_name[MAX_NAME_LENGTH];
45    char pool_type[MAX_NAME_LENGTH];
46 };
47
48 /* Reserve context */
49 class RCTX {
50 public:
51    alist errors;
52    JCR *jcr;
53    char *device_name;
54    DIRSTORE *store;
55    DEVRES   *device;
56 };
57
58
59 /* Forward referenced functions */
60 static int can_reserve_drive(DCR *dcr); 
61 static int search_res_for_device(RCTX &rctx);
62 static int reserve_device(RCTX &rctx);
63 static bool reserve_device_for_read(DCR *dcr);
64 static bool reserve_device_for_append(DCR *dcr);
65 static bool use_storage_cmd(JCR *jcr);
66
67 /* Requests from the Director daemon */
68 static char use_storage[]  = "use storage=%127s media_type=%127s "
69    "pool_name=%127s pool_type=%127s append=%d copy=%d stripe=%d\n";
70 static char use_device[]  = "use device=%127s\n";
71
72 /* Responses sent to Director daemon */
73 static char OK_device[] = "3000 OK use device device=%s\n";
74 static char NO_device[] = "3924 Device \"%s\" not in SD Device resources.\n";
75 static char BAD_use[]   = "3913 Bad use command: %s\n";
76
77
78 bool use_cmd(JCR *jcr) 
79 {
80    /*
81     * Wait for the device, media, and pool information
82     */
83    if (!use_storage_cmd(jcr)) {
84       set_jcr_job_status(jcr, JS_ErrorTerminated);
85       memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
86       return false;
87    }
88    return true;
89 }
90
91 static bool use_storage_cmd(JCR *jcr)
92 {
93    POOL_MEM store_name, dev_name, media_type, pool_name, pool_type;
94    BSOCK *dir = jcr->dir_bsock;
95    int append;
96    bool ok;       
97    int Copy, Stripe;
98    alist *dirstore;   
99    DIRSTORE *store;
100    char *device_name;
101    DCR *dcr = NULL;
102    RCTX rctx;
103    rctx.jcr = jcr;
104    char *error;
105
106    /*
107     * If there are multiple devices, the director sends us
108     *   use_device for each device that it wants to use.
109     */
110    Dmsg1(100, "<dird: %s", dir->msg);
111    dirstore = New(alist(10, not_owned_by_alist));
112    do {
113       ok = sscanf(dir->msg, use_storage, store_name.c_str(), 
114                   media_type.c_str(), pool_name.c_str(), 
115                   pool_type.c_str(), &append, &Copy, &Stripe) == 7;
116       if (!ok) {
117          break;
118       }
119       unbash_spaces(store_name);
120       unbash_spaces(media_type);
121       unbash_spaces(pool_name);
122       unbash_spaces(pool_type);
123       store = new DIRSTORE;
124       dirstore->append(store);
125       memset(store, 0, sizeof(DIRSTORE));
126       store->device = New(alist(10));
127       bstrncpy(store->name, store_name, sizeof(store->name));
128       bstrncpy(store->media_type, media_type, sizeof(store->media_type));
129       bstrncpy(store->pool_name, pool_name, sizeof(store->pool_name));
130       bstrncpy(store->pool_type, pool_type, sizeof(store->pool_type));
131       store->append = append;
132
133       /* Now get all devices */
134       while (bnet_recv(dir) >= 0) {
135          ok = sscanf(dir->msg, use_device, dev_name.c_str()) == 1;
136          if (!ok) {
137             break;
138          }
139          unbash_spaces(dev_name);
140          store->device->append(bstrdup(dev_name.c_str()));
141       }
142    }  while (ok && bnet_recv(dir) >= 0);
143
144 #ifdef DEVELOPER
145    /* This loop is debug code and can be removed */
146    /* ***FIXME**** remove after 1.38 release */
147    foreach_alist(store, dirstore) {
148       Dmsg4(100, "Storage=%s media_type=%s pool=%s pool_type=%s\n", 
149          store->name, store->media_type, store->pool_name, 
150          store->pool_type);
151       foreach_alist(device_name, store->device) {
152          Dmsg1(100, "   Device=%s\n", device_name);
153       }
154    }
155 #endif
156
157    /*                    
158     * At this point, we have a list of all the Director's Storage
159     *  resources indicated for this Job, which include Pool, PoolType,
160     *  storage name, and Media type.     
161     * Then for each of the Storage resources, we have a list of
162     *  device names that were given.
163     *
164     * Wiffle through them and find one that can do the backup.
165     */
166    if (ok) {
167       bool first = true;
168       init_jcr_device_wait_timers(jcr);
169       for ( ;; ) {
170          int need_wait = false;
171          foreach_alist(store, dirstore) {
172             rctx.store = store;
173             foreach_alist(device_name, store->device) {
174                int stat;
175                rctx.device_name = device_name;
176                stat = search_res_for_device(rctx); 
177                if (stat == 1) {             /* found available device */
178                   dcr = jcr->dcr;
179                   dcr->Copy = Copy;
180                   dcr->Stripe = Stripe;
181                   ok = true;
182                   goto done;
183                } else if (stat == 0) {      /* device busy */
184                   need_wait = true;
185                }
186                rctx.errors.push(bstrdup(jcr->errmsg));
187             }
188          }
189          /*
190           * If there is some device for which we can wait, then
191           *  wait and try again until the wait time expires
192           */
193          if (!need_wait || !wait_for_device(jcr, first)) {
194             break;
195          }
196          first = false;
197          for (error=(char*)rctx.errors.first(); error;
198               error=(char*)rctx.errors.next()) {
199             free(error);
200          }
201       }
202       if (verbose) {
203          unbash_spaces(dir->msg);
204          pm_strcpy(jcr->errmsg, dir->msg);
205          Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
206       }
207       Jmsg(jcr, M_FATAL, 0, _("\n"
208          "     Device \"%s\" with MediaType \"%s\" requested by DIR not found in SD Device resources.\n"),
209            dev_name.c_str(), media_type.c_str());
210       bnet_fsend(dir, NO_device, dev_name.c_str());
211       Dmsg1(100, ">dird: %s\n", dir->msg);
212       ok = false;
213    } else {
214       unbash_spaces(dir->msg);
215       pm_strcpy(jcr->errmsg, dir->msg);
216       if (verbose) {
217          Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
218       }
219       Jmsg(jcr, M_FATAL, 0, _("Could not find an available device.\n"));
220       for (error=(char*)rctx.errors.first(); error;
221            error=(char*)rctx.errors.next()) {
222          Jmsg(jcr, M_INFO, 0, "%s", error);
223       }
224       bnet_fsend(dir, BAD_use, jcr->errmsg);
225       Dmsg1(100, ">dird: %s\n", dir->msg);
226       ok = false;
227    }
228
229 done:
230    foreach_alist(store, dirstore) {
231       delete store->device;
232       delete store;
233    }
234    delete dirstore;
235    if (!ok && dcr) {
236       free_dcr(dcr);
237    }
238    for (error=(char*)rctx.errors.first(); error;
239         error=(char*)rctx.errors.next()) {
240       free(error);
241    }
242    return ok;
243 }
244
245 /*
246  * Search for a particular storage device with particular storage
247  *  characteristics (MediaType).
248  */
249 static int search_res_for_device(RCTX &rctx) 
250 {
251    AUTOCHANGER *changer;
252    BSOCK *dir = rctx.jcr->dir_bsock;
253    bool ok;
254    int stat;
255
256    Dmsg1(100, "Search res for %s\n", rctx.device_name);
257    foreach_res(rctx.device, R_DEVICE) {
258       Dmsg1(100, "Try res=%s\n", rctx.device->hdr.name);
259       /* Find resource, and make sure we were able to open it */
260       if (fnmatch(rctx.device_name, rctx.device->hdr.name, 0) == 0 &&
261           strcmp(rctx.device->media_type, rctx.store->media_type) == 0) {
262          stat = reserve_device(rctx);
263          if (stat != 1) {
264             return stat;
265          }
266          Dmsg1(220, "Got: %s", dir->msg);
267          bash_spaces(rctx.device_name);
268          ok = bnet_fsend(dir, OK_device, rctx.device_name);
269          Dmsg1(100, ">dird: %s\n", dir->msg);
270          return ok ? 1 : -1;
271       }
272    }
273    foreach_res(changer, R_AUTOCHANGER) {
274       Dmsg1(100, "Try changer res=%s\n", changer->hdr.name);
275       /* Find resource, and make sure we were able to open it */
276       if (fnmatch(rctx.device_name, changer->hdr.name, 0) == 0) {
277          /* Try each device in this AutoChanger */
278          foreach_alist(rctx.device, changer->device) {
279             Dmsg1(100, "Try changer device %s\n", rctx.device->hdr.name);
280             stat = reserve_device(rctx);
281             if (stat == -1) {            /* hard error */
282                return -1;
283             }
284             if (stat == 0) {             /* must wait, try next one */
285                continue;
286             }
287             POOL_MEM dev_name;
288             Dmsg1(100, "Device %s opened.\n", rctx.device_name);
289             pm_strcpy(dev_name, rctx.device->hdr.name);
290             bash_spaces(dev_name);
291             ok = bnet_fsend(dir, OK_device, dev_name.c_str());  /* Return real device name */
292             Dmsg1(100, ">dird: %s\n", dir->msg);
293             return ok ? 1 : -1;
294          }
295       }
296    }
297    return 0;                    /* nothing found */
298 }
299
300 /*
301  *  Try to reserve a specific device.
302  *
303  *  Returns: 1 -- OK, have DCR
304  *           0 -- must wait
305  *          -1 -- fatal error
306  */
307 static int reserve_device(RCTX &rctx)
308 {
309    bool ok;
310    DCR *dcr;
311    const int name_len = MAX_NAME_LENGTH;
312    if (!rctx.device->dev) {
313       rctx.device->dev = init_dev(rctx.jcr, NULL, rctx.device);
314    }
315    if (!rctx.device->dev) {
316       if (dev_cap(rctx.device->dev, CAP_AUTOCHANGER)) {
317         Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
318            "     Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
319              rctx.device->hdr.name, rctx.device_name);
320       } else {
321          Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
322             "     Device \"%s\" requested by DIR could not be opened or does not exist.\n"),
323               rctx.device_name);
324       }
325       return 0;
326    }  
327    Dmsg1(100, "Found device %s\n", rctx.device->hdr.name);
328    dcr = new_dcr(rctx.jcr, rctx.device->dev);
329    if (!dcr) {
330       BSOCK *dir = rctx.jcr->dir_bsock;
331       bnet_fsend(dir, _("3926 Could not get dcr for device: %s\n"), rctx.device_name);
332       Dmsg1(100, ">dird: %s\n", dir->msg);
333       return -1;
334    }
335    rctx.jcr->dcr = dcr;
336    bstrncpy(dcr->pool_name, rctx.store->pool_name, name_len);
337    bstrncpy(dcr->pool_type, rctx.store->pool_type, name_len);
338    bstrncpy(dcr->media_type, rctx.store->media_type, name_len);
339    bstrncpy(dcr->dev_name, rctx.device_name, name_len);
340    if (rctx.store->append == SD_APPEND) {
341       ok = reserve_device_for_append(dcr);
342       Dmsg3(200, "dev_name=%s mediatype=%s ok=%d\n", dcr->dev_name, dcr->media_type, ok);
343    } else {
344       ok = reserve_device_for_read(dcr);
345    }
346    if (!ok) {
347       free_dcr(rctx.jcr->dcr);
348       return 0;
349    }
350    return 1;
351 }
352
353 /*
354  * We "reserve" the drive by setting the ST_READ bit. No one else
355  *  should touch the drive until that is cleared.
356  *  This allows the DIR to "reserve" the device before actually
357  *  starting the job. 
358  */
359 static bool reserve_device_for_read(DCR *dcr)
360 {
361    DEVICE *dev = dcr->dev;
362    JCR *jcr = dcr->jcr;
363    bool ok = false;
364
365    ASSERT(dcr);
366
367    dev->block(BST_DOING_ACQUIRE);
368
369    if (device_is_unmounted(dev)) {             
370       Dmsg1(200, "Device %s is BLOCKED due to user unmount.\n", dev->print_name());
371       Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"),
372            dev->print_name());
373       goto bail_out;
374    }
375
376    if (dev->is_busy()) {
377       Dmsg4(200, "Device %s is busy ST_READ=%d num_writers=%d reserved=%d.\n", dev->print_name(),
378          dev->state & ST_READ?1:0, dev->num_writers, dev->reserved_device);
379       Mmsg1(jcr->errmsg, _("Device %s is busy.\n"),
380             dev->print_name());
381       goto bail_out;
382    }
383
384    dev->clear_append();
385    dev->set_read();
386    ok = true;
387
388 bail_out:
389    dev->unblock();
390    return ok;
391 }
392
393
394 /*
395  * We reserve the device for appending by incrementing the 
396  *  reserved_device. We do virtually all the same work that
397  *  is done in acquire_device_for_append(), but we do
398  *  not attempt to mount the device. This routine allows
399  *  the DIR to reserve multiple devices before *really* 
400  *  starting the job. It also permits the SD to refuse 
401  *  certain devices (not up, ...).
402  *
403  * Note, in reserving a device, if the device is for the
404  *  same pool and the same pool type, then it is acceptable.
405  *  The Media Type has already been checked. If we are
406  *  the first tor reserve the device, we put the pool
407  *  name and pool type in the device record.
408  */
409 static bool reserve_device_for_append(DCR *dcr)
410 {
411    JCR *jcr = dcr->jcr;
412    DEVICE *dev = dcr->dev;
413    bool ok = false;
414
415    ASSERT(dcr);
416
417    dev->block(BST_DOING_ACQUIRE);
418
419    if (dev->can_read()) {
420       Mmsg1(jcr->errmsg, _("Device %s is busy reading.\n"), dev->print_name());
421       goto bail_out;
422    }
423
424    if (device_is_unmounted(dev)) {
425       Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"), dev->print_name());
426       goto bail_out;
427    }
428
429    Dmsg1(190, "reserve_append device is %s\n", dev->is_tape()?"tape":"disk");
430
431    if (can_reserve_drive(dcr) != 1) {
432       Mmsg1(jcr->errmsg, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
433       goto bail_out;
434    }
435
436    dev->reserved_device++;
437    Dmsg1(200, "============= Inc reserve=%d\n", dev->reserved_device);
438    dcr->reserved_device = true;
439    ok = true;
440
441 bail_out:
442    dev->unblock();
443    return ok;
444 }
445
446 /*
447  * Returns: 1 if drive can be reserved
448  *          0 if we should wait
449  *         -1 on error
450  */
451 static int can_reserve_drive(DCR *dcr) 
452 {
453    DEVICE *dev = dcr->dev;
454    JCR *jcr = dcr->jcr;
455    /*
456     * First handle the case that the drive is not yet in append mode
457     */
458    if (!dev->can_append() && dev->num_writers == 0) {
459       /* Now check if there are any reservations on the drive */
460       if (dev->reserved_device) {           
461          /* Yes, now check if we want the same Pool and pool type */
462          if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
463              strcmp(dev->pool_type, dcr->pool_type) == 0) {
464             /* OK, compatible device */
465          } else {
466             /* Drive not suitable for us */
467             return 0;                 /* wait */
468          }
469       } else {
470          /* Device is available but not yet reserved, reserve it for us */
471          bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
472          bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
473       }
474       return 1;                       /* reserve drive */
475    }
476
477    /*
478     * Check if device in append mode with no writers (i.e. available)
479     */
480    if (dev->can_append() && dev->num_writers == 0) {
481       /* Device is available but not yet reserved, reserve it for us */
482       bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
483       bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
484       return 1;
485    }
486
487    /*
488     * Now check if the device is in append mode with writers (i.e.
489     *  available if pool is the same).
490     */
491    if (dev->can_append() || dev->num_writers > 0) {
492       Dmsg0(190, "device already in append.\n");
493       /* Yes, now check if we want the same Pool and pool type */
494       if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
495           strcmp(dev->pool_type, dcr->pool_type) == 0) {
496          /* OK, compatible device */
497       } else {
498          /* Drive not suitable for us */
499          Jmsg(jcr, M_WARNING, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
500          return 0;                    /* wait */
501       }
502    } else {
503       Pmsg0(000, "Logic error!!!! Should not get here.\n");
504       Jmsg0(jcr, M_FATAL, 0, _("Logic error!!!! Should not get here.\n"));
505       return -1;                      /* error, should not get here */
506    }
507    return 1;                          /* reserve drive */
508 }