Whamcloud - gitweb
LU-7134 utils: Ensure hostid set for ZFS during mkfs
[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, 2014, 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 /* Persistent mount data is stored in these user attributes */
36 #define LDD_PREFIX              "lustre:"
37 #define LDD_VERSION_PROP        LDD_PREFIX "version"
38 #define LDD_FLAGS_PROP          LDD_PREFIX "flags"
39 #define LDD_INDEX_PROP          LDD_PREFIX "index"
40 #define LDD_FSNAME_PROP         LDD_PREFIX "fsname"
41 #define LDD_SVNAME_PROP         LDD_PREFIX "svname"
42 #define LDD_UUID_PROP           LDD_PREFIX "uuid"
43 #define LDD_USERDATA_PROP       LDD_PREFIX "userdata"
44 #define LDD_MOUNTOPTS_PROP      LDD_PREFIX "mountopts"
45
46 /* This structure is used to help bridge the gap between the ZFS
47  * properties Lustre uses and their corresponding internal LDD fields.
48  * It is meant to be used internally by the mount utility only. */
49 struct zfs_ldd_prop_bridge {
50         /* Contains the publicly visible name for the property
51          * (i.e. what is shown when running "zfs get") */
52         char *zlpb_prop_name;
53         /* Contains the offset into the lustre_disk_data structure where
54          * the value of this property is or will be stored. (i.e. the
55          * property is read from and written to this offset within ldd) */
56         int   zlpb_ldd_offset;
57         /* Function pointer responsible for reading in the @prop
58          * property from @zhp and storing it in @ldd_field */
59         int (*zlpb_get_prop_fn)(zfs_handle_t *zhp, char *prop, void *ldd_field);
60         /* Function pointer responsible for writing the value of @ldd_field
61          * into the @prop dataset property in @zhp */
62         int (*zlpb_set_prop_fn)(zfs_handle_t *zhp, char *prop, void *ldd_field);
63 };
64
65 /* Forward declarations needed to initialize the ldd prop bridge list */
66 static int zfs_get_prop_int(zfs_handle_t *, char *, void *);
67 static int zfs_set_prop_int(zfs_handle_t *, char *, void *);
68 static int zfs_get_prop_str(zfs_handle_t *, char *, void *);
69 static int zfs_set_prop_str(zfs_handle_t *, char *, void *);
70
71 /* Helper for initializing the entries in the special_ldd_prop_params list.
72  *    - @name: stored directly in the zlpb_prop_name field
73  *             (e.g. lustre:fsname, lustre:version, etc.)
74  *    - @field: the field in the lustre_disk_data which directly maps to
75  *              the @name property. (e.g. ldd_fsname, ldd_config_ver, etc.)
76  *    - @type: The type of @field. Only "int" and "str" are supported.
77  */
78 #define ZLB_INIT(name, field, type)                     \
79 {                                                       \
80         name, offsetof(struct lustre_disk_data, field), \
81         zfs_get_prop_ ## type, zfs_set_prop_ ## type    \
82 }
83
84 /* These ldd properties are special because they all have their own
85  * individual fields in the lustre_disk_data structure, as opposed to
86  * being globbed into the ldd_params field. As such, these need special
87  * handling when reading/writing the ldd structure to/from persistent
88  * storage. */
89 struct zfs_ldd_prop_bridge special_ldd_prop_params[] = {
90         ZLB_INIT(LDD_VERSION_PROP,   ldd_config_ver, int),
91         ZLB_INIT(LDD_FLAGS_PROP,     ldd_flags,      int),
92         ZLB_INIT(LDD_INDEX_PROP,     ldd_svindex,    int),
93         ZLB_INIT(LDD_FSNAME_PROP,    ldd_fsname,     str),
94         ZLB_INIT(LDD_SVNAME_PROP,    ldd_svname,     str),
95         ZLB_INIT(LDD_UUID_PROP,      ldd_uuid,       str),
96         ZLB_INIT(LDD_USERDATA_PROP,  ldd_userdata,   str),
97         ZLB_INIT(LDD_MOUNTOPTS_PROP, ldd_mount_opts, str),
98         { NULL }
99 };
100
101 /* indicate if the ZFS OSD has been successfully setup */
102 static int osd_zfs_setup = 0;
103
104 static libzfs_handle_t *g_zfs;
105
106 void zfs_fini(void);
107
108 static int zfs_set_prop_int(zfs_handle_t *zhp, char *prop, void *val)
109 {
110         char str[64];
111         int ret;
112
113         (void) snprintf(str, sizeof (str), "%i", *(int *)val);
114         vprint("  %s=%s\n", prop, str);
115         ret = zfs_prop_set(zhp, prop, str);
116
117         return ret;
118 }
119
120 /*
121  * Write the zfs property string, note that properties with a NULL or
122  * zero-length value will not be written and 0 returned.
123  */
124 static int zfs_set_prop_str(zfs_handle_t *zhp, char *prop, void *val)
125 {
126         int ret = 0;
127
128         if (val && strlen(val) > 0) {
129                 vprint("  %s=%s\n", prop, (char *)val);
130                 ret = zfs_prop_set(zhp, prop, (char *)val);
131         }
132
133         return ret;
134 }
135
136 /*
137  * Map '<key>=<value> ...' pairs in the passed string to dataset properties
138  * of the form 'lustre:<key>=<value>'.  Malformed <key>=<value> pairs will
139  * be skipped.
140  */
141 static int zfs_set_prop_params(zfs_handle_t *zhp, char *params)
142 {
143         char *params_dup, *token, *key, *value;
144         char *save_token = NULL;
145         char prop_name[ZFS_MAXNAMELEN];
146         int ret = 0;
147
148         params_dup = strdup(params);
149         if (params_dup == NULL)
150                 return ENOMEM;
151
152         token = strtok_r(params_dup, " ", &save_token);
153         while (token) {
154                 key = strtok(token, "=");
155                 if (key == NULL)
156                         continue;
157
158                 value = strtok(NULL, "=");
159                 if (value == NULL)
160                         continue;
161
162                 sprintf(prop_name, "%s%s", LDD_PREFIX, key);
163                 vprint("  %s=%s\n", prop_name, value);
164
165                 ret = zfs_prop_set(zhp, prop_name, value);
166                 if (ret)
167                         break;
168
169                 token = strtok_r(NULL, " ", &save_token);
170         }
171
172         free(params_dup);
173
174         return ret;
175 }
176
177 static int zfs_check_hostid(struct mkfs_opts *mop)
178 {
179         FILE *f;
180         unsigned long hostid;
181         int rc;
182
183         if (strstr(mop->mo_ldd.ldd_params, PARAM_FAILNODE) == NULL)
184                 return 0;
185
186         f = fopen("/sys/module/spl/parameters/spl_hostid", "r");
187         if (f == NULL) {
188                 fatal();
189                 fprintf(stderr, "Failed to open spl_hostid: %s\n",
190                         strerror(errno));
191                 return errno;
192         }
193         rc = fscanf(f, "%li", &hostid);
194         fclose(f);
195         if (rc != 1) {
196                 fatal();
197                 fprintf(stderr, "Failed to read spl_hostid: %d\n", rc);
198                 return rc;
199         }
200
201         if (hostid == 0) {
202                 if (mop->mo_flags & MO_NOHOSTID_CHECK) {
203                         fprintf(stderr, "WARNING: spl_hostid not set. ZFS has "
204                                 "no zpool import protection\n");
205                 } else {
206                         fatal();
207                         fprintf(stderr, "spl_hostid not set. See %s(8)",
208                                 progname);
209                         return EINVAL;
210                 }
211         }
212
213         return 0;
214 }
215
216 static int osd_check_zfs_setup(void)
217 {
218         if (osd_zfs_setup == 0) {
219                 /* setup failed */
220                 fatal();
221                 fprintf(stderr, "Failed to initialize ZFS library. Are the ZFS "
222                         "packages and modules correctly installed?\n");
223         }
224         return osd_zfs_setup == 1;
225 }
226
227 /* Write the server config as properties associated with the dataset */
228 int zfs_write_ldd(struct mkfs_opts *mop)
229 {
230         struct lustre_disk_data *ldd = &mop->mo_ldd;
231         char *ds = mop->mo_device;
232         zfs_handle_t *zhp;
233         struct zfs_ldd_prop_bridge *bridge;
234         int i, ret = EINVAL;
235
236         if (osd_check_zfs_setup() == 0)
237                 goto out;
238
239         zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
240         if (zhp == NULL) {
241                 fprintf(stderr, "Failed to open zfs dataset %s\n", ds);
242                 goto out;
243         }
244
245         ret = zfs_check_hostid(mop);
246         if (ret != 0)
247                 goto out;
248
249         vprint("Writing %s properties\n", ds);
250
251         for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) {
252                 bridge = &special_ldd_prop_params[i];
253                 ret = bridge->zlpb_set_prop_fn(zhp, bridge->zlpb_prop_name,
254                                         (void *)ldd + bridge->zlpb_ldd_offset);
255                 if (ret)
256                         goto out_close;
257         }
258
259         ret = zfs_set_prop_params(zhp, ldd->ldd_params);
260
261 out_close:
262         zfs_close(zhp);
263 out:
264         return ret;
265 }
266
267 static int zfs_get_prop_int(zfs_handle_t *zhp, char *prop, void *val)
268 {
269         nvlist_t *propval;
270         char *propstr;
271         int ret;
272
273         ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
274         if (ret)
275                 return ret;
276
277         ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
278         if (ret)
279                 return ret;
280
281         errno = 0;
282         *(__u32 *)val = strtoul(propstr, NULL, 10);
283         if (errno)
284                 return errno;
285
286         return ret;
287 }
288
289 static int zfs_get_prop_str(zfs_handle_t *zhp, char *prop, void *val)
290 {
291         nvlist_t *propval;
292         char *propstr;
293         int ret;
294
295         ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
296         if (ret)
297                 return ret;
298
299         ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
300         if (ret)
301                 return ret;
302
303         (void) strcpy(val, propstr);
304
305         return ret;
306 }
307
308 static int zfs_is_special_ldd_prop_param(char *name)
309 {
310         int i;
311
312         for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++)
313                 if (!strcmp(name, special_ldd_prop_params[i].zlpb_prop_name))
314                         return 1;
315
316         return 0;
317 }
318
319 static int zfs_get_prop_params(zfs_handle_t *zhp, char *param, int len)
320 {
321         nvlist_t *props;
322         nvpair_t *nvp;
323         char key[ZFS_MAXNAMELEN];
324         char *value;
325         int ret = 0;
326
327         props = zfs_get_user_props(zhp);
328         if (props == NULL)
329                 return ENOENT;
330
331         value = malloc(len);
332         if (value == NULL)
333                 return ENOMEM;
334
335         nvp = NULL;
336         while (nvp = nvlist_next_nvpair(props, nvp), nvp) {
337                 ret = zfs_get_prop_str(zhp, nvpair_name(nvp), value);
338                 if (ret)
339                         break;
340
341                 if (strncmp(nvpair_name(nvp), LDD_PREFIX, strlen(LDD_PREFIX)))
342                         continue;
343
344                 if (zfs_is_special_ldd_prop_param(nvpair_name(nvp)))
345                         continue;
346
347                 sprintf(key, "%s=",  nvpair_name(nvp) + strlen(LDD_PREFIX));
348
349                 ret = add_param(param, key, value);
350                 if (ret)
351                         break;
352         }
353
354         free(value);
355
356         return ret;
357 }
358
359 /*
360  * Read the server config as properties associated with the dataset.
361  * Missing entries as not treated error and are simply skipped.
362  */
363 int zfs_read_ldd(char *ds,  struct lustre_disk_data *ldd)
364 {
365         zfs_handle_t *zhp;
366         struct zfs_ldd_prop_bridge *bridge;
367         int i, ret = EINVAL;
368
369         if (osd_check_zfs_setup() == 0)
370                 return EINVAL;
371
372         zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
373         if (zhp == NULL)
374                 goto out;
375
376         for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) {
377                 bridge = &special_ldd_prop_params[i];
378                 ret = bridge->zlpb_get_prop_fn(zhp, bridge->zlpb_prop_name,
379                                         (void *)ldd + bridge->zlpb_ldd_offset);
380                 if (ret && (ret != ENOENT))
381                         goto out_close;
382         }
383
384         ret = zfs_get_prop_params(zhp, ldd->ldd_params, 4096);
385         if (ret && (ret != ENOENT))
386                 goto out_close;
387
388         ldd->ldd_mount_type = LDD_MT_ZFS;
389         ret = 0;
390 out_close:
391         zfs_close(zhp);
392 out:
393         return ret;
394 }
395
396 int zfs_is_lustre(char *ds, unsigned *mount_type)
397 {
398         struct lustre_disk_data tmp_ldd;
399         int ret;
400
401         if (osd_zfs_setup == 0)
402                 return 0;
403
404         ret = zfs_read_ldd(ds, &tmp_ldd);
405         if ((ret == 0) && (tmp_ldd.ldd_config_ver > 0) &&
406             (strlen(tmp_ldd.ldd_svname) > 0)) {
407                 *mount_type = tmp_ldd.ldd_mount_type;
408                 return 1;
409         }
410
411         return 0;
412 }
413
414 static char *zfs_mkfs_opts(struct mkfs_opts *mop, char *str, int len)
415 {
416         memset(str, 0, len);
417
418         if (strlen(mop->mo_mkfsopts) != 0)
419                 snprintf(str, len, " -o %s", mop->mo_mkfsopts);
420
421         return str;
422 }
423
424 static int zfs_create_vdev(struct mkfs_opts *mop, char *vdev)
425 {
426         int ret = 0;
427
428         /* Silently ignore reserved vdev names */
429         if ((strncmp(vdev, "disk", 4) == 0) ||
430             (strncmp(vdev, "file", 4) == 0) ||
431             (strncmp(vdev, "mirror", 6) == 0) ||
432             (strncmp(vdev, "raidz", 5) == 0) ||
433             (strncmp(vdev, "spare", 5) == 0) ||
434             (strncmp(vdev, "log", 3) == 0) ||
435             (strncmp(vdev, "cache", 5) == 0))
436                 return ret;
437
438         /*
439          * Verify a file exists at the provided absolute path.  If it doesn't
440          * and mo_device_kb is set attempt to create a file vdev to be used.
441          * Relative paths will be passed directly to 'zpool create' which
442          * will check multiple multiple locations under /dev/.
443          */
444         if (vdev[0] == '/') {
445                 ret = access(vdev, F_OK);
446                 if (ret == 0)
447                         return ret;
448
449                 ret = errno;
450                 if (ret != ENOENT) {
451                         fatal();
452                         fprintf(stderr, "Unable to access required vdev "
453                                 "for pool %s (%d)\n", vdev, ret);
454                         return ret;
455                 }
456
457                 if (mop->mo_device_kb == 0) {
458                         fatal();
459                         fprintf(stderr, "Unable to create vdev due to "
460                                 "missing --device-size=#N(KB) parameter\n");
461                         return EINVAL;
462                 }
463
464                 ret = file_create(vdev, mop->mo_device_kb);
465                 if (ret) {
466                         fatal();
467                         fprintf(stderr, "Unable to create vdev %s (%d)\n",
468                                 vdev, ret);
469                         return ret;
470                 }
471         }
472
473         return ret;
474 }
475
476 int zfs_make_lustre(struct mkfs_opts *mop)
477 {
478         zfs_handle_t *zhp;
479         zpool_handle_t *php;
480         char *pool = NULL;
481         char *mkfs_cmd = NULL;
482         char *mkfs_tmp = NULL;
483         char *ds = mop->mo_device;
484         int pool_exists = 0, ret;
485
486         if (osd_check_zfs_setup() == 0)
487                 return EINVAL;
488
489         /* no automatic index with zfs backend */
490         if (mop->mo_ldd.ldd_flags & LDD_F_NEED_INDEX) {
491                 fatal();
492                 fprintf(stderr, "The target index must be specified with "
493                                 "--index\n");
494                 return EINVAL;
495         }
496
497         ret = zfs_check_hostid(mop);
498         if (ret != 0)
499                 goto out;
500
501         pool = strdup(ds);
502         if (pool == NULL)
503                 return ENOMEM;
504
505         mkfs_cmd = malloc(PATH_MAX);
506         if (mkfs_cmd == NULL) {
507                 ret = ENOMEM;
508                 goto out;
509         }
510
511         mkfs_tmp = malloc(PATH_MAX);
512         if (mkfs_tmp == NULL) {
513                 ret = ENOMEM;
514                 goto out;
515         }
516
517         /* Due to zfs_prepare_lustre() check the '/' must exist */
518         strchr(pool, '/')[0] = '\0';
519
520         /* If --reformat was given attempt to destroy the previous dataset */
521         if ((mop->mo_flags & MO_FORCEFORMAT) &&
522             ((zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM)) != NULL)) {
523
524                 ret = zfs_destroy(zhp, 0);
525                 if (ret) {
526                         zfs_close(zhp);
527                         fprintf(stderr, "Failed destroy zfs dataset %s (%d)\n",
528                                 ds, ret);
529                         goto out;
530                 }
531
532                 zfs_close(zhp);
533         }
534
535         /*
536          * Create the zpool if the vdevs have been specified and the pool
537          * does not already exists.  The pool creation itself will be done
538          * with the zpool command rather than the zpool_create() library call
539          * so the existing zpool error handling can be leveraged.
540          */
541         php = zpool_open(g_zfs, pool);
542         if (php) {
543                 pool_exists = 1;
544                 zpool_close(php);
545         }
546
547         if ((mop->mo_pool_vdevs != NULL) && (pool_exists == 0)) {
548
549                 memset(mkfs_cmd, 0, PATH_MAX);
550                 snprintf(mkfs_cmd, PATH_MAX,
551                         "zpool create -f -O canmount=off %s", pool);
552
553                 /* Append the vdev config and create file vdevs as required */
554                 while (*mop->mo_pool_vdevs != NULL) {
555                         strscat(mkfs_cmd, " ", PATH_MAX);
556                         strscat(mkfs_cmd, *mop->mo_pool_vdevs, PATH_MAX);
557
558                         ret = zfs_create_vdev(mop, *mop->mo_pool_vdevs);
559                         if (ret)
560                                 goto out;
561
562                         mop->mo_pool_vdevs++;
563                 }
564
565                 vprint("mkfs_cmd = %s\n", mkfs_cmd);
566                 ret = run_command(mkfs_cmd, PATH_MAX);
567                 if (ret) {
568                         fatal();
569                         fprintf(stderr, "Unable to create pool %s (%d)\n",
570                                 pool, ret);
571                         goto out;
572                 }
573         }
574
575         /*
576          * Create the ZFS filesystem with any required mkfs options:
577          * - canmount=off is set to prevent zfs automounting
578          * - xattr=sa is set to use system attribute based xattrs
579          */
580         memset(mkfs_cmd, 0, PATH_MAX);
581         snprintf(mkfs_cmd, PATH_MAX,
582                  "zfs create -o canmount=off -o xattr=sa%s %s",
583                  zfs_mkfs_opts(mop, mkfs_tmp, PATH_MAX), ds);
584
585         vprint("mkfs_cmd = %s\n", mkfs_cmd);
586         ret = run_command(mkfs_cmd, PATH_MAX);
587         if (ret) {
588                 fatal();
589                 fprintf(stderr, "Unable to create filesystem %s (%d)\n",
590                         ds, ret);
591                 goto out;
592         }
593
594 out:
595         if (pool != NULL)
596                 free(pool);
597
598         if (mkfs_cmd != NULL)
599                 free(mkfs_cmd);
600
601         if (mkfs_tmp != NULL)
602                 free(mkfs_tmp);
603
604         return ret;
605 }
606
607 int zfs_enable_quota(struct mkfs_opts *mop)
608 {
609         fprintf(stderr, "this option is not only valid for zfs\n");
610         return ENOSYS;
611 }
612
613 int zfs_prepare_lustre(struct mkfs_opts *mop,
614                        char *wanted_mountopts, size_t len)
615 {
616         if (osd_check_zfs_setup() == 0)
617                 return EINVAL;
618
619         if (zfs_name_valid(mop->mo_device, ZFS_TYPE_FILESYSTEM) == 0) {
620                 fatal();
621                 fprintf(stderr, "Invalid filesystem name %s\n", mop->mo_device);
622                 return EINVAL;
623         }
624
625         if (strchr(mop->mo_device, '/') == NULL) {
626                 fatal();
627                 fprintf(stderr, "Missing pool in filesystem name %s\n",
628                         mop->mo_device);
629                 return EINVAL;
630         }
631
632         return 0;
633 }
634
635 int zfs_tune_lustre(char *dev, struct mount_opts *mop)
636 {
637         if (osd_check_zfs_setup() == 0)
638                 return EINVAL;
639
640         return 0;
641 }
642
643 int zfs_label_lustre(struct mount_opts *mop)
644 {
645         zfs_handle_t *zhp;
646         int ret;
647
648         if (osd_check_zfs_setup() == 0)
649                 return EINVAL;
650
651         zhp = zfs_open(g_zfs, mop->mo_source, ZFS_TYPE_FILESYSTEM);
652         if (zhp == NULL)
653                 return EINVAL;
654
655         ret = zfs_set_prop_str(zhp, LDD_SVNAME_PROP, mop->mo_ldd.ldd_svname);
656         zfs_close(zhp);
657
658         return ret;
659 }
660
661 int zfs_init(void)
662 {
663         int ret = 0;
664
665         g_zfs = libzfs_init();
666         if (g_zfs == NULL) {
667                 fprintf(stderr, "Failed to initialize ZFS library\n");
668                 ret = EINVAL;
669         } else {
670                 osd_zfs_setup = 1;
671         }
672
673         return ret;
674 }
675
676 void zfs_fini(void)
677 {
678         if (g_zfs) {
679                 libzfs_fini(g_zfs);
680                 g_zfs = NULL;
681         }
682         osd_zfs_setup = 0;
683 }