]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/reserve.c
- Make default mandir /usr/share/man
[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 static dlist *vol_list = NULL;
59 static pthread_mutex_t vol_list_lock = PTHREAD_MUTEX_INITIALIZER;
60
61 /* Forward referenced functions */
62 static int can_reserve_drive(DCR *dcr); 
63 static int search_res_for_device(RCTX &rctx);
64 static int reserve_device(RCTX &rctx);
65 static bool reserve_device_for_read(DCR *dcr);
66 static bool reserve_device_for_append(DCR *dcr);
67 static bool use_storage_cmd(JCR *jcr);
68 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx);
69
70 /* Requests from the Director daemon */
71 static char use_storage[]  = "use storage=%127s media_type=%127s "
72    "pool_name=%127s pool_type=%127s append=%d copy=%d stripe=%d\n";
73 static char use_device[]  = "use device=%127s\n";
74
75 /* Responses sent to Director daemon */
76 static char OK_device[] = "3000 OK use device device=%s\n";
77 static char NO_device[] = "3924 Device \"%s\" not in SD Device resources.\n";
78 static char BAD_use[]   = "3913 Bad use command: %s\n";
79
80 bool use_cmd(JCR *jcr) 
81 {
82    /*
83     * Wait for the device, media, and pool information
84     */
85    if (!use_storage_cmd(jcr)) {
86       set_jcr_job_status(jcr, JS_ErrorTerminated);
87       memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
88       return false;
89    }
90    return true;
91 }
92
93 static int my_compare(void *item1, void *item2)
94 {
95    return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
96 }
97
98
99 /*
100  * Put a new Volume entry in the Volume list. This
101  *  effectively reserves the volume so that it will
102  *  not be mounted again.
103  *
104  *  Return: VOLRES entry on success
105  *          NULL if the Volume is already in the list
106  */
107 VOLRES *new_volume(const char *VolumeName, DEVICE *dev)
108 {
109    VOLRES *vol, *nvol;
110    vol = (VOLRES *)malloc(sizeof(VOLRES));
111    memset(vol, 0, sizeof(VOLRES));
112    vol->vol_name = bstrdup(VolumeName);
113    vol->dev = dev;
114    P(vol_list_lock);
115    nvol = (VOLRES *)vol_list->binary_insert(vol, my_compare);
116    V(vol_list_lock);
117    if (nvol != vol) {
118       free(vol->vol_name);
119       free(vol);
120       if (dev) {
121          nvol->dev = dev;
122       }
123       return NULL;
124    }
125    return vol;
126 }
127
128 /*
129  * Search for a Volume name in the Volume list.
130  *
131  *  Returns: VOLRES entry on success
132  *           NULL if the Volume is not in the list
133  */
134 VOLRES *find_volume(const char *VolumeName)
135 {
136    VOLRES vol, *fvol;
137    vol.vol_name = bstrdup(VolumeName);
138    P(vol_list_lock);
139    fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
140    V(vol_list_lock);
141    free(vol.vol_name);
142    return fvol;
143 }
144
145 /*  
146  * Free a Volume from the Volume list
147  *
148  *  Returns: true if the Volume found and removed from the list
149  *           false if the Volume is not in the list
150  */
151 bool free_volume(DEVICE *dev)
152 {
153    VOLRES vol, *fvol;
154
155    if (dev->VolHdr.VolName[0] == 0) {
156       return false;
157    }
158    vol.vol_name = bstrdup(dev->VolHdr.VolName);
159    P(vol_list_lock);
160    fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
161    if (fvol) {
162       vol_list->remove(fvol);
163       free(fvol->vol_name);
164       free(fvol);
165    }
166    V(vol_list_lock);
167    free(vol.vol_name);
168    dev->VolHdr.VolName[0] = 0;
169    return fvol != NULL;
170 }
171
172 /*
173  * List Volumes -- this should be moved to status.c
174  */
175 void list_volumes(BSOCK *user)  
176 {
177    VOLRES *vol;
178    for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
179       bnet_fsend(user, "%s\n", vol->vol_name);
180    }
181 }
182       
183 /* Create the Volume list */
184 void create_volume_list()
185 {
186    VOLRES *dummy;
187    if (vol_list == NULL) {
188       vol_list = New(dlist(dummy, &dummy->link));
189    }
190 }
191
192 /* Release all Volumes from the list */
193 void free_volume_list()
194 {
195    VOLRES *vol;
196    for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
197       Dmsg1(000, "Unreleased Volume=%s\n", vol->vol_name);
198    }
199    delete vol_list;
200    vol_list = NULL;
201 }
202
203 bool is_volume_in_use(const char *VolumeName) 
204 {
205    VOLRES *vol = find_volume(VolumeName);
206    if (!vol) {
207       return false;                   /* vol not in list */
208    }
209    if (!vol->dev) {                   /* vol not attached to device */
210       return false;
211    }
212    if (!vol->dev->is_busy()) {
213       return false;
214    }
215    return true;
216 }
217
218
219 static bool use_storage_cmd(JCR *jcr)
220 {
221    POOL_MEM store_name, dev_name, media_type, pool_name, pool_type;
222    BSOCK *dir = jcr->dir_bsock;
223    int append;
224    bool ok;       
225    int Copy, Stripe;
226    DIRSTORE *store;
227    char *device_name;
228    RCTX rctx;
229    rctx.jcr = jcr;
230 #ifdef implemented
231    char *error;
232 #endif
233
234    /*
235     * If there are multiple devices, the director sends us
236     *   use_device for each device that it wants to use.
237     */
238    Dmsg1(100, "<dird: %s", dir->msg);
239    jcr->dirstore = New(alist(10, not_owned_by_alist));
240    do {
241       ok = sscanf(dir->msg, use_storage, store_name.c_str(), 
242                   media_type.c_str(), pool_name.c_str(), 
243                   pool_type.c_str(), &append, &Copy, &Stripe) == 7;
244       if (!ok) {
245          break;
246       }
247       unbash_spaces(store_name);
248       unbash_spaces(media_type);
249       unbash_spaces(pool_name);
250       unbash_spaces(pool_type);
251       store = new DIRSTORE;
252       jcr->dirstore->append(store);
253       memset(store, 0, sizeof(DIRSTORE));
254       store->device = New(alist(10));
255       bstrncpy(store->name, store_name, sizeof(store->name));
256       bstrncpy(store->media_type, media_type, sizeof(store->media_type));
257       bstrncpy(store->pool_name, pool_name, sizeof(store->pool_name));
258       bstrncpy(store->pool_type, pool_type, sizeof(store->pool_type));
259       store->append = append;
260
261       /* Now get all devices */
262       while (bnet_recv(dir) >= 0) {
263          ok = sscanf(dir->msg, use_device, dev_name.c_str()) == 1;
264          if (!ok) {
265             break;
266          }
267          unbash_spaces(dev_name);
268          store->device->append(bstrdup(dev_name.c_str()));
269       }
270    }  while (ok && bnet_recv(dir) >= 0);
271
272 #ifdef DEVELOPER
273    /* This loop is debug code and can be removed */
274    /* ***FIXME**** remove after 1.38 release */
275    foreach_alist(store, jcr->dirstore) {
276       Dmsg4(100, "Storage=%s media_type=%s pool=%s pool_type=%s\n", 
277          store->name, store->media_type, store->pool_name, 
278          store->pool_type);
279       foreach_alist(device_name, store->device) {
280          Dmsg1(100, "   Device=%s\n", device_name);
281       }
282    }
283 #endif
284
285    /*                    
286     * At this point, we have a list of all the Director's Storage
287     *  resources indicated for this Job, which include Pool, PoolType,
288     *  storage name, and Media type.     
289     * Then for each of the Storage resources, we have a list of
290     *  device names that were given.
291     *
292     * Wiffle through them and find one that can do the backup.
293     */
294    if (ok) {
295       ok = find_suitable_device_for_job(jcr, rctx);
296       if (ok) {
297          goto done;
298       }
299       if (verbose) {
300          unbash_spaces(dir->msg);
301          pm_strcpy(jcr->errmsg, dir->msg);
302          Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
303       }
304       Jmsg(jcr, M_FATAL, 0, _("\n"
305          "     Device \"%s\" with MediaType \"%s\" requested by DIR not found in SD Device resources.\n"),
306            dev_name.c_str(), media_type.c_str());
307       bnet_fsend(dir, NO_device, dev_name.c_str());
308 #ifdef implemented
309       for (error=(char*)rctx->errors.first(); error;
310            error=(char*)rctx->errors.next()) {
311          Jmsg(jcr, M_INFO, 0, "%s", error);
312       }
313 #endif
314       Dmsg1(100, ">dird: %s\n", dir->msg);
315    } else {
316       unbash_spaces(dir->msg);
317       pm_strcpy(jcr->errmsg, dir->msg);
318       if (verbose) {
319          Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
320       }
321       bnet_fsend(dir, BAD_use, jcr->errmsg);
322       Dmsg1(100, ">dird: %s\n", dir->msg);
323    }
324
325 done:
326    foreach_alist(store, jcr->dirstore) {
327       delete store->device;
328       delete store;
329    }
330    delete jcr->dirstore;
331 #ifdef implemented
332    for (error=(char*)rctx->errors.first(); error;
333         error=(char*)rctx->errors.next()) {
334       free(error);
335    }
336 #endif
337    return ok;
338 }
339
340
341 /*
342  * Search for a device suitable for this job.
343  */
344 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx)
345 {
346    bool first = true;
347    bool ok = false;
348    DCR *dcr = NULL;
349    DIRSTORE *store;
350    char *device_name;
351
352    init_jcr_device_wait_timers(jcr);
353    for ( ;; ) {
354       int need_wait = false;
355       foreach_alist(store, jcr->dirstore) {
356          rctx.store = store;
357          foreach_alist(device_name, store->device) {
358             int stat;
359             rctx.device_name = device_name;
360             stat = search_res_for_device(rctx); 
361             if (stat == 1) {             /* found available device */
362                dcr = jcr->dcr;
363                ok = true;
364                break;
365             } else if (stat == 0) {      /* device busy */
366                need_wait = true;
367             }
368             /* otherwise error */
369 //             rctx->errors.push(bstrdup(jcr->errmsg));
370          }
371       }
372       /*
373        * If there is some device for which we can wait, then
374        *  wait and try again until the wait time expires
375        */
376       if (!need_wait || !wait_for_device(jcr, first)) {
377          break;
378       }
379       first = false;
380 #ifdef implemented
381       for (error=(char*)rctx->errors.first(); error;
382            error=(char*)rctx->errors.next()) {
383          free(error);
384       }
385 #endif
386    }
387    if (!ok && dcr) {
388       free_dcr(dcr);
389    }
390
391    return ok;
392 }
393
394 /*
395  * Search for a particular storage device with particular storage
396  *  characteristics (MediaType).
397  */
398 static int search_res_for_device(RCTX &rctx) 
399 {
400    AUTOCHANGER *changer;
401    BSOCK *dir = rctx.jcr->dir_bsock;
402    bool ok;
403    int stat;
404
405    Dmsg1(100, "Search res for %s\n", rctx.device_name);
406    foreach_res(rctx.device, R_DEVICE) {
407       Dmsg1(100, "Try res=%s\n", rctx.device->hdr.name);
408       /* Find resource, and make sure we were able to open it */
409       if (fnmatch(rctx.device_name, rctx.device->hdr.name, 0) == 0 &&
410           strcmp(rctx.device->media_type, rctx.store->media_type) == 0) {
411          stat = reserve_device(rctx);
412          if (stat != 1) {
413             return stat;
414          }
415          Dmsg1(220, "Got: %s", dir->msg);
416          bash_spaces(rctx.device_name);
417          ok = bnet_fsend(dir, OK_device, rctx.device_name);
418          Dmsg1(100, ">dird: %s\n", dir->msg);
419          return ok ? 1 : -1;
420       }
421    }
422    foreach_res(changer, R_AUTOCHANGER) {
423       Dmsg1(100, "Try changer res=%s\n", changer->hdr.name);
424       /* Find resource, and make sure we were able to open it */
425       if (fnmatch(rctx.device_name, changer->hdr.name, 0) == 0) {
426          /* Try each device in this AutoChanger */
427          foreach_alist(rctx.device, changer->device) {
428             Dmsg1(100, "Try changer device %s\n", rctx.device->hdr.name);
429             stat = reserve_device(rctx);
430             if (stat == -1) {            /* hard error */
431                return -1;
432             }
433             if (stat == 0) {             /* must wait, try next one */
434                continue;
435             }
436             POOL_MEM dev_name;
437             Dmsg1(100, "Device %s opened.\n", rctx.device_name);
438             pm_strcpy(dev_name, rctx.device->hdr.name);
439             bash_spaces(dev_name);
440             ok = bnet_fsend(dir, OK_device, dev_name.c_str());  /* Return real device name */
441             Dmsg1(100, ">dird: %s\n", dir->msg);
442             return ok ? 1 : -1;
443          }
444       }
445    }
446    return 0;                    /* nothing found */
447 }
448
449 /*
450  *  Try to reserve a specific device.
451  *
452  *  Returns: 1 -- OK, have DCR
453  *           0 -- must wait
454  *          -1 -- fatal error
455  */
456 static int reserve_device(RCTX &rctx)
457 {
458    bool ok;
459    DCR *dcr;
460    const int name_len = MAX_NAME_LENGTH;
461    if (!rctx.device->dev) {
462       rctx.device->dev = init_dev(rctx.jcr, NULL, rctx.device);
463    }
464    if (!rctx.device->dev) {
465       if (rctx.device->changer_res) {
466         Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
467            "     Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
468              rctx.device->hdr.name, rctx.device_name);
469       } else {
470          Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
471             "     Device \"%s\" requested by DIR could not be opened or does not exist.\n"),
472               rctx.device_name);
473       }
474       return -1;  /* no use waiting */
475    }  
476    Dmsg1(100, "Found device %s\n", rctx.device->hdr.name);
477    dcr = new_dcr(rctx.jcr, rctx.device->dev);
478    if (!dcr) {
479       BSOCK *dir = rctx.jcr->dir_bsock;
480       bnet_fsend(dir, _("3926 Could not get dcr for device: %s\n"), rctx.device_name);
481       Dmsg1(100, ">dird: %s\n", dir->msg);
482       return -1;
483    }
484    rctx.jcr->dcr = dcr;
485    bstrncpy(dcr->pool_name, rctx.store->pool_name, name_len);
486    bstrncpy(dcr->pool_type, rctx.store->pool_type, name_len);
487    bstrncpy(dcr->media_type, rctx.store->media_type, name_len);
488    bstrncpy(dcr->dev_name, rctx.device_name, name_len);
489    if (rctx.store->append == SD_APPEND) {
490       ok = reserve_device_for_append(dcr);
491       Dmsg3(200, "dev_name=%s mediatype=%s ok=%d\n", dcr->dev_name, dcr->media_type, ok);
492    } else {
493       ok = reserve_device_for_read(dcr);
494    }
495    if (!ok) {
496       free_dcr(rctx.jcr->dcr);
497       return 0;
498    }
499    return 1;
500 }
501
502 /*
503  * We "reserve" the drive by setting the ST_READ bit. No one else
504  *  should touch the drive until that is cleared.
505  *  This allows the DIR to "reserve" the device before actually
506  *  starting the job. 
507  */
508 static bool reserve_device_for_read(DCR *dcr)
509 {
510    DEVICE *dev = dcr->dev;
511    JCR *jcr = dcr->jcr;
512    bool ok = false;
513
514    ASSERT(dcr);
515
516    dev->block(BST_DOING_ACQUIRE);
517
518    if (device_is_unmounted(dev)) {             
519       Dmsg1(200, "Device %s is BLOCKED due to user unmount.\n", dev->print_name());
520       Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"),
521            dev->print_name());
522       goto bail_out;
523    }
524
525    if (dev->is_busy()) {
526       Dmsg4(200, "Device %s is busy ST_READ=%d num_writers=%d reserved=%d.\n", dev->print_name(),
527          dev->state & ST_READ?1:0, dev->num_writers, dev->reserved_device);
528       Mmsg1(jcr->errmsg, _("Device %s is busy.\n"),
529             dev->print_name());
530       goto bail_out;
531    }
532
533    dev->clear_append();
534    dev->set_read();
535    ok = true;
536
537 bail_out:
538    dev->unblock();
539    return ok;
540 }
541
542
543 /*
544  * We reserve the device for appending by incrementing the 
545  *  reserved_device. We do virtually all the same work that
546  *  is done in acquire_device_for_append(), but we do
547  *  not attempt to mount the device. This routine allows
548  *  the DIR to reserve multiple devices before *really* 
549  *  starting the job. It also permits the SD to refuse 
550  *  certain devices (not up, ...).
551  *
552  * Note, in reserving a device, if the device is for the
553  *  same pool and the same pool type, then it is acceptable.
554  *  The Media Type has already been checked. If we are
555  *  the first tor reserve the device, we put the pool
556  *  name and pool type in the device record.
557  */
558 static bool reserve_device_for_append(DCR *dcr)
559 {
560    JCR *jcr = dcr->jcr;
561    DEVICE *dev = dcr->dev;
562    bool ok = false;
563
564    ASSERT(dcr);
565
566    dev->block(BST_DOING_ACQUIRE);
567
568    if (dev->can_read()) {
569       Mmsg1(jcr->errmsg, _("Device %s is busy reading.\n"), dev->print_name());
570       goto bail_out;
571    }
572
573    if (device_is_unmounted(dev)) {
574       Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"), dev->print_name());
575       goto bail_out;
576    }
577
578    Dmsg1(190, "reserve_append device is %s\n", dev->is_tape()?"tape":"disk");
579
580    if (can_reserve_drive(dcr) != 1) {
581       Mmsg1(jcr->errmsg, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
582       goto bail_out;
583    }
584
585    dev->reserved_device++;
586    Dmsg1(200, "============= Inc reserve=%d\n", dev->reserved_device);
587    dcr->reserved_device = true;
588    ok = true;
589
590 bail_out:
591    dev->unblock();
592    return ok;
593 }
594
595 /*
596  * Returns: 1 if drive can be reserved
597  *          0 if we should wait
598  *         -1 on error
599  */
600 static int can_reserve_drive(DCR *dcr) 
601 {
602    DEVICE *dev = dcr->dev;
603    JCR *jcr = dcr->jcr;
604    /*
605     * First handle the case that the drive is not yet in append mode
606     */
607    if (!dev->can_append() && dev->num_writers == 0) {
608       /* Now check if there are any reservations on the drive */
609       if (dev->reserved_device) {           
610          /* Yes, now check if we want the same Pool and pool type */
611          if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
612              strcmp(dev->pool_type, dcr->pool_type) == 0) {
613             /* OK, compatible device */
614          } else {
615             /* Drive not suitable for us */
616             return 0;                 /* wait */
617          }
618       } else {
619          /* Device is available but not yet reserved, reserve it for us */
620          bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
621          bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
622       }
623       return 1;                       /* reserve drive */
624    }
625
626    /*
627     * Check if device in append mode with no writers (i.e. available)
628     */
629    if (dev->can_append() && dev->num_writers == 0) {
630       /* Device is available but not yet reserved, reserve it for us */
631       bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
632       bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
633       return 1;
634    }
635
636    /*
637     * Now check if the device is in append mode with writers (i.e.
638     *  available if pool is the same).
639     */
640    if (dev->can_append() || dev->num_writers > 0) {
641       Dmsg0(190, "device already in append.\n");
642       /* Yes, now check if we want the same Pool and pool type */
643       if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
644           strcmp(dev->pool_type, dcr->pool_type) == 0) {
645          /* OK, compatible device */
646       } else {
647          /* Drive not suitable for us */
648          Jmsg(jcr, M_WARNING, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
649          return 0;                    /* wait */
650       }
651    } else {
652       Pmsg0(000, "Logic error!!!! Should not get here.\n");
653       Jmsg0(jcr, M_FATAL, 0, _("Logic error!!!! Should not get here.\n"));
654       return -1;                      /* error, should not get here */
655    }
656    return 1;                          /* reserve drive */
657 }