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