]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/vol_mgr.c
Backport from Bacula Enterprise
[bacula/bacula] / bacula / src / stored / vol_mgr.c
index f3e28e7b6b87d2d240619a719adae63881c4bc5e..0b7115473c95db6dcb28c12a837ee1d555a74f07 100644 (file)
@@ -1,29 +1,21 @@
 /*
-   Bacula® - The Network Backup Solution
-
-   Copyright (C) 2000-2013 Free Software Foundation Europe e.V.
-
-   The main author of Bacula is Kern Sibbald, with contributions from
-   many others, a complete list can be found in the file AUTHORS.
-   This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version three of the GNU Affero General Public
-   License as published by the Free Software Foundation and included
-   in the file LICENSE.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU Affero General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-   Bacula® is a registered trademark of Kern Sibbald.
-   The licensor of Bacula is the Free Software Foundation Europe
-   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
-   Switzerland, email:ftf@fsfeurope.org.
+   Bacula(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2015 Kern Sibbald
+   Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
+
+   The original author of Bacula is Kern Sibbald, with contributions
+   from many others, a complete list can be found in the file AUTHORS.
+
+   You may use this file and others of this release according to the
+   license defined in the LICENSE file, which includes the Affero General
+   Public License, v3.0 ("AGPLv3") and some additional permissions and
+   terms pursuant to its AGPLv3 Section 7.
+
+   This notice must be preserved when any source code is 
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
 */
 /*
  *   Volume management functions for Storage Daemon
@@ -52,7 +44,7 @@ static void debug_list_volumes(const char *imsg);
 /*
  * For append volumes the key is the VolumeName.
  */
-static int my_compare(void *item1, void *item2)
+static int name_compare(void *item1, void *item2)
 {
    return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
 }
@@ -74,8 +66,7 @@ static int read_compare(void *item1, void *item2)
    return 1;
 }
 
-
-bool is_vol_list_empty() 
+bool is_vol_list_empty()
 {
    return vol_list->empty();
 }
@@ -125,12 +116,13 @@ void _unlock_volumes()
    }
 }
 
-void lock_read_volumes(const char *file="**Unknown", int line=0)
+#define lock_read_volumes() lock_read_volumes_p(__FILE__, __LINE__)
+static void lock_read_volumes_p(const char *file="**Unknown", int line=0)
 {
    bthread_mutex_lock_p(&read_vol_lock, file, line);
 }
 
-void unlock_read_volumes()
+static void unlock_read_volumes()
 {
    bthread_mutex_unlock(&read_vol_lock);
 }
@@ -140,7 +132,7 @@ void unlock_read_volumes()
  * Note, we use VOLRES because it simplifies the code
  *   even though, the only part of VOLRES that we need is
  *   the volume name.  The same volume may be in the list
- *   multiple times, but each one is distinguished by the 
+ *   multiple times, but each one is distinguished by the
  *   JobId.  We use JobId, VolumeName as the key.
  * We can get called multiple times for the same volume because
  *   when parsing the bsr, the volume name appears multiple times.
@@ -151,15 +143,30 @@ void add_read_volume(JCR *jcr, const char *VolumeName)
 
    nvol = new_vol_item(NULL, VolumeName);
    nvol->set_jobid(jcr->JobId);
+   nvol->set_reading();
    lock_read_volumes();
    vol = (VOLRES *)read_vol_list->binary_insert(nvol, read_compare);
-   unlock_read_volumes();
    if (vol != nvol) {
       free_vol_item(nvol);
       Dmsg2(dbglvl, "read_vol=%s JobId=%d already in list.\n", VolumeName, jcr->JobId);
    } else {
       Dmsg2(dbglvl, "add read_vol=%s JobId=%d\n", VolumeName, jcr->JobId);
    }
+   unlock_read_volumes();
+}
+
+/*
+ * Check if volume name is in the read list.
+ */
+bool is_read_volume(JCR *jcr, const char *VolumeName)
+{
+   VOLRES vol, *fvol;
+   lock_read_volumes();
+   vol.vol_name = bstrdup(VolumeName);
+   fvol = (VOLRES *)read_vol_list->binary_search(&vol, name_compare);
+   free(vol.vol_name);
+   unlock_read_volumes();
+   return fvol != NULL;
 }
 
 /*
@@ -197,12 +204,17 @@ static void debug_list_volumes(const char *imsg)
    VOLRES *vol;
    POOL_MEM msg(PM_MESSAGE);
 
+   if (debug_level < dbglvl) {
+      return;
+   }
+
    foreach_vol(vol) {
       if (vol->dev) {
-         Mmsg(msg, "List %s: %s in_use=%d swap=%d on device %s\n", imsg, 
-              vol->vol_name, vol->is_in_use(), vol->is_swapping(), vol->dev->print_name());
+         Mmsg(msg, "List %s: %s in_use=%d swap=%d on %s device %s\n", imsg,
+              vol->vol_name, vol->is_in_use(), vol->is_swapping(),
+              vol->dev->print_type(), vol->dev->print_name());
       } else {
-         Mmsg(msg, "List %s: %s in_use=%d swap=%d no dev\n", imsg, vol->vol_name, 
+         Mmsg(msg, "List %s: %s in_use=%d swap=%d no dev\n", imsg, vol->vol_name,
               vol->is_in_use(), vol->is_swapping());
       }
       Dmsg1(dbglvl, "%s", msg.c_str());
@@ -223,14 +235,15 @@ void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
    foreach_vol(vol) {
       DEVICE *dev = vol->dev;
       if (dev) {
-         len = Mmsg(msg, "%s on device %s\n", vol->vol_name, dev->print_name());
+         len = Mmsg(msg, "Reserved volume: %s on %s device %s\n", vol->vol_name,
+                  dev->print_type(), dev->print_name());
          sendit(msg.c_str(), len, arg);
          len = Mmsg(msg, "    Reader=%d writers=%d reserves=%d volinuse=%d\n",
             dev->can_read()?1:0, dev->num_writers, dev->num_reserved(),
             vol->is_in_use());
          sendit(msg.c_str(), len, arg);
       } else {
-         len = Mmsg(msg, "Volume %s no device. volinuse= %d\n", vol->vol_name,
+         len = Mmsg(msg, "Volume %s no device. volinuse=%d\n", vol->vol_name,
             vol->is_in_use());
          sendit(msg.c_str(), len, arg);
       }
@@ -241,14 +254,15 @@ void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
    foreach_dlist(vol, read_vol_list) {
       DEVICE *dev = vol->dev;
       if (dev) {
-         len = Mmsg(msg, "Read volume: %s on device %s\n", vol->vol_name, dev->print_name());
+         len = Mmsg(msg, "Read volume: %s on %s device %s\n", vol->vol_name,
+                  dev->print_type(), dev->print_name());
          sendit(msg.c_str(), len, arg);
          len = Mmsg(msg, "    Reader=%d writers=%d reserves=%d volinuse=%d JobId=%d\n",
             dev->can_read()?1:0, dev->num_writers, dev->num_reserved(),
             vol->is_in_use(), vol->get_jobid());
          sendit(msg.c_str(), len, arg);
       } else {
-         len = Mmsg(msg, "Volume: %s no device. volinuse= %d\n", vol->vol_name,
+         len = Mmsg(msg, "Volume: %s no device. volinuse=%d\n", vol->vol_name,
             vol->is_in_use());
          sendit(msg.c_str(), len, arg);
       }
@@ -281,12 +295,12 @@ static void free_vol_item(VOLRES *vol)
    DEVICE *dev = NULL;
 
    vol->dec_use_count();
-   vol->Lock();
+   vol->vLock();
    if (vol->use_count() > 0) {
-      vol->Unlock();
+      vol->vUnlock();
       return;
    }
-   vol->Unlock();
+   vol->vUnlock();
    free(vol->vol_name);
    if (vol->dev) {
       dev = vol->dev;
@@ -306,7 +320,7 @@ static void free_vol_item(VOLRES *vol)
  * If the device has any current volume associated with it,
  *  and it is a different Volume, and the device is not busy,
  *  we release the old Volume item and insert the new one.
- * 
+ *
  * It is assumed that the device is free and locked so that
  *  we can change the device structure.
  *
@@ -347,20 +361,32 @@ static void free_vol_item(VOLRES *vol)
  *
  *  Return: VOLRES entry on success
  *          NULL volume busy on another drive
+ *               jcr->errmsg has details
  */
 VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
 {
    VOLRES *vol, *nvol;
    DEVICE * volatile dev = dcr->dev;
+   JCR *jcr = dcr->jcr;
 
+   jcr->errmsg[0] = 0;
    if (job_canceled(dcr->jcr)) {
+      Mmsg1(jcr->errmsg, _("Could not reserve volume \"%s\", because job canceled.\n"),
+         dev->VolHdr.VolumeName);
       return NULL;
    }
-   ASSERT(dev != NULL);
+   ASSERT2(dev != NULL, "No device in reserve_volume!");
 
    Dmsg2(dbglvl, "enter reserve_volume=%s drive=%s\n", VolumeName,
       dcr->dev->print_name());
 
+   /* If acquiring to write, don't accept a Volume in read list */
+   if (dcr->is_writing() && is_read_volume(dcr->jcr, VolumeName)) {
+      Mmsg1(jcr->errmsg, _("Could not reserve volume \"%s\" for append, because it will be read.\n"),
+         dev->VolHdr.VolumeName);
+      return NULL;
+   }
+
    /*
     * We lock the reservations system here to ensure
     *  when adding a new volume that no newly scheduled
@@ -382,13 +408,16 @@ VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
        *  is not being used and is marked as not reserved.
        */
       if (strcmp(vol->vol_name, VolumeName) == 0) {
-         Dmsg2(dbglvl, "=== set reserved vol=%s dev=%s\n", VolumeName,
+         Dmsg2(dbglvl, "set reserved vol=%s dev=%s\n", VolumeName,
                vol->dev->print_name());
          goto get_out;                  /* Volume already on this device */
       } else {
          /* Don't release a volume if it was reserved by someone other than us */
-         if (vol->is_in_use() && !dcr->reserved_volume) { 
-            Dmsg1(dbglvl, "Cannot free vol=%s. It is reserved.\n", vol->vol_name);
+         if (vol->is_in_use() && !dcr->reserved_volume) {
+            Dmsg2(dbglvl, "Set wait(). Cannot free vol=%s for %s. It is reserved.\n", vol->vol_name, VolumeName);
+            Mmsg1(dcr->jcr->errmsg, _("Cannot free Volume \"%s\", because it is reserved by someone else.\n"),
+               vol->vol_name);
+            dev->set_wait();
             vol = NULL;                  /* vol in use */
             goto get_out;
          }
@@ -407,21 +436,40 @@ VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
    nvol = new_vol_item(dcr, VolumeName);
 
    /*
-    * Now try to insert the new Volume
+    * Handle request for read volume for file
+    *  device, for which we assume we can open multiple
+    *  devices to read the Volume.
+    *
+    * Note: when doing multiple simultaneous reads
+    *  of the same volume, the volume names are not
+    *  inserted into the write volume list.
+    */
+   if (dcr->is_reading() && dev->is_file()) {
+      nvol->set_jobid(dcr->jcr->JobId);
+      nvol->set_reading();
+      vol = nvol;
+      dev->vol = vol;
+      goto get_out;
+   } else {
+      vol = (VOLRES *)vol_list->binary_insert(nvol, name_compare);
+   }
+
+   /*
+    * This part handles any write volumes or read volumes that
+    *  cannot be simultaneously on multiple devices.
     */
-   vol = (VOLRES *)vol_list->binary_insert(nvol, my_compare);
    if (vol != nvol) {
-      Dmsg2(dbglvl, "Found vol=%s dev-same=%d\n", vol->vol_name, dev==vol->dev);
       /*
        * At this point, a Volume with this name already is in the list,
        *   so we simply release our new Volume entry. Note, this should
        *   only happen if we are moving the volume from one drive to another.
        */
-      Dmsg2(dbglvl, "reserve_vol free-tmp vol=%s at %p\n", 
+      Dmsg2(dbglvl, "Found vol=%s dev-same=%d\n", vol->vol_name, dev==vol->dev);
+      Dmsg2(dbglvl, "reserve_vol free-tmp vol=%s at %p\n",
             vol->vol_name, vol->vol_name);
       /*
-       * Clear dev pointer so that free_vol_item() doesn't 
-       *  take away our volume. 
+       * Clear dev pointer so that free_vol_item() doesn't
+       *  take away our volume.
        */
       nvol->dev = NULL;                  /* don't zap dev entry */
       free_vol_item(nvol);
@@ -439,7 +487,7 @@ VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
          /* Caller wants to switch Volume to another device */
          if (!vol->dev->is_busy() && !vol->is_swapping()) {
             int32_t slot;
-            Dmsg3(dbglvl, "==== Swap vol=%s from dev=%s to %s\n", 
+            Dmsg3(dbglvl, "==== Swap vol=%s from dev=%s to %s\n",
                VolumeName, vol->dev->print_name(), dev->print_name());
             free_volume(dev);            /* free any volume attached to our drive */
             Dmsg1(50, "set_unload dev=%s\n", dev->print_name());
@@ -456,18 +504,30 @@ VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
             vol->dev = dev;              /* point the Volume at our drive */
             dev->vol = vol;              /* point our drive at the Volume */
          } else {
-            Jmsg7(dcr->jcr, M_WARNING, 0, "Need volume from other drive, "
-               "but swap not possible. Status: read=%d num_writers=%d "
-               "num_reserve=%d swap=%d vol=%s from dev=%s to %s\n", 
-               vol->dev->can_read(), vol->dev->num_writers,
-               vol->dev->num_reserved(), vol->is_swapping(),
-               VolumeName, vol->dev->print_name(), dev->print_name());
-            if (vol->is_swapping() && dev->swap_dev) {
-               Dmsg3(dbglvl, "Swap failed vol=%s from=%s to dev=%s\n", 
-                 vol->vol_name, dev->swap_dev->print_name(), dev->print_name());
+            if (dev) {
+               Jmsg8(jcr, M_WARNING, 0, "Need volume for %s from other drive, "
+                  "but swap not possible. Status: reader=%d writers=%d "
+                  "reserves=%d swap=%d vol=%s from dev=%s to %s\n",
+                  dcr->is_writing()?"write":"read",
+                  vol->dev->can_read(), vol->dev->num_writers,
+                  vol->dev->num_reserved(), vol->is_swapping(),
+                  VolumeName, vol->dev->print_name(), dev->print_name());
+            }
+            if (vol->is_swapping()) {
+               DEVICE *swapdev = dev->swap_dev;
+               if (vol && dev && swapdev) {
+                  Mmsg3(jcr->errmsg, _("Volume %s is busy swapping from %s to %s\n"),
+                     NPRT(vol->vol_name), dev->print_name(), swapdev->print_name());
+               } else {
+                  Mmsg1(jcr->errmsg, _("Volume %s is busy swapping.\n"),
+                     NPRT(vol->vol_name));
+               }
+            } else if (vol->dev) {
+               Mmsg2(jcr->errmsg, _("%s device %s is busy.\n"),
+                  vol->dev->print_type(), vol->dev->print_name());
             } else {
-               Dmsg3(dbglvl, "Swap failed vol=%s from=%p to dev=%s\n", 
-                  vol->vol_name, dev->swap_dev, dev->print_name());
+               Mmsg1(jcr->errmsg, _("Volume %s is busy swapping.\n"),
+                  NPRT(vol->vol_name));
             }
             debug_list_volumes("failed swap");
             vol = NULL;                  /* device busy */
@@ -482,7 +542,7 @@ VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
 
 get_out:
    if (vol) {
-      Dmsg2(dbglvl, "=== set in_use. vol=%s dev=%s\n", vol->vol_name,
+      Dmsg2(dbglvl, "set in_use. vol=%s dev=%s\n", vol->vol_name,
             vol->dev->print_name());
       vol->set_in_use();
       dcr->reserved_volume = true;
@@ -537,10 +597,10 @@ VOLRES *vol_walk_next(VOLRES *prev_vol)
       Dmsg2(dbglvl, "Inc walk_next use_count=%d volname=%s\n",
             vol->use_count(), vol->vol_name);
    }
-   unlock_volumes();
    if (prev_vol) {
       free_vol_item(prev_vol);
    }
+   unlock_volumes();
    return vol;
 }
 
@@ -550,9 +610,11 @@ VOLRES *vol_walk_next(VOLRES *prev_vol)
 void vol_walk_end(VOLRES *vol)
 {
    if (vol) {
+      lock_volumes();
       Dmsg2(dbglvl, "Free walk_end use_count=%d volname=%s\n",
             vol->use_count(), vol->vol_name);
       free_vol_item(vol);
+      unlock_volumes();
    }
 }
 
@@ -562,7 +624,7 @@ void vol_walk_end(VOLRES *vol)
  *  Returns: VOLRES entry on success
  *           NULL if the Volume is not in the list
  */
-VOLRES *find_volume(const char *VolumeName) 
+static VOLRES *find_volume(const char *VolumeName)
 {
    VOLRES vol, *fvol;
 
@@ -572,7 +634,7 @@ VOLRES *find_volume(const char *VolumeName)
    /* Do not lock reservations here */
    lock_volumes();
    vol.vol_name = bstrdup(VolumeName);
-   fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
+   fvol = (VOLRES *)vol_list->binary_search(&vol, name_compare);
    free(vol.vol_name);
    Dmsg2(dbglvl, "find_vol=%s found=%d\n", VolumeName, fvol!=NULL);
    debug_list_volumes("find_volume");
@@ -586,7 +648,7 @@ VOLRES *find_volume(const char *VolumeName)
  *  Returns: VOLRES entry on success
  *           NULL if the Volume is not in the list
  */
-static VOLRES *find_read_volume(const char *VolumeName) 
+static VOLRES *find_read_volume(const char *VolumeName)
 {
    VOLRES vol, *fvol;
 
@@ -597,8 +659,8 @@ static VOLRES *find_read_volume(const char *VolumeName)
    /* Do not lock reservations here */
    lock_read_volumes();
    vol.vol_name = bstrdup(VolumeName);
-   /* Note, we do want a simple my_compare on volume name only here */
-   fvol = (VOLRES *)read_vol_list->binary_search(&vol, my_compare);
+   /* Note, we do want a simple name_compare on volume name only here */
+   fvol = (VOLRES *)read_vol_list->binary_search(&vol, name_compare);
    free(vol.vol_name);
    Dmsg2(dbglvl, "find_read_vol=%s found=%d\n", VolumeName, fvol!=NULL);
    unlock_read_volumes();
@@ -626,7 +688,7 @@ bool volume_unused(DCR *dcr)
       return false;
    }
 
-   Dmsg1(dbglvl, "=== clear in_use vol=%s\n", dev->vol->vol_name);
+   Dmsg1(dbglvl, "Clear in_use vol=%s\n", dev->vol->vol_name);
    dev->vol->clear_in_use();
 
    if (dev->vol->is_swapping()) {
@@ -641,7 +703,7 @@ bool volume_unused(DCR *dcr)
     *  explicitly read in this drive. This allows the SD to remember
     *  where the tapes are or last were.
     */
-   Dmsg4(dbglvl, "=== set not reserved vol=%s num_writers=%d dev_reserved=%d dev=%s\n",
+   Dmsg4(dbglvl, "set not reserved vol=%s writers=%d reserves=%d dev=%s\n",
       dev->vol->vol_name, dev->num_writers, dev->num_reserved(), dev->print_name());
    if (dev->is_tape() || dev->is_autochanger()) {
       return true;
@@ -656,6 +718,8 @@ bool volume_unused(DCR *dcr)
 
 /*
  * Unconditionally release the volume entry
+ * Note: read volumes are not in the list, so
+ *   do not attempt to remove them.
  */
 bool free_volume(DEVICE *dev)
 {
@@ -670,21 +734,22 @@ bool free_volume(DEVICE *dev)
    }
    /* Don't free a volume while it is being swapped */
    if (!vol->is_swapping()) {
-      Dmsg1(dbglvl, "=== clear in_use vol=%s\n", vol->vol_name);
+      Dmsg1(dbglvl, "Clear in_use vol=%s\n", vol->vol_name);
       dev->vol = NULL;
-      vol_list->remove(vol);
-      Dmsg2(dbglvl, "=== remove volume %s dev=%s\n", vol->vol_name, dev->print_name());
+      if (vol->is_writing()) {
+         vol_list->remove(vol);
+      }
+      Dmsg2(dbglvl, "Remove volume %s dev=%s\n", vol->vol_name, dev->print_name());
       free_vol_item(vol);
       debug_list_volumes("free_volume");
    } else {
-      Dmsg1(dbglvl, "=== cannot clear swapping vol=%s\n", vol->vol_name);
+      Dmsg1(dbglvl, "=== Cannot clear. Swapping vol=%s\n", vol->vol_name);
    }
    unlock_volumes();
-// pthread_cond_broadcast(&wait_next_vol);
    return true;
 }
 
-      
+
 /* Create the Volume list */
 void create_volume_lists()
 {
@@ -746,8 +811,9 @@ void free_volume_lists()
    }
 }
 
-/* 
- * Determine if caller can write on volume
+/*
+ * Determine if caller can write on volume.
+ *  If not, return reason in jcr->errmsg
  */
 bool DCR::can_i_write_volume()
 {
@@ -755,6 +821,7 @@ bool DCR::can_i_write_volume()
 
    vol = find_read_volume(VolumeName);
    if (vol) {
+      Mmsg(jcr->errmsg, "Found in read list; cannot write vol=%s\n", VolumeName);
       Dmsg1(100, "Found in read list; cannot write vol=%s\n", VolumeName);
       return false;
    }
@@ -762,7 +829,8 @@ bool DCR::can_i_write_volume()
 }
 
 /*
- * Determine if caller can read or write volume
+ * Determine if caller can read or write volume.
+ *  If not, return reason in jcr->errmsg
  */
 bool DCR::can_i_use_volume()
 {
@@ -770,6 +838,7 @@ bool DCR::can_i_use_volume()
    VOLRES *vol;
 
    if (job_canceled(jcr)) {
+      Mmsg(jcr->errmsg, "Job is canceled\n");
       return false;
    }
    lock_volumes();
@@ -778,7 +847,7 @@ bool DCR::can_i_use_volume()
       Dmsg1(dbglvl, "Vol=%s not in use.\n", VolumeName);
       goto get_out;                   /* vol not in list */
    }
-   ASSERT(vol->dev != NULL);
+   ASSERT2(vol->dev != NULL, "No device in can_i_use_volume!");
 
    if (dev == vol->dev) {        /* same device OK */
       Dmsg1(dbglvl, "Vol=%s on same dev.\n", VolumeName);
@@ -794,7 +863,8 @@ bool DCR::can_i_use_volume()
    } else {
       Dmsg2(dbglvl, "Vol=%s dev=%s busy.\n", VolumeName, vol->dev->print_name());
    }
-   Dmsg2(dbglvl, "Vol=%s in use by %s.\n", VolumeName, vol->dev->print_name());
+   Mmsg(jcr->errmsg, "Volume=%s in use on another device %s.\n", VolumeName, vol->dev->print_name());
+   Dmsg2(dbglvl, "Volume=%s in use on another device %s.\n", VolumeName, vol->dev->print_name());
    rtn = false;
 
 get_out:
@@ -827,7 +897,7 @@ dlist *dup_vol_list(JCR *jcr)
       memset(tvol, 0, sizeof(VOLRES));
       tvol->vol_name = bstrdup(vol->vol_name);
       tvol->dev = vol->dev;
-      nvol = (VOLRES *)temp_vol_list->binary_insert(tvol, my_compare);
+      nvol = (VOLRES *)temp_vol_list->binary_insert(tvol, name_compare);
       if (tvol != nvol) {
          tvol->dev = NULL;                   /* don't zap dev entry */
          free_vol_item(tvol);