]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/acquire.c
Document SHA1 + work on returning child status
[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) 2002-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             /*
177              * ***FIXME*** add multiple writers here if permitted   
178              *  find end of dev chain 
179              *   dev->next = init_dev(NULL, dev->device);
180              *   ...
181              */
182             Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev));
183             goto get_out;
184          }
185          /* Wrong tape mounted, release it, then fall through to get correct one */
186          release = 1;
187          do_mount = 1;
188       }
189    } else { 
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));
193          goto get_out;
194       } 
195       ASSERT(dev->num_writers == 0);
196       do_mount = 1;
197    }
198
199    if (do_mount) {
200       if (!mount_next_write_volume(jcr, dev, block, release)) {
201          Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
202             dev_name(dev));
203          goto get_out;
204       }
205    }
206
207    dev->num_writers++;
208    if (dev->num_writers > 1) {
209       Dmsg2(100, "Hey!!!! There are %d writers on device %s\n", dev->num_writers,
210          dev_name(dev));
211    }
212    if (jcr->NumVolumes == 0) {
213       jcr->NumVolumes = 1;
214    }
215    attach_jcr_to_device(dev, jcr);    /* attach jcr to device */
216    stat = 1;                          /* good return */
217
218 get_out:
219    P(dev->mutex); 
220    unblock_device(dev);
221    V(dev->mutex);
222    return stat;
223 }
224
225 /*
226  * This job is done, so release the device. From a Unix standpoint,
227  *  the device remains open.
228  *
229  */
230 int release_device(JCR *jcr, DEVICE *dev)
231 {
232    lock_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)) {
238             offline_dev(dev);
239          }
240          close_dev(dev);
241       }
242       /******FIXME**** send read volume usage statistics to director */
243
244    } else if (dev->num_writers > 0) {
245       dev->num_writers--;
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);
250       } else {
251          jcr->EndBlock = (uint32_t)dev->file_addr;
252          jcr->EndFile = (uint32_t)(dev->file_addr >> 32);
253       }
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);
258          weof_dev(dev, 1);
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 */
264
265          if (!dev_is_tape(dev) || !dev_cap(dev, CAP_ALWAYSOPEN)) {
266             if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
267                offline_dev(dev);
268             }
269             close_dev(dev);
270          }
271       } else {
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 */
278       }
279    } else {
280       Jmsg2(jcr, M_ERROR, 0, _("BAD ERROR: release_device %s, Volume %s not in use.\n"), 
281             dev_name(dev), NPRT(jcr->VolumeName));
282    }
283    detach_jcr_from_device(dev, jcr);
284    unlock_device(dev);
285    return 1;
286 }