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 */
27 /*********************************************************************
28 * Acquire device for reading.
29 * The drive should have previously been reserved by calling
30 * reserve_device_for_read(). We read the Volume label from the block and
31 * leave the block pointers just after the label.
33 * Returns: NULL if failed for any reason
36 DCR *acquire_device_for_read(DCR *dcr)
38 DEVICE *dev = dcr->dev;
41 bool tape_previously_mounted;
42 bool tape_initially_mounted;
44 bool try_autochanger = true;
49 dev->block(BST_DOING_ACQUIRE);
51 if (dev->num_writers > 0) {
52 Jmsg2(jcr, M_FATAL, 0, _("Num_writers=%d not zero. Job %d canceled.\n"),
53 dev->num_writers, jcr->JobId);
57 /* Find next Volume, if any */
60 Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job %d canceled.\n"), jcr->JobId);
64 for (i=1; i<jcr->CurVolume; i++) {
68 goto get_out; /* should not happen */
70 bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
72 init_device_wait_timers(dcr);
74 tape_previously_mounted = dev->can_read() || dev->can_append() ||
76 tape_initially_mounted = tape_previously_mounted;
79 /* Volume info is always needed because of VolParts */
80 Dmsg0(200, "dir_get_volume_info\n");
81 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
82 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
86 /* If not polling limit retries */
87 if (!dev->poll && retry++ > 10) {
90 dev->clear_labeled(); /* force reread of label */
91 if (job_canceled(jcr)) {
92 Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
93 goto get_out; /* error return */
96 * This code ensures that the device is ready for
97 * reading. If it is a file, it opens it.
98 * If it is a tape, it checks the volume name
100 Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName);
101 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
102 if (dev->dev_errno == EIO) { /* no tape loaded */
103 Jmsg3(jcr, M_WARNING, 0, _("Read open device %s Volume \"%s\" failed (EIO): ERR=%s\n"),
104 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
108 Jmsg3(jcr, M_FATAL, 0, _("Read open device %s Volume \"%s\" failed: ERR=%s\n"),
109 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
112 Dmsg1(100, "opened dev %s OK\n", dev->print_name());
114 /* Read Volume Label */
116 Dmsg0(200, "calling read-vol-label\n");
117 vol_label_status = read_dev_volume_label(dcr);
118 switch (vol_label_status) {
121 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
125 * Send error message generated by read_dev_volume_label()
126 * only we really had a tape mounted. This supresses superfluous
127 * error messages when nothing is mounted.
129 if (tape_previously_mounted) {
130 Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
134 if (tape_initially_mounted) {
135 tape_initially_mounted = false;
138 /* If polling and got a previous bad name, ignore it */
139 if (dev->poll && strcmp(dev->BadVolName, dev->VolHdr.VolumeName) == 0) {
142 bstrncpy(dev->BadVolName, dev->VolHdr.VolumeName, sizeof(dev->BadVolName));
146 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
148 tape_previously_mounted = true;
150 /* If the device requires mount, close it, so the device can be ejected.
151 * FIXME: This should perhaps be done for all devices. */
152 if (dev->requires_mount()) {
153 force_close_device(dev);
156 /* Call autochanger only once unless ask_sysop called */
157 if (try_autochanger) {
159 Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
160 dcr->VolumeName, dcr->VolCatInfo.Slot);
161 stat = autoload_device(dcr, 0, NULL);
163 try_autochanger = false;
164 continue; /* try reading volume mounted */
168 /* Mount a specific volume and no other */
169 Dmsg0(200, "calling dir_ask_sysop\n");
170 if (!dir_ask_sysop_to_mount_volume(dcr)) {
171 goto get_out; /* error return */
173 try_autochanger = true; /* permit using autochanger again */
174 continue; /* try reading again */
179 Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"),
186 set_jcr_job_status(jcr, JS_Running);
187 dir_send_job_status(jcr);
188 Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
189 dcr->VolumeName, dev->print_name());
193 if (dcr->reserved_device) {
194 dev->reserved_device--;
195 Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
196 dcr->reserved_device = false;
200 Dmsg1(000, "jcr->dcr=%p\n", jcr->dcr);
206 * Acquire device for writing. We permit multiple writers.
207 * If this is the first one, we read the label.
209 * Returns: NULL if failed for any reason
211 * Note, normally reserve_device_for_append() is called
212 * before this routine.
214 DCR *acquire_device_for_append(DCR *dcr)
216 bool release = false;
217 bool recycle = false;
218 bool do_mount = false;
219 DEVICE *dev = dcr->dev;
222 init_device_wait_timers(dcr);
224 dev->block(BST_DOING_ACQUIRE);
225 Dmsg1(190, "acquire_append device is %s\n", dev->is_tape()?"tape":
226 (dev->is_dvd()?"DVD":"disk"));
229 * With the reservation system, this should not happen
231 if (dev->can_read()) {
232 Jmsg1(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev->print_name());
233 Dmsg1(200, "Device %s is busy reading.\n", dev->print_name());
237 if (dev->can_append()) {
238 Dmsg0(190, "device already in append.\n");
240 * Device already in append mode
242 * Check if we have the right Volume mounted
243 * OK if current volume info OK
244 * OK if next volume matches current volume
245 * otherwise mount desired volume obtained from
246 * dir_find_next_appendable_volume
247 * dev->VolHdr.VolumeName is what is in the drive
248 * dcr->VolumeName is what we pass into the routines, or
249 * get back from the subroutines.
251 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
252 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
253 !(dir_find_next_appendable_volume(dcr) &&
254 strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
255 Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
257 /* Release volume reserved by dir_find_next_appendable_volume() */
258 if (dcr->VolumeName[0]) {
259 free_unused_volume(dcr);
261 if (dev->num_writers != 0) {
262 Jmsg3(jcr, M_FATAL, 0, _("Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n"),
263 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
264 Dmsg3(200, "Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n",
265 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
268 /* Wrong tape mounted, release it, then fall through to get correct one */
269 Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
274 * At this point, the correct tape is already mounted, so
275 * we do not need to do mount_next_write_volume(), unless
276 * we need to recycle the tape.
278 recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
279 Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
280 if (recycle && dev->num_writers != 0) {
281 Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
282 " on device %s because it is in use by another job.\n"),
283 dev->VolHdr.VolumeName, dev->print_name());
286 if (dev->num_writers == 0) {
287 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
291 /* Not already in append mode, so mount the device */
292 Dmsg0(190, "Not in append mode, try mount.\n");
293 ASSERT(dev->num_writers == 0);
297 if (do_mount || recycle) {
298 Dmsg0(190, "Do mount_next_write_vol\n");
299 bool mounted = mount_next_write_volume(dcr, release);
301 if (!job_canceled(jcr)) {
302 /* Reduce "noise" -- don't print if job canceled */
303 Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
305 Dmsg1(200, "Could not ready device %s for append.\n",
312 dev->num_writers++; /* we are now a writer */
313 if (jcr->NumVolumes == 0) {
317 if (dcr->reserved_device) {
318 dev->reserved_device--;
319 Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device);
320 dcr->reserved_device = false;
331 if (dcr->reserved_device) {
332 dev->reserved_device--;
333 Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device);
334 dcr->reserved_device = false;
343 * This job is done, so release the device. From a Unix standpoint,
344 * the device remains open.
347 bool release_device(DCR *dcr)
350 DEVICE *dev = dcr->dev;
354 Dmsg1(100, "release_device device is %s\n", dev->is_tape()?"tape":"disk");
356 /* if device is reserved, job never started, so release the reserve here */
357 if (dcr->reserved_device) {
358 dev->reserved_device--;
359 Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device);
360 dcr->reserved_device = false;
363 if (dev->can_read()) {
364 dev->clear_read(); /* clear read bit */
366 /******FIXME**** send read volume usage statistics to director */
368 } else if (dev->num_writers > 0) {
370 * Note if WEOT is set, we are at the end of the tape
371 * and may not be positioned correctly, so the
372 * job_media_record and update_vol_info have already been
373 * done, which means we skip them here.
376 Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
377 if (dev->is_labeled()) {
378 Dmsg0(100, "dir_create_jobmedia_record. Release\n");
379 if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
380 Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
381 dcr->VolCatInfo.VolCatName, jcr->Job);
383 /* If no more writers, write an EOF */
384 if (!dev->num_writers && dev->can_write()) {
386 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
388 if (!dev->at_weot()) {
389 dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */
390 dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */
391 /* Note! do volume update before close, which zaps VolCatInfo */
392 Dmsg0(100, "dir_update_vol_info. Release0\n");
393 dir_update_volume_info(dcr, false); /* send Volume info to Director */
399 * If we reach here, it is most likely because the job
400 * has failed, since the device is not in read mode and
401 * there are no writers. It was probably reserved.
405 /* If no writers, close if file or !CAP_ALWAYS_OPEN */
406 if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
407 offline_or_rewind_dev(dev);
411 /* Fire off Alert command and include any output */
412 if (!job_canceled(jcr) && dcr->device->alert_command) {
416 char line[MAXSTRING];
417 alert = get_pool_memory(PM_FNAME);
418 alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
419 bpipe = open_bpipe(alert, 0, "r");
421 while (fgets(line, sizeof(line), bpipe->rfd)) {
422 Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
424 status = close_bpipe(bpipe);
430 Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
431 alert, be.strerror(status));
434 Dmsg1(400, "alert status=%d\n", status);
435 free_pool_memory(alert);
438 if (jcr->read_dcr == dcr) {
439 jcr->read_dcr = NULL;
441 if (jcr->dcr == dcr) {
449 * Create a new Device Control Record and attach
450 * it to the device (if this is a real job).
452 DCR *new_dcr(JCR *jcr, DEVICE *dev)
454 DCR *dcr = (DCR *)malloc(sizeof(DCR));
455 memset(dcr, 0, sizeof(DCR));
459 dcr->device = dev->device;
460 dcr->block = new_block(dev);
461 dcr->rec = new_record();
462 dcr->max_job_spool_size = dev->device->max_job_spool_size;
463 /* Attach this dcr only if dev is initialized */
464 if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
465 dev->attached_dcrs->append(dcr); /* attach dcr to device */
466 // jcr->dcrs->append(dcr); /* put dcr in list for Job */
474 * Search the dcrs list for the given dcr. If it is found,
475 * as it should be, then remove it. Also zap the jcr pointer
476 * to the dcr if it is the same one.
479 static void remove_dcr_from_dcrs(DCR *dcr)
485 int num = jcr->dcrs->size();
486 for (i=0; i < num; i++) {
487 ldcr = (DCR *)jcr->dcrs->get(i);
489 jcr->dcrs->remove(i);
490 if (jcr->dcr == dcr) {
500 * Free up all aspects of the given dcr -- i.e. dechain it,
501 * release allocated memory, zap pointers, ...
503 void free_dcr(DCR *dcr)
506 DEVICE *dev = dcr->dev;
508 if (dcr->reserved_device) {
510 dev->reserved_device--;
511 Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
512 dcr->reserved_device = false;
513 /* If we set read mode in reserving, remove it */
514 if (dev->can_read()) {
517 if (dev->num_writers < 0) {
518 Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers);
519 dev->num_writers = 0;
524 /* Detach this dcr only if the dev is initialized */
525 if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
526 dev->attached_dcrs->remove(dcr); /* detach dcr from device */
527 // remove_dcr_from_dcrs(dcr); /* remove dcr from jcr list */
530 free_block(dcr->block);
533 free_record(dcr->rec);
536 dcr->jcr->dcr = NULL;
538 free_unused_volume(dcr); /* free unused vols attached to this dcr */
540 pthread_cond_broadcast(&dev->wait_next_vol);
541 pthread_cond_broadcast(&wait_device_release);