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