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