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);
52 static void debug_list_volumes(const char *imsg);
55 * For append volumes the key is the VolumeName.
57 static int my_compare(void *item1, void *item2)
59 return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
63 * For read volumes the key is JobId, VolumeName.
65 static int read_compare(void *item1, void *item2)
67 VOLRES *vol1 = (VOLRES *)item1;
68 VOLRES *vol2 = (VOLRES *)item2;
70 if (vol1->get_jobid() == vol2->get_jobid()) {
71 return strcmp(vol1->vol_name, vol2->vol_name);
73 if (vol1->get_jobid() < vol2->get_jobid()) {
80 bool is_vol_list_empty()
82 return vol_list->empty();
85 int vol_list_lock_count = 0;
88 * Initialized the main volume list. Note, we are using a recursive lock.
90 void init_vol_list_lock()
93 if ((errstat=rwl_init(&vol_list_lock, PRIO_SD_VOL_LIST)) != 0) {
95 Emsg1(M_ABORT, 0, _("Unable to initialize volume list lock. ERR=%s\n"),
96 be.bstrerror(errstat));
100 void term_vol_list_lock()
102 rwl_destroy(&vol_list_lock);
106 * This allows a given thread to recursively call to lock_volumes()
111 vol_list_lock_count++;
112 if ((errstat=rwl_writelock(&vol_list_lock)) != 0) {
114 Emsg2(M_ABORT, 0, "rwl_writelock failure. stat=%d: ERR=%s\n",
115 errstat, be.bstrerror(errstat));
119 void _unlock_volumes()
122 vol_list_lock_count--;
123 if ((errstat=rwl_writeunlock(&vol_list_lock)) != 0) {
125 Emsg2(M_ABORT, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n",
126 errstat, be.bstrerror(errstat));
130 void lock_read_volumes()
135 void unlock_read_volumes()
141 * Add a volume to the read list.
142 * Note, we use VOLRES because it simplifies the code
143 * even though, the only part of VOLRES that we need is
144 * the volume name. The same volume may be in the list
145 * multiple times, but each one is distinguished by the
146 * JobId. We use JobId, VolumeName as the key.
147 * We can get called multiple times for the same volume because
148 * when parsing the bsr, the volume name appears multiple times.
150 void add_read_volume(JCR *jcr, const char *VolumeName)
155 nvol = new_vol_item(NULL, VolumeName);
156 nvol->set_jobid(jcr->JobId);
157 vol = (VOLRES *)read_vol_list->binary_insert(nvol, read_compare);
160 Dmsg2(dbglvl, "read_vol=%s JobId=%d already in list.\n", VolumeName, jcr->JobId);
162 Dmsg2(dbglvl, "add read_vol=%s JobId=%d\n", VolumeName, jcr->JobId);
164 unlock_read_volumes();
168 * Remove a given volume name from the read list.
170 void remove_read_volume(JCR *jcr, const char *VolumeName)
174 vol.vol_name = bstrdup(VolumeName);
175 vol.set_jobid(jcr->JobId);
176 fvol = (VOLRES *)read_vol_list->binary_search(&vol, read_compare);
179 Dmsg3(dbglvl, "remove_read_vol=%s JobId=%d found=%d\n", VolumeName, jcr->JobId, fvol!=NULL);
181 debug_list_volumes("remove_read_volume");
183 read_vol_list->remove(fvol);
186 unlock_read_volumes();
190 * List Volumes -- this should be moved to status.c
197 static void debug_list_volumes(const char *imsg)
200 POOL_MEM msg(PM_MESSAGE);
203 foreach_dlist(vol, vol_list) {
205 Mmsg(msg, "List %s: %s in_use=%d on device %s\n", imsg,
206 vol->vol_name, vol->is_in_use(), vol->dev->print_name());
208 Mmsg(msg, "List %s: %s in_use=%d no dev\n", imsg, vol->vol_name,
211 Dmsg1(dbglvl, "%s", msg.c_str());
219 * List Volumes -- this should be moved to status.c
221 void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
224 POOL_MEM msg(PM_MESSAGE);
228 foreach_dlist(vol, vol_list) {
229 DEVICE *dev = vol->dev;
231 len = Mmsg(msg, "%s on device %s\n", vol->vol_name, dev->print_name());
232 sendit(msg.c_str(), len, arg);
233 len = Mmsg(msg, " Reader=%d writers=%d devres=%d volinuse=%d\n",
234 dev->can_read()?1:0, dev->num_writers, dev->num_reserved(),
236 sendit(msg.c_str(), len, arg);
238 len = Mmsg(msg, "%s no device. volinuse= %d\n", vol->vol_name,
240 sendit(msg.c_str(), len, arg);
246 foreach_dlist(vol, read_vol_list) {
247 len = Mmsg(msg, "%s read volume JobId=%d\n", vol->vol_name,
249 sendit(msg.c_str(), len, arg);
251 unlock_read_volumes();
256 * Create a Volume item to put in the Volume list
257 * Ensure that the device points to it.
259 static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName)
262 vol = (VOLRES *)malloc(sizeof(VOLRES));
263 memset(vol, 0, sizeof(VOLRES));
264 vol->vol_name = bstrdup(VolumeName);
267 Dmsg3(dbglvl, "new Vol=%s at %p dev=%s\n",
268 VolumeName, vol->vol_name, vol->dev->print_name());
273 static void free_vol_item(VOLRES *vol)
288 * Put a new Volume entry in the Volume list. This
289 * effectively reserves the volume so that it will
290 * not be mounted again.
292 * If the device has any current volume associated with it,
293 * and it is a different Volume, and the device is not busy,
294 * we release the old Volume item and insert the new one.
296 * It is assumed that the device is free and locked so that
297 * we can change the device structure.
299 * Some details of the Volume list handling:
301 * 1. The Volume list entry must be attached to the drive (rather than
302 * attached to a job as it currently is. I.e. the drive that "owns"
303 * the volume (in use, mounted)
304 * must point to the volume (still to be maintained in a list).
306 * 2. The Volume is entered in the list when a drive is reserved.
308 * 3. When a drive is in use, the device code must appropriately update the
309 * volume name as it changes (currently the list is static -- an entry is
310 * removed when the Volume is no longer reserved, in use or mounted).
311 * The new code must keep the same list entry as long as the drive
312 * has any volume associated with it but the volume name in the list
313 * must be updated when the drive has a different volume mounted.
315 * 4. A job that has reserved a volume, can un-reserve the volume, and if the
316 * volume is not mounted, and not reserved, and not in use, it will be
317 * removed from the list.
319 * 5. If a job wants to reserve a drive with a different Volume from the one on
320 * the drive, it can re-use the drive for the new Volume.
322 * 6. If a job wants a Volume that is in a different drive, it can either use the
323 * other drive or take the volume, only if the other drive is not in use or
326 * One nice aspect of this is that the reserve use count and the writer use count
327 * already exist and are correctly programmed and will need no changes -- use
328 * counts are always very tricky.
330 * The old code had a concept of "reserving" a Volume, but was changed
331 * to reserving and using a drive. A volume is must be attached to (owned by) a
332 * drive and can move from drive to drive or be unused given certain specific
333 * conditions of the drive. The key is that the drive must "own" the Volume.
334 * The old code had the job (dcr) owning the volume (more or less). The job was
335 * to change the insertion and removal of the volumes from the list to be based
336 * on the drive rather than the job.
338 * Return: VOLRES entry on success
339 * NULL volume busy on another drive
341 VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
344 DEVICE * volatile dev = dcr->dev;
346 if (job_canceled(dcr->jcr)) {
351 Dmsg2(dbglvl, "enter reserve_volume=%s drive=%s\n", VolumeName,
352 dcr->dev->print_name());
354 * We lock the reservations system here to ensure
355 * when adding a new volume that no newly scheduled
356 * job can reserve it.
359 debug_list_volumes("begin reserve_volume");
361 * First, remove any old volume attached to this device as it
366 Dmsg4(dbglvl, "Vol attached=%s, newvol=%s volinuse=%d on %s\n",
367 vol->vol_name, VolumeName, vol->is_in_use(), dev->print_name());
369 * Make sure we don't remove the current volume we are inserting
370 * because it was probably inserted by another job, or it
371 * is not being used and is marked as not reserved.
373 if (strcmp(vol->vol_name, VolumeName) == 0) {
374 Dmsg2(dbglvl, "=== set reserved vol=%s dev=%s\n", VolumeName,
375 vol->dev->print_name());
376 goto get_out; /* Volume already on this device */
378 /* Don't release a volume if it was reserved by someone other than us */
379 if (vol->is_in_use() && !dcr->reserved_volume) {
380 Dmsg1(dbglvl, "Cannot free vol=%s. It is reserved.\n", vol->vol_name);
381 vol = NULL; /* vol in use */
384 Dmsg2(dbglvl, "reserve_vol free vol=%s at %p\n", vol->vol_name, vol->vol_name);
385 /* If old Volume is still mounted, must unload it */
386 if (strcmp(vol->vol_name, dev->VolHdr.VolumeName) == 0) {
387 Dmsg0(50, "set_unload\n");
388 dev->set_unload(); /* have to unload current volume */
390 free_volume(dev); /* Release old volume entry */
391 debug_list_volumes("reserve_vol free");
395 /* Create a new Volume entry */
396 nvol = new_vol_item(dcr, VolumeName);
399 * Now try to insert the new Volume
401 vol = (VOLRES *)vol_list->binary_insert(nvol, my_compare);
403 Dmsg2(dbglvl, "Found vol=%s dev-same=%d\n", vol->vol_name, dev==vol->dev);
405 * At this point, a Volume with this name already is in the list,
406 * so we simply release our new Volume entry. Note, this should
407 * only happen if we are moving the volume from one drive to another.
409 Dmsg2(dbglvl, "reserve_vol free-tmp vol=%s at %p\n",
410 vol->vol_name, vol->vol_name);
412 * Clear dev pointer so that free_vol_item() doesn't
413 * take away our volume.
415 nvol->dev = NULL; /* don't zap dev entry */
419 Dmsg2(dbglvl, "dev=%s vol->dev=%s\n", dev->print_name(), vol->dev->print_name());
423 * Check if we are trying to use the Volume on a different drive
425 * vol->dev is where the Volume we want is
427 if (dev != vol->dev) {
428 /* Caller wants to switch Volume to another device */
429 if (!vol->dev->is_busy() && !vol->is_swapping()) {
431 Dmsg3(dbglvl, "==== Swap vol=%s from dev=%s to %s\n",
432 VolumeName, vol->dev->print_name(), dev->print_name());
433 free_volume(dev); /* free any volume attached to our drive */
434 Dmsg0(50, "set_unload\n");
435 dev->set_unload(); /* Unload any volume that is on our drive */
436 dcr->dev = vol->dev; /* temp point to other dev */
437 slot = get_autochanger_loaded_slot(dcr); /* get slot on other drive */
438 dcr->dev = dev; /* restore dev */
439 vol->set_slot(slot); /* save slot */
440 vol->dev->set_unload(); /* unload the other drive */
441 vol->set_swapping(); /* swap from other drive */
442 dev->swap_dev = vol->dev; /* remember to get this vol */
443 dev->set_load(); /* then reload on our drive */
444 vol->dev->vol = NULL; /* remove volume from other drive */
445 vol->dev = dev; /* point the Volume at our drive */
446 dev->vol = vol; /* point our drive at the Volume */
448 Dmsg5(dbglvl, "==== Swap not possible Vol busy=%d swap=%d vol=%s from dev=%s to %s\n",
449 vol->dev->is_busy(), vol->is_swapping(),
450 VolumeName, vol->dev->print_name(), dev->print_name());
451 if (vol->is_swapping() && dev->swap_dev) {
452 Dmsg2(dbglvl, "Swap vol=%s dev=%s\n", vol->vol_name, dev->swap_dev->print_name());
454 Dmsg1(dbglvl, "swap_dev=%p\n", dev->swap_dev);
456 debug_list_volumes("failed swap");
457 vol = NULL; /* device busy */
464 dev->vol = vol; /* point to newly inserted volume */
469 Dmsg2(dbglvl, "=== set in_use. vol=%s dev=%s\n", vol->vol_name,
470 vol->dev->print_name());
472 dcr->reserved_volume = true;
473 bstrncpy(dcr->VolumeName, vol->vol_name, sizeof(dcr->VolumeName));
475 debug_list_volumes("end new volume");
481 * Switch from current device to given device
485 void switch_device(DCR *dcr, DEVICE *dev)
490 memcpy(&save_dcr, dcr, sizeof(save_dcr));
491 clean_device(dcr); /* clean up the dcr */
493 dcr->dev = dev; /* get new device pointer */
494 Jmsg(dcr->jcr, M_INFO, 0, _("Device switch. New device %s chosen.\n"),
495 dcr->dev->print_name());
497 bstrncpy(dcr->VolumeName, save_dcr.VolumeName, sizeof(dcr->VolumeName));
498 bstrncpy(dcr->media_type, save_dcr.media_type, sizeof(dcr->media_type));
499 dcr->VolCatInfo.Slot = save_dcr.VolCatInfo.Slot;
500 bstrncpy(dcr->pool_name, save_dcr.pool_name, sizeof(dcr->pool_name));
501 bstrncpy(dcr->pool_type, save_dcr.pool_type, sizeof(dcr->pool_type));
502 bstrncpy(dcr->dev_name, dev->dev_name, sizeof(dcr->dev_name));
504 // dcr->set_reserved();
511 * Search for a Volume name in the Volume list.
513 * Returns: VOLRES entry on success
514 * NULL if the Volume is not in the list
516 VOLRES *find_volume(const char *VolumeName)
520 if (vol_list->empty()) {
523 /* Do not lock reservations here */
525 vol.vol_name = bstrdup(VolumeName);
526 fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
528 Dmsg2(dbglvl, "find_vol=%s found=%d\n", VolumeName, fvol!=NULL);
529 debug_list_volumes("find_volume");
535 * Search for a Volume name in the read Volume list.
537 * Returns: VOLRES entry on success
538 * NULL if the Volume is not in the list
540 static VOLRES *find_read_volume(const char *VolumeName)
544 if (read_vol_list->empty()) {
545 Dmsg0(dbglvl, "find_read_vol: read_vol_list empty.\n");
548 /* Do not lock reservations here */
550 vol.vol_name = bstrdup(VolumeName);
551 /* Note, we do want a simple my_compare on volume name only here */
552 fvol = (VOLRES *)read_vol_list->binary_search(&vol, my_compare);
554 Dmsg2(dbglvl, "find_read_vol=%s found=%d\n", VolumeName, fvol!=NULL);
555 unlock_read_volumes();
561 * Free a Volume from the Volume list if it is no longer used
562 * Note, for tape drives we want to remember where the Volume
563 * was when last used, so rather than free the volume entry,
564 * we simply mark it "not reserved" so when the drive is really
565 * needed for another volume, we can reuse it.
567 * Returns: true if the Volume found and "removed" from the list
568 * false if the Volume is not in the list or is in use
570 bool volume_unused(DCR *dcr)
572 DEVICE *dev = dcr->dev;
575 Dmsg1(dbglvl, "vol_unused: no vol on %s\n", dev->print_name());
576 debug_list_volumes("null vol cannot unreserve_volume");
579 if (dev->vol->is_swapping()) {
580 Dmsg1(dbglvl, "vol_unused: vol being swapped on %s\n", dev->print_name());
581 Dmsg1(dbglvl, "=== clear in_use vol=%s\n", dev->vol->vol_name);
582 dev->vol->clear_in_use();
583 debug_list_volumes("swapping vol cannot free_volume");
588 * If this is a tape, we do not free the volume, rather we wait
589 * until the autoloader unloads it, or until another tape is
590 * explicitly read in this drive. This allows the SD to remember
591 * where the tapes are or last were.
593 Dmsg4(dbglvl, "=== set not reserved vol=%s num_writers=%d dev_reserved=%d dev=%s\n",
594 dev->vol->vol_name, dev->num_writers, dev->num_reserved(), dev->print_name());
595 Dmsg1(dbglvl, "=== clear in_use vol=%s\n", dev->vol->vol_name);
596 dev->vol->clear_in_use();
597 if (dev->is_tape() || dev->is_autochanger()) {
601 * Note, this frees the volume reservation entry, but the
602 * file descriptor remains open with the OS.
604 return free_volume(dev);
609 * Unconditionally release the volume entry
611 bool free_volume(DEVICE *dev)
615 if (dev->vol == NULL) {
616 Dmsg1(dbglvl, "No vol on dev %s\n", dev->print_name());
621 /* Don't free a volume while it is being swapped */
622 if (!vol->is_swapping()) {
623 Dmsg1(dbglvl, "=== clear in_use vol=%s\n", vol->vol_name);
625 vol_list->remove(vol);
626 Dmsg2(dbglvl, "=== remove volume %s dev=%s\n", vol->vol_name, dev->print_name());
628 debug_list_volumes("free_volume");
630 Dmsg1(dbglvl, "=== cannot clear swapping vol=%s\n", vol->vol_name);
637 /* Create the Volume list */
638 void create_volume_lists()
641 if (vol_list == NULL) {
642 vol_list = New(dlist(vol, &vol->link));
644 if (read_vol_list == NULL) {
645 read_vol_list = New(dlist(vol, &vol->link));
650 * Free normal append volumes list
652 static void free_volume_list()
657 foreach_dlist(vol, vol_list) {
659 Dmsg2(dbglvl, "free vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
661 Dmsg1(dbglvl, "free vol_list Volume=%s No dev\n", vol->vol_name);
664 vol->vol_name = NULL;
672 /* Release all Volumes from the list */
673 void free_volume_lists()
677 free_volume_list(); /* normal append list */
681 foreach_dlist(vol, read_vol_list) {
683 Dmsg2(dbglvl, "free read_vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
685 Dmsg1(dbglvl, "free read_vol_list Volume=%s No dev\n", vol->vol_name);
688 vol->vol_name = NULL;
690 delete read_vol_list;
691 read_vol_list = NULL;
692 unlock_read_volumes();
697 * Determine if caller can write on volume
699 bool DCR::can_i_write_volume()
703 vol = find_read_volume(VolumeName);
705 Dmsg1(100, "Found in read list; cannot write vol=%s\n", VolumeName);
708 return can_i_use_volume();
712 * Determine if caller can read or write volume
714 bool DCR::can_i_use_volume()
719 if (job_canceled(jcr)) {
723 vol = find_volume(VolumeName);
725 Dmsg1(dbglvl, "Vol=%s not in use.\n", VolumeName);
726 goto get_out; /* vol not in list */
728 ASSERT(vol->dev != NULL);
730 if (dev == vol->dev) { /* same device OK */
731 Dmsg1(dbglvl, "Vol=%s on same dev.\n", VolumeName);
734 Dmsg3(dbglvl, "Vol=%s on %s we have %s\n", VolumeName,
735 vol->dev->print_name(), dev->print_name());
737 /* ***FIXME*** check this ... */
738 if (!vol->dev->is_busy()) {
739 Dmsg2(dbglvl, "Vol=%s dev=%s not busy.\n", VolumeName, vol->dev->print_name());
742 Dmsg2(dbglvl, "Vol=%s dev=%s busy.\n", VolumeName, vol->dev->print_name());
744 Dmsg2(dbglvl, "Vol=%s in use by %s.\n", VolumeName, vol->dev->print_name());
754 * Create a temporary copy of the volume list. We do this,
755 * to avoid having the volume list locked during the
756 * call to reserve_device(), which would cause a deadlock.
757 * Note, we may want to add an update counter on the vol_list
758 * so that if it is modified while we are traversing the copy
759 * we can take note and act accordingly (probably redo the
760 * search at least a few times).
762 dlist *dup_vol_list(JCR *jcr)
764 dlist *temp_vol_list;
768 Dmsg0(dbglvl, "lock volumes\n");
770 Dmsg0(dbglvl, "duplicate vol list\n");
771 temp_vol_list = New(dlist(vol, &vol->link));
772 foreach_dlist(vol, vol_list) {
774 VOLRES *tvol = (VOLRES *)malloc(sizeof(VOLRES));
775 memset(tvol, 0, sizeof(VOLRES));
776 tvol->vol_name = bstrdup(vol->vol_name);
777 tvol->dev = vol->dev;
778 nvol = (VOLRES *)temp_vol_list->binary_insert(tvol, my_compare);
780 tvol->dev = NULL; /* don't zap dev entry */
782 Pmsg0(000, "Logic error. Duplicating vol list hit duplicate.\n");
783 Jmsg(jcr, M_WARNING, 0, "Logic error. Duplicating vol list hit duplicate.\n");
786 Dmsg0(dbglvl, "unlock volumes\n");
788 return temp_vol_list;
792 * Free the specified temp list.
794 void free_temp_vol_list(dlist *temp_vol_list)
796 dlist *save_vol_list;
799 save_vol_list = vol_list;
800 vol_list = temp_vol_list;
801 free_volume_list(); /* release temp_vol_list */
802 vol_list = save_vol_list;
803 Dmsg0(dbglvl, "deleted temp vol list\n");
804 Dmsg0(dbglvl, "unlock volumes\n");
806 debug_list_volumes("after free temp table");