]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/acquire.c
- Modify open() for tape so nonblocking really works.
[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 amended 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    if (dcr->reserved_device) {
93       lock_device(dev);
94       dev->reserved_device--;
95       Dmsg1(200, "Dec reserve=%d\n", dev->reserved_device);
96       dcr->reserved_device = false;
97       if (dev->num_writers < 0) {
98          Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers);
99          dev->num_writers = 0;
100       }
101       unlock_device(dev);
102    }
103
104    /* Detach this dcr only if the dev is initialized */
105    if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
106       dev->attached_dcrs->remove(dcr);  /* detach dcr from device */
107 //    remove_dcr_from_dcrs(dcr);      /* remove dcr from jcr list */
108    }
109    if (dcr->block) {
110       free_block(dcr->block);
111    }
112    if (dcr->rec) {
113       free_record(dcr->rec);
114    }
115    if (dcr->jcr) {
116       dcr->jcr->dcr = NULL;
117    }
118    free_unused_volume(dcr);           /* free unused vols attached to this dcr */
119    free(dcr);
120 }
121
122 /*********************************************************************
123  * Acquire device for reading. 
124  *  The drive should have previously been reserved by calling 
125  *  reserve_device_for_read(). We read the Volume label from the block and
126  *  leave the block pointers just after the label.
127  *
128  *  Returns: NULL if failed for any reason
129  *           dcr  if successful
130  */
131 DCR *acquire_device_for_read(DCR *dcr)
132 {
133    DEVICE *dev = dcr->dev;
134    JCR *jcr = dcr->jcr;
135    bool vol_ok = false;
136    bool tape_previously_mounted;
137    bool tape_initially_mounted;
138    VOL_LIST *vol;
139    bool try_autochanger = true;
140    int i;
141    int vol_label_status;
142    
143    dev->block(BST_DOING_ACQUIRE);
144
145    if (dev->num_writers > 0) {
146       Jmsg2(jcr, M_FATAL, 0, _("Num_writers=%d not zero. Job %d canceled.\n"), 
147          dev->num_writers, jcr->JobId);
148       goto get_out;
149    }
150
151    /* Find next Volume, if any */
152    vol = jcr->VolList;
153    if (!vol) {
154       Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job %d canceled.\n"), jcr->JobId);
155       goto get_out;
156    }
157    jcr->CurVolume++;
158    for (i=1; i<jcr->CurVolume; i++) {
159       vol = vol->next;
160    }
161    if (!vol) {
162       goto get_out;                   /* should not happen */   
163    }
164    bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
165
166    init_device_wait_timers(dcr);
167
168    tape_previously_mounted = dev->can_read() || dev->can_append() ||
169                              dev->is_labeled();
170    tape_initially_mounted = tape_previously_mounted;
171
172
173    /* Volume info is always needed because of VolParts */
174    Dmsg0(200, "dir_get_volume_info\n");
175    if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
176       Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
177    }
178    
179    for (i=0; i<5; i++) {
180       dev->clear_labeled();              /* force reread of label */
181       if (job_canceled(jcr)) {
182          Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
183          goto get_out;                /* error return */
184       }
185       /*
186        * This code ensures that the device is ready for
187        * reading. If it is a file, it opens it.
188        * If it is a tape, it checks the volume name
189        */
190       Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName);
191       if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
192          if (dev->dev_errno == EIO) {   /* no tape loaded */
193            Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed (EIO): ERR=%s\n"),
194                  dev->print_name(), dcr->VolumeName, strerror_dev(dev));
195             goto default_path;
196          }
197          
198 #ifdef xxx_needed
199          /* If we have a dvd that requires mount, 
200           * we need to try to open the label, so the info can be reported
201           * if a wrong volume has been mounted.   
202           */
203          if (dev->is_dvd() && (dcr->VolCatInfo.VolCatParts > 0)) {
204             break;
205          }  
206 #endif
207          
208          Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
209              dev->print_name(), dcr->VolumeName, strerror_dev(dev));
210          goto get_out;
211       }
212       Dmsg1(100, "opened dev %s OK\n", dev->print_name());
213       
214       /* Read Volume Label */
215       
216       Dmsg0(200, "calling read-vol-label\n");
217       vol_label_status = read_dev_volume_label(dcr);
218       switch (vol_label_status) {
219       case VOL_OK:
220          vol_ok = true;
221          memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
222          break;                    /* got it */
223       case VOL_IO_ERROR:
224          /*
225           * Send error message generated by read_dev_volume_label()
226           *  only we really had a tape mounted. This supresses superfluous
227           *  error messages when nothing is mounted.
228           */
229          if (tape_previously_mounted) {
230             Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
231          }
232          goto default_path;
233       case VOL_NAME_ERROR:
234          if (tape_initially_mounted) {
235             tape_initially_mounted = false;
236             goto default_path;
237          }
238          /* Fall through */
239       default:
240          Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
241 default_path:
242          tape_previously_mounted = true;
243          
244          /* If the device requires mount, close it, so the device can be ejected.
245           * FIXME: This should perhaps be done for all devices. */
246          if (dev->requires_mount()) {
247             force_close_device(dev);
248          }
249          
250          /* Call autochanger only once unless ask_sysop called */
251          if (try_autochanger) {
252             int stat;
253             Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
254                dcr->VolumeName, dcr->VolCatInfo.Slot);
255             stat = autoload_device(dcr, 0, NULL);
256             if (stat > 0) {
257                try_autochanger = false;
258                continue;              /* try reading volume mounted */
259             }
260          }
261          
262          /* Mount a specific volume and no other */
263          Dmsg0(200, "calling dir_ask_sysop\n");
264          if (!dir_ask_sysop_to_mount_volume(dcr)) {
265             goto get_out;             /* error return */
266          }
267          try_autochanger = true;      /* permit using autochanger again */
268          continue;                    /* try reading again */
269       } /* end switch */
270       break;
271    } /* end for loop */
272    if (!vol_ok) {
273       Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"),
274             dev->print_name());
275       goto get_out;
276    }
277
278    dev->clear_append();
279    dev->set_read();
280    set_jcr_job_status(jcr, JS_Running);
281    dir_send_job_status(jcr);
282    Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
283       dcr->VolumeName, dev->print_name());
284
285 get_out:
286    dev->unblock();
287    if (!vol_ok) {
288       free_dcr(dcr);
289       dcr = NULL;
290    }
291    return dcr;
292 }
293
294
295 /*
296  * Acquire device for writing. We permit multiple writers.
297  *  If this is the first one, we read the label.
298  *
299  *  Returns: NULL if failed for any reason
300  *           dcr if successful.
301  *   Note, normally reserve_device_for_append() is called
302  *   before this routine.
303  */
304 DCR *acquire_device_for_append(DCR *dcr)
305 {
306    bool release = false;
307    bool recycle = false;
308    bool do_mount = false;
309    DEVICE *dev = dcr->dev;
310    JCR *jcr = dcr->jcr;
311
312    init_device_wait_timers(dcr);
313
314    dev->block(BST_DOING_ACQUIRE);
315    Dmsg1(190, "acquire_append device is %s\n", dev->is_tape()?"tape":
316         (dev->is_dvd()?"DVD":"disk"));
317
318    if (dcr->reserved_device) {
319       dev->reserved_device--;
320       Dmsg1(200, "Dec reserve=%d\n", dev->reserved_device);
321       dcr->reserved_device = false;
322    }
323
324    /*
325     * With the reservation system, this should not happen
326     */
327    if (dev->can_read()) {
328       Jmsg1(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev->print_name());
329       goto get_out;
330    }
331
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        *   otherwise mount desired volume obtained from
341        *    dir_find_next_appendable_volume
342        *  dev->VolHdr.VolumeName is what is in the drive
343        *  dcr->VolumeName is what we pass into the routines, or
344        *    get back from the subroutines.
345        */
346       bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
347       if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
348           !(dir_find_next_appendable_volume(dcr) &&
349             strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
350          Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
351             dcr->VolumeName);
352          /* Release volume reserved by dir_find_next_appendable_volume() */
353          if (dcr->VolumeName[0]) {
354             free_unused_volume(dcr);
355          }
356          if (dev->num_writers != 0 || dev->reserved_device) {
357             Jmsg(jcr, M_FATAL, 0, _("Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n"), 
358                  dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
359             goto get_out;
360          }
361          /* Wrong tape mounted, release it, then fall through to get correct one */
362          Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
363          release = true;
364          do_mount = true;
365       } else {
366          /*
367           * At this point, the correct tape is already mounted, so
368           *   we do not need to do mount_next_write_volume(), unless
369           *   we need to recycle the tape.
370           */
371           recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
372           Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
373           if (recycle && dev->num_writers != 0) {
374              Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
375                   " on device %s because it is in use by another job.\n"),
376                   dev->VolHdr.VolumeName, dev->print_name());
377              goto get_out;
378           }
379           if (dev->num_writers == 0) {
380              memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
381           }
382       }
383    } else {
384       /* Not already in append mode, so mount the device */
385       Dmsg0(190, "Not in append mode, try mount.\n");
386       ASSERT(dev->num_writers == 0);
387       do_mount = true;
388    }
389
390    if (do_mount || recycle) {
391       Dmsg0(190, "Do mount_next_write_vol\n");
392       bool mounted = mount_next_write_volume(dcr, release);
393       if (!mounted) {
394          if (!job_canceled(jcr)) {
395             /* Reduce "noise" -- don't print if job canceled */
396             Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
397                dev->print_name());
398          }
399          goto get_out;
400       }
401    }
402
403    dev->num_writers++;                /* we are now a writer */
404    if (jcr->NumVolumes == 0) {
405       jcr->NumVolumes = 1;
406    }
407    goto ok_out;
408
409 /*
410  * If we jump here, it is an error return because
411  *  rtn_dev will still be NULL
412  */
413 get_out:
414    free_dcr(dcr);
415    dcr = NULL;
416 ok_out:
417    dev->unblock();
418    return dcr;
419 }
420
421 /*
422  * This job is done, so release the device. From a Unix standpoint,
423  *  the device remains open.
424  *
425  */
426 bool release_device(DCR *dcr)
427 {
428    JCR *jcr = dcr->jcr;
429    DEVICE *dev = dcr->dev;
430    bool ok = true;
431
432    lock_device(dev);
433    Dmsg1(100, "release_device device is %s\n", dev->is_tape()?"tape":"disk");
434
435    /* if device is reserved, job never started, so release the reserve here */
436    if (dcr->reserved_device) {
437       dev->reserved_device--;
438       Dmsg1(200, "Dec reserve=%d\n", dev->reserved_device);
439       dcr->reserved_device = false;
440    }
441
442    if (dev->can_read()) {
443       dev->clear_read();              /* clear read bit */
444
445       /******FIXME**** send read volume usage statistics to director */
446
447    } else if (dev->num_writers > 0) {
448       /* 
449        * Note if WEOT is set, we are at the end of the tape
450        *   and may not be positioned correctly, so the
451        *   job_media_record and update_vol_info have already been
452        *   done, which means we skip them here.
453        */
454       dev->num_writers--;
455       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
456       if (dev->is_labeled()) {
457          Dmsg0(100, "dir_create_jobmedia_record. Release\n");
458          if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
459             Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
460                dcr->VolCatInfo.VolCatName, jcr->Job);
461          }
462          /* If no more writers, write an EOF */
463          if (!dev->num_writers && dev->can_write()) {
464             weof_dev(dev, 1);
465             write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
466          }
467          if (!dev->at_weot()) {
468             dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
469             dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
470             /* Note! do volume update before close, which zaps VolCatInfo */
471             Dmsg0(100, "dir_update_vol_info. Release0\n");
472             dir_update_volume_info(dcr, false); /* send Volume info to Director */
473          }
474       }
475
476    } else {
477       /*                
478        * If we reach here, it is most likely because the job
479        *   has failed, since the device is not in read mode and
480        *   there are no writers. It was probably reserved.
481        */
482    }
483
484    /* If no writers, close if file or !CAP_ALWAYS_OPEN */
485    if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
486       offline_or_rewind_dev(dev);
487       close_device(dev);
488    }
489
490    /* Fire off Alert command and include any output */
491    if (!job_canceled(jcr) && dcr->device->alert_command) {
492       POOLMEM *alert;
493       int status = 1;
494       BPIPE *bpipe;
495       char line[MAXSTRING];
496       alert = get_pool_memory(PM_FNAME);
497       alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
498       bpipe = open_bpipe(alert, 0, "r");
499       if (bpipe) {
500          while (fgets(line, sizeof(line), bpipe->rfd)) {
501             Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
502          }
503          status = close_bpipe(bpipe);
504       } else {
505          status = errno;
506       }
507       if (status != 0) {
508          berrno be;
509          Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
510               alert, be.strerror(status));
511       }
512
513       Dmsg1(400, "alert status=%d\n", status);
514       free_pool_memory(alert);
515    }
516    unlock_device(dev);
517    free_dcr(dcr);
518    jcr->dcr = NULL;
519    pthread_cond_broadcast(&wait_device_release);
520    return ok;
521 }