#include "bacula.h" /* pull in global headers */
#include "stored.h" /* pull in Storage Deamon headers */
+static int can_reserve_drive(DCR *dcr);
+
/*
* Create a new Device Control Record and attach
* it to the device (if this is a real job).
dcr->max_spool_size = dev->device->max_spool_size;
/* Attach this dcr only if dev is initialized */
if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
- dev->attached_dcrs->append(dcr);
-// jcr->dcrs->append(dcr);
+ dev->attached_dcrs->append(dcr); /* attach dcr to device */
+// jcr->dcrs->append(dcr); /* put dcr in list for Job */
}
return dcr;
}
/* Detach this dcr only if the dev is initialized */
if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
- dev->attached_dcrs->remove(dcr);
-// remove_dcr_from_dcrs(dcr);
+ dev->attached_dcrs->remove(dcr); /* detach dcr from device */
+// remove_dcr_from_dcrs(dcr); /* remove dcr from jcr list */
}
if (dcr->block) {
free_block(dcr->block);
* starting the job. If the device is not available, the DIR
* can wait (to be implemented 1/05).
*/
-bool reserve_device_for_read(JCR *jcr, DEVICE *dev)
+bool reserve_device_for_read(DCR *dcr)
{
- DCR *dcr = jcr->dcr;
- bool ok = false;
+ DEVICE *dev = dcr->dev;
+ JCR *jcr = dcr->jcr;
+ bool first;
ASSERT(dcr);
- if (device_is_unmounted(dev)) {
- Jmsg(jcr, M_WARNING, 0, _("device %s is BLOCKED due to user unmount.\n"),
- dev_name(dev));
- return false;
- }
- lock_device(dev);
- block_device(dev, BST_DOING_ACQUIRE);
- unlock_device(dev);
- if (dev->is_busy()) {
- Jmsg2(jcr, M_FATAL, 0, _("Device %s is busy. Job %d canceled.\n"),
- dev->name(), jcr->JobId);
- goto get_out;
+ dev->block(BST_DOING_ACQUIRE);
+
+ Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"),
+ dev->print_name());
+ for (first=true; device_is_unmounted(dev); first=false) {
+ dev->unblock();
+ if (!wait_for_device(dcr, jcr->errmsg, first)) {
+ return false;
+ }
+ dev->block(BST_DOING_ACQUIRE);
}
- if (!dcr) {
- dcr = new_dcr(jcr, dev);
+
+ Mmsg2(jcr->errmsg, _("Device %s is busy. Job %d canceled.\n"),
+ dev->print_name(), jcr->JobId);
+ for (first=true; dev->is_busy(); first=false) {
+ dev->unblock();
+ if (!wait_for_device(dcr, jcr->errmsg, first)) {
+ return false;
+ }
+ dev->block(BST_DOING_ACQUIRE);
}
+
dev->clear_append();
dev->set_read();
- ok = true;
-
-get_out:
- P(dev->mutex);
- unblock_device(dev);
- V(dev->mutex);
- return ok;
+ dev->unblock();
+ return true;
}
* Returns: NULL if failed for any reason
* dcr if successful
*/
-DCR *acquire_device_for_read(JCR *jcr, DEVICE *dev)
+DCR *acquire_device_for_read(DCR *dcr)
{
+ DEVICE *dev = dcr->dev;
+ JCR *jcr = dcr->jcr;
bool vol_ok = false;
bool tape_previously_mounted;
bool tape_initially_mounted;
VOL_LIST *vol;
bool try_autochanger = true;
int i;
- DCR *dcr = jcr->dcr;
int vol_label_status;
- lock_device(dev);
- block_device(dev, BST_DOING_ACQUIRE);
- unlock_device(dev);
-
- init_dev_wait_timers(dev);
-
- tape_previously_mounted = dev->can_read() ||
- dev->can_append() ||
- dev->is_labeled();
- tape_initially_mounted = tape_previously_mounted;
+ dev->block(BST_DOING_ACQUIRE);
if (dev->num_writers > 0) {
Jmsg2(jcr, M_FATAL, 0, _("Num_writers=%d not zero. Job %d canceled.\n"),
for (i=1; i<jcr->CurVolume; i++) {
vol = vol->next;
}
+ if (!vol) {
+ goto get_out; /* should not happen */
+ }
bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
+ init_device_wait_timers(dcr);
+
+ tape_previously_mounted = dev->can_read() ||
+ dev->can_append() ||
+ dev->is_labeled();
+ tape_initially_mounted = tape_previously_mounted;
+
+
/* Volume info is always needed because of VolParts */
Dmsg0(200, "dir_get_volume_info\n");
if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
dev->num_parts = dcr->VolCatInfo.VolCatParts;
for (i=0; i<5; i++) {
- dev->clear_label(); /* force reread of label */
+ dev->clear_labeled(); /* force reread of label */
if (job_canceled(jcr)) {
Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
goto get_out; /* error return */
Dmsg1(120, "bstored: open vol=%s\n", dcr->VolumeName);
if (open_dev(dev, dcr->VolumeName, OPEN_READ_ONLY) < 0) {
if (dev->dev_errno == EIO) { /* no tape loaded */
+ Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
+ dev->print_name(), dcr->VolumeName, strerror_dev(dev));
goto default_path;
}
break;
}
- Jmsg(jcr, M_FATAL, 0, _("Open device %s volume %s failed, ERR=%s\n"),
- dev_name(dev), dcr->VolumeName, strerror_dev(dev));
+ Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
+ dev->print_name(), dcr->VolumeName, strerror_dev(dev));
goto get_out;
}
- Dmsg1(129, "open_dev %s OK\n", dev_name(dev));
+ Dmsg1(129, "open_dev %s OK\n", dev->print_name());
}
if (dev->is_dvd()) {
vol_label_status = read_dev_volume_label(dcr);
}
- /****FIXME***** do not reread label if ioctl() says we are
- * correctly possitioned. Possibly have way user can turn
- * this optimization (to be implemented) off.
- */
Dmsg0(200, "calling read-vol-label\n");
switch (vol_label_status) {
case VOL_OK:
}
/* Fall through */
default:
- Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+ Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
default_path:
tape_previously_mounted = true;
stat = autoload_device(dcr, 0, NULL);
if (stat > 0) {
try_autochanger = false;
- continue;
+ continue; /* try reading volume mounted */
}
}
break;
} /* end for loop */
if (!vol_ok) {
- Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device \"%s\".\n"),
- dev_name(dev));
+ Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"),
+ dev->print_name());
goto get_out;
}
set_jcr_job_status(jcr, JS_Running);
dir_send_job_status(jcr);
Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
- dcr->VolumeName, dev_name(dev));
+ dcr->VolumeName, dev->print_name());
get_out:
- P(dev->mutex);
- unblock_device(dev);
- V(dev->mutex);
+ dev->unblock();
if (!vol_ok) {
free_dcr(dcr);
dcr = NULL;
* the first tor reserve the device, we put the pool
* name and pool type in the device record.
*/
-bool reserve_device_for_append(JCR *jcr, DEVICE *dev)
+bool reserve_device_for_append(DCR *dcr)
{
- DCR *dcr = jcr->dcr;
+ JCR *jcr = dcr->jcr;
+ DEVICE *dev = dcr->dev;
bool ok = false;
+ bool first;
ASSERT(dcr);
-
- lock_device(dev);
- block_device(dev, BST_DOING_ACQUIRE);
- unlock_device(dev);
- if (dev->can_read()) {
- Jmsg(jcr, M_WARNING, 0, _("Device %s is busy reading.\n"), dev->name());
- goto bail_out;
+ dev->block(BST_DOING_ACQUIRE);
+
+ Mmsg2(jcr->errmsg, _("Device %s is busy reading. Job %d canceled.\n"),
+ dev->print_name(), jcr->JobId);
+ for (first=true; dev->can_read(); first=false) {
+ dev->unblock();
+ if (!wait_for_device(dcr, jcr->errmsg, first)) {
+ return false;
+ }
+ dev->block(BST_DOING_ACQUIRE);
}
- if (device_is_unmounted(dev)) {
- Jmsg(jcr, M_WARNING, 0, _("device %s is BLOCKED due to user unmount.\n"),
- dev_name(dev));
- goto bail_out;
+
+
+ Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"),
+ dev->print_name());
+ for (first=true; device_is_unmounted(dev); first=false) {
+ dev->unblock();
+ if (!wait_for_device(dcr, jcr->errmsg, first)) {
+ return false;
+ }
+ dev->block(BST_DOING_ACQUIRE);
}
+
Dmsg1(190, "reserve_append device is %s\n", dev_is_tape(dev)?"tape":"disk");
+
+ for ( ;; ) {
+ switch (can_reserve_drive(dcr)) {
+ case 0:
+ /* ****FIXME**** Make wait */
+ goto bail_out;
+ case -1:
+ goto bail_out; /* error */
+ default:
+ break; /* OK, reserve drive */
+ }
+ break;
+ }
+
+
+ dev->reserved_device++;
+ dcr->reserved_device = true;
+ ok = true;
+
+bail_out:
+ dev->unblock();
+ return ok;
+}
+
+/*
+ * Returns: 1 if drive can be reserved
+ * 0 if we should wait
+ * -1 on error
+ */
+static int can_reserve_drive(DCR *dcr)
+{
+ DEVICE *dev = dcr->dev;
+ JCR *jcr = dcr->jcr;
/*
* First handle the case that the drive is not yet in append mode
*/
/* OK, compatible device */
} else {
/* Drive not suitable for us */
- Jmsg(jcr, M_WARNING, 0, _("Device %s is busy writing on another Volume.\n"), dev->name());
- goto bail_out;
+ Jmsg(jcr, M_WARNING, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
+ return 0; /* wait */
}
} else {
/* Device is available but not yet reserved, reserve it for us */
bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
dev->PoolId = dcr->PoolId;
}
- goto do_reserve;
+ return 1; /* reserve drive */
}
/*
/* OK, compatible device */
} else {
/* Drive not suitable for us */
- Jmsg(jcr, M_WARNING, 0, _("Device %s is busy writing on another Volume.\n"), dev->name());
- goto bail_out;
+ Jmsg(jcr, M_WARNING, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
+ return 0; /* wait */
}
} else {
Pmsg0(000, "Logic error!!!! Should not get here.\n");
- goto bail_out; /* should not get here */
+ Jmsg0(jcr, M_FATAL, 0, _("Logic error!!!! Should not get here.\n"));
+ return -1; /* error, should not get here */
}
-
-do_reserve:
- dev->reserved_device++;
- dcr->reserved_device = true;
- ok = true;
-
-bail_out:
- P(dev->mutex);
- unblock_device(dev);
- V(dev->mutex);
- return ok;
+ return 1; /* reserve drive */
}
/*
* Note, normally reserve_device_for_append() is called
* before this routine.
*/
-DCR *acquire_device_for_append(JCR *jcr, DEVICE *dev)
+DCR *acquire_device_for_append(DCR *dcr)
{
bool release = false;
bool recycle = false;
bool do_mount = false;
- DCR *dcr = jcr->dcr;
+ DEVICE *dev = dcr->dev;
+ JCR *jcr = dcr->jcr;
- if (!dcr) {
- dcr = new_dcr(jcr, dev);
- }
- lock_device(dev);
- block_device(dev, BST_DOING_ACQUIRE);
- unlock_device(dev);
+ dev->block(BST_DOING_ACQUIRE);
Dmsg1(190, "acquire_append device is %s\n", dev_is_tape(dev)?"tape":"disk");
if (dcr->reserved_device) {
* With the reservation system, this should not happen
*/
if (dev->can_read()) {
- Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev));
+ Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev->print_name());
goto get_out;
}
strcmp(dev->VolHdr.VolName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
Dmsg0(190, "Wrong tape mounted.\n");
if (dev->num_writers != 0 || dev->reserved_device) {
- Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev));
+ Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
goto get_out;
}
/* Wrong tape mounted, release it, then fall through to get correct one */
if (!mounted) {
if (!job_canceled(jcr)) {
/* Reduce "noise" -- don't print if job canceled */
- Jmsg(jcr, M_FATAL, 0, _("Could not ready device \"%s\" for append.\n"),
- dev_name(dev));
+ Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
+ dev->print_name());
}
goto get_out;
}
free_dcr(dcr);
dcr = NULL;
ok_out:
- P(dev->mutex);
- unblock_device(dev);
- V(dev->mutex);
+ dev->unblock();
return dcr;
}
*/
bool release_device(DCR *dcr)
{
+ bool ok = true;
JCR *jcr = dcr->jcr;
DEVICE *dev = dcr->dev;
+
lock_device(dev);
Dmsg1(100, "release_device device is %s\n", dev_is_tape(dev)?"tape":"disk");
if (dev->can_read()) {
dev->clear_read(); /* clear read bit */
- /* Close if file or !CAP_ALWAYSOPEN */
- if (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN)) {
- offline_or_rewind_dev(dev);
- close_dev(dev);
- }
+
/******FIXME**** send read volume usage statistics to director */
} else if (dev->num_writers > 0) {
if (!dir_create_jobmedia_record(dcr)) {
Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
dcr->VolCatInfo.VolCatName, jcr->Job);
+ ok = false;
}
/* If no more writers, write an EOF */
if (!dev->num_writers && dev_can_write(dev)) {
weof_dev(dev, 1);
+ write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolName);
}
dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */
dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */
/* Note! do volume update before close, which zaps VolCatInfo */
Dmsg0(100, "dir_update_vol_info. Release0\n");
dir_update_volume_info(dcr, false); /* send Volume info to Director */
+ Dmsg0(100, "==== write ansi eof label \n");
}
- /* If no writers, close if file or !CAP_ALWAYS_OPEN */
- if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
- offline_or_rewind_dev(dev);
- close_dev(dev);
- }
} else {
- Jmsg2(jcr, M_FATAL, 0, _("BAD ERROR: release_device %s, Volume \"%s\" not in use.\n"),
- dev_name(dev), NPRT(dcr->VolumeName));
- Jmsg2(jcr, M_ERROR, 0, _("num_writers=%d state=%x\n"), dev->num_writers, dev->state);
+ /*
+ * If we reach here, it is most likely because the
+ * has failed, since the device is not in read mode and
+ * there are no writers.
+ */
+ }
+
+ /* If no writers, close if file or !CAP_ALWAYS_OPEN */
+ if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
+ offline_or_rewind_dev(dev);
+ close_dev(dev);
}
/* Fire off Alert command and include any output */
unlock_device(dev);
free_dcr(dcr);
jcr->dcr = NULL;
- return true;
+ pthread_cond_broadcast(&wait_device_release);
+ return ok;
}