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