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