2 * Routines to acquire and release a device for read/write
4 * Kern Sibbald, August MMII
9 Copyright (C) 2002-2003 Kern Sibbald and John Walker
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of
14 the License, or (at your option) any later version.
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 GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public
22 License along with this program; if not, write to the Free
23 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28 #include "bacula.h" /* pull in global headers */
29 #include "stored.h" /* pull in Storage Deamon headers */
32 /*********************************************************************
33 * Acquire device for reading. We permit (for the moment)
34 * only one reader. We read the Volume label from the block and
35 * leave the block pointers just after the label.
37 * Returns: 0 if failed for any reason
40 int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
43 int tape_previously_mounted;
47 block_device(dev, BST_DOING_ACQUIRE);
50 tape_previously_mounted = (dev->state & ST_READ) || (dev->state & ST_APPEND);
52 if (dev->state & ST_READ || dev->num_writers > 0) {
53 Jmsg1(jcr, M_FATAL, 0, _("Device %s is busy. Job cancelled.\n"), dev_name(dev));
57 /* Find next Volume, if any */
60 Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job cancelled.\n"));
64 for (int i=1; i<jcr->CurVolume; i++) {
67 pm_strcpy(&jcr->VolumeName, vol->VolumeName);
70 if (job_cancelled(jcr)) {
71 Mmsg0(&dev->errmsg, _("Job cancelled.\n"));
72 goto get_out; /* error return */
75 * This code ensures that the device is ready for
76 * reading. If it is a file, it opens it.
77 * If it is a tape, it checks the volume name
79 for ( ; !(dev->state & ST_OPENED); ) {
80 Dmsg1(120, "bstored: open vol=%s\n", jcr->VolumeName);
81 if (open_dev(dev, jcr->VolumeName, READ_ONLY) < 0) {
82 Jmsg(jcr, M_FATAL, 0, _("Open device %s volume %s failed, ERR=%s\n"),
83 dev_name(dev), jcr->VolumeName, strerror_dev(dev));
86 Dmsg1(129, "open_dev %s OK\n", dev_name(dev));
88 dev->state &= ~ST_LABEL; /* force reread of label */
89 Dmsg0(200, "calling read-vol-label\n");
90 switch (read_dev_volume_label(jcr, dev, block)) {
95 * Send error message generated by read_dev_volume_label()
96 * only we really had a tape mounted. This supresses superfluous
97 * error messages when nothing is mounted.
99 if (tape_previously_mounted) {
100 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
104 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
106 tape_previously_mounted = 0;
107 Dmsg0(200, "dir_get_volume_info\n");
108 if (!dir_get_volume_info(jcr, 0)) {
109 Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
111 Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
112 jcr->VolumeName, jcr->VolCatInfo.Slot);
113 if (autoload_device(jcr, dev, 0, NULL)) {
116 /* Mount a specific volume and no other */
117 Dmsg0(200, "calling dir_ask_sysop\n");
118 if (!dir_ask_sysop_to_mount_volume(jcr, dev)) {
119 goto get_out; /* error return */
121 continue; /* try reading again */
126 dev->state |= ST_READ;
127 attach_jcr_to_device(dev, jcr); /* attach jcr to device */
128 stat = 1; /* good return */
129 if ((dev->state & ST_TAPE) && vol->start_file > 0) {
130 Dmsg1(200, "====== Got start_file = %d\n", vol->start_file);
131 Jmsg(jcr, M_INFO, 0, _("Forward spacing to file %d.\n"), vol->start_file);
132 fsf_dev(dev, vol->start_file);
143 * Acquire device for writing. We permit multiple writers.
144 * If this is the first one, we read the label.
146 * Returns: 0 if failed for any reason
149 int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
156 block_device(dev, BST_DOING_ACQUIRE);
158 Dmsg1(190, "acquire_append device is %s\n", dev_is_tape(dev)?"tape":"disk");
161 if (dev->state & ST_APPEND) {
163 * Device already in append mode
165 * Check if we have the right Volume mounted
166 * OK if current volume info OK
167 * OK if next volume matches current volume
168 * otherwise mount desired volume obtained from
169 * dir_find_next_appendable_volume
171 strcpy(jcr->VolumeName, dev->VolHdr.VolName);
172 if (!dir_get_volume_info(jcr, 1) ||
173 !(dir_find_next_appendable_volume(jcr) &&
174 strcmp(dev->VolHdr.VolName, jcr->VolumeName) == 0)) { /* wrong tape mounted */
175 if (dev->num_writers != 0) {
177 * ***FIXME*** add multiple writers here if permitted
178 * find end of dev chain
179 * dev->next = init_dev(NULL, dev->device);
182 Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev));
185 /* Wrong tape mounted, release it, then fall through to get correct one */
190 /* Not already in append mode, so mount the device */
191 if (dev->state & ST_READ) {
192 Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev));
195 ASSERT(dev->num_writers == 0);
200 if (!mount_next_write_volume(jcr, dev, block, release)) {
201 Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
208 if (dev->num_writers > 1) {
209 Dmsg2(100, "Hey!!!! There are %d writers on device %s\n", dev->num_writers,
212 if (jcr->NumVolumes == 0) {
215 attach_jcr_to_device(dev, jcr); /* attach jcr to device */
216 stat = 1; /* good return */
226 * This job is done, so release the device. From a Unix standpoint,
227 * the device remains open.
230 int release_device(JCR *jcr, DEVICE *dev)
233 Dmsg1(100, "release_device device is %s\n", dev_is_tape(dev)?"tape":"disk");
234 if (dev->state & ST_READ) {
235 dev->state &= ~ST_READ; /* clear read bit */
236 if (!dev_is_tape(dev) || !dev_cap(dev, CAP_ALWAYSOPEN)) {
237 if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
242 /******FIXME**** send read volume usage statistics to director */
244 } else if (dev->num_writers > 0) {
246 if (dev->state & ST_TAPE) {
247 jcr->EndBlock = dev->EndBlock;
248 jcr->EndFile = dev->EndFile;
249 Dmsg2(200, "Release device: EndFile=%u EndBlock=%u\n", jcr->EndFile, jcr->EndBlock);
251 jcr->EndBlock = (uint32_t)dev->file_addr;
252 jcr->EndFile = (uint32_t)(dev->file_addr >> 32);
254 Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
255 if (dev->num_writers == 0) {
256 Dmsg0(100, "dir_create_jobmedia_record. Release\n");
257 dir_create_jobmedia_record(jcr);
259 dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */
260 dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */
261 /* Note! do volume update before close, which zaps VolCatInfo */
262 Dmsg0(200, "dir_update_vol_info. Release0\n");
263 dir_update_volume_info(jcr, &dev->VolCatInfo, 0); /* send Volume info to Director */
265 if (!dev_is_tape(dev) || !dev_cap(dev, CAP_ALWAYSOPEN)) {
266 if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
272 Dmsg0(100, "dir_create_jobmedia_record. Release\n");
273 dir_create_jobmedia_record(jcr);
274 Dmsg0(200, "dir_update_vol_info. Release1\n");
275 dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */
276 dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */
277 dir_update_volume_info(jcr, &dev->VolCatInfo, 0); /* send Volume info to Director */
280 Jmsg2(jcr, M_ERROR, 0, _("BAD ERROR: release_device %s, Volume %s not in use.\n"),
281 dev_name(dev), NPRT(jcr->VolumeName));
283 detach_jcr_from_device(dev, jcr);