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(&wait_device_release);
117 /*********************************************************************
118 * Acquire device for reading.
119 * The drive should have previously been reserved by calling
120 * reserve_device_for_read(). We read the Volume label from the block and
121 * leave the block pointers just after the label.
123 * Returns: NULL if failed for any reason
126 DCR *acquire_device_for_read(DCR *dcr)
128 DEVICE *dev = dcr->dev;
131 bool tape_previously_mounted;
132 bool tape_initially_mounted;
134 bool try_autochanger = true;
136 int vol_label_status;
138 dev->block(BST_DOING_ACQUIRE);
140 if (dev->num_writers > 0) {
141 Jmsg2(jcr, M_FATAL, 0, _("Num_writers=%d not zero. Job %d canceled.\n"),
142 dev->num_writers, jcr->JobId);
146 /* Find next Volume, if any */
149 Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job %d canceled.\n"), jcr->JobId);
153 for (i=1; i<jcr->CurVolume; i++) {
157 goto get_out; /* should not happen */
159 bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
161 init_device_wait_timers(dcr);
163 tape_previously_mounted = dev->can_read() || dev->can_append() ||
165 tape_initially_mounted = tape_previously_mounted;
168 /* Volume info is always needed because of VolParts */
169 Dmsg0(200, "dir_get_volume_info\n");
170 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
171 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
174 for (i=0; i<5; i++) {
175 dev->clear_labeled(); /* force reread of label */
176 if (job_canceled(jcr)) {
177 Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
178 goto get_out; /* error return */
181 * This code ensures that the device is ready for
182 * reading. If it is a file, it opens it.
183 * If it is a tape, it checks the volume name
185 Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName);
186 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
187 if (dev->dev_errno == EIO) { /* no tape loaded */
188 Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed (EIO): ERR=%s\n"),
189 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
193 Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
194 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
197 Dmsg1(100, "opened dev %s OK\n", dev->print_name());
199 /* Read Volume Label */
201 Dmsg0(200, "calling read-vol-label\n");
202 vol_label_status = read_dev_volume_label(dcr);
203 switch (vol_label_status) {
206 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
210 * Send error message generated by read_dev_volume_label()
211 * only we really had a tape mounted. This supresses superfluous
212 * error messages when nothing is mounted.
214 if (tape_previously_mounted) {
215 Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
219 if (tape_initially_mounted) {
220 tape_initially_mounted = false;
225 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
227 tape_previously_mounted = true;
229 /* If the device requires mount, close it, so the device can be ejected.
230 * FIXME: This should perhaps be done for all devices. */
231 if (dev->requires_mount()) {
232 force_close_device(dev);
235 /* Call autochanger only once unless ask_sysop called */
236 if (try_autochanger) {
238 Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
239 dcr->VolumeName, dcr->VolCatInfo.Slot);
240 stat = autoload_device(dcr, 0, NULL);
242 try_autochanger = false;
243 continue; /* try reading volume mounted */
247 /* Mount a specific volume and no other */
248 Dmsg0(200, "calling dir_ask_sysop\n");
249 if (!dir_ask_sysop_to_mount_volume(dcr)) {
250 goto get_out; /* error return */
252 try_autochanger = true; /* permit using autochanger again */
253 continue; /* try reading again */
258 Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"),
265 set_jcr_job_status(jcr, JS_Running);
266 dir_send_job_status(jcr);
267 Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
268 dcr->VolumeName, dev->print_name());
280 * Acquire device for writing. We permit multiple writers.
281 * If this is the first one, we read the label.
283 * Returns: NULL if failed for any reason
285 * Note, normally reserve_device_for_append() is called
286 * before this routine.
288 DCR *acquire_device_for_append(DCR *dcr)
290 bool release = false;
291 bool recycle = false;
292 bool do_mount = false;
293 DEVICE *dev = dcr->dev;
296 init_device_wait_timers(dcr);
298 dev->block(BST_DOING_ACQUIRE);
299 Dmsg1(190, "acquire_append device is %s\n", dev->is_tape()?"tape":
300 (dev->is_dvd()?"DVD":"disk"));
303 * With the reservation system, this should not happen
305 if (dev->can_read()) {
306 Jmsg1(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev->print_name());
307 Dmsg1(200, "Device %s is busy reading.\n", dev->print_name());
311 if (dev->can_append()) {
312 Dmsg0(190, "device already in append.\n");
314 * Device already in append mode
316 * Check if we have the right Volume mounted
317 * OK if current volume info OK
318 * OK if next volume matches current volume
319 * otherwise mount desired volume obtained from
320 * dir_find_next_appendable_volume
321 * dev->VolHdr.VolumeName is what is in the drive
322 * dcr->VolumeName is what we pass into the routines, or
323 * get back from the subroutines.
325 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
326 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
327 !(dir_find_next_appendable_volume(dcr) &&
328 strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
329 Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
331 /* Release volume reserved by dir_find_next_appendable_volume() */
332 if (dcr->VolumeName[0]) {
333 free_unused_volume(dcr);
335 if (dev->num_writers != 0) {
336 Jmsg3(jcr, M_FATAL, 0, _("Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n"),
337 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
338 Dmsg3(200, "Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n",
339 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
342 /* Wrong tape mounted, release it, then fall through to get correct one */
343 Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
348 * At this point, the correct tape is already mounted, so
349 * we do not need to do mount_next_write_volume(), unless
350 * we need to recycle the tape.
352 recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
353 Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
354 if (recycle && dev->num_writers != 0) {
355 Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
356 " on device %s because it is in use by another job.\n"),
357 dev->VolHdr.VolumeName, dev->print_name());
360 if (dev->num_writers == 0) {
361 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
365 /* Not already in append mode, so mount the device */
366 Dmsg0(190, "Not in append mode, try mount.\n");
367 ASSERT(dev->num_writers == 0);
371 if (do_mount || recycle) {
372 Dmsg0(190, "Do mount_next_write_vol\n");
373 bool mounted = mount_next_write_volume(dcr, release);
375 if (!job_canceled(jcr)) {
376 /* Reduce "noise" -- don't print if job canceled */
377 Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
379 Dmsg1(200, "Could not ready device %s for append.\n",
386 dev->num_writers++; /* we are now a writer */
387 if (jcr->NumVolumes == 0) {
393 * If we jump here, it is an error return because
394 * rtn_dev will still be NULL
401 if (dcr->reserved_device) {
402 dev->reserved_device--;
403 Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device);
404 dcr->reserved_device = false;
412 * This job is done, so release the device. From a Unix standpoint,
413 * the device remains open.
416 bool release_device(DCR *dcr)
419 DEVICE *dev = dcr->dev;
421 bool was_reading = false;
424 Dmsg1(100, "release_device device is %s\n", dev->is_tape()?"tape":"disk");
426 /* if device is reserved, job never started, so release the reserve here */
427 if (dcr->reserved_device) {
428 dev->reserved_device--;
429 Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device);
430 dcr->reserved_device = false;
433 if (dev->can_read()) {
434 dev->clear_read(); /* clear read bit */
437 /******FIXME**** send read volume usage statistics to director */
439 } else if (dev->num_writers > 0) {
441 * Note if WEOT is set, we are at the end of the tape
442 * and may not be positioned correctly, so the
443 * job_media_record and update_vol_info have already been
444 * done, which means we skip them here.
447 Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
448 if (dev->is_labeled()) {
449 Dmsg0(100, "dir_create_jobmedia_record. Release\n");
450 if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
451 Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
452 dcr->VolCatInfo.VolCatName, jcr->Job);
454 /* If no more writers, write an EOF */
455 if (!dev->num_writers && dev->can_write()) {
457 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
459 if (!dev->at_weot()) {
460 dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */
461 dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */
462 /* Note! do volume update before close, which zaps VolCatInfo */
463 Dmsg0(100, "dir_update_vol_info. Release0\n");
464 dir_update_volume_info(dcr, false); /* send Volume info to Director */
470 * If we reach here, it is most likely because the job
471 * has failed, since the device is not in read mode and
472 * there are no writers. It was probably reserved.
476 /* If no writers, close if file or !CAP_ALWAYS_OPEN */
477 if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
478 offline_or_rewind_dev(dev);
482 /* Fire off Alert command and include any output */
483 if (!job_canceled(jcr) && dcr->device->alert_command) {
487 char line[MAXSTRING];
488 alert = get_pool_memory(PM_FNAME);
489 alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
490 bpipe = open_bpipe(alert, 0, "r");
492 while (fgets(line, sizeof(line), bpipe->rfd)) {
493 Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
495 status = close_bpipe(bpipe);
501 Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
502 alert, be.strerror(status));
505 Dmsg1(400, "alert status=%d\n", status);
506 free_pool_memory(alert);
511 jcr->read_dcr = NULL;