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