2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Volume management functions for Storage Daemon
33 * Split from reserve.c October 2008
40 const int dbglvl = 150;
42 static dlist *vol_list = NULL;
43 static brwlock_t vol_list_lock;
44 static dlist *read_vol_list = NULL;
45 static bthread_mutex_t read_vol_lock = BTHREAD_MUTEX_PRIORITY(PRIO_SD_READ_VOL_LIST);
47 /* Forward referenced functions */
48 static void free_vol_item(VOLRES *vol);
49 static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName);
50 static void debug_list_volumes(const char *imsg);
53 * For append volumes the key is the VolumeName.
55 static int my_compare(void *item1, void *item2)
57 return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
61 * For read volumes the key is JobId, VolumeName.
63 static int read_compare(void *item1, void *item2)
65 VOLRES *vol1 = (VOLRES *)item1;
66 VOLRES *vol2 = (VOLRES *)item2;
68 if (vol1->get_jobid() == vol2->get_jobid()) {
69 return strcmp(vol1->vol_name, vol2->vol_name);
71 if (vol1->get_jobid() < vol2->get_jobid()) {
78 bool is_vol_list_empty()
80 return vol_list->empty();
83 int vol_list_lock_count = 0;
86 * Initialized the main volume list. Note, we are using a recursive lock.
88 void init_vol_list_lock()
91 if ((errstat=rwl_init(&vol_list_lock, PRIO_SD_VOL_LIST)) != 0) {
93 Emsg1(M_ABORT, 0, _("Unable to initialize volume list lock. ERR=%s\n"),
94 be.bstrerror(errstat));
98 void term_vol_list_lock()
100 rwl_destroy(&vol_list_lock);
104 * This allows a given thread to recursively call to lock_volumes()
106 void _lock_volumes(const char *file, int line)
109 vol_list_lock_count++;
110 if ((errstat=rwl_writelock_p(&vol_list_lock, file, line)) != 0) {
112 Emsg2(M_ABORT, 0, "rwl_writelock failure. stat=%d: ERR=%s\n",
113 errstat, be.bstrerror(errstat));
117 void _unlock_volumes()
120 vol_list_lock_count--;
121 if ((errstat=rwl_writeunlock(&vol_list_lock)) != 0) {
123 Emsg2(M_ABORT, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n",
124 errstat, be.bstrerror(errstat));
128 void lock_read_volumes(const char *file="**Unknown", int line=0)
130 bthread_mutex_lock_p(&read_vol_lock, file, line);
133 void unlock_read_volumes()
135 bthread_mutex_unlock(&read_vol_lock);
139 * Add a volume to the read list.
140 * Note, we use VOLRES because it simplifies the code
141 * even though, the only part of VOLRES that we need is
142 * the volume name. The same volume may be in the list
143 * multiple times, but each one is distinguished by the
144 * JobId. We use JobId, VolumeName as the key.
145 * We can get called multiple times for the same volume because
146 * when parsing the bsr, the volume name appears multiple times.
148 void add_read_volume(JCR *jcr, const char *VolumeName)
153 nvol = new_vol_item(NULL, VolumeName);
154 nvol->set_jobid(jcr->JobId);
155 vol = (VOLRES *)read_vol_list->binary_insert(nvol, read_compare);
158 Dmsg2(dbglvl, "read_vol=%s JobId=%d already in list.\n", VolumeName, jcr->JobId);
160 Dmsg2(dbglvl, "add read_vol=%s JobId=%d\n", VolumeName, jcr->JobId);
162 unlock_read_volumes();
166 * Remove a given volume name from the read list.
168 void remove_read_volume(JCR *jcr, const char *VolumeName)
172 vol.vol_name = bstrdup(VolumeName);
173 vol.set_jobid(jcr->JobId);
174 fvol = (VOLRES *)read_vol_list->binary_search(&vol, read_compare);
177 Dmsg3(dbglvl, "remove_read_vol=%s JobId=%d found=%d\n", VolumeName, jcr->JobId, fvol!=NULL);
180 read_vol_list->remove(fvol);
183 unlock_read_volumes();
187 * List Volumes -- this should be moved to status.c
194 static void debug_list_volumes(const char *imsg)
197 POOL_MEM msg(PM_MESSAGE);
200 foreach_dlist(vol, vol_list) {
202 Mmsg(msg, "List %s: %s in_use=%d on device %s\n", imsg,
203 vol->vol_name, vol->is_in_use(), vol->dev->print_name());
205 Mmsg(msg, "List %s: %s in_use=%d no dev\n", imsg, vol->vol_name,
208 Dmsg1(dbglvl, "%s", msg.c_str());
216 * List Volumes -- this should be moved to status.c
218 void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
221 POOL_MEM msg(PM_MESSAGE);
225 foreach_dlist(vol, vol_list) {
226 DEVICE *dev = vol->dev;
228 len = Mmsg(msg, "%s on device %s\n", vol->vol_name, dev->print_name());
229 sendit(msg.c_str(), len, arg);
230 len = Mmsg(msg, " Reader=%d writers=%d devres=%d volinuse=%d\n",
231 dev->can_read()?1:0, dev->num_writers, dev->num_reserved(),
233 sendit(msg.c_str(), len, arg);
235 len = Mmsg(msg, "%s no device. volinuse= %d\n", vol->vol_name,
237 sendit(msg.c_str(), len, arg);
243 foreach_dlist(vol, read_vol_list) {
244 len = Mmsg(msg, "%s read volume JobId=%d\n", vol->vol_name,
246 sendit(msg.c_str(), len, arg);
248 unlock_read_volumes();
253 * Create a Volume item to put in the Volume list
254 * Ensure that the device points to it.
256 static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName)
259 vol = (VOLRES *)malloc(sizeof(VOLRES));
260 memset(vol, 0, sizeof(VOLRES));
261 vol->vol_name = bstrdup(VolumeName);
264 Dmsg3(dbglvl, "new Vol=%s at %p dev=%s\n",
265 VolumeName, vol->vol_name, vol->dev->print_name());
270 static void free_vol_item(VOLRES *vol)
285 * Put a new Volume entry in the Volume list. This
286 * effectively reserves the volume so that it will
287 * not be mounted again.
289 * If the device has any current volume associated with it,
290 * and it is a different Volume, and the device is not busy,
291 * we release the old Volume item and insert the new one.
293 * It is assumed that the device is free and locked so that
294 * we can change the device structure.
296 * Some details of the Volume list handling:
298 * 1. The Volume list entry must be attached to the drive (rather than
299 * attached to a job as it currently is. I.e. the drive that "owns"
300 * the volume (in use, mounted)
301 * must point to the volume (still to be maintained in a list).
303 * 2. The Volume is entered in the list when a drive is reserved.
305 * 3. When a drive is in use, the device code must appropriately update the
306 * volume name as it changes (currently the list is static -- an entry is
307 * removed when the Volume is no longer reserved, in use or mounted).
308 * The new code must keep the same list entry as long as the drive
309 * has any volume associated with it but the volume name in the list
310 * must be updated when the drive has a different volume mounted.
312 * 4. A job that has reserved a volume, can un-reserve the volume, and if the
313 * volume is not mounted, and not reserved, and not in use, it will be
314 * removed from the list.
316 * 5. If a job wants to reserve a drive with a different Volume from the one on
317 * the drive, it can re-use the drive for the new Volume.
319 * 6. If a job wants a Volume that is in a different drive, it can either use the
320 * other drive or take the volume, only if the other drive is not in use or
323 * One nice aspect of this is that the reserve use count and the writer use count
324 * already exist and are correctly programmed and will need no changes -- use
325 * counts are always very tricky.
327 * The old code had a concept of "reserving" a Volume, but was changed
328 * to reserving and using a drive. A volume is must be attached to (owned by) a
329 * drive and can move from drive to drive or be unused given certain specific
330 * conditions of the drive. The key is that the drive must "own" the Volume.
331 * The old code had the job (dcr) owning the volume (more or less). The job was
332 * to change the insertion and removal of the volumes from the list to be based
333 * on the drive rather than the job.
335 * Return: VOLRES entry on success
336 * NULL volume busy on another drive
338 VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
341 DEVICE * volatile dev = dcr->dev;
343 if (job_canceled(dcr->jcr)) {
348 Dmsg2(dbglvl, "enter reserve_volume=%s drive=%s\n", VolumeName,
349 dcr->dev->print_name());
351 * We lock the reservations system here to ensure
352 * when adding a new volume that no newly scheduled
353 * job can reserve it.
356 debug_list_volumes("begin reserve_volume");
358 * First, remove any old volume attached to this device as it
363 Dmsg4(dbglvl, "Vol attached=%s, newvol=%s volinuse=%d on %s\n",
364 vol->vol_name, VolumeName, vol->is_in_use(), dev->print_name());
366 * Make sure we don't remove the current volume we are inserting
367 * because it was probably inserted by another job, or it
368 * is not being used and is marked as not reserved.
370 if (strcmp(vol->vol_name, VolumeName) == 0) {
371 Dmsg2(dbglvl, "=== set reserved vol=%s dev=%s\n", VolumeName,
372 vol->dev->print_name());
373 goto get_out; /* Volume already on this device */
375 /* Don't release a volume if it was reserved by someone other than us */
376 if (vol->is_in_use() && !dcr->reserved_volume) {
377 Dmsg1(dbglvl, "Cannot free vol=%s. It is reserved.\n", vol->vol_name);
378 vol = NULL; /* vol in use */
381 Dmsg2(dbglvl, "reserve_vol free vol=%s at %p\n", vol->vol_name, vol->vol_name);
382 /* If old Volume is still mounted, must unload it */
383 if (strcmp(vol->vol_name, dev->VolHdr.VolumeName) == 0) {
384 Dmsg0(50, "set_unload\n");
385 dev->set_unload(); /* have to unload current volume */
387 free_volume(dev); /* Release old volume entry */
388 debug_list_volumes("reserve_vol free");
392 /* Create a new Volume entry */
393 nvol = new_vol_item(dcr, VolumeName);
396 * Now try to insert the new Volume
398 vol = (VOLRES *)vol_list->binary_insert(nvol, my_compare);
400 Dmsg2(dbglvl, "Found vol=%s dev-same=%d\n", vol->vol_name, dev==vol->dev);
402 * At this point, a Volume with this name already is in the list,
403 * so we simply release our new Volume entry. Note, this should
404 * only happen if we are moving the volume from one drive to another.
406 Dmsg2(dbglvl, "reserve_vol free-tmp vol=%s at %p\n",
407 vol->vol_name, vol->vol_name);
409 * Clear dev pointer so that free_vol_item() doesn't
410 * take away our volume.
412 nvol->dev = NULL; /* don't zap dev entry */
416 Dmsg2(dbglvl, "dev=%s vol->dev=%s\n", dev->print_name(), vol->dev->print_name());
420 * Check if we are trying to use the Volume on a different drive
422 * vol->dev is where the Volume we want is
424 if (dev != vol->dev) {
425 /* Caller wants to switch Volume to another device */
426 if (!vol->dev->is_busy() && !vol->is_swapping()) {
428 Dmsg3(dbglvl, "==== Swap vol=%s from dev=%s to %s\n",
429 VolumeName, vol->dev->print_name(), dev->print_name());
430 free_volume(dev); /* free any volume attached to our drive */
431 Dmsg0(50, "set_unload\n");
432 dev->set_unload(); /* Unload any volume that is on our drive */
433 dcr->dev = vol->dev; /* temp point to other dev */
434 slot = get_autochanger_loaded_slot(dcr); /* get slot on other drive */
435 dcr->dev = dev; /* restore dev */
436 vol->set_slot(slot); /* save slot */
437 vol->dev->set_unload(); /* unload the other drive */
438 vol->set_swapping(); /* swap from other drive */
439 dev->swap_dev = vol->dev; /* remember to get this vol */
440 dev->set_load(); /* then reload on our drive */
441 vol->dev->vol = NULL; /* remove volume from other drive */
442 vol->dev = dev; /* point the Volume at our drive */
443 dev->vol = vol; /* point our drive at the Volume */
445 Dmsg5(dbglvl, "==== Swap not possible Vol busy=%d swap=%d vol=%s from dev=%s to %s\n",
446 vol->dev->is_busy(), vol->is_swapping(),
447 VolumeName, vol->dev->print_name(), dev->print_name());
448 if (vol->is_swapping() && dev->swap_dev) {
449 Dmsg2(dbglvl, "Swap vol=%s dev=%s\n", vol->vol_name, dev->swap_dev->print_name());
451 Dmsg1(dbglvl, "swap_dev=%p\n", dev->swap_dev);
453 debug_list_volumes("failed swap");
454 vol = NULL; /* device busy */
461 dev->vol = vol; /* point to newly inserted volume */
466 Dmsg2(dbglvl, "=== set in_use. vol=%s dev=%s\n", vol->vol_name,
467 vol->dev->print_name());
469 dcr->reserved_volume = true;
470 bstrncpy(dcr->VolumeName, vol->vol_name, sizeof(dcr->VolumeName));
472 debug_list_volumes("end new volume");
478 * Switch from current device to given device
482 void switch_device(DCR *dcr, DEVICE *dev)
487 memcpy(&save_dcr, dcr, sizeof(save_dcr));
488 clean_device(dcr); /* clean up the dcr */
490 dcr->dev = dev; /* get new device pointer */
491 Jmsg(dcr->jcr, M_INFO, 0, _("Device switch. New device %s chosen.\n"),
492 dcr->dev->print_name());
494 bstrncpy(dcr->VolumeName, save_dcr.VolumeName, sizeof(dcr->VolumeName));
495 bstrncpy(dcr->media_type, save_dcr.media_type, sizeof(dcr->media_type));
496 dcr->VolCatInfo.Slot = save_dcr.VolCatInfo.Slot;
497 bstrncpy(dcr->pool_name, save_dcr.pool_name, sizeof(dcr->pool_name));
498 bstrncpy(dcr->pool_type, save_dcr.pool_type, sizeof(dcr->pool_type));
499 bstrncpy(dcr->dev_name, dev->dev_name, sizeof(dcr->dev_name));
501 // dcr->set_reserved();
508 * Search for a Volume name in the Volume list.
510 * Returns: VOLRES entry on success
511 * NULL if the Volume is not in the list
513 VOLRES *find_volume(const char *VolumeName)
517 if (vol_list->empty()) {
520 /* Do not lock reservations here */
522 vol.vol_name = bstrdup(VolumeName);
523 fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
525 Dmsg2(dbglvl, "find_vol=%s found=%d\n", VolumeName, fvol!=NULL);
526 debug_list_volumes("find_volume");
532 * Search for a Volume name in the read Volume list.
534 * Returns: VOLRES entry on success
535 * NULL if the Volume is not in the list
537 static VOLRES *find_read_volume(const char *VolumeName)
541 if (read_vol_list->empty()) {
542 Dmsg0(dbglvl, "find_read_vol: read_vol_list empty.\n");
545 /* Do not lock reservations here */
547 vol.vol_name = bstrdup(VolumeName);
548 /* Note, we do want a simple my_compare on volume name only here */
549 fvol = (VOLRES *)read_vol_list->binary_search(&vol, my_compare);
551 Dmsg2(dbglvl, "find_read_vol=%s found=%d\n", VolumeName, fvol!=NULL);
552 unlock_read_volumes();
558 * Free a Volume from the Volume list if it is no longer used
559 * Note, for tape drives we want to remember where the Volume
560 * was when last used, so rather than free the volume entry,
561 * we simply mark it "not reserved" so when the drive is really
562 * needed for another volume, we can reuse it.
564 * Returns: true if the Volume found and "removed" from the list
565 * false if the Volume is not in the list or is in use
567 bool volume_unused(DCR *dcr)
569 DEVICE *dev = dcr->dev;
572 Dmsg1(dbglvl, "vol_unused: no vol on %s\n", dev->print_name());
573 debug_list_volumes("null vol cannot unreserve_volume");
576 if (dev->vol->is_swapping()) {
577 Dmsg1(dbglvl, "vol_unused: vol being swapped on %s\n", dev->print_name());
578 Dmsg1(dbglvl, "=== clear in_use vol=%s\n", dev->vol->vol_name);
579 dev->vol->clear_in_use();
580 debug_list_volumes("swapping vol cannot free_volume");
585 * If this is a tape, we do not free the volume, rather we wait
586 * until the autoloader unloads it, or until another tape is
587 * explicitly read in this drive. This allows the SD to remember
588 * where the tapes are or last were.
590 Dmsg4(dbglvl, "=== set not reserved vol=%s num_writers=%d dev_reserved=%d dev=%s\n",
591 dev->vol->vol_name, dev->num_writers, dev->num_reserved(), dev->print_name());
592 Dmsg1(dbglvl, "=== clear in_use vol=%s\n", dev->vol->vol_name);
593 dev->vol->clear_in_use();
594 if (dev->is_tape() || dev->is_autochanger()) {
598 * Note, this frees the volume reservation entry, but the
599 * file descriptor remains open with the OS.
601 return free_volume(dev);
606 * Unconditionally release the volume entry
608 bool free_volume(DEVICE *dev)
615 Dmsg1(dbglvl, "No vol on dev %s\n", dev->print_name());
619 /* Don't free a volume while it is being swapped */
620 if (!vol->is_swapping()) {
621 Dmsg1(dbglvl, "=== clear in_use vol=%s\n", vol->vol_name);
623 vol_list->remove(vol);
624 Dmsg2(dbglvl, "=== remove volume %s dev=%s\n", vol->vol_name, dev->print_name());
626 debug_list_volumes("free_volume");
628 Dmsg1(dbglvl, "=== cannot clear swapping vol=%s\n", vol->vol_name);
635 /* Create the Volume list */
636 void create_volume_lists()
639 if (vol_list == NULL) {
640 vol_list = New(dlist(vol, &vol->link));
642 if (read_vol_list == NULL) {
643 read_vol_list = New(dlist(vol, &vol->link));
648 * Free normal append volumes list
650 static void free_volume_list()
655 foreach_dlist(vol, vol_list) {
657 Dmsg2(dbglvl, "free vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
659 Dmsg1(dbglvl, "free vol_list Volume=%s No dev\n", vol->vol_name);
662 vol->vol_name = NULL;
670 /* Release all Volumes from the list */
671 void free_volume_lists()
675 free_volume_list(); /* normal append list */
679 foreach_dlist(vol, read_vol_list) {
681 Dmsg2(dbglvl, "free read_vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
683 Dmsg1(dbglvl, "free read_vol_list Volume=%s No dev\n", vol->vol_name);
686 vol->vol_name = NULL;
688 delete read_vol_list;
689 read_vol_list = NULL;
690 unlock_read_volumes();
695 * Determine if caller can write on volume
697 bool DCR::can_i_write_volume()
701 vol = find_read_volume(VolumeName);
703 Dmsg1(100, "Found in read list; cannot write vol=%s\n", VolumeName);
706 return can_i_use_volume();
710 * Determine if caller can read or write volume
712 bool DCR::can_i_use_volume()
717 if (job_canceled(jcr)) {
721 vol = find_volume(VolumeName);
723 Dmsg1(dbglvl, "Vol=%s not in use.\n", VolumeName);
724 goto get_out; /* vol not in list */
726 ASSERT(vol->dev != NULL);
728 if (dev == vol->dev) { /* same device OK */
729 Dmsg1(dbglvl, "Vol=%s on same dev.\n", VolumeName);
732 Dmsg3(dbglvl, "Vol=%s on %s we have %s\n", VolumeName,
733 vol->dev->print_name(), dev->print_name());
735 /* ***FIXME*** check this ... */
736 if (!vol->dev->is_busy()) {
737 Dmsg2(dbglvl, "Vol=%s dev=%s not busy.\n", VolumeName, vol->dev->print_name());
740 Dmsg2(dbglvl, "Vol=%s dev=%s busy.\n", VolumeName, vol->dev->print_name());
742 Dmsg2(dbglvl, "Vol=%s in use by %s.\n", VolumeName, vol->dev->print_name());
752 * Create a temporary copy of the volume list. We do this,
753 * to avoid having the volume list locked during the
754 * call to reserve_device(), which would cause a deadlock.
755 * Note, we may want to add an update counter on the vol_list
756 * so that if it is modified while we are traversing the copy
757 * we can take note and act accordingly (probably redo the
758 * search at least a few times).
760 dlist *dup_vol_list(JCR *jcr)
762 dlist *temp_vol_list;
766 Dmsg0(dbglvl, "lock volumes\n");
768 Dmsg0(dbglvl, "duplicate vol list\n");
769 temp_vol_list = New(dlist(vol, &vol->link));
770 foreach_dlist(vol, vol_list) {
772 VOLRES *tvol = (VOLRES *)malloc(sizeof(VOLRES));
773 memset(tvol, 0, sizeof(VOLRES));
774 tvol->vol_name = bstrdup(vol->vol_name);
775 tvol->dev = vol->dev;
776 nvol = (VOLRES *)temp_vol_list->binary_insert(tvol, my_compare);
778 tvol->dev = NULL; /* don't zap dev entry */
780 Pmsg0(000, "Logic error. Duplicating vol list hit duplicate.\n");
781 Jmsg(jcr, M_WARNING, 0, "Logic error. Duplicating vol list hit duplicate.\n");
784 Dmsg0(dbglvl, "unlock volumes\n");
786 return temp_vol_list;
790 * Free the specified temp list.
792 void free_temp_vol_list(dlist *temp_vol_list)
794 dlist *save_vol_list;
797 save_vol_list = vol_list;
798 vol_list = temp_vol_list;
799 free_volume_list(); /* release temp_vol_list */
800 vol_list = save_vol_list;
801 Dmsg0(dbglvl, "deleted temp vol list\n");
802 Dmsg0(dbglvl, "unlock volumes\n");
804 debug_list_volumes("after free temp table");