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