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)) != 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);
108 * This allows a given thread to recursively call to lock_volumes()
113 vol_list_lock_count++;
114 if ((errstat=rwl_writelock(&vol_list_lock)) != 0) {
116 Emsg2(M_ABORT, 0, "rwl_writelock failure. stat=%d: ERR=%s\n",
117 errstat, be.bstrerror(errstat));
121 void _unlock_volumes()
124 vol_list_lock_count--;
125 if ((errstat=rwl_writeunlock(&vol_list_lock)) != 0) {
127 Emsg2(M_ABORT, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n",
128 errstat, be.bstrerror(errstat));
132 void lock_read_volumes()
137 void unlock_read_volumes()
143 * Add a volume to the read list.
144 * Note, we use VOLRES because it simplifies the code
145 * even though, the only part of VOLRES that we need is
146 * the volume name. The same volume may be in the list
147 * multiple times, but each one is distinguished by the
148 * JobId. We use JobId, VolumeName as the key.
149 * We can get called multiple times for the same volume because
150 * when parsing the bsr, the volume name appears multiple times.
152 void add_read_volume(JCR *jcr, const char *VolumeName)
157 nvol = new_vol_item(NULL, VolumeName);
158 nvol->set_jobid(jcr->JobId);
159 vol = (VOLRES *)read_vol_list->binary_insert(nvol, read_compare);
162 Dmsg2(dbglvl, "read_vol=%s JobId=%d already in list.\n", VolumeName, jcr->JobId);
164 Dmsg2(dbglvl, "add read_vol=%s JobId=%d\n", VolumeName, jcr->JobId);
166 unlock_read_volumes();
170 * Remove a given volume name from the read list.
172 void remove_read_volume(JCR *jcr, const char *VolumeName)
176 vol.vol_name = bstrdup(VolumeName);
177 vol.set_jobid(jcr->JobId);
178 fvol = (VOLRES *)read_vol_list->binary_search(&vol, read_compare);
181 Dmsg3(dbglvl, "remove_read_vol=%s JobId=%d found=%d\n", VolumeName, jcr->JobId, fvol!=NULL);
183 debug_list_volumes("remove_read_volume");
185 read_vol_list->remove(fvol);
188 unlock_read_volumes();
192 * List Volumes -- this should be moved to status.c
199 static void debug_list_volumes(const char *imsg)
202 POOL_MEM msg(PM_MESSAGE);
205 foreach_dlist(vol, vol_list) {
207 Mmsg(msg, "List %s: %s in_use=%d on device %s\n", imsg,
208 vol->vol_name, vol->is_in_use(), vol->dev->print_name());
210 Mmsg(msg, "List %s: %s in_use=%d no dev\n", imsg, vol->vol_name,
213 Dmsg1(dbglvl, "%s", msg.c_str());
221 * List Volumes -- this should be moved to status.c
223 void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
226 POOL_MEM msg(PM_MESSAGE);
230 foreach_dlist(vol, vol_list) {
231 DEVICE *dev = vol->dev;
233 len = Mmsg(msg, "%s on device %s\n", vol->vol_name, dev->print_name());
234 sendit(msg.c_str(), len, arg);
235 len = Mmsg(msg, " Reader=%d writers=%d devres=%d volinuse=%d\n",
236 dev->can_read()?1:0, dev->num_writers, dev->num_reserved(),
238 sendit(msg.c_str(), len, arg);
240 len = Mmsg(msg, "%s no device. volinuse= %d\n", vol->vol_name,
242 sendit(msg.c_str(), len, arg);
248 foreach_dlist(vol, read_vol_list) {
249 len = Mmsg(msg, "%s read volume JobId=%d\n", vol->vol_name,
251 sendit(msg.c_str(), len, arg);
253 unlock_read_volumes();
258 * Create a Volume item to put in the Volume list
259 * Ensure that the device points to it.
261 static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName)
264 vol = (VOLRES *)malloc(sizeof(VOLRES));
265 memset(vol, 0, sizeof(VOLRES));
266 vol->vol_name = bstrdup(VolumeName);
269 Dmsg3(dbglvl, "new Vol=%s at %p dev=%s\n",
270 VolumeName, vol->vol_name, vol->dev->print_name());
275 static void free_vol_item(VOLRES *vol)
290 * Put a new Volume entry in the Volume list. This
291 * effectively reserves the volume so that it will
292 * not be mounted again.
294 * If the device has any current volume associated with it,
295 * and it is a different Volume, and the device is not busy,
296 * we release the old Volume item and insert the new one.
298 * It is assumed that the device is free and locked so that
299 * we can change the device structure.
301 * Some details of the Volume list handling:
303 * 1. The Volume list entry must be attached to the drive (rather than
304 * attached to a job as it currently is. I.e. the drive that "owns"
305 * the volume (in use, mounted)
306 * must point to the volume (still to be maintained in a list).
308 * 2. The Volume is entered in the list when a drive is reserved.
310 * 3. When a drive is in use, the device code must appropriately update the
311 * volume name as it changes (currently the list is static -- an entry is
312 * removed when the Volume is no longer reserved, in use or mounted).
313 * The new code must keep the same list entry as long as the drive
314 * has any volume associated with it but the volume name in the list
315 * must be updated when the drive has a different volume mounted.
317 * 4. A job that has reserved a volume, can un-reserve the volume, and if the
318 * volume is not mounted, and not reserved, and not in use, it will be
319 * removed from the list.
321 * 5. If a job wants to reserve a drive with a different Volume from the one on
322 * the drive, it can re-use the drive for the new Volume.
324 * 6. If a job wants a Volume that is in a different drive, it can either use the
325 * other drive or take the volume, only if the other drive is not in use or
328 * One nice aspect of this is that the reserve use count and the writer use count
329 * already exist and are correctly programmed and will need no changes -- use
330 * counts are always very tricky.
332 * The old code had a concept of "reserving" a Volume, but was changed
333 * to reserving and using a drive. A volume is must be attached to (owned by) a
334 * drive and can move from drive to drive or be unused given certain specific
335 * conditions of the drive. The key is that the drive must "own" the Volume.
336 * The old code had the job (dcr) owning the volume (more or less). The job was
337 * to change the insertion and removal of the volumes from the list to be based
338 * on the drive rather than the job.
340 * Return: VOLRES entry on success
341 * NULL volume busy on another drive
343 VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
346 DEVICE * volatile dev = dcr->dev;
348 if (job_canceled(dcr->jcr)) {
353 Dmsg2(dbglvl, "enter reserve_volume=%s drive=%s\n", VolumeName,
354 dcr->dev->print_name());
356 * We lock the reservations system here to ensure
357 * when adding a new volume that no newly scheduled
358 * job can reserve it.
361 debug_list_volumes("begin reserve_volume");
363 * First, remove any old volume attached to this device as it
368 Dmsg4(dbglvl, "Vol attached=%s, newvol=%s volinuse=%d on %s\n",
369 vol->vol_name, VolumeName, vol->is_in_use(), dev->print_name());
371 * Make sure we don't remove the current volume we are inserting
372 * because it was probably inserted by another job, or it
373 * is not being used and is marked as not reserved.
375 if (strcmp(vol->vol_name, VolumeName) == 0) {
376 Dmsg2(dbglvl, "=== set reserved vol=%s dev=%s\n", VolumeName,
377 vol->dev->print_name());
378 goto get_out; /* Volume already on this device */
380 /* Don't release a volume if it was reserved by someone other than us */
381 if (vol->is_in_use() && !dcr->reserved_volume) {
382 Dmsg1(dbglvl, "Cannot free vol=%s. It is reserved.\n", vol->vol_name);
383 vol = NULL; /* vol in use */
386 Dmsg2(dbglvl, "reserve_vol free vol=%s at %p\n", vol->vol_name, vol->vol_name);
387 /* If old Volume is still mounted, must unload it */
388 if (strcmp(vol->vol_name, dev->VolHdr.VolumeName) == 0) {
389 Dmsg0(50, "set_unload\n");
390 dev->set_unload(); /* have to unload current volume */
392 free_volume(dev); /* Release old volume entry */
393 debug_list_volumes("reserve_vol free");
397 /* Create a new Volume entry */
398 nvol = new_vol_item(dcr, VolumeName);
401 * Now try to insert the new Volume
403 vol = (VOLRES *)vol_list->binary_insert(nvol, my_compare);
405 Dmsg2(dbglvl, "Found vol=%s dev-same=%d\n", vol->vol_name, dev==vol->dev);
407 * At this point, a Volume with this name already is in the list,
408 * so we simply release our new Volume entry. Note, this should
409 * only happen if we are moving the volume from one drive to another.
411 Dmsg2(dbglvl, "reserve_vol free-tmp vol=%s at %p\n",
412 vol->vol_name, vol->vol_name);
414 * Clear dev pointer so that free_vol_item() doesn't
415 * take away our volume.
417 nvol->dev = NULL; /* don't zap dev entry */
421 Dmsg2(dbglvl, "dev=%s vol->dev=%s\n", dev->print_name(), vol->dev->print_name());
425 * Check if we are trying to use the Volume on a different drive
427 * vol->dev is where the Volume we want is
429 if (dev != vol->dev) {
430 /* Caller wants to switch Volume to another device */
431 if (!vol->dev->is_busy() && !vol->is_swapping()) {
433 Dmsg3(dbglvl, "==== Swap vol=%s from dev=%s to %s\n",
434 VolumeName, vol->dev->print_name(), dev->print_name());
435 free_volume(dev); /* free any volume attached to our drive */
436 Dmsg0(50, "set_unload\n");
437 dev->set_unload(); /* Unload any volume that is on our drive */
438 dcr->dev = vol->dev; /* temp point to other dev */
439 slot = get_autochanger_loaded_slot(dcr); /* get slot on other drive */
440 dcr->dev = dev; /* restore dev */
441 vol->set_slot(slot); /* save slot */
442 vol->dev->set_unload(); /* unload the other drive */
443 vol->set_swapping(); /* swap from other drive */
444 dev->swap_dev = vol->dev; /* remember to get this vol */
445 dev->set_load(); /* then reload on our drive */
446 vol->dev->vol = NULL; /* remove volume from other drive */
447 vol->dev = dev; /* point the Volume at our drive */
448 dev->vol = vol; /* point our drive at the Volume */
450 Dmsg5(dbglvl, "==== Swap not possible Vol busy=%d swap=%d vol=%s from dev=%s to %s\n",
451 vol->dev->is_busy(), vol->is_swapping(),
452 VolumeName, vol->dev->print_name(), dev->print_name());
453 if (vol->is_swapping() && dev->swap_dev) {
454 Dmsg2(dbglvl, "Swap vol=%s dev=%s\n", vol->vol_name, dev->swap_dev->print_name());
456 Dmsg1(dbglvl, "swap_dev=%p\n", dev->swap_dev);
458 debug_list_volumes("failed swap");
459 vol = NULL; /* device busy */
466 dev->vol = vol; /* point to newly inserted volume */
471 Dmsg2(dbglvl, "=== set in_use. vol=%s dev=%s\n", vol->vol_name,
472 vol->dev->print_name());
474 dcr->reserved_volume = true;
475 bstrncpy(dcr->VolumeName, vol->vol_name, sizeof(dcr->VolumeName));
477 debug_list_volumes("end new volume");
483 * Switch from current device to given device
487 void switch_device(DCR *dcr, DEVICE *dev)
492 memcpy(&save_dcr, dcr, sizeof(save_dcr));
493 clean_device(dcr); /* clean up the dcr */
495 dcr->dev = dev; /* get new device pointer */
496 Jmsg(dcr->jcr, M_INFO, 0, _("Device switch. New device %s chosen.\n"),
497 dcr->dev->print_name());
499 bstrncpy(dcr->VolumeName, save_dcr.VolumeName, sizeof(dcr->VolumeName));
500 bstrncpy(dcr->media_type, save_dcr.media_type, sizeof(dcr->media_type));
501 dcr->VolCatInfo.Slot = save_dcr.VolCatInfo.Slot;
502 bstrncpy(dcr->pool_name, save_dcr.pool_name, sizeof(dcr->pool_name));
503 bstrncpy(dcr->pool_type, save_dcr.pool_type, sizeof(dcr->pool_type));
504 bstrncpy(dcr->dev_name, dev->dev_name, sizeof(dcr->dev_name));
506 // dcr->set_reserved();
513 * Search for a Volume name in the Volume list.
515 * Returns: VOLRES entry on success
516 * NULL if the Volume is not in the list
518 VOLRES *find_volume(const char *VolumeName)
522 if (vol_list->empty()) {
525 /* Do not lock reservations here */
527 vol.vol_name = bstrdup(VolumeName);
528 fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
530 Dmsg2(dbglvl, "find_vol=%s found=%d\n", VolumeName, fvol!=NULL);
531 debug_list_volumes("find_volume");
537 * Search for a Volume name in the read Volume list.
539 * Returns: VOLRES entry on success
540 * NULL if the Volume is not in the list
542 static VOLRES *find_read_volume(const char *VolumeName)
546 if (read_vol_list->empty()) {
547 Dmsg0(dbglvl, "find_read_vol: read_vol_list empty.\n");
550 /* Do not lock reservations here */
552 vol.vol_name = bstrdup(VolumeName);
553 /* Note, we do want a simple my_compare on volume name only here */
554 fvol = (VOLRES *)read_vol_list->binary_search(&vol, my_compare);
556 Dmsg2(dbglvl, "find_read_vol=%s found=%d\n", VolumeName, fvol!=NULL);
557 unlock_read_volumes();
563 * Free a Volume from the Volume list if it is no longer used
564 * Note, for tape drives we want to remember where the Volume
565 * was when last used, so rather than free the volume entry,
566 * we simply mark it "not reserved" so when the drive is really
567 * needed for another volume, we can reuse it.
569 * Returns: true if the Volume found and "removed" from the list
570 * false if the Volume is not in the list or is in use
572 bool volume_unused(DCR *dcr)
574 DEVICE *dev = dcr->dev;
577 Dmsg1(dbglvl, "vol_unused: no vol on %s\n", dev->print_name());
578 debug_list_volumes("null vol cannot unreserve_volume");
581 if (dev->vol->is_swapping()) {
582 Dmsg1(dbglvl, "vol_unused: vol being swapped on %s\n", dev->print_name());
583 Dmsg1(dbglvl, "=== clear in_use vol=%s\n", dev->vol->vol_name);
584 dev->vol->clear_in_use();
585 debug_list_volumes("swapping vol cannot free_volume");
590 * If this is a tape, we do not free the volume, rather we wait
591 * until the autoloader unloads it, or until another tape is
592 * explicitly read in this drive. This allows the SD to remember
593 * where the tapes are or last were.
595 Dmsg4(dbglvl, "=== set not reserved vol=%s num_writers=%d dev_reserved=%d dev=%s\n",
596 dev->vol->vol_name, dev->num_writers, dev->num_reserved(), dev->print_name());
597 Dmsg1(dbglvl, "=== clear in_use vol=%s\n", dev->vol->vol_name);
598 dev->vol->clear_in_use();
599 if (dev->is_tape() || dev->is_autochanger()) {
603 * Note, this frees the volume reservation entry, but the
604 * file descriptor remains open with the OS.
606 return free_volume(dev);
611 * Unconditionally release the volume entry
613 bool free_volume(DEVICE *dev)
617 if (dev->vol == NULL) {
618 Dmsg1(dbglvl, "No vol on dev %s\n", dev->print_name());
623 /* Don't free a volume while it is being swapped */
624 if (!vol->is_swapping()) {
625 Dmsg1(dbglvl, "=== clear in_use vol=%s\n", vol->vol_name);
627 vol_list->remove(vol);
628 Dmsg2(dbglvl, "=== remove volume %s dev=%s\n", vol->vol_name, dev->print_name());
630 debug_list_volumes("free_volume");
632 Dmsg1(dbglvl, "=== cannot clear swapping vol=%s\n", vol->vol_name);
639 /* Create the Volume list */
640 void create_volume_lists()
643 if (vol_list == NULL) {
644 vol_list = New(dlist(vol, &vol->link));
646 if (read_vol_list == NULL) {
647 read_vol_list = New(dlist(vol, &vol->link));
652 * Free normal append volumes list
654 static void free_volume_list()
659 foreach_dlist(vol, vol_list) {
661 Dmsg2(dbglvl, "free vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
663 Dmsg1(dbglvl, "free vol_list Volume=%s No dev\n", vol->vol_name);
666 vol->vol_name = NULL;
674 /* Release all Volumes from the list */
675 void free_volume_lists()
679 free_volume_list(); /* normal append list */
683 foreach_dlist(vol, read_vol_list) {
685 Dmsg2(dbglvl, "free read_vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
687 Dmsg1(dbglvl, "free read_vol_list Volume=%s No dev\n", vol->vol_name);
690 vol->vol_name = NULL;
692 delete read_vol_list;
693 read_vol_list = NULL;
694 unlock_read_volumes();
699 * Determine if caller can write on volume
701 bool DCR::can_i_write_volume()
705 vol = find_read_volume(VolumeName);
707 Dmsg1(100, "Found in read list; cannot write vol=%s\n", VolumeName);
710 return can_i_use_volume();
714 * Determine if caller can read or write volume
716 bool DCR::can_i_use_volume()
721 if (job_canceled(jcr)) {
725 vol = find_volume(VolumeName);
727 Dmsg1(dbglvl, "Vol=%s not in use.\n", VolumeName);
728 goto get_out; /* vol not in list */
730 ASSERT(vol->dev != NULL);
732 if (dev == vol->dev) { /* same device OK */
733 Dmsg1(dbglvl, "Vol=%s on same dev.\n", VolumeName);
736 Dmsg3(dbglvl, "Vol=%s on %s we have %s\n", VolumeName,
737 vol->dev->print_name(), dev->print_name());
739 /* ***FIXME*** check this ... */
740 if (!vol->dev->is_busy()) {
741 Dmsg2(dbglvl, "Vol=%s dev=%s not busy.\n", VolumeName, vol->dev->print_name());
744 Dmsg2(dbglvl, "Vol=%s dev=%s busy.\n", VolumeName, vol->dev->print_name());
746 Dmsg2(dbglvl, "Vol=%s in use by %s.\n", VolumeName, vol->dev->print_name());
756 * Create a temporary copy of the volume list. We do this,
757 * to avoid having the volume list locked during the
758 * call to reserve_device(), which would cause a deadlock.
759 * Note, we may want to add an update counter on the vol_list
760 * so that if it is modified while we are traversing the copy
761 * we can take note and act accordingly (probably redo the
762 * search at least a few times).
764 dlist *dup_vol_list(JCR *jcr)
766 dlist *temp_vol_list;
770 Dmsg0(dbglvl, "lock volumes\n");
772 Dmsg0(dbglvl, "duplicate vol list\n");
773 temp_vol_list = New(dlist(vol, &vol->link));
774 foreach_dlist(vol, vol_list) {
776 VOLRES *tvol = (VOLRES *)malloc(sizeof(VOLRES));
777 memset(tvol, 0, sizeof(VOLRES));
778 tvol->vol_name = bstrdup(vol->vol_name);
779 tvol->dev = vol->dev;
780 nvol = (VOLRES *)temp_vol_list->binary_insert(tvol, my_compare);
782 tvol->dev = NULL; /* don't zap dev entry */
784 Pmsg0(000, "Logic error. Duplicating vol list hit duplicate.\n");
785 Jmsg(jcr, M_WARNING, 0, "Logic error. Duplicating vol list hit duplicate.\n");
788 Dmsg0(dbglvl, "unlock volumes\n");
790 return temp_vol_list;
794 * Free the specified temp list.
796 void free_temp_vol_list(dlist *temp_vol_list)
798 dlist *save_vol_list;
801 save_vol_list = vol_list;
802 vol_list = temp_vol_list;
803 free_volume_list(); /* release temp_vol_list */
804 vol_list = save_vol_list;
805 Dmsg0(dbglvl, "deleted temp vol list\n");
806 Dmsg0(dbglvl, "unlock volumes\n");
808 debug_list_volumes("after free temp table");