unlock_reservations();
       if (stat == 1) {
          DCR *ndcr = jcr->read_dcr;
-         dev->dunblock(dev_unlocked);
+         dev->dunblock(DEV_UNLOCKED);
          detach_dcr_from_dev(dcr);    /* release old device */
          /* Copy important info from the new dcr */
          dev = dcr->dev = ndcr->dev; 
       Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
       dcr->reserved_device = false;
    }
-   dev->dunblock(dev_locked);
+   dev->dunblock(DEV_LOCKED);
    Dmsg1(50, "jcr->dcr=%p\n", jcr->dcr);
    return ok;
 }
       Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
       dcr->reserved_device = false;
    }
-   dev->dunblock(dev_locked);
+   dev->dunblock(DEV_LOCKED);
    return dcr;
 
 /*
       Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
       dcr->reserved_device = false;
    }
-   dev->dunblock(dev_locked);
+   dev->dunblock(DEV_LOCKED);
    return NULL;
 }
 
    bool ok = true;
 
    /* lock only if not already locked by this thread */
-   if (!dcr->dev_locked) {
+   if (!dcr->is_dev_locked()) {
       dev->r_dlock();
    }
    Dmsg2(100, "release_device device %s is %s\n", dev->print_name(), dev->is_tape()?"tape":"disk");
 
       return stat;
    }
 
-   if (!dcr->dev_locked) {            /* device already locked? */
+   if (!dcr->is_dev_locked()) {        /* device already locked? */
+      /* note, do not change this to dcr->r_dlock */
       dev->r_dlock();                  /* no, lock it */
    }
 
    }
 
 bail_out:
-   if (!dcr->dev_locked) {            /* did we lock dev above? */
+   if (!dcr->is_dev_locked()) {        /* did we lock dev above? */
+      /* note, do not change this to dcr->dunlock */
       dev->dunlock();                  /* unlock it now */
    }
    return stat;
 
    bool spooling;                     /* set when actually spooling */
    bool despooling;                   /* set when despooling */
    bool despool_wait;                 /* waiting for despooling */
-   bool dev_locked;                   /* set if dev already locked */
+   bool m_dev_locked;                 /* set if dev already locked */
    bool NewVol;                       /* set if new Volume mounted */
    bool WroteVol;                     /* set if Volume written */
    bool NewFile;                      /* set when EOF written */
    int Copy;                          /* identical copy number */
    int Stripe;                        /* RAIT stripe */
    VOLUME_CAT_INFO VolCatInfo;        /* Catalog info for desired volume */
+
+   /* Methods */
+   bool is_dev_locked() { return m_dev_locked; }
+   void dlock() { dev->dlock(); m_dev_locked = true; }
+   void dunlock() { dev->dunlock(); m_dev_locked = false;}
+   void dblock(int why) { dev->dblock(why); }
+
 };
 
 /*
 
    char dt[MAX_TIME_LENGTH];
    JCR *jcr = dcr->jcr;
    DEVICE *dev = dcr->dev;
+   int blocked = dev->blocked();         /* save any previous blocked status */
+   bool ok = false;
 
    wait_time = time(NULL);
 
    Dmsg0(100, "Enter fixup_device_block_write_error\n");
 
+   /*
+    * If we are blocked at entry, unblock it, and set our own block status
+    */
+   if (blocked != BST_NOT_BLOCKED) {
+      unblock_device(dev);
+   }
    block_device(dev, BST_DOING_ACQUIRE);
-   /* Unlock, but leave BLOCKED */
+
+   /* Continue unlocked, but leave BLOCKED */
    dev->dunlock();
 
    bstrncpy(PrevVolName, dev->VolCatInfo.VolCatName, sizeof(PrevVolName));
       free_block(label_blk);
       dcr->block = block;
       dev->dlock();  
-      unblock_device(dev);
-      return false;                /* device locked */
+      goto bail_out;
    }
    dev->dlock();                    /* lock again */
 
         be.bstrerror(dev->dev_errno));
       free_block(label_blk);
       dcr->block = block;
-      unblock_device(dev);
-      return false;                /* device locked */
+      goto bail_out;
    }
    free_block(label_blk);
    dcr->block = block;
       berrno be;
       Pmsg1(0, _("write_block_to_device overflow block failed. ERR=%s"),
         be.bstrerror(dev->dev_errno));
-      unblock_device(dev);
-      return false;                /* device locked */
+      goto bail_out;
    }
+   ok = true;
 
+bail_out:
+   /*
+    * At this point, the device is locked and blocked.
+    * Unblock the device, restore any entry blocked condition, then
+    *   return leaving the device locked (as it was on entry).
+    */
    unblock_device(dev);
-   return true;                             /* device locked */
+   if (blocked != BST_NOT_BLOCKED) {
+      block_device(dev, blocked);
+   }
+   return ok;                               /* device locked */
 }
 
 /*
 
  * Used in unblock() call
  */
 enum {
-   dev_locked = true,
-   dev_unlocked = false
+   DEV_LOCKED = true,
+   DEV_UNLOCKED = false
 };
 
 #endif
 
    }
    dcr->despool_wait = true;
    dcr->spooling = false;
-   dcr->dev->r_dlock();
+   /*
+    * We work with device blocked, but not locked so that
+    *  other threads -- e.g. reservations can lock the device
+    *  structure.
+    */
+   dcr->dblock(BST_DESPOOLING);
    dcr->despool_wait = false;
    dcr->despooling = true;
-   dcr->dev_locked = true;
 
    /*
     * This is really quite kludgy and should be fixed some time.
    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).
+    */
+   dcr->dlock();
+   unblock_device(dcr->dev);
    /* If doing a commit, leave the device locked -- unlocked in release_device() */
    if (!commit) {
-      dcr->dev_locked = false;
-      dcr->dev->dunlock();
+      dcr->dunlock();
    }
    return ok;
 }
 
 
 #undef  VERSION
 #define VERSION "2.1.23"
-#define BDATE   "28 June 2007"
-#define LSMDATE "28Jun07"
+#define BDATE   "29 June 2007"
+#define LSMDATE "29Jun07"
 
 #define PROG_COPYRIGHT "Copyright (C) %d-2007 Free Software Foundation Europe e.V.\n"
 #define BYEAR "2007"       /* year for copyright messages in progs */
 
               Technical notes on version 2.1
 
 General:
-
+29Jun07
+kes  Implement new BST_DESPOOLING blocked state. Change from locking
+     during despooling in SD to blocking. This means that other threads
+     can work with the device structure, in particular the reservations
+     system while despooling.
+28Jun07
+kes  Fix return in reservation message queue that missed clearing
+     the jcr lock (implemented 26Jun07 below).
+kes  Rename a number of dev methods to make locking function names
+     a bit clearer.
+kes  Document locking in lock.c. Move lock structures to new file
+     lock.h.
 26Jun07
 kes  Move reservations message lock to lock jcr only this
      fixes bug #861.