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