]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/acquire.c
42f15bd7655cb48cf62840d6abf3693ea2d73da6
[bacula/bacula] / bacula / src / stored / acquire.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2008 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 and included
11    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(950, "jcr->dcr=%p\n", jcr->dcr);
66    dev->dblock(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    dev->clear_unload();
74
75    /* Find next Volume, if any */
76    vol = jcr->VolList;
77    if (!vol) {
78       char ed1[50];
79       Jmsg(jcr, M_FATAL, 0, _("No volumes specified for reading. Job %s canceled.\n"), 
80          edit_int64(jcr->JobId, ed1));
81       goto get_out;
82    }
83    jcr->CurReadVolume++;
84    for (i=1; i<jcr->CurReadVolume; i++) {
85       vol = vol->next;
86    }
87    if (!vol) {
88       Jmsg(jcr, M_FATAL, 0, _("Logic error: no next volume to read. Numvol=%d Curvol=%d\n"),
89          jcr->NumReadVolumes, jcr->CurReadVolume);
90       goto get_out;                   /* should not happen */   
91    }
92    /*    
93     * Note, if we want to be able to work from a .bsr file only          
94     *  for disaster recovery, we must "simulate" reading the catalog
95     */
96    bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
97    bstrncpy(dcr->VolCatInfo.VolCatName, vol->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
98    bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type));
99    dcr->VolCatInfo.Slot = vol->Slot;
100    dcr->VolCatInfo.InChanger = vol->Slot > 0; 
101     
102    /*
103     * If the MediaType requested for this volume is not the
104     *  same as the current drive, we attempt to find the same
105     *  device that was used to write the orginal volume.  If
106     *  found, we switch to using that device.
107     *
108     *  N.B. A lot of routines rely on the dcr pointer not changing
109     *    read_records.c even has multiple dcrs cached, so we take care
110     *    here to release all important parts of the dcr and re-acquire
111     *    them such as the block pointer (size may change), but we do
112     *    not release the dcr.
113     */
114    Dmsg2(50, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
115    if (dcr->media_type[0] && strcmp(dcr->media_type, dev->device->media_type) != 0) {
116       RCTX rctx;
117       DIRSTORE *store;
118       int stat;
119
120       Jmsg3(jcr, M_INFO, 0, _("Changing device. Want Media Type=\"%s\" have=\"%s\"\n"
121                               "  device=%s\n"), 
122             dcr->media_type, dev->device->media_type, dev->print_name());
123       Dmsg3(50, "Changing device. Want Media Type=\"%s\" have=\"%s\"\n"
124                               "  device=%s\n", 
125             dcr->media_type, dev->device->media_type, dev->print_name());
126
127       dev->dunblock(DEV_UNLOCKED);
128
129       lock_reservations();
130       memset(&rctx, 0, sizeof(RCTX));
131       rctx.jcr = jcr;
132       jcr->reserve_msgs = New(alist(10, not_owned_by_alist));
133       rctx.any_drive = true;
134       rctx.device_name = vol->device;
135       store = new DIRSTORE;
136       memset(store, 0, sizeof(DIRSTORE));
137       store->name[0] = 0; /* No dir name */
138       bstrncpy(store->media_type, vol->MediaType, sizeof(store->media_type));
139       bstrncpy(store->pool_name, dcr->pool_name, sizeof(store->pool_name));
140       bstrncpy(store->pool_type, dcr->pool_type, sizeof(store->pool_type));
141       store->append = false;
142       rctx.store = store;
143       clean_device(dcr);                     /* clean up the dcr */
144       
145       /*
146        * Search for a new device
147        */
148       stat = search_res_for_device(rctx);
149       release_reserve_messages(jcr);         /* release queued messages */
150       unlock_reservations();
151
152       if (stat == 1) {
153          dev = dcr->dev;                     /* get new device pointer */
154          dev->dblock(BST_DOING_ACQUIRE); 
155          dcr->VolumeName[0] = 0;
156          Jmsg(jcr, M_INFO, 0, _("Media Type change.  New device %s chosen.\n"),
157             dev->print_name());
158          Dmsg1(50, "Media Type change.  New device %s chosen.\n", dev->print_name());
159
160          bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
161          bstrncpy(dcr->VolCatInfo.VolCatName, vol->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
162          bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type));
163          dcr->VolCatInfo.Slot = vol->Slot;
164          dcr->VolCatInfo.InChanger = vol->Slot > 0; 
165          bstrncpy(dcr->pool_name, store->pool_name, sizeof(dcr->pool_name));
166          bstrncpy(dcr->pool_type, store->pool_type, sizeof(dcr->pool_type));
167       } else {
168          /* error */
169          Jmsg1(jcr, M_FATAL, 0, _("No suitable device found to read Volume \"%s\"\n"),
170             vol->VolumeName);
171          Dmsg1(50, "No suitable device found to read Volume \"%s\"\n", vol->VolumeName);
172          goto get_out;
173       }
174    }
175
176    if (reserve_volume(dcr, dcr->VolumeName) == NULL) {
177       Dmsg2(100, "Could not reserve volume %s on %s\n", dcr->VolumeName,
178             dcr->dev->print_name());
179       Jmsg2(jcr, M_FATAL, 0, _("Could not reserve volume %s on %s\n"), dcr->VolumeName,
180             dcr->dev->print_name());
181       goto get_out;
182    }
183    if (dev->vol && dev->vol->is_swapping()) {
184       dev->vol->set_slot(vol->Slot);
185       Dmsg3(100, "swapping: slot=%d Vol=%s dev=%s\n", dev->vol->get_slot(),
186          dev->vol->vol_name, dev->print_name());
187    }
188
189
190    init_device_wait_timers(dcr);
191
192    tape_previously_mounted = dev->can_read() || dev->can_append() ||
193                              dev->is_labeled();
194    tape_initially_mounted = tape_previously_mounted;
195
196
197    /* Volume info is always needed because of VolParts */
198    Dmsg1(150, "dir_get_volume_info vol=%s\n", dcr->VolumeName);
199    if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
200       Dmsg2(150, "dir_get_vol_info failed for vol=%s: %s\n", 
201          dcr->VolumeName, jcr->errmsg);
202       Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
203    }
204    dev->set_load();                /* set to load volume */
205    
206    for ( ;; ) {
207       /* If not polling limit retries */
208       if (!dev->poll && retry++ > 10) {
209          break;
210       }
211       dev->clear_labeled();              /* force reread of label */
212       if (job_canceled(jcr)) {
213          char ed1[50];
214          Mmsg1(dev->errmsg, _("Job %s canceled.\n"), edit_int64(jcr->JobId, ed1));
215          Jmsg(jcr, M_INFO, 0, dev->errmsg);
216          goto get_out;                /* error return */
217       }
218
219       dcr->do_swapping(false/*is_writing*/);
220
221       /*
222        * This code ensures that the device is ready for
223        * reading. If it is a file, it opens it.
224        * If it is a tape, it checks the volume name
225        */
226       Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName);
227       if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
228          if (!dev->poll) {
229             Jmsg3(jcr, M_WARNING, 0, _("Read open device %s Volume \"%s\" failed: ERR=%s\n"),
230                   dev->print_name(), dcr->VolumeName, dev->bstrerror());
231          }
232          goto default_path;
233       }
234       Dmsg1(50, "opened dev %s OK\n", dev->print_name());
235       
236       /* Read Volume Label */
237       Dmsg0(50, "calling read-vol-label\n");
238       vol_label_status = read_dev_volume_label(dcr);
239       switch (vol_label_status) {
240       case VOL_OK:
241          ok = true;
242          dev->VolCatInfo = dcr->VolCatInfo;     /* structure assignment */
243          break;                    /* got it */
244       case VOL_IO_ERROR:
245          /*
246           * Send error message generated by read_dev_volume_label()
247           *  only we really had a tape mounted. This supresses superfluous
248           *  error messages when nothing is mounted.
249           */
250          if (tape_previously_mounted) {
251             Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
252          }
253          goto default_path;
254       case VOL_NAME_ERROR:
255          if (dev->is_volume_to_unload()) {
256             goto default_path;
257          }
258 //       if (tape_initially_mounted) {
259             tape_initially_mounted = false;
260 //          goto default_path;
261 //       }
262          dev->set_unload();              /* force unload of unwanted tape */
263          if (!unload_autochanger(dcr, -1)) {
264             /* at least free the device so we can re-open with correct volume */
265             dev->close();                                                          
266          }
267          dev->set_load();
268          ASSERT(0);
269          /* Fall through */
270       default:
271          Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
272 default_path:
273          tape_previously_mounted = true;
274          
275          /*
276           * If the device requires mount, close it, so the device can be ejected.
277           */
278          if (dev->requires_mount()) {
279             dev->close();
280          }
281          
282          /* Call autochanger only once unless ask_sysop called */
283          if (try_autochanger) {
284             int stat;
285             Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
286                dcr->VolumeName, dcr->VolCatInfo.Slot);
287             stat = autoload_device(dcr, 0, NULL);
288             if (stat > 0) {
289                try_autochanger = false;
290                continue;              /* try reading volume mounted */
291             }
292             /* Try closing and re-opening */
293             dev->close();
294             if (dev->open(dcr, OPEN_READ_ONLY) >= 0) {
295                continue;
296             }
297             if (!dev->poll) {
298                Jmsg3(jcr, M_WARNING, 0, _("Read open device %s Volume \"%s\" failed: ERR=%s\n"),
299                      dev->print_name(), dcr->VolumeName, dev->bstrerror());
300             }
301          }
302          
303          /* Mount a specific volume and no other */
304          Dmsg0(200, "calling dir_ask_sysop\n");
305          if (!dir_ask_sysop_to_mount_volume(dcr, ST_READ)) {
306             goto get_out;             /* error return */
307          }
308          try_autochanger = true;      /* permit using autochanger again */
309          continue;                    /* try reading again */
310       } /* end switch */
311       break;
312    } /* end for loop */
313
314    if (!ok) {
315       Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s for reading.\n"),
316             dev->print_name());
317       goto get_out;
318    }
319
320    dev->clear_append();
321    dev->set_read();
322    set_jcr_job_status(jcr, JS_Running);
323    dir_send_job_status(jcr);
324    Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
325       dcr->VolumeName, dev->print_name());
326
327 get_out:
328    dev->dlock();
329    dcr->clear_reserved();
330    /* 
331     * Normally we are blocked, but in at least one error case above 
332     *   we are not blocked because we unsuccessfully tried changing
333     *   devices.  
334     */
335    if (dev->is_blocked()) {
336       dev->dunblock(DEV_LOCKED);
337    } else {
338       dev->dunlock();               /* dunblock() unlock the device too */
339    }
340    Dmsg1(950, "jcr->dcr=%p\n", jcr->dcr);
341    return ok;
342 }
343
344
345 /*
346  * Acquire device for writing. We permit multiple writers.
347  *  If this is the first one, we read the label.
348  *
349  *  Returns: NULL if failed for any reason
350  *           dcr if successful.
351  *   Note, normally reserve_device_for_append() is called
352  *   before this routine.
353  */
354 DCR *acquire_device_for_append(DCR *dcr)
355 {
356    DEVICE *dev = dcr->dev;
357    JCR *jcr = dcr->jcr;
358    bool ok = false;
359    bool have_vol = false;
360
361    init_device_wait_timers(dcr);
362
363    dev->dblock(BST_DOING_ACQUIRE);
364    Dmsg1(100, "acquire_append device is %s\n", dev->is_tape()?"tape":
365         (dev->is_dvd()?"DVD":"disk"));
366
367    /*
368     * With the reservation system, this should not happen
369     */
370    if (dev->can_read()) {
371       Jmsg1(jcr, M_FATAL, 0, _("Want to append, but device %s is busy reading.\n"), dev->print_name());
372       Dmsg1(200, "Want to append but device %s is busy reading.\n", dev->print_name());
373       goto get_out;
374    }
375
376    dev->clear_unload();
377
378    /*
379     * have_vol defines whether or not mount_next_write_volume should
380     *   ask the Director again about what Volume to use.
381     */
382    if (dev->can_append() && dcr->is_suitable_volume_mounted() &&
383        strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") != 0) {
384       Dmsg0(190, "device already in append.\n");
385       /*
386        * At this point, the correct tape is already mounted, so
387        *   we do not need to do mount_next_write_volume(), unless
388        *   we need to recycle the tape.
389        */
390        if (dev->num_writers == 0) {
391           memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
392        }
393        have_vol = dcr->is_tape_position_ok();
394    }
395
396    if (!have_vol) {
397       Dmsg1(190, "jid=%u Do mount_next_write_vol\n", (uint32_t)jcr->JobId);
398       if (!dcr->mount_next_write_volume()) {
399          if (!job_canceled(jcr)) {
400             /* Reduce "noise" -- don't print if job canceled */
401             Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
402                dev->print_name());
403             Dmsg1(200, "Could not ready device %s for append.\n", 
404                dev->print_name());
405          }
406          goto get_out;
407       }
408       Dmsg2(190, "Output pos=%u:%u\n", dcr->dev->file, dcr->dev->block_num);
409    }
410
411    dev->num_writers++;                /* we are now a writer */
412    if (jcr->NumWriteVolumes == 0) {
413       jcr->NumWriteVolumes = 1;
414    }
415    dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
416    dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
417    ok = true;
418
419 get_out:
420    dev->dlock();
421    dcr->clear_reserved();
422    dev->dunblock(DEV_LOCKED);
423    return ok ? dcr : NULL;
424 }
425
426 /*
427  * This job is done, so release the device. From a Unix standpoint,
428  *  the device remains open.
429  *
430  * Note, if we are spooling, we may enter with the device locked.
431  * However, in all cases, unlock the device when leaving.
432  *
433  */
434 bool release_device(DCR *dcr)
435 {
436    JCR *jcr = dcr->jcr;
437    DEVICE *dev = dcr->dev;
438    bool ok = true;
439    char tbuf[100];
440
441    /* lock only if not already locked by this thread */
442    if (!dcr->is_dev_locked()) {
443       dev->r_dlock();
444    }
445    lock_volumes();
446    Dmsg2(100, "release_device device %s is %s\n", dev->print_name(), dev->is_tape()?"tape":"disk");
447
448    /* if device is reserved, job never started, so release the reserve here */
449    dcr->clear_reserved();
450
451    if (dev->can_read()) {
452       dev->clear_read();              /* clear read bit */
453       Dmsg0(100, "dir_update_vol_info. Release0\n");
454       dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
455       volume_unused(dcr);
456
457    } else if (dev->num_writers > 0) {
458       /* 
459        * Note if WEOT is set, we are at the end of the tape
460        *   and may not be positioned correctly, so the
461        *   job_media_record and update_vol_info have already been
462        *   done, which means we skip them here.
463        */
464       dev->num_writers--;
465       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
466       if (dev->is_labeled()) {
467          Dmsg2(200, "dir_create_jobmedia. Release vol=%s dev=%s\n", 
468                dev->VolCatInfo.VolCatName, dev->print_name());
469          if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
470             Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
471                dcr->VolCatInfo.VolCatName, jcr->Job);
472          }
473          /* If no more writers, and no errors, and wrote something, write an EOF */
474          if (!dev->num_writers && dev->can_write() && dev->block_num > 0) {
475             dev->weof(1);
476             write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
477          }
478          if (!dev->at_weot()) {
479             dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
480             /* Note! do volume update before close, which zaps VolCatInfo */
481             dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
482             Dmsg2(200, "dir_update_vol_info. Release vol=%s dev=%s\n", 
483                   dev->VolCatInfo.VolCatName, dev->print_name());
484          }
485          if (dev->num_writers == 0) {         /* if not being used */
486             volume_unused(dcr);               /*  we obviously are not using the volume */
487          }
488       }
489
490    } else {
491       /*                
492        * If we reach here, it is most likely because the job
493        *   has failed, since the device is not in read mode and
494        *   there are no writers. It was probably reserved.
495        */
496       volume_unused(dcr);
497    }
498    unlock_volumes();
499    Dmsg3(100, "%d writers, %d reserve, dev=%s\n", dev->num_writers, dev->num_reserved(),
500          dev->print_name());
501    debug_list_volumes("acquire:release_device()");
502
503
504    /* If no writers, close if file or !CAP_ALWAYS_OPEN */
505    if (dev->num_writers == 0 && (!dev->is_tape() || !dev->has_cap(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.bstrerror(status));
531       }
532
533       Dmsg1(400, "alert status=%d\n", status);
534       free_pool_memory(alert);
535    }
536    pthread_cond_broadcast(&dev->wait_next_vol);
537    Dmsg2(100, "JobId=%u broadcast wait_device_release at %s\n", 
538          (uint32_t)jcr->JobId, bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL)));
539    pthread_cond_broadcast(&wait_device_release);
540    dev->dunlock();
541    if (dcr->keep_dcr) {
542       detach_dcr_from_dev(dcr);
543    } else {
544       if (jcr->read_dcr == dcr) {
545          jcr->read_dcr = NULL;
546       }
547       if (jcr->dcr == dcr) {
548          jcr->dcr = NULL;
549       }
550       free_dcr(dcr);
551    }
552    Dmsg2(100, "===== Device %s released by JobId=%u\n", dev->print_name(),
553          (uint32_t)jcr->JobId);
554    return ok;
555 }
556
557 /*
558  * Clean up the device for reuse without freeing the memory
559  */
560 bool clean_device(DCR *dcr)
561 {
562    bool ok;
563    dcr->keep_dcr = true;                  /* do not free the dcr */
564    ok = release_device(dcr);
565    dcr->keep_dcr = false;
566    return ok;
567 }
568
569 /*
570  * Create a new Device Control Record and attach
571  *   it to the device (if this is a real job).
572  * Note, this has been updated so that it can be called first 
573  *   without a DEVICE, then a second or third time with a DEVICE,
574  *   and each time, it should cleanup and point to the new device.
575  *   This should facilitate switching devices.
576  * Note, each dcr must point to the controlling job (jcr).  However,
577  *   a job can have multiple dcrs, so we must not store in the jcr's
578  *   structure as previously. The higher level routine must store
579  *   this dcr in the right place
580  *
581  */
582 DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev)
583 {
584    if (!dcr) {
585       dcr = (DCR *)malloc(sizeof(DCR));
586       memset(dcr, 0, sizeof(DCR));
587       dcr->tid = pthread_self();
588       dcr->spool_fd = -1;
589    }
590    dcr->jcr = jcr;                 /* point back to jcr */
591    /* Set device information, possibly change device */
592    if (dev) {
593       if (dcr->block) {
594          free_block(dcr->block);
595       }
596       dcr->block = new_block(dev);
597       if (dcr->rec) {
598          free_record(dcr->rec);
599       }
600       dcr->rec = new_record();
601       if (dcr->attached_to_dev) {
602          detach_dcr_from_dev(dcr);
603       }
604       /* Use job spoolsize prior to device spoolsize */
605       if (jcr->spool_size) {
606          dcr->max_job_spool_size = jcr->spool_size;
607       } else {
608          dcr->max_job_spool_size = dev->device->max_job_spool_size;
609       }
610       dcr->device = dev->device;
611       dcr->dev = dev;
612       attach_dcr_to_dev(dcr);
613    }
614    return dcr;
615 }
616
617 /*
618  * Search the dcrs list for the given dcr. If it is found,
619  *  as it should be, then remove it. Also zap the jcr pointer
620  *  to the dcr if it is the same one.
621  *
622  * Note, this code will be turned on when we can write to multiple
623  *  dcrs at the same time.
624  */
625 #ifdef needed
626 static void remove_dcr_from_dcrs(DCR *dcr)
627 {
628    JCR *jcr = dcr->jcr;
629    if (jcr->dcrs) {
630       int i = 0;
631       DCR *ldcr;
632       int num = jcr->dcrs->size();
633       for (i=0; i < num; i++) {
634          ldcr = (DCR *)jcr->dcrs->get(i);
635          if (ldcr == dcr) {
636             jcr->dcrs->remove(i);
637             if (jcr->dcr == dcr) {
638                jcr->dcr = NULL;
639             }
640          }
641       }
642    }
643 }
644 #endif
645
646 static void attach_dcr_to_dev(DCR *dcr)
647 {
648    DEVICE *dev = dcr->dev;
649    JCR *jcr = dcr->jcr;
650
651    if (jcr) Dmsg1(500, "JobId=%u enter attach_dcr_to_dev\n", (uint32_t)jcr->JobId);
652    if (!dcr->attached_to_dev && dev->initiated && jcr && jcr->JobType != JT_SYSTEM) {
653       dev->attached_dcrs->append(dcr);  /* attach dcr to device */
654       dcr->attached_to_dev = true;
655       Dmsg1(500, "JobId=%u attach_dcr_to_dev\n", (uint32_t)jcr->JobId);
656    }
657 }
658
659 void detach_dcr_from_dev(DCR *dcr)
660 {
661    DEVICE *dev = dcr->dev;
662    Dmsg0(500, "Enter detach_dcr_from_dev\n"); /* jcr is NULL in some cases */
663
664    /* Detach this dcr only if attached */
665    if (dcr->attached_to_dev && dev) {
666       dev->dlock();
667       dcr->unreserve_device();
668       dcr->dev->attached_dcrs->remove(dcr);  /* detach dcr from device */
669       dcr->attached_to_dev = false;
670 //    remove_dcr_from_dcrs(dcr);      /* remove dcr from jcr list */
671       dev->dunlock();
672    }
673 }
674
675 /*
676  * Free up all aspects of the given dcr -- i.e. dechain it,
677  *  release allocated memory, zap pointers, ...
678  */
679 void free_dcr(DCR *dcr)
680 {
681    JCR *jcr = dcr->jcr;
682
683    detach_dcr_from_dev(dcr);
684
685    if (dcr->block) {
686       free_block(dcr->block);
687    }
688    if (dcr->rec) {
689       free_record(dcr->rec);
690    }
691    if (jcr && jcr->dcr == dcr) {
692       jcr->dcr = NULL;
693    }
694    free(dcr);
695 }