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(200, "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 */
116 /*********************************************************************
117 * Acquire device for reading.
118 * The drive should have previously been reserved by calling
119 * reserve_device_for_read(). We read the Volume label from the block and
120 * leave the block pointers just after the label.
122 * Returns: NULL if failed for any reason
125 DCR *acquire_device_for_read(DCR *dcr)
127 DEVICE *dev = dcr->dev;
130 bool tape_previously_mounted;
131 bool tape_initially_mounted;
133 bool try_autochanger = true;
135 int vol_label_status;
137 dev->block(BST_DOING_ACQUIRE);
139 if (dev->num_writers > 0) {
140 Jmsg2(jcr, M_FATAL, 0, _("Num_writers=%d not zero. Job %d canceled.\n"),
141 dev->num_writers, jcr->JobId);
145 /* Find next Volume, if any */
148 Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job %d canceled.\n"), jcr->JobId);
152 for (i=1; i<jcr->CurVolume; i++) {
156 goto get_out; /* should not happen */
158 bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
160 init_device_wait_timers(dcr);
162 tape_previously_mounted = dev->can_read() || dev->can_append() ||
164 tape_initially_mounted = tape_previously_mounted;
167 /* Volume info is always needed because of VolParts */
168 Dmsg0(200, "dir_get_volume_info\n");
169 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
170 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
173 for (i=0; i<5; i++) {
174 dev->clear_labeled(); /* force reread of label */
175 if (job_canceled(jcr)) {
176 Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
177 goto get_out; /* error return */
180 * This code ensures that the device is ready for
181 * reading. If it is a file, it opens it.
182 * If it is a tape, it checks the volume name
184 Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName);
185 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
186 if (dev->dev_errno == EIO) { /* no tape loaded */
187 Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed (EIO): ERR=%s\n"),
188 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
192 Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
193 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
196 Dmsg1(100, "opened dev %s OK\n", dev->print_name());
198 /* Read Volume Label */
200 Dmsg0(200, "calling read-vol-label\n");
201 vol_label_status = read_dev_volume_label(dcr);
202 switch (vol_label_status) {
205 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
209 * Send error message generated by read_dev_volume_label()
210 * only we really had a tape mounted. This supresses superfluous
211 * error messages when nothing is mounted.
213 if (tape_previously_mounted) {
214 Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
218 if (tape_initially_mounted) {
219 tape_initially_mounted = false;
224 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
226 tape_previously_mounted = true;
228 /* If the device requires mount, close it, so the device can be ejected.
229 * FIXME: This should perhaps be done for all devices. */
230 if (dev->requires_mount()) {
231 force_close_device(dev);
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());
279 * Acquire device for writing. We permit multiple writers.
280 * If this is the first one, we read the label.
282 * Returns: NULL if failed for any reason
284 * Note, normally reserve_device_for_append() is called
285 * before this routine.
287 DCR *acquire_device_for_append(DCR *dcr)
289 bool release = false;
290 bool recycle = false;
291 bool do_mount = false;
292 DEVICE *dev = dcr->dev;
295 init_device_wait_timers(dcr);
297 dev->block(BST_DOING_ACQUIRE);
298 Dmsg1(190, "acquire_append device is %s\n", dev->is_tape()?"tape":
299 (dev->is_dvd()?"DVD":"disk"));
301 if (dcr->reserved_device) {
302 dev->reserved_device--;
303 Dmsg1(200, "Dec reserve=%d\n", dev->reserved_device);
304 dcr->reserved_device = false;
308 * With the reservation system, this should not happen
310 if (dev->can_read()) {
311 Jmsg1(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev->print_name());
312 Dmsg1(200, "Device %s is busy reading.\n", dev->print_name());
316 if (dev->can_append()) {
317 Dmsg0(190, "device already in append.\n");
319 * Device already in append mode
321 * Check if we have the right Volume mounted
322 * OK if current volume info OK
323 * OK if next volume matches current volume
324 * otherwise mount desired volume obtained from
325 * dir_find_next_appendable_volume
326 * dev->VolHdr.VolumeName is what is in the drive
327 * dcr->VolumeName is what we pass into the routines, or
328 * get back from the subroutines.
330 bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
331 if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
332 !(dir_find_next_appendable_volume(dcr) &&
333 strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
334 Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
336 /* Release volume reserved by dir_find_next_appendable_volume() */
337 if (dcr->VolumeName[0]) {
338 free_unused_volume(dcr);
340 if (dev->num_writers != 0) {
341 Jmsg3(jcr, M_FATAL, 0, _("Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n"),
342 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
343 Dmsg3(200, "Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n",
344 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
347 /* Wrong tape mounted, release it, then fall through to get correct one */
348 Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
353 * At this point, the correct tape is already mounted, so
354 * we do not need to do mount_next_write_volume(), unless
355 * we need to recycle the tape.
357 recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
358 Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
359 if (recycle && dev->num_writers != 0) {
360 Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
361 " on device %s because it is in use by another job.\n"),
362 dev->VolHdr.VolumeName, dev->print_name());
365 if (dev->num_writers == 0) {
366 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
370 /* Not already in append mode, so mount the device */
371 Dmsg0(190, "Not in append mode, try mount.\n");
372 ASSERT(dev->num_writers == 0);
376 if (do_mount || recycle) {
377 Dmsg0(190, "Do mount_next_write_vol\n");
378 bool mounted = mount_next_write_volume(dcr, release);
380 if (!job_canceled(jcr)) {
381 /* Reduce "noise" -- don't print if job canceled */
382 Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
384 Dmsg1(200, "Could not ready device %s for append.\n",
391 dev->num_writers++; /* we are now a writer */
392 if (jcr->NumVolumes == 0) {
398 * If we jump here, it is an error return because
399 * rtn_dev will still be NULL
410 * This job is done, so release the device. From a Unix standpoint,
411 * the device remains open.
414 bool release_device(DCR *dcr)
417 DEVICE *dev = dcr->dev;
419 bool was_reading = false;
422 Dmsg1(100, "release_device device is %s\n", dev->is_tape()?"tape":"disk");
424 /* if device is reserved, job never started, so release the reserve here */
425 if (dcr->reserved_device) {
426 dev->reserved_device--;
427 Dmsg1(200, "Dec reserve=%d\n", dev->reserved_device);
428 dcr->reserved_device = false;
431 if (dev->can_read()) {
432 dev->clear_read(); /* clear read bit */
435 /******FIXME**** send read volume usage statistics to director */
437 } else if (dev->num_writers > 0) {
439 * Note if WEOT is set, we are at the end of the tape
440 * and may not be positioned correctly, so the
441 * job_media_record and update_vol_info have already been
442 * done, which means we skip them here.
445 Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
446 if (dev->is_labeled()) {
447 Dmsg0(100, "dir_create_jobmedia_record. Release\n");
448 if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
449 Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
450 dcr->VolCatInfo.VolCatName, jcr->Job);
452 /* If no more writers, write an EOF */
453 if (!dev->num_writers && dev->can_write()) {
455 write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
457 if (!dev->at_weot()) {
458 dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */
459 dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */
460 /* Note! do volume update before close, which zaps VolCatInfo */
461 Dmsg0(100, "dir_update_vol_info. Release0\n");
462 dir_update_volume_info(dcr, false); /* send Volume info to Director */
468 * If we reach here, it is most likely because the job
469 * has failed, since the device is not in read mode and
470 * there are no writers. It was probably reserved.
474 /* If no writers, close if file or !CAP_ALWAYS_OPEN */
475 if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
476 offline_or_rewind_dev(dev);
480 /* Fire off Alert command and include any output */
481 if (!job_canceled(jcr) && dcr->device->alert_command) {
485 char line[MAXSTRING];
486 alert = get_pool_memory(PM_FNAME);
487 alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
488 bpipe = open_bpipe(alert, 0, "r");
490 while (fgets(line, sizeof(line), bpipe->rfd)) {
491 Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
493 status = close_bpipe(bpipe);
499 Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
500 alert, be.strerror(status));
503 Dmsg1(400, "alert status=%d\n", status);
504 free_pool_memory(alert);
509 jcr->read_dcr = NULL;
513 pthread_cond_broadcast(&wait_device_release);