]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/acquire.c
Status cleanup and cancelling FD
[bacula/bacula] / bacula / src / stored / acquire.c
1 /*
2  *  Routines to acquire and release a device for read/write
3  *
4  *   Kern Sibbald, August MMII
5  *                            
6  *   Version $Id$
7  */
8 /*
9    Copyright (C) 2000-2003 Kern Sibbald and John Walker
10
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.
15
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.
20
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,
24    MA 02111-1307, USA.
25
26  */
27
28 #include "bacula.h"                   /* pull in global headers */
29 #include "stored.h"                   /* pull in Storage Deamon headers */
30
31
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.
36  *
37  *  Returns: 0 if failed for any reason
38  *           1 if successful
39  */
40 int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
41 {
42    int stat = 0;
43    int tape_previously_mounted;
44    VOL_LIST *vol;
45
46    lock_device(dev);
47    block_device(dev, BST_DOING_ACQUIRE);
48    unlock_device(dev);
49
50    tape_previously_mounted = (dev->state & ST_READ) || (dev->state & ST_APPEND);
51
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));
54       goto get_out;
55    }
56
57    /* Find next Volume, if any */
58    vol = jcr->VolList;
59    if (!vol) {
60       Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job cancelled.\n"));
61       goto get_out;
62    }
63    jcr->CurVolume++;
64    for (int i=1; i<jcr->CurVolume; i++) {
65       vol = vol->next;
66    }
67    pm_strcpy(&jcr->VolumeName, vol->VolumeName);
68
69    for (;;) {
70       if (job_cancelled(jcr)) {
71          Mmsg0(&dev->errmsg, _("Job cancelled.\n"));
72          goto get_out;                /* error return */
73       }
74       /*
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 
78        */
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));
84              goto get_out;
85           }
86           Dmsg1(129, "open_dev %s OK\n", dev_name(dev));
87       }
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)) {
91          case VOL_OK:
92             break;                    /* got it */
93          case VOL_IO_ERROR:
94             /*
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.
98              */
99             if (tape_previously_mounted) {
100                Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);                         
101             }
102             goto default_path;
103          default:
104             Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
105 default_path:
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);
110             }
111             Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
112                jcr->VolumeName, jcr->VolCatInfo.Slot);                         
113             if (autoload_device(jcr, dev, 0, NULL)) {
114                continue;
115             }
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 */
120             }
121             continue;                 /* try reading again */
122       }
123       break;
124    }
125
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);
133    }
134
135 get_out:
136    P(dev->mutex); 
137    unblock_device(dev);
138    V(dev->mutex);
139    return stat;
140 }
141
142 /*
143  * Acquire device for writing. We permit multiple writers.
144  *  If this is the first one, we read the label.
145  *
146  *  Returns: 0 if failed for any reason
147  *           1 if successful
148  */
149 int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
150 {
151    int release = 0;
152    int do_mount = 0;
153    int stat = 0;
154
155    lock_device(dev);
156    block_device(dev, BST_DOING_ACQUIRE);
157    unlock_device(dev);
158    Dmsg1(190, "acquire_append device is %s\n", dev_is_tape(dev)?"tape":"disk");
159
160
161    if (dev->state & ST_APPEND) {
162       /* 
163        * Device already in append mode   
164        *
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
170        */
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) {
176             Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev));
177             goto get_out;
178          }
179          /* Wrong tape mounted, release it, then fall through to get correct one */
180          release = 1;
181          do_mount = 1;
182       }
183    } else { 
184       /* Not already in append mode, so mount the device */
185       if (dev->state & ST_READ) {
186          Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev));
187          goto get_out;
188       } 
189       ASSERT(dev->num_writers == 0);
190       do_mount = 1;
191    }
192
193    if (do_mount) {
194       if (!mount_next_write_volume(jcr, dev, block, release)) {
195          Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
196             dev_name(dev));
197          goto get_out;
198       }
199    }
200
201    dev->num_writers++;
202    if (dev->num_writers > 1) {
203       Dmsg2(100, "Hey!!!! There are %d writers on device %s\n", dev->num_writers,
204          dev_name(dev));
205    }
206    if (jcr->NumVolumes == 0) {
207       jcr->NumVolumes = 1;
208    }
209    attach_jcr_to_device(dev, jcr);    /* attach jcr to device */
210    stat = 1;                          /* good return */
211
212 get_out:
213    P(dev->mutex); 
214    unblock_device(dev);
215    V(dev->mutex);
216    return stat;
217 }
218
219 /*
220  * This job is done, so release the device. From a Unix standpoint,
221  *  the device remains open.
222  *
223  */
224 int release_device(JCR *jcr, DEVICE *dev)
225 {
226    lock_device(dev);
227    Dmsg1(100, "release_device device is %s\n", dev_is_tape(dev)?"tape":"disk");
228    if (dev->state & ST_READ) {
229       dev->state &= ~ST_READ;         /* clear read bit */
230       if (!dev_is_tape(dev) || !(dev->capabilities & CAP_ALWAYSOPEN)) {
231          if (dev->capabilities & CAP_OFFLINEUNMOUNT) {
232             offline_dev(dev);
233          }
234          close_dev(dev);
235       }
236       /******FIXME**** send read volume usage statistics to director */
237
238    } else if (dev->num_writers > 0) {
239       dev->num_writers--;
240       if (dev->state & ST_TAPE) {
241          jcr->EndBlock = dev->EndBlock;
242          jcr->EndFile  = dev->EndFile;
243          Dmsg2(200, "Release device: EndFile=%u EndBlock=%u\n", jcr->EndFile, jcr->EndBlock);
244       } else {
245          jcr->EndBlock = (uint32_t)dev->file_addr;
246          jcr->EndFile = (uint32_t)(dev->file_addr >> 32);
247       }
248       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
249       if (dev->num_writers == 0) {
250          Dmsg0(100, "dir_create_jobmedia_record. Release\n");
251          dir_create_jobmedia_record(jcr);
252          weof_dev(dev, 1);
253          dev->VolCatInfo.VolCatFiles++;             /* increment number of files */
254          dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
255          /* Note! do volume update before close, which zaps VolCatInfo */
256          Dmsg0(200, "dir_update_vol_info. Release0\n");
257          dir_update_volume_info(jcr, &dev->VolCatInfo, 0); /* send Volume info to Director */
258
259          if (!dev_is_tape(dev) || !(dev->capabilities & CAP_ALWAYSOPEN)) {
260             if (dev->capabilities & CAP_OFFLINEUNMOUNT) {
261                offline_dev(dev);
262             }
263             close_dev(dev);
264          }
265       } else {
266          Dmsg0(100, "dir_create_jobmedia_record. Release\n");
267          dir_create_jobmedia_record(jcr);
268          Dmsg0(200, "dir_update_vol_info. Release1\n");
269          dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
270          dir_update_volume_info(jcr, &dev->VolCatInfo, 0); /* send Volume info to Director */
271       }
272    } else {
273       Jmsg2(jcr, M_ERROR, 0, _("BAD ERROR: release_device %s, Volume %s not in use.\n"), 
274             dev_name(dev), NPRT(jcr->VolumeName));
275    }
276    detach_jcr_from_device(dev, jcr);
277    unlock_device(dev);
278    return 1;
279 }