2 * Routines to acquire and release a device for read/write
4 * Kern Sibbald, August MMII
9 Copyright (C) 2002-2005 Kern Sibbald
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of
14 the License, or (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public
22 License along with this program; if not, write to the Free
23 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28 #include "bacula.h" /* pull in global headers */
29 #include "stored.h" /* pull in Storage Deamon headers */
32 * Create a new Device Control Record and attach
33 * it to the device (if this is a real job).
35 DCR *new_dcr(JCR *jcr, DEVICE *dev)
37 if (jcr && jcr->dcr) {
40 DCR *dcr = (DCR *)malloc(sizeof(DCR));
41 memset(dcr, 0, sizeof(DCR));
48 dcr->device = dev->device;
50 dcr->block = new_block(dev);
51 dcr->rec = new_record();
53 dcr->max_spool_size = dev->device->max_spool_size;
54 /* Attach this dcr only if dev is initialized */
55 if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
56 dev->attached_dcrs->append(dcr);
61 void free_dcr(DCR *dcr)
64 DEVICE *dev = dcr->dev;
67 * If we reserved the device, we must decrement the
70 if (dcr->reserved_device) {
76 /* Detach this dcr only if the dev is initialized */
77 if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
78 dcr->dev->attached_dcrs->remove(dcr);
81 free_block(dcr->block);
84 free_record(dcr->rec);
93 * We "reserve" the drive by setting the ST_READ bit. No one else
94 * should touch the drive until that is cleared.
95 * This allows the DIR to "reserve" the device before actually
96 * starting the job. If the device is not available, the DIR
97 * can wait (to be implemented 1/05).
99 bool reserve_device_for_read(JCR *jcr, DEVICE *dev)
105 if (device_is_unmounted(dev)) {
106 Jmsg(jcr, M_WARNING, 0, _("device %s is BLOCKED due to user unmount.\n"),
111 block_device(dev, BST_DOING_ACQUIRE);
114 if (dev->can_read() || dev->num_writers > 0) {
115 Jmsg2(jcr, M_FATAL, 0, _("Device %s is busy. Job %d canceled.\n"),
116 dev_name(dev), jcr->JobId);
120 dcr = new_dcr(jcr, dev);
122 dev->state &= ~ST_APPEND; /* clear any previous append mode */
123 dev->state |= ST_READ; /* set read mode */
134 /*********************************************************************
135 * Acquire device for reading.
136 * The drive should have previously been reserved by calling
137 * reserve_device_for_read(). We read the Volume label from the block and
138 * leave the block pointers just after the label.
140 * Returns: NULL if failed for any reason
143 DCR *acquire_device_for_read(JCR *jcr, DEVICE *dev)
146 bool tape_previously_mounted;
147 bool tape_initially_mounted;
149 bool try_autochanger = true;
152 int vol_label_status;
155 block_device(dev, BST_DOING_ACQUIRE);
158 init_dev_wait_timers(dev);
160 tape_previously_mounted = dev->can_read() ||
163 tape_initially_mounted = tape_previously_mounted;
165 /* Find next Volume, if any */
168 Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job %d canceled.\n"), jcr->JobId);
172 for (i=1; i<jcr->CurVolume; i++) {
175 bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
177 /* Volume info is always needed because of VolParts */
178 Dmsg0(200, "dir_get_volume_info\n");
179 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
180 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
183 dev->num_parts = dcr->VolCatInfo.VolCatParts;
185 for (i=0; i<5; i++) {
186 dev->state &= ~ST_LABEL; /* force reread of label */
187 if (job_canceled(jcr)) {
188 Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
189 goto get_out; /* error return */
192 * This code ensures that the device is ready for
193 * reading. If it is a file, it opens it.
194 * If it is a tape, it checks the volume name
196 for ( ; !dev->is_open(); ) {
197 Dmsg1(120, "bstored: open vol=%s\n", dcr->VolumeName);
198 if (open_dev(dev, dcr->VolumeName, OPEN_READ_ONLY) < 0) {
199 if (dev->dev_errno == EIO) { /* no tape loaded */
203 /* If we have a dvd that requires mount,
204 * we need to try to open the label, so the info can be reported
205 * if a wrong volume has been mounted. */
206 if (dev->is_dvd() && (dcr->VolCatInfo.VolCatParts > 0)) {
210 Jmsg(jcr, M_FATAL, 0, _("Open device %s volume %s failed, ERR=%s\n"),
211 dev_name(dev), dcr->VolumeName, strerror_dev(dev));
214 Dmsg1(129, "open_dev %s OK\n", dev_name(dev));
218 vol_label_status = read_dev_volume_label_guess(dcr, 0);
220 vol_label_status = read_dev_volume_label(dcr);
223 /****FIXME***** do not reread label if ioctl() says we are
224 * correctly possitioned. Possibly have way user can turn
225 * this optimization (to be implemented) off.
227 Dmsg0(200, "calling read-vol-label\n");
228 switch (vol_label_status) {
231 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
235 * Send error message generated by read_dev_volume_label()
236 * only we really had a tape mounted. This supresses superfluous
237 * error messages when nothing is mounted.
239 if (tape_previously_mounted) {
240 Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
244 if (tape_initially_mounted) {
245 tape_initially_mounted = false;
250 Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
252 tape_previously_mounted = true;
254 /* If the device requires mount, close it, so the device can be ejected.
255 * FIXME: This should perhaps be done for all devices. */
256 if (dev_cap(dev, CAP_REQMOUNT)) {
257 force_close_dev(dev);
260 /* Call autochanger only once unless ask_sysop called */
261 if (try_autochanger) {
263 Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
264 dcr->VolumeName, dcr->VolCatInfo.Slot);
265 stat = autoload_device(dcr, 0, NULL);
267 try_autochanger = false;
272 /* Mount a specific volume and no other */
273 Dmsg0(200, "calling dir_ask_sysop\n");
274 if (!dir_ask_sysop_to_mount_volume(dcr)) {
275 goto get_out; /* error return */
277 try_autochanger = true; /* permit using autochanger again */
278 continue; /* try reading again */
283 Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device \"%s\".\n"),
288 dev->state &= ~ST_APPEND; /* clear any previous append mode */
289 dev->num_writers = 0;
290 dev->state |= ST_READ; /* set read mode */
291 set_jcr_job_status(jcr, JS_Running);
292 dir_send_job_status(jcr);
293 Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
294 dcr->VolumeName, dev_name(dev));
308 * We reserve the device for appending by incrementing the
309 * reserved_device. We do virtually all the same work that
310 * is done in acquire_device_for_append(), but we do
311 * not attempt to mount the device. This routine allows
312 * the DIR to reserve multiple devices before *really*
313 * starting the job. It also permits the SD to refuse
314 * certain devices (not up, ...).
316 bool reserve_device_for_append(JCR *jcr, DEVICE *dev)
325 block_device(dev, BST_DOING_ACQUIRE);
327 if (device_is_unmounted(dev)) {
328 Jmsg(jcr, M_WARNING, 0, _("device %s is BLOCKED due to user unmount.\n"),
332 Dmsg1(190, "reserve_append device is %s\n", dev_is_tape(dev)?"tape":"disk");
333 if (dev->can_append() || dev->num_writers > 0) {
334 Dmsg0(190, "device already in append.\n");
336 * Device already in append mode
338 * Check if we have the right Volume mounted
339 * OK if current volume info OK
340 * OK if next volume matches current volume
342 bstrncpy(dcr->VolumeName, dev->VolHdr.VolName, sizeof(dcr->VolumeName));
343 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
344 !(dir_find_next_appendable_volume(dcr) &&
345 strcmp(dev->VolHdr.VolName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
346 Dmsg0(190, "Wrong tape mounted.\n");
347 if (dev->num_writers != 0 || dev->reserved_device) {
348 Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev));
353 * At this point, the correct tape is already mounted, so
354 * we do not need to do mount_next_write_volume(), unless
355 * we need to recycle the tape.
357 recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
358 Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
359 if (recycle && dev->num_writers != 0) {
360 Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
361 " because it is in use by another job.\n"));
364 if (dev->num_writers == 0) {
365 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
369 if (dev->can_read()) {
370 Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev));
373 ASSERT(dev->num_writers == 0);
376 dev->reserved_device++;
377 dcr->reserved_device = true;
388 * Acquire device for writing. We permit multiple writers.
389 * If this is the first one, we read the label.
391 * Returns: NULL if failed for any reason
393 * Note, normally reserve_device_for_append() is called
394 * before this routine.
396 DCR *acquire_device_for_append(JCR *jcr, DEVICE *dev)
398 bool release = false;
399 bool recycle = false;
400 bool do_mount = false;
404 dcr = new_dcr(jcr, dev);
407 block_device(dev, BST_DOING_ACQUIRE);
409 Dmsg1(190, "acquire_append device is %s\n", dev_is_tape(dev)?"tape":"disk");
411 if (dcr->reserved_device) {
412 dev->reserved_device--;
413 dcr->reserved_device = false;
415 if (dev->can_append()) {
416 Dmsg0(190, "device already in append.\n");
418 * Device already in append mode
420 * Check if we have the right Volume mounted
421 * OK if current volume info OK
422 * OK if next volume matches current volume
423 * otherwise mount desired volume obtained from
424 * dir_find_next_appendable_volume
426 bstrncpy(dcr->VolumeName, dev->VolHdr.VolName, sizeof(dcr->VolumeName));
427 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
428 !(dir_find_next_appendable_volume(dcr) &&
429 strcmp(dev->VolHdr.VolName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
430 Dmsg0(190, "Wrong tape mounted.\n");
431 if (dev->num_writers != 0 || dev->reserved_device) {
432 Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev));
435 /* Wrong tape mounted, release it, then fall through to get correct one */
436 Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
441 * At this point, the correct tape is already mounted, so
442 * we do not need to do mount_next_write_volume(), unless
443 * we need to recycle the tape.
445 recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
446 Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
447 if (recycle && dev->num_writers != 0) {
448 Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
449 " because it is in use by another job.\n"));
452 if (dev->num_writers == 0) {
453 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
457 /* Not already in append mode, so mount the device */
458 Dmsg0(190, "Not in append mode, try mount.\n");
459 if (dev->can_read()) {
460 Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev));
463 ASSERT(dev->num_writers == 0);
467 if (do_mount || recycle) {
468 Dmsg0(190, "Do mount_next_write_vol\n");
469 bool mounted = mount_next_write_volume(dcr, release);
471 if (!job_canceled(jcr)) {
472 /* Reduce "noise" -- don't print if job canceled */
473 Jmsg(jcr, M_FATAL, 0, _("Could not ready device \"%s\" for append.\n"),
481 if (jcr->NumVolumes == 0) {
487 * If we jump here, it is an error return because
488 * rtn_dev will still be NULL
501 * This job is done, so release the device. From a Unix standpoint,
502 * the device remains open.
505 bool release_device(JCR *jcr)
508 DEVICE *dev = dcr->dev;
510 Dmsg1(100, "release_device device is %s\n", dev_is_tape(dev)?"tape":"disk");
511 if (dev_state(dev, ST_READ)) {
512 dev->state &= ~ST_READ; /* clear read bit */
513 if (!dev_is_tape(dev) || !dev_cap(dev, CAP_ALWAYSOPEN)) {
514 offline_or_rewind_dev(dev);
517 /******FIXME**** send read volume usage statistics to director */
519 } else if (dev->num_writers > 0) {
521 Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
522 if (dev->is_labeled()) {
523 Dmsg0(100, "dir_create_jobmedia_record. Release\n");
524 if (!dir_create_jobmedia_record(dcr)) {
525 Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
526 dcr->VolCatInfo.VolCatName, jcr->Job);
528 /* If no more writers, write an EOF */
529 if (!dev->num_writers && dev_can_write(dev)) {
532 dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */
533 dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */
534 /* Note! do volume update before close, which zaps VolCatInfo */
535 Dmsg0(100, "dir_update_vol_info. Release0\n");
536 dir_update_volume_info(dcr, false); /* send Volume info to Director */
539 if (!dev->num_writers && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
540 offline_or_rewind_dev(dev);
544 Jmsg2(jcr, M_FATAL, 0, _("BAD ERROR: release_device %s, Volume \"%s\" not in use.\n"),
545 dev_name(dev), NPRT(dcr->VolumeName));
546 Jmsg2(jcr, M_ERROR, 0, _("num_writers=%d state=%x\n"), dev->num_writers, dev->state);
549 /* Fire off Alert command and include any output */
550 if (!job_canceled(jcr) && dcr->device->alert_command) {
554 char line[MAXSTRING];
555 alert = get_pool_memory(PM_FNAME);
556 alert = edit_device_codes(dcr, alert, "");
557 bpipe = open_bpipe(alert, 0, "r");
559 while (fgets(line, sizeof(line), bpipe->rfd)) {
560 Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
562 status = close_bpipe(bpipe);
568 Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
569 alert, be.strerror(status));
572 Dmsg1(400, "alert status=%d\n", status);
573 free_pool_memory(alert);