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