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