]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/acquire.c
kes Generally clean up the manual tape loading code. The main
[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    /*
377     * have_vol defines whether or not mount_next_write_volume should
378     *   ask the Director again about what Volume to use.
379     */
380    if (dev->can_append() && dcr->is_suitable_volume_mounted() &&
381        strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") != 0) {
382       Dmsg0(190, "device already in append.\n");
383       /*
384        * At this point, the correct tape is already mounted, so
385        *   we do not need to do mount_next_write_volume(), unless
386        *   we need to recycle the tape.
387        */
388        if (dev->num_writers == 0) {
389           memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
390        }
391        have_vol = dcr->is_tape_position_ok();
392    }
393
394    if (!have_vol) {
395       Dmsg1(190, "jid=%u Do mount_next_write_vol\n", (uint32_t)jcr->JobId);
396       if (!dcr->mount_next_write_volume()) {
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       Dmsg2(190, "Output pos=%u:%u\n", dcr->dev->file, dcr->dev->block_num);
407    }
408
409    dev->num_writers++;                /* we are now a writer */
410    if (jcr->NumWriteVolumes == 0) {
411       jcr->NumWriteVolumes = 1;
412    }
413    dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
414    dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
415    ok = true;
416
417 get_out:
418    dev->dlock();
419    dcr->clear_reserved();
420    dev->dunblock(DEV_LOCKED);
421    return ok ? dcr : NULL;
422 }
423
424 /*
425  * This job is done, so release the device. From a Unix standpoint,
426  *  the device remains open.
427  *
428  * Note, if we are spooling, we may enter with the device locked.
429  * However, in all cases, unlock the device when leaving.
430  *
431  */
432 bool release_device(DCR *dcr)
433 {
434    JCR *jcr = dcr->jcr;
435    DEVICE *dev = dcr->dev;
436    bool ok = true;
437    char tbuf[100];
438
439    /* lock only if not already locked by this thread */
440    if (!dcr->is_dev_locked()) {
441       dev->r_dlock();
442    }
443    lock_volumes();
444    Dmsg2(100, "release_device device %s is %s\n", dev->print_name(), dev->is_tape()?"tape":"disk");
445
446    /* if device is reserved, job never started, so release the reserve here */
447    dcr->clear_reserved();
448
449    if (dev->can_read()) {
450       dev->clear_read();              /* clear read bit */
451       Dmsg0(100, "dir_update_vol_info. Release0\n");
452       dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
453       volume_unused(dcr);
454
455    } else if (dev->num_writers > 0) {
456       /* 
457        * Note if WEOT is set, we are at the end of the tape
458        *   and may not be positioned correctly, so the
459        *   job_media_record and update_vol_info have already been
460        *   done, which means we skip them here.
461        */
462       dev->num_writers--;
463       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
464       if (dev->is_labeled()) {
465          Dmsg2(200, "dir_create_jobmedia. Release vol=%s dev=%s\n", 
466                dev->VolCatInfo.VolCatName, dev->print_name());
467          if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
468             Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
469                dcr->VolCatInfo.VolCatName, jcr->Job);
470          }
471          /* If no more writers, and no errors, and wrote something, write an EOF */
472          if (!dev->num_writers && dev->can_write() && dev->block_num > 0) {
473             dev->weof(1);
474             write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
475          }
476          if (!dev->at_weot()) {
477             dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
478             /* Note! do volume update before close, which zaps VolCatInfo */
479             dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
480             Dmsg2(200, "dir_update_vol_info. Release vol=%s dev=%s\n", 
481                   dev->VolCatInfo.VolCatName, dev->print_name());
482          }
483          if (dev->num_writers == 0) {         /* if not being used */
484             volume_unused(dcr);               /*  we obviously are not using the volume */
485          }
486       }
487
488    } else {
489       /*                
490        * If we reach here, it is most likely because the job
491        *   has failed, since the device is not in read mode and
492        *   there are no writers. It was probably reserved.
493        */
494       volume_unused(dcr);
495    }
496    unlock_volumes();
497    Dmsg3(100, "%d writers, %d reserve, dev=%s\n", dev->num_writers, dev->num_reserved(),
498          dev->print_name());
499    debug_list_volumes("acquire:release_device()");
500
501
502    /* If no writers, close if file or !CAP_ALWAYS_OPEN */
503    if (dev->num_writers == 0 && (!dev->is_tape() || !dev->has_cap(CAP_ALWAYSOPEN))) {
504       dvd_remove_empty_part(dcr);        /* get rid of any empty spool part */
505       dev->close();
506    }
507
508    /* Fire off Alert command and include any output */
509    if (!job_canceled(jcr) && dcr->device->alert_command) {
510       POOLMEM *alert;
511       int status = 1;
512       BPIPE *bpipe;
513       char line[MAXSTRING];
514       alert = get_pool_memory(PM_FNAME);
515       alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
516       bpipe = open_bpipe(alert, 0, "r");
517       if (bpipe) {
518          while (fgets(line, sizeof(line), bpipe->rfd)) {
519             Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
520          }
521          status = close_bpipe(bpipe);
522       } else {
523          status = errno;
524       }
525       if (status != 0) {
526          berrno be;
527          Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
528               alert, be.bstrerror(status));
529       }
530
531       Dmsg1(400, "alert status=%d\n", status);
532       free_pool_memory(alert);
533    }
534    pthread_cond_broadcast(&dev->wait_next_vol);
535    Dmsg2(100, "JobId=%u broadcast wait_device_release at %s\n", 
536          (uint32_t)jcr->JobId, bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL)));
537    pthread_cond_broadcast(&wait_device_release);
538    dev->dunlock();
539    if (dcr->keep_dcr) {
540       detach_dcr_from_dev(dcr);
541    } else {
542       if (jcr->read_dcr == dcr) {
543          jcr->read_dcr = NULL;
544       }
545       if (jcr->dcr == dcr) {
546          jcr->dcr = NULL;
547       }
548       free_dcr(dcr);
549    }
550    Dmsg2(100, "===== Device %s released by JobId=%u\n", dev->print_name(),
551          (uint32_t)jcr->JobId);
552    return ok;
553 }
554
555 /*
556  * Clean up the device for reuse without freeing the memory
557  */
558 bool clean_device(DCR *dcr)
559 {
560    bool ok;
561    dcr->keep_dcr = true;                  /* do not free the dcr */
562    ok = release_device(dcr);
563    dcr->keep_dcr = false;
564    return ok;
565 }
566
567 /*
568  * Create a new Device Control Record and attach
569  *   it to the device (if this is a real job).
570  * Note, this has been updated so that it can be called first 
571  *   without a DEVICE, then a second or third time with a DEVICE,
572  *   and each time, it should cleanup and point to the new device.
573  *   This should facilitate switching devices.
574  * Note, each dcr must point to the controlling job (jcr).  However,
575  *   a job can have multiple dcrs, so we must not store in the jcr's
576  *   structure as previously. The higher level routine must store
577  *   this dcr in the right place
578  *
579  */
580 DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev)
581 {
582    if (!dcr) {
583       dcr = (DCR *)malloc(sizeof(DCR));
584       memset(dcr, 0, sizeof(DCR));
585       dcr->tid = pthread_self();
586       dcr->spool_fd = -1;
587    }
588    dcr->jcr = jcr;                 /* point back to jcr */
589    /* Set device information, possibly change device */
590    if (dev) {
591       if (dcr->block) {
592          free_block(dcr->block);
593       }
594       dcr->block = new_block(dev);
595       if (dcr->rec) {
596          free_record(dcr->rec);
597       }
598       dcr->rec = new_record();
599       if (dcr->attached_to_dev) {
600          detach_dcr_from_dev(dcr);
601       }
602       /* Use job spoolsize prior to device spoolsize */
603       if (jcr->spool_size) {
604          dcr->max_job_spool_size = jcr->spool_size;
605       } else {
606          dcr->max_job_spool_size = dev->device->max_job_spool_size;
607       }
608       dcr->device = dev->device;
609       dcr->dev = dev;
610       attach_dcr_to_dev(dcr);
611    }
612    return dcr;
613 }
614
615 /*
616  * Search the dcrs list for the given dcr. If it is found,
617  *  as it should be, then remove it. Also zap the jcr pointer
618  *  to the dcr if it is the same one.
619  *
620  * Note, this code will be turned on when we can write to multiple
621  *  dcrs at the same time.
622  */
623 #ifdef needed
624 static void remove_dcr_from_dcrs(DCR *dcr)
625 {
626    JCR *jcr = dcr->jcr;
627    if (jcr->dcrs) {
628       int i = 0;
629       DCR *ldcr;
630       int num = jcr->dcrs->size();
631       for (i=0; i < num; i++) {
632          ldcr = (DCR *)jcr->dcrs->get(i);
633          if (ldcr == dcr) {
634             jcr->dcrs->remove(i);
635             if (jcr->dcr == dcr) {
636                jcr->dcr = NULL;
637             }
638          }
639       }
640    }
641 }
642 #endif
643
644 static void attach_dcr_to_dev(DCR *dcr)
645 {
646    DEVICE *dev = dcr->dev;
647    JCR *jcr = dcr->jcr;
648
649    if (jcr) Dmsg1(500, "JobId=%u enter attach_dcr_to_dev\n", (uint32_t)jcr->JobId);
650    if (!dcr->attached_to_dev && dev->initiated && jcr && jcr->JobType != JT_SYSTEM) {
651       dev->attached_dcrs->append(dcr);  /* attach dcr to device */
652       dcr->attached_to_dev = true;
653       Dmsg1(500, "JobId=%u attach_dcr_to_dev\n", (uint32_t)jcr->JobId);
654    }
655 }
656
657 void detach_dcr_from_dev(DCR *dcr)
658 {
659    DEVICE *dev = dcr->dev;
660    Dmsg0(500, "Enter detach_dcr_from_dev\n"); /* jcr is NULL in some cases */
661
662    /* Detach this dcr only if attached */
663    if (dcr->attached_to_dev && dev) {
664       dev->dlock();
665       dcr->unreserve_device();
666       dcr->dev->attached_dcrs->remove(dcr);  /* detach dcr from device */
667       dcr->attached_to_dev = false;
668 //    remove_dcr_from_dcrs(dcr);      /* remove dcr from jcr list */
669       dev->dunlock();
670    }
671 }
672
673 /*
674  * Free up all aspects of the given dcr -- i.e. dechain it,
675  *  release allocated memory, zap pointers, ...
676  */
677 void free_dcr(DCR *dcr)
678 {
679    JCR *jcr = dcr->jcr;
680
681    detach_dcr_from_dev(dcr);
682
683    if (dcr->block) {
684       free_block(dcr->block);
685    }
686    if (dcr->rec) {
687       free_record(dcr->rec);
688    }
689    if (jcr && jcr->dcr == dcr) {
690       jcr->dcr = NULL;
691    }
692    free(dcr);
693 }