Whamcloud - gitweb
LU-16791 utils: ZFS 2.2 const prop args
[fs/lustre-release.git] / lustre / utils / libmount_utils_zfs.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9
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.
15
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
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2012, 2017, Intel Corporation.
24  * Use is subject to license terms.
25  */
26 /*
27  * Author: Brian Behlendorf <behlendorf1@llnl.gov>
28  */
29 #include "mount_utils.h"
30 #include <stddef.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <libzfs.h>
34 #include <sys/systeminfo.h>
35
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"
46
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") */
53         char *zlpb_prop_name;
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) */
57         int   zlpb_ldd_offset;
58         /* Function pointer responsible for reading in the @prop
59          * property from @zhp and storing it in @ldd_field */
60 #ifdef HAVE_ZFS_NVLIST_CONST_INTERFACES
61         int (*zlpb_get_prop_fn)(zfs_handle_t *zhp, const char *prop,
62              void *ldd_field);
63 #else
64         int (*zlpb_get_prop_fn)(zfs_handle_t *zhp, char *prop, void *ldd_field);
65 #endif
66         /* Function pointer responsible for writing the value of @ldd_field
67          * into the @prop dataset property in @zhp */
68         int (*zlpb_set_prop_fn)(zfs_handle_t *zhp, char *prop, void *ldd_field);
69 };
70
71 /* Forward declarations needed to initialize the ldd prop bridge list */
72 #ifdef HAVE_ZFS_NVLIST_CONST_INTERFACES
73 static int zfs_get_prop_int(zfs_handle_t *, const char *, void *);
74 static int zfs_get_prop_str(zfs_handle_t *, const char *, void *);
75 #else
76 static int zfs_get_prop_int(zfs_handle_t *, char *, void *);
77 static int zfs_get_prop_str(zfs_handle_t *, char *, void *);
78 #endif
79 static int zfs_set_prop_int(zfs_handle_t *, char *, void *);
80 static int zfs_set_prop_str(zfs_handle_t *, char *, void *);
81
82 /* Helper for initializing the entries in the special_ldd_prop_params list.
83  *    - @name: stored directly in the zlpb_prop_name field
84  *             (e.g. lustre:fsname, lustre:version, etc.)
85  *    - @field: the field in the lustre_disk_data which directly maps to
86  *              the @name property. (e.g. ldd_fsname, ldd_config_ver, etc.)
87  *    - @type: The type of @field. Only "int" and "str" are supported.
88  */
89 #define ZLB_INIT(name, field, type)                                     \
90 {                                                                       \
91         .zlpb_prop_name   = name,                                       \
92         .zlpb_ldd_offset  = offsetof(struct lustre_disk_data, field),   \
93         .zlpb_get_prop_fn = zfs_get_prop_ ## type,                      \
94         .zlpb_set_prop_fn = zfs_set_prop_ ## type                       \
95 }
96
97 /* These ldd properties are special because they all have their own
98  * individual fields in the lustre_disk_data structure, as opposed to
99  * being globbed into the ldd_params field. As such, these need special
100  * handling when reading/writing the ldd structure to/from persistent
101  * storage. */
102 struct zfs_ldd_prop_bridge special_ldd_prop_params[] = {
103         ZLB_INIT(LDD_VERSION_PROP,   ldd_config_ver, int),
104         ZLB_INIT(LDD_FLAGS_PROP,     ldd_flags,      int),
105         ZLB_INIT(LDD_INDEX_PROP,     ldd_svindex,    int),
106         ZLB_INIT(LDD_FSNAME_PROP,    ldd_fsname,     str),
107         ZLB_INIT(LDD_SVNAME_PROP,    ldd_svname,     str),
108         ZLB_INIT(LDD_UUID_PROP,      ldd_uuid,       str),
109         ZLB_INIT(LDD_USERDATA_PROP,  ldd_userdata,   str),
110         ZLB_INIT(LDD_MOUNTOPTS_PROP, ldd_mount_opts, str),
111         { NULL }
112 };
113
114 /* indicate if the ZFS OSD has been successfully setup */
115 static int osd_zfs_setup = 0;
116
117 static libzfs_handle_t *g_zfs;
118
119 void zfs_fini(void);
120
121 static int zfs_set_prop_int(zfs_handle_t *zhp, char *prop, void *val)
122 {
123         char str[64];
124         int ret;
125
126         (void) snprintf(str, sizeof (str), "%i", *(int *)val);
127         vprint("  %s=%s\n", prop, str);
128         ret = zfs_prop_set(zhp, prop, str);
129
130         return ret;
131 }
132
133 /*
134  * Write the zfs property string, note that properties with a NULL or
135  * zero-length value will not be written and 0 returned.
136  */
137 static int zfs_set_prop_str(zfs_handle_t *zhp, char *prop, void *val)
138 {
139         int ret = 0;
140
141         if (val && strlen(val) > 0) {
142                 vprint("  %s=%s\n", prop, (char *)val);
143                 ret = zfs_prop_set(zhp, prop, (char *)val);
144         }
145
146         return ret;
147 }
148
149 /*
150  * Remove a property from zfs property dataset
151  */
152 static int zfs_remove_prop(zfs_handle_t *zhp, nvlist_t *nvl, char *propname)
153 {
154         nvlist_remove_all(nvl, propname);
155         /* XXX: please replace zfs_prop_inherit() if there is a better function
156          * to call zfs_ioctl() to update data on-disk.
157          */
158         return zfs_prop_inherit(zhp, propname, false);
159 }
160
161 static int zfs_erase_prop(zfs_handle_t *zhp, char *param)
162 {
163         nvlist_t *nvl;
164         char propname[ZFS_MAXPROPLEN];
165         int len = strlen(param) + strlen(LDD_PREFIX);
166
167         if (len > ZFS_MAXPROPLEN) {
168                 fprintf(stderr, "%s: zfs prop to erase is too long-\n%s\n",
169                         progname, param);
170                 return EINVAL;
171         }
172
173         nvl = zfs_get_user_props(zhp);
174         if (!nvl)
175                 return ENOENT;
176
177         snprintf(propname, len + 1, "%s%s", LDD_PREFIX, param);
178         return zfs_remove_prop(zhp, nvl, propname);
179 }
180
181 #ifdef HAVE_ZFS_NVLIST_CONST_INTERFACES
182 static int zfs_is_special_ldd_prop_param(const char *name)
183 #else
184 static int zfs_is_special_ldd_prop_param(char *name)
185 #endif
186 {
187         int i;
188
189         for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++)
190                 if (!strcmp(name, special_ldd_prop_params[i].zlpb_prop_name))
191                         return 1;
192
193         return 0;
194 }
195
196 static int zfs_erase_allprops(zfs_handle_t *zhp)
197 {
198         nvlist_t *props;
199         nvpair_t *nvp;
200         size_t str_size = 1024 * 1024;
201         char *strs, *cur;
202         int rc = 0;
203
204         strs = malloc(str_size);
205         if (!strs)
206                 return ENOMEM;
207         cur = strs;
208
209         props = zfs_get_user_props(zhp);
210         if (props == NULL) {
211                 free(strs);
212                 return ENOENT;
213         }
214         nvp = NULL;
215         while (nvp = nvlist_next_nvpair(props, nvp), nvp) {
216                 if (strncmp(nvpair_name(nvp), LDD_PREFIX, strlen(LDD_PREFIX)))
217                         continue;
218
219                 if (zfs_is_special_ldd_prop_param(nvpair_name(nvp)))
220                         continue;
221
222                 rc = snprintf(cur, str_size - (cur - strs), "%s",
223                               nvpair_name(nvp));
224                 if (rc != strlen(nvpair_name(nvp))) {
225                         fprintf(stderr, "%s: zfs has too many properties to erase, please repeat\n",
226                                 progname);
227                         rc = EINVAL;
228                         break;
229                 }
230                 cur += strlen(cur) + 1;
231         }
232         cur = strs;
233         while ( cur < (strs + str_size) && strlen(cur) > 0) {
234                 zfs_prop_inherit(zhp, cur, false);
235                 cur += strlen(cur) + 1;
236         }
237
238         free(strs);
239         return rc;
240 }
241
242 /*
243  * Map '<key>=<value> ...' pairs in the passed string to dataset properties
244  * of the form 'lustre:<key>=<value>'. "<key>=" means to remove this key
245  * from the dataset.
246  */
247 static int zfs_set_prop_params(zfs_handle_t *zhp, char *params)
248 {
249         char *params_dup, *token, *key, *value;
250         char *save_token = NULL;
251         char propname[ZFS_MAXPROPLEN];
252         int ret = 0;
253
254         params_dup = strdup(params);
255         if (params_dup == NULL)
256                 return ENOMEM;
257
258         token = strtok_r(params_dup, " ", &save_token);
259         while (token) {
260                 key = strtok(token, "=");
261                 if (key == NULL)
262                         continue;
263
264                 value = strtok(NULL, "=");
265                 if (!value) {
266                         /* remove this prop when its value is null */
267                         ret = zfs_erase_prop(zhp, key);
268                         if (ret)
269                                 break;
270                 } else {
271                         snprintf(propname, strlen(LDD_PREFIX) + strlen(key) + 1,
272                                  "%s%s", LDD_PREFIX, key);
273                         vprint("  %s=%s\n", propname, value);
274
275                         ret = zfs_prop_set(zhp, propname, value);
276                         if (ret)
277                                 break;
278                 }
279
280                 token = strtok_r(NULL, " ", &save_token);
281         }
282
283         free(params_dup);
284
285         return ret;
286 }
287
288 static int zfs_check_hostid(struct mkfs_opts *mop)
289 {
290         unsigned long hostid;
291
292         if (strstr(mop->mo_ldd.ldd_params, PARAM_FAILNODE) == NULL)
293                 return 0;
294
295         hostid = get_system_hostid();
296         if (hostid == 0) {
297                 if (mop->mo_flags & MO_NOHOSTID_CHECK) {
298                         fprintf(stderr, "WARNING: spl_hostid not set. ZFS has "
299                                 "no zpool import protection\n");
300                 } else {
301                         fatal();
302                         fprintf(stderr, "spl_hostid not set. See %s(8)",
303                                 progname);
304                         return EINVAL;
305                 }
306         }
307
308         return 0;
309 }
310
311 static int osd_check_zfs_setup(void)
312 {
313         if (osd_zfs_setup == 0) {
314                 /* setup failed */
315                 fatal();
316                 fprintf(stderr, "Failed to initialize ZFS library. Are the ZFS "
317                         "packages and modules correctly installed?\n");
318         }
319         return osd_zfs_setup == 1;
320 }
321
322 /* Write the server config as properties associated with the dataset */
323 int zfs_write_ldd(struct mkfs_opts *mop)
324 {
325         struct lustre_disk_data *ldd = &mop->mo_ldd;
326         char *ds = mop->mo_device;
327         zfs_handle_t *zhp;
328         struct zfs_ldd_prop_bridge *bridge;
329         int i, ret = EINVAL;
330
331         if (osd_check_zfs_setup() == 0)
332                 goto out;
333
334         zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
335         if (zhp == NULL) {
336                 fprintf(stderr, "Failed to open zfs dataset %s\n", ds);
337                 goto out;
338         }
339
340         ret = zfs_check_hostid(mop);
341         if (ret != 0)
342                 goto out_close;
343
344         vprint("Writing %s properties\n", ds);
345
346         if (mop->mo_flags & MO_ERASE_ALL) {
347                 ret = zfs_erase_allprops(zhp);
348                 if (ret < 0) {
349                         fprintf(stderr, "zfs_erase_allprops Failed: %d\n", ret);
350                         goto out_close;
351                 }
352         }
353         ret = zfs_set_prop_params(zhp, ldd->ldd_params);
354
355         for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) {
356                 bridge = &special_ldd_prop_params[i];
357                 ret = bridge->zlpb_set_prop_fn(zhp, bridge->zlpb_prop_name,
358                                         (void *)ldd + bridge->zlpb_ldd_offset);
359                 if (ret)
360                         goto out_close;
361         }
362
363 out_close:
364         zfs_close(zhp);
365 out:
366         return ret;
367 }
368
369 /* Mark a property to be removed by the form of "key=" */
370 int zfs_erase_ldd(struct mkfs_opts *mop, char *param)
371 {
372         char key[ZFS_MAXPROPLEN] = "";
373
374         if (strlen(LDD_PREFIX) + strlen(param) > ZFS_MAXPROPLEN) {
375                 fprintf(stderr, "%s: zfs prop to erase is too long-\n%s\n",
376                         progname, param);
377                 return EINVAL;
378         }
379         snprintf(key, strlen(param) + 2, "%s=", param);
380         return add_param(mop->mo_ldd.ldd_params, key, "");
381 }
382
383 #ifdef HAVE_ZFS_NVLIST_CONST_INTERFACES
384 static int zfs_get_prop_int(zfs_handle_t *zhp, const char *prop, void *val)
385 {
386         const char *propstr;
387 #else
388 static int zfs_get_prop_int(zfs_handle_t *zhp, char *prop, void *val)
389 {
390         char *propstr;
391 #endif
392         nvlist_t *propval;
393         int ret;
394
395         ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
396         if (ret)
397                 return ret;
398
399         ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
400         if (ret)
401                 return ret;
402
403         errno = 0;
404         *(__u32 *)val = strtoul(propstr, NULL, 10);
405         if (errno)
406                 return errno;
407
408         return ret;
409 }
410
411 #ifdef HAVE_ZFS_NVLIST_CONST_INTERFACES
412 static int zfs_get_prop_str(zfs_handle_t *zhp, const char *prop, void *val)
413 {
414         const char *propstr;
415 #else
416 static int zfs_get_prop_str(zfs_handle_t *zhp, char *prop, void *val)
417 {
418         char *propstr;
419 #endif
420         nvlist_t *propval;
421         int ret;
422
423         ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
424         if (ret)
425                 return ret;
426
427         ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
428         if (ret)
429                 return ret;
430
431         (void) strcpy(val, propstr);
432
433         return ret;
434 }
435
436 static int zfs_get_prop_params(zfs_handle_t *zhp, char *param)
437 {
438         nvlist_t *props;
439         nvpair_t *nvp;
440         char key[ZFS_MAXPROPLEN] = "";
441         char value[PARAM_MAX] = "";
442         int ret = 0;
443
444         props = zfs_get_user_props(zhp);
445         if (props == NULL)
446                 return ENOENT;
447
448         nvp = NULL;
449         while (nvp = nvlist_next_nvpair(props, nvp), nvp) {
450                 ret = zfs_get_prop_str(zhp, nvpair_name(nvp), value);
451                 if (ret)
452                         break;
453
454                 if (strncmp(nvpair_name(nvp), LDD_PREFIX, strlen(LDD_PREFIX)))
455                         continue;
456
457                 if (zfs_is_special_ldd_prop_param(nvpair_name(nvp)))
458                         continue;
459
460                 sprintf(key, "%s=",  nvpair_name(nvp) + strlen(LDD_PREFIX));
461                 ret = add_param(param, key, value);
462                 if (ret)
463                         break;
464         }
465
466         return ret;
467 }
468
469 /*
470  * Read the server config as properties associated with the dataset.
471  * Missing entries as not treated error and are simply skipped.
472  */
473 int zfs_read_ldd(char *ds,  struct lustre_disk_data *ldd)
474 {
475         zfs_handle_t *zhp;
476         struct zfs_ldd_prop_bridge *bridge;
477         int i, ret = EINVAL;
478
479         if (osd_check_zfs_setup() == 0)
480                 return EINVAL;
481
482         zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
483         if (!zhp) {
484                 zhp = zfs_open(g_zfs, ds, ZFS_TYPE_SNAPSHOT);
485                 if (!zhp)
486                         goto out;
487         }
488
489         for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) {
490                 bridge = &special_ldd_prop_params[i];
491                 ret = bridge->zlpb_get_prop_fn(zhp, bridge->zlpb_prop_name,
492                                         (void *)ldd + bridge->zlpb_ldd_offset);
493                 if (ret && (ret != ENOENT))
494                         goto out_close;
495         }
496
497         ret = zfs_get_prop_params(zhp, ldd->ldd_params);
498         if (ret && (ret != ENOENT))
499                 goto out_close;
500
501         ldd->ldd_mount_type = LDD_MT_ZFS;
502         ret = 0;
503
504         if (strstr(ldd->ldd_params, PARAM_FAILNODE) != NULL) {
505                 zpool_handle_t *pool = zfs_get_pool_handle(zhp);
506                 uint64_t mh = zpool_get_prop_int(pool, ZPOOL_PROP_MULTIHOST,
507                                                  NULL);
508                 if (!mh)
509                         fprintf(stderr, "%s: %s is configured for failover "
510                                 "but zpool does not have multihost enabled\n",
511                                 progname, ds);
512         }
513
514 out_close:
515         zfs_close(zhp);
516
517 out:
518         return ret;
519 }
520
521 /* Print ldd params */
522 void zfs_print_ldd_params(struct mkfs_opts *mop)
523 {
524         char *from = mop->mo_ldd.ldd_params;
525         char *to;
526         int len;
527
528         vprint("Parameters:");
529         while (from) {
530                 /* skip those keys to be removed in the form of "key=" */
531                 to = strstr(from, "= ");
532                 if (!to)
533                         /* "key=" may be in the end */
534                         if (*(from + strlen(from) - 1) == '=')
535                                 to = from + strlen(from) - 1;
536
537                 /* find " " inward */
538                 len = strlen(from);
539                 if (to) {
540                         len = strlen(from) - strlen(to);
541                         while ((*(from + len) != ' ') && len)
542                                 len--;
543                 }
544                 if (len)
545                         /* no space in the end */
546                         vprint("%*.*s", len, len, from);
547
548                 /* If there is no "key=" or "key=" is in the end, stop. */
549                 if (!to || strlen(to) == 1)
550                         break;
551
552                 /* skip "=" */
553                 from = to + 1;
554         }
555 }
556
557 int zfs_is_lustre(char *ds, unsigned *mount_type)
558 {
559         struct lustre_disk_data tmp_ldd;
560         int ret;
561
562         if (osd_zfs_setup == 0)
563                 return 0;
564
565         ret = zfs_read_ldd(ds, &tmp_ldd);
566         if ((ret == 0) && (tmp_ldd.ldd_config_ver > 0) &&
567             (strlen(tmp_ldd.ldd_svname) > 0)) {
568                 *mount_type = tmp_ldd.ldd_mount_type;
569                 return 1;
570         }
571
572         return 0;
573 }
574
575 static char *zfs_mkfs_opts(struct mkfs_opts *mop, char *str, int len)
576 {
577         memset(str, 0, len);
578
579         if (strlen(mop->mo_mkfsopts) != 0)
580                 snprintf(str, len, " -o %s", mop->mo_mkfsopts);
581         if (mop->mo_device_kb)
582                 snprintf(str, len, " -o quota=%llu",
583                          (unsigned long long)mop->mo_device_kb * 1024);
584
585         return str;
586 }
587
588 static int zfs_create_vdev(struct mkfs_opts *mop, char *vdev)
589 {
590         int ret = 0;
591
592         /* Silently ignore reserved vdev names */
593         if ((strncmp(vdev, "disk", 4) == 0) ||
594             (strncmp(vdev, "file", 4) == 0) ||
595             (strncmp(vdev, "mirror", 6) == 0) ||
596             (strncmp(vdev, "raidz", 5) == 0) ||
597             (strncmp(vdev, "spare", 5) == 0) ||
598             (strncmp(vdev, "log", 3) == 0) ||
599             (strncmp(vdev, "cache", 5) == 0))
600                 return ret;
601
602         /*
603          * Verify a file exists at the provided absolute path.  If it doesn't
604          * and mo_device_kb is set attempt to create a file vdev to be used.
605          * Relative paths will be passed directly to 'zpool create' which
606          * will check multiple multiple locations under /dev/.
607          */
608         if (vdev[0] == '/') {
609                 ret = access(vdev, F_OK);
610                 if (ret == 0)
611                         return ret;
612
613                 ret = errno;
614                 if (ret != ENOENT) {
615                         fatal();
616                         fprintf(stderr, "Unable to access required vdev "
617                                 "for pool %s (%d)\n", vdev, ret);
618                         return ret;
619                 }
620
621                 if (mop->mo_device_kb == 0) {
622                         fatal();
623                         fprintf(stderr, "Unable to create vdev due to "
624                                 "missing --device-size=#N(KB) parameter\n");
625                         return EINVAL;
626                 }
627
628                 ret = file_create(vdev, mop->mo_device_kb);
629                 if (ret) {
630                         fatal();
631                         fprintf(stderr, "Unable to create vdev %s (%d)\n",
632                                 vdev, ret);
633                         return ret;
634                 }
635         }
636
637         return ret;
638 }
639
640 int zfs_make_lustre(struct mkfs_opts *mop)
641 {
642         zfs_handle_t *zhp;
643         zpool_handle_t *php;
644         char *pool = NULL;
645         char *mkfs_cmd = NULL;
646         char *mkfs_tmp = NULL;
647         char *ds = mop->mo_device;
648         int pool_exists = 0, ret;
649
650         if (osd_check_zfs_setup() == 0)
651                 return EINVAL;
652
653         /* no automatic index with zfs backend */
654         if (mop->mo_ldd.ldd_flags & LDD_F_NEED_INDEX) {
655                 fatal();
656                 fprintf(stderr, "The target index must be specified with "
657                                 "--index\n");
658                 return EINVAL;
659         }
660
661         ret = zfs_check_hostid(mop);
662         if (ret != 0)
663                 goto out;
664
665         pool = strdup(ds);
666         if (pool == NULL)
667                 return ENOMEM;
668
669         mkfs_cmd = malloc(PATH_MAX);
670         if (mkfs_cmd == NULL) {
671                 ret = ENOMEM;
672                 goto out;
673         }
674
675         mkfs_tmp = malloc(PATH_MAX);
676         if (mkfs_tmp == NULL) {
677                 ret = ENOMEM;
678                 goto out;
679         }
680
681         /* Due to zfs_prepare_lustre() check the '/' must exist */
682         strchr(pool, '/')[0] = '\0';
683
684         /* If --reformat was given attempt to destroy the previous dataset */
685         if ((mop->mo_flags & MO_FORCEFORMAT) &&
686             ((zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM)) != NULL)) {
687
688                 ret = zfs_destroy(zhp, 0);
689                 if (ret) {
690                         zfs_close(zhp);
691                         fprintf(stderr, "Failed destroy zfs dataset %s (%d)\n",
692                                 ds, ret);
693                         goto out;
694                 }
695
696                 zfs_close(zhp);
697         }
698
699         /*
700          * Create the zpool if the vdevs have been specified and the pool
701          * does not already exists.  The pool creation itself will be done
702          * with the zpool command rather than the zpool_create() library call
703          * so the existing zpool error handling can be leveraged.
704          */
705         php = zpool_open(g_zfs, pool);
706         if (php) {
707                 pool_exists = 1;
708                 zpool_set_prop(php, "canmount", "off");
709                 zpool_close(php);
710         }
711
712         if ((mop->mo_pool_vdevs != NULL) && (pool_exists == 0)) {
713
714                 memset(mkfs_cmd, 0, PATH_MAX);
715                 snprintf(mkfs_cmd, PATH_MAX,
716                         "zpool create -f -O canmount=off %s", pool);
717
718                 /* Append the vdev config and create file vdevs as required */
719                 while (*mop->mo_pool_vdevs != NULL) {
720                         strscat(mkfs_cmd, " ", PATH_MAX);
721                         strscat(mkfs_cmd, *mop->mo_pool_vdevs, PATH_MAX);
722
723                         ret = zfs_create_vdev(mop, *mop->mo_pool_vdevs);
724                         if (ret)
725                                 goto out;
726
727                         mop->mo_pool_vdevs++;
728                 }
729
730                 vprint("mkfs_cmd = %s\n", mkfs_cmd);
731                 ret = run_command(mkfs_cmd, PATH_MAX);
732                 if (ret) {
733                         fatal();
734                         fprintf(stderr, "Unable to create pool %s (%d)\n",
735                                 pool, ret);
736                         goto out;
737                 }
738         }
739
740         /*
741          * Set Options on ZPOOL
742          *
743          * ALL   - canmount=off (set above)
744          * 0.7.0 - multihost=on
745          * 0.7.0 - feature@userobj_accounting=enabled
746          */
747         php = zpool_open(g_zfs, pool);
748         if (php) {
749                 zpool_set_prop(php, "multihost", "on");
750                 zpool_set_prop(php, "feature@userobj_accounting", "enabled");
751                 zpool_close(php);
752         }
753
754         /*
755          * Create the ZFS filesystem with any required mkfs options:
756          * - canmount=off is set to prevent zfs automounting
757          */
758         memset(mkfs_cmd, 0, PATH_MAX);
759         snprintf(mkfs_cmd, PATH_MAX,
760                  "zfs create -o canmount=off %s %s",
761                  zfs_mkfs_opts(mop, mkfs_tmp, PATH_MAX), ds);
762
763         vprint("mkfs_cmd = %s\n", mkfs_cmd);
764         ret = run_command(mkfs_cmd, PATH_MAX);
765         if (ret) {
766                 fatal();
767                 fprintf(stderr, "Unable to create filesystem %s (%d)\n",
768                         ds, ret);
769                 goto out;
770         }
771
772         /*
773          * Attempt to set dataset properties to reasonable defaults
774          * to optimize performance, unless the values were specified
775          * at the mkfs command line. Some ZFS pools or ZFS versions
776          * do not support these properties. We can safely ignore the
777          * errors and continue in those cases.
778          *
779          * zfs 0.6.1 - system attribute based xattrs
780          * zfs 0.6.5 - large block support
781          * zfs 0.7.0 - large dnode support
782          *
783          * Check if zhp is NULL as a defensive measure. Any dataset
784          * validation errors that would cause zfs_open() to fail
785          * should have been caught earlier.
786          */
787         zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
788         if (zhp) {
789                 /* zfs 0.6.1 - system attribute based xattrs */
790                 if (!strstr(mop->mo_mkfsopts, "xattr="))
791                         zfs_set_prop_str(zhp, "xattr", "sa");
792
793                 /* zfs 0.7.0 - large dnode support */
794                 if (!strstr(mop->mo_mkfsopts, "dnodesize=") &&
795                     !strstr(mop->mo_mkfsopts, "dnsize="))
796                         zfs_set_prop_str(zhp, "dnodesize", "auto");
797
798                 if (IS_OST(&mop->mo_ldd)) {
799                         /* zfs 0.6.5 - large block support */
800                         if (!strstr(mop->mo_mkfsopts, "recordsize=") &&
801                             !strstr(mop->mo_mkfsopts, "recsize="))
802                                 zfs_set_prop_str(zhp, "recordsize", "1M");
803                 }
804
805                 zfs_close(zhp);
806         }
807
808 out:
809         if (pool != NULL)
810                 free(pool);
811
812         if (mkfs_cmd != NULL)
813                 free(mkfs_cmd);
814
815         if (mkfs_tmp != NULL)
816                 free(mkfs_tmp);
817
818         return ret;
819 }
820
821 int zfs_enable_quota(struct mkfs_opts *mop)
822 {
823         fprintf(stderr, "this option is not only valid for zfs\n");
824         return ENOSYS;
825 }
826
827 int zfs_prepare_lustre(struct mkfs_opts *mop,
828                        char *wanted_mountopts, size_t len)
829 {
830         if (osd_check_zfs_setup() == 0)
831                 return EINVAL;
832
833         if (zfs_name_valid(mop->mo_device, ZFS_TYPE_FILESYSTEM) == 0) {
834                 fatal();
835                 fprintf(stderr, "Invalid filesystem name %s\n", mop->mo_device);
836                 return EINVAL;
837         }
838
839         if (strchr(mop->mo_device, '/') == NULL) {
840                 fatal();
841                 fprintf(stderr, "Missing pool in filesystem name %s\n",
842                         mop->mo_device);
843                 return EINVAL;
844         }
845
846         return 0;
847 }
848
849 int zfs_tune_lustre(char *dev, struct mount_opts *mop)
850 {
851         if (osd_check_zfs_setup() == 0)
852                 return EINVAL;
853
854         return 0;
855 }
856
857 int zfs_label_lustre(struct mount_opts *mop)
858 {
859         zfs_handle_t *zhp;
860         int ret;
861
862         if (osd_check_zfs_setup() == 0)
863                 return EINVAL;
864
865         zhp = zfs_open(g_zfs, mop->mo_source, ZFS_TYPE_FILESYSTEM);
866         if (zhp == NULL)
867                 return EINVAL;
868
869         ret = zfs_set_prop_str(zhp, LDD_SVNAME_PROP, mop->mo_ldd.ldd_svname);
870         zfs_close(zhp);
871
872         return ret;
873 }
874
875 int zfs_rename_fsname(struct mkfs_opts *mop, const char *oldname)
876 {
877         struct mount_opts opts;
878         char mntpt[] = "/tmp/mntXXXXXX";
879         char *cmd_buf;
880         int ret;
881
882         /* Change the filesystem label. */
883         opts.mo_ldd = mop->mo_ldd;
884         opts.mo_source = mop->mo_device;
885         ret = zfs_label_lustre(&opts);
886         if (ret) {
887                 if (errno != 0)
888                         ret = errno;
889                 fprintf(stderr, "Can't change filesystem label: %s\n",
890                         strerror(ret));
891                 return ret;
892         }
893
894         /* Mount this device temporarily in order to write these files */
895         if (mkdtemp(mntpt) == NULL) {
896                 if (errno != 0)
897                         ret = errno;
898                 fprintf(stderr, "Can't create temp mount point %s: %s\n",
899                         mntpt, strerror(ret));
900                 return ret;
901         }
902
903         cmd_buf = malloc(PATH_MAX);
904         if (!cmd_buf) {
905                 ret = ENOMEM;
906                 goto out_rmdir;
907         }
908
909         memset(cmd_buf, 0, PATH_MAX);
910         snprintf(cmd_buf, PATH_MAX - 1, "zfs set mountpoint=%s %s && "
911                  "zfs set canmount=on %s && zfs mount %s",
912                  mntpt, mop->mo_device, mop->mo_device, mop->mo_device);
913         ret = run_command(cmd_buf, PATH_MAX);
914         if (ret) {
915                 if (errno != 0)
916                         ret = errno;
917                 fprintf(stderr, "Unable to mount %s (%s)\n",
918                         mop->mo_device, strerror(ret));
919                 if (ret == ENODEV)
920                         fprintf(stderr, "Is the %s module available?\n",
921                                 MT_STR(&mop->mo_ldd));
922                 goto out_free;
923         }
924
925         ret = lustre_rename_fsname(mop, mntpt, oldname);
926         memset(cmd_buf, 0, PATH_MAX);
927         snprintf(cmd_buf, PATH_MAX - 1, "zfs umount %s && "
928                  "zfs set canmount=off %s && zfs set mountpoint=none %s",
929                  mop->mo_device, mop->mo_device, mop->mo_device);
930         run_command(cmd_buf, PATH_MAX);
931
932 out_free:
933         free(cmd_buf);
934 out_rmdir:
935         rmdir(mntpt);
936         return ret;
937 }
938
939 int zfs_init(void)
940 {
941         int ret = 0;
942
943         g_zfs = libzfs_init();
944
945         if (g_zfs == NULL) {
946                 /* Try to load zfs.ko and retry libzfs_init() */
947
948                 ret = system("/sbin/modprobe -q zfs");
949
950                 if (ret == 0) {
951                         g_zfs = libzfs_init();
952                         if (g_zfs == NULL)
953                                 ret = EINVAL;
954                 }
955         }
956
957         if (ret == 0)
958                 osd_zfs_setup = 1;
959         else
960                 fprintf(stderr, "Failed to initialize ZFS library: %d\n", ret);
961
962         return ret;
963 }
964
965 void zfs_fini(void)
966 {
967         if (g_zfs) {
968                 libzfs_fini(g_zfs);
969                 g_zfs = NULL;
970         }
971         osd_zfs_setup = 0;
972 }
973
974 #ifndef PLUGIN_DIR
975 struct module_backfs_ops zfs_ops = {
976         .init                   = zfs_init,
977         .fini                   = zfs_fini,
978         .read_ldd               = zfs_read_ldd,
979         .write_ldd              = zfs_write_ldd,
980         .erase_ldd              = zfs_erase_ldd,
981         .print_ldd_params       = zfs_print_ldd_params,
982         .is_lustre              = zfs_is_lustre,
983         .make_lustre            = zfs_make_lustre,
984         .prepare_lustre         = zfs_prepare_lustre,
985         .tune_lustre            = zfs_tune_lustre,
986         .label_lustre           = zfs_label_lustre,
987         .enable_quota           = zfs_enable_quota,
988         .rename_fsname          = zfs_rename_fsname,
989 };
990 #endif /* PLUGIN_DIR */