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