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 * 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 /* If we set read mode in reserving, remove it */
90 if (dev->can_read()) {
93 Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device);
94 dcr->reserved_device = false;
95 if (dev->num_writers < 0) {
96 Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers);
102 /* Detach this dcr only if the dev is initialized */
103 if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
104 dev->attached_dcrs->remove(dcr); /* detach dcr from device */
105 // remove_dcr_from_dcrs(dcr); /* remove dcr from jcr list */
108 free_block(dcr->block);
111 free_record(dcr->rec);
114 dcr->jcr->dcr = NULL;
116 free_unused_volume(dcr); /* free unused vols attached to this dcr */
118 pthread_cond_broadcast(&dev->wait_next_vol);
119 pthread_cond_broadcast(&wait_device_release);
122 /*********************************************************************
123 * Acquire device for reading.
124 * The drive should have previously been reserved by calling
125 * reserve_device_for_read(). We read the Volume label from the block and
126 * leave the block pointers just after the label.
128 * Returns: NULL if failed for any reason
131 DCR *acquire_device_for_read(DCR *dcr)
133 DEVICE *dev = dcr->dev;
136 bool tape_previously_mounted;
137 bool tape_initially_mounted;
139 bool try_autochanger = true;
141 int vol_label_status;
143 dev->block(BST_DOING_ACQUIRE);
145 if (dev->num_writers > 0) {
146 Jmsg2(jcr, M_FATAL, 0, _("Num_writers=%d not zero. Job %d canceled.\n"),
147 dev->num_writers, jcr->JobId);
151 /* Find next Volume, if any */
154 Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job %d canceled.\n"), jcr->JobId);
158 for (i=1; i<jcr->CurVolume; i++) {
162 goto get_out; /* should not happen */
164 bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
166 init_device_wait_timers(dcr);
168 tape_previously_mounted = dev->can_read() || dev->can_append() ||
170 tape_initially_mounted = tape_previously_mounted;
173 /* Volume info is always needed because of VolParts */
174 Dmsg0(200, "dir_get_volume_info\n");
175 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
176 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
179 for (i=0; i<5; i++) {
180 dev->clear_labeled(); /* force reread of label */
181 if (job_canceled(jcr)) {
182 Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
183 goto get_out; /* error return */
186 * This code ensures that the device is ready for
187 * reading. If it is a file, it opens it.
188 * If it is a tape, it checks the volume name
190 Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName);
191 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
192 if (dev->dev_errno == EIO) { /* no tape loaded */
193 Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed (EIO): ERR=%s\n"),
194 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
198 Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
199 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
202 Dmsg1(100, "opened dev %s OK\n", dev->print_name());
204 /* Read Volume Label */
206 Dmsg0(200, "calling read-vol-label\n");
207 vol_label_status = read_dev_volume_label(dcr);
208 switch (vol_label_status) {
211 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
215 * Send error message generated by read_dev_volume_label()
216 * only we really had a tape mounted. This supresses superfluous
217 * error messages when nothing is mounted.
219 if (tape_previously_mounted) {
220 Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
224 if (tape_initially_mounted) {
225 tape_initially_mounted = false;
230 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
232 tape_previously_mounted = true;
235 * If the device requires mount, close it, so the device can be ejected.
237 if (dev->requires_mount()) {
241 /* Call autochanger only once unless ask_sysop called */
242 if (try_autochanger) {
244 Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
245 dcr->VolumeName, dcr->VolCatInfo.Slot);
246 stat = autoload_device(dcr, 0, NULL);
248 try_autochanger = false;
249 continue; /* try reading volume mounted */
253 /* Mount a specific volume and no other */
254 Dmsg0(200, "calling dir_ask_sysop\n");
255 if (!dir_ask_sysop_to_mount_volume(dcr)) {
256 goto get_out; /* error return */
258 try_autochanger = true; /* permit using autochanger again */
259 continue; /* try reading again */
264 Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"),
271 set_jcr_job_status(jcr, JS_Running);
272 dir_send_job_status(jcr);
273 Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
274 dcr->VolumeName, dev->print_name());
286 * Acquire device for writing. We permit multiple writers.
287 * If this is the first one, we read the label.
289 * Returns: NULL if failed for any reason
291 * Note, normally reserve_device_for_append() is called
292 * before this routine.
294 DCR *acquire_device_for_append(DCR *dcr)
296 bool release = false;
297 bool recycle = false;
298 bool do_mount = false;
299 DEVICE *dev = dcr->dev;
302 init_device_wait_timers(dcr);
304 dev->block(BST_DOING_ACQUIRE);
305 Dmsg1(190, "acquire_append device is %s\n", dev->is_tape()?"tape":
306 (dev->is_dvd()?"DVD":"disk"));
309 * With the reservation system, this should not happen
311 if (dev->can_read()) {
312 Jmsg1(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev->print_name());
313 Dmsg1(200, "Device %s is busy reading.\n", dev->print_name());
317 if (dev->can_append()) {
318 Dmsg0(190, "device already in append.\n");
320 * Device already in append mode
322 * Check if we have the right Volume mounted
323 * OK if current volume info OK
324 * OK if next volume matches current volume
325 * otherwise mount desired volume obtained from
326 * dir_find_next_appendable_volume
327 * dev->VolHdr.VolumeName is what is in the drive
328 * dcr->VolumeName is what we pass into the routines, or
329 * get back from the subroutines.
331 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
332 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
333 !(dir_find_next_appendable_volume(dcr) &&
334 strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
335 Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
337 /* Release volume reserved by dir_find_next_appendable_volume() */
338 if (dcr->VolumeName[0]) {
339 free_unused_volume(dcr);
341 if (dev->num_writers != 0) {
342 Jmsg3(jcr, M_FATAL, 0, _("Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n"),
343 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
344 Dmsg3(200, "Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n",
345 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
348 /* Wrong tape mounted, release it, then fall through to get correct one */
349 Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
354 * At this point, the correct tape is already mounted, so
355 * we do not need to do mount_next_write_volume(), unless
356 * we need to recycle the tape.
358 recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
359 Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
360 if (recycle && dev->num_writers != 0) {
361 Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
362 " on device %s because it is in use by another job.\n"),
363 dev->VolHdr.VolumeName, dev->print_name());
366 if (dev->num_writers == 0) {
367 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
371 /* Not already in append mode, so mount the device */
372 Dmsg0(190, "Not in append mode, try mount.\n");
373 ASSERT(dev->num_writers == 0);
377 if (do_mount || recycle) {
378 Dmsg0(190, "Do mount_next_write_vol\n");
379 bool mounted = mount_next_write_volume(dcr, release);
381 if (!job_canceled(jcr)) {
382 /* Reduce "noise" -- don't print if job canceled */
383 Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
385 Dmsg1(200, "Could not ready device %s for append.\n",
392 dev->num_writers++; /* we are now a writer */
393 if (jcr->NumVolumes == 0) {
397 if (dcr->reserved_device) {
398 dev->reserved_device--;
399 Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device);
400 dcr->reserved_device = false;
411 if (dcr->reserved_device) {
412 dev->reserved_device--;
413 Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device);
414 dcr->reserved_device = false;
423 * This job is done, so release the device. From a Unix standpoint,
424 * the device remains open.
427 bool release_device(DCR *dcr)
430 DEVICE *dev = dcr->dev;
432 bool was_reading = false;
435 Dmsg1(100, "release_device device is %s\n", dev->is_tape()?"tape":"disk");
437 /* if device is reserved, job never started, so release the reserve here */
438 if (dcr->reserved_device) {
439 dev->reserved_device--;
440 Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device);
441 dcr->reserved_device = false;
444 if (dev->can_read()) {
445 dev->clear_read(); /* clear read bit */
448 /******FIXME**** send read volume usage statistics to director */
450 } else if (dev->num_writers > 0) {
452 * Note if WEOT is set, we are at the end of the tape
453 * and may not be positioned correctly, so the
454 * job_media_record and update_vol_info have already been
455 * done, which means we skip them here.
458 Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
459 if (dev->is_labeled()) {
460 Dmsg0(100, "dir_create_jobmedia_record. Release\n");
461 if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
462 Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
463 dcr->VolCatInfo.VolCatName, jcr->Job);
465 /* If no more writers, write an EOF */
466 if (!dev->num_writers && dev->can_write()) {
468 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
470 if (!dev->at_weot()) {
471 dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */
472 dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */
473 /* Note! do volume update before close, which zaps VolCatInfo */
474 Dmsg0(100, "dir_update_vol_info. Release0\n");
475 dir_update_volume_info(dcr, false); /* send Volume info to Director */
481 * If we reach here, it is most likely because the job
482 * has failed, since the device is not in read mode and
483 * there are no writers. It was probably reserved.
487 /* If no writers, close if file or !CAP_ALWAYS_OPEN */
488 if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
492 /* Fire off Alert command and include any output */
493 if (!job_canceled(jcr) && dcr->device->alert_command) {
497 char line[MAXSTRING];
498 alert = get_pool_memory(PM_FNAME);
499 alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
500 bpipe = open_bpipe(alert, 0, "r");
502 while (fgets(line, sizeof(line), bpipe->rfd)) {
503 Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
505 status = close_bpipe(bpipe);
511 Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
512 alert, be.strerror(status));
515 Dmsg1(400, "alert status=%d\n", status);
516 free_pool_memory(alert);
521 jcr->read_dcr = NULL;