2 * Routines to acquire and release a device for read/write
4 * Kern Sibbald, August MMII
9 Copyright (C) 2002-2006 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
13 version 2 as amended with additional clauses defined in the
14 file LICENSE in the main source directory.
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
19 the file LICENSE for additional details.
23 #include "bacula.h" /* pull in global headers */
24 #include "stored.h" /* pull in Storage Deamon headers */
26 /* Forward referenced functions */
27 static void detach_dcr_from_dev(DCR *dcr);
30 /*********************************************************************
31 * Acquire device for reading.
32 * The drive should have previously been reserved by calling
33 * reserve_device_for_read(). We read the Volume label from the block and
34 * leave the block pointers just after the label.
36 * Returns: NULL if failed for any reason
39 bool acquire_device_for_read(DCR *dcr)
41 DEVICE *dev = dcr->dev;
44 bool tape_previously_mounted;
45 bool tape_initially_mounted;
47 bool try_autochanger = true;
52 Dmsg1(50, "jcr->dcr=%p\n", jcr->dcr);
53 dev->block(BST_DOING_ACQUIRE);
55 if (dev->num_writers > 0) {
56 Jmsg2(jcr, M_FATAL, 0, _("Num_writers=%d not zero. Job %d canceled.\n"),
57 dev->num_writers, jcr->JobId);
61 /* Find next Volume, if any */
64 Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job %d canceled.\n"), jcr->JobId);
68 for (i=1; i<jcr->CurVolume; i++) {
72 goto get_out; /* should not happen */
74 bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
75 bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type));
76 dcr->VolCatInfo.Slot = vol->Slot;
79 * If the MediaType requested for this volume is not the
80 * same as the current drive, we attempt to find the same
81 * device that was used to write the orginal volume. If
82 * found, we switch to using that device.
84 Dmsg2(100, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
85 if (dcr->media_type[0] && strcmp(dcr->media_type, dev->device->media_type) != 0) {
89 DCR *dcr_save = jcr->dcr;
93 memset(&rctx, 0, sizeof(RCTX));
95 jcr->reserve_msgs = New(alist(10, not_owned_by_alist));
96 rctx.any_drive = true;
97 rctx.device_name = vol->device;
99 memset(store, 0, sizeof(DIRSTORE));
100 store->name[0] = 0; /* No dir name */
101 bstrncpy(store->media_type, vol->MediaType, sizeof(store->media_type));
102 bstrncpy(store->pool_name, dcr->pool_name, sizeof(store->pool_name));
103 bstrncpy(store->pool_type, dcr->pool_type, sizeof(store->pool_type));
104 store->append = false;
108 * Note, if search_for_device() succeeds, we get a new_dcr,
109 * which we do not use except for the dev info.
111 stat = search_res_for_device(rctx);
112 release_msgs(jcr); /* release queued messages */
113 unlock_reservations();
115 DCR *new_dcr = jcr->read_dcr;
117 detach_dcr_from_dev(dcr); /* release old device */
118 /* Copy important info from the new dcr */
119 dev = dcr->dev = new_dcr->dev;
121 dcr->device = new_dcr->device;
122 dcr->max_job_spool_size = dcr->device->max_job_spool_size;
123 if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
124 dev->attached_dcrs->append(dcr); /* attach dcr to device */
126 new_dcr->VolumeName[0] = 0;
128 dev->block(BST_DOING_ACQUIRE);
129 Jmsg(jcr, M_INFO, 0, _("Media Type change. New device %s chosen.\n"),
131 bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
132 bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type));
133 dcr->VolCatInfo.Slot = vol->Slot;
134 bstrncpy(dcr->pool_name, store->pool_name, sizeof(dcr->pool_name));
135 bstrncpy(dcr->pool_type, store->pool_type, sizeof(dcr->pool_type));
136 } else if (stat == 0) { /* device busy */
137 Dmsg1(000, "Device %s is busy.\n", vol->device);
140 Jmsg1(jcr, M_FATAL, 0, _("No suitable device found to read Volume \"%s\"\n"),
149 init_device_wait_timers(dcr);
151 tape_previously_mounted = dev->can_read() || dev->can_append() ||
153 tape_initially_mounted = tape_previously_mounted;
156 /* Volume info is always needed because of VolParts */
157 Dmsg0(200, "dir_get_volume_info\n");
158 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
159 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
163 /* If not polling limit retries */
164 if (!dev->poll && retry++ > 10) {
167 dev->clear_labeled(); /* force reread of label */
168 if (job_canceled(jcr)) {
169 Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
170 goto get_out; /* error return */
173 * This code ensures that the device is ready for
174 * reading. If it is a file, it opens it.
175 * If it is a tape, it checks the volume name
177 Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName);
178 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
179 if (dev->dev_errno == EIO) { /* no tape loaded */
180 Jmsg3(jcr, M_WARNING, 0, _("Read open device %s Volume \"%s\" failed (EIO): ERR=%s\n"),
181 dev->print_name(), dcr->VolumeName, dev->bstrerror());
185 Jmsg3(jcr, M_FATAL, 0, _("Read open device %s Volume \"%s\" failed: ERR=%s\n"),
186 dev->print_name(), dcr->VolumeName, dev->bstrerror());
189 Dmsg1(100, "opened dev %s OK\n", dev->print_name());
191 /* Read Volume Label */
193 Dmsg0(200, "calling read-vol-label\n");
194 vol_label_status = read_dev_volume_label(dcr);
195 switch (vol_label_status) {
198 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
202 * Send error message generated by read_dev_volume_label()
203 * only we really had a tape mounted. This supresses superfluous
204 * error messages when nothing is mounted.
206 if (tape_previously_mounted) {
207 Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
211 if (tape_initially_mounted) {
212 tape_initially_mounted = false;
215 /* If polling and got a previous bad name, ignore it */
216 if (dev->poll && strcmp(dev->BadVolName, dev->VolHdr.VolumeName) == 0) {
219 bstrncpy(dev->BadVolName, dev->VolHdr.VolumeName, sizeof(dev->BadVolName));
223 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
225 tape_previously_mounted = true;
228 * If the device requires mount, close it, so the device can be ejected.
230 if (dev->requires_mount()) {
234 /* Call autochanger only once unless ask_sysop called */
235 if (try_autochanger) {
237 Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
238 dcr->VolumeName, dcr->VolCatInfo.Slot);
239 stat = autoload_device(dcr, 0, NULL);
241 try_autochanger = false;
242 continue; /* try reading volume mounted */
246 /* Mount a specific volume and no other */
247 Dmsg0(200, "calling dir_ask_sysop\n");
248 if (!dir_ask_sysop_to_mount_volume(dcr)) {
249 goto get_out; /* error return */
251 try_autochanger = true; /* permit using autochanger again */
252 continue; /* try reading again */
257 Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"),
264 set_jcr_job_status(jcr, JS_Running);
265 dir_send_job_status(jcr);
266 Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
267 dcr->VolumeName, dev->print_name());
271 if (dcr->reserved_device) {
272 dev->reserved_device--;
273 Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
274 dcr->reserved_device = false;
278 Dmsg1(50, "jcr->dcr=%p\n", jcr->dcr);
284 * Acquire device for writing. We permit multiple writers.
285 * If this is the first one, we read the label.
287 * Returns: NULL if failed for any reason
289 * Note, normally reserve_device_for_append() is called
290 * before this routine.
292 DCR *acquire_device_for_append(DCR *dcr)
294 bool release = false;
295 bool recycle = false;
296 bool do_mount = false;
297 DEVICE *dev = dcr->dev;
300 init_device_wait_timers(dcr);
302 dev->block(BST_DOING_ACQUIRE);
303 Dmsg1(190, "acquire_append device is %s\n", dev->is_tape()?"tape":
304 (dev->is_dvd()?"DVD":"disk"));
307 * With the reservation system, this should not happen
309 if (dev->can_read()) {
310 Jmsg1(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev->print_name());
311 Dmsg1(200, "Device %s is busy reading.\n", dev->print_name());
315 if (dev->can_append()) {
316 Dmsg0(190, "device already in append.\n");
318 * Device already in append mode
320 * Check if we have the right Volume mounted
321 * OK if current volume info OK
322 * OK if next volume matches current volume
323 * otherwise mount desired volume obtained from
324 * dir_find_next_appendable_volume
325 * dev->VolHdr.VolumeName is what is in the drive
326 * dcr->VolumeName is what we pass into the routines, or
327 * get back from the subroutines.
329 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
330 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
331 !(dir_find_next_appendable_volume(dcr) &&
332 strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
333 Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
335 /* Release volume reserved by dir_find_next_appendable_volume() */
336 if (dcr->VolumeName[0]) {
337 free_unused_volume(dcr);
339 if (dev->num_writers != 0) {
340 Jmsg3(jcr, M_FATAL, 0, _("Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n"),
341 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
342 Dmsg3(200, "Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n",
343 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
346 /* Wrong tape mounted, release it, then fall through to get correct one */
347 Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
352 * At this point, the correct tape is already mounted, so
353 * we do not need to do mount_next_write_volume(), unless
354 * we need to recycle the tape.
356 recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
357 Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
358 if (recycle && dev->num_writers != 0) {
359 Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
360 " on device %s because it is in use by another job.\n"),
361 dev->VolHdr.VolumeName, dev->print_name());
364 if (dev->num_writers == 0) {
365 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
369 /* Not already in append mode, so mount the device */
370 Dmsg0(190, "Not in append mode, try mount.\n");
371 ASSERT(dev->num_writers == 0);
375 if (do_mount || recycle) {
376 Dmsg0(190, "Do mount_next_write_vol\n");
377 bool mounted = mount_next_write_volume(dcr, release);
379 if (!job_canceled(jcr)) {
380 /* Reduce "noise" -- don't print if job canceled */
381 Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
383 Dmsg1(200, "Could not ready device %s for append.\n",
388 Dmsg2(190, "Output pos=%u:%u\n", dcr->dev->file, dcr->dev->block_num);
391 dev->num_writers++; /* we are now a writer */
392 if (jcr->NumVolumes == 0) {
396 if (dcr->reserved_device) {
397 dev->reserved_device--;
398 Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
399 dcr->reserved_device = false;
410 if (dcr->reserved_device) {
411 dev->reserved_device--;
412 Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
413 dcr->reserved_device = false;
422 * This job is done, so release the device. From a Unix standpoint,
423 * the device remains open.
426 bool release_device(DCR *dcr)
429 DEVICE *dev = dcr->dev;
433 Dmsg2(100, "release_device device %s is %s\n", dev->print_name(), dev->is_tape()?"tape":"disk");
435 /* if device is reserved, job never started, so release the reserve here */
436 if (dcr->reserved_device) {
437 dev->reserved_device--;
438 Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
439 dcr->reserved_device = false;
442 if (dev->can_read()) {
443 dev->clear_read(); /* clear read bit */
445 /******FIXME**** send read volume usage statistics to director */
447 } else if (dev->num_writers > 0) {
449 * Note if WEOT is set, we are at the end of the tape
450 * and may not be positioned correctly, so the
451 * job_media_record and update_vol_info have already been
452 * done, which means we skip them here.
455 Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
456 if (dev->is_labeled()) {
457 Dmsg0(100, "dir_create_jobmedia_record. Release\n");
458 if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
459 Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
460 dcr->VolCatInfo.VolCatName, jcr->Job);
462 /* If no more writers, write an EOF */
463 if (!dev->num_writers && dev->can_write()) {
465 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
467 if (!dev->at_weot()) {
468 dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */
469 dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */
470 /* Note! do volume update before close, which zaps VolCatInfo */
471 Dmsg0(100, "dir_update_vol_info. Release0\n");
472 dir_update_volume_info(dcr, false); /* send Volume info to Director */
478 * If we reach here, it is most likely because the job
479 * has failed, since the device is not in read mode and
480 * there are no writers. It was probably reserved.
484 /* If no writers, close if file or !CAP_ALWAYS_OPEN */
485 if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
489 /* Fire off Alert command and include any output */
490 if (!job_canceled(jcr) && dcr->device->alert_command) {
494 char line[MAXSTRING];
495 alert = get_pool_memory(PM_FNAME);
496 alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
497 bpipe = open_bpipe(alert, 0, "r");
499 while (fgets(line, sizeof(line), bpipe->rfd)) {
500 Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
502 status = close_bpipe(bpipe);
508 Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
509 alert, be.strerror(status));
512 Dmsg1(400, "alert status=%d\n", status);
513 free_pool_memory(alert);
516 if (jcr->read_dcr == dcr) {
517 jcr->read_dcr = NULL;
519 if (jcr->dcr == dcr) {
527 * Create a new Device Control Record and attach
528 * it to the device (if this is a real job).
530 DCR *new_dcr(JCR *jcr, DEVICE *dev)
532 DCR *dcr = (DCR *)malloc(sizeof(DCR));
533 memset(dcr, 0, sizeof(DCR));
537 dcr->device = dev->device;
538 dcr->block = new_block(dev);
539 dcr->rec = new_record();
540 dcr->max_job_spool_size = dev->device->max_job_spool_size;
541 /* Attach this dcr only if dev is initialized */
542 if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
543 dev->attached_dcrs->append(dcr); /* attach dcr to device */
544 // jcr->dcrs->append(dcr); /* put dcr in list for Job */
552 * Search the dcrs list for the given dcr. If it is found,
553 * as it should be, then remove it. Also zap the jcr pointer
554 * to the dcr if it is the same one.
557 static void remove_dcr_from_dcrs(DCR *dcr)
563 int num = jcr->dcrs->size();
564 for (i=0; i < num; i++) {
565 ldcr = (DCR *)jcr->dcrs->get(i);
567 jcr->dcrs->remove(i);
568 if (jcr->dcr == dcr) {
577 static void detach_dcr_from_dev(DCR *dcr)
579 DEVICE *dev = dcr->dev;
581 if (dcr->reserved_device) {
582 dcr->reserved_device = false;
584 dev->reserved_device--;
585 Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
586 dcr->reserved_device = false;
587 /* If we set read mode in reserving, remove it */
588 if (dev->can_read()) {
591 if (dev->num_writers < 0) {
592 Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers);
593 dev->num_writers = 0;
598 /* Detach this dcr only if the dev is initialized */
599 if (dcr->dev->fd != 0 && dcr->jcr && dcr->jcr->JobType != JT_SYSTEM) {
600 dcr->dev->attached_dcrs->remove(dcr); /* detach dcr from device */
601 // remove_dcr_from_dcrs(dcr); /* remove dcr from jcr list */
603 free_unused_volume(dcr); /* free unused vols attached to this dcr */
604 pthread_cond_broadcast(&dcr->dev->wait_next_vol);
605 pthread_cond_broadcast(&wait_device_release);
609 * Free up all aspects of the given dcr -- i.e. dechain it,
610 * release allocated memory, zap pointers, ...
612 void free_dcr(DCR *dcr)
615 detach_dcr_from_dev(dcr);
618 free_block(dcr->block);
621 free_record(dcr->rec);
624 dcr->jcr->dcr = NULL;