2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 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 two of the GNU 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 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
35 * Version $Id: reserve.c 7380 2008-07-14 10:42:59Z kerns $
42 const int dbglvl = 150;
44 static dlist *vol_list = NULL;
45 static brwlock_t vol_list_lock;
46 static dlist *read_vol_list = NULL;
47 static pthread_mutex_t read_vol_lock = PTHREAD_MUTEX_INITIALIZER;
49 /* Forward referenced functions */
50 static void free_vol_item(VOLRES *vol);
51 static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName);
54 * For append volumes the key is the VolumeName.
56 static int my_compare(void *item1, void *item2)
58 return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
62 * For read volumes the key is JobId, VolumeName.
64 static int read_compare(void *item1, void *item2)
66 VOLRES *vol1 = (VOLRES *)item1;
67 VOLRES *vol2 = (VOLRES *)item2;
69 if (vol1->get_jobid() == vol2->get_jobid()) {
70 return strcmp(vol1->vol_name, vol2->vol_name);
72 if (vol1->get_jobid() < vol2->get_jobid()) {
79 bool is_vol_list_empty()
81 return vol_list->empty();
84 int vol_list_lock_count = 0;
87 * Initialized the main volume list. Note, we are using a recursive lock.
89 void init_vol_list_lock()
92 if ((errstat=rwl_init(&vol_list_lock)) != 0) {
94 Emsg1(M_ABORT, 0, _("Unable to initialize volume list lock. ERR=%s\n"),
95 be.bstrerror(errstat));
99 void term_vol_list_lock()
101 rwl_destroy(&vol_list_lock);
107 * This allows a given thread to recursively call to lock_volumes()
112 vol_list_lock_count++;
113 if ((errstat=rwl_writelock(&vol_list_lock)) != 0) {
115 Emsg2(M_ABORT, 0, "rwl_writelock failure. stat=%d: ERR=%s\n",
116 errstat, be.bstrerror(errstat));
120 void _unlock_volumes()
123 vol_list_lock_count--;
124 if ((errstat=rwl_writeunlock(&vol_list_lock)) != 0) {
126 Emsg2(M_ABORT, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n",
127 errstat, be.bstrerror(errstat));
131 void lock_read_volumes()
136 void unlock_read_volumes()
142 * Add a volume to the read list.
143 * Note, we use VOLRES because it simplifies the code
144 * even though, the only part of VOLRES that we need is
145 * the volume name. The same volume may be in the list
146 * multiple times, but each one is distinguished by the
147 * JobId. We use JobId, VolumeName as the key.
148 * We can get called multiple times for the same volume because
149 * when parsing the bsr, the volume name appears multiple times.
151 void add_read_volume(JCR *jcr, const char *VolumeName)
156 nvol = new_vol_item(NULL, VolumeName);
157 nvol->set_jobid(jcr->JobId);
158 vol = (VOLRES *)read_vol_list->binary_insert(nvol, read_compare);
161 Dmsg2(dbglvl, "read_vol=%s JobId=%d already in list.\n", VolumeName, jcr->JobId);
163 Dmsg2(dbglvl, "add read_vol=%s JobId=%d\n", VolumeName, jcr->JobId);
165 unlock_read_volumes();
169 * Remove a given volume name from the read list.
171 void remove_read_volume(JCR *jcr, const char *VolumeName)
175 vol.vol_name = bstrdup(VolumeName);
176 vol.set_jobid(jcr->JobId);
177 fvol = (VOLRES *)read_vol_list->binary_search(&vol, read_compare);
180 Dmsg3(dbglvl, "remove_read_vol=%s JobId=%d found=%d\n", VolumeName, jcr->JobId, fvol!=NULL);
182 debug_list_volumes("remove_read_volume");
184 read_vol_list->remove(fvol);
187 unlock_read_volumes();
191 * List Volumes -- this should be moved to status.c
198 void debug_list_volumes(const char *imsg)
201 POOL_MEM msg(PM_MESSAGE);
204 foreach_dlist(vol, vol_list) {
206 Mmsg(msg, "List %s: %s in_use=%d on device %s\n", imsg,
207 vol->vol_name, vol->is_in_use(), vol->dev->print_name());
209 Mmsg(msg, "List %s: %s in_use=%d no dev\n", imsg, vol->vol_name,
212 Dmsg1(dbglvl, "%s", msg.c_str());
220 * List Volumes -- this should be moved to status.c
222 void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
225 POOL_MEM msg(PM_MESSAGE);
229 foreach_dlist(vol, vol_list) {
230 DEVICE *dev = vol->dev;
232 len = Mmsg(msg, "%s on device %s\n", vol->vol_name, dev->print_name());
233 sendit(msg.c_str(), len, arg);
234 len = Mmsg(msg, " Reader=%d writers=%d devres=%d volinuse=%d\n",
235 dev->can_read()?1:0, dev->num_writers, dev->num_reserved(),
237 sendit(msg.c_str(), len, arg);
239 len = Mmsg(msg, "%s no device. volinuse= %d\n", vol->vol_name,
241 sendit(msg.c_str(), len, arg);
247 foreach_dlist(vol, read_vol_list) {
248 len = Mmsg(msg, "%s read volume JobId=%d\n", vol->vol_name,
250 sendit(msg.c_str(), len, arg);
252 unlock_read_volumes();
257 * Create a Volume item to put in the Volume list
258 * Ensure that the device points to it.
260 static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName)
263 vol = (VOLRES *)malloc(sizeof(VOLRES));
264 memset(vol, 0, sizeof(VOLRES));
265 vol->vol_name = bstrdup(VolumeName);
268 Dmsg3(dbglvl, "new Vol=%s at %p dev=%s\n",
269 VolumeName, vol->vol_name, vol->dev->print_name());
274 static void free_vol_item(VOLRES *vol)
289 * Put a new Volume entry in the Volume list. This
290 * effectively reserves the volume so that it will
291 * not be mounted again.
293 * If the device has any current volume associated with it,
294 * and it is a different Volume, and the device is not busy,
295 * we release the old Volume item and insert the new one.
297 * It is assumed that the device is free and locked so that
298 * we can change the device structure.
300 * Some details of the Volume list handling:
302 * 1. The Volume list entry must be attached to the drive (rather than
303 * attached to a job as it currently is. I.e. the drive that "owns"
304 * the volume (in use, mounted)
305 * must point to the volume (still to be maintained in a list).
307 * 2. The Volume is entered in the list when a drive is reserved.
309 * 3. When a drive is in use, the device code must appropriately update the
310 * volume name as it changes (currently the list is static -- an entry is
311 * removed when the Volume is no longer reserved, in use or mounted).
312 * The new code must keep the same list entry as long as the drive
313 * has any volume associated with it but the volume name in the list
314 * must be updated when the drive has a different volume mounted.
316 * 4. A job that has reserved a volume, can un-reserve the volume, and if the
317 * volume is not mounted, and not reserved, and not in use, it will be
318 * removed from the list.
320 * 5. If a job wants to reserve a drive with a different Volume from the one on
321 * the drive, it can re-use the drive for the new Volume.
323 * 6. If a job wants a Volume that is in a different drive, it can either use the
324 * other drive or take the volume, only if the other drive is not in use or
327 * One nice aspect of this is that the reserve use count and the writer use count
328 * already exist and are correctly programmed and will need no changes -- use
329 * counts are always very tricky.
331 * The old code had a concept of "reserving" a Volume, but was changed
332 * to reserving and using a drive. A volume is must be attached to (owned by) a
333 * drive and can move from drive to drive or be unused given certain specific
334 * conditions of the drive. The key is that the drive must "own" the Volume.
335 * The old code had the job (dcr) owning the volume (more or less). The job was
336 * to change the insertion and removal of the volumes from the list to be based
337 * on the drive rather than the job.
339 * Return: VOLRES entry on success
340 * NULL volume busy on another drive
342 VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
345 DEVICE * volatile dev = dcr->dev;
347 if (job_canceled(dcr->jcr)) {
352 Dmsg2(dbglvl, "enter reserve_volume=%s drive=%s\n", VolumeName,
353 dcr->dev->print_name());
355 * We lock the reservations system here to ensure
356 * when adding a new volume that no newly scheduled
357 * job can reserve it.
360 debug_list_volumes("begin reserve_volume");
362 * First, remove any old volume attached to this device as it
367 Dmsg4(dbglvl, "Vol attached=%s, newvol=%s volinuse=%d on %s\n",
368 vol->vol_name, VolumeName, vol->is_in_use(), dev->print_name());
370 * Make sure we don't remove the current volume we are inserting
371 * because it was probably inserted by another job, or it
372 * is not being used and is marked as not reserved.
374 if (strcmp(vol->vol_name, VolumeName) == 0) {
375 Dmsg2(dbglvl, "=== set reserved vol=%s dev=%s\n", VolumeName,
376 vol->dev->print_name());
377 goto get_out; /* Volume already on this device */
379 /* Don't release a volume if it was reserved by someone other than us */
380 if (vol->is_in_use() && !dcr->reserved_volume) {
381 Dmsg1(dbglvl, "Cannot free vol=%s. It is reserved.\n", vol->vol_name);
382 vol = NULL; /* vol in use */
385 Dmsg2(dbglvl, "reserve_vol free vol=%s at %p\n", vol->vol_name, vol->vol_name);
386 /* If old Volume is still mounted, must unload it */
387 if (strcmp(vol->vol_name, dev->VolHdr.VolumeName) == 0) {
388 Dmsg0(50, "set_unload\n");
389 dev->set_unload(); /* have to unload current volume */
391 free_volume(dev); /* Release old volume entry */
392 debug_list_volumes("reserve_vol free");
396 /* Create a new Volume entry */
397 nvol = new_vol_item(dcr, VolumeName);
400 * Now try to insert the new Volume
402 vol = (VOLRES *)vol_list->binary_insert(nvol, my_compare);
404 Dmsg2(dbglvl, "Found vol=%s dev-same=%d\n", vol->vol_name, dev==vol->dev);
406 * At this point, a Volume with this name already is in the list,
407 * so we simply release our new Volume entry. Note, this should
408 * only happen if we are moving the volume from one drive to another.
410 Dmsg2(dbglvl, "reserve_vol free-tmp vol=%s at %p\n",
411 vol->vol_name, vol->vol_name);
413 * Clear dev pointer so that free_vol_item() doesn't
414 * take away our volume.
416 nvol->dev = NULL; /* don't zap dev entry */
420 Dmsg2(dbglvl, "dev=%s vol->dev=%s\n", dev->print_name(), vol->dev->print_name());
424 * Check if we are trying to use the Volume on a different drive
426 * vol->dev is where the Volume we want is
428 if (dev != vol->dev) {
429 /* Caller wants to switch Volume to another device */
430 if (!vol->dev->is_busy() && !vol->is_swapping()) {
432 Dmsg3(dbglvl, "==== Swap vol=%s from dev=%s to %s\n",
433 VolumeName, vol->dev->print_name(), dev->print_name());
434 free_volume(dev); /* free any volume attached to our drive */
435 Dmsg0(50, "set_unload\n");
436 dev->set_unload(); /* Unload any volume that is on our drive */
437 dcr->dev = vol->dev; /* temp point to other dev */
438 slot = get_autochanger_loaded_slot(dcr); /* get slot on other drive */
439 dcr->dev = dev; /* restore dev */
440 vol->set_slot(slot); /* save slot */
441 vol->dev->set_unload(); /* unload the other drive */
442 vol->set_swapping(); /* swap from other drive */
443 dev->swap_dev = vol->dev; /* remember to get this vol */
444 dev->set_load(); /* then reload on our drive */
445 vol->dev->vol = NULL; /* remove volume from other drive */
446 vol->dev = dev; /* point the Volume at our drive */
447 dev->vol = vol; /* point our drive at the Volume */
449 Dmsg5(dbglvl, "==== Swap not possible Vol busy=%d swap=%d vol=%s from dev=%s to %s\n",
450 vol->dev->is_busy(), vol->is_swapping(),
451 VolumeName, vol->dev->print_name(), dev->print_name());
452 if (vol->is_swapping() && dev->swap_dev) {
453 Dmsg2(dbglvl, "Swap vol=%s dev=%s\n", vol->vol_name, dev->swap_dev->print_name());
455 Dmsg1(dbglvl, "swap_dev=%p\n", dev->swap_dev);
457 debug_list_volumes("failed swap");
458 vol = NULL; /* device busy */
465 dev->vol = vol; /* point to newly inserted volume */
470 Dmsg2(dbglvl, "=== set in_use. vol=%s dev=%s\n", vol->vol_name,
471 vol->dev->print_name());
473 dcr->reserved_volume = true;
474 bstrncpy(dcr->VolumeName, vol->vol_name, sizeof(dcr->VolumeName));
476 debug_list_volumes("end new volume");
482 * Switch from current device to given device
486 void switch_device(DCR *dcr, DEVICE *dev)
491 memcpy(&save_dcr, dcr, sizeof(save_dcr));
492 clean_device(dcr); /* clean up the dcr */
494 dcr->dev = dev; /* get new device pointer */
495 Jmsg(dcr->jcr, M_INFO, 0, _("Device switch. New device %s chosen.\n"),
496 dcr->dev->print_name());
498 bstrncpy(dcr->VolumeName, save_dcr.VolumeName, sizeof(dcr->VolumeName));
499 bstrncpy(dcr->media_type, save_dcr.media_type, sizeof(dcr->media_type));
500 dcr->VolCatInfo.Slot = save_dcr.VolCatInfo.Slot;
501 bstrncpy(dcr->pool_name, save_dcr.pool_name, sizeof(dcr->pool_name));
502 bstrncpy(dcr->pool_type, save_dcr.pool_type, sizeof(dcr->pool_type));
503 bstrncpy(dcr->dev_name, dev->dev_name, sizeof(dcr->dev_name));
505 // dcr->set_reserved();
512 * Search for a Volume name in the Volume list.
514 * Returns: VOLRES entry on success
515 * NULL if the Volume is not in the list
517 VOLRES *find_volume(const char *VolumeName)
521 if (vol_list->empty()) {
524 /* Do not lock reservations here */
526 vol.vol_name = bstrdup(VolumeName);
527 fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
529 Dmsg2(dbglvl, "find_vol=%s found=%d\n", VolumeName, fvol!=NULL);
530 debug_list_volumes("find_volume");
536 * Search for a Volume name in the read Volume list.
538 * Returns: VOLRES entry on success
539 * NULL if the Volume is not in the list
541 static VOLRES *find_read_volume(const char *VolumeName)
545 if (read_vol_list->empty()) {
546 Dmsg0(dbglvl, "find_read_vol: read_vol_list empty.\n");
549 /* Do not lock reservations here */
551 vol.vol_name = bstrdup(VolumeName);
552 /* Note, we do want a simple my_compare on volume name only here */
553 fvol = (VOLRES *)read_vol_list->binary_search(&vol, my_compare);
555 Dmsg2(dbglvl, "find_read_vol=%s found=%d\n", VolumeName, fvol!=NULL);
556 unlock_read_volumes();
562 * Free a Volume from the Volume list if it is no longer used
563 * Note, for tape drives we want to remember where the Volume
564 * was when last used, so rather than free the volume entry,
565 * we simply mark it "not reserved" so when the drive is really
566 * needed for another volume, we can reuse it.
568 * Returns: true if the Volume found and "removed" from the list
569 * false if the Volume is not in the list or is in use
571 bool volume_unused(DCR *dcr)
573 DEVICE *dev = dcr->dev;
576 Dmsg1(dbglvl, "vol_unused: no vol on %s\n", dev->print_name());
577 debug_list_volumes("null vol cannot unreserve_volume");
580 if (dev->vol->is_swapping()) {
581 Dmsg1(dbglvl, "vol_unused: vol being swapped on %s\n", dev->print_name());
582 Dmsg1(dbglvl, "=== clear in_use vol=%s\n", dev->vol->vol_name);
583 dev->vol->clear_in_use();
584 debug_list_volumes("swapping vol cannot free_volume");
589 * If this is a tape, we do not free the volume, rather we wait
590 * until the autoloader unloads it, or until another tape is
591 * explicitly read in this drive. This allows the SD to remember
592 * where the tapes are or last were.
594 Dmsg4(dbglvl, "=== set not reserved vol=%s num_writers=%d dev_reserved=%d dev=%s\n",
595 dev->vol->vol_name, dev->num_writers, dev->num_reserved(), dev->print_name());
596 Dmsg1(dbglvl, "=== clear in_use vol=%s\n", dev->vol->vol_name);
597 dev->vol->clear_in_use();
598 if (dev->is_tape() || dev->is_autochanger()) {
602 * Note, this frees the volume reservation entry, but the
603 * file descriptor remains open with the OS.
605 return free_volume(dev);
610 * Unconditionally release the volume entry
612 bool free_volume(DEVICE *dev)
616 if (dev->vol == NULL) {
617 Dmsg1(dbglvl, "No vol on dev %s\n", dev->print_name());
622 /* Don't free a volume while it is being swapped */
623 if (!vol->is_swapping()) {
624 Dmsg1(dbglvl, "=== clear in_use vol=%s\n", vol->vol_name);
626 vol_list->remove(vol);
627 Dmsg2(dbglvl, "=== remove volume %s dev=%s\n", vol->vol_name, dev->print_name());
629 debug_list_volumes("free_volume");
631 Dmsg1(dbglvl, "=== cannot clear swapping vol=%s\n", vol->vol_name);
638 /* Create the Volume list */
639 void create_volume_lists()
642 if (vol_list == NULL) {
643 vol_list = New(dlist(vol, &vol->link));
645 if (read_vol_list == NULL) {
646 read_vol_list = New(dlist(vol, &vol->link));
651 * Free normal append volumes list
653 static void free_volume_list()
658 foreach_dlist(vol, vol_list) {
660 Dmsg2(dbglvl, "free vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
662 Dmsg1(dbglvl, "free vol_list Volume=%s No dev\n", vol->vol_name);
665 vol->vol_name = NULL;
673 /* Release all Volumes from the list */
674 void free_volume_lists()
678 free_volume_list(); /* normal append list */
682 foreach_dlist(vol, read_vol_list) {
684 Dmsg2(dbglvl, "free read_vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
686 Dmsg1(dbglvl, "free read_vol_list Volume=%s No dev\n", vol->vol_name);
689 vol->vol_name = NULL;
691 delete read_vol_list;
692 read_vol_list = NULL;
693 unlock_read_volumes();
698 * Determine if caller can write on volume
700 bool DCR::can_i_write_volume()
704 vol = find_read_volume(VolumeName);
706 Dmsg1(100, "Found in read list; cannot write vol=%s\n", VolumeName);
709 return can_i_use_volume();
713 * Determine if caller can read or write volume
715 bool DCR::can_i_use_volume()
720 if (job_canceled(jcr)) {
724 vol = find_volume(VolumeName);
726 Dmsg1(dbglvl, "Vol=%s not in use.\n", VolumeName);
727 goto get_out; /* vol not in list */
729 ASSERT(vol->dev != NULL);
731 if (dev == vol->dev) { /* same device OK */
732 Dmsg1(dbglvl, "Vol=%s on same dev.\n", VolumeName);
735 Dmsg3(dbglvl, "Vol=%s on %s we have %s\n", VolumeName,
736 vol->dev->print_name(), dev->print_name());
738 /* ***FIXME*** check this ... */
739 if (!vol->dev->is_busy()) {
740 Dmsg2(dbglvl, "Vol=%s dev=%s not busy.\n", VolumeName, vol->dev->print_name());
743 Dmsg2(dbglvl, "Vol=%s dev=%s busy.\n", VolumeName, vol->dev->print_name());
745 Dmsg2(dbglvl, "Vol=%s in use by %s.\n", VolumeName, vol->dev->print_name());
755 * Create a temporary copy of the volume list. We do this,
756 * to avoid having the volume list locked during the
757 * call to reserve_device(), which would cause a deadlock.
758 * Note, we may want to add an update counter on the vol_list
759 * so that if it is modified while we are traversing the copy
760 * we can take note and act accordingly (probably redo the
761 * search at least a few times).
763 dlist *dup_vol_list(JCR *jcr)
765 dlist *temp_vol_list;
769 Dmsg0(dbglvl, "lock volumes\n");
771 Dmsg0(dbglvl, "duplicate vol list\n");
772 temp_vol_list = New(dlist(vol, &vol->link));
773 foreach_dlist(vol, vol_list) {
775 VOLRES *tvol = (VOLRES *)malloc(sizeof(VOLRES));
776 memset(tvol, 0, sizeof(VOLRES));
777 tvol->vol_name = bstrdup(vol->vol_name);
778 tvol->dev = vol->dev;
779 nvol = (VOLRES *)temp_vol_list->binary_insert(tvol, my_compare);
781 tvol->dev = NULL; /* don't zap dev entry */
783 Pmsg0(000, "Logic error. Duplicating vol list hit duplicate.\n");
784 Jmsg(jcr, M_WARNING, 0, "Logic error. Duplicating vol list hit duplicate.\n");
787 Dmsg0(dbglvl, "unlock volumes\n");
789 return temp_vol_list;
793 * Free the specified temp list.
795 void free_temp_vol_list(dlist *temp_vol_list)
797 dlist *save_vol_list;
800 save_vol_list = vol_list;
801 vol_list = temp_vol_list;
802 free_volume_list(); /* release temp_vol_list */
803 vol_list = save_vol_list;
804 Dmsg0(dbglvl, "deleted temp vol list\n");
805 Dmsg0(dbglvl, "unlock volumes\n");
807 debug_list_volumes("after free temp table");