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) 2012, Intel Corporation.
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_PREFIX "lustre:"
38 #define LDD_VERSION_PROP LDD_PREFIX "version"
39 #define LDD_FLAGS_PROP LDD_PREFIX "flags"
40 #define LDD_INDEX_PROP LDD_PREFIX "index"
41 #define LDD_FSNAME_PROP LDD_PREFIX "fsname"
42 #define LDD_SVNAME_PROP LDD_PREFIX "svname"
43 #define LDD_UUID_PROP LDD_PREFIX "uuid"
44 #define LDD_USERDATA_PROP LDD_PREFIX "userdata"
45 #define LDD_MOUNTOPTS_PROP LDD_PREFIX "mountopts"
47 /* This structure is used to help bridge the gap between the ZFS
48 * properties Lustre uses and their corresponding internal LDD fields.
49 * It is meant to be used internally by the mount utility only. */
50 struct zfs_ldd_prop_bridge {
51 /* Contains the publicly visible name for the property
52 * (i.e. what is shown when running "zfs get") */
54 /* Contains the offset into the lustre_disk_data structure where
55 * the value of this property is or will be stored. (i.e. the
56 * property is read from and written to this offset within ldd) */
58 /* Function pointer responsible for reading in the @prop
59 * property from @zhp and storing it in @ldd_field */
60 int (*zlpb_get_prop_fn)(zfs_handle_t *zhp, char *prop, void *ldd_field);
61 /* Function pointer responsible for writing the value of @ldd_field
62 * into the @prop dataset property in @zhp */
63 int (*zlpb_set_prop_fn)(zfs_handle_t *zhp, char *prop, void *ldd_field);
66 /* Forward declarations needed to initialize the ldd prop bridge list */
67 static int zfs_get_prop_int(zfs_handle_t *, char *, void *);
68 static int zfs_set_prop_int(zfs_handle_t *, char *, void *);
69 static int zfs_get_prop_str(zfs_handle_t *, char *, void *);
70 static int zfs_set_prop_str(zfs_handle_t *, char *, void *);
72 /* Helper for initializing the entries in the special_ldd_prop_params list.
73 * - @name: stored directly in the zlpb_prop_name field
74 * (e.g. lustre:fsname, lustre:version, etc.)
75 * - @field: the field in the lustre_disk_data which directly maps to
76 * the @name property. (e.g. ldd_fsname, ldd_config_ver, etc.)
77 * - @type: The type of @field. Only "int" and "str" are supported.
79 #define ZLB_INIT(name, field, type) \
81 name, offsetof(struct lustre_disk_data, field), \
82 zfs_get_prop_ ## type, zfs_set_prop_ ## type \
85 /* These ldd properties are special because they all have their own
86 * individual fields in the lustre_disk_data structure, as opposed to
87 * being globbed into the ldd_params field. As such, these need special
88 * handling when reading/writing the ldd structure to/from persistent
90 struct zfs_ldd_prop_bridge special_ldd_prop_params[] = {
91 ZLB_INIT(LDD_VERSION_PROP, ldd_config_ver, int),
92 ZLB_INIT(LDD_FLAGS_PROP, ldd_flags, int),
93 ZLB_INIT(LDD_INDEX_PROP, ldd_svindex, int),
94 ZLB_INIT(LDD_FSNAME_PROP, ldd_fsname, str),
95 ZLB_INIT(LDD_SVNAME_PROP, ldd_svname, str),
96 ZLB_INIT(LDD_UUID_PROP, ldd_uuid, str),
97 ZLB_INIT(LDD_USERDATA_PROP, ldd_userdata, str),
98 ZLB_INIT(LDD_MOUNTOPTS_PROP, ldd_mount_opts, str),
102 /* indicate if the ZFS OSD has been successfully setup */
103 static int osd_zfs_setup = 0;
105 static libzfs_handle_t *g_zfs;
107 /* dynamic linking handles for libzfs & libnvpair */
108 static void *handle_libzfs;
109 static void *handle_nvpair;
111 /* symbol table looked up with dlsym */
113 libzfs_handle_t *(*libzfs_init)(void);
114 void (*libzfs_fini)(libzfs_handle_t *);
115 int (*libzfs_load_module)(char *);
116 zfs_handle_t* (*zfs_open)(libzfs_handle_t *, const char *, int);
117 int (*zfs_destroy)(zfs_handle_t *, boolean_t);
118 void (*zfs_close)(zfs_handle_t *);
119 int (*zfs_prop_set)(zfs_handle_t*, const char*, const char*);
120 nvlist_t* (*zfs_get_user_props) (zfs_handle_t *);
121 int (*zfs_name_valid)(const char *, zfs_type_t);
122 zpool_handle_t* (*zpool_open)(libzfs_handle_t *, const char *);
123 void (*zpool_close)(zpool_handle_t *zhp);
124 int (*nvlist_lookup_string)(nvlist_t*, const char*, char**);
125 int (*nvlist_lookup_nvlist)(nvlist_t *, const char *, nvlist_t **);
126 nvpair_t * (*nvlist_next_nvpair)(nvlist_t *, nvpair_t *);
127 char * (*nvpair_name)(nvpair_t *);
130 static struct zfs_symbols sym;
133 #define DLSYM(handle, func) \
135 sym.func = (typeof(sym.func))dlsym(handle, #func); \
138 /* populate the symbol table after a successful call to dlopen() */
139 static int zfs_populate_symbols(void)
143 dlerror(); /* Clear any existing error */
145 DLSYM(handle_libzfs, libzfs_init);
146 #define libzfs_init (*sym.libzfs_init)
147 DLSYM(handle_libzfs, libzfs_fini);
148 #define libzfs_fini (*sym.libzfs_fini)
149 DLSYM(handle_libzfs, libzfs_load_module);
150 #define libzfs_load_module (*sym.libzfs_load_module)
151 DLSYM(handle_libzfs, zfs_open);
152 #define zfs_open (*sym.zfs_open)
153 DLSYM(handle_libzfs, zfs_destroy);
154 #define zfs_destroy (*sym.zfs_destroy)
155 DLSYM(handle_libzfs, zfs_close);
156 #define zfs_close (*sym.zfs_close)
157 DLSYM(handle_libzfs, zfs_prop_set);
158 #define zfs_prop_set (*sym.zfs_prop_set)
159 DLSYM(handle_libzfs, zfs_get_user_props);
160 #define zfs_get_user_props (*sym.zfs_get_user_props)
161 DLSYM(handle_libzfs, zfs_name_valid);
162 #define zfs_name_valid (*sym.zfs_name_valid)
163 DLSYM(handle_libzfs, zpool_open);
164 #define zpool_open (*sym.zpool_open)
165 DLSYM(handle_libzfs, zpool_close);
166 #define zpool_close (*sym.zpool_close)
167 DLSYM(handle_nvpair, nvlist_lookup_string);
168 #define nvlist_lookup_string (*sym.nvlist_lookup_string)
169 DLSYM(handle_nvpair, nvlist_lookup_nvlist);
170 #define nvlist_lookup_nvlist (*sym.nvlist_lookup_nvlist)
171 DLSYM(handle_nvpair, nvlist_next_nvpair);
172 #define nvlist_next_nvpair (*sym.nvlist_next_nvpair)
173 DLSYM(handle_nvpair, nvpair_name);
174 #define nvpair_name (*sym.nvpair_name)
179 fprintf(stderr, "%s\n", error);
185 static int zfs_set_prop_int(zfs_handle_t *zhp, char *prop, void *val)
190 (void) snprintf(str, sizeof (str), "%i", *(int *)val);
191 vprint(" %s=%s\n", prop, str);
192 ret = zfs_prop_set(zhp, prop, str);
198 * Write the zfs property string, note that properties with a NULL or
199 * zero-length value will not be written and 0 returned.
201 static int zfs_set_prop_str(zfs_handle_t *zhp, char *prop, void *val)
205 if (val && strlen(val) > 0) {
206 vprint(" %s=%s\n", prop, (char *)val);
207 ret = zfs_prop_set(zhp, prop, (char *)val);
214 * Map '<key>=<value> ...' pairs in the passed string to dataset properties
215 * of the form 'lustre:<key>=<value>'. Malformed <key>=<value> pairs will
218 static int zfs_set_prop_params(zfs_handle_t *zhp, char *params)
220 char *params_dup, *token, *key, *value;
221 char *save_token = NULL;
222 char prop_name[ZFS_MAXNAMELEN];
225 params_dup = strdup(params);
226 if (params_dup == NULL)
229 token = strtok_r(params_dup, " ", &save_token);
231 key = strtok(token, "=");
235 value = strtok(NULL, "=");
239 sprintf(prop_name, "%s%s", LDD_PREFIX, key);
240 vprint(" %s=%s\n", prop_name, value);
242 ret = zfs_prop_set(zhp, prop_name, value);
246 token = strtok_r(NULL, " ", &save_token);
254 static int osd_check_zfs_setup(void)
256 if (osd_zfs_setup == 0) {
259 fprintf(stderr, "Failed to initialize ZFS library. Are the ZFS "
260 "packages and modules correctly installed?\n");
262 return osd_zfs_setup == 1;
265 /* Write the server config as properties associated with the dataset */
266 int zfs_write_ldd(struct mkfs_opts *mop)
268 struct lustre_disk_data *ldd = &mop->mo_ldd;
269 char *ds = mop->mo_device;
271 struct zfs_ldd_prop_bridge *bridge;
274 if (osd_check_zfs_setup() == 0)
277 zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
279 fprintf(stderr, "Failed to open zfs dataset %s\n", ds);
283 vprint("Writing %s properties\n", ds);
285 for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) {
286 bridge = &special_ldd_prop_params[i];
287 ret = bridge->zlpb_set_prop_fn(zhp, bridge->zlpb_prop_name,
288 (void *)ldd + bridge->zlpb_ldd_offset);
293 ret = zfs_set_prop_params(zhp, ldd->ldd_params);
301 static int zfs_get_prop_int(zfs_handle_t *zhp, char *prop, void *val)
307 ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
311 ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
316 *(__u32 *)val = strtoul(propstr, NULL, 10);
323 static int zfs_get_prop_str(zfs_handle_t *zhp, char *prop, void *val)
329 ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
333 ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
337 (void) strcpy(val, propstr);
342 static int zfs_is_special_ldd_prop_param(char *name)
346 for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++)
347 if (!strcmp(name, special_ldd_prop_params[i].zlpb_prop_name))
353 static int zfs_get_prop_params(zfs_handle_t *zhp, char *param, int len)
357 char key[ZFS_MAXNAMELEN];
361 props = zfs_get_user_props(zhp);
370 while (nvp = nvlist_next_nvpair(props, nvp), nvp) {
371 ret = zfs_get_prop_str(zhp, nvpair_name(nvp), value);
375 if (strncmp(nvpair_name(nvp), LDD_PREFIX, strlen(LDD_PREFIX)))
378 if (zfs_is_special_ldd_prop_param(nvpair_name(nvp)))
381 sprintf(key, "%s=", nvpair_name(nvp) + strlen(LDD_PREFIX));
383 ret = add_param(param, key, value);
394 * Read the server config as properties associated with the dataset.
395 * Missing entries as not treated error and are simply skipped.
397 int zfs_read_ldd(char *ds, struct lustre_disk_data *ldd)
400 struct zfs_ldd_prop_bridge *bridge;
403 if (osd_check_zfs_setup() == 0)
406 zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
410 for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) {
411 bridge = &special_ldd_prop_params[i];
412 ret = bridge->zlpb_get_prop_fn(zhp, bridge->zlpb_prop_name,
413 (void *)ldd + bridge->zlpb_ldd_offset);
414 if (ret && (ret != ENOENT))
418 ret = zfs_get_prop_params(zhp, ldd->ldd_params, 4096);
419 if (ret && (ret != ENOENT))
422 ldd->ldd_mount_type = LDD_MT_ZFS;
430 int zfs_is_lustre(char *ds, unsigned *mount_type)
432 struct lustre_disk_data tmp_ldd;
435 if (osd_zfs_setup == 0)
438 ret = zfs_read_ldd(ds, &tmp_ldd);
439 if ((ret == 0) && (tmp_ldd.ldd_config_ver > 0) &&
440 (strlen(tmp_ldd.ldd_svname) > 0)) {
441 *mount_type = tmp_ldd.ldd_mount_type;
448 static char *zfs_mkfs_opts(struct mkfs_opts *mop, char *str, int len)
452 if (strlen(mop->mo_mkfsopts) != 0)
453 snprintf(str, len, " -o %s", mop->mo_mkfsopts);
458 static int zfs_create_vdev(struct mkfs_opts *mop, char *vdev)
462 /* Silently ignore reserved vdev names */
463 if ((strncmp(vdev, "disk", 4) == 0) ||
464 (strncmp(vdev, "file", 4) == 0) ||
465 (strncmp(vdev, "mirror", 6) == 0) ||
466 (strncmp(vdev, "raidz", 5) == 0) ||
467 (strncmp(vdev, "spare", 5) == 0) ||
468 (strncmp(vdev, "log", 3) == 0) ||
469 (strncmp(vdev, "cache", 5) == 0))
473 * Verify a file exists at the provided absolute path. If it doesn't
474 * and mo_device_sz is set attempt to create a file vdev to be used.
475 * Relative paths will be passed directly to 'zpool create' which
476 * will check multiple multiple locations under /dev/.
478 if (vdev[0] == '/') {
479 ret = access(vdev, F_OK);
486 fprintf(stderr, "Unable to access required vdev "
487 "for pool %s (%d)\n", vdev, ret);
491 if (mop->mo_device_sz == 0) {
493 fprintf(stderr, "Unable to create vdev due to "
494 "missing --device-size=#N(KB) parameter\n");
498 ret = file_create(vdev, mop->mo_device_sz);
501 fprintf(stderr, "Unable to create vdev %s (%d)\n",
510 int zfs_make_lustre(struct mkfs_opts *mop)
515 char *mkfs_cmd = NULL;
516 char *mkfs_tmp = NULL;
517 char *ds = mop->mo_device;
518 int pool_exists = 0, ret;
520 if (osd_check_zfs_setup() == 0)
523 /* no automatic index with zfs backend */
524 if (mop->mo_ldd.ldd_flags & LDD_F_NEED_INDEX) {
526 fprintf(stderr, "The target index must be specified with "
535 mkfs_cmd = malloc(PATH_MAX);
536 if (mkfs_cmd == NULL) {
541 mkfs_tmp = malloc(PATH_MAX);
542 if (mkfs_tmp == NULL) {
547 /* Due to zfs_prepare_lustre() check the '/' must exist */
548 strchr(pool, '/')[0] = '\0';
550 /* If --reformat was given attempt to destroy the previous dataset */
551 if ((mop->mo_flags & MO_FORCEFORMAT) &&
552 ((zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM)) != NULL)) {
554 ret = zfs_destroy(zhp, 0);
557 fprintf(stderr, "Failed destroy zfs dataset %s (%d)\n",
566 * Create the zpool if the vdevs have been specified and the pool
567 * does not already exists. The pool creation itself will be done
568 * with the zpool command rather than the zpool_create() library call
569 * so the existing zpool error handling can be leveraged.
571 php = zpool_open(g_zfs, pool);
577 if ((mop->mo_pool_vdevs != NULL) && (pool_exists == 0)) {
579 memset(mkfs_cmd, 0, PATH_MAX);
580 snprintf(mkfs_cmd, PATH_MAX,
581 "zpool create -f -O canmount=off %s", pool);
583 /* Append the vdev config and create file vdevs as required */
584 while (*mop->mo_pool_vdevs != NULL) {
585 strscat(mkfs_cmd, " ", PATH_MAX);
586 strscat(mkfs_cmd, *mop->mo_pool_vdevs, PATH_MAX);
588 ret = zfs_create_vdev(mop, *mop->mo_pool_vdevs);
592 mop->mo_pool_vdevs++;
595 vprint("mkfs_cmd = %s\n", mkfs_cmd);
596 ret = run_command(mkfs_cmd, PATH_MAX);
599 fprintf(stderr, "Unable to create pool %s (%d)\n",
606 * Create the ZFS filesystem with any required mkfs options:
607 * - canmount=off is set to prevent zfs automounting
608 * - version=4 is set because SA are not yet handled by the osd
610 memset(mkfs_cmd, 0, PATH_MAX);
611 snprintf(mkfs_cmd, PATH_MAX,
612 "zfs create -o canmount=off -o xattr=sa%s %s",
613 zfs_mkfs_opts(mop, mkfs_tmp, PATH_MAX),
616 vprint("mkfs_cmd = %s\n", mkfs_cmd);
617 ret = run_command(mkfs_cmd, PATH_MAX);
620 fprintf(stderr, "Unable to create filesystem %s (%d)\n",
629 if (mkfs_cmd != NULL)
632 if (mkfs_tmp != NULL)
638 int zfs_prepare_lustre(struct mkfs_opts *mop,
639 char *default_mountopts, int default_len,
640 char *always_mountopts, int always_len)
642 if (osd_check_zfs_setup() == 0)
645 if (zfs_name_valid(mop->mo_device, ZFS_TYPE_FILESYSTEM) == 0) {
647 fprintf(stderr, "Invalid filesystem name %s\n", mop->mo_device);
651 if (strchr(mop->mo_device, '/') == NULL) {
653 fprintf(stderr, "Missing pool in filesystem name %s\n",
661 int zfs_tune_lustre(char *dev, struct mount_opts *mop)
663 if (osd_check_zfs_setup() == 0)
669 int zfs_label_lustre(struct mount_opts *mop)
674 if (osd_check_zfs_setup() == 0)
677 zhp = zfs_open(g_zfs, mop->mo_source, ZFS_TYPE_FILESYSTEM);
681 ret = zfs_set_prop_str(zhp, LDD_SVNAME_PROP, mop->mo_ldd.ldd_svname);
691 /* If the ZFS libs are not installed, don't print an error to avoid
692 * spamming ldiskfs users. An error message will still be printed if
693 * someone tries to do some real work involving a ZFS backend */
695 handle_libzfs = dlopen("libzfs.so.1", RTLD_LAZY);
696 if (handle_libzfs == NULL)
699 handle_nvpair = dlopen("libnvpair.so.1", RTLD_LAZY);
700 if (handle_nvpair == NULL) {
705 ret = zfs_populate_symbols();
709 if (libzfs_load_module("zfs") != 0) {
710 /* The ZFS modules are not installed */
715 g_zfs = libzfs_init();
717 fprintf(stderr, "Failed to initialize ZFS library\n");
734 dlclose(handle_nvpair);
735 handle_nvpair = NULL;
738 dlclose(handle_libzfs);
739 handle_libzfs = NULL;