]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/acquire.c
faa369213fdbb634235860028197699ce2d9a46c
[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    Bacula® - The Network Backup Solution
10
11    Copyright (C) 2002-2006 Free Software Foundation Europe e.V.
12
13    The main author of Bacula is Kern Sibbald, with contributions from
14    many others, a complete list can be found in the file AUTHORS.
15    This program is Free Software; you can redistribute it and/or
16    modify it under the terms of version two of the GNU General Public
17    License as published by the Free Software Foundation plus additions
18    that are listed in the file LICENSE.
19
20    This program is distributed in the hope that it will be useful, but
21    WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23    General Public License for more details.
24
25    You should have received a copy of the GNU General Public License
26    along with this program; if not, write to the Free Software
27    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28    02110-1301, USA.
29
30    Bacula® is a registered trademark of John Walker.
31    The licensor of Bacula is the Free Software Foundation Europe
32    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
33    Switzerland, email:ftf@fsfeurope.org.
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, _("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. Job %s canceled.\n"), 
79          edit_int64(jcr->JobId, ed1));
80       goto get_out;
81    }
82    jcr->CurVolume++;
83    for (i=1; i<jcr->CurVolume; i++) {
84       vol = vol->next;
85    }
86    if (!vol) {
87       Jmsg(jcr, M_FATAL, 0, _("Logic error: no next volume. Numvol=%d Curvol=%d\n"),
88          jcr->NumVolumes, jcr->CurVolume);
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          Dmsg1(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.\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    P(dev->mutex);
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    V(dev->mutex);
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, _("Device %s is busy reading.\n"), dev->print_name());
325       Dmsg1(200, "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 Volume \"%s\", but device %s is busy writing on \"%s\" .\n"), 
355                  dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
356             Dmsg3(200, "Wanted 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    } else {
383       /* Not already in append mode, so mount the device */
384       Dmsg0(190, "Not in append mode, try mount.\n");
385       ASSERT(dev->num_writers == 0);
386       do_mount = true;
387    }
388
389    if (do_mount || recycle) {
390       Dmsg0(190, "Do mount_next_write_vol\n");
391       bool mounted = mount_next_write_volume(dcr, release);
392       if (!mounted) {
393          if (!job_canceled(jcr)) {
394             /* Reduce "noise" -- don't print if job canceled */
395             Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
396                dev->print_name());
397             Dmsg1(200, "Could not ready device %s for append.\n", 
398                dev->print_name());
399          }
400          goto get_out;
401       }
402       Dmsg2(190, "Output pos=%u:%u\n", dcr->dev->file, dcr->dev->block_num);
403    }
404
405    dev->num_writers++;                /* we are now a writer */
406    if (jcr->NumVolumes == 0) {
407       jcr->NumVolumes = 1;
408    }
409    P(dev->mutex);
410    if (dcr->reserved_device) {
411       dev->reserved_device--;
412       Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
413       dcr->reserved_device = false;
414    }
415    V(dev->mutex);
416    dev->unblock();
417    return dcr;
418
419 /*
420  * Error return
421  */
422 get_out:
423    P(dev->mutex);
424    if (dcr->reserved_device) {
425       dev->reserved_device--;
426       Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
427       dcr->reserved_device = false;
428    }
429    V(dev->mutex);
430    dev->unblock();
431    return NULL;
432 }
433
434
435 /*
436  * This job is done, so release the device. From a Unix standpoint,
437  *  the device remains open.
438  *
439  * Note, if we are spooling, we may enter with the device locked.
440  * However, in all cases, unlock the device when leaving.
441  *
442  */
443 bool release_device(DCR *dcr)
444 {
445    JCR *jcr = dcr->jcr;
446    DEVICE *dev = dcr->dev;
447    bool ok = true;
448
449    /* lock only if not already locked by this thread */
450    if (!dcr->dev_locked) {
451       lock_device(dev);
452    }
453    Dmsg2(100, "release_device device %s is %s\n", dev->print_name(), dev->is_tape()?"tape":"disk");
454
455    /* if device is reserved, job never started, so release the reserve here */
456    if (dcr->reserved_device) {
457       dev->reserved_device--;
458       Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
459       dcr->reserved_device = false;
460    }
461
462    if (dev->can_read()) {
463       dev->clear_read();              /* clear read bit */
464
465       /******FIXME**** send read volume usage statistics to director */
466
467    } else if (dev->num_writers > 0) {
468       /* 
469        * Note if WEOT is set, we are at the end of the tape
470        *   and may not be positioned correctly, so the
471        *   job_media_record and update_vol_info have already been
472        *   done, which means we skip them here.
473        */
474       dev->num_writers--;
475       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
476       if (dev->is_labeled()) {
477          Dmsg0(100, "dir_create_jobmedia_record. Release\n");
478          if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
479             Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
480                dcr->VolCatInfo.VolCatName, jcr->Job);
481          }
482          /* If no more writers, write an EOF */
483          if (!dev->num_writers && dev->can_write()) {
484             dev->weof(1);
485             write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
486          }
487          if (!dev->at_weot()) {
488             dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
489             dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
490             /* Note! do volume update before close, which zaps VolCatInfo */
491             Dmsg0(100, "dir_update_vol_info. Release0\n");
492             dir_update_volume_info(dcr, false); /* send Volume info to Director */
493          }
494       }
495
496    } else {
497       /*                
498        * If we reach here, it is most likely because the job
499        *   has failed, since the device is not in read mode and
500        *   there are no writers. It was probably reserved.
501        */
502    }
503
504    /* If no writers, close if file or !CAP_ALWAYS_OPEN */
505    if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
506       dvd_remove_empty_part(dcr);        /* get rid of any empty spool part */
507       dev->close();
508    }
509
510    /* Fire off Alert command and include any output */
511    if (!job_canceled(jcr) && dcr->device->alert_command) {
512       POOLMEM *alert;
513       int status = 1;
514       BPIPE *bpipe;
515       char line[MAXSTRING];
516       alert = get_pool_memory(PM_FNAME);
517       alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
518       bpipe = open_bpipe(alert, 0, "r");
519       if (bpipe) {
520          while (fgets(line, sizeof(line), bpipe->rfd)) {
521             Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
522          }
523          status = close_bpipe(bpipe);
524       } else {
525          status = errno;
526       }
527       if (status != 0) {
528          berrno be;
529          Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
530               alert, be.strerror(status));
531       }
532
533       Dmsg1(400, "alert status=%d\n", status);
534       free_pool_memory(alert);
535    }
536    dcr->dev_locked = false;              /* set no longer locked */
537    unlock_device(dev);
538    if (jcr->read_dcr == dcr) {
539       jcr->read_dcr = NULL;
540    }
541    if (jcr->dcr == dcr) {
542       jcr->dcr = NULL;
543    }
544    free_dcr(dcr);
545    return ok;
546 }
547
548 /*
549  * Create a new Device Control Record and attach
550  *   it to the device (if this is a real job).
551  */
552 DCR *new_dcr(JCR *jcr, DEVICE *dev)
553 {
554    DCR *dcr = (DCR *)malloc(sizeof(DCR));
555    memset(dcr, 0, sizeof(DCR));
556    dcr->jcr = jcr;
557    if (dev) {
558       dcr->dev = dev;
559       dcr->device = dev->device;
560       dcr->block = new_block(dev);
561       dcr->rec = new_record();
562       dcr->max_job_spool_size = dev->device->max_job_spool_size;
563       attach_dcr_to_dev(dcr);
564    }
565    dcr->spool_fd = -1;
566    return dcr;
567 }
568
569 /*
570  * Search the dcrs list for the given dcr. If it is found,
571  *  as it should be, then remove it. Also zap the jcr pointer
572  *  to the dcr if it is the same one.
573  */
574 #ifdef needed
575 static void remove_dcr_from_dcrs(DCR *dcr)
576 {
577    JCR *jcr = dcr->jcr;
578    if (jcr->dcrs) {
579       int i = 0;
580       DCR *ldcr;
581       int num = jcr->dcrs->size();
582       for (i=0; i < num; i++) {
583          ldcr = (DCR *)jcr->dcrs->get(i);
584          if (ldcr == dcr) {
585             jcr->dcrs->remove(i);
586             if (jcr->dcr == dcr) {
587                jcr->dcr = NULL;
588             }
589          }
590       }
591    }
592 }
593 #endif
594
595 static void attach_dcr_to_dev(DCR *dcr)
596 {
597    DEVICE *dev = dcr->dev;
598    JCR *jcr = dcr->jcr;
599
600    if (!dcr->attached_to_dev && dev->is_open() && jcr && jcr->JobType != JT_SYSTEM) {
601       dev->attached_dcrs->append(dcr);  /* attach dcr to device */
602       dcr->attached_to_dev = true;
603    }
604 }
605
606 void detach_dcr_from_dev(DCR *dcr)
607 {
608    DEVICE *dev = dcr->dev;
609
610    if (dcr->reserved_device) {
611       dcr->reserved_device = false;
612       lock_device(dev);
613       dev->reserved_device--;
614       Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
615       dcr->reserved_device = false;
616       /* If we set read mode in reserving, remove it */
617       if (dev->can_read()) {
618          dev->clear_read();
619       }
620       if (dev->num_writers < 0) {
621          Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers);
622          dev->num_writers = 0;
623       }
624       unlock_device(dev);
625    }
626
627    /* Detach this dcr only if attached */
628    if (dcr->attached_to_dev) {
629       dcr->dev->attached_dcrs->remove(dcr);  /* detach dcr from device */
630       dcr->attached_to_dev = false;
631 //    remove_dcr_from_dcrs(dcr);      /* remove dcr from jcr list */
632    }
633    free_unused_volume(dcr);           /* free unused vols attached to this dcr */
634    pthread_cond_broadcast(&dcr->dev->wait_next_vol);
635    pthread_cond_broadcast(&wait_device_release);
636 }
637
638 /*
639  * Free up all aspects of the given dcr -- i.e. dechain it,
640  *  release allocated memory, zap pointers, ...
641  */
642 void free_dcr(DCR *dcr)
643 {
644
645    if (dcr->dev) {
646       detach_dcr_from_dev(dcr);
647    }
648
649    if (dcr->block) {
650       free_block(dcr->block);
651    }
652    if (dcr->rec) {
653       free_record(dcr->rec);
654    }
655    if (dcr->jcr) {
656       dcr->jcr->dcr = NULL;
657    }
658    free(dcr);
659 }