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