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 ammended 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 static dlist *vol_list = NULL;
60 static pthread_mutex_t vol_list_lock = PTHREAD_MUTEX_INITIALIZER;
62 /* Forward referenced functions */
63 static int can_reserve_drive(DCR *dcr, bool PerferMountedVols);
64 static int search_res_for_device(RCTX &rctx);
65 static int reserve_device(RCTX &rctx);
66 static bool reserve_device_for_read(DCR *dcr);
67 static bool reserve_device_for_append(DCR *dcr, bool PreferMountedVols);
68 static bool use_storage_cmd(JCR *jcr);
69 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx);
71 /* Requests from the Director daemon */
72 static char use_storage[] = "use storage=%127s media_type=%127s "
73 "pool_name=%127s pool_type=%127s append=%d copy=%d stripe=%d\n";
74 static char use_device[] = "use device=%127s\n";
76 /* Responses sent to Director daemon */
77 static char OK_device[] = "3000 OK use device device=%s\n";
78 static char NO_device[] = "3924 Device \"%s\" not in SD Device resources.\n";
79 static char BAD_use[] = "3913 Bad use command: %s\n";
81 bool use_cmd(JCR *jcr)
84 * Get the device, media, and pool information
86 if (!use_storage_cmd(jcr)) {
87 set_jcr_job_status(jcr, JS_ErrorTerminated);
88 memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
94 static int my_compare(void *item1, void *item2)
96 return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
101 * Put a new Volume entry in the Volume list. This
102 * effectively reserves the volume so that it will
103 * not be mounted again.
105 * Return: VOLRES entry on success
106 * NULL if the Volume is already in the list
108 VOLRES *new_volume(const char *VolumeName, DEVICE *dev)
111 vol = (VOLRES *)malloc(sizeof(VOLRES));
112 memset(vol, 0, sizeof(VOLRES));
113 vol->vol_name = bstrdup(VolumeName);
116 nvol = (VOLRES *)vol_list->binary_insert(vol, my_compare);
130 * Search for a Volume name in the Volume list.
132 * Returns: VOLRES entry on success
133 * NULL if the Volume is not in the list
135 VOLRES *find_volume(const char *VolumeName)
138 vol.vol_name = bstrdup(VolumeName);
140 fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
147 * Free a Volume from the Volume list
149 * Returns: true if the Volume found and removed from the list
150 * false if the Volume is not in the list
152 bool free_volume(DEVICE *dev)
156 if (dev->VolHdr.VolumeName[0] == 0) {
159 vol.vol_name = bstrdup(dev->VolHdr.VolumeName);
161 fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
163 vol_list->remove(fvol);
164 free(fvol->vol_name);
169 dev->VolHdr.VolumeName[0] = 0;
174 * List Volumes -- this should be moved to status.c
176 void list_volumes(BSOCK *user)
179 for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
180 bnet_fsend(user, "%s\n", vol->vol_name);
184 /* Create the Volume list */
185 void create_volume_list()
188 if (vol_list == NULL) {
189 vol_list = New(dlist(dummy, &dummy->link));
193 /* Release all Volumes from the list */
194 void free_volume_list()
197 for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
198 Dmsg1(000, "Unreleased Volume=%s\n", vol->vol_name);
204 bool is_volume_in_use(const char *VolumeName)
206 VOLRES *vol = find_volume(VolumeName);
208 return false; /* vol not in list */
210 if (!vol->dev) { /* vol not attached to device */
213 if (!vol->dev->is_busy()) {
220 static bool use_storage_cmd(JCR *jcr)
222 POOL_MEM store_name, dev_name, media_type, pool_name, pool_type;
223 BSOCK *dir = jcr->dir_bsock;
235 * If there are multiple devices, the director sends us
236 * use_device for each device that it wants to use.
238 Dmsg1(100, "<dird: %s", dir->msg);
239 jcr->dirstore = New(alist(10, not_owned_by_alist));
241 ok = sscanf(dir->msg, use_storage, store_name.c_str(),
242 media_type.c_str(), pool_name.c_str(),
243 pool_type.c_str(), &append, &Copy, &Stripe) == 7;
247 unbash_spaces(store_name);
248 unbash_spaces(media_type);
249 unbash_spaces(pool_name);
250 unbash_spaces(pool_type);
251 store = new DIRSTORE;
252 jcr->dirstore->append(store);
253 memset(store, 0, sizeof(DIRSTORE));
254 store->device = New(alist(10));
255 bstrncpy(store->name, store_name, sizeof(store->name));
256 bstrncpy(store->media_type, media_type, sizeof(store->media_type));
257 bstrncpy(store->pool_name, pool_name, sizeof(store->pool_name));
258 bstrncpy(store->pool_type, pool_type, sizeof(store->pool_type));
259 store->append = append;
261 /* Now get all devices */
262 while (bnet_recv(dir) >= 0) {
263 ok = sscanf(dir->msg, use_device, dev_name.c_str()) == 1;
267 unbash_spaces(dev_name);
268 store->device->append(bstrdup(dev_name.c_str()));
270 } while (ok && bnet_recv(dir) >= 0);
273 /* This loop is debug code and can be removed */
274 /* ***FIXME**** remove after 1.38 release */
276 foreach_alist(store, jcr->dirstore) {
277 Dmsg4(100, "Storage=%s media_type=%s pool=%s pool_type=%s\n",
278 store->name, store->media_type, store->pool_name,
280 foreach_alist(device_name, store->device) {
281 Dmsg1(100, " Device=%s\n", device_name);
287 * At this point, we have a list of all the Director's Storage
288 * resources indicated for this Job, which include Pool, PoolType,
289 * storage name, and Media type.
290 * Then for each of the Storage resources, we have a list of
291 * device names that were given.
293 * Wiffle through them and find one that can do the backup.
297 * Make up to two passes. The first with PreferMountedVols possibly
298 * set to true. In that case, we look only for an available
299 * drive with something mounted. If that fails, then we
300 * do a second pass with PerferMountedVols set false.
302 rctx.PreferMountedVols = jcr->PreferMountedVols;
303 ok = find_suitable_device_for_job(jcr, rctx);
307 if (rctx.PreferMountedVols) {
308 rctx.PreferMountedVols = false;
309 ok = find_suitable_device_for_job(jcr, rctx);
315 unbash_spaces(dir->msg);
316 pm_strcpy(jcr->errmsg, dir->msg);
317 Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
319 Jmsg(jcr, M_FATAL, 0, _("\n"
320 " Device \"%s\" with MediaType \"%s\" requested by DIR not found in SD Device resources.\n"),
321 dev_name.c_str(), media_type.c_str());
322 bnet_fsend(dir, NO_device, dev_name.c_str());
324 for (error=(char*)rctx->errors.first(); error;
325 error=(char*)rctx->errors.next()) {
326 Jmsg(jcr, M_INFO, 0, "%s", error);
329 Dmsg1(100, ">dird: %s\n", dir->msg);
331 unbash_spaces(dir->msg);
332 pm_strcpy(jcr->errmsg, dir->msg);
334 Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
336 bnet_fsend(dir, BAD_use, jcr->errmsg);
337 Dmsg1(100, ">dird: %s\n", dir->msg);
341 foreach_alist(store, jcr->dirstore) {
342 delete store->device;
345 delete jcr->dirstore;
347 for (error=(char*)rctx->errors.first(); error;
348 error=(char*)rctx->errors.next()) {
357 * Search for a device suitable for this job.
359 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx)
367 init_jcr_device_wait_timers(jcr);
369 int need_wait = false;
370 foreach_alist(store, jcr->dirstore) {
372 foreach_alist(device_name, store->device) {
374 rctx.device_name = device_name;
375 stat = search_res_for_device(rctx);
376 if (stat == 1) { /* found available device */
380 } else if (stat == 0) { /* device busy */
383 /* otherwise error */
384 // rctx->errors.push(bstrdup(jcr->errmsg));
388 * If there is some device for which we can wait, then
389 * wait and try again until the wait time expires
391 if (!need_wait || !wait_for_device(jcr, first)) {
396 for (error=(char*)rctx->errors.first(); error;
397 error=(char*)rctx->errors.next()) {
410 * Search for a particular storage device with particular storage
411 * characteristics (MediaType).
413 static int search_res_for_device(RCTX &rctx)
415 AUTOCHANGER *changer;
416 BSOCK *dir = rctx.jcr->dir_bsock;
420 Dmsg1(100, "Search res for %s\n", rctx.device_name);
421 foreach_res(rctx.device, R_DEVICE) {
422 Dmsg1(100, "Try res=%s\n", rctx.device->hdr.name);
423 /* Find resource, and make sure we were able to open it */
424 if (fnmatch(rctx.device_name, rctx.device->hdr.name, 0) == 0 &&
425 strcmp(rctx.device->media_type, rctx.store->media_type) == 0) {
426 stat = reserve_device(rctx);
430 Dmsg1(220, "Got: %s", dir->msg);
431 bash_spaces(rctx.device_name);
432 ok = bnet_fsend(dir, OK_device, rctx.device_name);
433 Dmsg1(100, ">dird: %s\n", dir->msg);
437 foreach_res(changer, R_AUTOCHANGER) {
438 Dmsg1(100, "Try changer res=%s\n", changer->hdr.name);
439 /* Find resource, and make sure we were able to open it */
440 if (fnmatch(rctx.device_name, changer->hdr.name, 0) == 0) {
441 /* Try each device in this AutoChanger */
442 foreach_alist(rctx.device, changer->device) {
443 Dmsg1(100, "Try changer device %s\n", rctx.device->hdr.name);
444 stat = reserve_device(rctx);
445 if (stat == -1) { /* hard error */
448 if (stat == 0) { /* must wait, try next one */
452 Dmsg1(100, "Device %s opened.\n", rctx.device_name);
453 pm_strcpy(dev_name, rctx.device->hdr.name);
454 bash_spaces(dev_name);
455 ok = bnet_fsend(dir, OK_device, dev_name.c_str()); /* Return real device name */
456 Dmsg1(100, ">dird: %s\n", dir->msg);
461 return 0; /* nothing found */
465 * Try to reserve a specific device.
467 * Returns: 1 -- OK, have DCR
471 static int reserve_device(RCTX &rctx)
475 const int name_len = MAX_NAME_LENGTH;
476 if (!rctx.device->dev) {
477 rctx.device->dev = init_dev(rctx.jcr, rctx.device);
479 if (!rctx.device->dev) {
480 if (rctx.device->changer_res) {
481 Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
482 " Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
483 rctx.device->hdr.name, rctx.device_name);
485 Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
486 " Device \"%s\" requested by DIR could not be opened or does not exist.\n"),
489 return -1; /* no use waiting */
491 Dmsg1(100, "Found device %s\n", rctx.device->hdr.name);
492 dcr = new_dcr(rctx.jcr, rctx.device->dev);
494 BSOCK *dir = rctx.jcr->dir_bsock;
495 bnet_fsend(dir, _("3926 Could not get dcr for device: %s\n"), rctx.device_name);
496 Dmsg1(100, ">dird: %s\n", dir->msg);
500 bstrncpy(dcr->pool_name, rctx.store->pool_name, name_len);
501 bstrncpy(dcr->pool_type, rctx.store->pool_type, name_len);
502 bstrncpy(dcr->media_type, rctx.store->media_type, name_len);
503 bstrncpy(dcr->dev_name, rctx.device_name, name_len);
504 if (rctx.store->append == SD_APPEND) {
505 ok = reserve_device_for_append(dcr, rctx.PreferMountedVols);
506 Dmsg3(200, "dev_name=%s mediatype=%s ok=%d\n", dcr->dev_name, dcr->media_type, ok);
508 ok = reserve_device_for_read(dcr);
511 free_dcr(rctx.jcr->dcr);
518 * We "reserve" the drive by setting the ST_READ bit. No one else
519 * should touch the drive until that is cleared.
520 * This allows the DIR to "reserve" the device before actually
523 static bool reserve_device_for_read(DCR *dcr)
525 DEVICE *dev = dcr->dev;
531 dev->block(BST_DOING_ACQUIRE);
533 if (device_is_unmounted(dev)) {
534 Dmsg1(200, "Device %s is BLOCKED due to user unmount.\n", dev->print_name());
535 Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"),
540 if (dev->is_busy()) {
541 Dmsg4(200, "Device %s is busy ST_READ=%d num_writers=%d reserved=%d.\n", dev->print_name(),
542 dev->state & ST_READ?1:0, dev->num_writers, dev->reserved_device);
543 Mmsg1(jcr->errmsg, _("Device %s is busy.\n"),
559 * We reserve the device for appending by incrementing the
560 * reserved_device. We do virtually all the same work that
561 * is done in acquire_device_for_append(), but we do
562 * not attempt to mount the device. This routine allows
563 * the DIR to reserve multiple devices before *really*
564 * starting the job. It also permits the SD to refuse
565 * certain devices (not up, ...).
567 * Note, in reserving a device, if the device is for the
568 * same pool and the same pool type, then it is acceptable.
569 * The Media Type has already been checked. If we are
570 * the first tor reserve the device, we put the pool
571 * name and pool type in the device record.
573 static bool reserve_device_for_append(DCR *dcr, bool PreferMountedVols)
576 DEVICE *dev = dcr->dev;
581 dev->block(BST_DOING_ACQUIRE);
583 if (dev->can_read()) {
584 Mmsg1(jcr->errmsg, _("Device %s is busy reading.\n"), dev->print_name());
585 Dmsg1(100, "%s", jcr->errmsg);
589 if (device_is_unmounted(dev)) {
590 Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"), dev->print_name());
591 Dmsg1(100, "%s", jcr->errmsg);
595 Dmsg1(190, "reserve_append device is %s\n", dev->is_tape()?"tape":"disk");
597 if (can_reserve_drive(dcr, PreferMountedVols) != 1) {
598 Mmsg1(jcr->errmsg, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
599 Dmsg1(100, "%s", jcr->errmsg);
603 dev->reserved_device++;
604 Dmsg1(200, "============= Inc reserve=%d\n", dev->reserved_device);
605 dcr->reserved_device = true;
614 * Returns: 1 if drive can be reserved
615 * 0 if we should wait
618 static int can_reserve_drive(DCR *dcr, bool PreferMountedVols)
620 DEVICE *dev = dcr->dev;
623 if (PreferMountedVols && !dev->VolHdr.VolumeName[0] &&
624 dev->is_tape() && !dev->is_autochanger()) {
625 return 0; /* No volume mounted */
629 * Handle the case that the drive is not yet in append mode
631 if (!dev->can_append() && dev->num_writers == 0) {
632 /* Now check if there are any reservations on the drive */
633 if (dev->reserved_device) {
634 /* Yes, now check if we want the same Pool and pool type */
635 if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
636 strcmp(dev->pool_type, dcr->pool_type) == 0) {
637 /* OK, compatible device */
639 /* Drive not suitable for us */
643 /* Device is available but not yet reserved, reserve it for us */
644 bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
645 bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
647 return 1; /* reserve drive */
651 * Check if device in append mode with no writers (i.e. available)
653 if (dev->can_append() && dev->num_writers == 0) {
654 /* Device is available but not yet reserved, reserve it for us */
655 bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
656 bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
660 * Check if the device is in append mode with writers (i.e.
661 * available if pool is the same).
663 if (dev->can_append() || dev->num_writers > 0) {
664 Dmsg0(190, "device already in append.\n");
665 /* Yes, now check if we want the same Pool and pool type */
666 if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
667 strcmp(dev->pool_type, dcr->pool_type) == 0) {
668 /* OK, compatible device */
671 /* Drive not suitable for us */
672 Jmsg(jcr, M_WARNING, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
676 Pmsg0(000, "Logic error!!!! Should not get here.\n");
677 Jmsg0(jcr, M_FATAL, 0, _("Logic error!!!! Should not get here.\n"));
678 return -1; /* error, should not get here */