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