1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8 
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *   Volume management functions for Storage Daemon
21  *
22  *   Kern Sibbald, MM
23  *
24  *   Split from reserve.c October 2008
25  *
26  */
27 
28 #include "bacula.h"
29 #include "stored.h"
30 
31 const int dbglvl =  150;
32 
33 static dlist *vol_list = NULL;
34 static brwlock_t vol_list_lock;
35 static dlist *read_vol_list = NULL;
36 static bthread_mutex_t read_vol_lock = BTHREAD_MUTEX_PRIORITY(PRIO_SD_READ_VOL_LIST);
37 
38 /* Forward referenced functions */
39 static void free_vol_item(VOLRES *vol);
40 static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName);
41 static void debug_list_volumes(const char *imsg);
42 
43 /*
44  * For append volumes the key is the VolumeName.
45  */
name_compare(void * item1,void * item2)46 static int name_compare(void *item1, void *item2)
47 {
48    return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
49 }
50 
51 /*
52  * For read volumes the key is JobId, VolumeName.
53  */
read_compare(void * item1,void * item2)54 static int read_compare(void *item1, void *item2)
55 {
56    VOLRES *vol1 = (VOLRES *)item1;
57    VOLRES *vol2 = (VOLRES *)item2;
58 
59    if (vol1->get_jobid() == vol2->get_jobid()) {
60       return strcmp(vol1->vol_name, vol2->vol_name);
61    }
62    if (vol1->get_jobid() < vol2->get_jobid()) {
63       return -1;
64    }
65    return 1;
66 }
67 
is_vol_list_empty()68 bool is_vol_list_empty()
69 {
70    return vol_list->empty();
71 }
72 
73 int vol_list_lock_count = 0;
74 
75 /*
76  *  Initialized the main volume list. Note, we are using a recursive lock.
77  */
init_vol_list_lock()78 void init_vol_list_lock()
79 {
80    int errstat;
81    if ((errstat=rwl_init(&vol_list_lock, PRIO_SD_VOL_LIST)) != 0) {
82       berrno be;
83       Emsg1(M_ABORT, 0, _("Unable to initialize volume list lock. ERR=%s\n"),
84             be.bstrerror(errstat));
85    }
86 }
87 
term_vol_list_lock()88 void term_vol_list_lock()
89 {
90    rwl_destroy(&vol_list_lock);
91 }
92 
93 /*
94  * This allows a given thread to recursively call to lock_volumes()
95  */
_lock_volumes(const char * file,int line)96 void _lock_volumes(const char *file, int line)
97 {
98    int errstat;
99    vol_list_lock_count++;
100    if ((errstat=rwl_writelock_p(&vol_list_lock, file, line)) != 0) {
101       berrno be;
102       Emsg2(M_ABORT, 0, "rwl_writelock failure. stat=%d: ERR=%s\n",
103            errstat, be.bstrerror(errstat));
104    }
105 }
106 
_unlock_volumes()107 void _unlock_volumes()
108 {
109    int errstat;
110    vol_list_lock_count--;
111    if ((errstat=rwl_writeunlock(&vol_list_lock)) != 0) {
112       berrno be;
113       Emsg2(M_ABORT, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n",
114            errstat, be.bstrerror(errstat));
115    }
116 }
117 
118 #define lock_read_volumes() lock_read_volumes_p(__FILE__, __LINE__)
119 static void lock_read_volumes_p(const char *file="**Unknown", int line=0)
120 {
121    bthread_mutex_lock_p(&read_vol_lock, file, line);
122 }
123 
unlock_read_volumes()124 static void unlock_read_volumes()
125 {
126    bthread_mutex_unlock(&read_vol_lock);
127 }
128 
129 /*
130  * Add a volume to the read list.
131  * Note, we use VOLRES because it simplifies the code
132  *   even though, the only part of VOLRES that we need is
133  *   the volume name.  The same volume may be in the list
134  *   multiple times, but each one is distinguished by the
135  *   JobId.  We use JobId, VolumeName as the key.
136  * We can get called multiple times for the same volume because
137  *   when parsing the bsr, the volume name appears multiple times.
138  */
add_read_volume(JCR * jcr,const char * VolumeName)139 void add_read_volume(JCR *jcr, const char *VolumeName)
140 {
141    VOLRES *nvol, *vol;
142 
143    nvol = new_vol_item(NULL, VolumeName);
144    nvol->set_jobid(jcr->JobId);
145    nvol->set_reading();
146    lock_read_volumes();
147    vol = (VOLRES *)read_vol_list->binary_insert(nvol, read_compare);
148    if (vol != nvol) {
149       free_vol_item(nvol);
150       Dmsg2(dbglvl, "read_vol=%s JobId=%d already in list.\n", VolumeName, jcr->JobId);
151    } else {
152       Dmsg2(dbglvl, "add read_vol=%s JobId=%d\n", VolumeName, jcr->JobId);
153    }
154    unlock_read_volumes();
155 }
156 
157 /*
158  * Check if volume name is in the read list.
159  */
is_read_volume(JCR * jcr,const char * VolumeName)160 bool is_read_volume(JCR *jcr, const char *VolumeName)
161 {
162    VOLRES vol, *fvol;
163    lock_read_volumes();
164    vol.vol_name = bstrdup(VolumeName);
165    fvol = (VOLRES *)read_vol_list->binary_search(&vol, name_compare);
166    free(vol.vol_name);
167    unlock_read_volumes();
168    return fvol != NULL;
169 }
170 
171 /*
172  * Remove a given volume name from the read list.
173  */
remove_read_volume(JCR * jcr,const char * VolumeName)174 void remove_read_volume(JCR *jcr, const char *VolumeName)
175 {
176    VOLRES vol, *fvol;
177    lock_read_volumes();
178    vol.vol_name = bstrdup(VolumeName);
179    vol.set_jobid(jcr->JobId);
180    fvol = (VOLRES *)read_vol_list->binary_search(&vol, read_compare);
181    free(vol.vol_name);
182    if (fvol) {
183       Dmsg3(dbglvl, "remove_read_vol=%s JobId=%d found=%d\n", VolumeName, jcr->JobId, fvol!=NULL);
184    }
185    if (fvol) {
186       read_vol_list->remove(fvol);
187       free_vol_item(fvol);
188    }
189    unlock_read_volumes();
190 // pthread_cond_broadcast(&wait_next_vol);
191 }
192 
193 /*
194  * List Volumes -- this should be moved to status.c
195  */
196 enum {
197    debug_lock = true,
198    debug_nolock = false
199 };
200 
debug_list_volumes(const char * imsg)201 static void debug_list_volumes(const char *imsg)
202 {
203    VOLRES *vol;
204    POOL_MEM msg(PM_MESSAGE);
205 
206    if (debug_level < dbglvl) {
207       return;
208    }
209 
210    foreach_vol(vol) {
211       if (vol->dev) {
212          Mmsg(msg, "List %s: %s in_use=%d swap=%d slot=%d on %s device %s\n", imsg,
213               vol->vol_name, vol->is_in_use(), vol->is_swapping(),
214               vol->get_slot(),
215               vol->dev->print_type(), vol->dev->print_name());
216       } else {
217          Mmsg(msg, "List %s: %s in_use=%d swap=%d slot=%d no dev\n", imsg, vol->vol_name,
218               vol->is_in_use(), vol->is_swapping(), vol->get_slot());
219       }
220       Dmsg1(dbglvl, "%s", msg.c_str());
221    }
222    endeach_vol(vol);
223 }
224 
225 
226 /*
227  * List Volumes -- this should be moved to status.c
228  */
list_volumes(void sendit (const char * msg,int len,void * sarg),void * arg)229 void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
230 {
231    VOLRES *vol;
232    POOL_MEM msg(PM_MESSAGE);
233    int len;
234 
235    foreach_vol(vol) {
236       DEVICE *dev = vol->dev;
237       if (dev) {
238          len = Mmsg(msg, "Reserved volume: %s on %s device %s\n", vol->vol_name,
239                   dev->print_type(), dev->print_name());
240          sendit(msg.c_str(), len, arg);
241          len = Mmsg(msg, "    Reader=%d writers=%d reserves=%d volinuse=%d worm=%d\n",
242             dev->can_read()?1:0, dev->num_writers, dev->num_reserved(),
243             vol->is_in_use(), dev->is_worm());
244          sendit(msg.c_str(), len, arg);
245       } else {
246          len = Mmsg(msg, "Volume %s no device. volinuse=%d\n", vol->vol_name,
247             vol->is_in_use());
248          sendit(msg.c_str(), len, arg);
249       }
250    }
251    endeach_vol(vol);
252 
253    lock_read_volumes();
254    foreach_dlist(vol, read_vol_list) {
255       DEVICE *dev = vol->dev;
256       if (dev) {
257          len = Mmsg(msg, "Read volume: %s on %s device %s\n", vol->vol_name,
258                   dev->print_type(), dev->print_name());
259          sendit(msg.c_str(), len, arg);
260          len = Mmsg(msg, "    Reader=%d writers=%d reserves=%d volinuse=%d JobId=%d\n",
261             dev->can_read()?1:0, dev->num_writers, dev->num_reserved(),
262             vol->is_in_use(), vol->get_jobid());
263          sendit(msg.c_str(), len, arg);
264       } else {
265          len = Mmsg(msg, "Volume: %s no device. volinuse=%d\n", vol->vol_name,
266             vol->is_in_use());
267          sendit(msg.c_str(), len, arg);
268       }
269    }
270    unlock_read_volumes();
271 }
272 
273 /*
274  * Create a Volume item to put in the Volume list
275  *   Ensure that the device points to it.
276  */
new_vol_item(DCR * dcr,const char * VolumeName)277 static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName)
278 {
279    VOLRES *vol;
280    vol = (VOLRES *)malloc(sizeof(VOLRES));
281    memset(vol, 0, sizeof(VOLRES));
282    vol->vol_name = bstrdup(VolumeName);
283    if (dcr) {
284       vol->dev = dcr->dev;
285       Dmsg4(dbglvl, "new Vol=%s slot=%d at %p dev=%s\n",
286             VolumeName, vol->get_slot(), vol->vol_name, vol->dev->print_name());
287    }
288    vol->init_mutex();
289    vol->inc_use_count();
290    return vol;
291 }
292 
free_vol_item(VOLRES * vol)293 static void free_vol_item(VOLRES *vol)
294 {
295    DEVICE *dev = NULL;
296 
297    vol->dec_use_count();
298    vol->vLock();
299    if (vol->use_count() > 0) {
300       vol->vUnlock();
301       return;
302    }
303    vol->vUnlock();
304    free(vol->vol_name);
305    if (vol->dev) {
306       dev = vol->dev;
307    }
308    vol->destroy_mutex();
309    free(vol);
310    if (dev) {
311       dev->vol = NULL;
312    }
313 }
314 
315 /*
316  * Put a new Volume entry in the Volume list. This
317  *  effectively reserves the volume so that it will
318  *  not be mounted again.
319  *
320  * If the device has any current volume associated with it,
321  *  and it is a different Volume, and the device is not busy,
322  *  we release the old Volume item and insert the new one.
323  *
324  * It is assumed that the device is free and locked so that
325  *  we can change the device structure.
326  *
327  * Some details of the Volume list handling:
328  *
329  *  1. The Volume list entry is attached to the drive (rather than
330  *       attached to a job as it was previously. I.e. the drive that "owns"
331  *       the volume (in use, mounted)
332  *       must point to the volume (still to be maintained in a list).
333  *
334  *  2. The Volume is entered in the list when a drive is reserved.
335  *
336  *  3. When a drive is in use, the device code must appropriately update the
337  *       volume name as it changes.
338   *      This code keeps the same list entry as long as the drive
339  *       has any volume associated with it but the volume name in the list
340  *       must be updated when the drive has a different volume mounted.
341  *
342  *  4. A job that has reserved a volume, can un-reserve the volume, and if the
343  *      volume is not mounted, and not reserved, and not in use, it will be
344  *      removed from the list.
345  *
346  *  5. If a job wants to reserve a drive with a different Volume from the one on
347  *      the drive, it can re-use the drive for the new Volume.
348 
349  *  6. If a job wants a Volume that is in a different drive, it can either use the
350  *      other drive or take the volume, only if the other drive is not in use or
351  *      not reserved.
352  *
353  *  One nice aspect of this is that the reserve use count and the writer use count
354  *  already exist and are correctly programmed and will need no changes -- use
355  *  counts are always very tricky.
356  *
357  *  The old code had a concept of "reserving" a Volume, but was changed
358  *  to reserving and using a drive.  A volume is must be attached to (owned by) a
359  *  drive and can move from drive to drive or be unused given certain specific
360  *  conditions of the drive.  The key is that the drive must "own" the Volume.
361  *
362  *  Return: VOLRES entry on success
363  *          NULL volume busy on another drive
364  *               jcr->errmsg has details
365  */
reserve_volume(DCR * dcr,const char * VolumeName)366 VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
367 {
368    VOLRES *vol, *nvol;
369    DEVICE * volatile dev = dcr->dev;
370    JCR *jcr = dcr->jcr;
371 
372    jcr->errmsg[0] = 0;
373    if (job_canceled(dcr->jcr)) {
374       Mmsg1(jcr->errmsg, _("Could not reserve volume \"%s\", because job canceled.\n"),
375          dev->VolHdr.VolumeName);
376       return NULL;
377    }
378    ASSERT2(dev != NULL, "No device in reserve_volume!");
379 
380    Dmsg2(dbglvl, "enter reserve_volume=%s drive=%s\n", VolumeName,
381       dcr->dev->print_name());
382 
383    /* If acquiring to write, don't accept a Volume in read list */
384    if (dcr->is_writing() && is_read_volume(dcr->jcr, VolumeName)) {
385       Mmsg1(jcr->errmsg, _("Could not reserve volume \"%s\" for append, because it will be read.\n"),
386          dev->VolHdr.VolumeName);
387       return NULL;
388    }
389 
390    /*
391     * We lock the reservations system here to ensure
392     *  when adding a new volume that no newly scheduled
393     *  job can reserve it.
394     */
395    lock_volumes();
396    debug_list_volumes("begin reserve_volume");
397    /*
398     * First, remove any old volume attached to this device as it
399     *  is no longer used.
400     */
401    if (dev->vol) {
402       vol = dev->vol;
403       Dmsg4(dbglvl, "Vol attached=%s, newvol=%s volinuse=%d on %s\n",
404          vol->vol_name, VolumeName, vol->is_in_use(), dev->print_name());
405       /*
406        * Make sure we don't remove the current volume we are inserting
407        *  because it was probably inserted by another job, or it
408        *  is not being used and is marked as not reserved.
409        */
410       if (strcmp(vol->vol_name, VolumeName) == 0) {
411          Dmsg3(dbglvl, "set reserved vol=%s slot=%d dev=%s\n", VolumeName,
412                vol->get_slot(), vol->dev->print_name());
413          goto get_out;                  /* Volume already on this device */
414       } else {
415          /* Don't release a volume if it was reserved by someone other than us */
416          if (vol->is_in_use() && !dcr->reserved_volume) {
417             Dmsg5(dbglvl, "Set wait(). Cannot free vol=%s for %s (JobId=%ld). volinuse=%d on %s\n",
418                vol->vol_name, VolumeName, vol->get_jobid(), vol->is_in_use(), dev->print_name());
419             Mmsg3(dcr->jcr->errmsg, _("Cannot reserve Volume=%s because drive is busy with Volume=%s (JobId=%ld).\n"),
420                VolumeName, vol->vol_name, vol->get_jobid());
421             dev->set_wait();
422             vol = NULL;                  /* vol in use */
423             goto get_out;
424          }
425          Dmsg2(dbglvl, "reserve_vol free vol=%s at %p\n", vol->vol_name, vol->vol_name);
426          /* If old Volume is still mounted, must unload it */
427          if (strcmp(vol->vol_name, dev->VolHdr.VolumeName) == 0) {
428             Dmsg2(50, "set_unload vol=%s slot=%d\n", vol->vol_name, vol->get_slot());
429             dev->set_unload();          /* have to unload current volume */
430          }
431          free_volume(dev);              /* Release old volume entry */
432          debug_list_volumes("reserve_vol free");
433       }
434    }
435 
436    /* Create a new Volume entry */
437    nvol = new_vol_item(dcr, VolumeName);
438 
439    /*
440     * Handle request for read volume for file
441     *  device, for which we assume we can open multiple
442     *  devices to read the Volume.
443     *
444     * Note: when doing multiple simultaneous reads
445     *  of the same volume, the volume names are not
446     *  inserted into the write volume list.
447     */
448    if (dcr->is_reading() && dev->is_file()) {
449       nvol->set_jobid(dcr->jcr->JobId);
450       nvol->set_reading();
451       vol = nvol;
452       dev->vol = vol;
453       goto get_out;
454    } else {
455       vol = (VOLRES *)vol_list->binary_insert(nvol, name_compare);
456    }
457 
458    /*
459     * This part handles any write volumes or read volumes that
460     *  cannot be simultaneously on multiple devices.
461     */
462    if (vol != nvol) {
463       /*
464        * At this point, a Volume with this name already is in the list,
465        *   so we simply release our new Volume entry. Note, this should
466        *   only happen if we are moving the volume from one drive to another.
467        */
468       Dmsg2(dbglvl, "Found vol=%s dev-same=%d\n", vol->vol_name, dev==vol->dev);
469       Dmsg2(dbglvl, "reserve_vol free-tmp vol=%s at %p\n",
470             vol->vol_name, vol->vol_name);
471       /*
472        * Clear dev pointer so that free_vol_item() doesn't
473        *  take away our volume.
474        */
475       nvol->dev = NULL;                  /* don't zap dev entry */
476       free_vol_item(nvol);
477 
478       if (vol->dev) {
479          Dmsg2(dbglvl, "dev=%s vol->dev=%s\n", dev->print_name(), vol->dev->print_name());
480       }
481 
482       /*
483        * Check if we are trying to use the Volume on a different drive
484        *  dev      is our device
485        *  vol->dev is where the Volume we want is
486        */
487       if (dev != vol->dev) {
488          /* Caller wants to switch Volume to another device */
489          if (!vol->dev->is_busy() && !vol->is_swapping()) {
490             int32_t slot;
491             Dmsg3(dbglvl, "==== Swap vol=%s from dev=%s to %s\n",
492                VolumeName, vol->dev->print_name(), dev->print_name());
493             free_volume(dev);            /* free any volume attached to our drive */
494             Dmsg3(50, "set_unload vol=%s slot=%d dev=%s\n", vol->vol_name,
495                vol->get_slot(), dev->print_name());
496             dev->set_unload();           /* Unload any volume that is on our drive */
497             dcr->set_dev(vol->dev);      /* temp point to other dev */
498             slot = get_autochanger_loaded_slot(dcr);  /* get slot on other drive */
499             dcr->set_dev(dev);           /* restore dev */
500             vol->set_slot(slot);         /* save slot */
501             vol->dev->set_unload();      /* unload the other drive */
502             vol->set_swapping();         /* swap from other drive */
503             dev->swap_dev = vol->dev;    /* remember to get this vol */
504             dev->set_load();             /* then reload on our drive */
505             vol->dev->vol = NULL;        /* remove volume from other drive */
506             vol->dev = dev;              /* point the Volume at our drive */
507             dev->vol = vol;              /* point our drive at the Volume */
508          } else {
509             if (dev) {
510                Jmsg8(jcr, M_WARNING, 0, "Need volume for %s from other drive, "
511                   "but swap not possible. Status: reader=%d writers=%d "
512                   "reserves=%d swap=%d vol=%s from dev=%s to %s\n",
513                   dcr->is_writing()?"write":"read",
514                   vol->dev->can_read(), vol->dev->num_writers,
515                   vol->dev->num_reserved(), vol->is_swapping(),
516                   VolumeName, vol->dev->print_name(), dev->print_name());
517             }
518             if (vol->is_swapping()) {
519                DEVICE *swapdev = dev->swap_dev;
520                if (vol && dev && swapdev) {
521                   Mmsg3(jcr->errmsg, _("Volume %s is busy swapping from %s to %s\n"),
522                      NPRT(vol->vol_name), dev->print_name(), swapdev->print_name());
523                } else {
524                   Mmsg1(jcr->errmsg, _("Volume %s is busy swapping.\n"),
525                      NPRT(vol->vol_name));
526                }
527             } else if (vol->dev) {
528                Mmsg2(jcr->errmsg, _("%s device %s is busy.\n"),
529                   vol->dev->print_type(), vol->dev->print_name());
530             } else {
531                Mmsg1(jcr->errmsg, _("Volume %s is busy swapping.\n"),
532                   NPRT(vol->vol_name));
533             }
534             debug_list_volumes("failed swap");
535             vol = NULL;                  /* device busy */
536             goto get_out;
537          }
538       } else {
539          dev->vol = vol;
540       }
541    } else {
542       dev->vol = vol;                    /* point to newly inserted volume */
543    }
544 
545 get_out:
546    if (vol) {
547       Dmsg2(dbglvl, "set in_use. vol=%s dev=%s\n", vol->vol_name,
548             vol->dev->print_name());
549       vol->set_in_use();
550       dcr->reserved_volume = true;
551       bstrncpy(dcr->VolumeName, vol->vol_name, sizeof(dcr->VolumeName));
552    }
553    debug_list_volumes("end new volume");
554    unlock_volumes();
555    return vol;
556 }
557 
558 /*
559  * Start walk of vol chain
560  * The proper way to walk the vol chain is:
561  *    VOLRES *vol;
562  *    foreach_vol(vol) {
563  *      ...
564  *    }
565  *    endeach_vol(vol);
566  *
567  *  It is possible to leave out the endeach_vol(vol), but
568  *   in that case, the last vol referenced must be explicitly
569  *   released with:
570  *
571  *    free_vol_item(vol);
572  *
573  */
vol_walk_start()574 VOLRES *vol_walk_start()
575 {
576    VOLRES *vol;
577    lock_volumes();
578    vol = (VOLRES *)vol_list->first();
579    if (vol) {
580       vol->inc_use_count();
581       Dmsg2(dbglvl, "Inc walk_start use_count=%d volname=%s\n",
582             vol->use_count(), vol->vol_name);
583    }
584    unlock_volumes();
585    return vol;
586 }
587 
588 /*
589  * Get next vol from chain, and release current one
590  */
vol_walk_next(VOLRES * prev_vol)591 VOLRES *vol_walk_next(VOLRES *prev_vol)
592 {
593    VOLRES *vol;
594 
595    lock_volumes();
596    vol = (VOLRES *)vol_list->next(prev_vol);
597    if (vol) {
598       vol->inc_use_count();
599       Dmsg2(dbglvl, "Inc walk_next use_count=%d volname=%s\n",
600             vol->use_count(), vol->vol_name);
601    }
602    if (prev_vol) {
603       free_vol_item(prev_vol);
604    }
605    unlock_volumes();
606    return vol;
607 }
608 
609 /*
610  * Release last vol referenced
611  */
vol_walk_end(VOLRES * vol)612 void vol_walk_end(VOLRES *vol)
613 {
614    if (vol) {
615       lock_volumes();
616       Dmsg2(dbglvl, "Free walk_end use_count=%d volname=%s\n",
617             vol->use_count(), vol->vol_name);
618       free_vol_item(vol);
619       unlock_volumes();
620    }
621 }
622 
623 /*
624  * Search for a Volume name in the Volume list.
625  *
626  *  Returns: VOLRES entry on success
627  *           NULL if the Volume is not in the list
628  */
find_volume(const char * VolumeName)629 static VOLRES *find_volume(const char *VolumeName)
630 {
631    VOLRES vol, *fvol;
632 
633    if (vol_list->empty()) {
634       return NULL;
635    }
636    /* Do not lock reservations here */
637    lock_volumes();
638    vol.vol_name = bstrdup(VolumeName);
639    fvol = (VOLRES *)vol_list->binary_search(&vol, name_compare);
640    free(vol.vol_name);
641    Dmsg2(dbglvl, "find_vol=%s found=%d\n", VolumeName, fvol!=NULL);
642    debug_list_volumes("find_volume");
643    unlock_volumes();
644    return fvol;
645 }
646 
647 /*
648  * Search for a Volume name in the read Volume list.
649  *
650  *  Returns: VOLRES entry on success
651  *           NULL if the Volume is not in the list
652  */
find_read_volume(const char * VolumeName)653 static VOLRES *find_read_volume(const char *VolumeName)
654 {
655    VOLRES vol, *fvol;
656 
657    if (read_vol_list->empty()) {
658       Dmsg0(dbglvl, "find_read_vol: read_vol_list empty.\n");
659       return NULL;
660    }
661    /* Do not lock reservations here */
662    lock_read_volumes();
663    vol.vol_name = bstrdup(VolumeName);
664    /* Note, we do want a simple name_compare on volume name only here */
665    fvol = (VOLRES *)read_vol_list->binary_search(&vol, name_compare);
666    free(vol.vol_name);
667    Dmsg2(dbglvl, "find_read_vol=%s found=%d\n", VolumeName, fvol!=NULL);
668    unlock_read_volumes();
669    return fvol;
670 }
671 
672 
673 /*
674  * Free a Volume from the Volume list if it is no longer used
675  *   Note, for tape drives we want to remember where the Volume
676  *   was when last used, so rather than free the volume entry,
677  *   we simply mark it "not reserved" so when the drive is really
678  *   needed for another volume, we can reuse it.
679  *
680  *  Returns: true if the Volume found and "removed" from the list
681  *           false if the Volume is not in the list or is in use
682  */
volume_unused(DCR * dcr)683 bool volume_unused(DCR *dcr)
684 {
685    DEVICE *dev = dcr->dev;
686 
687    if (!dev->vol) {
688       Dmsg1(dbglvl, "vol_unused: no vol on %s\n", dev->print_name());
689       debug_list_volumes("null vol cannot unreserve_volume");
690       return false;
691    }
692 
693    Dmsg2(dbglvl, "Clear in_use vol=%s slot=%d\n", dev->vol->vol_name,
694          dev->vol->get_slot());
695    dev->vol->clear_in_use();
696 
697    if (dev->vol->is_swapping()) {
698       Dmsg1(dbglvl, "vol_unused: vol being swapped on %s\n", dev->print_name());
699       debug_list_volumes("swapping vol cannot free_volume");
700       return false;
701    }
702 
703    /*
704     * If this is a tape, we do not free the volume, rather we wait
705     *  until the autoloader unloads it, or until another tape is
706     *  explicitly read in this drive. This allows the SD to remember
707     *  where the tapes are or last were.
708     */
709    Dmsg5(dbglvl, "set not reserved vol=%s slot=%d writers=%d reserves=%d dev=%s\n",
710       dev->vol->vol_name, dev->vol->get_slot(), dev->num_writers,
711       dev->num_reserved(), dev->print_name());
712    if (dev->is_tape() || dev->is_autochanger()) {
713       return true;
714    } else {
715       /*
716        * Note, this frees the volume reservation entry, but the
717        *   file descriptor remains open with the OS.
718        */
719       return free_volume(dev);
720    }
721 }
722 
723 /*
724  * Unconditionally release the volume entry
725  * Note: read volumes are not in the list, so
726  *   do not attempt to remove them.
727  */
free_volume(DEVICE * dev)728 bool free_volume(DEVICE *dev)
729 {
730    VOLRES *vol;
731 
732    lock_volumes();
733    vol = dev->vol;
734    if (vol == NULL) {
735       Dmsg1(dbglvl, "No vol on dev %s\n", dev->print_name());
736       unlock_volumes();
737       return false;
738    }
739    /* Don't free a volume while it is being swapped */
740    if (!vol->is_swapping()) {
741       Dmsg2(dbglvl, "Clear in_use vol=%s slot=%d\n", vol->vol_name, vol->get_slot());
742       dev->vol = NULL;
743       if (vol->is_writing()) {
744          vol_list->remove(vol);
745       }
746       Dmsg3(dbglvl, "Remove volume %s slot=%d dev=%s\n", vol->vol_name,
747          vol->get_slot(), dev->print_name());
748       free_vol_item(vol);
749       debug_list_volumes("free_volume");
750    } else {
751       Dmsg1(dbglvl, "=== Cannot clear. Swapping vol=%s\n", vol->vol_name);
752    }
753    unlock_volumes();
754    return true;
755 }
756 
757 
758 /* Create the Volume list */
create_volume_lists()759 void create_volume_lists()
760 {
761    VOLRES *vol = NULL;
762    if (vol_list == NULL) {
763       vol_list = New(dlist(vol, &vol->link));
764    }
765    if (read_vol_list == NULL) {
766       read_vol_list = New(dlist(vol, &vol->link));
767    }
768 }
769 
770 /*
771  * Free normal append volumes list
772  */
free_volume_list()773 static void free_volume_list()
774 {
775    VOLRES *vol;
776    if (vol_list) {
777       lock_volumes();
778       foreach_dlist(vol, vol_list) {
779          if (vol->dev) {
780             Dmsg2(dbglvl, "free vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
781          } else {
782             Dmsg1(dbglvl, "free vol_list Volume=%s No dev\n", vol->vol_name);
783          }
784          free(vol->vol_name);
785          vol->vol_name = NULL;
786          vol->destroy_mutex();
787       }
788       delete vol_list;
789       vol_list = NULL;
790       unlock_volumes();
791    }
792 }
793 
794 /* Release all Volumes from the list */
free_volume_lists()795 void free_volume_lists()
796 {
797    VOLRES *vol;
798 
799    free_volume_list();           /* normal append list */
800 
801    if (read_vol_list) {
802       lock_read_volumes();
803       foreach_dlist(vol, read_vol_list) {
804          if (vol->dev) {
805             Dmsg2(dbglvl, "free read_vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
806          } else {
807             Dmsg1(dbglvl, "free read_vol_list Volume=%s No dev\n", vol->vol_name);
808          }
809          free(vol->vol_name);
810          vol->vol_name = NULL;
811          vol->destroy_mutex();
812       }
813       delete read_vol_list;
814       read_vol_list = NULL;
815       unlock_read_volumes();
816    }
817 }
818 
819 /*
820  * Determine if caller can write on volume.
821  *  If not, return reason in jcr->errmsg
822  */
can_i_write_volume()823 bool DCR::can_i_write_volume()
824 {
825    VOLRES *vol;
826 
827    vol = find_read_volume(VolumeName);
828    if (vol) {
829       Mmsg(jcr->errmsg, "Found in read list; cannot write vol=%s\n", VolumeName);
830       Dmsg1(100, "Found in read list; cannot write vol=%s\n", VolumeName);
831       return false;
832    }
833    return can_i_use_volume();
834 }
835 
836 /*
837  * Determine if caller can read or write volume.
838  *  If not, return reason in jcr->errmsg
839  */
can_i_use_volume()840 bool DCR::can_i_use_volume()
841 {
842    bool rtn = true;
843    VOLRES *vol;
844 
845    if (job_canceled(jcr)) {
846       Mmsg(jcr->errmsg, "Job is canceled\n");
847       return false;
848    }
849    lock_volumes();
850    vol = find_volume(VolumeName);
851    if (!vol) {
852       Dmsg1(dbglvl, "Vol=%s not in use.\n", VolumeName);
853       goto get_out;                   /* vol not in list */
854    }
855    ASSERT2(vol->dev != NULL, "No device in can_i_use_volume!");
856 
857    if (dev == vol->dev) {        /* same device OK */
858       Dmsg1(dbglvl, "Vol=%s on same dev.\n", VolumeName);
859       goto get_out;
860    } else {
861       Dmsg3(dbglvl, "Vol=%s on %s we have %s\n", VolumeName,
862             vol->dev->print_name(), dev->print_name());
863    }
864    /* ***FIXME*** check this ... */
865    if (!vol->dev->is_busy()) {
866       Dmsg2(dbglvl, "Vol=%s dev=%s not busy.\n", VolumeName, vol->dev->print_name());
867       goto get_out;
868    } else {
869       Dmsg2(dbglvl, "Vol=%s dev=%s busy.\n", VolumeName, vol->dev->print_name());
870    }
871    Mmsg(jcr->errmsg, "Volume=%s in use on another device %s.\n", VolumeName, vol->dev->print_name());
872    Dmsg2(dbglvl, "Volume=%s in use on another device %s.\n", VolumeName, vol->dev->print_name());
873    rtn = false;
874 
875 get_out:
876    unlock_volumes();
877    return rtn;
878 
879 }
880 
881 /*
882  * Create a temporary copy of the volume list.  We do this,
883  *   to avoid having the volume list locked during the
884  *   call to reserve_device(), which would cause a deadlock.
885  * Note, we may want to add an update counter on the vol_list
886  *   so that if it is modified while we are traversing the copy
887  *   we can take note and act accordingly (probably redo the
888  *   search at least a few times).
889  */
dup_vol_list(JCR * jcr)890 dlist *dup_vol_list(JCR *jcr)
891 {
892    dlist *temp_vol_list;
893    VOLRES *vol = NULL;
894 
895    Dmsg0(dbglvl, "lock volumes\n");
896 
897    Dmsg0(dbglvl, "duplicate vol list\n");
898    temp_vol_list = New(dlist(vol, &vol->link));
899    foreach_vol(vol) {
900       VOLRES *nvol;
901       VOLRES *tvol = (VOLRES *)malloc(sizeof(VOLRES));
902       memset(tvol, 0, sizeof(VOLRES));
903       tvol->vol_name = bstrdup(vol->vol_name);
904       tvol->dev = vol->dev;
905       tvol->init_mutex();
906       tvol->inc_use_count();
907       nvol = (VOLRES *)temp_vol_list->binary_insert(tvol, name_compare);
908       if (tvol != nvol) {
909          tvol->dev = NULL;                   /* don't zap dev entry */
910          free_vol_item(tvol);
911          Pmsg0(000, "Logic error. Duplicating vol list hit duplicate.\n");
912          Jmsg(jcr, M_WARNING, 0, "Logic error. Duplicating vol list hit duplicate.\n");
913       }
914    }
915    endeach_vol(vol);
916    Dmsg0(dbglvl, "unlock volumes\n");
917    return temp_vol_list;
918 }
919 
920 /*
921  * Free the specified temp list.
922  */
free_temp_vol_list(dlist * temp_vol_list)923 void free_temp_vol_list(dlist *temp_vol_list)
924 {
925    dlist *save_vol_list;
926 
927    lock_volumes();
928    save_vol_list = vol_list;
929    vol_list = temp_vol_list;
930    free_volume_list();                  /* release temp_vol_list */
931    vol_list = save_vol_list;
932    Dmsg0(dbglvl, "deleted temp vol list\n");
933    Dmsg0(dbglvl, "unlock volumes\n");
934    unlock_volumes();
935    debug_list_volumes("after free temp table");
936 }
937