* This job is done, so release the device. From a Unix standpoint,
  *  the device remains open.
  *
- * Note, if we are spooling, we may enter with the device locked.
- * However, in all cases, unlock the device when leaving.
+ * Note, if we are spooling, we may enter with the device blocked.
+ * However, in all cases, unblock the device when leaving.
  *
  */
 bool release_device(DCR *dcr)
    bool ok = true;
    char tbuf[100];
 
-   /* lock only if not already locked by this thread */
-   if (!dcr->is_dev_locked()) {
-      dev->r_dlock();
-   }
    lock_volumes();
+   dev->dlock();
+   if (!dev->is_blocked()) {
+      block_device(dev, BST_RELEASING);
+   } else if (dev->blocked() == BST_DESPOOLING) {
+      dev->set_blocked(BST_RELEASING);
+   }
    Dmsg2(100, "release_device device %s is %s\n", dev->print_name(), dev->is_tape()?"tape":"disk");
 
    /* if device is reserved, job never started, so release the reserve here */
        */
       volume_unused(dcr);
    }
-   unlock_volumes();
    Dmsg3(100, "%d writers, %d reserve, dev=%s\n", dev->num_writers, dev->num_reserved(),
          dev->print_name());
 
-
    /* If no writers, close if file or !CAP_ALWAYS_OPEN */
    if (dev->num_writers == 0 && (!dev->is_tape() || !dev->has_cap(CAP_ALWAYSOPEN))) {
       dvd_remove_empty_part(dcr);        /* get rid of any empty spool part */
    Dmsg2(100, "JobId=%u broadcast wait_device_release at %s\n", 
          (uint32_t)jcr->JobId, bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL)));
    pthread_cond_broadcast(&wait_device_release);
-   dev->dunlock();
+   dev->dunblock(true);
+   unlock_volumes();
    if (dcr->keep_dcr) {
       detach_dcr_from_dev(dcr);
    } else {
 
    if (!ok) {
       discard_data_spool(dcr);
    } else {
-      /* Note: if commit is OK, the device will remain locked */
+      /* Note: if commit is OK, the device will remain blocked */
       commit_data_spool(dcr);
    }
 
 
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2009 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.
       return "BST_MOUNT";
    case BST_DESPOOLING:
       return "BST_DESPOOLING";
+   case BST_RELEASING:
+      return "BST_RELEASING";
    default:
       return _("unknown blocked code");
    }
 
    BST_WRITING_LABEL,                 /* Labeling a tape */
    BST_UNMOUNTED_WAITING_FOR_SYSOP,   /* User unmounted during wait for op */
    BST_MOUNT,                         /* Mount request */
-   BST_DESPOOLING                     /* Despooling -- i.e. multiple writes */
+   BST_DESPOOLING,                    /* Despooling -- i.e. multiple writes */
+   BST_RELEASING                      /* Releasing the device */
 };
 
 typedef struct s_steal_lock {
 
       if (!ok) {
          discard_data_spool(jcr->dcr);
       } else {
-         /* Note: if commit is OK, the device will remain locked */
+         /* Note: if commit is OK, the device will remain blocked */
          commit_data_spool(jcr->dcr);
       }
 
 
  * This routine is meant to be called once the first pass
  *   to ensure that we have a candidate volume to mount.
  *   Otherwise, we ask the sysop to created one.
+ * Note, the the Volumes are locked on entry.
+ *   They are unlocked on failure and remain locked on
+ *   success.  The caller must know this!!!
  */
 bool DCR::find_a_volume()  
 {
 
    free(rdev);
    dcr->spooling = true;           /* turn on spooling again */
    dcr->despooling = false;
-
-   /* 
-    * We are done, so unblock the device, but if we have done a 
-    *  commit, leave it locked so that the job cleanup does not
-    *  need to wait to release the device (no re-acquire of the lock).
+   /*
+    * Note, if committing we leave the device blocked. It will be removed in
+    *  release_device();
     */
-   dcr->dlock();
-   unblock_device(dcr->dev);
-   /* If doing a commit, leave the device locked -- unlocked in release_device() */
    if (!commit) {
-      dcr->dunlock();
+      dcr->dev->dunblock();
    }
    set_jcr_job_status(jcr, JS_Running);
    dir_send_job_status(jcr);