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