]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/acquire.c
Vacation work -- see tech log
[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-2005 Kern Sibbald
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  * Create a new Device Control Record and attach
33  *   it to the device (if this is a real job).
34  */
35 DCR *new_dcr(JCR *jcr, DEVICE *dev)
36 {
37    if (jcr && jcr->dcr) {
38       return jcr->dcr;
39    }
40    DCR *dcr = (DCR *)malloc(sizeof(DCR));
41    memset(dcr, 0, sizeof(DCR));
42    if (jcr) {
43       jcr->dcr = dcr;
44    }
45    dcr->jcr = jcr;
46    dcr->dev = dev;
47    if (dev) {
48       dcr->device = dev->device;
49    }
50    dcr->block = new_block(dev);
51    dcr->rec = new_record();
52    dcr->spool_fd = -1;
53    dcr->max_spool_size = dev->device->max_spool_size;
54    /* Attach this dcr only if dev is initialized */
55    if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
56       dev->attached_dcrs->append(dcr);
57    }
58    return dcr;
59 }
60
61 void free_dcr(DCR *dcr)
62 {
63    JCR *jcr = dcr->jcr;
64    DEVICE *dev = dcr->dev;
65
66    /*
67     * If we reserved the device, we must decrement the
68     *  number of writers.
69     */
70    if (dcr->reserved_device) {
71       lock_device(dev);
72       dev->num_writers--;
73       unlock_device(dev);
74    }
75
76    /* Detach this dcr only if the dev is initialized */
77    if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
78       dcr->dev->attached_dcrs->remove(dcr);
79    }
80    if (dcr->block) {
81       free_block(dcr->block);
82    }
83    if (dcr->rec) {
84       free_record(dcr->rec);
85    }
86    if (dcr->jcr) {
87       dcr->jcr->dcr = NULL;
88    }
89    free(dcr);
90 }
91
92 /*
93  * We "reserve" the drive by setting the ST_READ bit. No one else
94  *  should touch the drive until that is cleared.
95  *  This allows the DIR to "reserve" the device before actually
96  *  starting the job. If the device is not available, the DIR
97  *  can wait (to be implemented 1/05).
98  */
99 bool reserve_device_for_read(JCR *jcr, DEVICE *dev)
100 {
101    DCR *dcr = jcr->dcr;
102    bool ok = false;
103
104    ASSERT(dcr);
105    if (device_is_unmounted(dev)) {
106       Jmsg(jcr, M_WARNING, 0, _("device %s is BLOCKED due to user unmount.\n"),
107          dev_name(dev));
108       return false;
109    }
110    lock_device(dev);
111    block_device(dev, BST_DOING_ACQUIRE);
112    unlock_device(dev);
113
114    if (dev->can_read() || dev->num_writers > 0) {
115       Jmsg2(jcr, M_FATAL, 0, _("Device %s is busy. Job %d canceled.\n"),
116             dev_name(dev), jcr->JobId);
117       goto get_out;
118    }
119    if (!dcr) {
120       dcr = new_dcr(jcr, dev);
121    }
122    dev->state &= ~ST_APPEND;          /* clear any previous append mode */
123    dev->state |= ST_READ;             /* set read mode */
124    ok = true;
125
126 get_out:
127    P(dev->mutex);
128    unblock_device(dev);
129    V(dev->mutex);
130    return ok;
131 }
132
133
134 /*********************************************************************
135  * Acquire device for reading. 
136  *  The drive should have previously been reserved by calling 
137  *  reserve_device_for_read(). We read the Volume label from the block and
138  *  leave the block pointers just after the label.
139  *
140  *  Returns: NULL if failed for any reason
141  *           dcr  if successful
142  */
143 DCR *acquire_device_for_read(JCR *jcr, DEVICE *dev)
144 {
145    bool vol_ok = false;
146    bool tape_previously_mounted;
147    bool tape_initially_mounted;
148    VOL_LIST *vol;
149    bool try_autochanger = true;
150    int i;
151    DCR *dcr = jcr->dcr;
152    int vol_label_status;
153    
154    lock_device(dev);
155    block_device(dev, BST_DOING_ACQUIRE);
156    unlock_device(dev);
157
158    init_dev_wait_timers(dev);
159
160    tape_previously_mounted = dev->can_read() ||
161                              dev->can_append() ||
162                              dev->is_labeled();
163    tape_initially_mounted = tape_previously_mounted;
164
165    /* Find next Volume, if any */
166    vol = jcr->VolList;
167    if (!vol) {
168       Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job %d canceled.\n"), jcr->JobId);
169       goto get_out;
170    }
171    jcr->CurVolume++;
172    for (i=1; i<jcr->CurVolume; i++) {
173       vol = vol->next;
174    }
175    bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
176
177    /* Volume info is always needed because of VolParts */
178    Dmsg0(200, "dir_get_volume_info\n");
179    if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
180       Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
181    }
182    
183    dev->num_parts = dcr->VolCatInfo.VolCatParts;
184    
185    for (i=0; i<5; i++) {
186       dev->state &= ~ST_LABEL;           /* force reread of label */
187       if (job_canceled(jcr)) {
188          Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
189          goto get_out;                /* error return */
190       }
191       /*
192        * This code ensures that the device is ready for
193        * reading. If it is a file, it opens it.
194        * If it is a tape, it checks the volume name
195        */
196       for ( ; !dev->is_open(); ) {
197          Dmsg1(120, "bstored: open vol=%s\n", dcr->VolumeName);
198          if (open_dev(dev, dcr->VolumeName, OPEN_READ_ONLY) < 0) {
199             if (dev->dev_errno == EIO) {   /* no tape loaded */
200                goto default_path;
201             }
202             
203             /* If we have a dvd that requires mount, 
204              * we need to try to open the label, so the info can be reported
205              * if a wrong volume has been mounted. */
206             if (dev->is_dvd() && (dcr->VolCatInfo.VolCatParts > 0)) {
207                break;
208             }
209             
210             Jmsg(jcr, M_FATAL, 0, _("Open device %s volume %s failed, ERR=%s\n"),
211                 dev_name(dev), dcr->VolumeName, strerror_dev(dev));
212             goto get_out;
213          }
214          Dmsg1(129, "open_dev %s OK\n", dev_name(dev));
215       }
216       
217       if (dev->is_dvd()) {
218          vol_label_status = read_dev_volume_label_guess(dcr, 0);
219       } else {
220          vol_label_status = read_dev_volume_label(dcr);
221       }
222       
223       /****FIXME***** do not reread label if ioctl() says we are
224        *  correctly possitioned.  Possibly have way user can turn
225        *  this optimization (to be implemented) off.
226        */
227       Dmsg0(200, "calling read-vol-label\n");
228       switch (vol_label_status) {
229       case VOL_OK:
230          vol_ok = true;
231          memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
232          break;                    /* got it */
233       case VOL_IO_ERROR:
234          /*
235           * Send error message generated by read_dev_volume_label()
236           *  only we really had a tape mounted. This supresses superfluous
237           *  error messages when nothing is mounted.
238           */
239          if (tape_previously_mounted) {
240             Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
241          }
242          goto default_path;
243       case VOL_NAME_ERROR:
244          if (tape_initially_mounted) {
245             tape_initially_mounted = false;
246             goto default_path;
247          }
248          /* Fall through */
249       default:
250          Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
251 default_path:
252          tape_previously_mounted = true;
253          
254          /* If the device requires mount, close it, so the device can be ejected.
255           * FIXME: This should perhaps be done for all devices. */
256          if (dev_cap(dev, CAP_REQMOUNT)) {
257             force_close_dev(dev);
258          }
259          
260          /* Call autochanger only once unless ask_sysop called */
261          if (try_autochanger) {
262             int stat;
263             Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
264                dcr->VolumeName, dcr->VolCatInfo.Slot);
265             stat = autoload_device(dcr, 0, NULL);
266             if (stat > 0) {
267                try_autochanger = false;
268                continue;
269             }
270          }
271          
272          /* Mount a specific volume and no other */
273          Dmsg0(200, "calling dir_ask_sysop\n");
274          if (!dir_ask_sysop_to_mount_volume(dcr)) {
275             goto get_out;             /* error return */
276          }
277          try_autochanger = true;      /* permit using autochanger again */
278          continue;                    /* try reading again */
279       } /* end switch */
280       break;
281    } /* end for loop */
282    if (!vol_ok) {
283       Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device \"%s\".\n"),
284             dev_name(dev));
285       goto get_out;
286    }
287
288    dev->state &= ~ST_APPEND;          /* clear any previous append mode */
289    dev->state |= ST_READ;             /* set read mode */
290    set_jcr_job_status(jcr, JS_Running);
291    dir_send_job_status(jcr);
292    Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
293       dcr->VolumeName, dev_name(dev));
294
295 get_out:
296    P(dev->mutex);
297    unblock_device(dev);
298    V(dev->mutex);
299    if (!vol_ok) {
300       free_dcr(dcr);
301       dcr = NULL;
302    }
303    return dcr;
304 }
305
306 /*
307  * We reserve the device for appending by incrementing the 
308  *  reserved_device. We do virtually all the same work that
309  *  is done in acquire_device_for_append(), but we do
310  *  not attempt to mount the device. This routine allows
311  *  the DIR to reserve multiple devices before *really* 
312  *  starting the job. It also permits the SD to refuse 
313  *  certain devices (not up, ...).
314  */
315 bool reserve_device_for_append(JCR *jcr, DEVICE *dev)
316 {
317    DCR *dcr = jcr->dcr;
318    bool recycle;
319    bool ok = false;
320
321    ASSERT(dcr);
322
323    lock_device(dev);
324    block_device(dev, BST_DOING_ACQUIRE);
325    unlock_device(dev);
326    if (device_is_unmounted(dev)) {
327       Jmsg(jcr, M_WARNING, 0, _("device %s is BLOCKED due to user unmount.\n"),
328          dev_name(dev));
329       goto get_out;
330    }
331    Dmsg1(190, "reserve_append device is %s\n", dev_is_tape(dev)?"tape":"disk");
332    if (dev->can_append()) {
333       Dmsg0(190, "device already in append.\n");
334       /*
335        * Device already in append mode
336        *
337        * Check if we have the right Volume mounted
338        *   OK if current volume info OK
339        *   OK if next volume matches current volume
340        */
341       bstrncpy(dcr->VolumeName, dev->VolHdr.VolName, sizeof(dcr->VolumeName));
342       if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
343           !(dir_find_next_appendable_volume(dcr) &&
344             strcmp(dev->VolHdr.VolName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
345          Dmsg0(190, "Wrong tape mounted.\n");
346          if (dev->num_writers != 0 || dev->reserved_device) {
347             Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev));
348             goto get_out;
349          }
350       } else {
351          /*
352           * At this point, the correct tape is already mounted, so
353           *   we do not need to do mount_next_write_volume(), unless
354           *   we need to recycle the tape.
355           */
356           recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
357           Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
358           if (recycle && dev->num_writers != 0) {
359              Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
360                   " because it is in use by another job.\n"));
361              goto get_out;
362           }
363           if (dev->num_writers == 0) {
364              memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
365           }
366        }
367    } else {
368       if (dev->can_read()) {
369          Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev));
370          goto get_out;
371       }
372       ASSERT(dev->num_writers == 0);
373    }
374
375    dev->reserved_device++;
376    dcr->reserved_device = true;
377    ok = true;
378
379 get_out:
380    P(dev->mutex);
381    unblock_device(dev);
382    V(dev->mutex);
383    return ok;
384 }
385
386 /*
387  * Acquire device for writing. We permit multiple writers.
388  *  If this is the first one, we read the label.
389  *
390  *  Returns: NULL if failed for any reason
391  *           dcr if successful.
392  *   Note, normally reserve_device_for_append() is called
393  *   before this routine.
394  */
395 DCR *acquire_device_for_append(JCR *jcr, DEVICE *dev)
396 {
397    bool release = false;
398    bool recycle = false;
399    bool do_mount = false;
400    DCR *dcr = jcr->dcr;
401
402    if (!dcr) {
403       dcr = new_dcr(jcr, dev);
404    }
405    lock_device(dev);
406    block_device(dev, BST_DOING_ACQUIRE);
407    unlock_device(dev);
408    Dmsg1(190, "acquire_append device is %s\n", dev_is_tape(dev)?"tape":"disk");
409
410    if (dcr->reserved_device) {
411       dev->reserved_device--;
412       dcr->reserved_device = false;
413    }
414    if (dev->can_append()) {
415       Dmsg0(190, "device already in append.\n");
416       /*
417        * Device already in append mode
418        *
419        * Check if we have the right Volume mounted
420        *   OK if current volume info OK
421        *   OK if next volume matches current volume
422        *   otherwise mount desired volume obtained from
423        *    dir_find_next_appendable_volume
424        */
425       bstrncpy(dcr->VolumeName, dev->VolHdr.VolName, sizeof(dcr->VolumeName));
426       if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
427           !(dir_find_next_appendable_volume(dcr) &&
428             strcmp(dev->VolHdr.VolName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
429          Dmsg0(190, "Wrong tape mounted.\n");
430          if (dev->num_writers != 0 || dev->reserved_device) {
431             Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev));
432             goto get_out;
433          }
434          /* Wrong tape mounted, release it, then fall through to get correct one */
435          Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
436          release = true;
437          do_mount = true;
438       } else {
439          /*
440           * At this point, the correct tape is already mounted, so
441           *   we do not need to do mount_next_write_volume(), unless
442           *   we need to recycle the tape.
443           */
444           recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
445           Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
446           if (recycle && dev->num_writers != 0) {
447              Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
448                   " because it is in use by another job.\n"));
449              goto get_out;
450           }
451           if (dev->num_writers == 0) {
452              memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
453           }
454        }
455    } else {
456       /* Not already in append mode, so mount the device */
457       Dmsg0(190, "Not in append mode, try mount.\n");
458       if (dev->can_read()) {
459          Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev));
460          goto get_out;
461       }
462       ASSERT(dev->num_writers == 0);
463       do_mount = true;
464    }
465
466    if (do_mount || recycle) {
467       Dmsg0(190, "Do mount_next_write_vol\n");
468       bool mounted = mount_next_write_volume(dcr, release);
469       if (!mounted) {
470          if (!job_canceled(jcr)) {
471             /* Reduce "noise" -- don't print if job canceled */
472             Jmsg(jcr, M_FATAL, 0, _("Could not ready device \"%s\" for append.\n"),
473                dev_name(dev));
474          }
475          goto get_out;
476       }
477    }
478
479    dev->num_writers++;
480    if (jcr->NumVolumes == 0) {
481       jcr->NumVolumes = 1;
482    }
483    goto ok_out;
484
485 /*
486  * If we jump here, it is an error return because
487  *  rtn_dev will still be NULL
488  */
489 get_out:
490    free_dcr(dcr);
491    dcr = NULL;
492 ok_out:
493    P(dev->mutex);
494    unblock_device(dev);
495    V(dev->mutex);
496    return dcr;
497 }
498
499 /*
500  * This job is done, so release the device. From a Unix standpoint,
501  *  the device remains open.
502  *
503  */
504 bool release_device(JCR *jcr)
505 {
506    DCR *dcr = jcr->dcr;
507    DEVICE *dev = dcr->dev;
508    lock_device(dev);
509    Dmsg1(100, "release_device device is %s\n", dev_is_tape(dev)?"tape":"disk");
510    if (dev_state(dev, ST_READ)) {
511       dev->state &= ~ST_READ;         /* clear read bit */
512       if (!dev_is_tape(dev) || !dev_cap(dev, CAP_ALWAYSOPEN)) {
513          offline_or_rewind_dev(dev);
514          close_dev(dev);
515       }
516       /******FIXME**** send read volume usage statistics to director */
517
518    } else if (dev->num_writers > 0) {
519       dev->num_writers--;
520       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
521       if (dev->is_labeled()) {
522          Dmsg0(100, "dir_create_jobmedia_record. Release\n");
523          if (!dir_create_jobmedia_record(dcr)) {
524             Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
525                dcr->VolCatInfo.VolCatName, jcr->Job);
526          }
527          /* If no more writers, write an EOF */
528          if (!dev->num_writers && dev_can_write(dev)) {
529             weof_dev(dev, 1);
530          }
531          dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
532          dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
533          /* Note! do volume update before close, which zaps VolCatInfo */
534          Dmsg0(100, "dir_update_vol_info. Release0\n");
535          dir_update_volume_info(dcr, false); /* send Volume info to Director */
536       }
537
538       if (!dev->num_writers && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
539          offline_or_rewind_dev(dev);
540          close_dev(dev);
541       }
542    } else {
543       Jmsg2(jcr, M_FATAL, 0, _("BAD ERROR: release_device %s, Volume \"%s\" not in use.\n"),
544             dev_name(dev), NPRT(dcr->VolumeName));
545       Jmsg2(jcr, M_ERROR, 0, _("num_writers=%d state=%x\n"), dev->num_writers, dev->state);
546    }
547
548    /* Fire off Alert command and include any output */
549    if (!job_canceled(jcr) && dcr->device->alert_command) {
550       POOLMEM *alert;
551       int status = 1;
552       BPIPE *bpipe;
553       char line[MAXSTRING];
554       alert = get_pool_memory(PM_FNAME);
555       alert = edit_device_codes(dcr, alert, "");
556       bpipe = open_bpipe(alert, 0, "r");
557       if (bpipe) {
558          while (fgets(line, sizeof(line), bpipe->rfd)) {
559             Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
560          }
561          status = close_bpipe(bpipe);
562       } else {
563          status = errno;
564       }
565       if (status != 0) {
566          berrno be;
567          Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
568               alert, be.strerror(status));
569       }
570
571       Dmsg1(400, "alert status=%d\n", status);
572       free_pool_memory(alert);
573    }
574    unlock_device(dev);
575    free_dcr(jcr->dcr);
576    jcr->dcr = NULL;
577    return true;
578 }