Whamcloud - gitweb
LU-13306 mgc: handle large NID formats
[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         ret = zfs_set_prop_params(zhp, ldd->ldd_params);
335
336         for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) {
337                 bridge = &special_ldd_prop_params[i];
338                 ret = bridge->zlpb_set_prop_fn(zhp, bridge->zlpb_prop_name,
339                                         (void *)ldd + bridge->zlpb_ldd_offset);
340                 if (ret)
341                         goto out_close;
342         }
343
344 out_close:
345         zfs_close(zhp);
346 out:
347         return ret;
348 }
349
350 /* Mark a property to be removed by the form of "key=" */
351 int zfs_erase_ldd(struct mkfs_opts *mop, char *param)
352 {
353         char key[ZFS_MAXPROPLEN] = "";
354
355         if (strlen(LDD_PREFIX) + strlen(param) > ZFS_MAXPROPLEN) {
356                 fprintf(stderr, "%s: zfs prop to erase is too long-\n%s\n",
357                         progname, param);
358                 return EINVAL;
359         }
360         snprintf(key, strlen(param) + 2, "%s=", param);
361         return add_param(mop->mo_ldd.ldd_params, key, "");
362 }
363
364 static int zfs_get_prop_int(zfs_handle_t *zhp, char *prop, void *val)
365 {
366         nvlist_t *propval;
367         char *propstr;
368         int ret;
369
370         ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
371         if (ret)
372                 return ret;
373
374         ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
375         if (ret)
376                 return ret;
377
378         errno = 0;
379         *(__u32 *)val = strtoul(propstr, NULL, 10);
380         if (errno)
381                 return errno;
382
383         return ret;
384 }
385
386 static int zfs_get_prop_str(zfs_handle_t *zhp, char *prop, void *val)
387 {
388         nvlist_t *propval;
389         char *propstr;
390         int ret;
391
392         ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
393         if (ret)
394                 return ret;
395
396         ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
397         if (ret)
398                 return ret;
399
400         (void) strcpy(val, propstr);
401
402         return ret;
403 }
404
405 static int zfs_get_prop_params(zfs_handle_t *zhp, char *param)
406 {
407         nvlist_t *props;
408         nvpair_t *nvp;
409         char key[ZFS_MAXPROPLEN] = "";
410         char value[PARAM_MAX] = "";
411         int ret = 0;
412
413         props = zfs_get_user_props(zhp);
414         if (props == NULL)
415                 return ENOENT;
416
417         nvp = NULL;
418         while (nvp = nvlist_next_nvpair(props, nvp), nvp) {
419                 ret = zfs_get_prop_str(zhp, nvpair_name(nvp), value);
420                 if (ret)
421                         break;
422
423                 if (strncmp(nvpair_name(nvp), LDD_PREFIX, strlen(LDD_PREFIX)))
424                         continue;
425
426                 if (zfs_is_special_ldd_prop_param(nvpair_name(nvp)))
427                         continue;
428
429                 sprintf(key, "%s=",  nvpair_name(nvp) + strlen(LDD_PREFIX));
430                 ret = add_param(param, key, value);
431                 if (ret)
432                         break;
433         }
434
435         return ret;
436 }
437
438 /*
439  * Read the server config as properties associated with the dataset.
440  * Missing entries as not treated error and are simply skipped.
441  */
442 int zfs_read_ldd(char *ds,  struct lustre_disk_data *ldd)
443 {
444         zfs_handle_t *zhp;
445         struct zfs_ldd_prop_bridge *bridge;
446         int i, ret = EINVAL;
447
448         if (osd_check_zfs_setup() == 0)
449                 return EINVAL;
450
451         zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
452         if (!zhp) {
453                 zhp = zfs_open(g_zfs, ds, ZFS_TYPE_SNAPSHOT);
454                 if (!zhp)
455                         goto out;
456         }
457
458         for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) {
459                 bridge = &special_ldd_prop_params[i];
460                 ret = bridge->zlpb_get_prop_fn(zhp, bridge->zlpb_prop_name,
461                                         (void *)ldd + bridge->zlpb_ldd_offset);
462                 if (ret && (ret != ENOENT))
463                         goto out_close;
464         }
465
466         ret = zfs_get_prop_params(zhp, ldd->ldd_params);
467         if (ret && (ret != ENOENT))
468                 goto out_close;
469
470         ldd->ldd_mount_type = LDD_MT_ZFS;
471         ret = 0;
472
473         if (strstr(ldd->ldd_params, PARAM_FAILNODE) != NULL) {
474                 zpool_handle_t *pool = zfs_get_pool_handle(zhp);
475                 uint64_t mh = zpool_get_prop_int(pool, ZPOOL_PROP_MULTIHOST,
476                                                  NULL);
477                 if (!mh)
478                         fprintf(stderr, "%s: %s is configured for failover "
479                                 "but zpool does not have multihost enabled\n",
480                                 progname, ds);
481         }
482
483 out_close:
484         zfs_close(zhp);
485
486 out:
487         return ret;
488 }
489
490 /* Print ldd params */
491 void zfs_print_ldd_params(struct mkfs_opts *mop)
492 {
493         char *from = mop->mo_ldd.ldd_params;
494         char *to;
495         int len;
496
497         vprint("Parameters:");
498         while (from) {
499                 /* skip those keys to be removed in the form of "key=" */
500                 to = strstr(from, "= ");
501                 if (!to)
502                         /* "key=" may be in the end */
503                         if (*(from + strlen(from) - 1) == '=')
504                                 to = from + strlen(from) - 1;
505
506                 /* find " " inward */
507                 len = strlen(from);
508                 if (to) {
509                         len = strlen(from) - strlen(to);
510                         while ((*(from + len) != ' ') && len)
511                                 len--;
512                 }
513                 if (len)
514                         /* no space in the end */
515                         vprint("%*.*s", len, len, from);
516
517                 /* If there is no "key=" or "key=" is in the end, stop. */
518                 if (!to || strlen(to) == 1)
519                         break;
520
521                 /* skip "=" */
522                 from = to + 1;
523         }
524 }
525
526 int zfs_is_lustre(char *ds, unsigned *mount_type)
527 {
528         struct lustre_disk_data tmp_ldd;
529         int ret;
530
531         if (osd_zfs_setup == 0)
532                 return 0;
533
534         ret = zfs_read_ldd(ds, &tmp_ldd);
535         if ((ret == 0) && (tmp_ldd.ldd_config_ver > 0) &&
536             (strlen(tmp_ldd.ldd_svname) > 0)) {
537                 *mount_type = tmp_ldd.ldd_mount_type;
538                 return 1;
539         }
540
541         return 0;
542 }
543
544 static char *zfs_mkfs_opts(struct mkfs_opts *mop, char *str, int len)
545 {
546         memset(str, 0, len);
547
548         if (strlen(mop->mo_mkfsopts) != 0)
549                 snprintf(str, len, " -o %s", mop->mo_mkfsopts);
550         if (mop->mo_device_kb)
551                 snprintf(str, len, " -o quota=%llu",
552                          (unsigned long long)mop->mo_device_kb * 1024);
553
554         return str;
555 }
556
557 static int zfs_create_vdev(struct mkfs_opts *mop, char *vdev)
558 {
559         int ret = 0;
560
561         /* Silently ignore reserved vdev names */
562         if ((strncmp(vdev, "disk", 4) == 0) ||
563             (strncmp(vdev, "file", 4) == 0) ||
564             (strncmp(vdev, "mirror", 6) == 0) ||
565             (strncmp(vdev, "raidz", 5) == 0) ||
566             (strncmp(vdev, "spare", 5) == 0) ||
567             (strncmp(vdev, "log", 3) == 0) ||
568             (strncmp(vdev, "cache", 5) == 0))
569                 return ret;
570
571         /*
572          * Verify a file exists at the provided absolute path.  If it doesn't
573          * and mo_device_kb is set attempt to create a file vdev to be used.
574          * Relative paths will be passed directly to 'zpool create' which
575          * will check multiple multiple locations under /dev/.
576          */
577         if (vdev[0] == '/') {
578                 ret = access(vdev, F_OK);
579                 if (ret == 0)
580                         return ret;
581
582                 ret = errno;
583                 if (ret != ENOENT) {
584                         fatal();
585                         fprintf(stderr, "Unable to access required vdev "
586                                 "for pool %s (%d)\n", vdev, ret);
587                         return ret;
588                 }
589
590                 if (mop->mo_device_kb == 0) {
591                         fatal();
592                         fprintf(stderr, "Unable to create vdev due to "
593                                 "missing --device-size=#N(KB) parameter\n");
594                         return EINVAL;
595                 }
596
597                 ret = file_create(vdev, mop->mo_device_kb);
598                 if (ret) {
599                         fatal();
600                         fprintf(stderr, "Unable to create vdev %s (%d)\n",
601                                 vdev, ret);
602                         return ret;
603                 }
604         }
605
606         return ret;
607 }
608
609 int zfs_make_lustre(struct mkfs_opts *mop)
610 {
611         zfs_handle_t *zhp;
612         zpool_handle_t *php;
613         char *pool = NULL;
614         char *mkfs_cmd = NULL;
615         char *mkfs_tmp = NULL;
616         char *ds = mop->mo_device;
617         int pool_exists = 0, ret;
618
619         if (osd_check_zfs_setup() == 0)
620                 return EINVAL;
621
622         /* no automatic index with zfs backend */
623         if (mop->mo_ldd.ldd_flags & LDD_F_NEED_INDEX) {
624                 fatal();
625                 fprintf(stderr, "The target index must be specified with "
626                                 "--index\n");
627                 return EINVAL;
628         }
629
630         ret = zfs_check_hostid(mop);
631         if (ret != 0)
632                 goto out;
633
634         pool = strdup(ds);
635         if (pool == NULL)
636                 return ENOMEM;
637
638         mkfs_cmd = malloc(PATH_MAX);
639         if (mkfs_cmd == NULL) {
640                 ret = ENOMEM;
641                 goto out;
642         }
643
644         mkfs_tmp = malloc(PATH_MAX);
645         if (mkfs_tmp == NULL) {
646                 ret = ENOMEM;
647                 goto out;
648         }
649
650         /* Due to zfs_prepare_lustre() check the '/' must exist */
651         strchr(pool, '/')[0] = '\0';
652
653         /* If --reformat was given attempt to destroy the previous dataset */
654         if ((mop->mo_flags & MO_FORCEFORMAT) &&
655             ((zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM)) != NULL)) {
656
657                 ret = zfs_destroy(zhp, 0);
658                 if (ret) {
659                         zfs_close(zhp);
660                         fprintf(stderr, "Failed destroy zfs dataset %s (%d)\n",
661                                 ds, ret);
662                         goto out;
663                 }
664
665                 zfs_close(zhp);
666         }
667
668         /*
669          * Create the zpool if the vdevs have been specified and the pool
670          * does not already exists.  The pool creation itself will be done
671          * with the zpool command rather than the zpool_create() library call
672          * so the existing zpool error handling can be leveraged.
673          */
674         php = zpool_open(g_zfs, pool);
675         if (php) {
676                 pool_exists = 1;
677                 zpool_set_prop(php, "canmount", "off");
678                 zpool_close(php);
679         }
680
681         if ((mop->mo_pool_vdevs != NULL) && (pool_exists == 0)) {
682
683                 memset(mkfs_cmd, 0, PATH_MAX);
684                 snprintf(mkfs_cmd, PATH_MAX,
685                         "zpool create -f -O canmount=off %s", pool);
686
687                 /* Append the vdev config and create file vdevs as required */
688                 while (*mop->mo_pool_vdevs != NULL) {
689                         strscat(mkfs_cmd, " ", PATH_MAX);
690                         strscat(mkfs_cmd, *mop->mo_pool_vdevs, PATH_MAX);
691
692                         ret = zfs_create_vdev(mop, *mop->mo_pool_vdevs);
693                         if (ret)
694                                 goto out;
695
696                         mop->mo_pool_vdevs++;
697                 }
698
699                 vprint("mkfs_cmd = %s\n", mkfs_cmd);
700                 ret = run_command(mkfs_cmd, PATH_MAX);
701                 if (ret) {
702                         fatal();
703                         fprintf(stderr, "Unable to create pool %s (%d)\n",
704                                 pool, ret);
705                         goto out;
706                 }
707         }
708
709         /*
710          * Set Options on ZPOOL
711          *
712          * ALL   - canmount=off (set above)
713          * 0.7.0 - multihost=on
714          * 0.7.0 - feature@userobj_accounting=enabled
715          */
716         php = zpool_open(g_zfs, pool);
717         if (php) {
718                 zpool_set_prop(php, "multihost", "on");
719                 zpool_set_prop(php, "feature@userobj_accounting", "enabled");
720                 zpool_close(php);
721         }
722
723         /*
724          * Create the ZFS filesystem with any required mkfs options:
725          * - canmount=off is set to prevent zfs automounting
726          */
727         memset(mkfs_cmd, 0, PATH_MAX);
728         snprintf(mkfs_cmd, PATH_MAX,
729                  "zfs create -o canmount=off %s %s",
730                  zfs_mkfs_opts(mop, mkfs_tmp, PATH_MAX), ds);
731
732         vprint("mkfs_cmd = %s\n", mkfs_cmd);
733         ret = run_command(mkfs_cmd, PATH_MAX);
734         if (ret) {
735                 fatal();
736                 fprintf(stderr, "Unable to create filesystem %s (%d)\n",
737                         ds, ret);
738                 goto out;
739         }
740
741         /*
742          * Attempt to set dataset properties to reasonable defaults
743          * to optimize performance, unless the values were specified
744          * at the mkfs command line. Some ZFS pools or ZFS versions
745          * do not support these properties. We can safely ignore the
746          * errors and continue in those cases.
747          *
748          * zfs 0.6.1 - system attribute based xattrs
749          * zfs 0.6.5 - large block support
750          * zfs 0.7.0 - large dnode support
751          *
752          * Check if zhp is NULL as a defensive measure. Any dataset
753          * validation errors that would cause zfs_open() to fail
754          * should have been caught earlier.
755          */
756         zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
757         if (zhp) {
758                 /* zfs 0.6.1 - system attribute based xattrs */
759                 if (!strstr(mop->mo_mkfsopts, "xattr="))
760                         zfs_set_prop_str(zhp, "xattr", "sa");
761
762                 /* zfs 0.7.0 - large dnode support */
763                 if (!strstr(mop->mo_mkfsopts, "dnodesize=") &&
764                     !strstr(mop->mo_mkfsopts, "dnsize="))
765                         zfs_set_prop_str(zhp, "dnodesize", "auto");
766
767                 if (IS_OST(&mop->mo_ldd)) {
768                         /* zfs 0.6.5 - large block support */
769                         if (!strstr(mop->mo_mkfsopts, "recordsize=") &&
770                             !strstr(mop->mo_mkfsopts, "recsize="))
771                                 zfs_set_prop_str(zhp, "recordsize", "1M");
772                 }
773
774                 zfs_close(zhp);
775         }
776
777 out:
778         if (pool != NULL)
779                 free(pool);
780
781         if (mkfs_cmd != NULL)
782                 free(mkfs_cmd);
783
784         if (mkfs_tmp != NULL)
785                 free(mkfs_tmp);
786
787         return ret;
788 }
789
790 int zfs_enable_quota(struct mkfs_opts *mop)
791 {
792         fprintf(stderr, "this option is not only valid for zfs\n");
793         return ENOSYS;
794 }
795
796 int zfs_prepare_lustre(struct mkfs_opts *mop,
797                        char *wanted_mountopts, size_t len)
798 {
799         if (osd_check_zfs_setup() == 0)
800                 return EINVAL;
801
802         if (zfs_name_valid(mop->mo_device, ZFS_TYPE_FILESYSTEM) == 0) {
803                 fatal();
804                 fprintf(stderr, "Invalid filesystem name %s\n", mop->mo_device);
805                 return EINVAL;
806         }
807
808         if (strchr(mop->mo_device, '/') == NULL) {
809                 fatal();
810                 fprintf(stderr, "Missing pool in filesystem name %s\n",
811                         mop->mo_device);
812                 return EINVAL;
813         }
814
815         return 0;
816 }
817
818 int zfs_tune_lustre(char *dev, struct mount_opts *mop)
819 {
820         if (osd_check_zfs_setup() == 0)
821                 return EINVAL;
822
823         return 0;
824 }
825
826 int zfs_label_lustre(struct mount_opts *mop)
827 {
828         zfs_handle_t *zhp;
829         int ret;
830
831         if (osd_check_zfs_setup() == 0)
832                 return EINVAL;
833
834         zhp = zfs_open(g_zfs, mop->mo_source, ZFS_TYPE_FILESYSTEM);
835         if (zhp == NULL)
836                 return EINVAL;
837
838         ret = zfs_set_prop_str(zhp, LDD_SVNAME_PROP, mop->mo_ldd.ldd_svname);
839         zfs_close(zhp);
840
841         return ret;
842 }
843
844 int zfs_rename_fsname(struct mkfs_opts *mop, const char *oldname)
845 {
846         struct mount_opts opts;
847         char mntpt[] = "/tmp/mntXXXXXX";
848         char *cmd_buf;
849         int ret;
850
851         /* Change the filesystem label. */
852         opts.mo_ldd = mop->mo_ldd;
853         opts.mo_source = mop->mo_device;
854         ret = zfs_label_lustre(&opts);
855         if (ret) {
856                 if (errno != 0)
857                         ret = errno;
858                 fprintf(stderr, "Can't change filesystem label: %s\n",
859                         strerror(ret));
860                 return ret;
861         }
862
863         /* Mount this device temporarily in order to write these files */
864         if (mkdtemp(mntpt) == NULL) {
865                 if (errno != 0)
866                         ret = errno;
867                 fprintf(stderr, "Can't create temp mount point %s: %s\n",
868                         mntpt, strerror(ret));
869                 return ret;
870         }
871
872         cmd_buf = malloc(PATH_MAX);
873         if (!cmd_buf) {
874                 ret = ENOMEM;
875                 goto out_rmdir;
876         }
877
878         memset(cmd_buf, 0, PATH_MAX);
879         snprintf(cmd_buf, PATH_MAX - 1, "zfs set mountpoint=%s %s && "
880                  "zfs set canmount=on %s && zfs mount %s",
881                  mntpt, mop->mo_device, mop->mo_device, mop->mo_device);
882         ret = run_command(cmd_buf, PATH_MAX);
883         if (ret) {
884                 if (errno != 0)
885                         ret = errno;
886                 fprintf(stderr, "Unable to mount %s (%s)\n",
887                         mop->mo_device, strerror(ret));
888                 if (ret == ENODEV)
889                         fprintf(stderr, "Is the %s module available?\n",
890                                 MT_STR(&mop->mo_ldd));
891                 goto out_free;
892         }
893
894         ret = lustre_rename_fsname(mop, mntpt, oldname);
895         memset(cmd_buf, 0, PATH_MAX);
896         snprintf(cmd_buf, PATH_MAX - 1, "zfs umount %s && "
897                  "zfs set canmount=off %s && zfs set mountpoint=none %s",
898                  mop->mo_device, mop->mo_device, mop->mo_device);
899         run_command(cmd_buf, PATH_MAX);
900
901 out_free:
902         free(cmd_buf);
903 out_rmdir:
904         rmdir(mntpt);
905         return ret;
906 }
907
908 int zfs_init(void)
909 {
910         int ret = 0;
911
912         g_zfs = libzfs_init();
913
914         if (g_zfs == NULL) {
915                 /* Try to load zfs.ko and retry libzfs_init() */
916
917                 ret = system("/sbin/modprobe -q zfs");
918
919                 if (ret == 0) {
920                         g_zfs = libzfs_init();
921                         if (g_zfs == NULL)
922                                 ret = EINVAL;
923                 }
924         }
925
926         if (ret == 0)
927                 osd_zfs_setup = 1;
928         else
929                 fprintf(stderr, "Failed to initialize ZFS library: %d\n", ret);
930
931         return ret;
932 }
933
934 void zfs_fini(void)
935 {
936         if (g_zfs) {
937                 libzfs_fini(g_zfs);
938                 g_zfs = NULL;
939         }
940         osd_zfs_setup = 0;
941 }
942
943 #ifndef PLUGIN_DIR
944 struct module_backfs_ops zfs_ops = {
945         .init                   = zfs_init,
946         .fini                   = zfs_fini,
947         .read_ldd               = zfs_read_ldd,
948         .write_ldd              = zfs_write_ldd,
949         .erase_ldd              = zfs_erase_ldd,
950         .print_ldd_params       = zfs_print_ldd_params,
951         .is_lustre              = zfs_is_lustre,
952         .make_lustre            = zfs_make_lustre,
953         .prepare_lustre         = zfs_prepare_lustre,
954         .tune_lustre            = zfs_tune_lustre,
955         .label_lustre           = zfs_label_lustre,
956         .enable_quota           = zfs_enable_quota,
957         .rename_fsname          = zfs_rename_fsname,
958 };
959 #endif /* PLUGIN_DIR */