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;
59 char VolumeName[MAX_NAME_LENGTH];
62 static dlist *vol_list = NULL;
63 static pthread_mutex_t vol_list_lock = PTHREAD_MUTEX_INITIALIZER;
64 static pthread_mutex_t search_lock = PTHREAD_MUTEX_INITIALIZER;
66 /* Forward referenced functions */
67 static int can_reserve_drive(DCR *dcr, RCTX &rctx);
68 static int search_res_for_device(RCTX &rctx);
69 static int reserve_device(RCTX &rctx);
70 static bool reserve_device_for_read(DCR *dcr);
71 static bool reserve_device_for_append(DCR *dcr, RCTX &rctx);
72 static bool use_storage_cmd(JCR *jcr);
73 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx);
75 /* Requests from the Director daemon */
76 static char use_storage[] = "use storage=%127s media_type=%127s "
77 "pool_name=%127s pool_type=%127s append=%d copy=%d stripe=%d\n";
78 static char use_device[] = "use device=%127s\n";
80 /* Responses sent to Director daemon */
81 static char OK_device[] = "3000 OK use device device=%s\n";
82 static char NO_device[] = "3924 Device \"%s\" not in SD Device resources.\n";
83 static char BAD_use[] = "3913 Bad use command: %s\n";
85 bool use_cmd(JCR *jcr)
88 * Get the device, media, and pool information
90 if (!use_storage_cmd(jcr)) {
91 set_jcr_job_status(jcr, JS_ErrorTerminated);
92 memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
98 static int my_compare(void *item1, void *item2)
100 return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
105 * Put a new Volume entry in the Volume list. This
106 * effectively reserves the volume so that it will
107 * not be mounted again.
109 * Return: VOLRES entry on success
110 * NULL if the Volume is already in the list
112 VOLRES *new_volume(DCR *dcr, const char *VolumeName)
116 Dmsg1(400, "new_volume %s\n", VolumeName);
117 vol = (VOLRES *)malloc(sizeof(VOLRES));
118 memset(vol, 0, sizeof(VOLRES));
119 vol->vol_name = bstrdup(VolumeName);
123 nvol = (VOLRES *)vol_list->binary_insert(vol, my_compare);
129 nvol->dev = dcr->dev;
137 * Search for a Volume name in the Volume list.
139 * Returns: VOLRES entry on success
140 * NULL if the Volume is not in the list
142 VOLRES *find_volume(const char *VolumeName)
145 vol.vol_name = bstrdup(VolumeName);
147 fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
154 * Free a Volume from the Volume list
156 * Returns: true if the Volume found and removed from the list
157 * false if the Volume is not in the list
159 bool free_volume(DEVICE *dev)
163 if (dev->VolHdr.VolumeName[0] == 0) {
166 Dmsg1(400, "free_volume %s\n", dev->VolHdr.VolumeName);
167 vol.vol_name = bstrdup(dev->VolHdr.VolumeName);
169 fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
171 vol_list->remove(fvol);
172 free(fvol->vol_name);
177 dev->VolHdr.VolumeName[0] = 0;
181 /* Free volume reserved by this dcr but not attached to a dev */
182 void free_unused_volume(DCR *dcr)
186 for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
187 if (vol->dcr == dcr && (vol->dev == NULL ||
188 strcmp(vol->vol_name, vol->dev->VolHdr.VolumeName) != 0)) {
189 vol_list->remove(vol);
199 * List Volumes -- this should be moved to status.c
201 void list_volumes(BSOCK *user)
204 for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
205 bnet_fsend(user, "%s\n", vol->vol_name);
209 /* Create the Volume list */
210 void create_volume_list()
212 VOLRES *dummy = NULL;
213 if (vol_list == NULL) {
214 vol_list = New(dlist(dummy, &dummy->link));
218 /* Release all Volumes from the list */
219 void free_volume_list()
225 for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
226 Dmsg3(000, "Unreleased Volume=%s dcr=0x%x dev=0x%x\n", vol->vol_name,
233 bool is_volume_in_use(DCR *dcr)
235 VOLRES *vol = find_volume(dcr->VolumeName);
237 return false; /* vol not in list */
239 if (!vol->dev) { /* vol not attached to device */
242 if (dcr->dev == vol->dev) { /* same device OK */
245 if (!vol->dev->is_busy()) {
252 static bool use_storage_cmd(JCR *jcr)
254 POOL_MEM store_name, dev_name, media_type, pool_name, pool_type;
255 BSOCK *dir = jcr->dir_bsock;
265 memset(&rctx, 0, sizeof(RCTX));
268 * If there are multiple devices, the director sends us
269 * use_device for each device that it wants to use.
271 Dmsg1(100, "<dird: %s", dir->msg);
272 jcr->dirstore = New(alist(10, not_owned_by_alist));
274 ok = sscanf(dir->msg, use_storage, store_name.c_str(),
275 media_type.c_str(), pool_name.c_str(),
276 pool_type.c_str(), &append, &Copy, &Stripe) == 7;
280 unbash_spaces(store_name);
281 unbash_spaces(media_type);
282 unbash_spaces(pool_name);
283 unbash_spaces(pool_type);
284 store = new DIRSTORE;
285 jcr->dirstore->append(store);
286 memset(store, 0, sizeof(DIRSTORE));
287 store->device = New(alist(10));
288 bstrncpy(store->name, store_name, sizeof(store->name));
289 bstrncpy(store->media_type, media_type, sizeof(store->media_type));
290 bstrncpy(store->pool_name, pool_name, sizeof(store->pool_name));
291 bstrncpy(store->pool_type, pool_type, sizeof(store->pool_type));
292 store->append = append;
294 /* Now get all devices */
295 while (bnet_recv(dir) >= 0) {
296 ok = sscanf(dir->msg, use_device, dev_name.c_str()) == 1;
300 unbash_spaces(dev_name);
301 store->device->append(bstrdup(dev_name.c_str()));
303 } while (ok && bnet_recv(dir) >= 0);
306 /* This loop is debug code and can be removed */
307 /* ***FIXME**** remove after 1.38 release */
309 foreach_alist(store, jcr->dirstore) {
310 Dmsg4(100, "Storage=%s media_type=%s pool=%s pool_type=%s\n",
311 store->name, store->media_type, store->pool_name,
313 foreach_alist(device_name, store->device) {
314 Dmsg1(100, " Device=%s\n", device_name);
320 * At this point, we have a list of all the Director's Storage
321 * resources indicated for this Job, which include Pool, PoolType,
322 * storage name, and Media type.
323 * Then for each of the Storage resources, we have a list of
324 * device names that were given.
326 * Wiffle through them and find one that can do the backup.
330 * Make up to two passes. The first with PreferMountedVols possibly
331 * set to true. In that case, we look only for an available
332 * drive with something mounted. If that fails, then we
333 * do a second pass with PerferMountedVols set false.
335 rctx.exact_match = true;
336 if ((ok = find_suitable_device_for_job(jcr, rctx))) {
339 rctx.exact_match = false;
340 rctx.PreferMountedVols = jcr->PreferMountedVols;
341 ok = find_suitable_device_for_job(jcr, rctx);
345 if (rctx.PreferMountedVols) {
346 rctx.PreferMountedVols = false;
347 ok = find_suitable_device_for_job(jcr, rctx);
353 unbash_spaces(dir->msg);
354 pm_strcpy(jcr->errmsg, dir->msg);
355 Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
357 Jmsg(jcr, M_FATAL, 0, _("\n"
358 " Device \"%s\" with MediaType \"%s\" requested by DIR not found in SD Device resources.\n"),
359 dev_name.c_str(), media_type.c_str());
360 bnet_fsend(dir, NO_device, dev_name.c_str());
362 for (error=(char*)rctx->errors.first(); error;
363 error=(char*)rctx->errors.next()) {
364 Jmsg(jcr, M_INFO, 0, "%s", error);
367 Dmsg1(100, ">dird: %s", dir->msg);
369 unbash_spaces(dir->msg);
370 pm_strcpy(jcr->errmsg, dir->msg);
372 Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
374 bnet_fsend(dir, BAD_use, jcr->errmsg);
375 Dmsg1(100, ">dird: %s", dir->msg);
379 foreach_alist(store, jcr->dirstore) {
380 delete store->device;
383 delete jcr->dirstore;
385 for (error=(char*)rctx->errors.first(); error;
386 error=(char*)rctx->errors.next()) {
395 * Search for a device suitable for this job.
397 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx)
405 init_jcr_device_wait_timers(jcr);
407 int can_wait = false;
410 foreach_alist(store, jcr->dirstore) {
412 foreach_alist(device_name, store->device) {
414 rctx.device_name = device_name;
415 stat = search_res_for_device(rctx);
416 if (stat == 1) { /* found available device */
419 } else if (stat == 0) { /* device busy */
422 /* otherwise error */
423 // rctx->errors.push(bstrdup(jcr->errmsg));
431 * We did not find a suitable device, so
432 * if there is some device for which we can wait, then
433 * wait and try again until the wait time expires
435 if (!can_wait || !wait_for_device(jcr, first)) {
438 first = false; /* first wait complete */
441 for (error=(char*)rctx->errors.first(); error;
442 error=(char*)rctx->errors.next()) {
455 * Search for a particular storage device with particular storage
456 * characteristics (MediaType).
458 static int search_res_for_device(RCTX &rctx)
460 AUTOCHANGER *changer;
461 BSOCK *dir = rctx.jcr->dir_bsock;
465 Dmsg1(100, "Search res for %s\n", rctx.device_name);
466 foreach_res(rctx.device, R_DEVICE) {
467 Dmsg1(100, "Try res=%s\n", rctx.device->hdr.name);
468 /* Find resource, and make sure we were able to open it */
469 if (fnmatch(rctx.device_name, rctx.device->hdr.name, 0) == 0) {
470 stat = reserve_device(rctx);
474 Dmsg1(220, "Got: %s", dir->msg);
475 bash_spaces(rctx.device_name);
476 ok = bnet_fsend(dir, OK_device, rctx.device_name);
477 Dmsg1(100, ">dird dev: %s", dir->msg);
481 foreach_res(changer, R_AUTOCHANGER) {
482 Dmsg1(100, "Try changer res=%s\n", changer->hdr.name);
483 /* Find resource, and make sure we were able to open it */
484 if (fnmatch(rctx.device_name, changer->hdr.name, 0) == 0) {
485 /* Try each device in this AutoChanger */
486 foreach_alist(rctx.device, changer->device) {
487 Dmsg1(100, "Try changer device %s\n", rctx.device->hdr.name);
488 stat = reserve_device(rctx);
489 if (stat == -1) { /* hard error */
492 if (stat == 0) { /* must wait, try next one */
496 Dmsg1(100, "Device %s opened.\n", rctx.device_name);
497 pm_strcpy(dev_name, rctx.device->hdr.name);
498 bash_spaces(dev_name);
499 ok = bnet_fsend(dir, OK_device, dev_name.c_str()); /* Return real device name */
500 Dmsg1(100, ">dird changer: %s", dir->msg);
505 return 0; /* nothing found */
509 * Try to reserve a specific device.
511 * Returns: 1 -- OK, have DCR
515 static int reserve_device(RCTX &rctx)
519 const int name_len = MAX_NAME_LENGTH;
521 /* Make sure MediaType is OK */
522 if (strcmp(rctx.device->media_type, rctx.store->media_type) != 0) {
526 if (!rctx.device->dev) {
527 rctx.device->dev = init_dev(rctx.jcr, rctx.device);
529 if (!rctx.device->dev) {
530 if (rctx.device->changer_res) {
531 Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
532 " Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
533 rctx.device->hdr.name, rctx.device_name);
535 Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
536 " Device \"%s\" requested by DIR could not be opened or does not exist.\n"),
539 return -1; /* no use waiting */
541 Dmsg1(100, "Found device %s\n", rctx.device->hdr.name);
542 dcr = new_dcr(rctx.jcr, rctx.device->dev);
544 BSOCK *dir = rctx.jcr->dir_bsock;
545 bnet_fsend(dir, _("3926 Could not get dcr for device: %s\n"), rctx.device_name);
546 Dmsg1(100, ">dird: %s", dir->msg);
550 bstrncpy(dcr->pool_name, rctx.store->pool_name, name_len);
551 bstrncpy(dcr->pool_type, rctx.store->pool_type, name_len);
552 bstrncpy(dcr->media_type, rctx.store->media_type, name_len);
553 bstrncpy(dcr->dev_name, rctx.device_name, name_len);
554 if (rctx.store->append == SD_APPEND) {
555 if (rctx.exact_match && !rctx.have_volume) {
556 dcr->any_volume = true;
557 if (dir_find_next_appendable_volume(dcr)) {
558 Dmsg1(000, "Looking for Volume=%s\n", dcr->VolumeName);
559 bstrncpy(rctx.VolumeName, dcr->VolumeName, sizeof(rctx.VolumeName));
560 rctx.have_volume = true;
562 Dmsg0(000, "No next volume found\n");
563 rctx.VolumeName[0] = 0;
566 ok = reserve_device_for_append(dcr, rctx);
567 Dmsg3(200, "dev_name=%s mediatype=%s ok=%d\n", dcr->dev_name, dcr->media_type, ok);
569 ok = reserve_device_for_read(dcr);
572 free_dcr(rctx.jcr->dcr);
579 * We "reserve" the drive by setting the ST_READ bit. No one else
580 * should touch the drive until that is cleared.
581 * This allows the DIR to "reserve" the device before actually
584 static bool reserve_device_for_read(DCR *dcr)
586 DEVICE *dev = dcr->dev;
592 dev->block(BST_DOING_ACQUIRE);
594 if (is_device_unmounted(dev)) {
595 Dmsg1(200, "Device %s is BLOCKED due to user unmount.\n", dev->print_name());
596 Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"),
601 if (dev->is_busy()) {
602 Dmsg4(200, "Device %s is busy ST_READ=%d num_writers=%d reserved=%d.\n", dev->print_name(),
603 dev->state & ST_READ?1:0, dev->num_writers, dev->reserved_device);
604 Mmsg1(jcr->errmsg, _("Device %s is busy.\n"),
620 * We reserve the device for appending by incrementing the
621 * reserved_device. We do virtually all the same work that
622 * is done in acquire_device_for_append(), but we do
623 * not attempt to mount the device. This routine allows
624 * the DIR to reserve multiple devices before *really*
625 * starting the job. It also permits the SD to refuse
626 * certain devices (not up, ...).
628 * Note, in reserving a device, if the device is for the
629 * same pool and the same pool type, then it is acceptable.
630 * The Media Type has already been checked. If we are
631 * the first tor reserve the device, we put the pool
632 * name and pool type in the device record.
634 static bool reserve_device_for_append(DCR *dcr, RCTX &rctx)
637 DEVICE *dev = dcr->dev;
642 dev->block(BST_DOING_ACQUIRE);
644 if (dev->can_read()) {
645 Mmsg1(jcr->errmsg, _("Device %s is busy reading.\n"), dev->print_name());
646 Dmsg1(100, "%s", jcr->errmsg);
650 if (is_device_unmounted(dev)) {
651 Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"), dev->print_name());
652 Dmsg1(100, "%s", jcr->errmsg);
656 Dmsg1(190, "reserve_append device is %s\n", dev->is_tape()?"tape":"disk");
658 if (can_reserve_drive(dcr, rctx) != 1) {
659 Mmsg1(jcr->errmsg, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
660 Dmsg1(100, "%s", jcr->errmsg);
664 dev->reserved_device++;
665 Dmsg1(200, "Inc reserve=%d\n", dev->reserved_device);
666 dcr->reserved_device = true;
675 * Returns: 1 if drive can be reserved
676 * 0 if we should wait
679 static int can_reserve_drive(DCR *dcr, RCTX &rctx)
681 DEVICE *dev = dcr->dev;
684 /* Check for prefer mounted volumes */
685 if (rctx.PreferMountedVols && !dev->VolHdr.VolumeName[0] && dev->is_tape()) {
686 Dmsg0(200, "want mounted -- no vol\n");
687 return 0; /* No volume mounted */
690 /* Check for exact Volume name match */
691 if (rctx.exact_match && rctx.have_volume &&
692 strcmp(dev->VolHdr.VolumeName, rctx.VolumeName) != 0) {
693 Dmsg2(200, "Not exact match have=%s want=%s\n",
694 dev->VolHdr.VolumeName, rctx.VolumeName);
699 * Handle the case that there are no writers
701 if (dev->num_writers == 0) {
702 /* Now check if there are any reservations on the drive */
703 if (dev->reserved_device) {
704 /* Now check if we want the same Pool and pool type */
705 if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
706 strcmp(dev->pool_type, dcr->pool_type) == 0) {
707 /* OK, compatible device */
708 Dmsg0(200, "got dev: num_writers=0, reserved, pool matches\n");
711 /* Drive not suitable for us */
712 Dmsg2(200, "busy: num_writers=0, reserved, pool=%s wanted=%s\n",
713 dev->pool_name, dcr->pool_name);
716 } else if (dev->can_append()) {
717 /* Device in append mode, check if changing pool */
718 if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
719 strcmp(dev->pool_type, dcr->pool_type) == 0) {
720 Dmsg0(200, "got dev: num_writers=0, can_append, pool matches\n");
721 /* OK, compatible device */
724 /* Changing pool, unload old tape if any in drive */
725 Dmsg0(200, "got dev: num_writers=0, reserved, pool change\n");
726 unload_autochanger(dcr, 0);
729 /* Device is available but not yet reserved, reserve it for us */
730 bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
731 bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
732 return 1; /* reserve drive */
736 * Check if the device is in append mode with writers (i.e.
737 * available if pool is the same).
739 if (dev->can_append() || dev->num_writers > 0) {
740 Dmsg0(190, "device already in append.\n");
741 /* Yes, now check if we want the same Pool and pool type */
742 if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
743 strcmp(dev->pool_type, dcr->pool_type) == 0) {
744 Dmsg0(200, "got dev: num_writers>=0, can_append, pool matches\n");
745 /* OK, compatible device */
748 /* Drive not suitable for us */
749 Jmsg(jcr, M_WARNING, 0, _("Wanted Pool \"%s\", but device %s is using Pool \"%s\" .\n"),
750 dcr->pool_name, dev->print_name(), dev->pool_name);
751 Dmsg2(200, "busy: num_writers>0, can_append, pool=%s wanted=%s\n",
752 dev->pool_name, dcr->pool_name);
756 Pmsg0(000, _("Logic error!!!! Should not get here.\n"));
757 Jmsg0(jcr, M_FATAL, 0, _("Logic error!!!! Should not get here.\n"));
758 return -1; /* error, should not get here */