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