]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/vol_mgr.c
update version
[bacula/bacula] / bacula / src / stored / vol_mgr.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
5
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
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /*
29  *   Volume management functions for Storage Daemon
30  *
31  *   Kern Sibbald, MM
32  *
33  *   Split from reserve.c October 2008
34  *
35  *   Version $Id: reserve.c 7380 2008-07-14 10:42:59Z kerns $
36  *
37  */
38
39 #include "bacula.h"
40 #include "stored.h"
41
42 const int dbglvl =  150;
43
44 static dlist *vol_list = NULL;
45 static brwlock_t vol_list_lock;
46 static dlist *read_vol_list = NULL;
47 static bthread_mutex_t read_vol_lock = BTHREAD_MUTEX_PRIORITY(PRIO_SD_READ_VOL_LIST);
48
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);
53
54 /*
55  * For append volumes the key is the VolumeName.
56  */
57 static int my_compare(void *item1, void *item2)
58 {
59    return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
60 }
61
62 /*
63  * For read volumes the key is JobId, VolumeName.
64  */
65 static int read_compare(void *item1, void *item2)
66 {
67    VOLRES *vol1 = (VOLRES *)item1;
68    VOLRES *vol2 = (VOLRES *)item2;
69
70    if (vol1->get_jobid() == vol2->get_jobid()) {
71       return strcmp(vol1->vol_name, vol2->vol_name);
72    }
73    if (vol1->get_jobid() < vol2->get_jobid()) {
74       return -1;
75    }
76    return 1;
77 }
78
79
80 bool is_vol_list_empty() 
81 {
82    return vol_list->empty();
83 }
84
85 int vol_list_lock_count = 0;
86
87 /*
88  *  Initialized the main volume list. Note, we are using a recursive lock.
89  */
90 void init_vol_list_lock()
91 {
92    int errstat;
93    if ((errstat=rwl_init(&vol_list_lock, PRIO_SD_VOL_LIST)) != 0) {
94       berrno be;
95       Emsg1(M_ABORT, 0, _("Unable to initialize volume list lock. ERR=%s\n"),
96             be.bstrerror(errstat));
97    }
98 }
99
100 void term_vol_list_lock()
101 {
102    rwl_destroy(&vol_list_lock);
103 }
104
105 /* 
106  * This allows a given thread to recursively call to lock_volumes()
107  */
108 void _lock_volumes(const char *file, int line)
109 {
110    int errstat;
111    vol_list_lock_count++;
112    if ((errstat=rwl_writelock_p(&vol_list_lock, file, line)) != 0) {
113       berrno be;
114       Emsg2(M_ABORT, 0, "rwl_writelock failure. stat=%d: ERR=%s\n",
115            errstat, be.bstrerror(errstat));
116    }
117 }
118
119 void _unlock_volumes()
120 {
121    int errstat;
122    vol_list_lock_count--;
123    if ((errstat=rwl_writeunlock(&vol_list_lock)) != 0) {
124       berrno be;
125       Emsg2(M_ABORT, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n",
126            errstat, be.bstrerror(errstat));
127    }
128 }
129
130 void lock_read_volumes(const char *file="**Unknown", int line=0)
131 {
132    bthread_mutex_lock_p(&read_vol_lock, file, line);
133 }
134
135 void unlock_read_volumes()
136 {
137    bthread_mutex_unlock(&read_vol_lock);
138 }
139
140 /*
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.
149  */
150 void add_read_volume(JCR *jcr, const char *VolumeName)
151 {
152    VOLRES *nvol, *vol;
153
154    lock_read_volumes();
155    nvol = new_vol_item(NULL, VolumeName);
156    nvol->set_jobid(jcr->JobId);
157    vol = (VOLRES *)read_vol_list->binary_insert(nvol, read_compare);
158    if (vol != nvol) {
159       free_vol_item(nvol);
160       Dmsg2(dbglvl, "read_vol=%s JobId=%d already in list.\n", VolumeName, jcr->JobId);
161    } else {
162       Dmsg2(dbglvl, "add read_vol=%s JobId=%d\n", VolumeName, jcr->JobId);
163    }
164    unlock_read_volumes();
165 }
166
167 /*
168  * Remove a given volume name from the read list.
169  */
170 void remove_read_volume(JCR *jcr, const char *VolumeName)
171 {
172    VOLRES vol, *fvol;
173    lock_read_volumes();
174    vol.vol_name = bstrdup(VolumeName);
175    vol.set_jobid(jcr->JobId);
176    fvol = (VOLRES *)read_vol_list->binary_search(&vol, read_compare);
177    free(vol.vol_name);
178    if (fvol) {
179       Dmsg3(dbglvl, "remove_read_vol=%s JobId=%d found=%d\n", VolumeName, jcr->JobId, fvol!=NULL);
180    }
181    if (fvol) {
182       read_vol_list->remove(fvol);
183       free_vol_item(fvol);
184    }
185    unlock_read_volumes();
186 }
187
188 /*
189  * List Volumes -- this should be moved to status.c
190  */
191 enum {
192    debug_lock = true,
193    debug_nolock = false
194 };
195
196 static void debug_list_volumes(const char *imsg)
197 {
198    VOLRES *vol;
199    POOL_MEM msg(PM_MESSAGE);
200
201    lock_volumes();
202    foreach_dlist(vol, vol_list) {
203       if (vol->dev) {
204          Mmsg(msg, "List %s: %s in_use=%d on device %s\n", imsg, 
205               vol->vol_name, vol->is_in_use(), vol->dev->print_name());
206       } else {
207          Mmsg(msg, "List %s: %s in_use=%d no dev\n", imsg, vol->vol_name, 
208               vol->is_in_use());
209       }
210       Dmsg1(dbglvl, "%s", msg.c_str());
211    }
212
213    unlock_volumes();
214 }
215
216
217 /*
218  * List Volumes -- this should be moved to status.c
219  */
220 void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
221 {
222    VOLRES *vol;
223    POOL_MEM msg(PM_MESSAGE);
224    int len;
225
226    lock_volumes();
227    foreach_dlist(vol, vol_list) {
228       DEVICE *dev = vol->dev;
229       if (dev) {
230          len = Mmsg(msg, "%s on device %s\n", vol->vol_name, dev->print_name());
231          sendit(msg.c_str(), len, arg);
232          len = Mmsg(msg, "    Reader=%d writers=%d devres=%d volinuse=%d\n", 
233             dev->can_read()?1:0, dev->num_writers, dev->num_reserved(),   
234             vol->is_in_use());
235          sendit(msg.c_str(), len, arg);
236       } else {
237          len = Mmsg(msg, "%s no device. volinuse= %d\n", vol->vol_name, 
238             vol->is_in_use());
239          sendit(msg.c_str(), len, arg);
240       }
241    }
242    unlock_volumes();
243
244    lock_read_volumes();
245    foreach_dlist(vol, read_vol_list) {
246       len = Mmsg(msg, "%s read volume JobId=%d\n", vol->vol_name, 
247             vol->get_jobid());
248       sendit(msg.c_str(), len, arg);
249    }
250    unlock_read_volumes();
251
252 }
253
254 /*
255  * Create a Volume item to put in the Volume list
256  *   Ensure that the device points to it.
257  */
258 static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName)
259 {
260    VOLRES *vol;
261    vol = (VOLRES *)malloc(sizeof(VOLRES));
262    memset(vol, 0, sizeof(VOLRES));
263    vol->vol_name = bstrdup(VolumeName);
264    if (dcr) {
265       vol->dev = dcr->dev;
266       Dmsg3(dbglvl, "new Vol=%s at %p dev=%s\n",
267             VolumeName, vol->vol_name, vol->dev->print_name());
268    }
269    return vol;
270 }
271
272 static void free_vol_item(VOLRES *vol)
273 {
274    DEVICE *dev = NULL;
275
276    free(vol->vol_name);
277    if (vol->dev) {
278       dev = vol->dev;
279    }
280    free(vol);
281    if (dev) {
282       dev->vol = NULL;
283    }
284 }
285
286 /*
287  * Put a new Volume entry in the Volume list. This
288  *  effectively reserves the volume so that it will
289  *  not be mounted again.
290  *
291  * If the device has any current volume associated with it,
292  *  and it is a different Volume, and the device is not busy,
293  *  we release the old Volume item and insert the new one.
294  * 
295  * It is assumed that the device is free and locked so that
296  *  we can change the device structure.
297  *
298  * Some details of the Volume list handling:
299  *
300  *  1. The Volume list entry must be attached to the drive (rather than 
301  *       attached to a job as it currently is. I.e. the drive that "owns" 
302  *       the volume (in use, mounted)
303  *       must point to the volume (still to be maintained in a list).
304  *
305  *  2. The Volume is entered in the list when a drive is reserved.  
306  *
307  *  3. When a drive is in use, the device code must appropriately update the
308  *      volume name as it changes (currently the list is static -- an entry is
309  *      removed when the Volume is no longer reserved, in use or mounted).  
310  *      The new code must keep the same list entry as long as the drive
311  *       has any volume associated with it but the volume name in the list
312  *       must be updated when the drive has a different volume mounted.
313  *
314  *  4. A job that has reserved a volume, can un-reserve the volume, and if the 
315  *      volume is not mounted, and not reserved, and not in use, it will be
316  *      removed from the list.
317  *
318  *  5. If a job wants to reserve a drive with a different Volume from the one on
319  *      the drive, it can re-use the drive for the new Volume.
320  *
321  *  6. If a job wants a Volume that is in a different drive, it can either use the
322  *      other drive or take the volume, only if the other drive is not in use or
323  *      not reserved.
324  *
325  *  One nice aspect of this is that the reserve use count and the writer use count 
326  *  already exist and are correctly programmed and will need no changes -- use 
327  *  counts are always very tricky.
328  *
329  *  The old code had a concept of "reserving" a Volume, but was changed 
330  *  to reserving and using a drive.  A volume is must be attached to (owned by) a 
331  *  drive and can move from drive to drive or be unused given certain specific 
332  *  conditions of the drive.  The key is that the drive must "own" the Volume.  
333  *  The old code had the job (dcr) owning the volume (more or less).  The job was
334  *  to change the insertion and removal of the volumes from the list to be based 
335  *  on the drive rather than the job.  
336  *
337  *  Return: VOLRES entry on success
338  *          NULL volume busy on another drive
339  */
340 VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
341 {
342    VOLRES *vol, *nvol;
343    DEVICE * volatile dev = dcr->dev;
344
345    if (job_canceled(dcr->jcr)) {
346       return NULL;
347    }
348    ASSERT(dev != NULL);
349
350    Dmsg2(dbglvl, "enter reserve_volume=%s drive=%s\n", VolumeName, 
351       dcr->dev->print_name());
352    /* 
353     * We lock the reservations system here to ensure
354     *  when adding a new volume that no newly scheduled
355     *  job can reserve it.
356     */
357    lock_volumes();
358    debug_list_volumes("begin reserve_volume");
359    /* 
360     * First, remove any old volume attached to this device as it
361     *  is no longer used.
362     */
363    if (dev->vol) {
364       vol = dev->vol;
365       Dmsg4(dbglvl, "Vol attached=%s, newvol=%s volinuse=%d on %s\n",
366          vol->vol_name, VolumeName, vol->is_in_use(), dev->print_name());
367       /*
368        * Make sure we don't remove the current volume we are inserting
369        *  because it was probably inserted by another job, or it
370        *  is not being used and is marked as not reserved.
371        */
372       if (strcmp(vol->vol_name, VolumeName) == 0) {
373          Dmsg2(dbglvl, "=== set reserved vol=%s dev=%s\n", VolumeName,
374                vol->dev->print_name());
375          goto get_out;                  /* Volume already on this device */
376       } else {
377          /* Don't release a volume if it was reserved by someone other than us */
378          if (vol->is_in_use() && !dcr->reserved_volume) { 
379             Dmsg1(dbglvl, "Cannot free vol=%s. It is reserved.\n", vol->vol_name);
380             vol = NULL;                  /* vol in use */
381             goto get_out;
382          }
383          Dmsg2(dbglvl, "reserve_vol free vol=%s at %p\n", vol->vol_name, vol->vol_name);
384          /* If old Volume is still mounted, must unload it */
385          if (strcmp(vol->vol_name, dev->VolHdr.VolumeName) == 0) {
386             Dmsg0(50, "set_unload\n");
387             dev->set_unload();          /* have to unload current volume */
388          }
389          free_volume(dev);              /* Release old volume entry */
390          debug_list_volumes("reserve_vol free");
391       }
392    }
393
394    /* Create a new Volume entry */
395    nvol = new_vol_item(dcr, VolumeName);
396
397    /*
398     * Now try to insert the new Volume
399     */
400    vol = (VOLRES *)vol_list->binary_insert(nvol, my_compare);
401    if (vol != nvol) {
402       Dmsg2(dbglvl, "Found vol=%s dev-same=%d\n", vol->vol_name, dev==vol->dev);
403       /*
404        * At this point, a Volume with this name already is in the list,
405        *   so we simply release our new Volume entry. Note, this should
406        *   only happen if we are moving the volume from one drive to another.
407        */
408       Dmsg2(dbglvl, "reserve_vol free-tmp vol=%s at %p\n", 
409             vol->vol_name, vol->vol_name);
410       /*
411        * Clear dev pointer so that free_vol_item() doesn't 
412        *  take away our volume. 
413        */
414       nvol->dev = NULL;                  /* don't zap dev entry */
415       free_vol_item(nvol);
416
417       if (vol->dev) {
418          Dmsg2(dbglvl, "dev=%s vol->dev=%s\n", dev->print_name(), vol->dev->print_name());
419       }
420          
421       /*
422        * Check if we are trying to use the Volume on a different drive
423        *  dev      is our device
424        *  vol->dev is where the Volume we want is
425        */
426       if (dev != vol->dev) {
427          /* Caller wants to switch Volume to another device */
428          if (!vol->dev->is_busy() && !vol->is_swapping()) {
429             int32_t slot;
430             Dmsg3(dbglvl, "==== Swap vol=%s from dev=%s to %s\n", 
431                VolumeName, vol->dev->print_name(), dev->print_name());
432             free_volume(dev);            /* free any volume attached to our drive */
433             Dmsg0(50, "set_unload\n");
434             dev->set_unload();           /* Unload any volume that is on our drive */
435             dcr->dev = vol->dev;         /* temp point to other dev */
436             slot = get_autochanger_loaded_slot(dcr);  /* get slot on other drive */
437             dcr->dev = dev;              /* restore dev */
438             vol->set_slot(slot);         /* save slot */
439             vol->dev->set_unload();      /* unload the other drive */
440             vol->set_swapping();         /* swap from other drive */
441             dev->swap_dev = vol->dev;    /* remember to get this vol */
442             dev->set_load();             /* then reload on our drive */
443             vol->dev->vol = NULL;        /* remove volume from other drive */
444             vol->dev = dev;              /* point the Volume at our drive */
445             dev->vol = vol;              /* point our drive at the Volume */
446          } else {
447             Dmsg5(dbglvl, "==== Swap not possible Vol busy=%d swap=%d vol=%s from dev=%s to %s\n", 
448                vol->dev->is_busy(), vol->is_swapping(),
449                VolumeName, vol->dev->print_name(), dev->print_name());
450             if (vol->is_swapping() && dev->swap_dev) {
451                Dmsg2(dbglvl, "Swap vol=%s dev=%s\n", vol->vol_name, dev->swap_dev->print_name());
452             } else {
453                Dmsg1(dbglvl, "swap_dev=%p\n", dev->swap_dev);
454             }
455             debug_list_volumes("failed swap");
456             vol = NULL;                  /* device busy */
457             goto get_out;
458          }
459       } else {
460          dev->vol = vol;
461       }
462    } else {
463       dev->vol = vol;                    /* point to newly inserted volume */
464    }
465
466 get_out:
467    if (vol) {
468       Dmsg2(dbglvl, "=== set in_use. vol=%s dev=%s\n", vol->vol_name,
469             vol->dev->print_name());
470       vol->set_in_use();
471       dcr->reserved_volume = true;
472       bstrncpy(dcr->VolumeName, vol->vol_name, sizeof(dcr->VolumeName));
473    }
474    debug_list_volumes("end new volume");
475    unlock_volumes();
476    return vol;
477 }
478
479 /* 
480  * Switch from current device to given device  
481  *   (not yet used) 
482  */
483 #ifdef xxx
484 void switch_device(DCR *dcr, DEVICE *dev)
485 {
486    DCR save_dcr;
487
488    dev->dlock();
489    memcpy(&save_dcr, dcr, sizeof(save_dcr));
490    clean_device(dcr);                  /* clean up the dcr */
491
492    dcr->dev = dev;                     /* get new device pointer */
493    Jmsg(dcr->jcr, M_INFO, 0, _("Device switch. New device %s chosen.\n"),
494       dcr->dev->print_name());
495
496    bstrncpy(dcr->VolumeName, save_dcr.VolumeName, sizeof(dcr->VolumeName));
497    bstrncpy(dcr->media_type, save_dcr.media_type, sizeof(dcr->media_type));
498    dcr->VolCatInfo.Slot = save_dcr.VolCatInfo.Slot;
499    bstrncpy(dcr->pool_name, save_dcr.pool_name, sizeof(dcr->pool_name));
500    bstrncpy(dcr->pool_type, save_dcr.pool_type, sizeof(dcr->pool_type));
501    bstrncpy(dcr->dev_name, dev->dev_name, sizeof(dcr->dev_name));
502
503 // dcr->set_reserved();
504
505    dev->dunlock();
506 }
507 #endif
508
509 /*
510  * Search for a Volume name in the Volume list.
511  *
512  *  Returns: VOLRES entry on success
513  *           NULL if the Volume is not in the list
514  */
515 VOLRES *find_volume(const char *VolumeName) 
516 {
517    VOLRES vol, *fvol;
518
519    if (vol_list->empty()) {
520       return NULL;
521    }
522    /* Do not lock reservations here */
523    lock_volumes();
524    vol.vol_name = bstrdup(VolumeName);
525    fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
526    free(vol.vol_name);
527    Dmsg2(dbglvl, "find_vol=%s found=%d\n", VolumeName, fvol!=NULL);
528    debug_list_volumes("find_volume");
529    unlock_volumes();
530    return fvol;
531 }
532
533 /*
534  * Search for a Volume name in the read Volume list.
535  *
536  *  Returns: VOLRES entry on success
537  *           NULL if the Volume is not in the list
538  */
539 static VOLRES *find_read_volume(const char *VolumeName) 
540 {
541    VOLRES vol, *fvol;
542
543    if (read_vol_list->empty()) {
544       Dmsg0(dbglvl, "find_read_vol: read_vol_list empty.\n");
545       return NULL;
546    }
547    /* Do not lock reservations here */
548    lock_read_volumes();
549    vol.vol_name = bstrdup(VolumeName);
550    /* Note, we do want a simple my_compare on volume name only here */
551    fvol = (VOLRES *)read_vol_list->binary_search(&vol, my_compare);
552    free(vol.vol_name);
553    Dmsg2(dbglvl, "find_read_vol=%s found=%d\n", VolumeName, fvol!=NULL);
554    unlock_read_volumes();
555    return fvol;
556 }
557
558
559 /*  
560  * Free a Volume from the Volume list if it is no longer used
561  *   Note, for tape drives we want to remember where the Volume
562  *   was when last used, so rather than free the volume entry,
563  *   we simply mark it "not reserved" so when the drive is really
564  *   needed for another volume, we can reuse it.
565  *
566  *  Returns: true if the Volume found and "removed" from the list
567  *           false if the Volume is not in the list or is in use
568  */
569 bool volume_unused(DCR *dcr)
570 {
571    DEVICE *dev = dcr->dev;
572
573    if (!dev->vol) {
574       Dmsg1(dbglvl, "vol_unused: no vol on %s\n", dev->print_name());
575       debug_list_volumes("null vol cannot unreserve_volume");
576       return false;
577    }
578    if (dev->vol->is_swapping()) {
579       Dmsg1(dbglvl, "vol_unused: vol being swapped on %s\n", dev->print_name());
580       Dmsg1(dbglvl, "=== clear in_use vol=%s\n", dev->vol->vol_name);
581       dev->vol->clear_in_use();
582       debug_list_volumes("swapping vol cannot free_volume");
583       return false;
584    }
585
586    /*  
587     * If this is a tape, we do not free the volume, rather we wait
588     *  until the autoloader unloads it, or until another tape is
589     *  explicitly read in this drive. This allows the SD to remember
590     *  where the tapes are or last were.
591     */
592    Dmsg4(dbglvl, "=== set not reserved vol=%s num_writers=%d dev_reserved=%d dev=%s\n",
593       dev->vol->vol_name, dev->num_writers, dev->num_reserved(), dev->print_name());
594    Dmsg1(dbglvl, "=== clear in_use vol=%s\n", dev->vol->vol_name);
595    dev->vol->clear_in_use();
596    if (dev->is_tape() || dev->is_autochanger()) {
597       return true;
598    } else {
599       /*
600        * Note, this frees the volume reservation entry, but the 
601        *   file descriptor remains open with the OS.
602        */
603       return free_volume(dev);
604    }
605 }
606
607 /*
608  * Unconditionally release the volume entry
609  */
610 bool free_volume(DEVICE *dev)
611 {
612    VOLRES *vol;
613
614    if (dev->vol == NULL) {
615       Dmsg1(dbglvl, "No vol on dev %s\n", dev->print_name());
616       return false;
617    }
618    lock_volumes();
619    vol = dev->vol;
620    /* Don't free a volume while it is being swapped */
621    if (!vol->is_swapping()) {
622       Dmsg1(dbglvl, "=== clear in_use vol=%s\n", vol->vol_name);
623       dev->vol = NULL;
624       vol_list->remove(vol);
625       Dmsg2(dbglvl, "=== remove volume %s dev=%s\n", vol->vol_name, dev->print_name());
626       free_vol_item(vol);
627       debug_list_volumes("free_volume");
628    } else {
629       Dmsg1(dbglvl, "=== cannot clear swapping vol=%s\n", vol->vol_name);
630    }
631    unlock_volumes();
632    return true;
633 }
634
635       
636 /* Create the Volume list */
637 void create_volume_lists()
638 {
639    VOLRES *vol = NULL;
640    if (vol_list == NULL) {
641       vol_list = New(dlist(vol, &vol->link));
642    }
643    if (read_vol_list == NULL) {
644       read_vol_list = New(dlist(vol, &vol->link));
645    }
646 }
647
648 /*
649  * Free normal append volumes list
650  */
651 static void free_volume_list()
652 {
653    VOLRES *vol;
654    if (vol_list) {
655       lock_volumes();
656       foreach_dlist(vol, vol_list) {
657          if (vol->dev) {
658             Dmsg2(dbglvl, "free vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
659          } else {
660             Dmsg1(dbglvl, "free vol_list Volume=%s No dev\n", vol->vol_name);
661          }
662          free(vol->vol_name);
663          vol->vol_name = NULL;
664       }
665       delete vol_list;
666       vol_list = NULL;
667       unlock_volumes();
668    }
669 }
670
671 /* Release all Volumes from the list */
672 void free_volume_lists()
673 {
674    VOLRES *vol;
675
676    free_volume_list();           /* normal append list */
677
678    if (read_vol_list) {
679       lock_read_volumes();
680       foreach_dlist(vol, read_vol_list) {
681          if (vol->dev) {
682             Dmsg2(dbglvl, "free read_vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name());
683          } else {
684             Dmsg1(dbglvl, "free read_vol_list Volume=%s No dev\n", vol->vol_name);
685          }
686          free(vol->vol_name);
687          vol->vol_name = NULL;
688       }
689       delete read_vol_list;
690       read_vol_list = NULL;
691       unlock_read_volumes();
692    }
693 }
694
695 /* 
696  * Determine if caller can write on volume
697  */
698 bool DCR::can_i_write_volume()
699 {
700    VOLRES *vol;
701
702    vol = find_read_volume(VolumeName);
703    if (vol) {
704       Dmsg1(100, "Found in read list; cannot write vol=%s\n", VolumeName);
705       return false;
706    }
707    return can_i_use_volume();
708 }
709
710 /*
711  * Determine if caller can read or write volume
712  */
713 bool DCR::can_i_use_volume()
714 {
715    bool rtn = true;
716    VOLRES *vol;
717
718    if (job_canceled(jcr)) {
719       return false;
720    }
721    lock_volumes();
722    vol = find_volume(VolumeName);
723    if (!vol) {
724       Dmsg1(dbglvl, "Vol=%s not in use.\n", VolumeName);
725       goto get_out;                   /* vol not in list */
726    }
727    ASSERT(vol->dev != NULL);
728
729    if (dev == vol->dev) {        /* same device OK */
730       Dmsg1(dbglvl, "Vol=%s on same dev.\n", VolumeName);
731       goto get_out;
732    } else {
733       Dmsg3(dbglvl, "Vol=%s on %s we have %s\n", VolumeName,
734             vol->dev->print_name(), dev->print_name());
735    }
736    /* ***FIXME*** check this ... */
737    if (!vol->dev->is_busy()) {
738       Dmsg2(dbglvl, "Vol=%s dev=%s not busy.\n", VolumeName, vol->dev->print_name());
739       goto get_out;
740    } else {
741       Dmsg2(dbglvl, "Vol=%s dev=%s busy.\n", VolumeName, vol->dev->print_name());
742    }
743    Dmsg2(dbglvl, "Vol=%s in use by %s.\n", VolumeName, vol->dev->print_name());
744    rtn = false;
745
746 get_out:
747    unlock_volumes();
748    return rtn;
749
750 }
751
752 /*  
753  * Create a temporary copy of the volume list.  We do this,
754  *   to avoid having the volume list locked during the
755  *   call to reserve_device(), which would cause a deadlock.
756  * Note, we may want to add an update counter on the vol_list
757  *   so that if it is modified while we are traversing the copy
758  *   we can take note and act accordingly (probably redo the 
759  *   search at least a few times).
760  */
761 dlist *dup_vol_list(JCR *jcr)
762 {
763    dlist *temp_vol_list;
764    VOLRES *vol = NULL;
765
766    lock_volumes();
767    Dmsg0(dbglvl, "lock volumes\n");                           
768
769    Dmsg0(dbglvl, "duplicate vol list\n");
770    temp_vol_list = New(dlist(vol, &vol->link));
771    foreach_dlist(vol, vol_list) {
772       VOLRES *nvol;
773       VOLRES *tvol = (VOLRES *)malloc(sizeof(VOLRES));
774       memset(tvol, 0, sizeof(VOLRES));
775       tvol->vol_name = bstrdup(vol->vol_name);
776       tvol->dev = vol->dev;
777       nvol = (VOLRES *)temp_vol_list->binary_insert(tvol, my_compare);
778       if (tvol != nvol) {
779          tvol->dev = NULL;                   /* don't zap dev entry */
780          free_vol_item(tvol);
781          Pmsg0(000, "Logic error. Duplicating vol list hit duplicate.\n");
782          Jmsg(jcr, M_WARNING, 0, "Logic error. Duplicating vol list hit duplicate.\n");
783       }
784    }
785    Dmsg0(dbglvl, "unlock volumes\n");
786    unlock_volumes();
787    return temp_vol_list;
788 }
789
790 /*
791  * Free the specified temp list.
792  */
793 void free_temp_vol_list(dlist *temp_vol_list)
794 {
795    dlist *save_vol_list;
796    
797    lock_volumes();
798    save_vol_list = vol_list;
799    vol_list = temp_vol_list;
800    free_volume_list();                  /* release temp_vol_list */
801    vol_list = save_vol_list;
802    Dmsg0(dbglvl, "deleted temp vol list\n");
803    Dmsg0(dbglvl, "unlock volumes\n");
804    unlock_volumes();
805    debug_list_volumes("after free temp table");
806 }