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()
200 for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
201 Dmsg1(000, "Unreleased Volume=%s\n", vol->vol_name);
207 bool is_volume_in_use(const char *VolumeName)
209 VOLRES *vol = find_volume(VolumeName);
211 return false; /* vol not in list */
213 if (!vol->dev) { /* vol not attached to device */
216 if (!vol->dev->is_busy()) {
223 static bool use_storage_cmd(JCR *jcr)
225 POOL_MEM store_name, dev_name, media_type, pool_name, pool_type;
226 BSOCK *dir = jcr->dir_bsock;
238 * If there are multiple devices, the director sends us
239 * use_device for each device that it wants to use.
241 Dmsg1(100, "<dird: %s", dir->msg);
242 jcr->dirstore = New(alist(10, not_owned_by_alist));
244 ok = sscanf(dir->msg, use_storage, store_name.c_str(),
245 media_type.c_str(), pool_name.c_str(),
246 pool_type.c_str(), &append, &Copy, &Stripe) == 7;
250 unbash_spaces(store_name);
251 unbash_spaces(media_type);
252 unbash_spaces(pool_name);
253 unbash_spaces(pool_type);
254 store = new DIRSTORE;
255 jcr->dirstore->append(store);
256 memset(store, 0, sizeof(DIRSTORE));
257 store->device = New(alist(10));
258 bstrncpy(store->name, store_name, sizeof(store->name));
259 bstrncpy(store->media_type, media_type, sizeof(store->media_type));
260 bstrncpy(store->pool_name, pool_name, sizeof(store->pool_name));
261 bstrncpy(store->pool_type, pool_type, sizeof(store->pool_type));
262 store->append = append;
264 /* Now get all devices */
265 while (bnet_recv(dir) >= 0) {
266 ok = sscanf(dir->msg, use_device, dev_name.c_str()) == 1;
270 unbash_spaces(dev_name);
271 store->device->append(bstrdup(dev_name.c_str()));
273 } while (ok && bnet_recv(dir) >= 0);
276 /* This loop is debug code and can be removed */
277 /* ***FIXME**** remove after 1.38 release */
279 foreach_alist(store, jcr->dirstore) {
280 Dmsg4(100, "Storage=%s media_type=%s pool=%s pool_type=%s\n",
281 store->name, store->media_type, store->pool_name,
283 foreach_alist(device_name, store->device) {
284 Dmsg1(100, " Device=%s\n", device_name);
290 * At this point, we have a list of all the Director's Storage
291 * resources indicated for this Job, which include Pool, PoolType,
292 * storage name, and Media type.
293 * Then for each of the Storage resources, we have a list of
294 * device names that were given.
296 * Wiffle through them and find one that can do the backup.
300 * Make up to two passes. The first with PreferMountedVols possibly
301 * set to true. In that case, we look only for an available
302 * drive with something mounted. If that fails, then we
303 * do a second pass with PerferMountedVols set false.
305 rctx.PreferMountedVols = jcr->PreferMountedVols;
306 ok = find_suitable_device_for_job(jcr, rctx);
310 if (rctx.PreferMountedVols) {
311 rctx.PreferMountedVols = false;
312 ok = find_suitable_device_for_job(jcr, rctx);
318 unbash_spaces(dir->msg);
319 pm_strcpy(jcr->errmsg, dir->msg);
320 Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
322 Jmsg(jcr, M_FATAL, 0, _("\n"
323 " Device \"%s\" with MediaType \"%s\" requested by DIR not found in SD Device resources.\n"),
324 dev_name.c_str(), media_type.c_str());
325 bnet_fsend(dir, NO_device, dev_name.c_str());
327 for (error=(char*)rctx->errors.first(); error;
328 error=(char*)rctx->errors.next()) {
329 Jmsg(jcr, M_INFO, 0, "%s", error);
332 Dmsg1(100, ">dird: %s\n", dir->msg);
334 unbash_spaces(dir->msg);
335 pm_strcpy(jcr->errmsg, dir->msg);
337 Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
339 bnet_fsend(dir, BAD_use, jcr->errmsg);
340 Dmsg1(100, ">dird: %s\n", dir->msg);
344 foreach_alist(store, jcr->dirstore) {
345 delete store->device;
348 delete jcr->dirstore;
350 for (error=(char*)rctx->errors.first(); error;
351 error=(char*)rctx->errors.next()) {
360 * Search for a device suitable for this job.
362 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx)
370 init_jcr_device_wait_timers(jcr);
372 int need_wait = false;
373 foreach_alist(store, jcr->dirstore) {
375 foreach_alist(device_name, store->device) {
377 rctx.device_name = device_name;
378 stat = search_res_for_device(rctx);
379 if (stat == 1) { /* found available device */
383 } else if (stat == 0) { /* device busy */
386 /* otherwise error */
387 // rctx->errors.push(bstrdup(jcr->errmsg));
391 * If there is some device for which we can wait, then
392 * wait and try again until the wait time expires
394 if (!need_wait || !wait_for_device(jcr, first)) {
399 for (error=(char*)rctx->errors.first(); error;
400 error=(char*)rctx->errors.next()) {
413 * Search for a particular storage device with particular storage
414 * characteristics (MediaType).
416 static int search_res_for_device(RCTX &rctx)
418 AUTOCHANGER *changer;
419 BSOCK *dir = rctx.jcr->dir_bsock;
423 Dmsg1(100, "Search res for %s\n", rctx.device_name);
424 foreach_res(rctx.device, R_DEVICE) {
425 Dmsg1(100, "Try res=%s\n", rctx.device->hdr.name);
426 /* Find resource, and make sure we were able to open it */
427 if (fnmatch(rctx.device_name, rctx.device->hdr.name, 0) == 0 &&
428 strcmp(rctx.device->media_type, rctx.store->media_type) == 0) {
429 stat = reserve_device(rctx);
433 Dmsg1(220, "Got: %s", dir->msg);
434 bash_spaces(rctx.device_name);
435 ok = bnet_fsend(dir, OK_device, rctx.device_name);
436 Dmsg1(100, ">dird: %s\n", dir->msg);
440 foreach_res(changer, R_AUTOCHANGER) {
441 Dmsg1(100, "Try changer res=%s\n", changer->hdr.name);
442 /* Find resource, and make sure we were able to open it */
443 if (fnmatch(rctx.device_name, changer->hdr.name, 0) == 0) {
444 /* Try each device in this AutoChanger */
445 foreach_alist(rctx.device, changer->device) {
446 Dmsg1(100, "Try changer device %s\n", rctx.device->hdr.name);
447 stat = reserve_device(rctx);
448 if (stat == -1) { /* hard error */
451 if (stat == 0) { /* must wait, try next one */
455 Dmsg1(100, "Device %s opened.\n", rctx.device_name);
456 pm_strcpy(dev_name, rctx.device->hdr.name);
457 bash_spaces(dev_name);
458 ok = bnet_fsend(dir, OK_device, dev_name.c_str()); /* Return real device name */
459 Dmsg1(100, ">dird: %s\n", dir->msg);
464 return 0; /* nothing found */
468 * Try to reserve a specific device.
470 * Returns: 1 -- OK, have DCR
474 static int reserve_device(RCTX &rctx)
478 const int name_len = MAX_NAME_LENGTH;
479 if (!rctx.device->dev) {
480 rctx.device->dev = init_dev(rctx.jcr, rctx.device);
482 if (!rctx.device->dev) {
483 if (rctx.device->changer_res) {
484 Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
485 " Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
486 rctx.device->hdr.name, rctx.device_name);
488 Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
489 " Device \"%s\" requested by DIR could not be opened or does not exist.\n"),
492 return -1; /* no use waiting */
494 Dmsg1(100, "Found device %s\n", rctx.device->hdr.name);
495 dcr = new_dcr(rctx.jcr, rctx.device->dev);
497 BSOCK *dir = rctx.jcr->dir_bsock;
498 bnet_fsend(dir, _("3926 Could not get dcr for device: %s\n"), rctx.device_name);
499 Dmsg1(100, ">dird: %s\n", dir->msg);
503 bstrncpy(dcr->pool_name, rctx.store->pool_name, name_len);
504 bstrncpy(dcr->pool_type, rctx.store->pool_type, name_len);
505 bstrncpy(dcr->media_type, rctx.store->media_type, name_len);
506 bstrncpy(dcr->dev_name, rctx.device_name, name_len);
507 if (rctx.store->append == SD_APPEND) {
508 ok = reserve_device_for_append(dcr, rctx.PreferMountedVols);
509 Dmsg3(200, "dev_name=%s mediatype=%s ok=%d\n", dcr->dev_name, dcr->media_type, ok);
511 ok = reserve_device_for_read(dcr);
514 free_dcr(rctx.jcr->dcr);
521 * We "reserve" the drive by setting the ST_READ bit. No one else
522 * should touch the drive until that is cleared.
523 * This allows the DIR to "reserve" the device before actually
526 static bool reserve_device_for_read(DCR *dcr)
528 DEVICE *dev = dcr->dev;
534 dev->block(BST_DOING_ACQUIRE);
536 if (device_is_unmounted(dev)) {
537 Dmsg1(200, "Device %s is BLOCKED due to user unmount.\n", dev->print_name());
538 Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"),
543 if (dev->is_busy()) {
544 Dmsg4(200, "Device %s is busy ST_READ=%d num_writers=%d reserved=%d.\n", dev->print_name(),
545 dev->state & ST_READ?1:0, dev->num_writers, dev->reserved_device);
546 Mmsg1(jcr->errmsg, _("Device %s is busy.\n"),
562 * We reserve the device for appending by incrementing the
563 * reserved_device. We do virtually all the same work that
564 * is done in acquire_device_for_append(), but we do
565 * not attempt to mount the device. This routine allows
566 * the DIR to reserve multiple devices before *really*
567 * starting the job. It also permits the SD to refuse
568 * certain devices (not up, ...).
570 * Note, in reserving a device, if the device is for the
571 * same pool and the same pool type, then it is acceptable.
572 * The Media Type has already been checked. If we are
573 * the first tor reserve the device, we put the pool
574 * name and pool type in the device record.
576 static bool reserve_device_for_append(DCR *dcr, bool PreferMountedVols)
579 DEVICE *dev = dcr->dev;
584 dev->block(BST_DOING_ACQUIRE);
586 if (dev->can_read()) {
587 Mmsg1(jcr->errmsg, _("Device %s is busy reading.\n"), dev->print_name());
588 Dmsg1(100, "%s", jcr->errmsg);
592 if (device_is_unmounted(dev)) {
593 Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"), dev->print_name());
594 Dmsg1(100, "%s", jcr->errmsg);
598 Dmsg1(190, "reserve_append device is %s\n", dev->is_tape()?"tape":"disk");
600 if (can_reserve_drive(dcr, PreferMountedVols) != 1) {
601 Mmsg1(jcr->errmsg, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
602 Dmsg1(100, "%s", jcr->errmsg);
606 dev->reserved_device++;
607 Dmsg1(200, "Inc reserve=%d\n", dev->reserved_device);
608 dcr->reserved_device = true;
617 * Returns: 1 if drive can be reserved
618 * 0 if we should wait
621 static int can_reserve_drive(DCR *dcr, bool PreferMountedVols)
623 DEVICE *dev = dcr->dev;
626 if (PreferMountedVols && !dev->VolHdr.VolumeName[0] &&
627 dev->is_tape() && !dev->is_autochanger()) {
628 return 0; /* No volume mounted */
632 * Handle the case that the drive is not yet in append mode
634 if (!dev->can_append() && dev->num_writers == 0) {
635 /* Now check if there are any reservations on the drive */
636 if (dev->reserved_device) {
637 /* Yes, now check if we want the same Pool and pool type */
638 if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
639 strcmp(dev->pool_type, dcr->pool_type) == 0) {
640 /* OK, compatible device */
642 /* Drive not suitable for us */
646 /* Device is available but not yet reserved, reserve it for us */
647 bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
648 bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
650 return 1; /* reserve drive */
654 * Check if device in append mode with no writers (i.e. available)
656 if (dev->can_append() && dev->num_writers == 0) {
657 /* Device is available but not yet reserved, reserve it for us */
658 bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
659 bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
663 * Check if the device is in append mode with writers (i.e.
664 * available if pool is the same).
666 if (dev->can_append() || dev->num_writers > 0) {
667 Dmsg0(190, "device already in append.\n");
668 /* Yes, now check if we want the same Pool and pool type */
669 if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
670 strcmp(dev->pool_type, dcr->pool_type) == 0) {
671 /* OK, compatible device */
674 /* Drive not suitable for us */
675 Jmsg(jcr, M_WARNING, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
679 Pmsg0(000, "Logic error!!!! Should not get here.\n");
680 Jmsg0(jcr, M_FATAL, 0, _("Logic error!!!! Should not get here.\n"));
681 return -1; /* error, should not get here */