1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
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.
8
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.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * Volume management functions for Storage Daemon
21 *
22 * Kern Sibbald, MM
23 *
24 * Split from reserve.c October 2008
25 *
26 */
27
28 #include "bacula.h"
29 #include "stored.h"
30
31 const int dbglvl = 150;
32
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);
37
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);
42
43 /*
44 * For append volumes the key is the VolumeName.
45 */
name_compare(void * item1,void * item2)46 static int name_compare(void *item1, void *item2)
47 {
48 return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
49 }
50
51 /*
52 * For read volumes the key is JobId, VolumeName.
53 */
read_compare(void * item1,void * item2)54 static int read_compare(void *item1, void *item2)
55 {
56 VOLRES *vol1 = (VOLRES *)item1;
57 VOLRES *vol2 = (VOLRES *)item2;
58
59 if (vol1->get_jobid() == vol2->get_jobid()) {
60 return strcmp(vol1->vol_name, vol2->vol_name);
61 }
62 if (vol1->get_jobid() < vol2->get_jobid()) {
63 return -1;
64 }
65 return 1;
66 }
67
is_vol_list_empty()68 bool is_vol_list_empty()
69 {
70 return vol_list->empty();
71 }
72
73 int vol_list_lock_count = 0;
74
75 /*
76 * Initialized the main volume list. Note, we are using a recursive lock.
77 */
init_vol_list_lock()78 void init_vol_list_lock()
79 {
80 int errstat;
81 if ((errstat=rwl_init(&vol_list_lock, PRIO_SD_VOL_LIST)) != 0) {
82 berrno be;
83 Emsg1(M_ABORT, 0, _("Unable to initialize volume list lock. ERR=%s\n"),
84 be.bstrerror(errstat));
85 }
86 }
87
term_vol_list_lock()88 void term_vol_list_lock()
89 {
90 rwl_destroy(&vol_list_lock);
91 }
92
93 /*
94 * This allows a given thread to recursively call to lock_volumes()
95 */
_lock_volumes(const char * file,int line)96 void _lock_volumes(const char *file, int line)
97 {
98 int errstat;
99 vol_list_lock_count++;
100 if ((errstat=rwl_writelock_p(&vol_list_lock, file, line)) != 0) {
101 berrno be;
102 Emsg2(M_ABORT, 0, "rwl_writelock failure. stat=%d: ERR=%s\n",
103 errstat, be.bstrerror(errstat));
104 }
105 }
106
_unlock_volumes()107 void _unlock_volumes()
108 {
109 int errstat;
110 vol_list_lock_count--;
111 if ((errstat=rwl_writeunlock(&vol_list_lock)) != 0) {
112 berrno be;
113 Emsg2(M_ABORT, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n",
114 errstat, be.bstrerror(errstat));
115 }
116 }
117
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)
120 {
121 bthread_mutex_lock_p(&read_vol_lock, file, line);
122 }
123
unlock_read_volumes()124 static void unlock_read_volumes()
125 {
126 bthread_mutex_unlock(&read_vol_lock);
127 }
128
129 /*
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.
138 */
add_read_volume(JCR * jcr,const char * VolumeName)139 void add_read_volume(JCR *jcr, const char *VolumeName)
140 {
141 VOLRES *nvol, *vol;
142
143 nvol = new_vol_item(NULL, VolumeName);
144 nvol->set_jobid(jcr->JobId);
145 nvol->set_reading();
146 lock_read_volumes();
147 vol = (VOLRES *)read_vol_list->binary_insert(nvol, read_compare);
148 if (vol != nvol) {
149 free_vol_item(nvol);
150 Dmsg2(dbglvl, "read_vol=%s JobId=%d already in list.\n", VolumeName, jcr->JobId);
151 } else {
152 Dmsg2(dbglvl, "add read_vol=%s JobId=%d\n", VolumeName, jcr->JobId);
153 }
154 unlock_read_volumes();
155 }
156
157 /*
158 * Check if volume name is in the read list.
159 */
is_read_volume(JCR * jcr,const char * VolumeName)160 bool is_read_volume(JCR *jcr, const char *VolumeName)
161 {
162 VOLRES vol, *fvol;
163 lock_read_volumes();
164 vol.vol_name = bstrdup(VolumeName);
165 fvol = (VOLRES *)read_vol_list->binary_search(&vol, name_compare);
166 free(vol.vol_name);
167 unlock_read_volumes();
168 return fvol != NULL;
169 }
170
171 /*
172 * Remove a given volume name from the read list.
173 */
remove_read_volume(JCR * jcr,const char * VolumeName)174 void remove_read_volume(JCR *jcr, const char *VolumeName)
175 {
176 VOLRES vol, *fvol;
177 lock_read_volumes();
178 vol.vol_name = bstrdup(VolumeName);
179 vol.set_jobid(jcr->JobId);
180 fvol = (VOLRES *)read_vol_list->binary_search(&vol, read_compare);
181 free(vol.vol_name);
182 if (fvol) {
183 Dmsg3(dbglvl, "remove_read_vol=%s JobId=%d found=%d\n", VolumeName, jcr->JobId, fvol!=NULL);
184 }
185 if (fvol) {
186 read_vol_list->remove(fvol);
187 free_vol_item(fvol);
188 }
189 unlock_read_volumes();
190 // pthread_cond_broadcast(&wait_next_vol);
191 }
192
193 /*
194 * List Volumes -- this should be moved to status.c
195 */
196 enum {
197 debug_lock = true,
198 debug_nolock = false
199 };
200
debug_list_volumes(const char * imsg)201 static void debug_list_volumes(const char *imsg)
202 {
203 VOLRES *vol;
204 POOL_MEM msg(PM_MESSAGE);
205
206 if (debug_level < dbglvl) {
207 return;
208 }
209
210 foreach_vol(vol) {
211 if (vol->dev) {
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(),
214 vol->get_slot(),
215 vol->dev->print_type(), vol->dev->print_name());
216 } else {
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());
219 }
220 Dmsg1(dbglvl, "%s", msg.c_str());
221 }
222 endeach_vol(vol);
223 }
224
225
226 /*
227 * List Volumes -- this should be moved to status.c
228 */
list_volumes(void sendit (const char * msg,int len,void * sarg),void * arg)229 void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
230 {
231 VOLRES *vol;
232 POOL_MEM msg(PM_MESSAGE);
233 int len;
234
235 foreach_vol(vol) {
236 DEVICE *dev = vol->dev;
237 if (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 worm=%d\n",
242 dev->can_read()?1:0, dev->num_writers, dev->num_reserved(),
243 vol->is_in_use(), dev->is_worm());
244 sendit(msg.c_str(), len, arg);
245 } else {
246 len = Mmsg(msg, "Volume %s no device. volinuse=%d\n", vol->vol_name,
247 vol->is_in_use());
248 sendit(msg.c_str(), len, arg);
249 }
250 }
251 endeach_vol(vol);
252
253 lock_read_volumes();
254 foreach_dlist(vol, read_vol_list) {
255 DEVICE *dev = vol->dev;
256 if (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);
264 } else {
265 len = Mmsg(msg, "Volume: %s no device. volinuse=%d\n", vol->vol_name,
266 vol->is_in_use());
267 sendit(msg.c_str(), len, arg);
268 }
269 }
270 unlock_read_volumes();
271 }
272
273 /*
274 * Create a Volume item to put in the Volume list
275 * Ensure that the device points to it.
276 */
new_vol_item(DCR * dcr,const char * VolumeName)277 static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName)
278 {
279 VOLRES *vol;
280 vol = (VOLRES *)malloc(sizeof(VOLRES));
281 memset(vol, 0, sizeof(VOLRES));
282 vol->vol_name = bstrdup(VolumeName);
283 if (dcr) {
284 vol->dev = dcr->dev;
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());
287 }
288 vol->init_mutex();
289 vol->inc_use_count();
290 return vol;
291 }
292
free_vol_item(VOLRES * vol)293 static void free_vol_item(VOLRES *vol)
294 {
295 DEVICE *dev = NULL;
296
297 vol->dec_use_count();
298 vol->vLock();
299 if (vol->use_count() > 0) {
300 vol->vUnlock();
301 return;
302 }
303 vol->vUnlock();
304 free(vol->vol_name);
305 if (vol->dev) {
306 dev = vol->dev;
307 }
308 vol->destroy_mutex();
309 free(vol);
310 if (dev) {
311 dev->vol = NULL;
312 }
313 }
314
315 /*
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.
319 *
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.
323 *
324 * It is assumed that the device is free and locked so that
325 * we can change the device structure.
326 *
327 * Some details of the Volume list handling:
328 *
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).
333 *
334 * 2. The Volume is entered in the list when a drive is reserved.
335 *
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.
341 *
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.
345 *
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.
348
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
351 * not reserved.
352 *
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.
356 *
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.
361 *
362 * Return: VOLRES entry on success
363 * NULL volume busy on another drive
364 * jcr->errmsg has details
365 */
reserve_volume(DCR * dcr,const char * VolumeName)366 VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
367 {
368 VOLRES *vol, *nvol;
369 DEVICE * volatile dev = dcr->dev;
370 JCR *jcr = dcr->jcr;
371
372 jcr->errmsg[0] = 0;
373 if (job_canceled(dcr->jcr)) {
374 Mmsg1(jcr->errmsg, _("Could not reserve volume \"%s\", because job canceled.\n"),
375 dev->VolHdr.VolumeName);
376 return NULL;
377 }
378 ASSERT2(dev != NULL, "No device in reserve_volume!");
379
380 Dmsg2(dbglvl, "enter reserve_volume=%s drive=%s\n", VolumeName,
381 dcr->dev->print_name());
382
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);
387 return NULL;
388 }
389
390 /*
391 * We lock the reservations system here to ensure
392 * when adding a new volume that no newly scheduled
393 * job can reserve it.
394 */
395 lock_volumes();
396 debug_list_volumes("begin reserve_volume");
397 /*
398 * First, remove any old volume attached to this device as it
399 * is no longer used.
400 */
401 if (dev->vol) {
402 vol = dev->vol;
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());
405 /*
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.
409 */
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 */
414 } else {
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());
421 dev->set_wait();
422 vol = NULL; /* vol in use */
423 goto get_out;
424 }
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 */
430 }
431 free_volume(dev); /* Release old volume entry */
432 debug_list_volumes("reserve_vol free");
433 }
434 }
435
436 /* Create a new Volume entry */
437 nvol = new_vol_item(dcr, VolumeName);
438
439 /*
440 * Handle request for read volume for file
441 * device, for which we assume we can open multiple
442 * devices to read the Volume.
443 *
444 * Note: when doing multiple simultaneous reads
445 * of the same volume, the volume names are not
446 * inserted into the write volume list.
447 */
448 if (dcr->is_reading() && dev->is_file()) {
449 nvol->set_jobid(dcr->jcr->JobId);
450 nvol->set_reading();
451 vol = nvol;
452 dev->vol = vol;
453 goto get_out;
454 } else {
455 vol = (VOLRES *)vol_list->binary_insert(nvol, name_compare);
456 }
457
458 /*
459 * This part handles any write volumes or read volumes that
460 * cannot be simultaneously on multiple devices.
461 */
462 if (vol != nvol) {
463 /*
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.
467 */
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);
471 /*
472 * Clear dev pointer so that free_vol_item() doesn't
473 * take away our volume.
474 */
475 nvol->dev = NULL; /* don't zap dev entry */
476 free_vol_item(nvol);
477
478 if (vol->dev) {
479 Dmsg2(dbglvl, "dev=%s vol->dev=%s\n", dev->print_name(), vol->dev->print_name());
480 }
481
482 /*
483 * Check if we are trying to use the Volume on a different drive
484 * dev is our device
485 * vol->dev is where the Volume we want is
486 */
487 if (dev != vol->dev) {
488 /* Caller wants to switch Volume to another device */
489 if (!vol->dev->is_busy() && !vol->is_swapping()) {
490 int32_t slot;
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 */
508 } else {
509 if (dev) {
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());
517 }
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());
523 } else {
524 Mmsg1(jcr->errmsg, _("Volume %s is busy swapping.\n"),
525 NPRT(vol->vol_name));
526 }
527 } else if (vol->dev) {
528 Mmsg2(jcr->errmsg, _("%s device %s is busy.\n"),
529 vol->dev->print_type(), vol->dev->print_name());
530 } else {
531 Mmsg1(jcr->errmsg, _("Volume %s is busy swapping.\n"),
532 NPRT(vol->vol_name));
533 }
534 debug_list_volumes("failed swap");
535 vol = NULL; /* device busy */
536 goto get_out;
537 }
538 } else {
539 dev->vol = vol;
540 }
541 } else {
542 dev->vol = vol; /* point to newly inserted volume */
543 }
544
545 get_out:
546 if (vol) {
547 Dmsg2(dbglvl, "set in_use. vol=%s dev=%s\n", vol->vol_name,
548 vol->dev->print_name());
549 vol->set_in_use();
550 dcr->reserved_volume = true;
551 bstrncpy(dcr->VolumeName, vol->vol_name, sizeof(dcr->VolumeName));
552 }
553 debug_list_volumes("end new volume");
554 unlock_volumes();
555 return vol;
556 }
557
558 /*
559 * Start walk of vol chain
560 * The proper way to walk the vol chain is:
561 * VOLRES *vol;
562 * foreach_vol(vol) {
563 * ...
564 * }
565 * endeach_vol(vol);
566 *
567 * It is possible to leave out the endeach_vol(vol), but
568 * in that case, the last vol referenced must be explicitly
569 * released with:
570 *
571 * free_vol_item(vol);
572 *
573 */
vol_walk_start()574 VOLRES *vol_walk_start()
575 {
576 VOLRES *vol;
577 lock_volumes();
578 vol = (VOLRES *)vol_list->first();
579 if (vol) {
580 vol->inc_use_count();
581 Dmsg2(dbglvl, "Inc walk_start use_count=%d volname=%s\n",
582 vol->use_count(), vol->vol_name);
583 }
584 unlock_volumes();
585 return vol;
586 }
587
588 /*
589 * Get next vol from chain, and release current one
590 */
vol_walk_next(VOLRES * prev_vol)591 VOLRES *vol_walk_next(VOLRES *prev_vol)
592 {
593 VOLRES *vol;
594
595 lock_volumes();
596 vol = (VOLRES *)vol_list->next(prev_vol);
597 if (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);
601 }
602 if (prev_vol) {
603 free_vol_item(prev_vol);
604 }
605 unlock_volumes();
606 return vol;
607 }
608
609 /*
610 * Release last vol referenced
611 */
vol_walk_end(VOLRES * vol)612 void vol_walk_end(VOLRES *vol)
613 {
614 if (vol) {
615 lock_volumes();
616 Dmsg2(dbglvl, "Free walk_end use_count=%d volname=%s\n",
617 vol->use_count(), vol->vol_name);
618 free_vol_item(vol);
619 unlock_volumes();
620 }
621 }
622
623 /*
624 * Search for a Volume name in the Volume list.
625 *
626 * Returns: VOLRES entry on success
627 * NULL if the Volume is not in the list
628 */
find_volume(const char * VolumeName)629 static VOLRES *find_volume(const char *VolumeName)
630 {
631 VOLRES vol, *fvol;
632
633 if (vol_list->empty()) {
634 return NULL;
635 }
636 /* Do not lock reservations here */
637 lock_volumes();
638 vol.vol_name = bstrdup(VolumeName);
639 fvol = (VOLRES *)vol_list->binary_search(&vol, name_compare);
640 free(vol.vol_name);
641 Dmsg2(dbglvl, "find_vol=%s found=%d\n", VolumeName, fvol!=NULL);
642 debug_list_volumes("find_volume");
643 unlock_volumes();
644 return fvol;
645 }
646
647 /*
648 * Search for a Volume name in the read Volume list.
649 *
650 * Returns: VOLRES entry on success
651 * NULL if the Volume is not in the list
652 */
find_read_volume(const char * VolumeName)653 static VOLRES *find_read_volume(const char *VolumeName)
654 {
655 VOLRES vol, *fvol;
656
657 if (read_vol_list->empty()) {
658 Dmsg0(dbglvl, "find_read_vol: read_vol_list empty.\n");
659 return NULL;
660 }
661 /* Do not lock reservations here */
662 lock_read_volumes();
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);
666 free(vol.vol_name);
667 Dmsg2(dbglvl, "find_read_vol=%s found=%d\n", VolumeName, fvol!=NULL);
668 unlock_read_volumes();
669 return fvol;
670 }
671
672
673 /*
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.
679 *
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
682 */
volume_unused(DCR * dcr)683 bool volume_unused(DCR *dcr)
684 {
685 DEVICE *dev = dcr->dev;
686
687 if (!dev->vol) {
688 Dmsg1(dbglvl, "vol_unused: no vol on %s\n", dev->print_name());
689 debug_list_volumes("null vol cannot unreserve_volume");
690 return false;
691 }
692
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();
696
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");
700 return false;
701 }
702
703 /*
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.
708 */
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()) {
713 return true;
714 } else {
715 /*
716 * Note, this frees the volume reservation entry, but the
717 * file descriptor remains open with the OS.
718 */
719 return free_volume(dev);
720 }
721 }
722
723 /*
724 * Unconditionally release the volume entry
725 * Note: read volumes are not in the list, so
726 * do not attempt to remove them.
727 */
free_volume(DEVICE * dev)728 bool free_volume(DEVICE *dev)
729 {
730 VOLRES *vol;
731
732 lock_volumes();
733 vol = dev->vol;
734 if (vol == NULL) {
735 Dmsg1(dbglvl, "No vol on dev %s\n", dev->print_name());
736 unlock_volumes();
737 return false;
738 }
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());
742 dev->vol = NULL;
743 if (vol->is_writing()) {
744 vol_list->remove(vol);
745 }
746 Dmsg3(dbglvl, "Remove volume %s slot=%d dev=%s\n", vol->vol_name,
747 vol->get_slot(), dev->print_name());
748 free_vol_item(vol);
749 debug_list_volumes("free_volume");
750 } else {
751 Dmsg1(dbglvl, "=== Cannot clear. Swapping vol=%s\n", vol->vol_name);
752 }
753 unlock_volumes();
754 return true;
755 }
756
757
758 /* Create the Volume list */
create_volume_lists()759 void create_volume_lists()
760 {
761 VOLRES *vol = NULL;
762 if (vol_list == NULL) {
763 vol_list = New(dlist(vol, &vol->link));
764 }
765 if (read_vol_list == NULL) {
766 read_vol_list = New(dlist(vol, &vol->link));
767 }
768 }
769
770 /*
771 * Free normal append volumes list
772 */
free_volume_list()773 static void free_volume_list()
774 {
775 VOLRES *vol;
776 if (vol_list) {
777 lock_volumes();
778 foreach_dlist(vol, vol_list) {
779 if (vol->dev) {
780 Dmsg2(dbglvl, "free vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
781 } else {
782 Dmsg1(dbglvl, "free vol_list Volume=%s No dev\n", vol->vol_name);
783 }
784 free(vol->vol_name);
785 vol->vol_name = NULL;
786 vol->destroy_mutex();
787 }
788 delete vol_list;
789 vol_list = NULL;
790 unlock_volumes();
791 }
792 }
793
794 /* Release all Volumes from the list */
free_volume_lists()795 void free_volume_lists()
796 {
797 VOLRES *vol;
798
799 free_volume_list(); /* normal append list */
800
801 if (read_vol_list) {
802 lock_read_volumes();
803 foreach_dlist(vol, read_vol_list) {
804 if (vol->dev) {
805 Dmsg2(dbglvl, "free read_vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
806 } else {
807 Dmsg1(dbglvl, "free read_vol_list Volume=%s No dev\n", vol->vol_name);
808 }
809 free(vol->vol_name);
810 vol->vol_name = NULL;
811 vol->destroy_mutex();
812 }
813 delete read_vol_list;
814 read_vol_list = NULL;
815 unlock_read_volumes();
816 }
817 }
818
819 /*
820 * Determine if caller can write on volume.
821 * If not, return reason in jcr->errmsg
822 */
can_i_write_volume()823 bool DCR::can_i_write_volume()
824 {
825 VOLRES *vol;
826
827 vol = find_read_volume(VolumeName);
828 if (vol) {
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);
831 return false;
832 }
833 return can_i_use_volume();
834 }
835
836 /*
837 * Determine if caller can read or write volume.
838 * If not, return reason in jcr->errmsg
839 */
can_i_use_volume()840 bool DCR::can_i_use_volume()
841 {
842 bool rtn = true;
843 VOLRES *vol;
844
845 if (job_canceled(jcr)) {
846 Mmsg(jcr->errmsg, "Job is canceled\n");
847 return false;
848 }
849 lock_volumes();
850 vol = find_volume(VolumeName);
851 if (!vol) {
852 Dmsg1(dbglvl, "Vol=%s not in use.\n", VolumeName);
853 goto get_out; /* vol not in list */
854 }
855 ASSERT2(vol->dev != NULL, "No device in can_i_use_volume!");
856
857 if (dev == vol->dev) { /* same device OK */
858 Dmsg1(dbglvl, "Vol=%s on same dev.\n", VolumeName);
859 goto get_out;
860 } else {
861 Dmsg3(dbglvl, "Vol=%s on %s we have %s\n", VolumeName,
862 vol->dev->print_name(), dev->print_name());
863 }
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());
867 goto get_out;
868 } else {
869 Dmsg2(dbglvl, "Vol=%s dev=%s busy.\n", VolumeName, vol->dev->print_name());
870 }
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());
873 rtn = false;
874
875 get_out:
876 unlock_volumes();
877 return rtn;
878
879 }
880
881 /*
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).
889 */
dup_vol_list(JCR * jcr)890 dlist *dup_vol_list(JCR *jcr)
891 {
892 dlist *temp_vol_list;
893 VOLRES *vol = NULL;
894
895 Dmsg0(dbglvl, "lock volumes\n");
896
897 Dmsg0(dbglvl, "duplicate vol list\n");
898 temp_vol_list = New(dlist(vol, &vol->link));
899 foreach_vol(vol) {
900 VOLRES *nvol;
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;
905 tvol->init_mutex();
906 tvol->inc_use_count();
907 nvol = (VOLRES *)temp_vol_list->binary_insert(tvol, name_compare);
908 if (tvol != nvol) {
909 tvol->dev = NULL; /* don't zap dev entry */
910 free_vol_item(tvol);
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");
913 }
914 }
915 endeach_vol(vol);
916 Dmsg0(dbglvl, "unlock volumes\n");
917 return temp_vol_list;
918 }
919
920 /*
921 * Free the specified temp list.
922 */
free_temp_vol_list(dlist * temp_vol_list)923 void free_temp_vol_list(dlist *temp_vol_list)
924 {
925 dlist *save_vol_list;
926
927 lock_volumes();
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");
934 unlock_volumes();
935 debug_list_volumes("after free temp table");
936 }
937