X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Futils%2Fmount_utils_zfs.c;h=aacf076f80592b58c99a1e65ae510da1d5817199;hb=25e1cea871abd3c08dffb06ea62046ad84a822c1;hp=96f67fc86b0e8928dbb728837daee74989a279c6;hpb=08aa217ce49aba1ded52e0f7adb8a607035123fd;p=fs%2Flustre-release.git diff --git a/lustre/utils/mount_utils_zfs.c b/lustre/utils/mount_utils_zfs.c index 96f67fc..aacf076 100644 --- a/lustre/utils/mount_utils_zfs.c +++ b/lustre/utils/mount_utils_zfs.c @@ -20,113 +20,99 @@ * GPL HEADER END */ /* - * Copyright (c) 2012, 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 -#include - -/* Persistent mount data is stored in these user attributes */ -#define LDD_VERSION_PROP "lustre:version" -#define LDD_FLAGS_PROP "lustre:flags" -#define LDD_INDEX_PROP "lustre:index" -#define LDD_FSNAME_PROP "lustre:fsname" -#define LDD_SVNAME_PROP "lustre:svname" -#define LDD_UUID_PROP "lustre:uuid" -#define LDD_USERDATA_PROP "lustre:userdata" -#define LDD_MOUNTOPTS_PROP "lustre:mountopts" -#define LDD_PARAMS_PROP "lustre:params" -/* indicate if the ZFS OSD has been successfully setup */ -static int osd_zfs_setup = 0; +#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" +#define LDD_FLAGS_PROP LDD_PREFIX "flags" +#define LDD_INDEX_PROP LDD_PREFIX "index" +#define LDD_FSNAME_PROP LDD_PREFIX "fsname" +#define LDD_SVNAME_PROP LDD_PREFIX "svname" +#define LDD_UUID_PROP LDD_PREFIX "uuid" +#define LDD_USERDATA_PROP LDD_PREFIX "userdata" +#define LDD_MOUNTOPTS_PROP LDD_PREFIX "mountopts" + +/* This structure is used to help bridge the gap between the ZFS + * properties Lustre uses and their corresponding internal LDD fields. + * It is meant to be used internally by the mount utility only. */ +struct zfs_ldd_prop_bridge { + /* Contains the publicly visible name for the property + * (i.e. what is shown when running "zfs get") */ + char *zlpb_prop_name; + /* Contains the offset into the lustre_disk_data structure where + * the value of this property is or will be stored. (i.e. the + * property is read from and written to this offset within ldd) */ + int zlpb_ldd_offset; + /* Function pointer responsible for reading in the @prop + * property from @zhp and storing it in @ldd_field */ + int (*zlpb_get_prop_fn)(zfs_handle_t *zhp, char *prop, void *ldd_field); + /* Function pointer responsible for writing the value of @ldd_field + * into the @prop dataset property in @zhp */ + int (*zlpb_set_prop_fn)(zfs_handle_t *zhp, char *prop, void *ldd_field); +}; -static libzfs_handle_t *g_zfs; +/* Forward declarations needed to initialize the ldd prop bridge list */ +static int zfs_get_prop_int(zfs_handle_t *, char *, void *); +static int zfs_set_prop_int(zfs_handle_t *, char *, void *); +static int zfs_get_prop_str(zfs_handle_t *, char *, void *); +static int zfs_set_prop_str(zfs_handle_t *, char *, void *); + +/* Helper for initializing the entries in the special_ldd_prop_params list. + * - @name: stored directly in the zlpb_prop_name field + * (e.g. lustre:fsname, lustre:version, etc.) + * - @field: the field in the lustre_disk_data which directly maps to + * 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 \ +} -/* dynamic linking handles for libzfs & libnvpair */ -static void *handle_libzfs; -static void *handle_nvpair; - -/* symbol table looked up with dlsym */ -struct zfs_symbols { - libzfs_handle_t *(*libzfs_init)(void); - void (*libzfs_fini)(libzfs_handle_t *); - int (*libzfs_load_module)(char *); - zfs_handle_t* (*zfs_open)(libzfs_handle_t *, const char *, int); - int (*zfs_destroy)(zfs_handle_t *, boolean_t); - void (*zfs_close)(zfs_handle_t *); - int (*zfs_prop_set)(zfs_handle_t*, const char*, const char*); - nvlist_t* (*zfs_get_user_props) (zfs_handle_t *); - int (*zfs_name_valid)(const char *, zfs_type_t); - zpool_handle_t* (*zpool_open)(libzfs_handle_t *, const char *); - void (*zpool_close)(zpool_handle_t *zhp); - int (*nvlist_lookup_string)(nvlist_t*, const char*, char**); - int (*nvlist_lookup_nvlist)(nvlist_t *, const char *, nvlist_t **); +/* These ldd properties are special because they all have their own + * individual fields in the lustre_disk_data structure, as opposed to + * being globbed into the ldd_params field. As such, these need special + * handling when reading/writing the ldd structure to/from persistent + * storage. */ +struct zfs_ldd_prop_bridge special_ldd_prop_params[] = { + ZLB_INIT(LDD_VERSION_PROP, ldd_config_ver, int), + ZLB_INIT(LDD_FLAGS_PROP, ldd_flags, int), + ZLB_INIT(LDD_INDEX_PROP, ldd_svindex, int), + ZLB_INIT(LDD_FSNAME_PROP, ldd_fsname, str), + ZLB_INIT(LDD_SVNAME_PROP, ldd_svname, str), + ZLB_INIT(LDD_UUID_PROP, ldd_uuid, str), + ZLB_INIT(LDD_USERDATA_PROP, ldd_userdata, str), + ZLB_INIT(LDD_MOUNTOPTS_PROP, ldd_mount_opts, str), + { NULL } }; -static struct zfs_symbols sym; -void zfs_fini(void); +/* indicate if the ZFS OSD has been successfully setup */ +static int osd_zfs_setup = 0; -#define DLSYM(handle, func) \ - do { \ - sym.func = (typeof(sym.func))dlsym(handle, #func); \ - } while(0) +static libzfs_handle_t *g_zfs; -/* populate the symbol table after a successful call to dlopen() */ -static int zfs_populate_symbols(void) -{ - char *error; - - dlerror(); /* Clear any existing error */ - - DLSYM(handle_libzfs, libzfs_init); -#define libzfs_init (*sym.libzfs_init) - DLSYM(handle_libzfs, libzfs_fini); -#define libzfs_fini (*sym.libzfs_fini) - DLSYM(handle_libzfs, libzfs_load_module); -#define libzfs_load_module (*sym.libzfs_load_module) - DLSYM(handle_libzfs, zfs_open); -#define zfs_open (*sym.zfs_open) - DLSYM(handle_libzfs, zfs_destroy); -#define zfs_destroy (*sym.zfs_destroy) - DLSYM(handle_libzfs, zfs_close); -#define zfs_close (*sym.zfs_close) - DLSYM(handle_libzfs, zfs_prop_set); -#define zfs_prop_set (*sym.zfs_prop_set) - DLSYM(handle_libzfs, zfs_get_user_props); -#define zfs_get_user_props (*sym.zfs_get_user_props) - DLSYM(handle_libzfs, zfs_name_valid); -#define zfs_name_valid (*sym.zfs_name_valid) - DLSYM(handle_libzfs, zpool_open); -#define zpool_open (*sym.zpool_open) - DLSYM(handle_libzfs, zpool_close); -#define zpool_close (*sym.zpool_close) - DLSYM(handle_nvpair, nvlist_lookup_string); -#define nvlist_lookup_string (*sym.nvlist_lookup_string) - DLSYM(handle_nvpair, nvlist_lookup_nvlist); -#define nvlist_lookup_nvlist (*sym.nvlist_lookup_nvlist) - - error = dlerror(); - if (error != NULL) { - fatal(); - fprintf(stderr, "%s\n", error); - return EINVAL; - } - return 0; -} +void zfs_fini(void); -static int zfs_set_prop_int(zfs_handle_t *zhp, char *prop, __u32 val) +static int zfs_set_prop_int(zfs_handle_t *zhp, char *prop, void *val) { char str[64]; int ret; - (void) snprintf(str, sizeof (str), "%lu", (unsigned long)val); + (void) snprintf(str, sizeof (str), "%i", *(int *)val); vprint(" %s=%s\n", prop, str); ret = zfs_prop_set(zhp, prop, str); @@ -137,18 +123,172 @@ static int zfs_set_prop_int(zfs_handle_t *zhp, char *prop, __u32 val) * Write the zfs property string, note that properties with a NULL or * zero-length value will not be written and 0 returned. */ -static int zfs_set_prop_str(zfs_handle_t *zhp, char *prop, char *val) +static int zfs_set_prop_str(zfs_handle_t *zhp, char *prop, void *val) { int ret = 0; if (val && strlen(val) > 0) { - vprint(" %s=%s\n", prop, val); - ret = zfs_prop_set(zhp, prop, val); + vprint(" %s=%s\n", prop, (char *)val); + ret = zfs_prop_set(zhp, prop, (char *)val); } return ret; } +/* + * 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:='. "=" 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 propname[ZFS_MAXPROPLEN]; + int ret = 0; + + params_dup = strdup(params); + if (params_dup == NULL) + return ENOMEM; + + token = strtok_r(params_dup, " ", &save_token); + while (token) { + key = strtok(token, "="); + if (key == NULL) + continue; + + value = strtok(NULL, "="); + 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, propname, value); + if (ret) + break; + } + + token = strtok_r(NULL, " ", &save_token); + } + + free(params_dup); + + 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) { @@ -166,10 +306,11 @@ int zfs_write_ldd(struct mkfs_opts *mop) struct lustre_disk_data *ldd = &mop->mo_ldd; char *ds = mop->mo_device; zfs_handle_t *zhp; - int ret = EINVAL; + struct zfs_ldd_prop_bridge *bridge; + 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) { @@ -177,45 +318,23 @@ int zfs_write_ldd(struct mkfs_opts *mop) goto out; } - vprint("Writing %s properties\n", ds); - - ret = zfs_set_prop_int(zhp, LDD_VERSION_PROP, ldd->ldd_config_ver); - if (ret) - goto out_close; - - ret = zfs_set_prop_int(zhp, LDD_FLAGS_PROP, ldd->ldd_flags); - if (ret) - goto out_close; - - ret = zfs_set_prop_int(zhp, LDD_INDEX_PROP, ldd->ldd_svindex); - if (ret) - goto out_close; - - ret = zfs_set_prop_str(zhp, LDD_FSNAME_PROP, ldd->ldd_fsname); - if (ret) - goto out_close; - - ret = zfs_set_prop_str(zhp, LDD_SVNAME_PROP, ldd->ldd_svname); - if (ret) - goto out_close; - - ret = zfs_set_prop_str(zhp, LDD_UUID_PROP, (char *)ldd->ldd_uuid); - if (ret) + ret = zfs_check_hostid(mop); + if (ret != 0) goto out_close; - ret = zfs_set_prop_str(zhp, LDD_USERDATA_PROP, ldd->ldd_userdata); - if (ret) - goto out_close; + vprint("Writing %s properties\n", ds); - ret = zfs_set_prop_str(zhp, LDD_MOUNTOPTS_PROP, ldd->ldd_mount_opts); - if (ret) - goto out_close; + if (mop->mo_flags & MO_ERASE_ALL) + ret = zfs_erase_allprops(zhp); + ret = zfs_set_prop_params(zhp, ldd->ldd_params); - if (strlen(ldd->ldd_params) > ZAP_MAXVALUELEN) { - ret = E2BIG; - goto out_close; + 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, + (void *)ldd + bridge->zlpb_ldd_offset); + if (ret) + goto out_close; } - ret = zfs_set_prop_str(zhp, LDD_PARAMS_PROP, ldd->ldd_params); out_close: zfs_close(zhp); @@ -223,7 +342,21 @@ out: return ret; } -static int zfs_get_prop_int(zfs_handle_t *zhp, char *prop, __u32 *val) +/* 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; char *propstr; @@ -238,14 +371,14 @@ static int zfs_get_prop_int(zfs_handle_t *zhp, char *prop, __u32 *val) return ret; errno = 0; - *val = strtoul(propstr, NULL, 10); + *(__u32 *)val = strtoul(propstr, NULL, 10); if (errno) return errno; return ret; } -static int zfs_get_prop_str(zfs_handle_t *zhp, char *prop, char *val) +static int zfs_get_prop_str(zfs_handle_t *zhp, char *prop, void *val) { nvlist_t *propval; char *propstr; @@ -264,6 +397,50 @@ static int zfs_get_prop_str(zfs_handle_t *zhp, char *prop, char *val) return ret; } +static int zfs_is_special_ldd_prop_param(char *name) +{ + int i; + + for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) + if (!strcmp(name, special_ldd_prop_params[i].zlpb_prop_name)) + return 1; + + return 0; +} + +static int zfs_get_prop_params(zfs_handle_t *zhp, char *param) +{ + nvlist_t *props; + nvpair_t *nvp; + char key[ZFS_MAXPROPLEN] = ""; + char value[PARAM_MAX] = ""; + int ret = 0; + + props = zfs_get_user_props(zhp); + if (props == NULL) + return ENOENT; + + nvp = NULL; + while (nvp = nvlist_next_nvpair(props, nvp), nvp) { + ret = zfs_get_prop_str(zhp, nvpair_name(nvp), value); + if (ret) + break; + + if (strncmp(nvpair_name(nvp), LDD_PREFIX, strlen(LDD_PREFIX))) + continue; + + if (zfs_is_special_ldd_prop_param(nvpair_name(nvp))) + continue; + + sprintf(key, "%s=", nvpair_name(nvp) + strlen(LDD_PREFIX)); + ret = add_param(param, key, value); + if (ret) + break; + } + + return ret; +} + /* * Read the server config as properties associated with the dataset. * Missing entries as not treated error and are simply skipped. @@ -271,48 +448,28 @@ static int zfs_get_prop_str(zfs_handle_t *zhp, char *prop, char *val) int zfs_read_ldd(char *ds, struct lustre_disk_data *ldd) { zfs_handle_t *zhp; - int ret = EINVAL; + struct zfs_ldd_prop_bridge *bridge; + int i, ret = EINVAL; if (osd_check_zfs_setup() == 0) return EINVAL; zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM); - if (zhp == NULL) - goto out; - - ret = zfs_get_prop_int(zhp, LDD_VERSION_PROP, &ldd->ldd_config_ver); - if (ret && (ret != ENOENT)) - goto out_close; - - ret = zfs_get_prop_int(zhp, LDD_FLAGS_PROP, &ldd->ldd_flags); - if (ret && (ret != ENOENT)) - goto out_close; - - ret = zfs_get_prop_int(zhp, LDD_INDEX_PROP, &ldd->ldd_svindex); - if (ret && (ret != ENOENT)) - goto out_close; - - ret = zfs_get_prop_str(zhp, LDD_FSNAME_PROP, ldd->ldd_fsname); - if (ret && (ret != ENOENT)) - goto out_close; - - ret = zfs_get_prop_str(zhp, LDD_SVNAME_PROP, ldd->ldd_svname); - if (ret && (ret != ENOENT)) - goto out_close; - - ret = zfs_get_prop_str(zhp, LDD_UUID_PROP, (char *)ldd->ldd_uuid); - if (ret && (ret != ENOENT)) - goto out_close; - - ret = zfs_get_prop_str(zhp, LDD_USERDATA_PROP, ldd->ldd_userdata); - if (ret && (ret != ENOENT)) - goto out_close; + if (!zhp) { + zhp = zfs_open(g_zfs, ds, ZFS_TYPE_SNAPSHOT); + if (!zhp) + goto out; + } - ret = zfs_get_prop_str(zhp, LDD_MOUNTOPTS_PROP, ldd->ldd_mount_opts); - if (ret && (ret != ENOENT)) - goto out_close; + for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) { + bridge = &special_ldd_prop_params[i]; + ret = bridge->zlpb_get_prop_fn(zhp, bridge->zlpb_prop_name, + (void *)ldd + bridge->zlpb_ldd_offset); + if (ret && (ret != ENOENT)) + goto out_close; + } - ret = zfs_get_prop_str(zhp, LDD_PARAMS_PROP, ldd->ldd_params); + ret = zfs_get_prop_params(zhp, ldd->ldd_params); if (ret && (ret != ENOENT)) goto out_close; @@ -324,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; @@ -368,7 +561,7 @@ static int zfs_create_vdev(struct mkfs_opts *mop, char *vdev) /* * Verify a file exists at the provided absolute path. If it doesn't - * and mo_device_sz is set attempt to create a file vdev to be used. + * and mo_device_kb is set attempt to create a file vdev to be used. * Relative paths will be passed directly to 'zpool create' which * will check multiple multiple locations under /dev/. */ @@ -385,14 +578,14 @@ static int zfs_create_vdev(struct mkfs_opts *mop, char *vdev) return ret; } - if (mop->mo_device_sz == 0) { + if (mop->mo_device_kb == 0) { fatal(); fprintf(stderr, "Unable to create vdev due to " "missing --device-size=#N(KB) parameter\n"); return EINVAL; } - ret = file_create(vdev, mop->mo_device_sz); + ret = file_create(vdev, mop->mo_device_kb); if (ret) { fatal(); fprintf(stderr, "Unable to create vdev %s (%d)\n", @@ -425,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; @@ -441,7 +638,7 @@ int zfs_make_lustre(struct mkfs_opts *mop) goto out; } - /* Due to zfs_name_valid() check the '/' must exist */ + /* Due to zfs_prepare_lustre() check the '/' must exist */ strchr(pool, '/')[0] = '\0'; /* If --reformat was given attempt to destroy the previous dataset */ @@ -500,15 +697,30 @@ 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 - * - version=4 is set because SA are not yet handled by the osd + * - xattr=sa is set to use system attribute based xattrs */ memset(mkfs_cmd, 0, PATH_MAX); snprintf(mkfs_cmd, PATH_MAX, "zfs create -o canmount=off -o xattr=sa%s %s", - zfs_mkfs_opts(mop, mkfs_tmp, PATH_MAX), - ds); + zfs_mkfs_opts(mop, mkfs_tmp, PATH_MAX), ds); vprint("mkfs_cmd = %s\n", mkfs_cmd); ret = run_command(mkfs_cmd, PATH_MAX); @@ -532,22 +744,31 @@ out: return ret; } -int zfs_prepare_lustre(struct mkfs_opts *mop, - char *default_mountopts, int default_len, - char *always_mountopts, int always_len) +int zfs_enable_quota(struct mkfs_opts *mop) { - int ret; + fprintf(stderr, "this option is not only valid for zfs\n"); + return ENOSYS; +} +int zfs_prepare_lustre(struct mkfs_opts *mop, + char *wanted_mountopts, size_t len) +{ if (osd_check_zfs_setup() == 0) return EINVAL; - ret = zfs_name_valid(mop->mo_device, ZFS_TYPE_FILESYSTEM); - if (!ret) { + if (zfs_name_valid(mop->mo_device, ZFS_TYPE_FILESYSTEM) == 0) { fatal(); fprintf(stderr, "Invalid filesystem name %s\n", mop->mo_device); return EINVAL; } + if (strchr(mop->mo_device, '/') == NULL) { + fatal(); + fprintf(stderr, "Missing pool in filesystem name %s\n", + mop->mo_device); + return EINVAL; + } + return 0; } @@ -577,43 +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; - - /* 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 */ + struct mount_opts opts; + char mntpt[] = "/tmp/mntXXXXXX"; + char *cmd_buf; + int ret; - handle_libzfs = dlopen("libzfs.so", RTLD_LAZY); - if (handle_libzfs == NULL) - return EINVAL; + /* 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; + } - handle_nvpair = dlopen("libnvpair.so", RTLD_LAZY); - if (handle_nvpair == NULL) { - ret = EINVAL; - goto out; + /* 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; } - ret = zfs_populate_symbols(); - if (ret) - goto out; + 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; } @@ -623,14 +894,5 @@ void zfs_fini(void) libzfs_fini(g_zfs); g_zfs = NULL; } - if (handle_nvpair) { - dlclose(handle_nvpair); - handle_nvpair = NULL; - } - if (handle_libzfs) { - dlclose(handle_libzfs); - handle_libzfs = NULL; - } - osd_zfs_setup = 0; }