]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/reserve.c
Tweak debug levels in reservations + Correct typo in UTF-8 error message as reported by:
[bacula/bacula] / bacula / src / stored / reserve.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation plus additions
11    that are listed in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *   Drive reservation functions for Storage Daemon
30  *
31  *   Kern Sibbald, MM
32  *
33  *   Split from job.c and acquire.c June 2005
34  *
35  *   Version $Id$
36  *
37  */
38
39 #include "bacula.h"
40 #include "stored.h"
41
42 static dlist *vol_list = NULL;
43 static pthread_mutex_t vol_list_lock = PTHREAD_MUTEX_INITIALIZER;
44
45 /* Forward referenced functions */
46 static int can_reserve_drive(DCR *dcr, RCTX &rctx);
47 static int reserve_device(RCTX &rctx);
48 static bool reserve_device_for_read(DCR *dcr);
49 static bool reserve_device_for_append(DCR *dcr, RCTX &rctx);
50 static bool use_storage_cmd(JCR *jcr);
51 static void queue_reserve_message(JCR *jcr);
52
53 /* Requests from the Director daemon */
54 static char use_storage[]  = "use storage=%127s media_type=%127s "
55    "pool_name=%127s pool_type=%127s append=%d copy=%d stripe=%d\n";
56 static char use_device[]  = "use device=%127s\n";
57
58 /* Responses sent to Director daemon */
59 static char OK_device[] = "3000 OK use device device=%s\n";
60 static char NO_device[] = "3924 Device \"%s\" not in SD Device resources.\n";
61 static char BAD_use[]   = "3913 Bad use command: %s\n";
62
63 bool use_cmd(JCR *jcr) 
64 {
65    /*
66     * Get the device, media, and pool information
67     */
68    if (!use_storage_cmd(jcr)) {
69       set_jcr_job_status(jcr, JS_ErrorTerminated);
70       memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
71       return false;
72    }
73    return true;
74 }
75
76 static int my_compare(void *item1, void *item2)
77 {
78    return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
79 }
80
81 static brwlock_t reservation_lock;
82
83 void init_reservations_lock()
84 {
85    int errstat;
86    if ((errstat=rwl_init(&reservation_lock)) != 0) {
87       berrno be;
88       Emsg1(M_ABORT, 0, _("Unable to initialize reservation lock. ERR=%s\n"),
89             be.bstrerror(errstat));
90    }
91
92 }
93
94 void term_reservations_lock()
95 {
96    rwl_destroy(&reservation_lock);
97 }
98
99 int reservations_lock_count = 0;
100
101 /* This applies to a drive and to Volumes */
102 void _lock_reservations()
103 {
104    int errstat;
105    reservations_lock_count++;
106    if ((errstat=rwl_writelock(&reservation_lock)) != 0) {
107       berrno be;
108       Emsg2(M_ABORT, 0, "rwl_writelock failure. stat=%d: ERR=%s\n",
109            errstat, be.bstrerror(errstat));
110    }
111 }
112
113 void _unlock_reservations()
114 {
115    int errstat;
116    reservations_lock_count--;
117    if ((errstat=rwl_writeunlock(&reservation_lock)) != 0) {
118       berrno be;
119       Emsg2(M_ABORT, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n",
120            errstat, be.bstrerror(errstat));
121    }
122 }
123
124 /*
125  * List Volumes -- this should be moved to status.c
126  */
127 enum {
128    debug_lock = true,
129    debug_nolock = false
130 };
131
132 static void debug_list_volumes(const char *imsg, bool do_lock)
133 {
134    VOLRES *vol;
135    POOL_MEM msg(PM_MESSAGE);
136    int count = 0;
137    DEVICE *dev = NULL;
138
139    if (do_lock) P(vol_list_lock);
140    for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
141       if (vol->dev) {
142          Mmsg(msg, "List from %s: %s at %p on device %s\n", imsg, 
143               vol->vol_name, vol->vol_name, vol->dev->print_name());
144       } else {
145          Mmsg(msg, "List from %s: %s at %p no dev\n", imsg, vol->vol_name, vol->vol_name);
146       }
147       Dmsg1(100, "%s", msg.c_str());
148       count++;
149    }
150
151    for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
152       if (vol->dev == dev) {
153          Dmsg0(000, "Two Volumes on same device.\n");
154          ASSERT(0);
155          dev = vol->dev;
156       }
157    }
158
159    Dmsg2(100, "List from %s: %d volumes\n", imsg, count);
160    if (do_lock) V(vol_list_lock);
161 }
162
163
164 /*
165  * List Volumes -- this should be moved to status.c
166  */
167 void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
168 {
169    VOLRES *vol;
170    POOL_MEM msg(PM_MESSAGE);
171    int len;
172
173    P(vol_list_lock);
174    for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
175       if (vol->dev) {
176          len = Mmsg(msg, "%s on device %s\n", vol->vol_name, vol->dev->print_name());
177          sendit(msg.c_str(), len, arg);
178       } else {
179          len = Mmsg(msg, "%s no dev\n", vol->vol_name);
180          sendit(msg.c_str(), len, arg);
181       }
182    }
183    V(vol_list_lock);
184 }
185
186 /*
187  * Create a Volume item to put in the Volume list
188  *   Ensure that the device points to it.
189  */
190 static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName)
191 {
192    VOLRES *vol;
193    vol = (VOLRES *)malloc(sizeof(VOLRES));
194    memset(vol, 0, sizeof(VOLRES));
195    vol->vol_name = bstrdup(VolumeName);
196    vol->dev = dcr->dev;
197    Dmsg4(100, "New Vol=%s at %p dev=%s JobId=%u\n", VolumeName, vol->vol_name,
198          vol->dev->print_name(), (int)dcr->jcr->JobId);
199    return vol;
200 }
201
202 static void free_vol_item(VOLRES *vol)
203 {
204    free(vol->vol_name);
205    if (vol->dev) {
206       vol->dev->vol = NULL;
207    }
208    free(vol);
209 }
210
211
212 /*
213  * Put a new Volume entry in the Volume list. This
214  *  effectively reserves the volume so that it will
215  *  not be mounted again.
216  *
217  * If the device has any current volume associated with it,
218  *  and it is a different Volume, and the device is not busy,
219  *  we release the old Volume item and insert the new one.
220  * 
221  * It is assumed that the device is free and locked so that
222  *  we can change the device structure.
223  *
224  * Some details of the Volume list handling:
225  *
226  *  1. The Volume list entry must be attached to the drive (rather than 
227  *       attached to a job as it currently is. I.e. the drive that "owns" 
228  *       the volume (reserved, in use, mounted)
229  *       must point to the volume (still to be maintained in a list).
230  *
231  *  2. The Volume is entered in the list when a drive is reserved.  
232  *
233  *  3. When a drive is in use, the device code must appropriately update the
234  *      volume name as it changes (currently the list is static -- an entry is
235  *      removed when the Volume is no longer reserved, in use or mounted).  
236  *      The new code must keep the same list entry as long as the drive
237  *       has any volume associated with it but the volume name in the list
238  *       must be updated when the drive has a different volume mounted.
239  *
240  *  4. A job that has reserved a volume, can un-reserve the volume, and if the 
241  *      volume is not mounted, and not reserved, and not in use, it will be
242  *      removed from the list.
243  *
244  *  5. If a job wants to reserve a drive with a different Volume from the one on
245  *      the drive, it can re-use the drive for the new Volume.
246  *
247  *  6. If a job wants a Volume that is in a different drive, it can either use the
248  *      other drive or take the volume, only if the other drive is not in use or
249  *      not reserved.
250  *
251  *  One nice aspect of this is that the reserve use count and the writer use count 
252  *  already exist and are correctly programmed and will need no changes -- use 
253  *  counts are always very tricky.
254  *
255  *  The old code had a concept of "reserving" a Volume, but it needs to be changed 
256  *  to reserving and using a drive.  A volume is must be attached to (owned by) a 
257  *  drive and can move from drive to drive or be unused given certain specific 
258  *  conditions of the drive.  The key is that the drive must "own" the Volume.  
259  *  The old code has the job (dcr) owning the volume (more or less).  The job is 
260  *  to change the insertion and removal of the volumes from the list to be based 
261  *  on the drive rather than the job.  The new logic described above needs to be 
262  *  reviewed a couple more times for completeness and correctness.  Then I can 
263  *  program it.
264
265  *
266  *  Return: VOLRES entry on success
267  *          NULL volume busy on another drive
268  */
269 VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
270 {
271    VOLRES *vol, *nvol;
272    DEVICE *dev = dcr->dev;
273
274    ASSERT(dev != NULL);
275
276    Dmsg1(100, "reserve_volume %s\n", VolumeName);
277    /* 
278     * We lock the reservations system here to ensure
279     *  when adding a new volume that no newly scheduled
280     *  job can reserve it.
281     */
282    P(vol_list_lock);
283    debug_list_volumes("begin reserve_volume", debug_nolock);
284    /* 
285     * First, remove any old volume attached to this device as it
286     *  is no longer used.
287     */
288    if (dev->vol) {
289       vol = dev->vol;
290       /*
291        * Make sure we don't remove the current volume we are inserting
292        *  because it was probably inserted by another job.
293        */
294       if (strcmp(vol->vol_name, VolumeName) == 0) {
295          goto get_out;                  /* Volume already on this device */
296       } else {
297          Dmsg3(100, "reserve_vol free vol=%s at %p JobId=%u\n", vol->vol_name,
298                vol->vol_name, (int)dcr->jcr->JobId);
299          debug_list_volumes("reserve_vol free", debug_nolock);
300          vol_list->remove(vol);
301          free_vol_item(vol);
302       }
303    }
304
305    /* Create a new Volume entry */
306    nvol = new_vol_item(dcr, VolumeName);
307
308    /*
309     * Now try to insert the new Volume
310     */
311    vol = (VOLRES *)vol_list->binary_insert(nvol, my_compare);
312    if (vol != nvol) {
313       Dmsg2(100, "Found vol=%s dev-same=%d\n", vol->vol_name, dev==vol->dev);
314       /*
315        * At this point, a Volume with this name already is in the list,
316        *   so we simply release our new Volume entry. Note, this should
317        *   only happen if we are moving the volume from one drive to another.
318        */
319       Dmsg3(100, "reserve_vol free-tmp vol=%s at %p JobId=%u\n", vol->vol_name,
320             vol->vol_name, (int)dcr->jcr->JobId);
321       /*
322        * Clear dev pointer so that free_vol_item() doesn't 
323        *  take away our volume. 
324        */
325       nvol->dev = NULL;                   /* don't zap dev entry */
326       free_vol_item(nvol);
327
328       /* Check if we are trying to use the Volume on a different drive */
329       if (dev != vol->dev) {
330          /* Caller wants to switch Volume to another device */
331          if (!vol->dev->is_busy()) {
332             /* OK to move it -- I'm not sure this will work */
333             Dmsg3(100, "==== Swap vol=%s from dev=%s to %s\n", VolumeName,
334                vol->dev->print_name(), dev->print_name());
335             vol->dev->vol = NULL;         /* take vol from old drive */
336             vol->dev->VolHdr.VolumeName[0] = 0;
337             vol->dev = dev;               /* point vol at new drive */
338             dev->vol = vol;               /* point dev at vol */
339             dev->VolHdr.VolumeName[0] = 0;
340          } else {
341             Dmsg3(100, "Volume busy could not swap vol=%s from dev=%s to %s\n", VolumeName,
342                vol->dev->print_name(), dev->print_name());
343             vol = NULL;                /* device busy */
344          }
345       }
346    }
347    dev->vol = vol;
348
349 get_out:
350    debug_list_volumes("end new volume", debug_nolock);
351    V(vol_list_lock);
352    return vol;
353 }
354
355 /*
356  * Search for a Volume name in the Volume list.
357  *
358  *  Returns: VOLRES entry on success
359  *           NULL if the Volume is not in the list
360  */
361 VOLRES *find_volume(const char *VolumeName)
362 {
363    VOLRES vol, *fvol;
364    /* Do not lock reservations here */
365    P(vol_list_lock);
366    vol.vol_name = bstrdup(VolumeName);
367    fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
368    free(vol.vol_name);
369    Dmsg2(100, "find_vol=%s found=%d\n", VolumeName, fvol!=NULL);
370    debug_list_volumes("find_volume", debug_nolock);
371    V(vol_list_lock);
372    return fvol;
373 }
374
375 /* 
376  * Remove any reservation from a drive and tell the system
377  *  that the volume is unused at least by us.
378  */
379 void unreserve_device(DCR *dcr)
380 {
381    DEVICE *dev = dcr->dev;
382    dev->dlock();
383    if (dcr->reserved_device) {
384       dcr->reserved_device = false;
385       dev->reserved_device--;
386       Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
387       dcr->reserved_device = false;
388       /* If we set read mode in reserving, remove it */
389       if (dev->can_read()) {
390          dev->clear_read();
391       }
392       if (dev->num_writers < 0) {
393          Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers);
394          dev->num_writers = 0;
395       }
396    }
397
398    volume_unused(dcr);
399    dev->dunlock();
400 }
401
402 /*  
403  * Free a Volume from the Volume list if it is no longer used
404  *
405  *  Returns: true if the Volume found and removed from the list
406  *           false if the Volume is not in the list or is in use
407  */
408 bool volume_unused(DCR *dcr)
409 {
410    DEVICE *dev = dcr->dev;
411
412    if (dev->vol == NULL) {
413       Dmsg1(100, " unreserve_volume: no vol on %s\n", dev->print_name());
414       debug_list_volumes("null return unreserve_volume", debug_lock);
415       return false;
416    }
417
418    if (dev->is_busy()) {
419       Dmsg1(100, "unreserve_volume: dev is busy %s\n", dev->print_name());
420       debug_list_volumes("dev busy return unreserve_volume", debug_lock);
421       return false;
422    }
423
424    return free_volume(dev);
425 }
426
427 /*
428  * Unconditionally release the volume
429  */
430 bool free_volume(DEVICE *dev)
431 {
432    VOLRES *vol;
433
434    if (dev->vol == NULL) {
435       Dmsg1(100, "No vol on dev %s\n", dev->print_name());
436       return false;
437    }
438    P(vol_list_lock);
439    vol = dev->vol;
440    dev->vol = NULL;
441    Dmsg1(100, "free_volume %s\n", vol->vol_name);
442    vol_list->remove(vol);
443    Dmsg3(100, "free_volume %s at %p dev=%s\n", vol->vol_name, vol->vol_name,
444          dev->print_name());
445    free_vol_item(vol);
446    debug_list_volumes("free_volume", debug_nolock);
447    V(vol_list_lock);
448    return vol != NULL;
449 }
450
451       
452 /* Create the Volume list */
453 void create_volume_list()
454 {
455    VOLRES *dummy = NULL;
456    if (vol_list == NULL) {
457       vol_list = New(dlist(dummy, &dummy->link));
458    }
459 }
460
461 /* Release all Volumes from the list */
462 void free_volume_list()
463 {
464    VOLRES *vol;
465    if (!vol_list) {
466       return;
467    }
468    P(vol_list_lock);
469    for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
470       Dmsg2(100, "Unreleased Volume=%s dev=%p\n", vol->vol_name, vol->dev);
471       free(vol->vol_name);
472       vol->vol_name = NULL;
473    }
474    delete vol_list;
475    vol_list = NULL;
476    V(vol_list_lock);
477 }
478
479 bool is_volume_in_use(DCR *dcr)
480 {
481    VOLRES *vol = find_volume(dcr->VolumeName);
482    if (!vol) {
483       Dmsg1(100, "Vol=%s not in use.\n", dcr->VolumeName);
484       return false;                   /* vol not in list */
485    }
486    ASSERT(vol->dev != NULL);
487
488    if (dcr->dev == vol->dev) {        /* same device OK */
489       Dmsg1(100, "Vol=%s on same dev.\n", dcr->VolumeName);
490       return false;
491    }
492    if (!vol->dev->is_busy()) {
493       Dmsg2(100, "Vol=%s dev=%s not busy.\n", dcr->VolumeName, vol->dev->print_name());
494       return false;
495    }
496    Dmsg2(100, "Vol=%s used by %s.\n", dcr->VolumeName, vol->dev->print_name());
497    return true;
498 }
499
500
501 /*
502  * We get the following type of information:
503  *
504  * use storage=xxx media_type=yyy pool_name=xxx pool_type=yyy append=1 copy=0 strip=0
505  *  use device=zzz
506  *  use device=aaa
507  *  use device=bbb
508  * use storage=xxx media_type=yyy pool_name=xxx pool_type=yyy append=0 copy=0 strip=0
509  *  use device=bbb
510  *
511  */
512 static bool use_storage_cmd(JCR *jcr)
513 {
514    POOL_MEM store_name, dev_name, media_type, pool_name, pool_type;
515    BSOCK *dir = jcr->dir_bsock;
516    int append;
517    bool ok;       
518    int Copy, Stripe;
519    DIRSTORE *store;
520    RCTX rctx;
521    char *msg;
522    alist *msgs;
523    alist *dirstore;
524
525    memset(&rctx, 0, sizeof(RCTX));
526    rctx.jcr = jcr;
527    /*
528     * If there are multiple devices, the director sends us
529     *   use_device for each device that it wants to use.
530     */
531    dirstore = New(alist(10, not_owned_by_alist));
532 // Dmsg2(000, "dirstore=%p JobId=%u\n", dirstore, jcr->JobId);
533    msgs = jcr->reserve_msgs = New(alist(10, not_owned_by_alist));  
534    do {
535       Dmsg1(100, "<dird: %s", dir->msg);
536       ok = sscanf(dir->msg, use_storage, store_name.c_str(), 
537                   media_type.c_str(), pool_name.c_str(), 
538                   pool_type.c_str(), &append, &Copy, &Stripe) == 7;
539       if (!ok) {
540          break;
541       }
542       if (append) {
543          jcr->write_store = dirstore;
544       } else {
545          jcr->read_store = dirstore;
546       }
547       rctx.append = append;
548       unbash_spaces(store_name);
549       unbash_spaces(media_type);
550       unbash_spaces(pool_name);
551       unbash_spaces(pool_type);
552       store = new DIRSTORE;
553       dirstore->append(store);
554       memset(store, 0, sizeof(DIRSTORE));
555       store->device = New(alist(10));
556       bstrncpy(store->name, store_name, sizeof(store->name));
557       bstrncpy(store->media_type, media_type, sizeof(store->media_type));
558       bstrncpy(store->pool_name, pool_name, sizeof(store->pool_name));
559       bstrncpy(store->pool_type, pool_type, sizeof(store->pool_type));
560       store->append = append;
561
562       /* Now get all devices */
563       while (dir->recv() >= 0) {
564          Dmsg1(100, "<dird device: %s", dir->msg);
565          ok = sscanf(dir->msg, use_device, dev_name.c_str()) == 1;
566          if (!ok) {
567             break;
568          }
569          unbash_spaces(dev_name);
570          store->device->append(bstrdup(dev_name.c_str()));
571       }
572    }  while (ok && dir->recv() >= 0);
573
574 #ifdef DEVELOPER
575    /* This loop is debug code and can be removed */
576    /* ***FIXME**** remove after 1.38 release */
577    char *device_name;
578    foreach_alist(store, dirstore) {
579       Dmsg6(110, "JobId=%u Storage=%s media_type=%s pool=%s pool_type=%s append=%d\n", 
580          (int)rctx.jcr->JobId,
581          store->name, store->media_type, store->pool_name, 
582          store->pool_type, store->append);
583       foreach_alist(device_name, store->device) {
584          Dmsg1(110, "   Device=%s\n", device_name);
585       }
586    }
587 #endif
588
589    init_jcr_device_wait_timers(jcr);
590    /*                    
591     * At this point, we have a list of all the Director's Storage
592     *  resources indicated for this Job, which include Pool, PoolType,
593     *  storage name, and Media type.     
594     * Then for each of the Storage resources, we have a list of
595     *  device names that were given.
596     *
597     * Wiffle through them and find one that can do the backup.
598     */
599    if (ok) {
600       int retries = 0;                /* wait for device retries */
601       bool fail = false;
602       rctx.notify_dir = true;
603       lock_reservations();
604       for ( ; !fail && !job_canceled(jcr); ) {
605          while ((msg = (char *)msgs->pop())) {
606             free(msg);
607          }
608          rctx.suitable_device = false;
609          rctx.have_volume = false;
610          rctx.VolumeName[0] = 0;
611          rctx.any_drive = false;
612          if (!jcr->PreferMountedVols) {
613             /* Look for unused drives in autochangers */
614             rctx.num_writers = 20000000;   /* start with impossible number */
615             rctx.low_use_drive = NULL;
616             rctx.PreferMountedVols = false;                
617             rctx.exact_match = false;
618             rctx.autochanger_only = true;
619             Dmsg6(110, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
620                (int)rctx.jcr->JobId,
621                rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
622                rctx.autochanger_only, rctx.any_drive);
623             if ((ok = find_suitable_device_for_job(jcr, rctx))) {
624                break;
625             }
626             /* Look through all drives possibly for low_use drive */
627             if (rctx.low_use_drive) {
628                rctx.try_low_use_drive = true;
629                if ((ok = find_suitable_device_for_job(jcr, rctx))) {
630                   break;
631                }
632                rctx.try_low_use_drive = false;
633             }
634             rctx.autochanger_only = false;
635             Dmsg6(110, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
636                (int)rctx.jcr->JobId,
637                rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
638                rctx.autochanger_only, rctx.any_drive);
639             if ((ok = find_suitable_device_for_job(jcr, rctx))) {
640                break;
641             }
642          }
643          /* Look for an exact match all drives */
644          rctx.PreferMountedVols = true;
645          rctx.exact_match = true;
646          rctx.autochanger_only = false;
647          Dmsg6(110, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
648             (int)rctx.jcr->JobId,
649             rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
650             rctx.autochanger_only, rctx.any_drive);
651          if ((ok = find_suitable_device_for_job(jcr, rctx))) {
652             break;
653          }
654          /* Look for any mounted drive */
655          rctx.exact_match = false;
656          Dmsg6(110, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
657             (int)rctx.jcr->JobId,
658             rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
659             rctx.autochanger_only, rctx.any_drive);
660          if ((ok = find_suitable_device_for_job(jcr, rctx))) {
661             break;
662          }
663          /* Try any drive */
664          rctx.any_drive = true;
665          Dmsg6(110, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
666             (int)rctx.jcr->JobId,
667             rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
668             rctx.autochanger_only, rctx.any_drive);
669          if ((ok = find_suitable_device_for_job(jcr, rctx))) {
670             break;
671          }
672          /* Keep reservations locked *except* during wait_for_device() */
673          unlock_reservations();
674          if (!rctx.suitable_device || !wait_for_device(jcr, retries)) {
675             Dmsg1(100, "JobId=%u Fail. !suitable_device || !wait_for_device\n",
676                  (int)rctx.jcr->JobId);
677             fail = true;
678          }   
679          lock_reservations();
680          bnet_sig(dir, BNET_HEARTBEAT);  /* Inform Dir that we are alive */
681       }
682       unlock_reservations();
683       if (!ok) {
684          /*
685           * If we get here, there are no suitable devices available, which
686           *  means nothing configured.  If a device is suitable but busy
687           *  with another Volume, we will not come here.
688           */
689          unbash_spaces(dir->msg);
690          pm_strcpy(jcr->errmsg, dir->msg);
691          Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
692          Jmsg(jcr, M_FATAL, 0, _("\n"
693             "     Device \"%s\" with MediaType \"%s\" requested by DIR not found in SD Device resources.\n"),
694               dev_name.c_str(), media_type.c_str());
695          bnet_fsend(dir, NO_device, dev_name.c_str());
696
697          Dmsg1(100, ">dird: %s", dir->msg);
698       }
699    } else {
700       unbash_spaces(dir->msg);
701       pm_strcpy(jcr->errmsg, dir->msg);
702       Jmsg(jcr, M_FATAL, 0, _("Failed command: %s\n"), jcr->errmsg);
703       bnet_fsend(dir, BAD_use, jcr->errmsg);
704       Dmsg1(100, ">dird: %s", dir->msg);
705    }
706
707    release_msgs(jcr);
708    return ok;
709 }
710
711 void release_msgs(JCR *jcr)
712 {
713    alist *msgs = jcr->reserve_msgs;
714    char *msg;
715
716    if (!msgs) {
717       return;
718    }
719    lock_reservations();
720    while ((msg = (char *)msgs->pop())) {
721       free(msg);
722    }
723    delete msgs;
724    jcr->reserve_msgs = NULL;
725    unlock_reservations();
726 }
727
728 /*
729  * Search for a device suitable for this job.
730  */
731 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx)
732 {
733    bool ok;
734    DIRSTORE *store;
735    char *device_name;
736    alist *dirstore;
737
738    if (rctx.append) {
739       dirstore = jcr->write_store;
740    } else {
741       dirstore = jcr->read_store;
742    }
743    /* 
744     * For each storage device that the user specified, we
745     *  search and see if there is a resource for that device.
746     */
747    Dmsg5(110, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d\n",
748       (int)rctx.jcr->JobId,
749       rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
750       rctx.autochanger_only);
751    ok = false;
752    foreach_alist(store, dirstore) {
753       rctx.store = store;
754       foreach_alist(device_name, store->device) {
755          int stat;
756          rctx.device_name = device_name;
757          stat = search_res_for_device(rctx); 
758          if (stat == 1) {             /* found available device */
759             Dmsg2(100, "JobId=%u Suitable device found=%s\n", (int)rctx.jcr->JobId, 
760                   device_name);
761             ok = true;
762             break;
763          } else if (stat == 0) {      /* device busy */
764             Dmsg2(110, "JobId=%u Suitable device=%s, busy: not use\n", 
765                   (int)rctx.jcr->JobId, device_name);
766          } else {
767             /* otherwise error */
768             Dmsg1(110, "JobId=%u No suitable device found.\n", (int)rctx.jcr->JobId);
769          }
770       }
771       if (ok) {
772          break;
773       }
774    }
775    return ok;
776 }
777
778 /*
779  * Search for a particular storage device with particular storage
780  *  characteristics (MediaType).
781  */
782 int search_res_for_device(RCTX &rctx) 
783 {
784    AUTOCHANGER *changer;
785    BSOCK *dir = rctx.jcr->dir_bsock;
786    bool ok;
787    int stat;
788
789    Dmsg2(110, "JobId=%u search res for %s\n", (int)rctx.jcr->JobId, rctx.device_name);
790    /* Look through Autochangers first */
791    foreach_res(changer, R_AUTOCHANGER) {
792       Dmsg2(150, "JobId=%u Try match changer res=%s\n", (int)rctx.jcr->JobId, changer->hdr.name);
793       /* Find resource, and make sure we were able to open it */
794       if (fnmatch(rctx.device_name, changer->hdr.name, 0) == 0) {
795          /* Try each device in this AutoChanger */
796          foreach_alist(rctx.device, changer->device) {
797             Dmsg2(110, "JobId=%u Try changer device %s\n", (int)rctx.jcr->JobId, 
798                   rctx.device->hdr.name);
799             stat = reserve_device(rctx);
800             if (stat != 1) {             /* try another device */
801                continue;
802             }
803             POOL_MEM dev_name;
804             if (rctx.store->append == SD_APPEND) {
805                Dmsg3(100, "JobId=%u Device %s reserved=%d for append.\n", 
806                   (int)rctx.jcr->JobId, rctx.device->hdr.name,
807                   rctx.jcr->dcr->dev->reserved_device);
808             } else {
809                Dmsg3(100, "JobId=%u Device %s reserved=%d for read.\n", 
810                   (int)rctx.jcr->JobId, rctx.device->hdr.name,
811                   rctx.jcr->read_dcr->dev->reserved_device);
812             }
813             if (rctx.notify_dir) {
814                pm_strcpy(dev_name, rctx.device->hdr.name);
815                bash_spaces(dev_name);
816                ok = bnet_fsend(dir, OK_device, dev_name.c_str());  /* Return real device name */
817                Dmsg1(100, ">dird changer: %s", dir->msg);
818             } else {
819                ok = true;
820             }
821             return ok ? 1 : -1;
822          }
823       }
824    }
825
826    /* Now if requested look through regular devices */
827    if (!rctx.autochanger_only) {
828       foreach_res(rctx.device, R_DEVICE) {
829          Dmsg2(150, "JobId=%u Try match res=%s\n", (int)rctx.jcr->JobId, rctx.device->hdr.name);
830          /* Find resource, and make sure we were able to open it */
831          if (fnmatch(rctx.device_name, rctx.device->hdr.name, 0) == 0) {
832             stat = reserve_device(rctx);
833             if (stat != 1) {
834                return stat;
835             }
836             if (rctx.notify_dir) {
837                bash_spaces(rctx.device_name);
838                ok = bnet_fsend(dir, OK_device, rctx.device_name);
839                Dmsg1(100, ">dird dev: %s", dir->msg);
840             } else {
841                ok = true;
842             }
843             return ok ? 1 : -1;
844          }
845       }
846    }
847    return -1;                    /* nothing found */
848 }
849
850 /*
851  *  Try to reserve a specific device.
852  *
853  *  Returns: 1 -- OK, have DCR
854  *           0 -- must wait
855  *          -1 -- fatal error
856  */
857 static int reserve_device(RCTX &rctx)
858 {
859    bool ok;
860    DCR *dcr;
861    const int name_len = MAX_NAME_LENGTH;
862
863    /* Make sure MediaType is OK */
864    Dmsg3(110, "JobId=%u MediaType device=%s request=%s\n",
865          (int)rctx.jcr->JobId,
866          rctx.device->media_type, rctx.store->media_type);
867    if (strcmp(rctx.device->media_type, rctx.store->media_type) != 0) {
868       return -1;
869    }
870
871    /* Make sure device exists -- i.e. we can stat() it */
872    if (!rctx.device->dev) {
873       rctx.device->dev = init_dev(rctx.jcr, rctx.device);
874    }
875    if (!rctx.device->dev) {
876       if (rctx.device->changer_res) {
877         Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
878            "     Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
879              rctx.device->hdr.name, rctx.device_name);
880       } else {
881          Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
882             "     Device \"%s\" requested by DIR could not be opened or does not exist.\n"),
883               rctx.device_name);
884       }
885       return -1;  /* no use waiting */
886    }  
887
888    rctx.suitable_device = true;
889    Dmsg2(110, "Try reserve %s JobId=%u\n", rctx.device->hdr.name,
890          rctx.jcr->JobId);
891    dcr = new_dcr(rctx.jcr, rctx.device->dev);
892    if (!dcr) {
893       BSOCK *dir = rctx.jcr->dir_bsock;
894       bnet_fsend(dir, _("3926 Could not get dcr for device: %s\n"), rctx.device_name);
895       Dmsg1(100, ">dird: %s", dir->msg);
896       return -1;
897    }
898    bstrncpy(dcr->pool_name, rctx.store->pool_name, name_len);
899    bstrncpy(dcr->pool_type, rctx.store->pool_type, name_len);
900    bstrncpy(dcr->media_type, rctx.store->media_type, name_len);
901    bstrncpy(dcr->dev_name, rctx.device_name, name_len);
902    if (rctx.store->append == SD_APPEND) {
903       Dmsg3(100, "JobId=%u have_vol=%d vol=%s\n", (int)rctx.jcr->JobId,
904           rctx.have_volume, rctx.VolumeName);                                   
905       if (!rctx.have_volume) {
906          dcr->any_volume = true;
907          if (dir_find_next_appendable_volume(dcr)) {
908             bstrncpy(rctx.VolumeName, dcr->VolumeName, sizeof(rctx.VolumeName));
909             Dmsg2(100, "JobId=%u looking for Volume=%s\n", (int)rctx.jcr->JobId, rctx.VolumeName);
910             rctx.have_volume = true;
911          } else {
912             Dmsg1(100, "JobId=%u No next volume found\n", (int)rctx.jcr->JobId);
913             rctx.have_volume = false;
914             rctx.VolumeName[0] = 0;
915         }
916       }
917       ok = reserve_device_for_append(dcr, rctx);
918       if (ok) {
919          rctx.jcr->dcr = dcr;
920          Dmsg6(100, "JobId=%u Reserved=%d dev_name=%s mediatype=%s pool=%s ok=%d\n",
921                (int)rctx.jcr->JobId,
922                dcr->dev->reserved_device,
923                dcr->dev_name, dcr->media_type, dcr->pool_name, ok);
924       }
925    } else {
926       ok = reserve_device_for_read(dcr);
927       if (ok) {
928          rctx.jcr->read_dcr = dcr;
929          Dmsg6(100, "JobId=%u Read reserved=%d dev_name=%s mediatype=%s pool=%s ok=%d\n",
930                (int)rctx.jcr->JobId,
931                dcr->dev->reserved_device,
932                dcr->dev_name, dcr->media_type, dcr->pool_name, ok);
933       }
934    }
935    if (!ok) {
936       rctx.have_volume = false;
937       free_dcr(dcr);
938       Dmsg1(110, "JobId=%u Not OK.\n", (int)rctx.jcr->JobId);
939       return 0;
940    }
941    return 1;
942 }
943
944 /*
945  * We "reserve" the drive by setting the ST_READ bit. No one else
946  *  should touch the drive until that is cleared.
947  *  This allows the DIR to "reserve" the device before actually
948  *  starting the job. 
949  */
950 static bool reserve_device_for_read(DCR *dcr)
951 {
952    DEVICE *dev = dcr->dev;
953    JCR *jcr = dcr->jcr;
954    bool ok = false;
955
956    ASSERT(dcr);
957
958    dev->dlock();  
959
960    if (is_device_unmounted(dev)) {             
961       Dmsg2(200, "JobId=%u Device %s is BLOCKED due to user unmount.\n", 
962          (int)jcr->JobId, dev->print_name());
963       Mmsg(jcr->errmsg, _("3601 JobId=%u device %s is BLOCKED due to user unmount.\n"),
964            jcr->JobId, dev->print_name());
965       queue_reserve_message(jcr);
966       goto bail_out;
967    }
968
969    if (dev->is_busy()) {
970       Dmsg5(200, "JobId=%u Device %s is busy ST_READ=%d num_writers=%d reserved=%d.\n", 
971          (int)jcr->JobId, dev->print_name(),
972          dev->state & ST_READ?1:0, dev->num_writers, dev->reserved_device);
973       Mmsg(jcr->errmsg, _("3602 JobId=%u device %s is busy (already reading/writing).\n"),
974             jcr->JobId, dev->print_name());
975       queue_reserve_message(jcr);
976       goto bail_out;
977    }
978
979    dev->clear_append();
980    dev->set_read();
981    ok = true;
982    dev->reserved_device++;
983    Dmsg4(100, "JobId=%u Inc reserve=%d dev=%s %p\n", (int)jcr->JobId,
984       dev->reserved_device, dev->print_name(), dev);
985    dcr->reserved_device = true;
986
987 bail_out:
988    dev->dunlock();
989    return ok;
990 }
991
992
993 /*
994  * We reserve the device for appending by incrementing the 
995  *  reserved_device. We do virtually all the same work that
996  *  is done in acquire_device_for_append(), but we do
997  *  not attempt to mount the device. This routine allows
998  *  the DIR to reserve multiple devices before *really* 
999  *  starting the job. It also permits the SD to refuse 
1000  *  certain devices (not up, ...).
1001  *
1002  * Note, in reserving a device, if the device is for the
1003  *  same pool and the same pool type, then it is acceptable.
1004  *  The Media Type has already been checked. If we are
1005  *  the first tor reserve the device, we put the pool
1006  *  name and pool type in the device record.
1007  */
1008 static bool reserve_device_for_append(DCR *dcr, RCTX &rctx)
1009 {
1010    JCR *jcr = dcr->jcr;
1011    DEVICE *dev = dcr->dev;
1012    bool ok = false;
1013
1014    ASSERT(dcr);
1015
1016    dev->dlock();
1017
1018    /* If device is being read, we cannot write it */
1019    if (dev->can_read()) {
1020       Mmsg(jcr->errmsg, _("3603 JobId=%u device %s is busy reading.\n"), 
1021          jcr->JobId, dev->print_name());
1022       Dmsg1(110, "%s", jcr->errmsg);
1023       queue_reserve_message(jcr);
1024       goto bail_out;
1025    }
1026
1027    /* If device is unmounted, we are out of luck */
1028    if (is_device_unmounted(dev)) {
1029       Mmsg(jcr->errmsg, _("3604 JobId=%u device %s is BLOCKED due to user unmount.\n"), 
1030          jcr->JobId, dev->print_name());
1031       Dmsg1(110, "%s", jcr->errmsg);
1032       queue_reserve_message(jcr);
1033       goto bail_out;
1034    }
1035
1036    Dmsg2(110, "JobId=%u reserve_append device is %s\n", 
1037        (int)jcr->JobId, dev->is_tape()?"tape":"disk");
1038
1039    /* Now do detailed tests ... */
1040    if (can_reserve_drive(dcr, rctx) != 1) {
1041       Dmsg1(110, "JobId=%u can_reserve_drive!=1\n", (int)jcr->JobId);
1042       goto bail_out;
1043    }
1044
1045    dev->reserved_device++;
1046    Dmsg4(100, "JobId=%u Inc reserve=%d dev=%s %p\n", (int)jcr->JobId, dev->reserved_device, 
1047       dev->print_name(), dev);
1048    dcr->reserved_device = true;
1049    ok = true;
1050
1051 bail_out:
1052    dev->dunlock();
1053    return ok;
1054 }
1055
1056 /*
1057  * Returns: 1 if drive can be reserved
1058  *          0 if we should wait
1059  *         -1 on error or impossibility
1060  */
1061 static int can_reserve_drive(DCR *dcr, RCTX &rctx) 
1062 {
1063    DEVICE *dev = dcr->dev;
1064    JCR *jcr = dcr->jcr;
1065
1066    Dmsg6(110, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
1067          (int)jcr->JobId,
1068          rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
1069          rctx.autochanger_only, rctx.any_drive);
1070
1071    /* setting any_drive overrides PreferMountedVols flag */
1072    if (!rctx.any_drive) {
1073       /*
1074        * When PreferMountedVols is set, we keep track of the 
1075        *  drive in use that has the least number of writers, then if
1076        *  no unmounted drive is found, we try that drive. This   
1077        *  helps spread the load to the least used drives.  
1078        */
1079       if (rctx.try_low_use_drive && dev == rctx.low_use_drive) {
1080          Dmsg3(110, "OK dev=%s == low_drive=%s. JobId=%u\n",
1081             dev->print_name(), rctx.low_use_drive->print_name(), jcr->JobId);
1082          return 1;
1083       }
1084       /* If he wants a free drive, but this one is busy, no go */
1085       if (!rctx.PreferMountedVols && dev->is_busy()) {
1086          /* Save least used drive */
1087          if ((dev->num_writers + dev->reserved_device) < rctx.num_writers) {
1088             rctx.num_writers = dev->num_writers + dev->reserved_device;
1089             rctx.low_use_drive = dev;
1090             Dmsg3(110, "JobId=%u set low use drive=%s num_writers=%d\n", 
1091                (int)jcr->JobId, dev->print_name(), rctx.num_writers);
1092          } else {
1093             Dmsg2(110, "JobId=%u not low use num_writers=%d\n", 
1094                (int)jcr->JobId, dev->num_writers+dev->reserved_device);
1095          }
1096          Dmsg1(110, "failed: !prefMnt && busy. JobId=%u\n", jcr->JobId);
1097          Mmsg(jcr->errmsg, _("3605 JobId=%u wants free drive but device %s is busy.\n"), 
1098             jcr->JobId, dev->print_name());
1099          queue_reserve_message(jcr);
1100          return 0;
1101       }
1102
1103       /* Check for prefer mounted volumes */
1104 //    if (rctx.PreferMountedVols && !dev->VolHdr.VolumeName[0] && dev->is_tape()) {
1105       if (rctx.PreferMountedVols && !dev->vol && dev->is_tape()) {
1106          Mmsg(jcr->errmsg, _("3606 JobId=%u prefers mounted drives, but drive %s has no Volume.\n"), 
1107             jcr->JobId, dev->print_name());
1108          queue_reserve_message(jcr);
1109          Dmsg1(110, "failed: want mounted -- no vol JobId=%u\n", (uint32_t)jcr->JobId);
1110          return 0;                 /* No volume mounted */
1111       }
1112
1113       /* Check for exact Volume name match */
1114       /*  ***FIXME***  use dev->vol.VolumeName */
1115       if (rctx.exact_match && rctx.have_volume &&
1116           strcmp(dev->VolHdr.VolumeName, rctx.VolumeName) != 0) {
1117          Mmsg(jcr->errmsg, _("3607 JobId=%u wants Vol=\"%s\" drive has Vol=\"%s\" on drive %s.\n"), 
1118             jcr->JobId, rctx.VolumeName, dev->VolHdr.VolumeName, 
1119             dev->print_name());
1120          queue_reserve_message(jcr);
1121          Dmsg3(110, "JobId=%u failed: Not exact match have=%s want=%s\n",
1122                (int)jcr->JobId, dev->VolHdr.VolumeName, rctx.VolumeName);
1123          return 0;
1124       }
1125    }
1126
1127    /* Check for unused autochanger drive */
1128    /* ***FIXME*** use !dev->is_busy() */
1129    if (rctx.autochanger_only && dev->num_writers == 0 &&
1130        dev->VolHdr.VolumeName[0] == 0) {
1131       /* Device is available but not yet reserved, reserve it for us */
1132       Dmsg2(100, "OK Res Unused autochanger %s JobId=%u.\n",
1133          dev->print_name(), jcr->JobId);
1134       bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
1135       bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
1136       return 1;                       /* reserve drive */
1137    }
1138
1139    /*
1140     * Handle the case that there are no writers
1141     */
1142    if (dev->num_writers == 0) {
1143       /* Now check if there are any reservations on the drive */
1144       if (dev->reserved_device) {           
1145          /* Now check if we want the same Pool and pool type */
1146          if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
1147              strcmp(dev->pool_type, dcr->pool_type) == 0) {
1148             /* OK, compatible device */
1149             Dmsg2(100, "OK dev: %s num_writers=0, reserved, pool matches JobId=%u\n",
1150                dev->print_name(), jcr->JobId);
1151             return 1;
1152          } else {
1153             /* Drive Pool not suitable for us */
1154             Mmsg(jcr->errmsg, _(
1155 "3608 JobId=%u wants Pool=\"%s\" but have Pool=\"%s\" nreserve=%d on drive %s.\n"), 
1156                   jcr->JobId, dcr->pool_name, dev->pool_name,
1157                   dev->reserved_device, dev->print_name());
1158             queue_reserve_message(jcr);
1159             Dmsg3(110, "JobId=%u failed: busy num_writers=0, reserved, pool=%s wanted=%s\n",
1160                (int)jcr->JobId, dev->pool_name, dcr->pool_name);
1161             return 0;                 /* wait */
1162          }
1163       } else if (dev->can_append()) {
1164          /* Device in append mode, check if changing pool */
1165          if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
1166              strcmp(dev->pool_type, dcr->pool_type) == 0) {
1167             Dmsg2(100, "OK dev: %s num_writers=0, can_append, pool matches. JobId=%u\n",
1168                dev->print_name(), jcr->JobId);
1169             /* OK, compatible device */
1170             return 1;
1171          } else {
1172             /* Changing pool, unload old tape if any in drive */
1173             Dmsg1(100, "JobId=%u OK dev: num_writers=0, not reserved, pool change, unload changer\n",
1174                 (int)jcr->JobId);
1175             unload_autochanger(dcr, 0);
1176          }
1177       }
1178       /* Device is available but not yet reserved, reserve it for us */
1179       Dmsg2(100, "OK Dev avail reserved %s JobId=%u\n", dev->print_name(),
1180          jcr->JobId);
1181       bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
1182       bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
1183       return 1;                       /* reserve drive */
1184    }
1185
1186    /*
1187     * Check if the device is in append mode with writers (i.e.
1188     *  available if pool is the same).
1189     */
1190    if (dev->can_append() || dev->num_writers > 0) {
1191       /* Yes, now check if we want the same Pool and pool type */
1192       if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
1193           strcmp(dev->pool_type, dcr->pool_type) == 0) {
1194          Dmsg2(100, "OK dev: %s num_writers>=0, can_append, pool matches. JobId=%u\n",
1195             dev->print_name(), jcr->JobId);
1196          /* OK, compatible device */
1197          return 1;
1198       } else {
1199          /* Drive Pool not suitable for us */
1200          Mmsg(jcr->errmsg, _("3609 JobId=%u wants Pool=\"%s\" but has Pool=\"%s\" on drive %s.\n"), 
1201                jcr->JobId, dcr->pool_name, dev->pool_name, dev->print_name());
1202          queue_reserve_message(jcr);
1203          Dmsg3(110, "JobId=%u failed: busy num_writers>0, can_append, pool=%s wanted=%s\n",
1204             (int)jcr->JobId, dev->pool_name, dcr->pool_name);
1205          return 0;                    /* wait */
1206       }
1207    } else {
1208       Pmsg1(000, _("Logic error!!!! JobId=%u Should not get here.\n"), (int)jcr->JobId);
1209       Mmsg(jcr->errmsg, _("3910 JobId=%u Logic error!!!! drive %s Should not get here.\n"),
1210             jcr->JobId, dev->print_name());
1211       queue_reserve_message(jcr);
1212       Jmsg0(jcr, M_FATAL, 0, _("Logic error!!!! Should not get here.\n"));
1213       return -1;                      /* error, should not get here */
1214    }
1215    Mmsg(jcr->errmsg, _("3911 JobId=%u failed reserve drive %s.\n"), 
1216          jcr->JobId, dev->print_name());
1217    queue_reserve_message(jcr);
1218    Dmsg2(110, "failed: No reserve %s JobId=%u\n", dev->print_name(), jcr->JobId);
1219    return 0;
1220 }
1221
1222 /*
1223  * search_lock is already set on entering this routine 
1224  */
1225 static void queue_reserve_message(JCR *jcr)
1226 {
1227    int i;   
1228    alist *msgs = jcr->reserve_msgs;
1229    char *msg;
1230
1231    if (!msgs) {
1232       return;
1233    }
1234    /*
1235     * Look for duplicate message.  If found, do
1236     * not insert
1237     */
1238    for (i=msgs->size()-1; i >= 0; i--) {
1239       msg = (char *)msgs->get(i);
1240       if (!msg) {
1241          return;
1242       }
1243       /* Comparison based on 4 digit message number */
1244       if (strncmp(msg, jcr->errmsg, 4) == 0) {
1245          return;
1246       }
1247    }      
1248    /* Message unique, so insert it */
1249    jcr->reserve_msgs->push(bstrdup(jcr->errmsg));
1250 }
1251
1252 /*
1253  * Send any reservation messages queued for this jcr
1254  */
1255 void send_drive_reserve_messages(JCR *jcr, void sendit(const char *msg, int len, void *sarg), void *arg)
1256 {
1257    int i;
1258    alist *msgs;
1259    char *msg;
1260
1261    lock_reservations();
1262    msgs = jcr->reserve_msgs;
1263    if (!msgs || msgs->size() == 0) {
1264       unlock_reservations();
1265       return;
1266    }
1267    for (i=msgs->size()-1; i >= 0; i--) {
1268       msg = (char *)msgs->get(i);
1269       if (msg) {
1270          sendit("   ", 3, arg);
1271          sendit(msg, strlen(msg), arg);
1272       } else {
1273          break;
1274       }
1275    }
1276    unlock_reservations();
1277 }