2 * Drive reservation functions for Storage Daemon
6 * Split from job.c and acquire.c June 2005
12 Copyright (C) 2000-2005 Kern Sibbald
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License
16 version 2 as amended with additional clauses defined in the
17 file LICENSE in the main source directory.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 the file LICENSE for additional details.
30 * Use Device command from Director
31 * He tells is what Device Name to use, the Media Type,
32 * the Pool Name, and the Pool Type.
34 * Ensure that the device exists and is opened, then store
35 * the media and pool info in the JCR. This class is used
36 * only temporarily in this file.
42 char name[MAX_NAME_LENGTH];
43 char media_type[MAX_NAME_LENGTH];
44 char pool_name[MAX_NAME_LENGTH];
45 char pool_type[MAX_NAME_LENGTH];
56 bool PreferMountedVols;
57 char VolumeName[MAX_NAME_LENGTH];
60 static dlist *vol_list = NULL;
61 static pthread_mutex_t vol_list_lock = PTHREAD_MUTEX_INITIALIZER;
62 static pthread_mutex_t search_lock = PTHREAD_MUTEX_INITIALIZER;
64 /* Forward referenced functions */
65 static int can_reserve_drive(DCR *dcr, bool PerferMountedVols);
66 static int search_res_for_device(RCTX &rctx);
67 static int reserve_device(RCTX &rctx);
68 static bool reserve_device_for_read(DCR *dcr);
69 static bool reserve_device_for_append(DCR *dcr, bool PreferMountedVols);
70 static bool use_storage_cmd(JCR *jcr);
71 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx);
73 /* Requests from the Director daemon */
74 static char use_storage[] = "use storage=%127s media_type=%127s "
75 "pool_name=%127s pool_type=%127s append=%d copy=%d stripe=%d\n";
76 static char use_device[] = "use device=%127s\n";
78 /* Responses sent to Director daemon */
79 static char OK_device[] = "3000 OK use device device=%s\n";
80 static char NO_device[] = "3924 Device \"%s\" not in SD Device resources.\n";
81 static char BAD_use[] = "3913 Bad use command: %s\n";
83 bool use_cmd(JCR *jcr)
86 * Get the device, media, and pool information
88 if (!use_storage_cmd(jcr)) {
89 set_jcr_job_status(jcr, JS_ErrorTerminated);
90 memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
96 static int my_compare(void *item1, void *item2)
98 return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
103 * Put a new Volume entry in the Volume list. This
104 * effectively reserves the volume so that it will
105 * not be mounted again.
107 * Return: VOLRES entry on success
108 * NULL if the Volume is already in the list
110 VOLRES *new_volume(DCR *dcr, const char *VolumeName)
114 Dmsg1(400, "new_volume %s\n", VolumeName);
115 vol = (VOLRES *)malloc(sizeof(VOLRES));
116 memset(vol, 0, sizeof(VOLRES));
117 vol->vol_name = bstrdup(VolumeName);
121 nvol = (VOLRES *)vol_list->binary_insert(vol, my_compare);
127 nvol->dev = dcr->dev;
135 * Search for a Volume name in the Volume list.
137 * Returns: VOLRES entry on success
138 * NULL if the Volume is not in the list
140 VOLRES *find_volume(const char *VolumeName)
143 vol.vol_name = bstrdup(VolumeName);
145 fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
152 * Free a Volume from the Volume list
154 * Returns: true if the Volume found and removed from the list
155 * false if the Volume is not in the list
157 bool free_volume(DEVICE *dev)
161 if (dev->VolHdr.VolumeName[0] == 0) {
164 Dmsg1(400, "free_volume %s\n", dev->VolHdr.VolumeName);
165 vol.vol_name = bstrdup(dev->VolHdr.VolumeName);
167 fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
169 vol_list->remove(fvol);
170 free(fvol->vol_name);
175 dev->VolHdr.VolumeName[0] = 0;
179 /* Free volume reserved by this dcr but not attached to a dev */
180 void free_unused_volume(DCR *dcr)
184 for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
185 if (vol->dcr == dcr && (vol->dev == NULL ||
186 strcmp(vol->vol_name, vol->dev->VolHdr.VolumeName) != 0)) {
187 vol_list->remove(vol);
197 * List Volumes -- this should be moved to status.c
199 void list_volumes(BSOCK *user)
202 for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
203 bnet_fsend(user, "%s\n", vol->vol_name);
207 /* Create the Volume list */
208 void create_volume_list()
210 VOLRES *dummy = NULL;
211 if (vol_list == NULL) {
212 vol_list = New(dlist(dummy, &dummy->link));
216 /* Release all Volumes from the list */
217 void free_volume_list()
223 for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
224 Dmsg3(000, "Unreleased Volume=%s dcr=0x%x dev=0x%x\n", vol->vol_name,
231 bool is_volume_in_use(DCR *dcr)
233 VOLRES *vol = find_volume(dcr->VolumeName);
235 return false; /* vol not in list */
237 if (!vol->dev) { /* vol not attached to device */
240 if (dcr->dev == vol->dev) { /* same device OK */
243 if (!vol->dev->is_busy()) {
250 static bool use_storage_cmd(JCR *jcr)
252 POOL_MEM store_name, dev_name, media_type, pool_name, pool_type;
253 BSOCK *dir = jcr->dir_bsock;
263 memset(&rctx, 0, sizeof(RCTX));
266 * If there are multiple devices, the director sends us
267 * use_device for each device that it wants to use.
269 Dmsg1(100, "<dird: %s", dir->msg);
270 jcr->dirstore = New(alist(10, not_owned_by_alist));
272 ok = sscanf(dir->msg, use_storage, store_name.c_str(),
273 media_type.c_str(), pool_name.c_str(),
274 pool_type.c_str(), &append, &Copy, &Stripe) == 7;
278 unbash_spaces(store_name);
279 unbash_spaces(media_type);
280 unbash_spaces(pool_name);
281 unbash_spaces(pool_type);
282 store = new DIRSTORE;
283 jcr->dirstore->append(store);
284 memset(store, 0, sizeof(DIRSTORE));
285 store->device = New(alist(10));
286 bstrncpy(store->name, store_name, sizeof(store->name));
287 bstrncpy(store->media_type, media_type, sizeof(store->media_type));
288 bstrncpy(store->pool_name, pool_name, sizeof(store->pool_name));
289 bstrncpy(store->pool_type, pool_type, sizeof(store->pool_type));
290 store->append = append;
292 /* Now get all devices */
293 while (bnet_recv(dir) >= 0) {
294 ok = sscanf(dir->msg, use_device, dev_name.c_str()) == 1;
298 unbash_spaces(dev_name);
299 store->device->append(bstrdup(dev_name.c_str()));
301 } while (ok && bnet_recv(dir) >= 0);
304 /* This loop is debug code and can be removed */
305 /* ***FIXME**** remove after 1.38 release */
307 foreach_alist(store, jcr->dirstore) {
308 Dmsg4(100, "Storage=%s media_type=%s pool=%s pool_type=%s\n",
309 store->name, store->media_type, store->pool_name,
311 foreach_alist(device_name, store->device) {
312 Dmsg1(100, " Device=%s\n", device_name);
318 * At this point, we have a list of all the Director's Storage
319 * resources indicated for this Job, which include Pool, PoolType,
320 * storage name, and Media type.
321 * Then for each of the Storage resources, we have a list of
322 * device names that were given.
324 * Wiffle through them and find one that can do the backup.
328 * Make up to two passes. The first with PreferMountedVols possibly
329 * set to true. In that case, we look only for an available
330 * drive with something mounted. If that fails, then we
331 * do a second pass with PerferMountedVols set false.
333 rctx.PreferMountedVols = jcr->PreferMountedVols;
334 ok = find_suitable_device_for_job(jcr, rctx);
338 if (rctx.PreferMountedVols) {
339 rctx.PreferMountedVols = false;
340 ok = find_suitable_device_for_job(jcr, rctx);
346 unbash_spaces(dir->msg);
347 pm_strcpy(jcr->errmsg, dir->msg);
348 Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
350 Jmsg(jcr, M_FATAL, 0, _("\n"
351 " Device \"%s\" with MediaType \"%s\" requested by DIR not found in SD Device resources.\n"),
352 dev_name.c_str(), media_type.c_str());
353 bnet_fsend(dir, NO_device, dev_name.c_str());
355 for (error=(char*)rctx->errors.first(); error;
356 error=(char*)rctx->errors.next()) {
357 Jmsg(jcr, M_INFO, 0, "%s", error);
360 Dmsg1(100, ">dird: %s", dir->msg);
362 unbash_spaces(dir->msg);
363 pm_strcpy(jcr->errmsg, dir->msg);
365 Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
367 bnet_fsend(dir, BAD_use, jcr->errmsg);
368 Dmsg1(100, ">dird: %s", dir->msg);
372 foreach_alist(store, jcr->dirstore) {
373 delete store->device;
376 delete jcr->dirstore;
378 for (error=(char*)rctx->errors.first(); error;
379 error=(char*)rctx->errors.next()) {
388 * Search for a device suitable for this job.
390 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx)
398 init_jcr_device_wait_timers(jcr);
400 int can_wait = false;
403 foreach_alist(store, jcr->dirstore) {
405 foreach_alist(device_name, store->device) {
407 rctx.device_name = device_name;
408 stat = search_res_for_device(rctx);
409 if (stat == 1) { /* found available device */
412 } else if (stat == 0) { /* device busy */
415 /* otherwise error */
416 // rctx->errors.push(bstrdup(jcr->errmsg));
424 * We did not find a suitable device, so
425 * if there is some device for which we can wait, then
426 * wait and try again until the wait time expires
428 if (!can_wait || !wait_for_device(jcr, first)) {
431 first = false; /* first wait complete */
434 for (error=(char*)rctx->errors.first(); error;
435 error=(char*)rctx->errors.next()) {
448 * Search for a particular storage device with particular storage
449 * characteristics (MediaType).
451 static int search_res_for_device(RCTX &rctx)
453 AUTOCHANGER *changer;
454 BSOCK *dir = rctx.jcr->dir_bsock;
458 Dmsg1(100, "Search res for %s\n", rctx.device_name);
459 foreach_res(rctx.device, R_DEVICE) {
460 Dmsg1(100, "Try res=%s\n", rctx.device->hdr.name);
461 /* Find resource, and make sure we were able to open it */
462 if (fnmatch(rctx.device_name, rctx.device->hdr.name, 0) == 0) {
463 stat = reserve_device(rctx);
467 Dmsg1(220, "Got: %s", dir->msg);
468 bash_spaces(rctx.device_name);
469 ok = bnet_fsend(dir, OK_device, rctx.device_name);
470 Dmsg1(100, ">dird dev: %s", dir->msg);
474 foreach_res(changer, R_AUTOCHANGER) {
475 Dmsg1(100, "Try changer res=%s\n", changer->hdr.name);
476 /* Find resource, and make sure we were able to open it */
477 if (fnmatch(rctx.device_name, changer->hdr.name, 0) == 0) {
478 /* Try each device in this AutoChanger */
479 foreach_alist(rctx.device, changer->device) {
480 Dmsg1(100, "Try changer device %s\n", rctx.device->hdr.name);
481 stat = reserve_device(rctx);
482 if (stat == -1) { /* hard error */
485 if (stat == 0) { /* must wait, try next one */
489 Dmsg1(100, "Device %s opened.\n", rctx.device_name);
490 pm_strcpy(dev_name, rctx.device->hdr.name);
491 bash_spaces(dev_name);
492 ok = bnet_fsend(dir, OK_device, dev_name.c_str()); /* Return real device name */
493 Dmsg1(100, ">dird changer: %s", dir->msg);
498 return 0; /* nothing found */
502 * Try to reserve a specific device.
504 * Returns: 1 -- OK, have DCR
508 static int reserve_device(RCTX &rctx)
512 const int name_len = MAX_NAME_LENGTH;
514 /* Make sure MediaType is OK */
515 if (strcmp(rctx.device->media_type, rctx.store->media_type) != 0) {
519 if (!rctx.device->dev) {
520 rctx.device->dev = init_dev(rctx.jcr, rctx.device);
522 if (!rctx.device->dev) {
523 if (rctx.device->changer_res) {
524 Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
525 " Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
526 rctx.device->hdr.name, rctx.device_name);
528 Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
529 " Device \"%s\" requested by DIR could not be opened or does not exist.\n"),
532 return -1; /* no use waiting */
534 Dmsg1(100, "Found device %s\n", rctx.device->hdr.name);
535 dcr = new_dcr(rctx.jcr, rctx.device->dev);
537 BSOCK *dir = rctx.jcr->dir_bsock;
538 bnet_fsend(dir, _("3926 Could not get dcr for device: %s\n"), rctx.device_name);
539 Dmsg1(100, ">dird: %s", dir->msg);
543 bstrncpy(dcr->pool_name, rctx.store->pool_name, name_len);
544 bstrncpy(dcr->pool_type, rctx.store->pool_type, name_len);
545 bstrncpy(dcr->media_type, rctx.store->media_type, name_len);
546 bstrncpy(dcr->dev_name, rctx.device_name, name_len);
547 if (rctx.store->append == SD_APPEND) {
549 if (dir_find_next_appendable_volume(dcr)) {
550 Dmsg1(000, "Looking for Volume=%s\n", dcr->VolumeName);
552 Dmsg0(000, "No next volume found\n");
553 dcr->VolumeName[0] = 0;
556 ok = reserve_device_for_append(dcr, rctx.PreferMountedVols);
557 Dmsg3(200, "dev_name=%s mediatype=%s ok=%d\n", dcr->dev_name, dcr->media_type, ok);
559 ok = reserve_device_for_read(dcr);
562 free_dcr(rctx.jcr->dcr);
569 * We "reserve" the drive by setting the ST_READ bit. No one else
570 * should touch the drive until that is cleared.
571 * This allows the DIR to "reserve" the device before actually
574 static bool reserve_device_for_read(DCR *dcr)
576 DEVICE *dev = dcr->dev;
582 dev->block(BST_DOING_ACQUIRE);
584 if (is_device_unmounted(dev)) {
585 Dmsg1(200, "Device %s is BLOCKED due to user unmount.\n", dev->print_name());
586 Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"),
591 if (dev->is_busy()) {
592 Dmsg4(200, "Device %s is busy ST_READ=%d num_writers=%d reserved=%d.\n", dev->print_name(),
593 dev->state & ST_READ?1:0, dev->num_writers, dev->reserved_device);
594 Mmsg1(jcr->errmsg, _("Device %s is busy.\n"),
610 * We reserve the device for appending by incrementing the
611 * reserved_device. We do virtually all the same work that
612 * is done in acquire_device_for_append(), but we do
613 * not attempt to mount the device. This routine allows
614 * the DIR to reserve multiple devices before *really*
615 * starting the job. It also permits the SD to refuse
616 * certain devices (not up, ...).
618 * Note, in reserving a device, if the device is for the
619 * same pool and the same pool type, then it is acceptable.
620 * The Media Type has already been checked. If we are
621 * the first tor reserve the device, we put the pool
622 * name and pool type in the device record.
624 static bool reserve_device_for_append(DCR *dcr, bool PreferMountedVols)
627 DEVICE *dev = dcr->dev;
632 dev->block(BST_DOING_ACQUIRE);
634 if (dev->can_read()) {
635 Mmsg1(jcr->errmsg, _("Device %s is busy reading.\n"), dev->print_name());
636 Dmsg1(100, "%s", jcr->errmsg);
640 if (is_device_unmounted(dev)) {
641 Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"), dev->print_name());
642 Dmsg1(100, "%s", jcr->errmsg);
646 Dmsg1(190, "reserve_append device is %s\n", dev->is_tape()?"tape":"disk");
648 if (can_reserve_drive(dcr, PreferMountedVols) != 1) {
649 Mmsg1(jcr->errmsg, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
650 Dmsg1(100, "%s", jcr->errmsg);
654 dev->reserved_device++;
655 Dmsg1(200, "Inc reserve=%d\n", dev->reserved_device);
656 dcr->reserved_device = true;
665 * Returns: 1 if drive can be reserved
666 * 0 if we should wait
669 static int can_reserve_drive(DCR *dcr, bool PreferMountedVols)
671 DEVICE *dev = dcr->dev;
674 if (PreferMountedVols && !dev->VolHdr.VolumeName[0] && dev->is_tape()) {
675 return 0; /* No volume mounted */
679 * Handle the case that there are no writers
681 if (dev->num_writers == 0) {
682 /* Now check if there are any reservations on the drive */
683 if (dev->reserved_device) {
684 /* Yes, now check if we want the same Pool and pool type */
685 if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
686 strcmp(dev->pool_type, dcr->pool_type) == 0) {
687 /* OK, compatible device */
689 /* Drive not suitable for us */
692 } else if (dev->can_append()) {
693 /* Device in append mode, check if changing pool */
694 if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
695 strcmp(dev->pool_type, dcr->pool_type) == 0) {
696 /* OK, compatible device */
698 /* Changing pool, unload old tape if any in drive */
699 unload_autochanger(dcr, 0);
702 /* Device is available but not yet reserved, reserve it for us */
703 bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
704 bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
705 return 1; /* reserve drive */
709 * Check if the device is in append mode with writers (i.e.
710 * available if pool is the same).
712 if (dev->can_append() || dev->num_writers > 0) {
713 Dmsg0(190, "device already in append.\n");
714 /* Yes, now check if we want the same Pool and pool type */
715 if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
716 strcmp(dev->pool_type, dcr->pool_type) == 0) {
717 /* OK, compatible device */
720 /* Drive not suitable for us */
721 Jmsg(jcr, M_WARNING, 0, _("Wanted Pool \"%s\", but device %s is using Pool \"%s\" .\n"),
722 dcr->pool_name, dev->print_name(), dev->pool_name);
726 Pmsg0(000, _("Logic error!!!! Should not get here.\n"));
727 Jmsg0(jcr, M_FATAL, 0, _("Logic error!!!! Should not get here.\n"));
728 return -1; /* error, should not get here */