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