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, 2014, Intel Corporation.
24 * Use is subject to license terms.
27 * Author: Brian Behlendorf <behlendorf1@llnl.gov>
29 #include "mount_utils.h"
35 /* Persistent mount data is stored in these user attributes */
36 #define LDD_PREFIX "lustre:"
37 #define LDD_VERSION_PROP LDD_PREFIX "version"
38 #define LDD_FLAGS_PROP LDD_PREFIX "flags"
39 #define LDD_INDEX_PROP LDD_PREFIX "index"
40 #define LDD_FSNAME_PROP LDD_PREFIX "fsname"
41 #define LDD_SVNAME_PROP LDD_PREFIX "svname"
42 #define LDD_UUID_PROP LDD_PREFIX "uuid"
43 #define LDD_USERDATA_PROP LDD_PREFIX "userdata"
44 #define LDD_MOUNTOPTS_PROP LDD_PREFIX "mountopts"
46 /* This structure is used to help bridge the gap between the ZFS
47 * properties Lustre uses and their corresponding internal LDD fields.
48 * It is meant to be used internally by the mount utility only. */
49 struct zfs_ldd_prop_bridge {
50 /* Contains the publicly visible name for the property
51 * (i.e. what is shown when running "zfs get") */
53 /* Contains the offset into the lustre_disk_data structure where
54 * the value of this property is or will be stored. (i.e. the
55 * property is read from and written to this offset within ldd) */
57 /* Function pointer responsible for reading in the @prop
58 * property from @zhp and storing it in @ldd_field */
59 int (*zlpb_get_prop_fn)(zfs_handle_t *zhp, char *prop, void *ldd_field);
60 /* Function pointer responsible for writing the value of @ldd_field
61 * into the @prop dataset property in @zhp */
62 int (*zlpb_set_prop_fn)(zfs_handle_t *zhp, char *prop, void *ldd_field);
65 /* Forward declarations needed to initialize the ldd prop bridge list */
66 static int zfs_get_prop_int(zfs_handle_t *, char *, void *);
67 static int zfs_set_prop_int(zfs_handle_t *, char *, void *);
68 static int zfs_get_prop_str(zfs_handle_t *, char *, void *);
69 static int zfs_set_prop_str(zfs_handle_t *, char *, void *);
71 /* Helper for initializing the entries in the special_ldd_prop_params list.
72 * - @name: stored directly in the zlpb_prop_name field
73 * (e.g. lustre:fsname, lustre:version, etc.)
74 * - @field: the field in the lustre_disk_data which directly maps to
75 * the @name property. (e.g. ldd_fsname, ldd_config_ver, etc.)
76 * - @type: The type of @field. Only "int" and "str" are supported.
78 #define ZLB_INIT(name, field, type) \
80 name, offsetof(struct lustre_disk_data, field), \
81 zfs_get_prop_ ## type, zfs_set_prop_ ## type \
84 /* These ldd properties are special because they all have their own
85 * individual fields in the lustre_disk_data structure, as opposed to
86 * being globbed into the ldd_params field. As such, these need special
87 * handling when reading/writing the ldd structure to/from persistent
89 struct zfs_ldd_prop_bridge special_ldd_prop_params[] = {
90 ZLB_INIT(LDD_VERSION_PROP, ldd_config_ver, int),
91 ZLB_INIT(LDD_FLAGS_PROP, ldd_flags, int),
92 ZLB_INIT(LDD_INDEX_PROP, ldd_svindex, int),
93 ZLB_INIT(LDD_FSNAME_PROP, ldd_fsname, str),
94 ZLB_INIT(LDD_SVNAME_PROP, ldd_svname, str),
95 ZLB_INIT(LDD_UUID_PROP, ldd_uuid, str),
96 ZLB_INIT(LDD_USERDATA_PROP, ldd_userdata, str),
97 ZLB_INIT(LDD_MOUNTOPTS_PROP, ldd_mount_opts, str),
101 /* indicate if the ZFS OSD has been successfully setup */
102 static int osd_zfs_setup = 0;
104 static libzfs_handle_t *g_zfs;
108 static int zfs_set_prop_int(zfs_handle_t *zhp, char *prop, void *val)
113 (void) snprintf(str, sizeof (str), "%i", *(int *)val);
114 vprint(" %s=%s\n", prop, str);
115 ret = zfs_prop_set(zhp, prop, str);
121 * Write the zfs property string, note that properties with a NULL or
122 * zero-length value will not be written and 0 returned.
124 static int zfs_set_prop_str(zfs_handle_t *zhp, char *prop, void *val)
128 if (val && strlen(val) > 0) {
129 vprint(" %s=%s\n", prop, (char *)val);
130 ret = zfs_prop_set(zhp, prop, (char *)val);
137 * Map '<key>=<value> ...' pairs in the passed string to dataset properties
138 * of the form 'lustre:<key>=<value>'. Malformed <key>=<value> pairs will
141 static int zfs_set_prop_params(zfs_handle_t *zhp, char *params)
143 char *params_dup, *token, *key, *value;
144 char *save_token = NULL;
145 char prop_name[ZFS_MAXNAMELEN];
148 params_dup = strdup(params);
149 if (params_dup == NULL)
152 token = strtok_r(params_dup, " ", &save_token);
154 key = strtok(token, "=");
158 value = strtok(NULL, "=");
162 sprintf(prop_name, "%s%s", LDD_PREFIX, key);
163 vprint(" %s=%s\n", prop_name, value);
165 ret = zfs_prop_set(zhp, prop_name, value);
169 token = strtok_r(NULL, " ", &save_token);
177 static int zfs_check_hostid(struct mkfs_opts *mop)
180 unsigned long hostid;
183 if (strstr(mop->mo_ldd.ldd_params, PARAM_FAILNODE) == NULL)
186 f = fopen("/sys/module/spl/parameters/spl_hostid", "r");
189 fprintf(stderr, "Failed to open spl_hostid: %s\n",
193 rc = fscanf(f, "%li", &hostid);
197 fprintf(stderr, "Failed to read spl_hostid: %d\n", rc);
202 if (mop->mo_flags & MO_NOHOSTID_CHECK) {
203 fprintf(stderr, "WARNING: spl_hostid not set. ZFS has "
204 "no zpool import protection\n");
207 fprintf(stderr, "spl_hostid not set. See %s(8)",
216 static int osd_check_zfs_setup(void)
218 if (osd_zfs_setup == 0) {
221 fprintf(stderr, "Failed to initialize ZFS library. Are the ZFS "
222 "packages and modules correctly installed?\n");
224 return osd_zfs_setup == 1;
227 /* Write the server config as properties associated with the dataset */
228 int zfs_write_ldd(struct mkfs_opts *mop)
230 struct lustre_disk_data *ldd = &mop->mo_ldd;
231 char *ds = mop->mo_device;
233 struct zfs_ldd_prop_bridge *bridge;
236 if (osd_check_zfs_setup() == 0)
239 zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
241 fprintf(stderr, "Failed to open zfs dataset %s\n", ds);
245 ret = zfs_check_hostid(mop);
249 vprint("Writing %s properties\n", ds);
251 for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) {
252 bridge = &special_ldd_prop_params[i];
253 ret = bridge->zlpb_set_prop_fn(zhp, bridge->zlpb_prop_name,
254 (void *)ldd + bridge->zlpb_ldd_offset);
259 ret = zfs_set_prop_params(zhp, ldd->ldd_params);
267 static int zfs_get_prop_int(zfs_handle_t *zhp, char *prop, void *val)
273 ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
277 ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
282 *(__u32 *)val = strtoul(propstr, NULL, 10);
289 static int zfs_get_prop_str(zfs_handle_t *zhp, char *prop, void *val)
295 ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
299 ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
303 (void) strcpy(val, propstr);
308 static int zfs_is_special_ldd_prop_param(char *name)
312 for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++)
313 if (!strcmp(name, special_ldd_prop_params[i].zlpb_prop_name))
319 static int zfs_get_prop_params(zfs_handle_t *zhp, char *param, int len)
323 char key[ZFS_MAXNAMELEN];
327 props = zfs_get_user_props(zhp);
336 while (nvp = nvlist_next_nvpair(props, nvp), nvp) {
337 ret = zfs_get_prop_str(zhp, nvpair_name(nvp), value);
341 if (strncmp(nvpair_name(nvp), LDD_PREFIX, strlen(LDD_PREFIX)))
344 if (zfs_is_special_ldd_prop_param(nvpair_name(nvp)))
347 sprintf(key, "%s=", nvpair_name(nvp) + strlen(LDD_PREFIX));
349 ret = add_param(param, key, value);
360 * Read the server config as properties associated with the dataset.
361 * Missing entries as not treated error and are simply skipped.
363 int zfs_read_ldd(char *ds, struct lustre_disk_data *ldd)
366 struct zfs_ldd_prop_bridge *bridge;
369 if (osd_check_zfs_setup() == 0)
372 zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
376 for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) {
377 bridge = &special_ldd_prop_params[i];
378 ret = bridge->zlpb_get_prop_fn(zhp, bridge->zlpb_prop_name,
379 (void *)ldd + bridge->zlpb_ldd_offset);
380 if (ret && (ret != ENOENT))
384 ret = zfs_get_prop_params(zhp, ldd->ldd_params, 4096);
385 if (ret && (ret != ENOENT))
388 ldd->ldd_mount_type = LDD_MT_ZFS;
396 int zfs_is_lustre(char *ds, unsigned *mount_type)
398 struct lustre_disk_data tmp_ldd;
401 if (osd_zfs_setup == 0)
404 ret = zfs_read_ldd(ds, &tmp_ldd);
405 if ((ret == 0) && (tmp_ldd.ldd_config_ver > 0) &&
406 (strlen(tmp_ldd.ldd_svname) > 0)) {
407 *mount_type = tmp_ldd.ldd_mount_type;
414 static char *zfs_mkfs_opts(struct mkfs_opts *mop, char *str, int len)
418 if (strlen(mop->mo_mkfsopts) != 0)
419 snprintf(str, len, " -o %s", mop->mo_mkfsopts);
424 static int zfs_create_vdev(struct mkfs_opts *mop, char *vdev)
428 /* Silently ignore reserved vdev names */
429 if ((strncmp(vdev, "disk", 4) == 0) ||
430 (strncmp(vdev, "file", 4) == 0) ||
431 (strncmp(vdev, "mirror", 6) == 0) ||
432 (strncmp(vdev, "raidz", 5) == 0) ||
433 (strncmp(vdev, "spare", 5) == 0) ||
434 (strncmp(vdev, "log", 3) == 0) ||
435 (strncmp(vdev, "cache", 5) == 0))
439 * Verify a file exists at the provided absolute path. If it doesn't
440 * and mo_device_kb is set attempt to create a file vdev to be used.
441 * Relative paths will be passed directly to 'zpool create' which
442 * will check multiple multiple locations under /dev/.
444 if (vdev[0] == '/') {
445 ret = access(vdev, F_OK);
452 fprintf(stderr, "Unable to access required vdev "
453 "for pool %s (%d)\n", vdev, ret);
457 if (mop->mo_device_kb == 0) {
459 fprintf(stderr, "Unable to create vdev due to "
460 "missing --device-size=#N(KB) parameter\n");
464 ret = file_create(vdev, mop->mo_device_kb);
467 fprintf(stderr, "Unable to create vdev %s (%d)\n",
476 int zfs_make_lustre(struct mkfs_opts *mop)
481 char *mkfs_cmd = NULL;
482 char *mkfs_tmp = NULL;
483 char *ds = mop->mo_device;
484 int pool_exists = 0, ret;
486 if (osd_check_zfs_setup() == 0)
489 /* no automatic index with zfs backend */
490 if (mop->mo_ldd.ldd_flags & LDD_F_NEED_INDEX) {
492 fprintf(stderr, "The target index must be specified with "
497 ret = zfs_check_hostid(mop);
505 mkfs_cmd = malloc(PATH_MAX);
506 if (mkfs_cmd == NULL) {
511 mkfs_tmp = malloc(PATH_MAX);
512 if (mkfs_tmp == NULL) {
517 /* Due to zfs_prepare_lustre() check the '/' must exist */
518 strchr(pool, '/')[0] = '\0';
520 /* If --reformat was given attempt to destroy the previous dataset */
521 if ((mop->mo_flags & MO_FORCEFORMAT) &&
522 ((zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM)) != NULL)) {
524 ret = zfs_destroy(zhp, 0);
527 fprintf(stderr, "Failed destroy zfs dataset %s (%d)\n",
536 * Create the zpool if the vdevs have been specified and the pool
537 * does not already exists. The pool creation itself will be done
538 * with the zpool command rather than the zpool_create() library call
539 * so the existing zpool error handling can be leveraged.
541 php = zpool_open(g_zfs, pool);
547 if ((mop->mo_pool_vdevs != NULL) && (pool_exists == 0)) {
549 memset(mkfs_cmd, 0, PATH_MAX);
550 snprintf(mkfs_cmd, PATH_MAX,
551 "zpool create -f -O canmount=off %s", pool);
553 /* Append the vdev config and create file vdevs as required */
554 while (*mop->mo_pool_vdevs != NULL) {
555 strscat(mkfs_cmd, " ", PATH_MAX);
556 strscat(mkfs_cmd, *mop->mo_pool_vdevs, PATH_MAX);
558 ret = zfs_create_vdev(mop, *mop->mo_pool_vdevs);
562 mop->mo_pool_vdevs++;
565 vprint("mkfs_cmd = %s\n", mkfs_cmd);
566 ret = run_command(mkfs_cmd, PATH_MAX);
569 fprintf(stderr, "Unable to create pool %s (%d)\n",
576 * Create the ZFS filesystem with any required mkfs options:
577 * - canmount=off is set to prevent zfs automounting
578 * - xattr=sa is set to use system attribute based xattrs
580 memset(mkfs_cmd, 0, PATH_MAX);
581 snprintf(mkfs_cmd, PATH_MAX,
582 "zfs create -o canmount=off -o xattr=sa%s %s",
583 zfs_mkfs_opts(mop, mkfs_tmp, PATH_MAX), ds);
585 vprint("mkfs_cmd = %s\n", mkfs_cmd);
586 ret = run_command(mkfs_cmd, PATH_MAX);
589 fprintf(stderr, "Unable to create filesystem %s (%d)\n",
598 if (mkfs_cmd != NULL)
601 if (mkfs_tmp != NULL)
607 int zfs_enable_quota(struct mkfs_opts *mop)
609 fprintf(stderr, "this option is not only valid for zfs\n");
613 int zfs_prepare_lustre(struct mkfs_opts *mop,
614 char *wanted_mountopts, size_t len)
616 if (osd_check_zfs_setup() == 0)
619 if (zfs_name_valid(mop->mo_device, ZFS_TYPE_FILESYSTEM) == 0) {
621 fprintf(stderr, "Invalid filesystem name %s\n", mop->mo_device);
625 if (strchr(mop->mo_device, '/') == NULL) {
627 fprintf(stderr, "Missing pool in filesystem name %s\n",
635 int zfs_tune_lustre(char *dev, struct mount_opts *mop)
637 if (osd_check_zfs_setup() == 0)
643 int zfs_label_lustre(struct mount_opts *mop)
648 if (osd_check_zfs_setup() == 0)
651 zhp = zfs_open(g_zfs, mop->mo_source, ZFS_TYPE_FILESYSTEM);
655 ret = zfs_set_prop_str(zhp, LDD_SVNAME_PROP, mop->mo_ldd.ldd_svname);
665 g_zfs = libzfs_init();
667 fprintf(stderr, "Failed to initialize ZFS library\n");