4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License version 2 for more details. A copy is
14 * included in the COPYING file that accompanied this code.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * Copyright (c) 2011, 2012 Whamcloud, Inc.
24 * Use is subject to license terms.
28 * Author: Brian Behlendorf <behlendorf1@llnl.gov>
30 #include "mount_utils.h"
36 /* Persistent mount data is stored in these user attributes */
37 #define LDD_VERSION_PROP "lustre:version"
38 #define LDD_FLAGS_PROP "lustre:flags"
39 #define LDD_INDEX_PROP "lustre:index"
40 #define LDD_FSNAME_PROP "lustre:fsname"
41 #define LDD_SVNAME_PROP "lustre:svname"
42 #define LDD_UUID_PROP "lustre:uuid"
43 #define LDD_USERDATA_PROP "lustre:userdata"
44 #define LDD_MOUNTOPTS_PROP "lustre:mountopts"
45 #define LDD_MGSNODE_PROP "lustre:mgsnode"
46 #define LDD_FAILNODE_PROP "lustre:failnode"
47 #define LDD_FAILMODE_PROP "lustre:failmode"
48 #define LDD_IDENTITY_UPCALL_PROP "lustre:identity_upcall"
50 /* indicate if the ZFS OSD has been successfully setup */
51 static int osd_zfs_setup = 0;
53 static libzfs_handle_t *g_zfs;
55 /* dynamic linking handles for libzfs & libnvpair */
56 static void *handle_libzfs;
57 static void *handle_nvpair;
59 /* symbol table looked up with dlsym */
61 libzfs_handle_t *(*libzfs_init)(void);
62 void (*libzfs_fini)(libzfs_handle_t *);
63 int (*libzfs_load_module)(char *);
64 zfs_handle_t* (*zfs_open)(libzfs_handle_t *, const char *, int);
65 int (*zfs_destroy)(zfs_handle_t *, boolean_t);
66 void (*zfs_close)(zfs_handle_t *);
67 int (*zfs_prop_set)(zfs_handle_t*, const char*, const char*);
68 nvlist_t* (*zfs_get_user_props) (zfs_handle_t *);
69 int (*zfs_name_valid)(const char *, zfs_type_t);
70 zpool_handle_t* (*zpool_open)(libzfs_handle_t *, const char *);
71 void (*zpool_close)(zpool_handle_t *zhp);
72 int (*nvlist_lookup_string)(nvlist_t*, const char*, char**);
73 int (*nvlist_lookup_nvlist)(nvlist_t *, const char *, nvlist_t **);
76 static struct zfs_symbols sym;
79 #define DLSYM(handle, func) \
81 sym.func = (typeof(sym.func))dlsym(handle, #func); \
84 /* populate the symbol table after a successful call to dlopen() */
85 static int zfs_populate_symbols(void)
89 dlerror(); /* Clear any existing error */
91 DLSYM(handle_libzfs, libzfs_init);
92 #define libzfs_init (*sym.libzfs_init)
93 DLSYM(handle_libzfs, libzfs_fini);
94 #define libzfs_fini (*sym.libzfs_fini)
95 DLSYM(handle_libzfs, libzfs_load_module);
96 #define libzfs_load_module (*sym.libzfs_load_module)
97 DLSYM(handle_libzfs, zfs_open);
98 #define zfs_open (*sym.zfs_open)
99 DLSYM(handle_libzfs, zfs_destroy);
100 #define zfs_destroy (*sym.zfs_destroy)
101 DLSYM(handle_libzfs, zfs_close);
102 #define zfs_close (*sym.zfs_close)
103 DLSYM(handle_libzfs, zfs_prop_set);
104 #define zfs_prop_set (*sym.zfs_prop_set)
105 DLSYM(handle_libzfs, zfs_get_user_props);
106 #define zfs_get_user_props (*sym.zfs_get_user_props)
107 DLSYM(handle_libzfs, zfs_name_valid);
108 #define zfs_name_valid (*sym.zfs_name_valid)
109 DLSYM(handle_libzfs, zpool_open);
110 #define zpool_open (*sym.zpool_open)
111 DLSYM(handle_libzfs, zpool_close);
112 #define zpool_close (*sym.zpool_close)
113 DLSYM(handle_nvpair, nvlist_lookup_string);
114 #define nvlist_lookup_string (*sym.nvlist_lookup_string)
115 DLSYM(handle_nvpair, nvlist_lookup_nvlist);
116 #define nvlist_lookup_nvlist (*sym.nvlist_lookup_nvlist)
121 fprintf(stderr, "%s\n", error);
127 static int zfs_set_prop_int(zfs_handle_t *zhp, char *prop, __u32 val)
132 (void) snprintf(str, sizeof (str), "%lu", (unsigned long)val);
133 vprint(" %s=%s\n", prop, str);
134 ret = zfs_prop_set(zhp, prop, str);
140 * Write the zfs property string, note that properties with a NULL or
141 * zero-length value will not be written and 0 returned.
143 static int zfs_set_prop_str(zfs_handle_t *zhp, char *prop, char *val)
147 if (val && strlen(val) > 0) {
148 vprint(" %s=%s\n", prop, val);
149 ret = zfs_prop_set(zhp, prop, val);
155 static int zfs_set_prop_param(zfs_handle_t *zhp, struct lustre_disk_data *ldd,
156 char *param, char *prop)
161 if (get_param(ldd->ldd_params, param, &str) == 0) {
162 vprint(" %s=%s\n", prop, str);
163 ret = zfs_prop_set(zhp, prop, str);
170 static int osd_check_zfs_setup(void)
172 if (osd_zfs_setup == 0) {
175 fprintf(stderr, "Failed to initialize ZFS library. Are the ZFS "
176 "packages and modules correctly installed?\n");
178 return osd_zfs_setup == 1;
181 /* Write the server config as properties associated with the dataset */
182 int zfs_write_ldd(struct mkfs_opts *mop)
184 struct lustre_disk_data *ldd = &mop->mo_ldd;
185 char *ds = mop->mo_device;
189 if (osd_check_zfs_setup() == 0)
192 zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
194 fprintf(stderr, "Failed to open zfs dataset %s\n", ds);
198 vprint("Writing %s properties\n", ds);
200 ret = zfs_set_prop_int(zhp, LDD_VERSION_PROP, ldd->ldd_config_ver);
204 ret = zfs_set_prop_int(zhp, LDD_FLAGS_PROP, ldd->ldd_flags);
208 ret = zfs_set_prop_int(zhp, LDD_INDEX_PROP, ldd->ldd_svindex);
212 ret = zfs_set_prop_str(zhp, LDD_FSNAME_PROP, ldd->ldd_fsname);
216 ret = zfs_set_prop_str(zhp, LDD_SVNAME_PROP, ldd->ldd_svname);
220 ret = zfs_set_prop_str(zhp, LDD_UUID_PROP, (char *)ldd->ldd_uuid);
224 ret = zfs_set_prop_str(zhp, LDD_USERDATA_PROP, ldd->ldd_userdata);
228 ret = zfs_set_prop_str(zhp, LDD_MOUNTOPTS_PROP, ldd->ldd_mount_opts);
232 ret = zfs_set_prop_param(zhp, ldd, PARAM_MGSNODE, LDD_MGSNODE_PROP);
236 ret = zfs_set_prop_param(zhp, ldd, PARAM_FAILNODE, LDD_FAILNODE_PROP);
240 ret = zfs_set_prop_param(zhp, ldd, PARAM_FAILMODE, LDD_FAILMODE_PROP);
244 ret = zfs_set_prop_param(zhp, ldd, PARAM_MDT PARAM_ID_UPCALL,
245 LDD_IDENTITY_UPCALL_PROP);
255 static int zfs_get_prop_int(zfs_handle_t *zhp, char *prop, __u32 *val)
261 ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
265 ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
270 *val = strtoul(propstr, NULL, 10);
277 static int zfs_get_prop_str(zfs_handle_t *zhp, char *prop, char *val)
283 ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
287 ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
291 (void) strcpy(val, propstr);
296 static int zfs_get_prop_param(zfs_handle_t *zhp, struct lustre_disk_data *ldd,
297 char *param, char *prop)
303 ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
307 ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
311 ret = add_param(ldd->ldd_params, param, propstr);
317 * Read the server config as properties associated with the dataset.
318 * Missing entries as not treated error and are simply skipped.
320 int zfs_read_ldd(char *ds, struct lustre_disk_data *ldd)
325 if (osd_check_zfs_setup() == 0)
328 zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
332 ret = zfs_get_prop_int(zhp, LDD_VERSION_PROP, &ldd->ldd_config_ver);
333 if (ret && (ret != ENOENT))
336 ret = zfs_get_prop_int(zhp, LDD_FLAGS_PROP, &ldd->ldd_flags);
337 if (ret && (ret != ENOENT))
340 ret = zfs_get_prop_int(zhp, LDD_INDEX_PROP, &ldd->ldd_svindex);
341 if (ret && (ret != ENOENT))
344 ret = zfs_get_prop_str(zhp, LDD_FSNAME_PROP, ldd->ldd_fsname);
345 if (ret && (ret != ENOENT))
348 ret = zfs_get_prop_str(zhp, LDD_SVNAME_PROP, ldd->ldd_svname);
349 if (ret && (ret != ENOENT))
352 ret = zfs_get_prop_str(zhp, LDD_UUID_PROP, (char *)ldd->ldd_uuid);
353 if (ret && (ret != ENOENT))
356 ret = zfs_get_prop_str(zhp, LDD_USERDATA_PROP, ldd->ldd_userdata);
357 if (ret && (ret != ENOENT))
360 ret = zfs_get_prop_str(zhp, LDD_MOUNTOPTS_PROP, ldd->ldd_mount_opts);
361 if (ret && (ret != ENOENT))
364 ret = zfs_get_prop_param(zhp, ldd, PARAM_MGSNODE, LDD_MGSNODE_PROP);
365 if (ret && (ret != ENOENT))
368 ret = zfs_get_prop_param(zhp, ldd, PARAM_FAILNODE, LDD_FAILNODE_PROP);
369 if (ret && (ret != ENOENT))
372 ret = zfs_get_prop_param(zhp, ldd, PARAM_FAILMODE, LDD_FAILMODE_PROP);
373 if (ret && (ret != ENOENT))
376 ret = zfs_get_prop_param(zhp, ldd, PARAM_MDT PARAM_ID_UPCALL,
377 LDD_IDENTITY_UPCALL_PROP);
378 if (ret && (ret != ENOENT))
381 ldd->ldd_mount_type = LDD_MT_ZFS;
389 int zfs_is_lustre(char *ds, unsigned *mount_type)
391 struct lustre_disk_data tmp_ldd;
394 if (osd_zfs_setup == 0)
397 ret = zfs_read_ldd(ds, &tmp_ldd);
398 if ((ret == 0) && (tmp_ldd.ldd_config_ver > 0) &&
399 (strlen(tmp_ldd.ldd_svname) > 0)) {
400 *mount_type = tmp_ldd.ldd_mount_type;
407 static char *zfs_mkfs_opts(struct mkfs_opts *mop, char *str, int len)
411 if (strlen(mop->mo_mkfsopts) != 0)
412 snprintf(str, len, " -o %s", mop->mo_mkfsopts);
417 static int zfs_create_vdev(struct mkfs_opts *mop, char *vdev)
421 /* Silently ignore reserved vdev names */
422 if ((strncmp(vdev, "disk", 4) == 0) ||
423 (strncmp(vdev, "file", 4) == 0) ||
424 (strncmp(vdev, "mirror", 6) == 0) ||
425 (strncmp(vdev, "raidz", 5) == 0) ||
426 (strncmp(vdev, "spare", 5) == 0) ||
427 (strncmp(vdev, "log", 3) == 0) ||
428 (strncmp(vdev, "cache", 5) == 0))
432 * Verify a file exists at the provided absolute path. If it doesn't
433 * and mo_device_sz is set attempt to create a file vdev to be used.
434 * Relative paths will be passed directly to 'zpool create' which
435 * will check multiple multiple locations under /dev/.
437 if (vdev[0] == '/') {
438 ret = access(vdev, F_OK);
445 fprintf(stderr, "Unable to access required vdev "
446 "for pool %s (%d)\n", vdev, ret);
450 if (mop->mo_device_sz == 0) {
452 fprintf(stderr, "Unable to create vdev due to "
453 "missing --device-size=#N(KB) parameter\n");
457 ret = file_create(vdev, mop->mo_device_sz);
460 fprintf(stderr, "Unable to create vdev %s (%d)\n",
469 int zfs_make_lustre(struct mkfs_opts *mop)
474 char *mkfs_cmd = NULL;
475 char *mkfs_tmp = NULL;
476 char *ds = mop->mo_device;
477 int pool_exists = 0, ret;
479 if (osd_check_zfs_setup() == 0)
482 /* no automatic index with zfs backend */
483 if (mop->mo_ldd.ldd_flags & LDD_F_NEED_INDEX) {
485 fprintf(stderr, "The target index must be specified with "
494 mkfs_cmd = malloc(PATH_MAX);
495 if (mkfs_cmd == NULL) {
500 mkfs_tmp = malloc(PATH_MAX);
501 if (mkfs_tmp == NULL) {
506 /* Due to zfs_name_valid() check the '/' must exist */
507 strchr(pool, '/')[0] = '\0';
509 /* If --reformat was given attempt to destroy the previous dataset */
510 if ((mop->mo_flags & MO_FORCEFORMAT) &&
511 ((zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM)) != NULL)) {
513 ret = zfs_destroy(zhp, 0);
516 fprintf(stderr, "Failed destroy zfs dataset %s (%d)\n",
525 * Create the zpool if the vdevs have been specified and the pool
526 * does not already exists. The pool creation itself will be done
527 * with the zpool command rather than the zpool_create() library call
528 * so the existing zpool error handling can be leveraged.
530 php = zpool_open(g_zfs, pool);
536 if ((mop->mo_pool_vdevs != NULL) && (pool_exists == 0)) {
538 memset(mkfs_cmd, 0, PATH_MAX);
539 snprintf(mkfs_cmd, PATH_MAX,
540 "zpool create -f -O canmount=off %s", pool);
542 /* Append the vdev config and create file vdevs as required */
543 while (*mop->mo_pool_vdevs != NULL) {
544 strscat(mkfs_cmd, " ", PATH_MAX);
545 strscat(mkfs_cmd, *mop->mo_pool_vdevs, PATH_MAX);
547 ret = zfs_create_vdev(mop, *mop->mo_pool_vdevs);
551 mop->mo_pool_vdevs++;
554 vprint("mkfs_cmd = %s\n", mkfs_cmd);
555 ret = run_command(mkfs_cmd, PATH_MAX);
558 fprintf(stderr, "Unable to create pool %s (%d)\n",
565 * Create the ZFS filesystem with any required mkfs options:
566 * - canmount=off is set to prevent zfs automounting
567 * - version=4 is set because SA are not yet handled by the osd
569 memset(mkfs_cmd, 0, PATH_MAX);
570 snprintf(mkfs_cmd, PATH_MAX,
571 "zfs create -o canmount=off -o xattr=sa%s %s",
572 zfs_mkfs_opts(mop, mkfs_tmp, PATH_MAX),
575 vprint("mkfs_cmd = %s\n", mkfs_cmd);
576 ret = run_command(mkfs_cmd, PATH_MAX);
579 fprintf(stderr, "Unable to create filesystem %s (%d)\n",
588 if (mkfs_cmd != NULL)
591 if (mkfs_tmp != NULL)
597 int zfs_prepare_lustre(struct mkfs_opts *mop,
598 char *default_mountopts, int default_len,
599 char *always_mountopts, int always_len)
603 if (osd_check_zfs_setup() == 0)
606 ret = zfs_name_valid(mop->mo_device, ZFS_TYPE_FILESYSTEM);
609 fprintf(stderr, "Invalid filesystem name %s\n", mop->mo_device);
616 int zfs_tune_lustre(char *dev, struct mount_opts *mop)
618 if (osd_check_zfs_setup() == 0)
624 int zfs_label_lustre(struct mount_opts *mop)
629 if (osd_check_zfs_setup() == 0)
632 zhp = zfs_open(g_zfs, mop->mo_source, ZFS_TYPE_FILESYSTEM);
636 ret = zfs_set_prop_str(zhp, LDD_SVNAME_PROP, mop->mo_ldd.ldd_svname);
646 /* If the ZFS libs are not installed, don't print an error to avoid
647 * spamming ldiskfs users. An error message will still be printed if
648 * someone tries to do some real work involving a ZFS backend */
650 handle_libzfs = dlopen("libzfs.so", RTLD_LAZY);
651 if (handle_libzfs == NULL)
654 handle_nvpair = dlopen("libnvpair.so", RTLD_LAZY);
655 if (handle_nvpair == NULL) {
660 ret = zfs_populate_symbols();
664 if (libzfs_load_module("zfs") != 0) {
665 /* The ZFS modules are not installed */
670 g_zfs = libzfs_init();
672 fprintf(stderr, "Failed to initialize ZFS library\n");
689 dlclose(handle_nvpair);
690 handle_nvpair = NULL;
693 dlclose(handle_libzfs);
694 handle_libzfs = NULL;