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