]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/acquire.c
Start coding better reservation algorithm
[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    dcr->jcr = jcr;
38    if (dev) {
39       if (jcr) {
40          jcr->dcr = dcr;
41       }
42       dcr->dev = dev;
43       dcr->device = dev->device;
44       dcr->block = new_block(dev);
45       dcr->rec = new_record();
46       dcr->max_job_spool_size = dev->device->max_job_spool_size;
47       /* Attach this dcr only if dev is initialized */
48       if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
49          dev->attached_dcrs->append(dcr);  /* attach dcr to device */
50 //       jcr->dcrs->append(dcr);         /* put dcr in list for Job */
51       }
52    }
53    dcr->spool_fd = -1;
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       Dmsg1(200, "Device %s is busy reading.\n", dev->print_name());
330       goto get_out;
331    }
332
333    if (dev->can_append()) {
334       Dmsg0(190, "device already in append.\n");
335       /*
336        * Device already in append mode
337        *
338        * Check if we have the right Volume mounted
339        *   OK if current volume info OK
340        *   OK if next volume matches current volume
341        *   otherwise mount desired volume obtained from
342        *    dir_find_next_appendable_volume
343        *  dev->VolHdr.VolumeName is what is in the drive
344        *  dcr->VolumeName is what we pass into the routines, or
345        *    get back from the subroutines.
346        */
347       bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
348       if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
349           !(dir_find_next_appendable_volume(dcr) &&
350             strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
351          Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
352             dcr->VolumeName);
353          /* Release volume reserved by dir_find_next_appendable_volume() */
354          if (dcr->VolumeName[0]) {
355             free_unused_volume(dcr);
356          }
357          if (dev->num_writers != 0 || dev->reserved_device) {
358             Jmsg3(jcr, M_FATAL, 0, _("Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n"), 
359                  dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
360             Dmsg3(200, "Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n",  
361                  dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
362             goto get_out;
363          }
364          /* Wrong tape mounted, release it, then fall through to get correct one */
365          Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
366          release = true;
367          do_mount = true;
368       } else {
369          /*
370           * At this point, the correct tape is already mounted, so
371           *   we do not need to do mount_next_write_volume(), unless
372           *   we need to recycle the tape.
373           */
374           recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
375           Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
376           if (recycle && dev->num_writers != 0) {
377              Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
378                   " on device %s because it is in use by another job.\n"),
379                   dev->VolHdr.VolumeName, dev->print_name());
380              goto get_out;
381           }
382           if (dev->num_writers == 0) {
383              memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
384           }
385       }
386    } else {
387       /* Not already in append mode, so mount the device */
388       Dmsg0(190, "Not in append mode, try mount.\n");
389       ASSERT(dev->num_writers == 0);
390       do_mount = true;
391    }
392
393    if (do_mount || recycle) {
394       Dmsg0(190, "Do mount_next_write_vol\n");
395       bool mounted = mount_next_write_volume(dcr, release);
396       if (!mounted) {
397          if (!job_canceled(jcr)) {
398             /* Reduce "noise" -- don't print if job canceled */
399             Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
400                dev->print_name());
401             Dmsg1(200, "Could not ready device %s for append.\n", 
402                dev->print_name());
403          }
404          goto get_out;
405       }
406    }
407
408    dev->num_writers++;                /* we are now a writer */
409    if (jcr->NumVolumes == 0) {
410       jcr->NumVolumes = 1;
411    }
412    goto ok_out;
413
414 /*
415  * If we jump here, it is an error return because
416  *  rtn_dev will still be NULL
417  */
418 get_out:
419    free_dcr(dcr);
420    dcr = NULL;
421 ok_out:
422    dev->unblock();
423    return dcr;
424 }
425
426 /*
427  * This job is done, so release the device. From a Unix standpoint,
428  *  the device remains open.
429  *
430  */
431 bool release_device(DCR *dcr)
432 {
433    JCR *jcr = dcr->jcr;
434    DEVICE *dev = dcr->dev;
435    bool ok = true;
436
437    lock_device(dev);
438    Dmsg1(100, "release_device device is %s\n", dev->is_tape()?"tape":"disk");
439
440    /* if device is reserved, job never started, so release the reserve here */
441    if (dcr->reserved_device) {
442       dev->reserved_device--;
443       Dmsg1(200, "Dec reserve=%d\n", dev->reserved_device);
444       dcr->reserved_device = false;
445    }
446
447    if (dev->can_read()) {
448       dev->clear_read();              /* clear read bit */
449
450       /******FIXME**** send read volume usage statistics to director */
451
452    } else if (dev->num_writers > 0) {
453       /* 
454        * Note if WEOT is set, we are at the end of the tape
455        *   and may not be positioned correctly, so the
456        *   job_media_record and update_vol_info have already been
457        *   done, which means we skip them here.
458        */
459       dev->num_writers--;
460       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
461       if (dev->is_labeled()) {
462          Dmsg0(100, "dir_create_jobmedia_record. Release\n");
463          if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
464             Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
465                dcr->VolCatInfo.VolCatName, jcr->Job);
466          }
467          /* If no more writers, write an EOF */
468          if (!dev->num_writers && dev->can_write()) {
469             weof_dev(dev, 1);
470             write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
471          }
472          if (!dev->at_weot()) {
473             dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
474             dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
475             /* Note! do volume update before close, which zaps VolCatInfo */
476             Dmsg0(100, "dir_update_vol_info. Release0\n");
477             dir_update_volume_info(dcr, false); /* send Volume info to Director */
478          }
479       }
480
481    } else {
482       /*                
483        * If we reach here, it is most likely because the job
484        *   has failed, since the device is not in read mode and
485        *   there are no writers. It was probably reserved.
486        */
487    }
488
489    /* If no writers, close if file or !CAP_ALWAYS_OPEN */
490    if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
491       offline_or_rewind_dev(dev);
492       close_device(dev);
493    }
494
495    /* Fire off Alert command and include any output */
496    if (!job_canceled(jcr) && dcr->device->alert_command) {
497       POOLMEM *alert;
498       int status = 1;
499       BPIPE *bpipe;
500       char line[MAXSTRING];
501       alert = get_pool_memory(PM_FNAME);
502       alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
503       bpipe = open_bpipe(alert, 0, "r");
504       if (bpipe) {
505          while (fgets(line, sizeof(line), bpipe->rfd)) {
506             Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
507          }
508          status = close_bpipe(bpipe);
509       } else {
510          status = errno;
511       }
512       if (status != 0) {
513          berrno be;
514          Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
515               alert, be.strerror(status));
516       }
517
518       Dmsg1(400, "alert status=%d\n", status);
519       free_pool_memory(alert);
520    }
521    unlock_device(dev);
522    free_dcr(dcr);
523    jcr->dcr = NULL;
524    pthread_cond_broadcast(&wait_device_release);
525    return ok;
526 }