X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Futils%2Fmount_utils_zfs.c;h=ea495e3b7fd2449686a30d8ad4c76d1c3599d690;hb=990890eacf757d73fc87a83bfa703a51b739a05c;hp=755c218913567c5568e6573662da07dd598678ff;hpb=3092629deca3988f7b74e4c2877601688828462a;p=fs%2Flustre-release.git diff --git a/lustre/utils/mount_utils_zfs.c b/lustre/utils/mount_utils_zfs.c index 755c218..ea495e3 100644 --- a/lustre/utils/mount_utils_zfs.c +++ b/lustre/utils/mount_utils_zfs.c @@ -20,7 +20,7 @@ * GPL HEADER END */ /* - * Copyright (c) 2012, 2014, Intel Corporation. + * Copyright (c) 2012, 2016, Intel Corporation. * Use is subject to license terms. */ /* @@ -32,6 +32,8 @@ #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" @@ -75,10 +77,12 @@ static int zfs_set_prop_str(zfs_handle_t *, char *, void *); * the @name property. (e.g. ldd_fsname, ldd_config_ver, etc.) * - @type: The type of @field. Only "int" and "str" are supported. */ -#define ZLB_INIT(name, field, type) \ -{ \ - name, offsetof(struct lustre_disk_data, field), \ - zfs_get_prop_ ## type, zfs_set_prop_ ## type \ +#define ZLB_INIT(name, field, type) \ +{ \ + .zlpb_prop_name = name, \ + .zlpb_ldd_offset = offsetof(struct lustre_disk_data, field), \ + .zlpb_get_prop_fn = zfs_get_prop_ ## type, \ + .zlpb_set_prop_fn = zfs_set_prop_ ## type \ } /* These ldd properties are special because they all have their own @@ -134,15 +138,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_MAXPROPLEN]; + char propname[ZFS_MAXPROPLEN]; int ret = 0; params_dup = strdup(params); @@ -156,15 +212,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); } @@ -198,6 +259,23 @@ static int zfs_check_hostid(struct mkfs_opts *mop) 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 " @@ -244,10 +322,14 @@ int zfs_write_ldd(struct mkfs_opts *mop) ret = zfs_check_hostid(mop); if (ret != 0) - goto out; + 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, @@ -256,14 +338,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; @@ -316,22 +410,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_MAXPROPLEN]; - 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); @@ -345,14 +435,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; } @@ -370,8 +457,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]; @@ -381,7 +471,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; @@ -393,6 +483,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; @@ -573,6 +699,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 @@ -658,6 +800,70 @@ int zfs_label_lustre(struct mount_opts *mop) return ret; } +int zfs_rename_fsname(struct mkfs_opts *mop, const char *oldname) +{ + 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; + } + + cmd_buf = malloc(PATH_MAX); + if (!cmd_buf) { + ret = ENOMEM; + goto out_rmdir; + } + + 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;