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