2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
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.
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.
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
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.
29 * Drive reservation functions for Storage Daemon
33 * Split from job.c and acquire.c June 2005
42 const int dbglvl = 100;
44 static dlist *vol_list = NULL;
45 static pthread_mutex_t vol_list_lock = PTHREAD_MUTEX_INITIALIZER;
47 /* Forward referenced functions */
48 static int can_reserve_drive(DCR *dcr, RCTX &rctx);
49 static int reserve_device(RCTX &rctx);
50 static bool reserve_device_for_read(DCR *dcr);
51 static bool reserve_device_for_append(DCR *dcr, RCTX &rctx);
52 static bool use_storage_cmd(JCR *jcr);
53 static void queue_reserve_message(JCR *jcr);
55 /* Requests from the Director daemon */
56 static char use_storage[] = "use storage=%127s media_type=%127s "
57 "pool_name=%127s pool_type=%127s append=%d copy=%d stripe=%d\n";
58 static char use_device[] = "use device=%127s\n";
60 /* Responses sent to Director daemon */
61 static char OK_device[] = "3000 OK use device device=%s\n";
62 static char NO_device[] = "3924 Device \"%s\" not in SD Device resources.\n";
63 static char BAD_use[] = "3913 Bad use command: %s\n";
65 bool use_cmd(JCR *jcr)
68 * Get the device, media, and pool information
70 if (!use_storage_cmd(jcr)) {
71 set_jcr_job_status(jcr, JS_ErrorTerminated);
72 memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
78 static int my_compare(void *item1, void *item2)
80 return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
83 static brwlock_t reservation_lock;
85 void init_reservations_lock()
88 if ((errstat=rwl_init(&reservation_lock)) != 0) {
90 Emsg1(M_ABORT, 0, _("Unable to initialize reservation lock. ERR=%s\n"),
91 be.bstrerror(errstat));
96 void term_reservations_lock()
98 rwl_destroy(&reservation_lock);
101 int reservations_lock_count = 0;
103 /* This applies to a drive and to Volumes */
104 void _lock_reservations()
107 reservations_lock_count++;
108 if ((errstat=rwl_writelock(&reservation_lock)) != 0) {
110 Emsg2(M_ABORT, 0, "rwl_writelock failure. stat=%d: ERR=%s\n",
111 errstat, be.bstrerror(errstat));
115 void _unlock_reservations()
118 reservations_lock_count--;
119 if ((errstat=rwl_writeunlock(&reservation_lock)) != 0) {
121 Emsg2(M_ABORT, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n",
122 errstat, be.bstrerror(errstat));
127 * List Volumes -- this should be moved to status.c
134 static void debug_list_volumes(const char *imsg, bool do_lock)
137 POOL_MEM msg(PM_MESSAGE);
141 if (do_lock) P(vol_list_lock);
142 for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
144 Mmsg(msg, "List from %s: %s at %p on device %s\n", imsg,
145 vol->vol_name, vol->vol_name, vol->dev->print_name());
147 Mmsg(msg, "List from %s: %s at %p no dev\n", imsg, vol->vol_name, vol->vol_name);
149 Dmsg1(dbglvl, "%s", msg.c_str());
153 for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
154 if (vol->dev == dev) {
155 Dmsg0(000, "Two Volumes on same device.\n");
161 Dmsg2(dbglvl, "List from %s: %d volumes\n", imsg, count);
162 if (do_lock) V(vol_list_lock);
167 * List Volumes -- this should be moved to status.c
169 void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
172 POOL_MEM msg(PM_MESSAGE);
176 for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
178 len = Mmsg(msg, "%s on device %s\n", vol->vol_name, vol->dev->print_name());
179 sendit(msg.c_str(), len, arg);
181 len = Mmsg(msg, "%s no dev\n", vol->vol_name);
182 sendit(msg.c_str(), len, arg);
189 * Create a Volume item to put in the Volume list
190 * Ensure that the device points to it.
192 static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName)
195 vol = (VOLRES *)malloc(sizeof(VOLRES));
196 memset(vol, 0, sizeof(VOLRES));
197 vol->vol_name = bstrdup(VolumeName);
199 Dmsg4(dbglvl, "New Vol=%s at %p dev=%s JobId=%u\n", VolumeName, vol->vol_name,
200 vol->dev->print_name(), (int)dcr->jcr->JobId);
204 static void free_vol_item(VOLRES *vol)
208 vol->dev->vol = NULL;
215 * Put a new Volume entry in the Volume list. This
216 * effectively reserves the volume so that it will
217 * not be mounted again.
219 * If the device has any current volume associated with it,
220 * and it is a different Volume, and the device is not busy,
221 * we release the old Volume item and insert the new one.
223 * It is assumed that the device is free and locked so that
224 * we can change the device structure.
226 * Some details of the Volume list handling:
228 * 1. The Volume list entry must be attached to the drive (rather than
229 * attached to a job as it currently is. I.e. the drive that "owns"
230 * the volume (reserved, in use, mounted)
231 * must point to the volume (still to be maintained in a list).
233 * 2. The Volume is entered in the list when a drive is reserved.
235 * 3. When a drive is in use, the device code must appropriately update the
236 * volume name as it changes (currently the list is static -- an entry is
237 * removed when the Volume is no longer reserved, in use or mounted).
238 * The new code must keep the same list entry as long as the drive
239 * has any volume associated with it but the volume name in the list
240 * must be updated when the drive has a different volume mounted.
242 * 4. A job that has reserved a volume, can un-reserve the volume, and if the
243 * volume is not mounted, and not reserved, and not in use, it will be
244 * removed from the list.
246 * 5. If a job wants to reserve a drive with a different Volume from the one on
247 * the drive, it can re-use the drive for the new Volume.
249 * 6. If a job wants a Volume that is in a different drive, it can either use the
250 * other drive or take the volume, only if the other drive is not in use or
253 * One nice aspect of this is that the reserve use count and the writer use count
254 * already exist and are correctly programmed and will need no changes -- use
255 * counts are always very tricky.
257 * The old code had a concept of "reserving" a Volume, but it needs to be changed
258 * to reserving and using a drive. A volume is must be attached to (owned by) a
259 * drive and can move from drive to drive or be unused given certain specific
260 * conditions of the drive. The key is that the drive must "own" the Volume.
261 * The old code has the job (dcr) owning the volume (more or less). The job is
262 * to change the insertion and removal of the volumes from the list to be based
263 * on the drive rather than the job.
265 * Return: VOLRES entry on success
266 * NULL volume busy on another drive
268 VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
271 DEVICE *dev = dcr->dev;
275 Dmsg1(dbglvl, "reserve_volume %s\n", VolumeName);
277 * We lock the reservations system here to ensure
278 * when adding a new volume that no newly scheduled
279 * job can reserve it.
282 debug_list_volumes("begin reserve_volume", debug_nolock);
284 * First, remove any old volume attached to this device as it
290 * Make sure we don't remove the current volume we are inserting
291 * because it was probably inserted by another job.
293 if (strcmp(vol->vol_name, VolumeName) == 0) {
294 goto get_out; /* Volume already on this device */
296 Dmsg3(dbglvl, "reserve_vol free vol=%s at %p JobId=%u\n", vol->vol_name,
297 vol->vol_name, (int)dcr->jcr->JobId);
298 debug_list_volumes("reserve_vol free", debug_nolock);
299 vol_list->remove(vol);
304 /* Create a new Volume entry */
305 nvol = new_vol_item(dcr, VolumeName);
308 * Now try to insert the new Volume
310 vol = (VOLRES *)vol_list->binary_insert(nvol, my_compare);
312 Dmsg2(dbglvl, "Found vol=%s dev-same=%d\n", vol->vol_name, dev==vol->dev);
314 * At this point, a Volume with this name already is in the list,
315 * so we simply release our new Volume entry. Note, this should
316 * only happen if we are moving the volume from one drive to another.
318 Dmsg3(dbglvl, "reserve_vol free-tmp vol=%s at %p JobId=%u\n", vol->vol_name,
319 vol->vol_name, (int)dcr->jcr->JobId);
321 * Clear dev pointer so that free_vol_item() doesn't
322 * take away our volume.
324 nvol->dev = NULL; /* don't zap dev entry */
327 /* Check if we are trying to use the Volume on a different drive */
328 if (dev != vol->dev) {
329 /* Caller wants to switch Volume to another device */
330 if (!vol->dev->is_busy()) {
331 /* OK to move it -- I'm not sure this will work */
332 Dmsg3(dbglvl, "==== Swap vol=%s from dev=%s to %s\n", VolumeName,
333 vol->dev->print_name(), dev->print_name());
334 vol->dev->vol = NULL; /* take vol from old drive */
335 vol->dev->VolHdr.VolumeName[0] = 0;
336 vol->dev = dev; /* point vol at new drive */
337 dev->vol = vol; /* point dev at vol */
338 dev->VolHdr.VolumeName[0] = 0;
340 Dmsg3(dbglvl, "Volume busy could not swap vol=%s from dev=%s to %s\n", VolumeName,
341 vol->dev->print_name(), dev->print_name());
342 vol = NULL; /* device busy */
349 debug_list_volumes("end new volume", debug_nolock);
355 * Search for a Volume name in the Volume list.
357 * Returns: VOLRES entry on success
358 * NULL if the Volume is not in the list
360 VOLRES *find_volume(const char *VolumeName)
363 /* Do not lock reservations here */
365 vol.vol_name = bstrdup(VolumeName);
366 fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
368 Dmsg2(dbglvl, "find_vol=%s found=%d\n", VolumeName, fvol!=NULL);
369 debug_list_volumes("find_volume", debug_nolock);
375 * Remove any reservation from a drive and tell the system
376 * that the volume is unused at least by us.
378 void unreserve_device(DCR *dcr)
380 DEVICE *dev = dcr->dev;
382 if (dcr->reserved_device) {
383 dcr->reserved_device = false;
384 dev->reserved_device--;
385 Dmsg2(dbglvl, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
386 dcr->reserved_device = false;
387 /* If we set read mode in reserving, remove it */
388 if (dev->can_read()) {
391 if (dev->num_writers < 0) {
392 Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers);
393 dev->num_writers = 0;
402 * Free a Volume from the Volume list if it is no longer used
404 * Returns: true if the Volume found and removed from the list
405 * false if the Volume is not in the list or is in use
407 bool volume_unused(DCR *dcr)
409 DEVICE *dev = dcr->dev;
411 if (dev->vol == NULL) {
412 Dmsg1(dbglvl, " unreserve_volume: no vol on %s\n", dev->print_name());
413 debug_list_volumes("null return unreserve_volume", debug_lock);
417 if (dev->is_busy()) {
418 Dmsg1(dbglvl, "unreserve_volume: dev is busy %s\n", dev->print_name());
419 debug_list_volumes("dev busy return unreserve_volume", debug_lock);
423 return free_volume(dev);
427 * Unconditionally release the volume
429 bool free_volume(DEVICE *dev)
433 if (dev->vol == NULL) {
434 Dmsg1(dbglvl, "No vol on dev %s\n", dev->print_name());
440 Dmsg1(dbglvl, "free_volume %s\n", vol->vol_name);
441 vol_list->remove(vol);
442 Dmsg3(dbglvl, "free_volume %s at %p dev=%s\n", vol->vol_name, vol->vol_name,
445 debug_list_volumes("free_volume", debug_nolock);
451 /* Create the Volume list */
452 void create_volume_list()
454 VOLRES *dummy = NULL;
455 if (vol_list == NULL) {
456 vol_list = New(dlist(dummy, &dummy->link));
460 /* Release all Volumes from the list */
461 void free_volume_list()
468 for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
469 Dmsg2(dbglvl, "Unreleased Volume=%s dev=%p\n", vol->vol_name, vol->dev);
471 vol->vol_name = NULL;
478 bool is_volume_in_use(DCR *dcr)
480 VOLRES *vol = find_volume(dcr->VolumeName);
482 Dmsg1(dbglvl, "Vol=%s not in use.\n", dcr->VolumeName);
483 return false; /* vol not in list */
485 ASSERT(vol->dev != NULL);
487 if (dcr->dev == vol->dev) { /* same device OK */
488 Dmsg1(dbglvl, "Vol=%s on same dev.\n", dcr->VolumeName);
491 Dmsg3(dbglvl, "Vol=%s on %s we have %s\n", dcr->VolumeName,
492 vol->dev->print_name(), dcr->dev->print_name());
494 if (!vol->dev->is_busy()) {
495 Dmsg2(dbglvl, "Vol=%s dev=%s not busy.\n", dcr->VolumeName, vol->dev->print_name());
498 Dmsg2(dbglvl, "Vol=%s dev=%s busy.\n", dcr->VolumeName, vol->dev->print_name());
500 Dmsg2(dbglvl, "Vol=%s in use by %s.\n", dcr->VolumeName, vol->dev->print_name());
506 * We get the following type of information:
508 * use storage=xxx media_type=yyy pool_name=xxx pool_type=yyy append=1 copy=0 strip=0
512 * use storage=xxx media_type=yyy pool_name=xxx pool_type=yyy append=0 copy=0 strip=0
516 static bool use_storage_cmd(JCR *jcr)
518 POOL_MEM store_name, dev_name, media_type, pool_name, pool_type;
519 BSOCK *dir = jcr->dir_bsock;
529 memset(&rctx, 0, sizeof(RCTX));
532 * If there are multiple devices, the director sends us
533 * use_device for each device that it wants to use.
535 dirstore = New(alist(10, not_owned_by_alist));
536 msgs = jcr->reserve_msgs = New(alist(10, not_owned_by_alist));
538 Dmsg1(dbglvl, "<dird: %s", dir->msg);
539 ok = sscanf(dir->msg, use_storage, store_name.c_str(),
540 media_type.c_str(), pool_name.c_str(),
541 pool_type.c_str(), &append, &Copy, &Stripe) == 7;
546 jcr->write_store = dirstore;
548 jcr->read_store = dirstore;
550 rctx.append = append;
551 unbash_spaces(store_name);
552 unbash_spaces(media_type);
553 unbash_spaces(pool_name);
554 unbash_spaces(pool_type);
555 store = new DIRSTORE;
556 dirstore->append(store);
557 memset(store, 0, sizeof(DIRSTORE));
558 store->device = New(alist(10));
559 bstrncpy(store->name, store_name, sizeof(store->name));
560 bstrncpy(store->media_type, media_type, sizeof(store->media_type));
561 bstrncpy(store->pool_name, pool_name, sizeof(store->pool_name));
562 bstrncpy(store->pool_type, pool_type, sizeof(store->pool_type));
563 store->append = append;
565 /* Now get all devices */
566 while (dir->recv() >= 0) {
567 Dmsg1(dbglvl, "<dird device: %s", dir->msg);
568 ok = sscanf(dir->msg, use_device, dev_name.c_str()) == 1;
572 unbash_spaces(dev_name);
573 store->device->append(bstrdup(dev_name.c_str()));
575 } while (ok && dir->recv() >= 0);
578 /* This loop is debug code and can be removed */
579 /* ***FIXME**** remove after 1.38 release */
581 foreach_alist(store, dirstore) {
582 Dmsg6(dbglvl, "JobId=%u Storage=%s media_type=%s pool=%s pool_type=%s append=%d\n",
583 (int)rctx.jcr->JobId,
584 store->name, store->media_type, store->pool_name,
585 store->pool_type, store->append);
586 foreach_alist(device_name, store->device) {
587 Dmsg1(dbglvl, " Device=%s\n", device_name);
592 init_jcr_device_wait_timers(jcr);
594 * At this point, we have a list of all the Director's Storage
595 * resources indicated for this Job, which include Pool, PoolType,
596 * storage name, and Media type.
597 * Then for each of the Storage resources, we have a list of
598 * device names that were given.
600 * Wiffle through them and find one that can do the backup.
603 int retries = 0; /* wait for device retries */
606 rctx.notify_dir = true;
608 for ( ; !fail && !job_canceled(jcr); ) {
609 while ((msg = (char *)msgs->pop())) {
612 rctx.suitable_device = false;
613 rctx.have_volume = false;
614 rctx.VolumeName[0] = 0;
615 rctx.any_drive = false;
616 if (!jcr->PreferMountedVols) {
617 /* Look for unused drives in autochangers */
618 rctx.num_writers = 20000000; /* start with impossible number */
619 rctx.low_use_drive = NULL;
620 rctx.PreferMountedVols = false;
621 rctx.exact_match = false;
622 rctx.autochanger_only = true;
623 Dmsg6(dbglvl, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
624 (int)rctx.jcr->JobId,
625 rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
626 rctx.autochanger_only, rctx.any_drive);
627 if ((ok = find_suitable_device_for_job(jcr, rctx))) {
630 /* Look through all drives possibly for low_use drive */
631 if (rctx.low_use_drive) {
632 rctx.try_low_use_drive = true;
633 if ((ok = find_suitable_device_for_job(jcr, rctx))) {
636 rctx.try_low_use_drive = false;
638 rctx.autochanger_only = false;
639 Dmsg6(dbglvl, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
640 (int)rctx.jcr->JobId,
641 rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
642 rctx.autochanger_only, rctx.any_drive);
643 if ((ok = find_suitable_device_for_job(jcr, rctx))) {
647 /* Look for an exact match all drives */
648 rctx.PreferMountedVols = true;
649 rctx.exact_match = true;
650 rctx.autochanger_only = false;
651 Dmsg6(dbglvl, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
652 (int)rctx.jcr->JobId,
653 rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
654 rctx.autochanger_only, rctx.any_drive);
655 if ((ok = find_suitable_device_for_job(jcr, rctx))) {
658 /* Look for any mounted drive */
659 rctx.exact_match = false;
660 Dmsg6(dbglvl, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
661 (int)rctx.jcr->JobId,
662 rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
663 rctx.autochanger_only, rctx.any_drive);
664 if ((ok = find_suitable_device_for_job(jcr, rctx))) {
668 rctx.any_drive = true;
669 Dmsg6(dbglvl, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
670 (int)rctx.jcr->JobId,
671 rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
672 rctx.autochanger_only, rctx.any_drive);
673 if ((ok = find_suitable_device_for_job(jcr, rctx))) {
676 /* Keep reservations locked *except* during wait_for_device() */
677 unlock_reservations();
679 * The idea of looping on repeat a few times it to ensure
680 * that if there is some subtle timing problem between two
681 * jobs, we will simply try again, and most likely succeed.
682 * This can happen if one job reserves a drive or finishes using
683 * a drive at the same time a second job wants it.
685 if (repeat++ > 1) { /* try algorithm 3 times */
686 bmicrosleep(30, 0); /* wait a bit */
687 } else if (!rctx.suitable_device || !wait_for_device(jcr, retries)) {
688 Dmsg1(dbglvl, "JobId=%u Fail. !suitable_device || !wait_for_device\n",
689 (int)rctx.jcr->JobId);
693 bnet_sig(dir, BNET_HEARTBEAT); /* Inform Dir that we are alive */
695 unlock_reservations();
698 * If we get here, there are no suitable devices available, which
699 * means nothing configured. If a device is suitable but busy
700 * with another Volume, we will not come here.
702 unbash_spaces(dir->msg);
703 pm_strcpy(jcr->errmsg, dir->msg);
704 Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
705 Jmsg(jcr, M_FATAL, 0, _("\n"
706 " Device \"%s\" with MediaType \"%s\" requested by DIR not found in SD Device resources.\n"),
707 dev_name.c_str(), media_type.c_str());
708 bnet_fsend(dir, NO_device, dev_name.c_str());
710 Dmsg1(dbglvl, ">dird: %s", dir->msg);
713 unbash_spaces(dir->msg);
714 pm_strcpy(jcr->errmsg, dir->msg);
715 Jmsg(jcr, M_FATAL, 0, _("Failed command: %s\n"), jcr->errmsg);
716 bnet_fsend(dir, BAD_use, jcr->errmsg);
717 Dmsg1(dbglvl, ">dird: %s", dir->msg);
724 void release_msgs(JCR *jcr)
726 alist *msgs = jcr->reserve_msgs;
733 while ((msg = (char *)msgs->pop())) {
737 jcr->reserve_msgs = NULL;
738 unlock_reservations();
742 * Search for a device suitable for this job.
744 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx)
752 dirstore = jcr->write_store;
754 dirstore = jcr->read_store;
757 * For each storage device that the user specified, we
758 * search and see if there is a resource for that device.
760 Dmsg5(dbglvl, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d\n",
761 (int)rctx.jcr->JobId,
762 rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
763 rctx.autochanger_only);
765 foreach_alist(store, dirstore) {
767 foreach_alist(device_name, store->device) {
769 rctx.device_name = device_name;
770 stat = search_res_for_device(rctx);
771 if (stat == 1) { /* found available device */
772 Dmsg2(dbglvl, "JobId=%u Suitable device found=%s\n", (int)rctx.jcr->JobId,
776 } else if (stat == 0) { /* device busy */
777 Dmsg2(dbglvl, "JobId=%u Suitable device=%s, busy: not use\n",
778 (int)rctx.jcr->JobId, device_name);
780 /* otherwise error */
781 Dmsg1(dbglvl, "JobId=%u No suitable device found.\n", (int)rctx.jcr->JobId);
792 * Search for a particular storage device with particular storage
793 * characteristics (MediaType).
795 int search_res_for_device(RCTX &rctx)
797 AUTOCHANGER *changer;
798 BSOCK *dir = rctx.jcr->dir_bsock;
802 Dmsg2(dbglvl, "JobId=%u search res for %s\n", (int)rctx.jcr->JobId, rctx.device_name);
803 /* Look through Autochangers first */
804 foreach_res(changer, R_AUTOCHANGER) {
805 Dmsg2(150, "JobId=%u Try match changer res=%s\n", (int)rctx.jcr->JobId, changer->hdr.name);
806 /* Find resource, and make sure we were able to open it */
807 if (fnmatch(rctx.device_name, changer->hdr.name, 0) == 0) {
808 /* Try each device in this AutoChanger */
809 foreach_alist(rctx.device, changer->device) {
810 Dmsg2(dbglvl, "JobId=%u Try changer device %s\n", (int)rctx.jcr->JobId,
811 rctx.device->hdr.name);
812 stat = reserve_device(rctx);
813 if (stat != 1) { /* try another device */
817 if (rctx.store->append == SD_APPEND) {
818 Dmsg3(dbglvl, "JobId=%u Device %s reserved=%d for append.\n",
819 (int)rctx.jcr->JobId, rctx.device->hdr.name,
820 rctx.jcr->dcr->dev->reserved_device);
822 Dmsg3(dbglvl, "JobId=%u Device %s reserved=%d for read.\n",
823 (int)rctx.jcr->JobId, rctx.device->hdr.name,
824 rctx.jcr->read_dcr->dev->reserved_device);
826 if (rctx.notify_dir) {
827 pm_strcpy(dev_name, rctx.device->hdr.name);
828 bash_spaces(dev_name);
829 ok = bnet_fsend(dir, OK_device, dev_name.c_str()); /* Return real device name */
830 Dmsg1(dbglvl, ">dird changer: %s", dir->msg);
839 /* Now if requested look through regular devices */
840 if (!rctx.autochanger_only) {
841 foreach_res(rctx.device, R_DEVICE) {
842 Dmsg2(150, "JobId=%u Try match res=%s\n", (int)rctx.jcr->JobId, rctx.device->hdr.name);
843 /* Find resource, and make sure we were able to open it */
844 if (fnmatch(rctx.device_name, rctx.device->hdr.name, 0) == 0) {
845 stat = reserve_device(rctx);
849 if (rctx.notify_dir) {
850 bash_spaces(rctx.device_name);
851 ok = bnet_fsend(dir, OK_device, rctx.device_name);
852 Dmsg1(dbglvl, ">dird dev: %s", dir->msg);
860 return -1; /* nothing found */
864 * Try to reserve a specific device.
866 * Returns: 1 -- OK, have DCR
870 static int reserve_device(RCTX &rctx)
874 const int name_len = MAX_NAME_LENGTH;
876 /* Make sure MediaType is OK */
877 Dmsg3(dbglvl, "JobId=%u MediaType device=%s request=%s\n",
878 (int)rctx.jcr->JobId,
879 rctx.device->media_type, rctx.store->media_type);
880 if (strcmp(rctx.device->media_type, rctx.store->media_type) != 0) {
884 /* Make sure device exists -- i.e. we can stat() it */
885 if (!rctx.device->dev) {
886 rctx.device->dev = init_dev(rctx.jcr, rctx.device);
888 if (!rctx.device->dev) {
889 if (rctx.device->changer_res) {
890 Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
891 " Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
892 rctx.device->hdr.name, rctx.device_name);
894 Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
895 " Device \"%s\" requested by DIR could not be opened or does not exist.\n"),
898 return -1; /* no use waiting */
901 rctx.suitable_device = true;
902 Dmsg2(dbglvl, "Try reserve %s JobId=%u\n", rctx.device->hdr.name,
904 dcr = new_dcr(rctx.jcr, rctx.device->dev);
906 BSOCK *dir = rctx.jcr->dir_bsock;
907 bnet_fsend(dir, _("3926 Could not get dcr for device: %s\n"), rctx.device_name);
908 Dmsg1(dbglvl, ">dird: %s", dir->msg);
911 bstrncpy(dcr->pool_name, rctx.store->pool_name, name_len);
912 bstrncpy(dcr->pool_type, rctx.store->pool_type, name_len);
913 bstrncpy(dcr->media_type, rctx.store->media_type, name_len);
914 bstrncpy(dcr->dev_name, rctx.device_name, name_len);
915 if (rctx.store->append == SD_APPEND) {
916 Dmsg3(dbglvl, "JobId=%u have_vol=%d vol=%s\n", (int)rctx.jcr->JobId,
917 rctx.have_volume, rctx.VolumeName);
918 if (!rctx.have_volume) {
919 dcr->any_volume = true;
920 if (dir_find_next_appendable_volume(dcr)) {
921 bstrncpy(rctx.VolumeName, dcr->VolumeName, sizeof(rctx.VolumeName));
922 Dmsg2(dbglvl, "JobId=%u looking for Volume=%s\n", (int)rctx.jcr->JobId, rctx.VolumeName);
923 rctx.have_volume = true;
925 Dmsg1(dbglvl, "JobId=%u No next volume found\n", (int)rctx.jcr->JobId);
926 rctx.have_volume = false;
927 rctx.VolumeName[0] = 0;
930 ok = reserve_device_for_append(dcr, rctx);
933 Dmsg6(dbglvl, "JobId=%u Reserved=%d dev_name=%s mediatype=%s pool=%s ok=%d\n",
934 (int)rctx.jcr->JobId,
935 dcr->dev->reserved_device,
936 dcr->dev_name, dcr->media_type, dcr->pool_name, ok);
939 ok = reserve_device_for_read(dcr);
941 rctx.jcr->read_dcr = dcr;
942 Dmsg6(dbglvl, "JobId=%u Read reserved=%d dev_name=%s mediatype=%s pool=%s ok=%d\n",
943 (int)rctx.jcr->JobId,
944 dcr->dev->reserved_device,
945 dcr->dev_name, dcr->media_type, dcr->pool_name, ok);
949 rctx.have_volume = false;
951 Dmsg1(dbglvl, "JobId=%u Not OK.\n", (int)rctx.jcr->JobId);
958 * We "reserve" the drive by setting the ST_READ bit. No one else
959 * should touch the drive until that is cleared.
960 * This allows the DIR to "reserve" the device before actually
963 static bool reserve_device_for_read(DCR *dcr)
965 DEVICE *dev = dcr->dev;
973 if (is_device_unmounted(dev)) {
974 Dmsg2(dbglvl, "JobId=%u Device %s is BLOCKED due to user unmount.\n",
975 (int)jcr->JobId, dev->print_name());
976 Mmsg(jcr->errmsg, _("3601 JobId=%u device %s is BLOCKED due to user unmount.\n"),
977 jcr->JobId, dev->print_name());
978 queue_reserve_message(jcr);
982 if (dev->is_busy()) {
983 Dmsg5(dbglvl, "JobId=%u Device %s is busy ST_READ=%d num_writers=%d reserved=%d.\n",
984 (int)jcr->JobId, dev->print_name(),
985 dev->state & ST_READ?1:0, dev->num_writers, dev->reserved_device);
986 Mmsg(jcr->errmsg, _("3602 JobId=%u device %s is busy (already reading/writing).\n"),
987 jcr->JobId, dev->print_name());
988 queue_reserve_message(jcr);
995 dev->reserved_device++;
996 Dmsg4(dbglvl, "JobId=%u Inc reserve=%d dev=%s %p\n", (int)jcr->JobId,
997 dev->reserved_device, dev->print_name(), dev);
998 dcr->reserved_device = true;
1007 * We reserve the device for appending by incrementing the
1008 * reserved_device. We do virtually all the same work that
1009 * is done in acquire_device_for_append(), but we do
1010 * not attempt to mount the device. This routine allows
1011 * the DIR to reserve multiple devices before *really*
1012 * starting the job. It also permits the SD to refuse
1013 * certain devices (not up, ...).
1015 * Note, in reserving a device, if the device is for the
1016 * same pool and the same pool type, then it is acceptable.
1017 * The Media Type has already been checked. If we are
1018 * the first tor reserve the device, we put the pool
1019 * name and pool type in the device record.
1021 static bool reserve_device_for_append(DCR *dcr, RCTX &rctx)
1023 JCR *jcr = dcr->jcr;
1024 DEVICE *dev = dcr->dev;
1031 /* If device is being read, we cannot write it */
1032 if (dev->can_read()) {
1033 Mmsg(jcr->errmsg, _("3603 JobId=%u device %s is busy reading.\n"),
1034 jcr->JobId, dev->print_name());
1035 Dmsg1(dbglvl, "%s", jcr->errmsg);
1036 queue_reserve_message(jcr);
1040 /* If device is unmounted, we are out of luck */
1041 if (is_device_unmounted(dev)) {
1042 Mmsg(jcr->errmsg, _("3604 JobId=%u device %s is BLOCKED due to user unmount.\n"),
1043 jcr->JobId, dev->print_name());
1044 Dmsg1(dbglvl, "%s", jcr->errmsg);
1045 queue_reserve_message(jcr);
1049 Dmsg2(dbglvl, "JobId=%u reserve_append device is %s\n",
1050 (int)jcr->JobId, dev->print_name());
1052 /* Now do detailed tests ... */
1053 if (can_reserve_drive(dcr, rctx) != 1) {
1054 Dmsg1(dbglvl, "JobId=%u can_reserve_drive!=1\n", (int)jcr->JobId);
1058 dev->reserved_device++;
1059 Dmsg4(dbglvl, "JobId=%u Inc reserve=%d dev=%s %p\n", (int)jcr->JobId, dev->reserved_device,
1060 dev->print_name(), dev);
1061 dcr->reserved_device = true;
1070 * Returns: 1 if drive can be reserved
1071 * 0 if we should wait
1072 * -1 on error or impossibility
1074 static int can_reserve_drive(DCR *dcr, RCTX &rctx)
1076 DEVICE *dev = dcr->dev;
1077 JCR *jcr = dcr->jcr;
1079 Dmsg6(dbglvl, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
1081 rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
1082 rctx.autochanger_only, rctx.any_drive);
1084 /* setting any_drive overrides PreferMountedVols flag */
1085 if (!rctx.any_drive) {
1087 * When PreferMountedVols is set, we keep track of the
1088 * drive in use that has the least number of writers, then if
1089 * no unmounted drive is found, we try that drive. This
1090 * helps spread the load to the least used drives.
1092 if (rctx.try_low_use_drive && dev == rctx.low_use_drive) {
1093 Dmsg3(dbglvl, "OK dev=%s == low_drive=%s. JobId=%u\n",
1094 dev->print_name(), rctx.low_use_drive->print_name(), jcr->JobId);
1097 /* If he wants a free drive, but this one is busy, no go */
1098 if (!rctx.PreferMountedVols && dev->is_busy()) {
1099 /* Save least used drive */
1100 if ((dev->num_writers + dev->reserved_device) < rctx.num_writers) {
1101 rctx.num_writers = dev->num_writers + dev->reserved_device;
1102 rctx.low_use_drive = dev;
1103 Dmsg3(dbglvl, "JobId=%u set low use drive=%s num_writers=%d\n",
1104 (int)jcr->JobId, dev->print_name(), rctx.num_writers);
1106 Dmsg2(dbglvl, "JobId=%u not low use num_writers=%d\n",
1107 (int)jcr->JobId, dev->num_writers+dev->reserved_device);
1109 Dmsg1(dbglvl, "failed: !prefMnt && busy. JobId=%u\n", jcr->JobId);
1110 Mmsg(jcr->errmsg, _("3605 JobId=%u wants free drive but device %s is busy.\n"),
1111 jcr->JobId, dev->print_name());
1112 queue_reserve_message(jcr);
1116 /* Check for prefer mounted volumes */
1117 // if (rctx.PreferMountedVols && !dev->VolHdr.VolumeName[0] && dev->is_tape()) {
1118 if (rctx.PreferMountedVols && !dev->vol && dev->is_tape()) {
1119 Mmsg(jcr->errmsg, _("3606 JobId=%u prefers mounted drives, but drive %s has no Volume.\n"),
1120 jcr->JobId, dev->print_name());
1121 queue_reserve_message(jcr);
1122 Dmsg1(dbglvl, "failed: want mounted -- no vol JobId=%u\n", (uint32_t)jcr->JobId);
1123 return 0; /* No volume mounted */
1126 /* Check for exact Volume name match */
1127 /* ***FIXME*** for Disk, we can accept any volume that goes with this
1130 if (rctx.exact_match && rctx.have_volume) {
1132 Dmsg6(dbglvl, "JobId=%u PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
1134 rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
1135 rctx.autochanger_only, rctx.any_drive);
1136 Dmsg5(dbglvl, "JobId=%u have_vol=%d have=%s resvol=%s want=%s\n",
1137 (int)jcr->JobId, rctx.have_volume, dev->VolHdr.VolumeName,
1138 dev->vol?dev->vol->vol_name:"*none*", rctx.VolumeName);
1139 ok = strcmp(dev->VolHdr.VolumeName, rctx.VolumeName) == 0 ||
1140 (dev->vol && strcmp(dev->vol->vol_name, rctx.VolumeName) == 0);
1142 Mmsg(jcr->errmsg, _("3607 JobId=%u wants Vol=\"%s\" drive has Vol=\"%s\" on drive %s.\n"),
1143 jcr->JobId, rctx.VolumeName, dev->VolHdr.VolumeName,
1145 queue_reserve_message(jcr);
1146 Dmsg4(dbglvl, "JobId=%u failed: dev have=%s resvol=%s want=%s\n",
1147 (int)jcr->JobId, dev->VolHdr.VolumeName,
1148 dev->vol?dev->vol->vol_name:"*none*", rctx.VolumeName);
1151 if (is_volume_in_use(dcr)) {
1152 return 0; /* fail if volume on another drive */
1157 /* Check for unused autochanger drive */
1158 if (rctx.autochanger_only && !dev->is_busy() &&
1159 dev->VolHdr.VolumeName[0] == 0) {
1160 /* Device is available but not yet reserved, reserve it for us */
1161 Dmsg2(dbglvl, "OK Res Unused autochanger %s JobId=%u.\n",
1162 dev->print_name(), jcr->JobId);
1163 bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
1164 bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
1165 return 1; /* reserve drive */
1169 * Handle the case that there are no writers
1171 if (dev->num_writers == 0) {
1172 /* Now check if there are any reservations on the drive */
1173 if (dev->reserved_device) {
1174 /* Now check if we want the same Pool and pool type */
1175 if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
1176 strcmp(dev->pool_type, dcr->pool_type) == 0) {
1177 /* OK, compatible device */
1178 Dmsg2(dbglvl, "OK dev: %s num_writers=0, reserved, pool matches JobId=%u\n",
1179 dev->print_name(), jcr->JobId);
1182 /* Drive Pool not suitable for us */
1183 Mmsg(jcr->errmsg, _(
1184 "3608 JobId=%u wants Pool=\"%s\" but have Pool=\"%s\" nreserve=%d on drive %s.\n"),
1185 jcr->JobId, dcr->pool_name, dev->pool_name,
1186 dev->reserved_device, dev->print_name());
1187 queue_reserve_message(jcr);
1188 Dmsg3(dbglvl, "JobId=%u failed: busy num_writers=0, reserved, pool=%s wanted=%s\n",
1189 (int)jcr->JobId, dev->pool_name, dcr->pool_name);
1190 return 0; /* wait */
1192 } else if (dev->can_append()) {
1193 /* Device in append mode, check if changing pool */
1194 if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
1195 strcmp(dev->pool_type, dcr->pool_type) == 0) {
1196 Dmsg2(dbglvl, "OK dev: %s num_writers=0, can_append, pool matches. JobId=%u\n",
1197 dev->print_name(), jcr->JobId);
1198 /* OK, compatible device */
1201 /* Changing pool, unload old tape if any in drive */
1202 Dmsg1(dbglvl, "JobId=%u OK dev: num_writers=0, not reserved, pool change, unload changer\n",
1204 unload_autochanger(dcr, 0);
1207 /* Device is available but not yet reserved, reserve it for us */
1208 Dmsg2(dbglvl, "OK Dev avail reserved %s JobId=%u\n", dev->print_name(),
1210 bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
1211 bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
1212 return 1; /* reserve drive */
1216 * Check if the device is in append mode with writers (i.e.
1217 * available if pool is the same).
1219 if (dev->can_append() || dev->num_writers > 0) {
1220 /* Yes, now check if we want the same Pool and pool type */
1221 if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
1222 strcmp(dev->pool_type, dcr->pool_type) == 0) {
1223 Dmsg2(dbglvl, "OK dev: %s num_writers>=0, can_append, pool matches. JobId=%u\n",
1224 dev->print_name(), jcr->JobId);
1225 /* OK, compatible device */
1228 /* Drive Pool not suitable for us */
1229 Mmsg(jcr->errmsg, _("3609 JobId=%u wants Pool=\"%s\" but has Pool=\"%s\" on drive %s.\n"),
1230 jcr->JobId, dcr->pool_name, dev->pool_name, dev->print_name());
1231 queue_reserve_message(jcr);
1232 Dmsg3(dbglvl, "JobId=%u failed: busy num_writers>0, can_append, pool=%s wanted=%s\n",
1233 (int)jcr->JobId, dev->pool_name, dcr->pool_name);
1234 return 0; /* wait */
1237 Pmsg1(000, _("Logic error!!!! JobId=%u Should not get here.\n"), (int)jcr->JobId);
1238 Mmsg(jcr->errmsg, _("3910 JobId=%u Logic error!!!! drive %s Should not get here.\n"),
1239 jcr->JobId, dev->print_name());
1240 queue_reserve_message(jcr);
1241 Jmsg0(jcr, M_FATAL, 0, _("Logic error!!!! Should not get here.\n"));
1242 return -1; /* error, should not get here */
1244 Mmsg(jcr->errmsg, _("3911 JobId=%u failed reserve drive %s.\n"),
1245 jcr->JobId, dev->print_name());
1246 queue_reserve_message(jcr);
1247 Dmsg2(dbglvl, "failed: No reserve %s JobId=%u\n", dev->print_name(), jcr->JobId);
1252 * search_lock is already set on entering this routine
1254 static void queue_reserve_message(JCR *jcr)
1257 alist *msgs = jcr->reserve_msgs;
1264 * Look for duplicate message. If found, do
1267 for (i=msgs->size()-1; i >= 0; i--) {
1268 msg = (char *)msgs->get(i);
1272 /* Comparison based on 4 digit message number */
1273 if (strncmp(msg, jcr->errmsg, 4) == 0) {
1277 /* Message unique, so insert it */
1278 jcr->reserve_msgs->push(bstrdup(jcr->errmsg));
1282 * Send any reservation messages queued for this jcr
1284 void send_drive_reserve_messages(JCR *jcr, void sendit(const char *msg, int len, void *sarg), void *arg)
1290 lock_reservations();
1291 msgs = jcr->reserve_msgs;
1292 if (!msgs || msgs->size() == 0) {
1293 unlock_reservations();
1296 for (i=msgs->size()-1; i >= 0; i--) {
1297 msg = (char *)msgs->get(i);
1299 sendit(" ", 3, arg);
1300 sendit(msg, strlen(msg), arg);
1305 unlock_reservations();