X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Futils%2Fmount_utils_zfs.c;h=aacf076f80592b58c99a1e65ae510da1d5817199;hb=25e1cea871abd3c08dffb06ea62046ad84a822c1;hp=ec53cc8ea275ec1798c2a97a527365d9619f9cfd;hpb=2b294992edce5af7b79d4300ed3aa1ea6a8db850;p=fs%2Flustre-release.git diff --git a/lustre/utils/mount_utils_zfs.c b/lustre/utils/mount_utils_zfs.c index ec53cc8..aacf076 100644 --- a/lustre/utils/mount_utils_zfs.c +++ b/lustre/utils/mount_utils_zfs.c @@ -20,17 +20,20 @@ * GPL HEADER END */ /* - * Copyright (c) 2012, 2014, Intel Corporation. + * Copyright (c) 2012, 2016, Intel Corporation. * Use is subject to license terms. */ /* * Author: Brian Behlendorf */ #include "mount_utils.h" +#include #include #include #include +#define HOSTID_PATH "/etc/hostid" + /* Persistent mount data is stored in these user attributes */ #define LDD_PREFIX "lustre:" #define LDD_VERSION_PROP LDD_PREFIX "version" @@ -133,15 +136,67 @@ static int zfs_set_prop_str(zfs_handle_t *zhp, char *prop, void *val) } /* + * Remove a property from zfs property dataset + */ +static int zfs_remove_prop(zfs_handle_t *zhp, nvlist_t *nvl, char *propname) +{ + nvlist_remove_all(nvl, propname); + /* XXX: please replace zfs_prop_inherit() if there is a better function + * to call zfs_ioctl() to update data on-disk. + */ + return zfs_prop_inherit(zhp, propname, false); +} + +static int zfs_erase_prop(zfs_handle_t *zhp, char *param) +{ + nvlist_t *nvl; + char propname[ZFS_MAXPROPLEN]; + int len = strlen(param) + strlen(LDD_PREFIX); + + if (len > ZFS_MAXPROPLEN) { + fprintf(stderr, "%s: zfs prop to erase is too long-\n%s\n", + progname, param); + return EINVAL; + } + + nvl = zfs_get_user_props(zhp); + if (!nvl) + return ENOENT; + + snprintf(propname, len + 1, "%s%s", LDD_PREFIX, param); + return zfs_remove_prop(zhp, nvl, propname); +} + +static int zfs_erase_allprops(zfs_handle_t *zhp) +{ + nvlist_t *nvl; + nvpair_t *curr = NULL; + + nvl = zfs_get_user_props(zhp); + if (!nvl) + return ENOENT; + + curr = nvlist_next_nvpair(nvl, curr); + while (curr) { + nvpair_t *next = nvlist_next_nvpair(nvl, curr); + + zfs_remove_prop(zhp, nvl, nvpair_name(curr)); + curr = next; + } + + return 0; +} + +/* * Map '= ...' pairs in the passed string to dataset properties - * of the form 'lustre:='. Malformed = pairs will - * be skipped. + * of the form 'lustre:='. "=" means to remove this key + * from the dataset. */ static int zfs_set_prop_params(zfs_handle_t *zhp, char *params) { char *params_dup, *token, *key, *value; char *save_token = NULL; - char prop_name[ZFS_MAXNAMELEN]; + char propname[ZFS_MAXPROPLEN]; int ret = 0; params_dup = strdup(params); @@ -155,15 +210,20 @@ static int zfs_set_prop_params(zfs_handle_t *zhp, char *params) continue; value = strtok(NULL, "="); - if (value == NULL) - continue; - - sprintf(prop_name, "%s%s", LDD_PREFIX, key); - vprint(" %s=%s\n", prop_name, value); + if (!value) { + /* remove this prop when its value is null */ + ret = zfs_erase_prop(zhp, key); + if (ret) + break; + } else { + snprintf(propname, strlen(LDD_PREFIX) + strlen(key) + 1, + "%s%s", LDD_PREFIX, key); + vprint(" %s=%s\n", propname, value); - ret = zfs_prop_set(zhp, prop_name, value); - if (ret) - break; + ret = zfs_prop_set(zhp, propname, value); + if (ret) + break; + } token = strtok_r(NULL, " ", &save_token); } @@ -173,6 +233,62 @@ static int zfs_set_prop_params(zfs_handle_t *zhp, char *params) return ret; } +static int zfs_check_hostid(struct mkfs_opts *mop) +{ + FILE *f; + unsigned long hostid; + int rc; + + if (strstr(mop->mo_ldd.ldd_params, PARAM_FAILNODE) == NULL) + return 0; + + f = fopen("/sys/module/spl/parameters/spl_hostid", "r"); + if (f == NULL) { + fatal(); + fprintf(stderr, "Failed to open spl_hostid: %s\n", + strerror(errno)); + return errno; + } + rc = fscanf(f, "%li", &hostid); + fclose(f); + if (rc != 1) { + fatal(); + fprintf(stderr, "Failed to read spl_hostid: %d\n", rc); + return rc; + } + + if (hostid != 0) + return 0; + + f = fopen(HOSTID_PATH, "r"); + if (f == NULL) + goto out; + + rc = fread(&hostid, sizeof(uint32_t), 1, f); + fclose(f); + + if (rc != 1) { + fprintf(stderr, "Failed to read "HOSTID_PATH": %d\n", + rc); + hostid = 0; + } + +out: + if (hostid == 0) { + if (mop->mo_flags & MO_NOHOSTID_CHECK) { + fprintf(stderr, "WARNING: spl_hostid not set. ZFS has " + "no zpool import protection\n"); + } else { + fatal(); + fprintf(stderr, "spl_hostid not set. See %s(8)", + progname); + return EINVAL; + } + } + + return 0; +} + static int osd_check_zfs_setup(void) { if (osd_zfs_setup == 0) { @@ -194,7 +310,7 @@ int zfs_write_ldd(struct mkfs_opts *mop) int i, ret = EINVAL; if (osd_check_zfs_setup() == 0) - return EINVAL; + goto out; zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM); if (zhp == NULL) { @@ -202,8 +318,16 @@ int zfs_write_ldd(struct mkfs_opts *mop) goto out; } + ret = zfs_check_hostid(mop); + if (ret != 0) + goto out_close; + vprint("Writing %s properties\n", ds); + if (mop->mo_flags & MO_ERASE_ALL) + ret = zfs_erase_allprops(zhp); + ret = zfs_set_prop_params(zhp, ldd->ldd_params); + for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) { bridge = &special_ldd_prop_params[i]; ret = bridge->zlpb_set_prop_fn(zhp, bridge->zlpb_prop_name, @@ -212,14 +336,26 @@ int zfs_write_ldd(struct mkfs_opts *mop) goto out_close; } - ret = zfs_set_prop_params(zhp, ldd->ldd_params); - out_close: zfs_close(zhp); out: return ret; } +/* Mark a property to be removed by the form of "key=" */ +int zfs_erase_ldd(struct mkfs_opts *mop, char *param) +{ + char key[ZFS_MAXPROPLEN] = ""; + + if (strlen(LDD_PREFIX) + strlen(param) > ZFS_MAXPROPLEN) { + fprintf(stderr, "%s: zfs prop to erase is too long-\n%s\n", + progname, param); + return EINVAL; + } + snprintf(key, strlen(param) + 2, "%s=", param); + return add_param(mop->mo_ldd.ldd_params, key, ""); +} + static int zfs_get_prop_int(zfs_handle_t *zhp, char *prop, void *val) { nvlist_t *propval; @@ -272,22 +408,18 @@ static int zfs_is_special_ldd_prop_param(char *name) return 0; } -static int zfs_get_prop_params(zfs_handle_t *zhp, char *param, int len) +static int zfs_get_prop_params(zfs_handle_t *zhp, char *param) { nvlist_t *props; nvpair_t *nvp; - char key[ZFS_MAXNAMELEN]; - char *value; + char key[ZFS_MAXPROPLEN] = ""; + char value[PARAM_MAX] = ""; int ret = 0; props = zfs_get_user_props(zhp); if (props == NULL) return ENOENT; - value = malloc(len); - if (value == NULL) - return ENOMEM; - nvp = NULL; while (nvp = nvlist_next_nvpair(props, nvp), nvp) { ret = zfs_get_prop_str(zhp, nvpair_name(nvp), value); @@ -301,14 +433,11 @@ static int zfs_get_prop_params(zfs_handle_t *zhp, char *param, int len) continue; sprintf(key, "%s=", nvpair_name(nvp) + strlen(LDD_PREFIX)); - ret = add_param(param, key, value); if (ret) break; } - free(value); - return ret; } @@ -326,8 +455,11 @@ int zfs_read_ldd(char *ds, struct lustre_disk_data *ldd) return EINVAL; zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM); - if (zhp == NULL) - goto out; + if (!zhp) { + zhp = zfs_open(g_zfs, ds, ZFS_TYPE_SNAPSHOT); + if (!zhp) + goto out; + } for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) { bridge = &special_ldd_prop_params[i]; @@ -337,7 +469,7 @@ int zfs_read_ldd(char *ds, struct lustre_disk_data *ldd) goto out_close; } - ret = zfs_get_prop_params(zhp, ldd->ldd_params, 4096); + ret = zfs_get_prop_params(zhp, ldd->ldd_params); if (ret && (ret != ENOENT)) goto out_close; @@ -349,6 +481,42 @@ out: return ret; } +/* Print ldd params */ +void zfs_print_ldd_params(struct mkfs_opts *mop) +{ + char *from = mop->mo_ldd.ldd_params; + char *to; + int len; + + vprint("Parameters:"); + while (from) { + /* skip those keys to be removed in the form of "key=" */ + to = strstr(from, "= "); + if (!to) + /* "key=" may be in the end */ + if (*(from + strlen(from) - 1) == '=') + to = from + strlen(from) - 1; + + /* find " " inward */ + len = strlen(from); + if (to) { + len = strlen(from) - strlen(to); + while ((*(from + len) != ' ') && len) + len--; + } + if (len) + /* no space in the end */ + vprint("%*.*s", len, len, from); + + /* If there is no "key=" or "key=" is in the end, stop. */ + if (!to || strlen(to) == 1) + break; + + /* skip "=" */ + from = to + 1; + } +} + int zfs_is_lustre(char *ds, unsigned *mount_type) { struct lustre_disk_data tmp_ldd; @@ -450,6 +618,10 @@ int zfs_make_lustre(struct mkfs_opts *mop) return EINVAL; } + ret = zfs_check_hostid(mop); + if (ret != 0) + goto out; + pool = strdup(ds); if (pool == NULL) return ENOMEM; @@ -525,6 +697,22 @@ int zfs_make_lustre(struct mkfs_opts *mop) } /* + * Set Options on ZPOOL + * + * ALL - canmount=off + * 0.7.0 - multihost=on + */ + php = zpool_open(g_zfs, pool); + if (php) { + if (pool_exists) + zpool_set_prop(php, "canmount", "off"); + + zpool_set_prop(php, "multihost", "on"); + + zpool_close(php); + } + + /* * Create the ZFS filesystem with any required mkfs options: * - canmount=off is set to prevent zfs automounting * - xattr=sa is set to use system attribute based xattrs @@ -563,8 +751,7 @@ int zfs_enable_quota(struct mkfs_opts *mop) } int zfs_prepare_lustre(struct mkfs_opts *mop, - char *default_mountopts, int default_len, - char *always_mountopts, int always_len) + char *wanted_mountopts, size_t len) { if (osd_check_zfs_setup() == 0) return EINVAL; @@ -611,29 +798,93 @@ int zfs_label_lustre(struct mount_opts *mop) return ret; } -int zfs_init(void) +int zfs_rename_fsname(struct mkfs_opts *mop, const char *oldname) { - int ret = 0; + struct mount_opts opts; + char mntpt[] = "/tmp/mntXXXXXX"; + char *cmd_buf; + int ret; + + /* Change the filesystem label. */ + opts.mo_ldd = mop->mo_ldd; + opts.mo_source = mop->mo_device; + ret = zfs_label_lustre(&opts); + if (ret) { + if (errno != 0) + ret = errno; + fprintf(stderr, "Can't change filesystem label: %s\n", + strerror(ret)); + return ret; + } + + /* Mount this device temporarily in order to write these files */ + if (mkdtemp(mntpt) == NULL) { + if (errno != 0) + ret = errno; + fprintf(stderr, "Can't create temp mount point %s: %s\n", + mntpt, strerror(ret)); + return ret; + } - /* If the ZFS libs are not installed, don't print an error to avoid - * spamming ldiskfs users. An error message will still be printed if - * someone tries to do some real work involving a ZFS backend */ + cmd_buf = malloc(PATH_MAX); + if (!cmd_buf) { + ret = ENOMEM; + goto out_rmdir; + } - if (libzfs_load_module("zfs") != 0) { - /* The ZFS modules are not installed */ - ret = EINVAL; - goto out; + memset(cmd_buf, 0, PATH_MAX); + snprintf(cmd_buf, PATH_MAX - 1, "zfs set mountpoint=%s %s && " + "zfs set canmount=on %s && zfs mount %s", + mntpt, mop->mo_device, mop->mo_device, mop->mo_device); + ret = run_command(cmd_buf, PATH_MAX); + if (ret) { + if (errno != 0) + ret = errno; + fprintf(stderr, "Unable to mount %s (%s)\n", + mop->mo_device, strerror(ret)); + if (ret == ENODEV) + fprintf(stderr, "Is the %s module available?\n", + MT_STR(&mop->mo_ldd)); + goto out_free; } + ret = lustre_rename_fsname(mop, mntpt, oldname); + memset(cmd_buf, 0, PATH_MAX); + snprintf(cmd_buf, PATH_MAX - 1, "zfs umount %s && " + "zfs set canmount=off %s && zfs set mountpoint=none %s", + mop->mo_device, mop->mo_device, mop->mo_device); + run_command(cmd_buf, PATH_MAX); + +out_free: + free(cmd_buf); +out_rmdir: + rmdir(mntpt); + return ret; +} + +int zfs_init(void) +{ + int ret = 0; + g_zfs = libzfs_init(); if (g_zfs == NULL) { - fprintf(stderr, "Failed to initialize ZFS library\n"); - ret = EINVAL; + /* Try to load zfs.ko and retry libzfs_init() */ + + ret = system("/sbin/modprobe -q zfs"); + + if (ret == 0) { + g_zfs = libzfs_init(); + if (g_zfs == NULL) + ret = EINVAL; + } } -out: - osd_zfs_setup = 1; - if (ret) - zfs_fini(); + + if (ret == 0) + osd_zfs_setup = 1; + + else + fprintf(stderr, "Failed to initialize ZFS library: %d\n", ret); + return ret; }