Whamcloud - gitweb
LU-17744 ldiskfs: mballoc stats fixes
[fs/lustre-release.git] / lustre / utils / mount_utils.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, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  */
31
32 #if HAVE_CONFIG_H
33 #  include "config.h"
34 #endif /* HAVE_CONFIG_H */
35
36 #include <inttypes.h>
37 #include <limits.h>
38 #include <mntent.h>
39 #include <stdio.h>
40 #include <errno.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <config.h>
44 #include <linux/lnet/nidstr.h>
45 #include <linux/lustre/lustre_ver.h>
46 #include <sys/mount.h>
47 #include <sys/stat.h>
48 #include <sys/utsname.h>
49 #include <linux/loop.h>
50 #include <sys/types.h>
51 #include <dirent.h>
52 #include <dlfcn.h>
53 #include <linux/lustre/lustre_cfg.h>
54 #include <dirent.h>
55 #include <sys/types.h>
56 #include <sys/xattr.h>
57 #include <libmount/libmount.h>
58 #include <libcfs/util/string.h>
59
60 #ifdef HAVE_GSS
61 #ifdef HAVE_LIBKEYUTILS
62 #include <keyutils.h>
63 #endif
64 #include <lustre/utils/gss/sk_utils.h>
65 #endif
66
67 #include "mount_utils.h"
68
69 #define vprint(fmt, arg...) if (verbose > 0) printf(fmt, ##arg)
70 #define verrprint(fmt, arg...) if (verbose >= 0) fprintf(stderr, fmt, ##arg)
71
72 #ifdef HAVE_SERVER_SUPPORT
73 static struct module_backfs_ops *backfs_ops[LDD_MT_LAST];
74 #endif
75
76 void fatal(void)
77 {
78         verbose = 0;
79         fprintf(stderr, "\n%s FATAL: ", progname);
80 }
81
82 int run_command(char *cmd, int cmdsz)
83 {
84         char log[] = "/tmp/run_command_logXXXXXX";
85         int fd = -1, rc;
86
87         if ((cmdsz - strlen(cmd)) < 6) {
88                 fatal();
89                 fprintf(stderr, "Command buffer overflow: %.*s...\n",
90                         cmdsz, cmd);
91                 return ENOMEM;
92         }
93
94         if (verbose > 1) {
95                 printf("cmd: %s\n", cmd);
96         } else {
97                 if ((fd = mkstemp(log)) >= 0) {
98                         close(fd);
99                         strcat(cmd, " >");
100                         strcat(cmd, log);
101                 }
102         }
103         strcat(cmd, " 2>&1");
104
105         /* Can't use popen because we need the rv of the command */
106         rc = system(cmd);
107         if (rc && (fd >= 0)) {
108                 char buf[128];
109                 FILE *fp;
110
111                 fp = fopen(log, "r");
112                 if (fp) {
113                         while (fgets(buf, sizeof(buf), fp))
114                                 printf("   %s", buf);
115                         fclose(fp);
116                 }
117         }
118         if (fd >= 0)
119                 remove(log);
120         return rc;
121 }
122
123 #ifdef HAVE_SERVER_SUPPORT
124 int add_param(char *buf, char *key, char *val)
125 {
126         int end = sizeof(((struct lustre_disk_data *)0)->ldd_params);
127         int start = strlen(buf);
128         int keylen = 0;
129
130         if (key)
131                 keylen = strlen(key);
132         if (start + 1 + keylen + strlen(val) >= end) {
133                 fprintf(stderr, "%s: params are too long-\n%s %s%s\n",
134                         progname, buf, key ? key : "", val);
135                 return 1;
136         }
137
138         sprintf(buf + start, " %s%s", key ? key : "", val);
139         return 0;
140 }
141
142 int get_param(char *buf, char *key, char **val)
143 {
144         int i, key_len = strlen(key);
145         char *ptr;
146
147         ptr = strstr(buf, key);
148         if (ptr) {
149                 *val = strdup(ptr + key_len);
150                 if (!(*val))
151                         return ENOMEM;
152
153                 for (i = 0; i < strlen(*val); i++)
154                         if (((*val)[i] == ' ') || ((*val)[i] == '\0'))
155                                 break;
156
157                 (*val)[i] = '\0';
158                 return 0;
159         }
160
161         return ENOENT;
162 }
163
164 int append_param(char *buf, char *key, char *val, char sep)
165 {
166         int key_len, i, offset, old_val_len;
167         char *ptr = NULL, str[1024];
168
169         if (key)
170                 ptr = strstr(buf, key);
171
172         /* key doesn't exist yet, so just add it */
173         if (!ptr)
174                 return add_param(buf, key, val);
175
176         key_len = strlen(key);
177
178         /* Copy previous values to str */
179         for (i = 0; i < sizeof(str); ++i) {
180                 if ((ptr[i + key_len] == ' ') || (ptr[i + key_len] == '\0'))
181                         break;
182                 str[i] = ptr[i + key_len];
183         }
184         if (i == sizeof(str))
185                 return E2BIG;
186         old_val_len = i;
187
188         offset = old_val_len + key_len;
189
190         /* Move rest of buf to overwrite previous key and value */
191         for (i = 0; ptr[i + offset] != '\0'; ++i)
192                 ptr[i] = ptr[i + offset];
193
194         ptr[i] = '\0';
195
196         snprintf(str + old_val_len, sizeof(str) - old_val_len,
197                  "%c%s", sep, val);
198
199         return add_param(buf, key, str);
200 }
201 #endif
202
203 char *strscat(char *dst, char *src, int buflen)
204 {
205         dst[buflen - 1] = 0;
206         if (strlen(dst) + strlen(src) >= buflen) {
207                 fprintf(stderr,
208                         "string buffer overflow (max %d): '%s' + '%s'\n",
209                         buflen, dst, src);
210                 exit(EOVERFLOW);
211         }
212         return strcat(dst, src);
213 }
214
215 char *strscpy(char *dst, char *src, int buflen)
216 {
217         dst[0] = 0;
218         return strscat(dst, src, buflen);
219 }
220
221 int check_mtab_entry(char *spec1, char *spec2, char *mtpt, char *type)
222 {
223         FILE *fp;
224         struct mntent *mnt;
225
226         fp = setmntent(MOUNTED, "r");
227         if (!fp)
228                 return 0;
229
230         while ((mnt = getmntent(fp)) != NULL) {
231                 if ((strcmp(mnt->mnt_fsname, spec1) == 0 ||
232                      strcmp(mnt->mnt_fsname, spec2) == 0) &&
233                     (!mtpt || strcmp(mnt->mnt_dir, mtpt) == 0) &&
234                     (!type || strcmp(mnt->mnt_type, type) == 0)) {
235                         endmntent(fp);
236                         return EEXIST;
237                 }
238         }
239         endmntent(fp);
240
241         return 0;
242 }
243
244 #include <sys/vfs.h>
245 #include <linux/magic.h>
246
247 static int mtab_is_proc(const char *mtab)
248 {
249         struct statfs s;
250
251         if (statfs(mtab, &s) < 0)
252                 return 0;
253
254         return (s.f_type == PROC_SUPER_MAGIC);
255 }
256
257 /*
258  * The libmount is part of util-linux since 2.18.
259  * We use it to update utab to avoid umount would
260  * blocked in some rare case.
261  */
262 int update_utab_entry(struct mount_opts *mop)
263 {
264         struct libmnt_fs *fs = mnt_new_fs();
265         struct libmnt_update *upd;
266         int rc;
267
268         mnt_fs_set_source(fs, mop->mo_source);
269         mnt_fs_set_target(fs, mop->mo_target);
270         mnt_fs_set_fstype(fs, "lustre");
271         mnt_fs_set_attributes(fs, "lustre");
272
273         upd = mnt_new_update();
274         if (!upd)
275                 return -ENOMEM;
276
277         rc = mnt_update_set_fs(upd, mop->mo_nomtab ? MS_REMOUNT : 0, NULL, fs);
278         if (rc == 1) /* update is unnecessary */
279                 rc = 0;
280         if (rc) {
281                 fprintf(stderr,
282                         "error: failed to save utab entry: rc = %d\n", rc);
283         } else {
284                 rc = mnt_update_table(upd, NULL);
285         }
286
287         mnt_free_update(upd);
288         mnt_free_fs(fs);
289
290         return rc;
291 }
292
293 int update_mtab_entry(char *spec, char *mtpt, char *type, char *opts,
294                       int flags, int freq, int pass)
295 {
296         FILE *fp;
297         struct mntent mnt;
298         int rc = 0;
299
300         /* Don't update mtab if it is linked to any file in /proc direcotry.*/
301         if (mtab_is_proc(MOUNTED))
302                 return 0;
303
304         mnt.mnt_fsname = spec;
305         mnt.mnt_dir = mtpt;
306         mnt.mnt_type = type;
307         mnt.mnt_opts = opts ? opts : "";
308         mnt.mnt_freq = freq;
309         mnt.mnt_passno = pass;
310
311         fp = setmntent(MOUNTED, "a+");
312         if (!fp) {
313                 fprintf(stderr, "%s: setmntent(%s): %s\n",
314                         progname, MOUNTED, strerror(errno));
315                 rc = 16;
316         } else {
317                 if ((addmntent(fp, &mnt)) == 1) {
318                         fprintf(stderr, "%s: addmntent: %s\n",
319                                 progname, strerror(errno));
320                         rc = 16;
321                 }
322                 endmntent(fp);
323         }
324
325         return rc;
326 }
327
328 /* Search for opt in mntlist, returning true if found.
329  */
330 static int in_mntlist(char *opt, char *mntlist)
331 {
332         char *ml, *mlp, *item, *ctx = NULL;
333
334         if (!(ml = strdup(mntlist))) {
335                 fprintf(stderr, "%s: out of memory\n", progname);
336                 exit(1);
337         }
338         mlp = ml;
339         while ((item = strtok_r(mlp, ",", &ctx))) {
340                 if (!strcmp(opt, item))
341                         break;
342                 mlp = NULL;
343         }
344         free(ml);
345         return (item != NULL);
346 }
347
348 /* Issue a message on stderr for every item in wanted_mountopts that is not
349  * present in mountopts.  The justwarn boolean toggles between error and
350  * warning message.  Return an error count.
351  */
352 int check_mountfsoptions(char *mountopts, char *wanted_mountopts)
353 {
354         char *ml, *mlp, *item, *ctx = NULL;
355         int errors = 0;
356
357         if (!(ml = strdup(wanted_mountopts))) {
358                 fprintf(stderr, "%s: out of memory\n", progname);
359                 exit(1);
360         }
361         mlp = ml;
362         while ((item = strtok_r(mlp, ",", &ctx))) {
363                 if (!in_mntlist(item, mountopts)) {
364                         fprintf(stderr, "%s: Error: mandatory mount option"
365                                 " '%s' is missing\n", progname, item);
366                         errors++;
367                 }
368                 mlp = NULL;
369         }
370         free(ml);
371         return errors;
372 }
373
374 /* Trim embedded white space, leading and trailing commas from string s.
375  */
376 void trim_mountfsoptions(char *s)
377 {
378         char *p;
379
380         for (p = s; *p; ) {
381                 if (isspace(*p)) {
382                         memmove(p, p + 1, strlen(p + 1) + 1);
383                         continue;
384                 }
385                 p++;
386         }
387
388         while (s[0] == ',')
389                 memmove(&s[0], &s[1], strlen(&s[1]) + 1);
390
391         p = s + strlen(s) - 1;
392         while (p >= s && *p == ',')
393                 *p-- = '\0';
394 }
395
396 #ifdef HAVE_SERVER_SUPPORT
397 /* Setup a file in the first unused loop_device */
398 int loop_setup(struct mkfs_opts *mop)
399 {
400         char loop_base[20];
401         char l_device[64];
402         int i, ret = 0;
403
404         /* Figure out the loop device names */
405         if (!access("/dev/loop0", F_OK | R_OK) ||
406             !access("/dev/loop-control", F_OK | R_OK)) {
407                 strcpy(loop_base, "/dev/loop\0");
408         } else if (!access("/dev/loop/0", F_OK | R_OK)) {
409                 strcpy(loop_base, "/dev/loop/\0");
410         } else {
411                 fprintf(stderr, "%s: can't access loop devices\n", progname);
412                 return EACCES;
413         }
414
415         /* Find unused loop device */
416         for (i = 0; i < MAX_LOOP_DEVICES; i++) {
417                 char cmd[PATH_MAX];
418                 int cmdsz = sizeof(cmd);
419
420                 ret = open("/dev/loop-control", O_RDWR);
421                 if (ret < 0) {
422                         fprintf(stderr, "%s: can't access loop control\n",
423                                 progname);
424                         return EACCES;
425                 }
426                 /* find or allocate a free loop device to use */
427                 i = ioctl(ret, LOOP_CTL_GET_FREE);
428                 close(ret);
429                 if (i < 0) {
430                         fprintf(stderr, "%s: access loop control error\n",
431                                 progname);
432                         return EACCES;
433                 }
434                 sprintf(l_device, "%s%d", loop_base, i);
435
436                 snprintf(cmd, cmdsz, "losetup %s > /dev/null 2>&1", l_device);
437                 ret = system(cmd);
438
439                 /* losetup gets 1 (ret=256) for non-set-up device */
440                 if (ret) {
441                         /* Set up a loopback device to our file */
442                         snprintf(cmd, cmdsz, "losetup %s %s", l_device,
443                                  mop->mo_device);
444                         ret = run_command(cmd, cmdsz);
445                         if (ret == 256)
446                                 /*
447                                  * someone else picked up this loop device
448                                  * behind our back
449                                  */
450                                 continue;
451                         if (ret) {
452                                 fprintf(stderr, "%s: error %d on losetup: %s\n",
453                                         progname, ret,
454                                         ret >= 0 ? strerror(ret) : "");
455                                 return ret;
456                         }
457                         strscpy(mop->mo_loopdev, l_device,
458                                 sizeof(mop->mo_loopdev));
459                         return ret;
460                 }
461         }
462
463         fprintf(stderr, "%s: out of loop devices!\n", progname);
464         return EMFILE;
465 }
466
467 int loop_cleanup(struct mkfs_opts *mop)
468 {
469         char cmd[150];
470         int ret = 0;
471
472         if ((mop->mo_flags & MO_IS_LOOP) && *mop->mo_loopdev) {
473                 int tries;
474
475                 sprintf(cmd, "losetup -d %s", mop->mo_loopdev);
476                 for (tries = 0; tries < 3; tries++) {
477                         ret = run_command(cmd, sizeof(cmd));
478                         if (ret == 0)
479                                 break;
480                         sleep(1);
481                 }
482         }
483
484         if (ret != 0)
485                 fprintf(stderr, "cannot cleanup %s: rc = %d\n",
486                         mop->mo_loopdev, ret);
487         return ret;
488 }
489
490 int loop_format(struct mkfs_opts *mop)
491 {
492         int fd;
493
494         if (mop->mo_device_kb == 0) {
495                 fatal();
496                 fprintf(stderr,
497                         "loop device requires a --device-size= param\n");
498                 return EINVAL;
499         }
500
501         fd = creat(mop->mo_device, 0600);
502         if (fd < 0) {
503                 fatal();
504                 fprintf(stderr, "%s: Unable to create backing store: %s\n",
505                         progname, strerror(errno));
506                 return errno;
507         }
508
509         if (ftruncate(fd, mop->mo_device_kb * 1024) != 0) {
510                 close(fd);
511                 fatal();
512                 fprintf(stderr, "%s: Unable to truncate backing store: %s\n",
513                         progname, strerror(errno));
514                 return errno;
515         }
516
517         close(fd);
518         return 0;
519 }
520
521 #ifdef PLUGIN_DIR
522 #define DLSYM(prefix, sym, func)                                        \
523         do {                                                            \
524                 char _fname[PATH_MAX];                                  \
525                 snprintf(_fname, sizeof(_fname), "%s_%s", prefix, #func); \
526                 sym->func = (typeof(sym->func))dlsym(sym->dl_handle, _fname); \
527         } while (0)
528 #endif /* PLUGIN_DIR */
529
530 /**
531  * Load plugin for a given mount_type from ${pkglibdir}/mount_osd_FSTYPE.so and
532  * return struct of function pointers (will be freed in unloack_backfs_module).
533  *
534  * \param[in] mount_type        Mount type to load module for.
535  * \retval Value of backfs_ops struct
536  * \retval NULL if no module exists
537  */
538 struct module_backfs_ops *load_backfs_module(enum ldd_mount_type mount_type)
539 {
540         struct module_backfs_ops *ops;
541 #ifdef PLUGIN_DIR
542         char *error, filename[PATH_MAX], fsname[512], *name;
543         void *handle;
544
545         /*
546          * This deals with duplicate ldd_mount_types resolving to same OSD layer
547          * plugin (e.g. ext3/ldiskfs/ldiskfs2 all being ldiskfs)
548          */
549         strncpy(fsname, mt_type(mount_type), sizeof(fsname));
550         name = fsname + sizeof("osd-") - 1;
551
552         /* change osd- to osd_ */
553         fsname[sizeof("osd-") - 2] = '_';
554
555         snprintf(filename, sizeof(filename), PLUGIN_DIR"/mount_%s.so", fsname);
556
557         handle = dlopen(filename, RTLD_LAZY);
558
559         /*
560          * Check for $LUSTRE environment variable from test-framework.
561          * This allows using locally built modules to be used.
562          */
563         if (!handle) {
564                 char *dirname;
565
566                 dirname = getenv("LUSTRE");
567                 if (dirname) {
568                         snprintf(filename, sizeof(filename),
569                                  "%s/utils/mount_%s.so",
570                                  dirname, fsname);
571                         handle = dlopen(filename, RTLD_LAZY);
572                 }
573         }
574
575         /* Do not clutter up console with missing types */
576         if (!handle)
577                 return NULL;
578
579         ops = malloc(sizeof(*ops));
580         if (!ops) {
581                 dlclose(handle);
582                 return NULL;
583         }
584
585         ops->dl_handle = handle;
586         dlerror(); /* Clear any existing error */
587
588         DLSYM(name, ops, init);
589         DLSYM(name, ops, fini);
590         DLSYM(name, ops, read_ldd);
591         DLSYM(name, ops, write_ldd);
592         DLSYM(name, ops, erase_ldd);
593         DLSYM(name, ops, print_ldd_params);
594         DLSYM(name, ops, is_lustre);
595         DLSYM(name, ops, make_lustre);
596         DLSYM(name, ops, prepare_lustre);
597         DLSYM(name, ops, tune_lustre);
598         DLSYM(name, ops, label_lustre);
599         DLSYM(name, ops, rename_fsname);
600         DLSYM(name, ops, enable_quota);
601
602         error = dlerror();
603         if (error) {
604                 fatal();
605                 fprintf(stderr, "%s\n", error);
606                 dlclose(handle);
607                 free(ops);
608                 return NULL;
609         }
610
611         /* optional methods */
612         DLSYM(name, ops, fix_mountopts);
613 #else
614         switch (mount_type) {
615 #ifdef HAVE_LDISKFS_OSD
616         case LDD_MT_LDISKFS:
617                 ops = &ldiskfs_ops;
618                 break;
619 #endif /* HAVE_LDISKFS_OSD */
620 #ifdef HAVE_ZFS_OSD
621         case LDD_MT_ZFS:
622                 ops = &zfs_ops;
623                 break;
624 #endif /* HAVE_ZFS_OSD */
625         default:
626                 ops = NULL;
627                 break;
628         }
629 #endif
630         return ops;
631 }
632
633 /**
634  * Unload plugin and free backfs_ops structure. Must be called the same number
635  * of times as load_backfs_module is.
636  */
637 static void unload_backfs_module(struct module_backfs_ops *ops)
638 {
639 #ifdef PLUGIN_DIR
640         if (!ops)
641                 return;
642
643         dlclose(ops->dl_handle);
644         free(ops);
645 #endif
646 }
647
648 /* Return true if backfs_ops has operations for the given mount_type. */
649 static int backfs_mount_type_okay(enum ldd_mount_type mount_type)
650 {
651         if (mount_type >= LDD_MT_LAST || mount_type < 0) {
652                 fatal();
653                 fprintf(stderr, "fs type out of range %d\n", mount_type);
654                 return 0;
655         }
656         if (!backfs_ops[mount_type]) {
657                 fatal();
658                 fprintf(stderr, "unhandled/unloaded fs type %d '%s'\n",
659                         mount_type, mt_str(mount_type));
660                 return 0;
661         }
662         return 1;
663 }
664
665 /* Write the server config files */
666 int osd_write_ldd(struct mkfs_opts *mop)
667 {
668         struct lustre_disk_data *ldd = &mop->mo_ldd;
669         int ret;
670
671         if (backfs_mount_type_okay(ldd->ldd_mount_type))
672                 ret = backfs_ops[ldd->ldd_mount_type]->write_ldd(mop);
673         else
674                 ret = EINVAL;
675
676         return ret;
677 }
678
679 /* Read the server config files */
680 int osd_read_ldd(char *dev, struct lustre_disk_data *ldd)
681 {
682         int ret;
683
684         if (backfs_mount_type_okay(ldd->ldd_mount_type))
685                 ret = backfs_ops[ldd->ldd_mount_type]->read_ldd(dev, ldd);
686         else
687                 ret = EINVAL;
688
689         return ret;
690 }
691
692 /* Erase param from the server config files */
693 int osd_erase_ldd(struct mkfs_opts *mop, char *param)
694 {
695         struct lustre_disk_data *ldd = &mop->mo_ldd;
696         int ret;
697
698         if (backfs_mount_type_okay(ldd->ldd_mount_type))
699                 ret = backfs_ops[ldd->ldd_mount_type]->erase_ldd(mop, param);
700         else
701                 ret = EINVAL;
702
703         return ret;
704 }
705
706 /* Print ldd_params */
707 void osd_print_ldd_params(struct mkfs_opts *mop)
708 {
709         struct lustre_disk_data *ldd = &mop->mo_ldd;
710
711         if (backfs_mount_type_okay(ldd->ldd_mount_type))
712                 backfs_ops[ldd->ldd_mount_type]->print_ldd_params(mop);
713 }
714
715 /* Was this device formatted for Lustre */
716 int osd_is_lustre(char *dev, unsigned int *mount_type)
717 {
718         int i;
719
720         vprint("checking for existing Lustre data: ");
721
722         for (i = 0; i < LDD_MT_LAST; ++i) {
723                 if (backfs_ops[i] &&
724                     backfs_ops[i]->is_lustre(dev, mount_type)) {
725                         vprint("found\n");
726                         return 1;
727                 }
728         }
729
730         vprint("not found\n");
731         return 0;
732 }
733
734 /* Build fs according to type */
735 int osd_make_lustre(struct mkfs_opts *mop)
736 {
737         struct lustre_disk_data *ldd = &mop->mo_ldd;
738         int ret;
739
740         if (backfs_mount_type_okay(ldd->ldd_mount_type))
741                 ret = backfs_ops[ldd->ldd_mount_type]->make_lustre(mop);
742         else
743                 ret = EINVAL;
744
745         return ret;
746 }
747
748 int osd_prepare_lustre(struct mkfs_opts *mop,
749                        char *wanted_mountopts, size_t len)
750 {
751         struct lustre_disk_data *ldd = &mop->mo_ldd;
752         int ret;
753
754         if (backfs_mount_type_okay(ldd->ldd_mount_type))
755                 ret = backfs_ops[ldd->ldd_mount_type]->prepare_lustre(mop,
756                                                         wanted_mountopts, len);
757         else
758                 ret = EINVAL;
759
760         return ret;
761 }
762
763 int osd_fix_mountopts(struct mkfs_opts *mop, char *mountopts, size_t len)
764 {
765         struct lustre_disk_data *ldd = &mop->mo_ldd;
766
767         if (!backfs_mount_type_okay(ldd->ldd_mount_type))
768                 return EINVAL;
769
770         if (!backfs_ops[ldd->ldd_mount_type]->fix_mountopts)
771                 return 0;
772
773         return backfs_ops[ldd->ldd_mount_type]->fix_mountopts(mop, mountopts,
774                                                               len);
775 }
776
777 int osd_tune_lustre(char *dev, struct mount_opts *mop)
778 {
779         struct lustre_disk_data *ldd = &mop->mo_ldd;
780         int ret;
781
782         if (backfs_mount_type_okay(ldd->ldd_mount_type))
783                 ret = backfs_ops[ldd->ldd_mount_type]->tune_lustre(dev, mop);
784         else
785                 ret = EINVAL;
786
787         return ret;
788 }
789
790 int osd_label_lustre(struct mount_opts *mop)
791 {
792         struct lustre_disk_data *ldd = &mop->mo_ldd;
793         int ret;
794
795         if (backfs_mount_type_okay(ldd->ldd_mount_type))
796                 ret = backfs_ops[ldd->ldd_mount_type]->label_lustre(mop);
797         else
798                 ret = EINVAL;
799
800         return ret;
801 }
802
803 /* Rename filesystem fsname */
804 int osd_rename_fsname(struct mkfs_opts *mop, const char *oldname)
805 {
806         struct lustre_disk_data *ldd = &mop->mo_ldd;
807         int ret;
808
809         if (backfs_mount_type_okay(ldd->ldd_mount_type))
810                 ret = backfs_ops[ldd->ldd_mount_type]->rename_fsname(mop,
811                                                                      oldname);
812         else
813                 ret = EINVAL;
814
815         return ret;
816 }
817
818 /* Enable quota accounting */
819 int osd_enable_quota(struct mkfs_opts *mop)
820 {
821         struct lustre_disk_data *ldd = &mop->mo_ldd;
822         int ret;
823
824         if (backfs_mount_type_okay(ldd->ldd_mount_type))
825                 ret = backfs_ops[ldd->ldd_mount_type]->enable_quota(mop);
826         else
827                 ret = EINVAL;
828
829         return ret;
830 }
831
832 int osd_init(void)
833 {
834         int i, rc, ret = EINVAL;
835
836         for (i = 0; i < LDD_MT_LAST; ++i) {
837                 rc = 0;
838                 backfs_ops[i] = load_backfs_module(i);
839                 if (backfs_ops[i]) {
840                         rc = backfs_ops[i]->init();
841                         if (rc != 0) {
842                                 backfs_ops[i]->fini();
843                                 unload_backfs_module(backfs_ops[i]);
844                                 backfs_ops[i] = NULL;
845                         } else {
846                                 ret = 0;
847                         }
848                 }
849         }
850
851         return ret;
852 }
853
854 void osd_fini(void)
855 {
856         int i;
857
858         for (i = 0; i < LDD_MT_LAST; ++i) {
859                 if (backfs_ops[i]) {
860                         backfs_ops[i]->fini();
861                         unload_backfs_module(backfs_ops[i]);
862                         backfs_ops[i] = NULL;
863                 }
864         }
865 }
866
867 __u64 get_device_size(char *device)
868 {
869         int ret, fd;
870         __u64 size = 0;
871
872         fd = open(device, O_RDONLY);
873         if (fd < 0) {
874                 fprintf(stderr, "%s: cannot open %s: %s\n",
875                         progname, device, strerror(errno));
876                 return 0;
877         }
878
879 #ifdef BLKGETSIZE64
880         /* size in bytes. bz5831 */
881         ret = ioctl(fd, BLKGETSIZE64, (void *)&size);
882 #else
883         {
884                 __u32 lsize = 0;
885                 /* size in blocks */
886                 ret = ioctl(fd, BLKGETSIZE, (void *)&lsize);
887                 size = (__u64)lsize * 512;
888         }
889 #endif
890         close(fd);
891         if (ret < 0) {
892                 fprintf(stderr, "%s: size ioctl failed: %s\n",
893                         progname, strerror(errno));
894                 return 0;
895         }
896
897         vprint("device size = %juMB\n", (uintmax_t)(size >> 20));
898         /* return value in KB */
899         return size >> 10;
900 }
901 #endif
902
903 int file_create(char *path, __u64 size)
904 {
905         __u64 size_max;
906         int ret;
907         int fd;
908
909         /*
910          * Since "size" is in KB, the file offset it represents could overflow
911          * off_t.
912          */
913         size_max = (off_t)1 << (_FILE_OFFSET_BITS - 1 - 10);
914         if (size >= size_max) {
915                 fprintf(stderr,
916                         "%s: %ju KB: Backing store size must be smaller than %ju KB\n",
917                         progname, (uintmax_t)size, (uintmax_t)size_max);
918                 return EFBIG;
919         }
920
921         ret = access(path, F_OK);
922         if (ret == 0) {
923                 ret = unlink(path);
924                 if (ret != 0)
925                         return errno;
926         }
927
928         fd = creat(path, 0600);
929         if (fd < 0) {
930                 fatal();
931                 fprintf(stderr, "%s: Unable to create backing store: %s\n",
932                         progname, strerror(errno));
933                 return errno;
934         }
935
936         ret = ftruncate(fd, size * 1024);
937         close(fd);
938         if (ret != 0) {
939                 fatal();
940                 fprintf(stderr, "%s: Unable to truncate backing store: %s\n",
941                         progname, strerror(errno));
942                 return errno;
943         }
944
945         return 0;
946 }
947
948 /* Get rid of symbolic hostnames for tcp, since kernel can't do lookups */
949 #define MAXNIDSTR 1024
950
951 char *convert_hostnames(char *s1, bool mount)
952 {
953         char *converted, *s2 = 0, *c, *end, sep;
954         int left = MAXNIDSTR;
955         struct lnet_nid nid;
956
957         converted = malloc(left);
958         if (!converted) {
959                 fprintf(stderr, "%s: cannot allocate %u bytes for NID: %s\n",
960                         progname, left, strerror(ENOMEM));
961                 return NULL;
962         }
963
964         /* end is different between mount and mkfs case */
965         if (mount) {
966                 end = strchr(s1, '/');
967                 if (!end) {
968                         fprintf(stderr, "%s: Invalid mount string: %s\n",
969                                 progname, s1);
970                         goto out_bad_mnt_str;
971                 }
972                 end--;
973         } else {
974                 end = s1 + strlen(s1);
975         }
976
977         c = converted;
978         while ((left > 0) && (s1 < end)) {
979                 int rc;
980
981                 /* Needed to skip : in IPv6 / GUID strings. Lustre uses
982                  * ':' as a seperator as well which makes this complicated.
983                  */
984                 s2 = strchr(s1, '@');
985                 if (!s2 || s2 > end) {
986                         fprintf(stderr, "%s: Invalid NID string '%s'\n",
987                                 progname, s1);
988                         goto out_free;
989                 }
990
991                 s2 = strpbrk(s2, ",:");
992                 if (!s2) {
993                         s2 = end;
994                 } else if (s2 > end) {
995                         fprintf(stderr, "%s: Invalid NID string '%s'\n",
996                                 progname, s1);
997                         goto out_free;
998                 }
999                 sep = *s2;
1000                 *s2 = '\0';
1001
1002                 rc = libcfs_strnid(&nid, s1);
1003                 if (rc < 0) {
1004                         fprintf(stderr, "%s: Unsupported NID '%s': rc = %s.\n",
1005                                 progname, s1, strerror(rc));
1006                         goto out_free;
1007                 }
1008                 *s2 = sep;      /* back to original string */
1009
1010                 if (LNET_NID_IS_ANY(&nid)) {
1011                         fprintf(stderr, "%s: Cannot resolve hostname '%s'.\n",
1012                                 progname, s1);
1013                         goto out_free;
1014                 }
1015
1016                 if (sep != '\0')
1017                         c += scnprintf(c, left, "%s%c", libcfs_nidstr(&nid),
1018                                        sep);
1019                 else
1020                         c += scnprintf(c, left, "%s", libcfs_nidstr(&nid));
1021                 left = converted + MAXNIDSTR - c;
1022                 s1 = s2 + 1;
1023         }
1024
1025         if (mount)
1026                 snprintf(c, left, "%s", s1);
1027
1028         return converted;
1029 out_free:
1030         fprintf(stderr, "%s: Can't parse NID '%s'\n", progname, s1);
1031 out_bad_mnt_str:
1032         free(converted);
1033         return NULL;
1034 }
1035
1036 #ifdef HAVE_SERVER_SUPPORT
1037 struct lustre_cfg_entry {
1038         struct list_head lce_list;
1039         char             lce_name[0];
1040 };
1041
1042 static struct lustre_cfg_entry *lustre_cfg_entry_init(const char *name)
1043 {
1044         struct lustre_cfg_entry *lce;
1045         int len = strlen(name) + 1;
1046
1047         lce = malloc(sizeof(*lce) + len);
1048         if (lce) {
1049                 INIT_LIST_HEAD(&lce->lce_list);
1050                 memcpy(lce->lce_name, name, len);
1051         }
1052
1053         return lce;
1054 }
1055
1056 static void lustre_cfg_entry_fini(struct lustre_cfg_entry *lce)
1057 {
1058         free(lce);
1059 }
1060
1061 int lustre_rename_fsname(struct mkfs_opts *mop, const char *mntpt,
1062                          const char *oldname)
1063 {
1064         struct lustre_disk_data *ldd = &mop->mo_ldd;
1065         struct lr_server_data lsd;
1066         char filepnm[132];
1067         char cfg_dir[128];
1068         DIR *dir = NULL;
1069         struct dirent64 *dirent;
1070         struct lustre_cfg_entry *lce;
1071         struct list_head cfg_list;
1072         int old_namelen = strlen(oldname);
1073         int new_namelen = strlen(ldd->ldd_fsname);
1074         int ret;
1075         int fd;
1076
1077         INIT_LIST_HEAD(&cfg_list);
1078
1079         snprintf(filepnm, sizeof(filepnm), "%s/%s", mntpt, LAST_RCVD);
1080         fd = open(filepnm, O_RDWR);
1081         if (fd < 0) {
1082                 if (errno == ENOENT)
1083                         goto config;
1084
1085                 ret = errno;
1086                 fprintf(stderr, "Unable to open %s: %s\n",
1087                         filepnm, strerror(ret));
1088                 return ret;
1089         }
1090
1091         ret = read(fd, &lsd, sizeof(lsd));
1092         if (ret != sizeof(lsd)) {
1093                 if (ret < 0)
1094                         ret = errno;
1095                 else
1096                         /* short read */
1097                         ret = EINTR;
1098                 fprintf(stderr, "Unable to read %s: %s\n",
1099                         filepnm, strerror(ret));
1100                 close(fd);
1101                 return ret;
1102         }
1103
1104         ret = lseek(fd, 0, SEEK_SET);
1105         if (ret < 0) {
1106                 ret = errno;
1107                 fprintf(stderr, "Unable to lseek %s: %s\n",
1108                         filepnm, strerror(ret));
1109                 close(fd);
1110                 return ret;
1111         }
1112
1113         /* replace fsname in lr_server_data::lsd_uuid. */
1114         if (old_namelen > new_namelen)
1115                 memmove(lsd.lsd_uuid + new_namelen,
1116                         lsd.lsd_uuid + old_namelen,
1117                         sizeof(lsd.lsd_uuid) - old_namelen);
1118         else if (old_namelen < new_namelen)
1119                 memmove(lsd.lsd_uuid + new_namelen,
1120                         lsd.lsd_uuid + old_namelen,
1121                         sizeof(lsd.lsd_uuid) - new_namelen);
1122         memcpy(lsd.lsd_uuid, ldd->ldd_fsname, new_namelen);
1123         ret = write(fd, &lsd, sizeof(lsd));
1124         if (ret != sizeof(lsd)) {
1125                 if (ret < 0)
1126                         ret = errno;
1127                 else
1128                          /* short writes */
1129                         ret = EINTR;
1130                 fprintf(stderr, "Unable to write %s: %s\n",
1131                         filepnm, strerror(ret));
1132                 close(fd);
1133                 return ret;
1134         }
1135
1136         close(fd);
1137
1138 config:
1139         snprintf(cfg_dir, sizeof(cfg_dir), "%s/%s", mntpt, MOUNT_CONFIGS_DIR);
1140         dir = opendir(cfg_dir);
1141         if (!dir) {
1142                 ret = errno;
1143                 fprintf(stderr, "Unable to opendir %s: %s\n",
1144                         cfg_dir, strerror(ret));
1145                 return ret;
1146         }
1147
1148         while ((dirent = readdir64(dir)) != NULL) {
1149                 char *ptr;
1150
1151                 if (strlen(dirent->d_name) <= old_namelen)
1152                         continue;
1153
1154                 ptr = strrchr(dirent->d_name, '-');
1155                 if (!ptr || (ptr - dirent->d_name) != old_namelen)
1156                         continue;
1157
1158                 if (strncmp(dirent->d_name, oldname, old_namelen) != 0)
1159                         continue;
1160
1161                 lce = lustre_cfg_entry_init(dirent->d_name);
1162                 if (!lce) {
1163                         if (errno != 0)
1164                                 ret = errno;
1165                         else
1166                                 ret = EINVAL;
1167
1168                         fprintf(stderr, "Fail to init item for %s: %s\n",
1169                                 dirent->d_name, strerror(ret));
1170                         goto out;
1171                 }
1172
1173                 list_add(&lce->lce_list, &cfg_list);
1174         }
1175
1176         closedir(dir);
1177         dir = NULL;
1178         ret = 0;
1179
1180         while (!list_empty(&cfg_list) && ret == 0) {
1181                 lce = list_first_entry(&cfg_list, struct lustre_cfg_entry,
1182                                        lce_list);
1183                 list_del(&lce->lce_list);
1184                 snprintf(filepnm, sizeof(filepnm), "%s/%s", cfg_dir,
1185                          lce->lce_name);
1186                 if (IS_MGS(ldd))
1187                         /*
1188                          * Store the new fsname in the XATTR_TARGET_RENAME EA.
1189                          * When the MGS start, it will scan config logs, and
1190                          * for the ones which have the XATTR_TARGET_RENAME EA,
1191                          * it will replace old fsname with the new fsname in
1192                          * the config log by some shared kernel level config
1193                          * logs {fork,erase} functionalities automatically.
1194                          */
1195                         ret = setxattr(filepnm, XATTR_TARGET_RENAME,
1196                                        ldd->ldd_fsname,
1197                                        strlen(ldd->ldd_fsname), 0);
1198                 else
1199                         ret = unlink(filepnm);
1200
1201                 if (ret < 0) {
1202                         ret = errno;
1203
1204                         fprintf(stderr, "Fail to %s %s: %s\n",
1205                                 IS_MGS(ldd) ? "setxattr" : "unlink",
1206                                 filepnm, strerror(ret));
1207                 }
1208
1209                 lustre_cfg_entry_fini(lce);
1210         }
1211
1212 out:
1213         if (dir)
1214                 closedir(dir);
1215
1216         while (!list_empty(&cfg_list)) {
1217                 lce = list_first_entry(&cfg_list, struct lustre_cfg_entry,
1218                                        lce_list);
1219                 list_del(&lce->lce_list);
1220                 lustre_cfg_entry_fini(lce);
1221         }
1222
1223         return ret;
1224 }
1225 #endif /* HAVE_SERVER_SUPPORT */
1226
1227 #ifdef HAVE_GSS
1228 #ifdef HAVE_OPENSSL_SSK
1229 int load_shared_keys(struct mount_opts *mop)
1230 {
1231         DIR *dir;
1232         struct dirent *dentry;
1233         struct stat sbuf;
1234         char fullpath[PATH_MAX];
1235         char *path = mop->mo_skpath;
1236         int rc;
1237
1238         /* init logging */
1239         sk_init_logging(NULL, 1, 1);
1240
1241         rc = stat(path, &sbuf);
1242         if (rc < 0) {
1243                 fprintf(stderr, "stat() failed for key %s: %s\n", path,
1244                         strerror(errno));
1245                 return -errno;
1246         }
1247
1248         /* Load individual keys or a directory of them */
1249         if (S_ISREG(sbuf.st_mode)) {
1250                 return sk_load_keyfile(path);
1251         } else if (!S_ISDIR(sbuf.st_mode)) {
1252                 fprintf(stderr, "Invalid shared key path: %s\n", path);
1253                 return -ENOKEY;
1254         }
1255
1256         dir = opendir(path);
1257         if (!dir) {
1258                 fprintf(stderr, "Unable to open shared key directory: %s\n",
1259                         path);
1260                 return -ENOENT;
1261         }
1262
1263         /*
1264          * Loop through the files in the directory attempting to load them.
1265          * Any issue with loading the keyfile is treated as an error although
1266          * the loop continues until all files have been attempted.  This will
1267          * allow all errors be reported at once rather then requiring
1268          * incremental corrections to fix each one and try again.
1269          */
1270         while ((dentry = readdir(dir)) != NULL) {
1271                 if (strcmp(".", dentry->d_name) == 0 ||
1272                     strcmp("..", dentry->d_name) == 0)
1273                         continue;
1274
1275                 rc = snprintf(fullpath, PATH_MAX, "%s/%s", path,
1276                               dentry->d_name);
1277                 if (rc >= PATH_MAX) {
1278                         fprintf(stderr, "Path too long for %s/%s\n",
1279                                 path, dentry->d_name);
1280                         rc = -ENAMETOOLONG;
1281                         continue;
1282                 }
1283
1284                 rc = stat(fullpath, &sbuf);
1285                 if (rc < 0) {
1286                         fprintf(stderr, "Unable to stat %s: %s\n", fullpath,
1287                                 strerror(errno));
1288                         rc = -errno;
1289                         continue;
1290                 }
1291
1292                 if (!S_ISREG(sbuf.st_mode))
1293                         continue;
1294
1295                 rc = sk_load_keyfile(fullpath);
1296                 if (rc)
1297                         fprintf(stderr, "Failed to load key %s\n", fullpath);
1298         }
1299         closedir(dir);
1300
1301         return rc;
1302 }
1303 #endif /* HAVE_OPENSSL_SSK */
1304 #endif /* HAVE_GSS */