2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
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.
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.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Volume management functions for Storage Daemon
24 * Split from reserve.c October 2008
31 const int dbglvl = 150;
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);
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);
44 * For append volumes the key is the VolumeName.
46 static int name_compare(void *item1, void *item2)
48 return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
52 * For read volumes the key is JobId, VolumeName.
54 static int read_compare(void *item1, void *item2)
56 VOLRES *vol1 = (VOLRES *)item1;
57 VOLRES *vol2 = (VOLRES *)item2;
59 if (vol1->get_jobid() == vol2->get_jobid()) {
60 return strcmp(vol1->vol_name, vol2->vol_name);
62 if (vol1->get_jobid() < vol2->get_jobid()) {
68 bool is_vol_list_empty()
70 return vol_list->empty();
73 int vol_list_lock_count = 0;
76 * Initialized the main volume list. Note, we are using a recursive lock.
78 void init_vol_list_lock()
81 if ((errstat=rwl_init(&vol_list_lock, PRIO_SD_VOL_LIST)) != 0) {
83 Emsg1(M_ABORT, 0, _("Unable to initialize volume list lock. ERR=%s\n"),
84 be.bstrerror(errstat));
88 void term_vol_list_lock()
90 rwl_destroy(&vol_list_lock);
94 * This allows a given thread to recursively call to lock_volumes()
96 void _lock_volumes(const char *file, int line)
99 vol_list_lock_count++;
100 if ((errstat=rwl_writelock_p(&vol_list_lock, file, line)) != 0) {
102 Emsg2(M_ABORT, 0, "rwl_writelock failure. stat=%d: ERR=%s\n",
103 errstat, be.bstrerror(errstat));
107 void _unlock_volumes()
110 vol_list_lock_count--;
111 if ((errstat=rwl_writeunlock(&vol_list_lock)) != 0) {
113 Emsg2(M_ABORT, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n",
114 errstat, be.bstrerror(errstat));
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)
121 bthread_mutex_lock_p(&read_vol_lock, file, line);
124 static void unlock_read_volumes()
126 bthread_mutex_unlock(&read_vol_lock);
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.
139 void add_read_volume(JCR *jcr, const char *VolumeName)
143 nvol = new_vol_item(NULL, VolumeName);
144 nvol->set_jobid(jcr->JobId);
147 vol = (VOLRES *)read_vol_list->binary_insert(nvol, read_compare);
150 Dmsg2(dbglvl, "read_vol=%s JobId=%d already in list.\n", VolumeName, jcr->JobId);
152 Dmsg2(dbglvl, "add read_vol=%s JobId=%d\n", VolumeName, jcr->JobId);
154 unlock_read_volumes();
158 * Check if volume name is in the read list.
160 bool is_read_volume(JCR *jcr, const char *VolumeName)
164 vol.vol_name = bstrdup(VolumeName);
165 fvol = (VOLRES *)read_vol_list->binary_search(&vol, name_compare);
167 unlock_read_volumes();
172 * Remove a given volume name from the read list.
174 void remove_read_volume(JCR *jcr, const char *VolumeName)
178 vol.vol_name = bstrdup(VolumeName);
179 vol.set_jobid(jcr->JobId);
180 fvol = (VOLRES *)read_vol_list->binary_search(&vol, read_compare);
183 Dmsg3(dbglvl, "remove_read_vol=%s JobId=%d found=%d\n", VolumeName, jcr->JobId, fvol!=NULL);
186 read_vol_list->remove(fvol);
189 unlock_read_volumes();
190 // pthread_cond_broadcast(&wait_next_vol);
194 * List Volumes -- this should be moved to status.c
201 static void debug_list_volumes(const char *imsg)
204 POOL_MEM msg(PM_MESSAGE);
206 if (debug_level < dbglvl) {
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(),
215 vol->dev->print_type(), vol->dev->print_name());
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());
220 Dmsg1(dbglvl, "%s", msg.c_str());
227 * List Volumes -- this should be moved to status.c
229 void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
232 POOL_MEM msg(PM_MESSAGE);
236 DEVICE *dev = vol->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\n",
242 dev->can_read()?1:0, dev->num_writers, dev->num_reserved(),
244 sendit(msg.c_str(), len, arg);
246 len = Mmsg(msg, "Volume %s no device. volinuse=%d\n", vol->vol_name,
248 sendit(msg.c_str(), len, arg);
254 foreach_dlist(vol, read_vol_list) {
255 DEVICE *dev = vol->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);
265 len = Mmsg(msg, "Volume: %s no device. volinuse=%d\n", vol->vol_name,
267 sendit(msg.c_str(), len, arg);
270 unlock_read_volumes();
274 * Create a Volume item to put in the Volume list
275 * Ensure that the device points to it.
277 static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName)
280 vol = (VOLRES *)malloc(sizeof(VOLRES));
281 memset(vol, 0, sizeof(VOLRES));
282 vol->vol_name = bstrdup(VolumeName);
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());
289 vol->inc_use_count();
293 static void free_vol_item(VOLRES *vol)
297 vol->dec_use_count();
299 if (vol->use_count() > 0) {
308 vol->destroy_mutex();
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.
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.
324 * It is assumed that the device is free and locked so that
325 * we can change the device structure.
327 * Some details of the Volume list handling:
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).
334 * 2. The Volume is entered in the list when a drive is reserved.
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.
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.
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.
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
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.
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.
362 * Return: VOLRES entry on success
363 * NULL volume busy on another drive
364 * jcr->errmsg has details
366 VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
369 DEVICE * volatile dev = dcr->dev;
373 if (job_canceled(dcr->jcr)) {
374 Mmsg1(jcr->errmsg, _("Could not reserve volume \"%s\", because job canceled.\n"),
375 dev->VolHdr.VolumeName);
378 ASSERT2(dev != NULL, "No device in reserve_volume!");
380 Dmsg2(dbglvl, "enter reserve_volume=%s drive=%s\n", VolumeName,
381 dcr->dev->print_name());
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);
391 * We lock the reservations system here to ensure
392 * when adding a new volume that no newly scheduled
393 * job can reserve it.
396 debug_list_volumes("begin reserve_volume");
398 * First, remove any old volume attached to this device as it
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());
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.
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 */
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());
422 vol = NULL; /* vol in use */
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 */
431 free_volume(dev); /* Release old volume entry */
432 debug_list_volumes("reserve_vol free");
436 /* Create a new Volume entry */
437 nvol = new_vol_item(dcr, VolumeName);
440 * Handle request for read volume for file
441 * device, for which we assume we can open multiple
442 * devices to read the Volume.
444 * Note: when doing multiple simultaneous reads
445 * of the same volume, the volume names are not
446 * inserted into the write volume list.
448 if (dcr->is_reading() && dev->is_file()) {
449 nvol->set_jobid(dcr->jcr->JobId);
455 vol = (VOLRES *)vol_list->binary_insert(nvol, name_compare);
459 * This part handles any write volumes or read volumes that
460 * cannot be simultaneously on multiple devices.
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.
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);
472 * Clear dev pointer so that free_vol_item() doesn't
473 * take away our volume.
475 nvol->dev = NULL; /* don't zap dev entry */
479 Dmsg2(dbglvl, "dev=%s vol->dev=%s\n", dev->print_name(), vol->dev->print_name());
483 * Check if we are trying to use the Volume on a different drive
485 * vol->dev is where the Volume we want is
487 if (dev != vol->dev) {
488 /* Caller wants to switch Volume to another device */
489 if (!vol->dev->is_busy() && !vol->is_swapping()) {
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 */
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());
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());
524 Mmsg1(jcr->errmsg, _("Volume %s is busy swapping.\n"),
525 NPRT(vol->vol_name));
527 } else if (vol->dev) {
528 Mmsg2(jcr->errmsg, _("%s device %s is busy.\n"),
529 vol->dev->print_type(), vol->dev->print_name());
531 Mmsg1(jcr->errmsg, _("Volume %s is busy swapping.\n"),
532 NPRT(vol->vol_name));
534 debug_list_volumes("failed swap");
535 vol = NULL; /* device busy */
542 dev->vol = vol; /* point to newly inserted volume */
547 Dmsg2(dbglvl, "set in_use. vol=%s dev=%s\n", vol->vol_name,
548 vol->dev->print_name());
550 dcr->reserved_volume = true;
551 bstrncpy(dcr->VolumeName, vol->vol_name, sizeof(dcr->VolumeName));
553 debug_list_volumes("end new volume");
559 * Start walk of vol chain
560 * The proper way to walk the vol chain is:
567 * It is possible to leave out the endeach_vol(vol), but
568 * in that case, the last vol referenced must be explicitly
571 * free_vol_item(vol);
574 VOLRES *vol_walk_start()
578 vol = (VOLRES *)vol_list->first();
580 vol->inc_use_count();
581 Dmsg2(dbglvl, "Inc walk_start use_count=%d volname=%s\n",
582 vol->use_count(), vol->vol_name);
589 * Get next vol from chain, and release current one
591 VOLRES *vol_walk_next(VOLRES *prev_vol)
596 vol = (VOLRES *)vol_list->next(prev_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);
603 free_vol_item(prev_vol);
610 * Release last vol referenced
612 void vol_walk_end(VOLRES *vol)
616 Dmsg2(dbglvl, "Free walk_end use_count=%d volname=%s\n",
617 vol->use_count(), vol->vol_name);
624 * Search for a Volume name in the Volume list.
626 * Returns: VOLRES entry on success
627 * NULL if the Volume is not in the list
629 static VOLRES *find_volume(const char *VolumeName)
633 if (vol_list->empty()) {
636 /* Do not lock reservations here */
638 vol.vol_name = bstrdup(VolumeName);
639 fvol = (VOLRES *)vol_list->binary_search(&vol, name_compare);
641 Dmsg2(dbglvl, "find_vol=%s found=%d\n", VolumeName, fvol!=NULL);
642 debug_list_volumes("find_volume");
648 * Search for a Volume name in the read Volume list.
650 * Returns: VOLRES entry on success
651 * NULL if the Volume is not in the list
653 static VOLRES *find_read_volume(const char *VolumeName)
657 if (read_vol_list->empty()) {
658 Dmsg0(dbglvl, "find_read_vol: read_vol_list empty.\n");
661 /* Do not lock reservations here */
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);
667 Dmsg2(dbglvl, "find_read_vol=%s found=%d\n", VolumeName, fvol!=NULL);
668 unlock_read_volumes();
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.
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
683 bool volume_unused(DCR *dcr)
685 DEVICE *dev = dcr->dev;
688 Dmsg1(dbglvl, "vol_unused: no vol on %s\n", dev->print_name());
689 debug_list_volumes("null vol cannot unreserve_volume");
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();
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");
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.
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()) {
716 * Note, this frees the volume reservation entry, but the
717 * file descriptor remains open with the OS.
719 return free_volume(dev);
724 * Unconditionally release the volume entry
725 * Note: read volumes are not in the list, so
726 * do not attempt to remove them.
728 bool free_volume(DEVICE *dev)
735 Dmsg1(dbglvl, "No vol on dev %s\n", dev->print_name());
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());
743 if (vol->is_writing()) {
744 vol_list->remove(vol);
746 Dmsg3(dbglvl, "Remove volume %s slot=%d dev=%s\n", vol->vol_name,
747 vol->get_slot(), dev->print_name());
749 debug_list_volumes("free_volume");
751 Dmsg1(dbglvl, "=== Cannot clear. Swapping vol=%s\n", vol->vol_name);
758 /* Create the Volume list */
759 void create_volume_lists()
762 if (vol_list == NULL) {
763 vol_list = New(dlist(vol, &vol->link));
765 if (read_vol_list == NULL) {
766 read_vol_list = New(dlist(vol, &vol->link));
771 * Free normal append volumes list
773 static void free_volume_list()
778 foreach_dlist(vol, vol_list) {
780 Dmsg2(dbglvl, "free vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
782 Dmsg1(dbglvl, "free vol_list Volume=%s No dev\n", vol->vol_name);
785 vol->vol_name = NULL;
786 vol->destroy_mutex();
794 /* Release all Volumes from the list */
795 void free_volume_lists()
799 free_volume_list(); /* normal append list */
803 foreach_dlist(vol, read_vol_list) {
805 Dmsg2(dbglvl, "free read_vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
807 Dmsg1(dbglvl, "free read_vol_list Volume=%s No dev\n", vol->vol_name);
810 vol->vol_name = NULL;
811 vol->destroy_mutex();
813 delete read_vol_list;
814 read_vol_list = NULL;
815 unlock_read_volumes();
820 * Determine if caller can write on volume.
821 * If not, return reason in jcr->errmsg
823 bool DCR::can_i_write_volume()
827 vol = find_read_volume(VolumeName);
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);
833 return can_i_use_volume();
837 * Determine if caller can read or write volume.
838 * If not, return reason in jcr->errmsg
840 bool DCR::can_i_use_volume()
845 if (job_canceled(jcr)) {
846 Mmsg(jcr->errmsg, "Job is canceled\n");
850 vol = find_volume(VolumeName);
852 Dmsg1(dbglvl, "Vol=%s not in use.\n", VolumeName);
853 goto get_out; /* vol not in list */
855 ASSERT2(vol->dev != NULL, "No device in can_i_use_volume!");
857 if (dev == vol->dev) { /* same device OK */
858 Dmsg1(dbglvl, "Vol=%s on same dev.\n", VolumeName);
861 Dmsg3(dbglvl, "Vol=%s on %s we have %s\n", VolumeName,
862 vol->dev->print_name(), dev->print_name());
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());
869 Dmsg2(dbglvl, "Vol=%s dev=%s busy.\n", VolumeName, vol->dev->print_name());
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());
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).
890 dlist *dup_vol_list(JCR *jcr)
892 dlist *temp_vol_list;
895 Dmsg0(dbglvl, "lock volumes\n");
897 Dmsg0(dbglvl, "duplicate vol list\n");
898 temp_vol_list = New(dlist(vol, &vol->link));
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;
906 tvol->inc_use_count();
907 nvol = (VOLRES *)temp_vol_list->binary_insert(tvol, name_compare);
909 tvol->dev = NULL; /* don't zap dev entry */
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");
916 Dmsg0(dbglvl, "unlock volumes\n");
917 return temp_vol_list;
921 * Free the specified temp list.
923 void free_temp_vol_list(dlist *temp_vol_list)
925 dlist *save_vol_list;
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");
935 debug_list_volumes("after free temp table");