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