]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/acquire.c
- Add more documentation to mtx-changer.in
[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
13    version 2 as ammended with additional clauses defined in the
14    file LICENSE in the main source directory.
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 
19    the file LICENSE for additional details.
20
21  */
22
23 #include "bacula.h"                   /* pull in global headers */
24 #include "stored.h"                   /* pull in Storage Deamon headers */
25
26 /*
27  * Create a new Device Control Record and attach
28  *   it to the device (if this is a real job).
29  */
30 DCR *new_dcr(JCR *jcr, DEVICE *dev)
31 {
32    if (jcr && jcr->dcr) {
33       return jcr->dcr;
34    }
35    DCR *dcr = (DCR *)malloc(sizeof(DCR));
36    memset(dcr, 0, sizeof(DCR));
37    if (jcr) {
38       jcr->dcr = dcr;
39    }
40    dcr->jcr = jcr;
41    dcr->dev = dev;
42    if (dev) {
43       dcr->device = dev->device;
44    }
45    dcr->block = new_block(dev);
46    dcr->rec = new_record();
47    dcr->spool_fd = -1;
48    dcr->max_job_spool_size = dev->device->max_job_spool_size;
49    /* Attach this dcr only if dev is initialized */
50    if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
51       dev->attached_dcrs->append(dcr);  /* attach dcr to device */
52 //    jcr->dcrs->append(dcr);         /* put dcr in list for Job */
53    }
54    return dcr;
55 }
56
57 /*
58  * Search the dcrs list for the given dcr. If it is found,
59  *  as it should be, then remove it. Also zap the jcr pointer
60  *  to the dcr if it is the same one.
61  */
62 #ifdef needed
63 static void remove_dcr_from_dcrs(DCR *dcr)
64 {
65    JCR *jcr = dcr->jcr;
66    if (jcr->dcrs) {
67       int i = 0;
68       DCR *ldcr;
69       int num = jcr->dcrs->size();
70       for (i=0; i < num; i++) {
71          ldcr = (DCR *)jcr->dcrs->get(i);
72          if (ldcr == dcr) {
73             jcr->dcrs->remove(i);
74             if (jcr->dcr == dcr) {
75                jcr->dcr = NULL;
76             }
77          }
78       }
79    }
80 }
81 #endif
82
83 /*
84  * Free up all aspects of the given dcr -- i.e. dechain it,
85  *  release allocated memory, zap pointers, ...
86  */
87 void free_dcr(DCR *dcr)
88 {
89    JCR *jcr = dcr->jcr;
90    DEVICE *dev = dcr->dev;
91
92    /*
93     * If we reserved the device, we must decrement the
94     *  number of writers.
95     */
96    if (dcr->reserved_device) {
97       lock_device(dev);
98       dev->num_writers--;
99       if (dev->num_writers < 0) {
100          Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers);
101          dev->num_writers = 0;
102          dcr->reserved_device = false;
103       }
104       unlock_device(dev);
105    }
106
107    /* Detach this dcr only if the dev is initialized */
108    if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
109       dev->attached_dcrs->remove(dcr);  /* detach dcr from device */
110 //    remove_dcr_from_dcrs(dcr);      /* remove dcr from jcr list */
111    }
112    if (dcr->block) {
113       free_block(dcr->block);
114    }
115    if (dcr->rec) {
116       free_record(dcr->rec);
117    }
118    if (dcr->jcr) {
119       dcr->jcr->dcr = NULL;
120    }
121    free(dcr);
122 }
123
124 /*********************************************************************
125  * Acquire device for reading. 
126  *  The drive should have previously been reserved by calling 
127  *  reserve_device_for_read(). We read the Volume label from the block and
128  *  leave the block pointers just after the label.
129  *
130  *  Returns: NULL if failed for any reason
131  *           dcr  if successful
132  */
133 DCR *acquire_device_for_read(DCR *dcr)
134 {
135    DEVICE *dev = dcr->dev;
136    JCR *jcr = dcr->jcr;
137    bool vol_ok = false;
138    bool tape_previously_mounted;
139    bool tape_initially_mounted;
140    VOL_LIST *vol;
141    bool try_autochanger = true;
142    int i;
143    int vol_label_status;
144    
145    dev->block(BST_DOING_ACQUIRE);
146
147    if (dev->num_writers > 0) {
148       Jmsg2(jcr, M_FATAL, 0, _("Num_writers=%d not zero. Job %d canceled.\n"), 
149          dev->num_writers, jcr->JobId);
150       goto get_out;
151    }
152
153    /* Find next Volume, if any */
154    vol = jcr->VolList;
155    if (!vol) {
156       Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job %d canceled.\n"), jcr->JobId);
157       goto get_out;
158    }
159    jcr->CurVolume++;
160    for (i=1; i<jcr->CurVolume; i++) {
161       vol = vol->next;
162    }
163    if (!vol) {
164       goto get_out;                   /* should not happen */   
165    }
166    bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
167
168    init_device_wait_timers(dcr);
169
170    tape_previously_mounted = dev->can_read() || dev->can_append() ||
171                              dev->is_labeled();
172    tape_initially_mounted = tape_previously_mounted;
173
174
175    /* Volume info is always needed because of VolParts */
176    Dmsg0(200, "dir_get_volume_info\n");
177    if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
178       Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
179    }
180    
181    dev->num_parts = dcr->VolCatInfo.VolCatParts;
182    
183    for (i=0; i<5; i++) {
184       dev->clear_labeled();              /* force reread of label */
185       if (job_canceled(jcr)) {
186          Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
187          goto get_out;                /* error return */
188       }
189       /*
190        * This code ensures that the device is ready for
191        * reading. If it is a file, it opens it.
192        * If it is a tape, it checks the volume name
193        */
194       for ( ; !dev->is_open(); ) {
195          Dmsg1(120, "bstored: open vol=%s\n", dcr->VolumeName);
196          if (open_dev(dev, dcr->VolumeName, OPEN_READ_ONLY) < 0) {
197             if (dev->dev_errno == EIO) {   /* no tape loaded */
198               Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
199                     dev->print_name(), dcr->VolumeName, strerror_dev(dev));
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             Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
211                 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
212             goto get_out;
213          }
214          Dmsg1(129, "open_dev %s OK\n", dev->print_name());
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       Dmsg0(200, "calling read-vol-label\n");
224       switch (vol_label_status) {
225       case VOL_OK:
226          vol_ok = true;
227          memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
228          break;                    /* got it */
229       case VOL_IO_ERROR:
230          /*
231           * Send error message generated by read_dev_volume_label()
232           *  only we really had a tape mounted. This supresses superfluous
233           *  error messages when nothing is mounted.
234           */
235          if (tape_previously_mounted) {
236             Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
237          }
238          goto default_path;
239       case VOL_NAME_ERROR:
240          if (tape_initially_mounted) {
241             tape_initially_mounted = false;
242             goto default_path;
243          }
244          /* Fall through */
245       default:
246          Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
247 default_path:
248          tape_previously_mounted = true;
249          
250          /* If the device requires mount, close it, so the device can be ejected.
251           * FIXME: This should perhaps be done for all devices. */
252          if (dev_cap(dev, CAP_REQMOUNT)) {
253             force_close_dev(dev);
254          }
255          
256          /* Call autochanger only once unless ask_sysop called */
257          if (try_autochanger) {
258             int stat;
259             Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
260                dcr->VolumeName, dcr->VolCatInfo.Slot);
261             stat = autoload_device(dcr, 0, NULL);
262             if (stat > 0) {
263                try_autochanger = false;
264                continue;              /* try reading volume mounted */
265             }
266          }
267          
268          /* Mount a specific volume and no other */
269          Dmsg0(200, "calling dir_ask_sysop\n");
270          if (!dir_ask_sysop_to_mount_volume(dcr)) {
271             goto get_out;             /* error return */
272          }
273          try_autochanger = true;      /* permit using autochanger again */
274          continue;                    /* try reading again */
275       } /* end switch */
276       break;
277    } /* end for loop */
278    if (!vol_ok) {
279       Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"),
280             dev->print_name());
281       goto get_out;
282    }
283
284    dev->clear_append();
285    dev->set_read();
286    set_jcr_job_status(jcr, JS_Running);
287    dir_send_job_status(jcr);
288    Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
289       dcr->VolumeName, dev->print_name());
290
291 get_out:
292    dev->unblock();
293    if (!vol_ok) {
294       free_dcr(dcr);
295       dcr = NULL;
296    }
297    return dcr;
298 }
299
300
301 /*
302  * Acquire device for writing. We permit multiple writers.
303  *  If this is the first one, we read the label.
304  *
305  *  Returns: NULL if failed for any reason
306  *           dcr if successful.
307  *   Note, normally reserve_device_for_append() is called
308  *   before this routine.
309  */
310 DCR *acquire_device_for_append(DCR *dcr)
311 {
312    bool release = false;
313    bool recycle = false;
314    bool do_mount = false;
315    DEVICE *dev = dcr->dev;
316    JCR *jcr = dcr->jcr;
317
318    init_device_wait_timers(dcr);
319
320    dev->block(BST_DOING_ACQUIRE);
321    Dmsg1(190, "acquire_append device is %s\n", dev->is_tape()?"tape":"disk");
322
323    if (dcr->reserved_device) {
324       dev->reserved_device--;
325       dcr->reserved_device = false;
326    }
327
328    /*
329     * With the reservation system, this should not happen
330     */
331    if (dev->can_read()) {
332       Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev->print_name());
333       goto get_out;
334    }
335
336    if (dev->can_append()) {
337       Dmsg0(190, "device already in append.\n");
338       /*
339        * Device already in append mode
340        *
341        * Check if we have the right Volume mounted
342        *   OK if current volume info OK
343        *   OK if next volume matches current volume
344        *   otherwise mount desired volume obtained from
345        *    dir_find_next_appendable_volume
346        */
347       bstrncpy(dcr->VolumeName, dev->VolHdr.VolName, sizeof(dcr->VolumeName));
348       if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
349           !(dir_find_next_appendable_volume(dcr) &&
350             strcmp(dev->VolHdr.VolName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
351          Dmsg0(190, "Wrong tape mounted.\n");
352          if (dev->num_writers != 0 || dev->reserved_device) {
353             Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
354             goto get_out;
355          }
356          /* Wrong tape mounted, release it, then fall through to get correct one */
357          Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
358          release = true;
359          do_mount = true;
360       } else {
361          /*
362           * At this point, the correct tape is already mounted, so
363           *   we do not need to do mount_next_write_volume(), unless
364           *   we need to recycle the tape.
365           */
366           recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
367           Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
368           if (recycle && dev->num_writers != 0) {
369              Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
370                   " on device %s because it is in use by another job.\n"),
371                   dev->VolHdr.VolName, dev->print_name());
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       /* Not already in append mode, so mount the device */
380       Dmsg0(190, "Not in append mode, try mount.\n");
381       ASSERT(dev->num_writers == 0);
382       do_mount = true;
383    }
384
385    if (do_mount || recycle) {
386       Dmsg0(190, "Do mount_next_write_vol\n");
387       bool mounted = mount_next_write_volume(dcr, release);
388       if (!mounted) {
389          if (!job_canceled(jcr)) {
390             /* Reduce "noise" -- don't print if job canceled */
391             Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
392                dev->print_name());
393          }
394          goto get_out;
395       }
396    }
397
398    dev->num_writers++;                /* we are now a writer */
399    if (jcr->NumVolumes == 0) {
400       jcr->NumVolumes = 1;
401    }
402    goto ok_out;
403
404 /*
405  * If we jump here, it is an error return because
406  *  rtn_dev will still be NULL
407  */
408 get_out:
409    free_dcr(dcr);
410    dcr = NULL;
411 ok_out:
412    dev->unblock();
413    return dcr;
414 }
415
416 /*
417  * This job is done, so release the device. From a Unix standpoint,
418  *  the device remains open.
419  *
420  */
421 bool release_device(DCR *dcr)
422 {
423    JCR *jcr = dcr->jcr;
424    DEVICE *dev = dcr->dev;
425    bool ok = true;
426
427    lock_device(dev);
428    Dmsg1(100, "release_device device is %s\n", dev->is_tape()?"tape":"disk");
429
430    /* if device is reserved, job never started, so release the reserve here */
431    if (dcr->reserved_device) {
432       dev->reserved_device--;
433       dcr->reserved_device = false;
434    }
435
436    if (dev->can_read()) {
437       dev->clear_read();              /* clear read bit */
438
439       /******FIXME**** send read volume usage statistics to director */
440
441    } else if (dev->num_writers > 0) {
442       /* 
443        * Note if WEOT is set, we are at the end of the tape
444        *   and may not be positioned correctly, so the
445        *   job_media_record and update_vol_info have already been
446        *   done, which means we skip them here.
447        */
448       dev->num_writers--;
449       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
450       if (dev->is_labeled()) {
451          Dmsg0(100, "dir_create_jobmedia_record. Release\n");
452          if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
453             Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
454                dcr->VolCatInfo.VolCatName, jcr->Job);
455          }
456          /* If no more writers, write an EOF */
457          if (!dev->num_writers && dev->can_write()) {
458             weof_dev(dev, 1);
459             write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolName);
460          }
461          if (!dev->at_weot()) {
462             dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
463             dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
464             /* Note! do volume update before close, which zaps VolCatInfo */
465             Dmsg0(100, "dir_update_vol_info. Release0\n");
466             dir_update_volume_info(dcr, false); /* send Volume info to Director */
467          }
468       }
469
470    } else {
471       /*                
472        * If we reach here, it is most likely because the job
473        *   has failed, since the device is not in read mode and
474        *   there are no writers. It was probably reserved.
475        */
476    }
477
478    /* If no writers, close if file or !CAP_ALWAYS_OPEN */
479    if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
480       offline_or_rewind_dev(dev);
481       close_dev(dev);
482    }
483
484    /* Fire off Alert command and include any output */
485    if (!job_canceled(jcr) && dcr->device->alert_command) {
486       POOLMEM *alert;
487       int status = 1;
488       BPIPE *bpipe;
489       char line[MAXSTRING];
490       alert = get_pool_memory(PM_FNAME);
491       alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
492       bpipe = open_bpipe(alert, 0, "r");
493       if (bpipe) {
494          while (fgets(line, sizeof(line), bpipe->rfd)) {
495             Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
496          }
497          status = close_bpipe(bpipe);
498       } else {
499          status = errno;
500       }
501       if (status != 0) {
502          berrno be;
503          Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
504               alert, be.strerror(status));
505       }
506
507       Dmsg1(400, "alert status=%d\n", status);
508       free_pool_memory(alert);
509    }
510    unlock_device(dev);
511    free_dcr(dcr);
512    jcr->dcr = NULL;
513    pthread_cond_broadcast(&wait_device_release);
514    return ok;
515 }