* 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);