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
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 * Create a new Device Control Record and attach
28 * it to the device (if this is a real job).
30 DCR *new_dcr(JCR *jcr, DEVICE *dev)
32 DCR *dcr = (DCR *)malloc(sizeof(DCR));
33 memset(dcr, 0, sizeof(DCR));
37 dcr->device = dev->device;
38 dcr->block = new_block(dev);
39 dcr->rec = new_record();
40 dcr->max_job_spool_size = dev->device->max_job_spool_size;
41 /* Attach this dcr only if dev is initialized */
42 if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
43 dev->attached_dcrs->append(dcr); /* attach dcr to device */
44 // jcr->dcrs->append(dcr); /* put dcr in list for Job */
52 * Search the dcrs list for the given dcr. If it is found,
53 * as it should be, then remove it. Also zap the jcr pointer
54 * to the dcr if it is the same one.
57 static void remove_dcr_from_dcrs(DCR *dcr)
63 int num = jcr->dcrs->size();
64 for (i=0; i < num; i++) {
65 ldcr = (DCR *)jcr->dcrs->get(i);
68 if (jcr->dcr == dcr) {
78 * Free up all aspects of the given dcr -- i.e. dechain it,
79 * release allocated memory, zap pointers, ...
81 void free_dcr(DCR *dcr)
84 DEVICE *dev = dcr->dev;
86 if (dcr->reserved_device) {
88 dev->reserved_device--;
89 Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device);
90 dcr->reserved_device = false;
91 if (dev->num_writers < 0) {
92 Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers);
98 /* Detach this dcr only if the dev is initialized */
99 if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
100 dev->attached_dcrs->remove(dcr); /* detach dcr from device */
101 // remove_dcr_from_dcrs(dcr); /* remove dcr from jcr list */
104 free_block(dcr->block);
107 free_record(dcr->rec);
110 dcr->jcr->dcr = NULL;
112 free_unused_volume(dcr); /* free unused vols attached to this dcr */
114 pthread_cond_broadcast(&dev->wait_next_vol);
115 pthread_cond_broadcast(&wait_device_release);
118 /*********************************************************************
119 * Acquire device for reading.
120 * The drive should have previously been reserved by calling
121 * reserve_device_for_read(). We read the Volume label from the block and
122 * leave the block pointers just after the label.
124 * Returns: NULL if failed for any reason
127 DCR *acquire_device_for_read(DCR *dcr)
129 DEVICE *dev = dcr->dev;
132 bool tape_previously_mounted;
133 bool tape_initially_mounted;
135 bool try_autochanger = true;
137 int vol_label_status;
139 dev->block(BST_DOING_ACQUIRE);
141 if (dev->num_writers > 0) {
142 Jmsg2(jcr, M_FATAL, 0, _("Num_writers=%d not zero. Job %d canceled.\n"),
143 dev->num_writers, jcr->JobId);
147 /* Find next Volume, if any */
150 Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job %d canceled.\n"), jcr->JobId);
154 for (i=1; i<jcr->CurVolume; i++) {
158 goto get_out; /* should not happen */
160 bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
162 init_device_wait_timers(dcr);
164 tape_previously_mounted = dev->can_read() || dev->can_append() ||
166 tape_initially_mounted = tape_previously_mounted;
169 /* Volume info is always needed because of VolParts */
170 Dmsg0(200, "dir_get_volume_info\n");
171 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
172 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
175 for (i=0; i<5; i++) {
176 dev->clear_labeled(); /* force reread of label */
177 if (job_canceled(jcr)) {
178 Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
179 goto get_out; /* error return */
182 * This code ensures that the device is ready for
183 * reading. If it is a file, it opens it.
184 * If it is a tape, it checks the volume name
186 Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName);
187 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
188 if (dev->dev_errno == EIO) { /* no tape loaded */
189 Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed (EIO): ERR=%s\n"),
190 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
194 Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
195 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
198 Dmsg1(100, "opened dev %s OK\n", dev->print_name());
200 /* Read Volume Label */
202 Dmsg0(200, "calling read-vol-label\n");
203 vol_label_status = read_dev_volume_label(dcr);
204 switch (vol_label_status) {
207 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
211 * Send error message generated by read_dev_volume_label()
212 * only we really had a tape mounted. This supresses superfluous
213 * error messages when nothing is mounted.
215 if (tape_previously_mounted) {
216 Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
220 if (tape_initially_mounted) {
221 tape_initially_mounted = false;
226 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
228 tape_previously_mounted = true;
230 /* If the device requires mount, close it, so the device can be ejected.
231 * FIXME: This should perhaps be done for all devices. */
232 if (dev->requires_mount()) {
233 force_close_device(dev);
236 /* Call autochanger only once unless ask_sysop called */
237 if (try_autochanger) {
239 Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
240 dcr->VolumeName, dcr->VolCatInfo.Slot);
241 stat = autoload_device(dcr, 0, NULL);
243 try_autochanger = false;
244 continue; /* try reading volume mounted */
248 /* Mount a specific volume and no other */
249 Dmsg0(200, "calling dir_ask_sysop\n");
250 if (!dir_ask_sysop_to_mount_volume(dcr)) {
251 goto get_out; /* error return */
253 try_autochanger = true; /* permit using autochanger again */
254 continue; /* try reading again */
259 Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"),
266 set_jcr_job_status(jcr, JS_Running);
267 dir_send_job_status(jcr);
268 Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
269 dcr->VolumeName, dev->print_name());
281 * Acquire device for writing. We permit multiple writers.
282 * If this is the first one, we read the label.
284 * Returns: NULL if failed for any reason
286 * Note, normally reserve_device_for_append() is called
287 * before this routine.
289 DCR *acquire_device_for_append(DCR *dcr)
291 bool release = false;
292 bool recycle = false;
293 bool do_mount = false;
294 DEVICE *dev = dcr->dev;
297 init_device_wait_timers(dcr);
299 dev->block(BST_DOING_ACQUIRE);
300 Dmsg1(190, "acquire_append device is %s\n", dev->is_tape()?"tape":
301 (dev->is_dvd()?"DVD":"disk"));
304 * With the reservation system, this should not happen
306 if (dev->can_read()) {
307 Jmsg1(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev->print_name());
308 Dmsg1(200, "Device %s is busy reading.\n", dev->print_name());
312 if (dev->can_append()) {
313 Dmsg0(190, "device already in append.\n");
315 * Device already in append mode
317 * Check if we have the right Volume mounted
318 * OK if current volume info OK
319 * OK if next volume matches current volume
320 * otherwise mount desired volume obtained from
321 * dir_find_next_appendable_volume
322 * dev->VolHdr.VolumeName is what is in the drive
323 * dcr->VolumeName is what we pass into the routines, or
324 * get back from the subroutines.
326 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
327 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
328 !(dir_find_next_appendable_volume(dcr) &&
329 strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
330 Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
332 /* Release volume reserved by dir_find_next_appendable_volume() */
333 if (dcr->VolumeName[0]) {
334 free_unused_volume(dcr);
336 if (dev->num_writers != 0) {
337 Jmsg3(jcr, M_FATAL, 0, _("Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n"),
338 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
339 Dmsg3(200, "Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n",
340 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
343 /* Wrong tape mounted, release it, then fall through to get correct one */
344 Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
349 * At this point, the correct tape is already mounted, so
350 * we do not need to do mount_next_write_volume(), unless
351 * we need to recycle the tape.
353 recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
354 Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
355 if (recycle && dev->num_writers != 0) {
356 Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
357 " on device %s because it is in use by another job.\n"),
358 dev->VolHdr.VolumeName, dev->print_name());
361 if (dev->num_writers == 0) {
362 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
366 /* Not already in append mode, so mount the device */
367 Dmsg0(190, "Not in append mode, try mount.\n");
368 ASSERT(dev->num_writers == 0);
372 if (do_mount || recycle) {
373 Dmsg0(190, "Do mount_next_write_vol\n");
374 bool mounted = mount_next_write_volume(dcr, release);
376 if (!job_canceled(jcr)) {
377 /* Reduce "noise" -- don't print if job canceled */
378 Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
380 Dmsg1(200, "Could not ready device %s for append.\n",
387 dev->num_writers++; /* we are now a writer */
388 if (jcr->NumVolumes == 0) {
392 if (dcr->reserved_device) {
393 dev->reserved_device--;
394 Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device);
395 dcr->reserved_device = false;
406 if (dcr->reserved_device) {
407 dev->reserved_device--;
408 Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device);
409 dcr->reserved_device = false;
418 * This job is done, so release the device. From a Unix standpoint,
419 * the device remains open.
422 bool release_device(DCR *dcr)
425 DEVICE *dev = dcr->dev;
427 bool was_reading = false;
430 Dmsg1(100, "release_device device is %s\n", dev->is_tape()?"tape":"disk");
432 /* if device is reserved, job never started, so release the reserve here */
433 if (dcr->reserved_device) {
434 dev->reserved_device--;
435 Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device);
436 dcr->reserved_device = false;
439 if (dev->can_read()) {
440 dev->clear_read(); /* clear read bit */
443 /******FIXME**** send read volume usage statistics to director */
445 } else if (dev->num_writers > 0) {
447 * Note if WEOT is set, we are at the end of the tape
448 * and may not be positioned correctly, so the
449 * job_media_record and update_vol_info have already been
450 * done, which means we skip them here.
453 Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
454 if (dev->is_labeled()) {
455 Dmsg0(100, "dir_create_jobmedia_record. Release\n");
456 if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
457 Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
458 dcr->VolCatInfo.VolCatName, jcr->Job);
460 /* If no more writers, write an EOF */
461 if (!dev->num_writers && dev->can_write()) {
463 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
465 if (!dev->at_weot()) {
466 dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */
467 dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */
468 /* Note! do volume update before close, which zaps VolCatInfo */
469 Dmsg0(100, "dir_update_vol_info. Release0\n");
470 dir_update_volume_info(dcr, false); /* send Volume info to Director */
476 * If we reach here, it is most likely because the job
477 * has failed, since the device is not in read mode and
478 * there are no writers. It was probably reserved.
482 /* If no writers, close if file or !CAP_ALWAYS_OPEN */
483 if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
484 offline_or_rewind_dev(dev);
488 /* Fire off Alert command and include any output */
489 if (!job_canceled(jcr) && dcr->device->alert_command) {
493 char line[MAXSTRING];
494 alert = get_pool_memory(PM_FNAME);
495 alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
496 bpipe = open_bpipe(alert, 0, "r");
498 while (fgets(line, sizeof(line), bpipe->rfd)) {
499 Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
501 status = close_bpipe(bpipe);
507 Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
508 alert, be.strerror(status));
511 Dmsg1(400, "alert status=%d\n", status);
512 free_pool_memory(alert);
517 jcr->read_dcr = NULL;