Whamcloud - gitweb
0a0280a8a647d809907df2c78e2d980e989998e3
[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, 2013, Intel Corporation.
24  * Use is subject to license terms.
25  *
26  */
27 /*
28  * Author: Brian Behlendorf <behlendorf1@llnl.gov>
29  */
30 #include "mount_utils.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 osd_check_zfs_setup(void)
178 {
179         if (osd_zfs_setup == 0) {
180                 /* setup failed */
181                 fatal();
182                 fprintf(stderr, "Failed to initialize ZFS library. Are the ZFS "
183                         "packages and modules correctly installed?\n");
184         }
185         return osd_zfs_setup == 1;
186 }
187
188 /* Write the server config as properties associated with the dataset */
189 int zfs_write_ldd(struct mkfs_opts *mop)
190 {
191         struct lustre_disk_data *ldd = &mop->mo_ldd;
192         char *ds = mop->mo_device;
193         zfs_handle_t *zhp;
194         struct zfs_ldd_prop_bridge *bridge;
195         int i, ret = EINVAL;
196
197         if (osd_check_zfs_setup() == 0)
198                 return EINVAL;
199
200         zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
201         if (zhp == NULL) {
202                 fprintf(stderr, "Failed to open zfs dataset %s\n", ds);
203                 goto out;
204         }
205
206         vprint("Writing %s properties\n", ds);
207
208         for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) {
209                 bridge = &special_ldd_prop_params[i];
210                 ret = bridge->zlpb_set_prop_fn(zhp, bridge->zlpb_prop_name,
211                                         (void *)ldd + bridge->zlpb_ldd_offset);
212                 if (ret)
213                         goto out_close;
214         }
215
216         ret = zfs_set_prop_params(zhp, ldd->ldd_params);
217
218 out_close:
219         zfs_close(zhp);
220 out:
221         return ret;
222 }
223
224 static int zfs_get_prop_int(zfs_handle_t *zhp, char *prop, void *val)
225 {
226         nvlist_t *propval;
227         char *propstr;
228         int ret;
229
230         ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
231         if (ret)
232                 return ret;
233
234         ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
235         if (ret)
236                 return ret;
237
238         errno = 0;
239         *(__u32 *)val = strtoul(propstr, NULL, 10);
240         if (errno)
241                 return errno;
242
243         return ret;
244 }
245
246 static int zfs_get_prop_str(zfs_handle_t *zhp, char *prop, void *val)
247 {
248         nvlist_t *propval;
249         char *propstr;
250         int ret;
251
252         ret = nvlist_lookup_nvlist(zfs_get_user_props(zhp), prop, &propval);
253         if (ret)
254                 return ret;
255
256         ret = nvlist_lookup_string(propval, ZPROP_VALUE, &propstr);
257         if (ret)
258                 return ret;
259
260         (void) strcpy(val, propstr);
261
262         return ret;
263 }
264
265 static int zfs_is_special_ldd_prop_param(char *name)
266 {
267         int i;
268
269         for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++)
270                 if (!strcmp(name, special_ldd_prop_params[i].zlpb_prop_name))
271                         return 1;
272
273         return 0;
274 }
275
276 static int zfs_get_prop_params(zfs_handle_t *zhp, char *param, int len)
277 {
278         nvlist_t *props;
279         nvpair_t *nvp;
280         char key[ZFS_MAXNAMELEN];
281         char *value;
282         int ret = 0;
283
284         props = zfs_get_user_props(zhp);
285         if (props == NULL)
286                 return ENOENT;
287
288         value = malloc(len);
289         if (value == NULL)
290                 return ENOMEM;
291
292         nvp = NULL;
293         while (nvp = nvlist_next_nvpair(props, nvp), nvp) {
294                 ret = zfs_get_prop_str(zhp, nvpair_name(nvp), value);
295                 if (ret)
296                         break;
297
298                 if (strncmp(nvpair_name(nvp), LDD_PREFIX, strlen(LDD_PREFIX)))
299                         continue;
300
301                 if (zfs_is_special_ldd_prop_param(nvpair_name(nvp)))
302                         continue;
303
304                 sprintf(key, "%s=",  nvpair_name(nvp) + strlen(LDD_PREFIX));
305
306                 ret = add_param(param, key, value);
307                 if (ret)
308                         break;
309         }
310
311         free(value);
312
313         return ret;
314 }
315
316 /*
317  * Read the server config as properties associated with the dataset.
318  * Missing entries as not treated error and are simply skipped.
319  */
320 int zfs_read_ldd(char *ds,  struct lustre_disk_data *ldd)
321 {
322         zfs_handle_t *zhp;
323         struct zfs_ldd_prop_bridge *bridge;
324         int i, ret = EINVAL;
325
326         if (osd_check_zfs_setup() == 0)
327                 return EINVAL;
328
329         zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM);
330         if (zhp == NULL)
331                 goto out;
332
333         for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) {
334                 bridge = &special_ldd_prop_params[i];
335                 ret = bridge->zlpb_get_prop_fn(zhp, bridge->zlpb_prop_name,
336                                         (void *)ldd + bridge->zlpb_ldd_offset);
337                 if (ret && (ret != ENOENT))
338                         goto out_close;
339         }
340
341         ret = zfs_get_prop_params(zhp, ldd->ldd_params, 4096);
342         if (ret && (ret != ENOENT))
343                 goto out_close;
344
345         ldd->ldd_mount_type = LDD_MT_ZFS;
346         ret = 0;
347 out_close:
348         zfs_close(zhp);
349 out:
350         return ret;
351 }
352
353 int zfs_is_lustre(char *ds, unsigned *mount_type)
354 {
355         struct lustre_disk_data tmp_ldd;
356         int ret;
357
358         if (osd_zfs_setup == 0)
359                 return 0;
360
361         ret = zfs_read_ldd(ds, &tmp_ldd);
362         if ((ret == 0) && (tmp_ldd.ldd_config_ver > 0) &&
363             (strlen(tmp_ldd.ldd_svname) > 0)) {
364                 *mount_type = tmp_ldd.ldd_mount_type;
365                 return 1;
366         }
367
368         return 0;
369 }
370
371 static char *zfs_mkfs_opts(struct mkfs_opts *mop, char *str, int len)
372 {
373         memset(str, 0, len);
374
375         if (strlen(mop->mo_mkfsopts) != 0)
376                 snprintf(str, len, " -o %s", mop->mo_mkfsopts);
377
378         return str;
379 }
380
381 static int zfs_create_vdev(struct mkfs_opts *mop, char *vdev)
382 {
383         int ret = 0;
384
385         /* Silently ignore reserved vdev names */
386         if ((strncmp(vdev, "disk", 4) == 0) ||
387             (strncmp(vdev, "file", 4) == 0) ||
388             (strncmp(vdev, "mirror", 6) == 0) ||
389             (strncmp(vdev, "raidz", 5) == 0) ||
390             (strncmp(vdev, "spare", 5) == 0) ||
391             (strncmp(vdev, "log", 3) == 0) ||
392             (strncmp(vdev, "cache", 5) == 0))
393                 return ret;
394
395         /*
396          * Verify a file exists at the provided absolute path.  If it doesn't
397          * and mo_device_kb is set attempt to create a file vdev to be used.
398          * Relative paths will be passed directly to 'zpool create' which
399          * will check multiple multiple locations under /dev/.
400          */
401         if (vdev[0] == '/') {
402                 ret = access(vdev, F_OK);
403                 if (ret == 0)
404                         return ret;
405
406                 ret = errno;
407                 if (ret != ENOENT) {
408                         fatal();
409                         fprintf(stderr, "Unable to access required vdev "
410                                 "for pool %s (%d)\n", vdev, ret);
411                         return ret;
412                 }
413
414                 if (mop->mo_device_kb == 0) {
415                         fatal();
416                         fprintf(stderr, "Unable to create vdev due to "
417                                 "missing --device-size=#N(KB) parameter\n");
418                         return EINVAL;
419                 }
420
421                 ret = file_create(vdev, mop->mo_device_kb);
422                 if (ret) {
423                         fatal();
424                         fprintf(stderr, "Unable to create vdev %s (%d)\n",
425                                 vdev, ret);
426                         return ret;
427                 }
428         }
429
430         return ret;
431 }
432
433 int zfs_make_lustre(struct mkfs_opts *mop)
434 {
435         zfs_handle_t *zhp;
436         zpool_handle_t *php;
437         char *pool = NULL;
438         char *mkfs_cmd = NULL;
439         char *mkfs_tmp = NULL;
440         char *ds = mop->mo_device;
441         int pool_exists = 0, ret;
442
443         if (osd_check_zfs_setup() == 0)
444                 return EINVAL;
445
446         /* no automatic index with zfs backend */
447         if (mop->mo_ldd.ldd_flags & LDD_F_NEED_INDEX) {
448                 fatal();
449                 fprintf(stderr, "The target index must be specified with "
450                                 "--index\n");
451                 return EINVAL;
452         }
453
454         pool = strdup(ds);
455         if (pool == NULL)
456                 return ENOMEM;
457
458         mkfs_cmd = malloc(PATH_MAX);
459         if (mkfs_cmd == NULL) {
460                 ret = ENOMEM;
461                 goto out;
462         }
463
464         mkfs_tmp = malloc(PATH_MAX);
465         if (mkfs_tmp == NULL) {
466                 ret = ENOMEM;
467                 goto out;
468         }
469
470         /* Due to zfs_prepare_lustre() check the '/' must exist */
471         strchr(pool, '/')[0] = '\0';
472
473         /* If --reformat was given attempt to destroy the previous dataset */
474         if ((mop->mo_flags & MO_FORCEFORMAT) &&
475             ((zhp = zfs_open(g_zfs, ds, ZFS_TYPE_FILESYSTEM)) != NULL)) {
476
477                 ret = zfs_destroy(zhp, 0);
478                 if (ret) {
479                         zfs_close(zhp);
480                         fprintf(stderr, "Failed destroy zfs dataset %s (%d)\n",
481                                 ds, ret);
482                         goto out;
483                 }
484
485                 zfs_close(zhp);
486         }
487
488         /*
489          * Create the zpool if the vdevs have been specified and the pool
490          * does not already exists.  The pool creation itself will be done
491          * with the zpool command rather than the zpool_create() library call
492          * so the existing zpool error handling can be leveraged.
493          */
494         php = zpool_open(g_zfs, pool);
495         if (php) {
496                 pool_exists = 1;
497                 zpool_close(php);
498         }
499
500         if ((mop->mo_pool_vdevs != NULL) && (pool_exists == 0)) {
501
502                 memset(mkfs_cmd, 0, PATH_MAX);
503                 snprintf(mkfs_cmd, PATH_MAX,
504                         "zpool create -f -O canmount=off %s", pool);
505
506                 /* Append the vdev config and create file vdevs as required */
507                 while (*mop->mo_pool_vdevs != NULL) {
508                         strscat(mkfs_cmd, " ", PATH_MAX);
509                         strscat(mkfs_cmd, *mop->mo_pool_vdevs, PATH_MAX);
510
511                         ret = zfs_create_vdev(mop, *mop->mo_pool_vdevs);
512                         if (ret)
513                                 goto out;
514
515                         mop->mo_pool_vdevs++;
516                 }
517
518                 vprint("mkfs_cmd = %s\n", mkfs_cmd);
519                 ret = run_command(mkfs_cmd, PATH_MAX);
520                 if (ret) {
521                         fatal();
522                         fprintf(stderr, "Unable to create pool %s (%d)\n",
523                                 pool, ret);
524                         goto out;
525                 }
526         }
527
528         /*
529          * Create the ZFS filesystem with any required mkfs options:
530          * - canmount=off is set to prevent zfs automounting
531          * - version=4 is set because SA are not yet handled by the osd
532          */
533         memset(mkfs_cmd, 0, PATH_MAX);
534         snprintf(mkfs_cmd, PATH_MAX,
535                  "zfs create -o canmount=off -o xattr=sa%s %s",
536                  zfs_mkfs_opts(mop, mkfs_tmp, PATH_MAX),
537                  ds);
538
539         vprint("mkfs_cmd = %s\n", mkfs_cmd);
540         ret = run_command(mkfs_cmd, PATH_MAX);
541         if (ret) {
542                 fatal();
543                 fprintf(stderr, "Unable to create filesystem %s (%d)\n",
544                         ds, ret);
545                 goto out;
546         }
547
548 out:
549         if (pool != NULL)
550                 free(pool);
551
552         if (mkfs_cmd != NULL)
553                 free(mkfs_cmd);
554
555         if (mkfs_tmp != NULL)
556                 free(mkfs_tmp);
557
558         return ret;
559 }
560
561 int zfs_enable_quota(struct mkfs_opts *mop)
562 {
563         fprintf(stderr, "this option is not only valid for zfs\n");
564         return ENOSYS;
565 }
566
567 int zfs_prepare_lustre(struct mkfs_opts *mop,
568                 char *default_mountopts, int default_len,
569                 char *always_mountopts, int always_len)
570 {
571         if (osd_check_zfs_setup() == 0)
572                 return EINVAL;
573
574         if (zfs_name_valid(mop->mo_device, ZFS_TYPE_FILESYSTEM) == 0) {
575                 fatal();
576                 fprintf(stderr, "Invalid filesystem name %s\n", mop->mo_device);
577                 return EINVAL;
578         }
579
580         if (strchr(mop->mo_device, '/') == NULL) {
581                 fatal();
582                 fprintf(stderr, "Missing pool in filesystem name %s\n",
583                         mop->mo_device);
584                 return EINVAL;
585         }
586
587         return 0;
588 }
589
590 int zfs_tune_lustre(char *dev, struct mount_opts *mop)
591 {
592         if (osd_check_zfs_setup() == 0)
593                 return EINVAL;
594
595         return 0;
596 }
597
598 int zfs_label_lustre(struct mount_opts *mop)
599 {
600         zfs_handle_t *zhp;
601         int ret;
602
603         if (osd_check_zfs_setup() == 0)
604                 return EINVAL;
605
606         zhp = zfs_open(g_zfs, mop->mo_source, ZFS_TYPE_FILESYSTEM);
607         if (zhp == NULL)
608                 return EINVAL;
609
610         ret = zfs_set_prop_str(zhp, LDD_SVNAME_PROP, mop->mo_ldd.ldd_svname);
611         zfs_close(zhp);
612
613         return ret;
614 }
615
616 int zfs_init(void)
617 {
618         int ret = 0;
619
620         /* If the ZFS libs are not installed, don't print an error to avoid
621          * spamming ldiskfs users. An error message will still be printed if
622          * someone tries to do some real work involving a ZFS backend */
623
624         if (libzfs_load_module("zfs") != 0) {
625                 /* The ZFS modules are not installed */
626                 ret = EINVAL;
627                 goto out;
628         }
629
630         g_zfs = libzfs_init();
631         if (g_zfs == NULL) {
632                 fprintf(stderr, "Failed to initialize ZFS library\n");
633                 ret = EINVAL;
634         }
635 out:
636         osd_zfs_setup = 1;
637         if (ret)
638                 zfs_fini();
639         return ret;
640 }
641
642 void zfs_fini(void)
643 {
644         if (g_zfs) {
645                 libzfs_fini(g_zfs);
646                 g_zfs = NULL;
647         }
648         osd_zfs_setup = 0;
649 }