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