Whamcloud - gitweb
LU-8275 tests: add flag to enable secret shared key for tests
[fs/lustre-release.git] / lustre / utils / libmount_utils_ldiskfs.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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2016, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lustre/utils/mount_utils_ldiskfs.c
33  *
34  * Author: Nathan Rutman <nathan@clusterfs.com>
35 */
36
37 /* This source file is compiled into both mkfs.lustre and tunefs.lustre */
38
39 #if HAVE_CONFIG_H
40 #  include "config.h"
41 #endif /* HAVE_CONFIG_H */
42
43 #ifndef _GNU_SOURCE
44 #define _GNU_SOURCE
45 #endif
46 #include <stdarg.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <inttypes.h>
51 #include <unistd.h>
52 #include <fcntl.h>
53 #include <mntent.h>
54 #include <glob.h>
55
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <sys/mount.h>
59 #include <sys/utsname.h>
60
61 #include <string.h>
62 #include <getopt.h>
63 #include <limits.h>
64 #include <ctype.h>
65
66 #ifndef BLKGETSIZE64
67 #include <linux/fs.h> /* for BLKGETSIZE64 */
68 #endif
69 #include <linux/types.h>
70 #include <linux/version.h>
71 #include <lnet/lnetctl.h>
72 #include <lustre_ver.h>
73
74 #ifdef HAVE_SELINUX
75 #include <selinux/selinux.h>
76 #endif
77
78 #include "mount_utils.h"
79
80 #define MAX_HW_SECTORS_KB_PATH  "queue/max_hw_sectors_kb"
81 #define MAX_SECTORS_KB_PATH     "queue/max_sectors_kb"
82 #define SCHEDULER_PATH          "queue/scheduler"
83 #define STRIPE_CACHE_SIZE       "md/stripe_cache_size"
84
85 #define DEFAULT_SCHEDULER       "deadline"
86
87 extern char *progname;
88
89 #define L_BLOCK_SIZE 4096
90 /* keep it less than LL_FID_NAMELEN */
91 #define DUMMY_FILE_NAME_LEN             25
92 #define EXT3_DIRENT_SIZE                DUMMY_FILE_NAME_LEN
93
94 static void append_unique(char *buf, char *prefix, char *key, char *val,
95                           size_t maxbuflen);
96 static int is_e2fsprogs_feature_supp(const char *feature);
97 static void disp_old_e2fsprogs_msg(const char *feature, int make_backfs);
98
99 /*
100  * Concatenate context of the temporary mount point if selinux is enabled
101  */
102 #ifdef HAVE_SELINUX
103 static void append_context_for_mount(char *mntpt, struct mkfs_opts *mop)
104 {
105         security_context_t fcontext;
106
107         if (getfilecon(mntpt, &fcontext) < 0) {
108                 /* Continuing with default behaviour */
109                 fprintf(stderr, "%s: Get file context failed : %s\n",
110                         progname, strerror(errno));
111                 return;
112         }
113
114         if (fcontext != NULL) {
115                 append_unique(mop->mo_ldd.ldd_mount_opts,
116                               ",", "context", fcontext,
117                               sizeof(mop->mo_ldd.ldd_mount_opts));
118                 freecon(fcontext);
119         }
120 }
121 #endif
122
123 /* return canonicalized absolute pathname, even if the target file does not
124  * exist, unlike realpath */
125 static char *absolute_path(char *devname)
126 {
127         char  buf[PATH_MAX + 1] = "";
128         char *path;
129         char *ptr;
130         int len;
131
132         path = malloc(sizeof(buf));
133         if (path == NULL)
134                 return NULL;
135
136         if (devname[0] != '/') {
137                 if (getcwd(buf, sizeof(buf) - 1) == NULL) {
138                         free(path);
139                         return NULL;
140                 }
141                 len = snprintf(path, sizeof(buf), "%s/%s", buf, devname);
142                 if (len >= sizeof(buf)) {
143                         free(path);
144                         return NULL;
145                 }
146         } else {
147                 len = snprintf(path, sizeof(buf), "%s", devname);
148                 if (len >= sizeof(buf)) {
149                         free(path);
150                         return NULL;
151                 }
152         }
153
154         /* truncate filename before calling realpath */
155         ptr = strrchr(path, '/');
156         if (ptr == NULL) {
157                 free(path);
158                 return NULL;
159         }
160         *ptr = '\0';
161         if (buf != realpath(path, buf)) {
162                 free(path);
163                 return NULL;
164         }
165         /* add the filename back */
166         len = snprintf(path, PATH_MAX, "%s/%s", buf, ptr+1);
167         if (len >= PATH_MAX) {
168                 free(path);
169                 return NULL;
170         }
171         return path;
172 }
173
174 /* Determine if a device is a block device (as opposed to a file) */
175 static int is_block(char *devname)
176 {
177         struct stat st;
178         int     ret = 0;
179         char    *devpath;
180
181         devpath = absolute_path(devname);
182         if (devpath == NULL) {
183                 fprintf(stderr, "%s: failed to resolve path to %s\n",
184                         progname, devname);
185                 return -1;
186         }
187
188         ret = access(devname, F_OK);
189         if (ret != 0) {
190                 if (strncmp(devpath, "/dev/", 5) == 0) {
191                         /* nobody sane wants to create a loopback file under
192                          * /dev. Let's just report the device doesn't exist */
193                         fprintf(stderr, "%s: %s apparently does not exist\n",
194                                 progname, devpath);
195                         ret = -1;
196                         goto out;
197                 }
198                 ret = 0;
199                 goto out;
200         }
201         ret = stat(devpath, &st);
202         if (ret != 0) {
203                 fprintf(stderr, "%s: cannot stat %s\n", progname, devpath);
204                 goto out;
205         }
206         ret = S_ISBLK(st.st_mode);
207 out:
208         free(devpath);
209         return ret;
210 }
211
212 static int is_feature_enabled(const char *feature, const char *devpath)
213 {
214         char cmd[PATH_MAX];
215         FILE *fp;
216         char enabled_features[4096] = "";
217         int ret = 1;
218
219         snprintf(cmd, sizeof(cmd), "%s -c -R features %s 2>&1",
220                  DEBUGFS, devpath);
221
222         /* Using popen() instead of run_command() since debugfs does
223          * not return proper error code if command is not supported */
224         fp = popen(cmd, "r");
225         if (!fp) {
226                 fprintf(stderr, "%s: %s\n", progname, strerror(errno));
227                 return 0;
228         }
229
230         ret = fread(enabled_features, 1, sizeof(enabled_features) - 1, fp);
231         enabled_features[ret] = '\0';
232         pclose(fp);
233
234         if (strstr(enabled_features, feature))
235                 return 1;
236         return 0;
237 }
238
239 /* Write the server config files */
240 int ldiskfs_write_ldd(struct mkfs_opts *mop)
241 {
242         char mntpt[] = "/tmp/mntXXXXXX";
243         char filepnm[128];
244         char *dev;
245         FILE *filep;
246         int ret = 0;
247         size_t num;
248
249         /* Mount this device temporarily in order to write these files */
250         if (!mkdtemp(mntpt)) {
251                 fprintf(stderr, "%s: Can't create temp mount point %s: %s\n",
252                         progname, mntpt, strerror(errno));
253                 return errno;
254         }
255
256         /*
257          * Append file context to mount options if SE Linux is enabled
258          */
259         #ifdef HAVE_SELINUX
260         if (is_selinux_enabled() > 0)
261                 append_context_for_mount(mntpt, mop);
262         #endif
263
264         dev = mop->mo_device;
265         if (mop->mo_flags & MO_IS_LOOP)
266                 dev = mop->mo_loopdev;
267
268         /* Multiple mount protection enabled if failover node specified */
269         if (mop->mo_flags & MO_FAILOVER &&
270             !is_feature_enabled("mmp", dev)) {
271                 if (is_e2fsprogs_feature_supp("-O mmp") == 0) {
272                         char *command = filepnm;
273
274                         snprintf(command, sizeof(filepnm),
275                                  TUNE2FS" -O mmp '%s' >/dev/null 2>&1", dev);
276                         ret = run_command(command, sizeof(filepnm));
277                         if (ret)
278                                 fprintf(stderr,
279                                         "%s: Unable to set 'mmp' on %s: %d\n",
280                                         progname, dev, ret);
281                 } else
282                         disp_old_e2fsprogs_msg("mmp", 1);
283         }
284
285         ret = mount(dev, mntpt, MT_STR(&mop->mo_ldd), 0,
286                 (mop->mo_mountopts == NULL) ?
287                 "errors=remount-ro" : mop->mo_mountopts);
288         if (ret) {
289                 fprintf(stderr, "%s: Unable to mount %s: %s\n",
290                         progname, dev, strerror(errno));
291                 ret = errno;
292                 if (errno == ENODEV) {
293                         fprintf(stderr, "Is the %s module available?\n",
294                                 MT_STR(&mop->mo_ldd));
295                 }
296                 goto out_rmdir;
297         }
298
299         /* Set up initial directories */
300         sprintf(filepnm, "%s/%s", mntpt, MOUNT_CONFIGS_DIR);
301         ret = mkdir(filepnm, 0777);
302         if ((ret != 0) && (errno != EEXIST)) {
303                 fprintf(stderr, "%s: Can't make configs dir %s (%s)\n",
304                         progname, filepnm, strerror(errno));
305                 goto out_umnt;
306         } else if (errno == EEXIST) {
307                 ret = 0;
308         }
309
310         /* Save the persistent mount data into a file. Lustre must pre-read
311            this file to get the real mount options. */
312         vprint("Writing %s\n", MOUNT_DATA_FILE);
313         sprintf(filepnm, "%s/%s", mntpt, MOUNT_DATA_FILE);
314         filep = fopen(filepnm, "w");
315         if (!filep) {
316                 fprintf(stderr, "%s: Unable to create %s file: %s\n",
317                         progname, filepnm, strerror(errno));
318                 goto out_umnt;
319         }
320         num = fwrite(&mop->mo_ldd, sizeof(mop->mo_ldd), 1, filep);
321         if (num < 1 && ferror(filep)) {
322                 fprintf(stderr, "%s: Unable to write to file (%s): %s\n",
323                         progname, filepnm, strerror(errno));
324                 fclose(filep);
325                 goto out_umnt;
326         }
327         fsync(filep->_fileno);
328         fclose(filep);
329
330 out_umnt:
331         umount(mntpt);
332 out_rmdir:
333         rmdir(mntpt);
334         return ret;
335 }
336
337 static int readcmd(char *cmd, char *buf, int len)
338 {
339         FILE *fp;
340         int red;
341
342         fp = popen(cmd, "r");
343         if (!fp)
344                 return errno;
345
346         red = fread(buf, 1, len, fp);
347         pclose(fp);
348
349         /* strip trailing newline */
350         if (buf[red - 1] == '\n')
351                 buf[red - 1] = '\0';
352
353         return (red == 0) ? -ENOENT : 0;
354 }
355
356 int ldiskfs_read_ldd(char *dev, struct lustre_disk_data *mo_ldd)
357 {
358         char tmpdir[] = "/tmp/dirXXXXXX";
359         char cmd[PATH_MAX];
360         char filepnm[128];
361         FILE *filep;
362         int ret = 0;
363         int cmdsz = sizeof(cmd);
364
365         /* Make a temporary directory to hold Lustre data files. */
366         if (!mkdtemp(tmpdir)) {
367                 fprintf(stderr, "%s: Can't create temporary directory %s: %s\n",
368                         progname, tmpdir, strerror(errno));
369                 return errno;
370         }
371
372         /* TODO: it's worth observing the get_mountdata() function that is
373            in mount_utils.c for getting the mountdata out of the
374            filesystem */
375
376         /* Construct debugfs command line. */
377         snprintf(cmd, cmdsz, "%s -c -R 'dump /%s %s/mountdata' '%s'",
378                  DEBUGFS, MOUNT_DATA_FILE, tmpdir, dev);
379
380         ret = run_command(cmd, cmdsz);
381         if (ret)
382                 verrprint("%s: Unable to dump %s dir (%d)\n",
383                           progname, MOUNT_CONFIGS_DIR, ret);
384
385         sprintf(filepnm, "%s/mountdata", tmpdir);
386         filep = fopen(filepnm, "r");
387         if (filep) {
388                 size_t num_read;
389                 vprint("Reading %s\n", MOUNT_DATA_FILE);
390                 num_read = fread(mo_ldd, sizeof(*mo_ldd), 1, filep);
391                 if (num_read < 1 && ferror(filep)) {
392                         fprintf(stderr, "%s: Unable to read from file %s: %s\n",
393                                 progname, filepnm, strerror(errno));
394                 }
395                 fclose(filep);
396         }
397
398         snprintf(cmd, cmdsz, "rm -rf %s", tmpdir);
399         run_command(cmd, cmdsz);
400         if (ret)
401                 verrprint("Failed to read old data (%d)\n", ret);
402
403         /* As long as we at least have the label, we're good to go */
404         snprintf(cmd, sizeof(cmd), E2LABEL" %s", dev);
405         ret = readcmd(cmd, mo_ldd->ldd_svname, sizeof(mo_ldd->ldd_svname) - 1);
406
407         return ret;
408 }
409
410 int ldiskfs_erase_ldd(struct mkfs_opts *mop, char *param)
411 {
412         return 0;
413 }
414
415 void ldiskfs_print_ldd_params(struct mkfs_opts *mop)
416 {
417         printf("Parameters:%s\n", mop->mo_ldd.ldd_params);
418 }
419
420 /* Display the need for the latest e2fsprogs to be installed. make_backfs
421  * indicates if the caller is make_lustre_backfs() or not. */
422 static void disp_old_e2fsprogs_msg(const char *feature, int make_backfs)
423 {
424         static int msg_displayed;
425
426         if (msg_displayed) {
427                 fprintf(stderr, "WARNING: %s does not support %s "
428                         "feature.\n\n", E2FSPROGS, feature);
429                 return;
430         }
431
432         msg_displayed++;
433
434         fprintf(stderr, "WARNING: The %s package currently installed on "
435                 "your system does not support \"%s\" feature.\n",
436                 E2FSPROGS, feature);
437 #if !(HAVE_LDISKFSPROGS)
438         fprintf(stderr, "Please install the latest version of e2fsprogs from\n"
439                 "https://downloads.hpdd.intel.com/public/e2fsprogs/latest/\n"
440                 "to enable this feature.\n");
441 #endif
442         if (make_backfs)
443                 fprintf(stderr, "Feature will not be enabled until %s"
444                         "is updated and '%s -O %s %%{device}' "
445                         "is run.\n\n", E2FSPROGS, TUNE2FS, feature);
446 }
447
448 /* Check whether the file exists in the device */
449 static int file_in_dev(char *file_name, char *dev_name)
450 {
451         FILE *fp;
452         char debugfs_cmd[256];
453         unsigned int inode_num;
454         int i;
455
456         /* Construct debugfs command line. */
457         snprintf(debugfs_cmd, sizeof(debugfs_cmd),
458                  "%s -c -R 'stat %s' '%s' 2>&1 | egrep '(Inode|unsupported)'",
459                  DEBUGFS, file_name, dev_name);
460
461         fp = popen(debugfs_cmd, "r");
462         if (!fp) {
463                 fprintf(stderr, "%s: %s\n", progname, strerror(errno));
464                 return 0;
465         }
466
467         if (fscanf(fp, "Inode: %u", &inode_num) == 1) { /* exist */
468                 pclose(fp);
469                 return 1;
470         }
471         i = fread(debugfs_cmd, 1, sizeof(debugfs_cmd) - 1, fp);
472         if (i) {
473                 debugfs_cmd[i] = 0;
474                 fprintf(stderr, "%s", debugfs_cmd);
475                 if (strstr(debugfs_cmd, "unsupported feature")) {
476                         disp_old_e2fsprogs_msg("an unknown", 0);
477                 }
478                 pclose(fp);
479                 return -1;
480         }
481         pclose(fp);
482         return 0;
483 }
484
485 /* Check whether the device has already been used with lustre */
486 int ldiskfs_is_lustre(char *dev, unsigned *mount_type)
487 {
488         int ret;
489
490         ret = file_in_dev(MOUNT_DATA_FILE, dev);
491         if (ret) {
492                 /* in the -1 case, 'extents' means IS a lustre target */
493                 *mount_type = LDD_MT_LDISKFS;
494                 return 1;
495         }
496
497         ret = file_in_dev(LAST_RCVD, dev);
498         if (ret) {
499                 *mount_type = LDD_MT_LDISKFS;
500                 return 1;
501         }
502
503         return 0;
504 }
505
506 /* Check if a certain feature is supported by e2fsprogs.
507  * Firstly we try to use "debugfs supported_features" command to check if
508  * the feature is supported. If this fails we try to set this feature with
509  * mke2fs to check for its support. */
510 static int is_e2fsprogs_feature_supp(const char *feature)
511 {
512         static char supp_features[4096] = "";
513         FILE *fp;
514         char cmd[PATH_MAX];
515         char imgname[] = "/tmp/test-img-XXXXXX";
516         int fd = -1;
517         int ret = 1;
518
519         if (supp_features[0] == '\0') {
520                 snprintf(cmd, sizeof(cmd), "%s -c -R supported_features 2>&1",
521                          DEBUGFS);
522
523                 /* Using popen() instead of run_command() since debugfs does
524                  * not return proper error code if command is not supported */
525                 fp = popen(cmd, "r");
526                 if (!fp) {
527                         fprintf(stderr, "%s: %s\n", progname, strerror(errno));
528                         return 0;
529                 }
530                 ret = fread(supp_features, 1, sizeof(supp_features) - 1, fp);
531                 supp_features[ret] = '\0';
532                 pclose(fp);
533         }
534         if (ret > 0 && strstr(supp_features,
535                               strncmp(feature, "-O ", 3) ? feature : feature+3))
536                 return 0;
537
538         if ((fd = mkstemp(imgname)) < 0)
539                 return -1;
540         else
541                 close(fd);
542
543         snprintf(cmd, sizeof(cmd), "%s -F %s %s 100 >/dev/null 2>&1",
544                  MKE2FS, feature, imgname);
545         /* run_command() displays the output of mke2fs when it fails for
546          * some feature, so use system() directly */
547         ret = system(cmd);
548         unlink(imgname);
549
550         return ret;
551 }
552
553
554 /**
555  * append_unique: append @key or @key=@val pair to @buf only if @key does not
556  *                exists
557  *      @buf: buffer to hold @key or @key=@val
558  *      @prefix: prefix string before @key
559  *      @key: key string
560  *      @val: value string if it's a @key=@val pair
561  */
562 static void append_unique(char *buf, char *prefix, char *key, char *val,
563                           size_t maxbuflen)
564 {
565         char *anchor, *end;
566         int  len;
567
568         if (key == NULL)
569                 return;
570
571         anchor = end = strstr(buf, key);
572         /* try to find exact match string in @buf */
573         while (end && *end != '\0' && *end != ',' && *end != ' ' && *end != '=')
574                 ++end;
575         len = end - anchor;
576         if (anchor == NULL || strlen(key) != len ||
577                         strncmp(anchor, key, len) != 0) {
578                 if (prefix != NULL)
579                         strscat(buf, prefix, maxbuflen);
580
581                 strscat(buf, key, maxbuflen);
582                 if (val != NULL) {
583                         strscat(buf, "=\"", maxbuflen);
584                         strscat(buf, val, maxbuflen);
585                         strscat(buf, "\"", maxbuflen);
586                 }
587         }
588 }
589
590 static int enable_default_ext4_features(struct mkfs_opts *mop, char *anchor,
591                                         size_t maxbuflen, int user_spec)
592 {
593         if (IS_OST(&mop->mo_ldd)) {
594                 append_unique(anchor, user_spec ? "," : " -O ",
595                               "extents", NULL, maxbuflen);
596                 append_unique(anchor, ",", "uninit_bg", NULL, maxbuflen);
597         } else if (IS_MDT(&mop->mo_ldd)) {
598                 append_unique(anchor, user_spec ? "," : " -O ",
599                               "dirdata", NULL, maxbuflen);
600                 append_unique(anchor, ",", "uninit_bg", NULL, maxbuflen);
601                 append_unique(anchor, ",", "^extents", NULL, maxbuflen);
602         } else {
603                 append_unique(anchor, user_spec ? "," : " -O ",
604                               "uninit_bg", NULL, maxbuflen);
605         }
606
607         /* Multiple mount protection enabled only if failover node specified */
608         if (mop->mo_flags & MO_FAILOVER) {
609                 if (is_e2fsprogs_feature_supp("-O mmp") == 0)
610                         append_unique(anchor, ",", "mmp", NULL, maxbuflen);
611                 else
612                         disp_old_e2fsprogs_msg("mmp", 1);
613         }
614
615         /* Allow more than 65000 subdirectories */
616         if (is_e2fsprogs_feature_supp("-O dir_nlink") == 0)
617                 append_unique(anchor, ",", "dir_nlink", NULL, maxbuflen);
618
619         /* The following options are only valid for ext4-based ldiskfs.
620          * If --backfstype=ext3 is specified, do not enable them. */
621         if (mop->mo_ldd.ldd_mount_type == LDD_MT_EXT3)
622                 return 0;
623
624         /* Enable quota by default */
625         if (is_e2fsprogs_feature_supp("-O quota") == 0) {
626                 append_unique(anchor, ",", "quota", NULL, maxbuflen);
627         } else {
628                 fatal();
629                 fprintf(stderr, "\"-O quota\" must be supported by "
630                         "e2fsprogs, please upgrade your e2fsprogs.\n");
631                 return EINVAL;
632         }
633
634         /* Allow files larger than 2TB.  Also needs LU-16, but not harmful. */
635         if (is_e2fsprogs_feature_supp("-O huge_file") == 0)
636                 append_unique(anchor, ",", "huge_file", NULL, maxbuflen);
637
638         /* Enable large block addresses if the LUN is over 2^32 blocks. */
639         if (mop->mo_device_kb / (L_BLOCK_SIZE >> 10) >= 0x100002000ULL &&
640             is_e2fsprogs_feature_supp("-O 64bit") == 0)
641                 append_unique(anchor, ",", "64bit", NULL, maxbuflen);
642
643         /* Cluster inode/block bitmaps and inode table for more efficient IO.
644          * Align the flex groups on a 1MB boundary for better performance. */
645         /* This -O feature needs to go last, since it adds the "-G" option. */
646         if (is_e2fsprogs_feature_supp("-O flex_bg") == 0) {
647                 char tmp_buf[64];
648
649                 append_unique(anchor, ",", "flex_bg", NULL, maxbuflen);
650
651                 if (IS_OST(&mop->mo_ldd) &&
652                     strstr(mop->mo_mkfsopts, "-G") == NULL) {
653                         snprintf(tmp_buf, sizeof(tmp_buf), " -G %u",
654                                  (1 << 20) / L_BLOCK_SIZE);
655                         strscat(anchor, tmp_buf, maxbuflen);
656                 }
657         }
658         /* Don't add any more "-O" options here, see last comment above */
659         return 0;
660 }
661
662 /**
663  * moveopts_to_end: find the option string, move remaining strings to
664  *                  where option string starts, and append the option
665  *                  string at the end
666  *      @start: where the option string starts before the move
667  *      RETURN: where the option string starts after the move
668  */
669 static char *moveopts_to_end(char *start)
670 {
671         size_t len;
672         char save[512];
673         char *end, *idx;
674
675         /* skip whitespace before options */
676         end = start + 2;
677         while (*end == ' ')
678                 ++end;
679
680         /* find end of option characters */
681         while (*end != ' ' && *end != '\0')
682                 ++end;
683
684         len = end - start;
685         if (len >= sizeof(save))
686                 len = sizeof(save) - 1;
687
688         /* save options */
689         strncpy(save, start, len);
690         save[len] = '\0';
691
692         /* move remaining options up front */
693         if (*end)
694                 memmove(start, end, strlen(end));
695         *(start + strlen(end)) = '\0';
696
697         /* append the specified options */
698         if (*(start + strlen(start) - 1) != ' ')
699                 strcat(start, " ");
700         idx = start + strlen(start);
701         strcat(start, save);
702
703         return idx;
704 }
705
706 /* Build fs according to type */
707 int ldiskfs_make_lustre(struct mkfs_opts *mop)
708 {
709         __u64 device_kb = mop->mo_device_kb, block_count = 0;
710         char mkfs_cmd[PATH_MAX];
711         char buf[64];
712         char *start;
713         char *dev;
714         int ret = 0, ext_opts = 0;
715         size_t maxbuflen;
716
717         if (!(mop->mo_flags & MO_IS_LOOP)) {
718                 mop->mo_device_kb = get_device_size(mop->mo_device);
719
720                 if (mop->mo_device_kb == 0)
721                         return ENODEV;
722
723                 /* Compare to real size */
724                 if (device_kb == 0 || device_kb > mop->mo_device_kb)
725                         device_kb = mop->mo_device_kb;
726                 else
727                         mop->mo_device_kb = device_kb;
728         }
729
730         if (mop->mo_device_kb != 0) {
731                 if (mop->mo_device_kb < 32384) {
732                         fprintf(stderr, "%s: size of filesystem must be larger "
733                                 "than 32MB, but is set to %lldKB\n",
734                                 progname, (long long)mop->mo_device_kb);
735                         return EINVAL;
736                 }
737                 block_count = mop->mo_device_kb / (L_BLOCK_SIZE >> 10);
738                 /* If the LUN size is just over 2^32 blocks, limit the
739                  * filesystem size to 2^32-1 blocks to avoid problems with
740                  * ldiskfs/mkfs not handling this size.  Bug 22906 */
741                 if (block_count > 0xffffffffULL && block_count < 0x100002000ULL)
742                         block_count = 0xffffffffULL;
743         }
744
745         if ((mop->mo_ldd.ldd_mount_type == LDD_MT_EXT3) ||
746             (mop->mo_ldd.ldd_mount_type == LDD_MT_LDISKFS) ||
747             (mop->mo_ldd.ldd_mount_type == LDD_MT_LDISKFS2)) {
748                 long inode_size = 0;
749
750                 /* Journal size in MB */
751                 if (strstr(mop->mo_mkfsopts, "-J") == NULL &&
752                     device_kb > 1024 * 1024) {
753                         /* Choose our own default journal size */
754                         long journal_mb = 0, max_mb;
755
756                         /* cap journal size at 4GB for MDT,
757                          * leave it at 400MB for OSTs. */
758                         if (IS_MDT(&mop->mo_ldd))
759                                 max_mb = 4096;
760                         else if (IS_OST(&mop->mo_ldd))
761                                 max_mb = 400;
762                         else /* Use mke2fs default size for MGS */
763                                 max_mb = 0;
764
765                         /* Use at most 4% of device for journal */
766                         journal_mb = device_kb * 4 / (1024 * 100);
767                         if (journal_mb > max_mb)
768                                 journal_mb = max_mb;
769
770                         if (journal_mb) {
771                                 sprintf(buf, " -J size=%ld", journal_mb);
772                                 strscat(mop->mo_mkfsopts, buf,
773                                         sizeof(mop->mo_mkfsopts));
774                         }
775                 }
776
777                 /*
778                  * The inode size is constituted by following elements
779                  * (assuming all files are in composite layout and has
780                  * 3 components):
781                  *
782                  *   ldiskfs inode size: 156
783                  *   extended attributes size, including:
784                  *      ext4_xattr_header: 32
785                  *      LOV EA size: 32(lov_comp_md_v1) +
786                  *                   3 * 40(lov_comp_md_entry_v1) +
787                  *                   3 * 32(lov_mds_md) +
788                  *                   stripes * 24(lov_ost_data) +
789                  *                   16(xattr_entry) + 3(lov)
790                  *      LMA EA size: 24(lustre_mdt_attrs) +
791                  *                   16(xattr_entry) + 3(lma)
792                  *      link EA size: 24(link_ea_header) + 18(link_ea_entry) +
793                  *                    (filename) + 16(xattr_entry) + 4(link)
794                  *   and some margin for 4-byte alignment, ACLs and other EAs.
795                  *
796                  * If we say the average filename length is about 32 bytes,
797                  * the calculation looks like:
798                  * 156 + 32 + (32+3*(40 + 32)+24*N+19) + (24+19) +
799                  * (24+18+~32+20) + other <= 512*2^m, {m=0,1,2,3}
800                  */
801                 if (strstr(mop->mo_mkfsopts, "-I") == NULL) {
802                         if (IS_MDT(&mop->mo_ldd)) {
803                                 if (mop->mo_stripe_count > 59)
804                                         inode_size = 512; /* bz 7241 */
805                                 /* see also "-i" below for EA blocks */
806                                 else if (mop->mo_stripe_count > 16)
807                                         inode_size = 2048;
808                                 else
809                                         inode_size = 1024;
810                         } else if (IS_OST(&mop->mo_ldd)) {
811                                 /* We store MDS FID and necessary composite
812                                  * layout information in the OST object EA. */
813                                 inode_size = 512;
814                         }
815
816                         if (inode_size > 0) {
817                                 sprintf(buf, " -I %ld", inode_size);
818                                 strscat(mop->mo_mkfsopts, buf,
819                                         sizeof(mop->mo_mkfsopts));
820                         }
821                 }
822
823                 /* Bytes_per_inode: disk size / num inodes */
824                 if (strstr(mop->mo_mkfsopts, "-i") == NULL &&
825                     strstr(mop->mo_mkfsopts, "-N") == NULL) {
826                         long bytes_per_inode = 0;
827
828                         /* Allocate more inodes on MDT devices.  There is
829                          * no data stored on the MDT, and very little extra
830                          * metadata beyond the inode.  It could go down as
831                          * low as 1024 bytes, but this is conservative.
832                          * Account for external EA blocks for wide striping. */
833                         if (IS_MDT(&mop->mo_ldd)) {
834                                 bytes_per_inode = inode_size + 1536;
835
836                                 if (mop->mo_stripe_count > 59) {
837                                         int extra = mop->mo_stripe_count * 24;
838                                         extra = ((extra - 1) | 4095) + 1;
839                                         bytes_per_inode += extra;
840                                 }
841                         }
842
843                         /* Allocate fewer inodes on large OST devices.  Most
844                          * filesystems can be much more aggressive than even
845                          * this, but it is impossible to know in advance. */
846                         if (IS_OST(&mop->mo_ldd)) {
847                                 /* OST > 16TB assume average file size 1MB */
848                                 if (device_kb > (16ULL << 30))
849                                         bytes_per_inode = 1024 * 1024;
850                                 /* OST > 4TB assume average file size 512kB */
851                                 else if (device_kb > (4ULL << 30))
852                                         bytes_per_inode = 512 * 1024;
853                                 /* OST > 1TB assume average file size 256kB */
854                                 else if (device_kb > (1ULL << 30))
855                                         bytes_per_inode = 256 * 1024;
856                                 /* OST > 10GB assume average file size 64kB,
857                                  * plus a bit so that inodes will fit into a
858                                  * 256x flex_bg without overflowing */
859                                 else if (device_kb > (10ULL << 20))
860                                         bytes_per_inode = 69905;
861                         }
862
863                         if (bytes_per_inode > 0) {
864                                 sprintf(buf, " -i %ld", bytes_per_inode);
865                                 strscat(mop->mo_mkfsopts, buf,
866                                         sizeof(mop->mo_mkfsopts));
867                         }
868                 }
869
870                 if (verbose < 2) {
871                         strscat(mop->mo_mkfsopts, " -q",
872                                 sizeof(mop->mo_mkfsopts));
873                 }
874
875                 /* start handle -O mkfs options */
876                 if ((start = strstr(mop->mo_mkfsopts, "-O")) != NULL) {
877                         if (strstr(start + 2, "-O") != NULL) {
878                                 fprintf(stderr,
879                                         "%s: don't specify multiple -O options\n",
880                                         progname);
881                                 return EINVAL;
882                         }
883                         start = moveopts_to_end(start);
884                         maxbuflen = sizeof(mop->mo_mkfsopts) -
885                                 (start - mop->mo_mkfsopts) - strlen(start);
886                         ret = enable_default_ext4_features(mop, start, maxbuflen, 1);
887                 } else {
888                         start = mop->mo_mkfsopts + strlen(mop->mo_mkfsopts),
889                               maxbuflen = sizeof(mop->mo_mkfsopts) -
890                                       strlen(mop->mo_mkfsopts);
891                         ret = enable_default_ext4_features(mop, start, maxbuflen, 0);
892                 }
893                 if (ret)
894                         return ret;
895                 /* end handle -O mkfs options */
896
897                 /* start handle -E mkfs options */
898                 if ((start = strstr(mop->mo_mkfsopts, "-E")) != NULL) {
899                         if (strstr(start + 2, "-E") != NULL) {
900                                 fprintf(stderr,
901                                         "%s: don't specify multiple -E options\n",
902                                         progname);
903                                 return EINVAL;
904                         }
905                         start = moveopts_to_end(start);
906                         maxbuflen = sizeof(mop->mo_mkfsopts) -
907                                 (start - mop->mo_mkfsopts) - strlen(start);
908                         ext_opts = 1;
909                 } else {
910                         start = mop->mo_mkfsopts + strlen(mop->mo_mkfsopts);
911                         maxbuflen = sizeof(mop->mo_mkfsopts) -
912                                 strlen(mop->mo_mkfsopts);
913                 }
914
915                 /* In order to align the filesystem metadata on 1MB boundaries,
916                  * give a resize value that will reserve a power-of-two group
917                  * descriptor blocks, but leave one block for the superblock.
918                  * Only useful for filesystems with < 2^32 blocks due to resize
919                  * limitations. */
920                 if (strstr(mop->mo_mkfsopts, "meta_bg") == NULL &&
921                     IS_OST(&mop->mo_ldd) && mop->mo_device_kb > 100 * 1024 &&
922                     mop->mo_device_kb * 1024 / L_BLOCK_SIZE <= 0xffffffffULL) {
923                         unsigned group_blocks = L_BLOCK_SIZE * 8;
924                         unsigned desc_per_block = L_BLOCK_SIZE / 32;
925                         unsigned resize_blks;
926
927                         resize_blks = (1ULL<<32) - desc_per_block*group_blocks;
928                         snprintf(buf, sizeof(buf), "%u", resize_blks);
929                         append_unique(start, ext_opts ? "," : " -E ",
930                                       "resize", buf, maxbuflen);
931                         ext_opts = 1;
932                 }
933
934                 /* Avoid zeroing out the full journal - speeds up mkfs */
935                 if (is_e2fsprogs_feature_supp("-E lazy_journal_init") == 0)
936                         append_unique(start, ext_opts ? "," : " -E ",
937                                       "lazy_journal_init", NULL, maxbuflen);
938                 /* end handle -E mkfs options */
939
940                 /* Allow reformat of full devices (as opposed to
941                    partitions.)  We already checked for mounted dev. */
942                 strscat(mop->mo_mkfsopts, " -F", sizeof(mop->mo_mkfsopts));
943
944                 snprintf(mkfs_cmd, sizeof(mkfs_cmd),
945                          "%s -j -b %d -L %s ", MKE2FS, L_BLOCK_SIZE,
946                          mop->mo_ldd.ldd_svname);
947         } else {
948                 fprintf(stderr,"%s: unsupported fs type: %d (%s)\n",
949                         progname, mop->mo_ldd.ldd_mount_type,
950                         MT_STR(&mop->mo_ldd));
951                 return EINVAL;
952         }
953
954         /* For loop device format the dev, not the filename */
955         dev = mop->mo_device;
956         if (mop->mo_flags & MO_IS_LOOP)
957                 dev = mop->mo_loopdev;
958
959         vprint("formatting backing filesystem %s on %s\n",
960                MT_STR(&mop->mo_ldd), dev);
961         vprint("\ttarget name   %s\n", mop->mo_ldd.ldd_svname);
962         vprint("\t4k blocks     %ju\n", (uintmax_t)block_count);
963         vprint("\toptions       %s\n", mop->mo_mkfsopts);
964
965         /* mkfs_cmd's trailing space is important! */
966         strscat(mkfs_cmd, mop->mo_mkfsopts, sizeof(mkfs_cmd));
967         strscat(mkfs_cmd, " ", sizeof(mkfs_cmd));
968         strscat(mkfs_cmd, dev, sizeof(mkfs_cmd));
969         if (block_count != 0) {
970                 snprintf(buf, sizeof(buf), " %ju",
971                          (uintmax_t)block_count);
972                 strscat(mkfs_cmd, buf, sizeof(mkfs_cmd));
973         }
974
975         vprint("mkfs_cmd = %s\n", mkfs_cmd);
976         ret = run_command(mkfs_cmd, sizeof(mkfs_cmd));
977         if (ret) {
978                 fatal();
979                 fprintf(stderr, "Unable to build fs %s (%d)\n", dev, ret);
980         }
981         return ret;
982 }
983
984 int ldiskfs_prepare_lustre(struct mkfs_opts *mop,
985                            char *wanted_mountopts, size_t len)
986 {
987         struct lustre_disk_data *ldd = &mop->mo_ldd;
988         int ret;
989
990         /* Set MO_IS_LOOP to indicate a loopback device is needed */
991         ret = is_block(mop->mo_device);
992         if (ret < 0) {
993                 return errno;
994         } else if (ret == 0) {
995                 mop->mo_flags |= MO_IS_LOOP;
996         }
997
998         if (IS_MDT(ldd) || IS_MGS(ldd))
999                 strscat(wanted_mountopts, ",user_xattr", len);
1000
1001         return 0;
1002 }
1003
1004 int ldiskfs_fix_mountopts(struct mkfs_opts *mop, char *mountopts, size_t len)
1005 {
1006         if (strstr(mountopts, "errors=") == NULL)
1007                 strscat(mountopts, ",errors=remount-ro", len);
1008
1009         return 0;
1010 }
1011
1012 static int read_file(const char *path, char *buf, int size)
1013 {
1014         FILE *fd;
1015
1016         fd = fopen(path, "r");
1017         if (fd == NULL)
1018                 return errno;
1019
1020         if (fgets(buf, size, fd) == NULL) {
1021                 fprintf(stderr, "reading from %s: %s", path, strerror(errno));
1022                 fclose(fd);
1023                 return 1;
1024         }
1025         fclose(fd);
1026
1027         /* strip trailing newline */
1028         size = strlen(buf);
1029         if (buf[size - 1] == '\n')
1030                 buf[size - 1] = '\0';
1031
1032         return 0;
1033 }
1034
1035 static int write_file(const char *path, const char *buf)
1036 {
1037         int fd, rc;
1038
1039         fd = open(path, O_WRONLY);
1040         if (fd < 0)
1041                 return errno;
1042
1043         rc = write(fd, buf, strlen(buf));
1044         close(fd);
1045
1046         return rc < 0 ? errno : 0;
1047 }
1048
1049 static int set_blockdev_scheduler(const char *path, const char *scheduler)
1050 {
1051         char buf[PATH_MAX], *s, *e, orig_sched[50];
1052         int rc;
1053
1054         /* Before setting the scheduler, we need to check to see if it's
1055          * already set to "noop". If it is, we don't want to override
1056          * that setting. If it's set to anything other than "noop", set
1057          * the scheduler to what has been passed in. */
1058
1059         rc = read_file(path, buf, sizeof(buf));
1060         if (rc) {
1061                 if (verbose)
1062                         fprintf(stderr, "%s: cannot open '%s': %s\n",
1063                                 progname, path, strerror(errno));
1064                 return rc;
1065         }
1066
1067         /* The expected format of buf: noop anticipatory deadline [cfq] */
1068         s = strchr(buf, '[');
1069         e = strchr(buf, ']');
1070
1071         /* If the format is not what we expect. Play it safe and error out. */
1072         if (s == NULL || e == NULL) {
1073                 if (verbose)
1074                         fprintf(stderr, "%s: cannot parse scheduler "
1075                                         "options for '%s'\n", progname, path);
1076                 return -EINVAL;
1077         }
1078
1079         snprintf(orig_sched, e - s, "%s", s + 1);
1080
1081         if (strcmp(orig_sched, "noop") == 0 ||
1082             strcmp(orig_sched, scheduler) == 0)
1083                 return 0;
1084
1085         rc = write_file(path, scheduler);
1086         if (rc) {
1087                 if (verbose)
1088                         fprintf(stderr, "%s: cannot set scheduler on "
1089                                         "'%s': %s\n", progname, path,
1090                                         strerror(errno));
1091                 return rc;
1092         } else {
1093                 fprintf(stderr, "%s: change scheduler of %s from %s to %s\n",
1094                         progname, path, orig_sched, scheduler);
1095         }
1096
1097         return rc;
1098 }
1099
1100 /* This is to tune the kernel for good SCSI performance.
1101  * For that we set the value of /sys/block/{dev}/queue/max_sectors_kb
1102  * to the value of /sys/block/{dev}/queue/max_hw_sectors_kb */
1103 static int set_blockdev_tunables(char *source, struct mount_opts *mop)
1104 {
1105         glob_t glob_info = { 0 };
1106         struct stat stat_buf;
1107         char *chk_major, *chk_minor;
1108         char *savept = NULL, *dev;
1109         char *ret_path;
1110         char buf[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1111         char real_path[PATH_MAX] = {'\0'};
1112         int i, rc = 0;
1113         int major, minor;
1114         char *slave = NULL;
1115
1116         if (!source)
1117                 return -EINVAL;
1118
1119         ret_path = realpath(source, real_path);
1120         if (ret_path == NULL) {
1121                 if (verbose)
1122                         fprintf(stderr, "warning: %s: cannot resolve: %s\n",
1123                                 source, strerror(errno));
1124                 return -EINVAL;
1125         }
1126
1127         if (strncmp(real_path, "/dev/loop", 9) == 0)
1128                 return 0;
1129
1130         if ((real_path[0] != '/') && (strpbrk(real_path, ",:") != NULL))
1131                 return 0;
1132
1133         snprintf(path, sizeof(path), "/sys/block%s", real_path + 4);
1134         if (access(path, X_OK) == 0)
1135                 goto set_params;
1136
1137         /* The name of the device say 'X' specified in /dev/X may not
1138          * match any entry under /sys/block/. In that case we need to
1139          * match the major/minor number to find the entry under
1140          * sys/block corresponding to /dev/X */
1141
1142         /* Don't chop tail digit on /dev/mapper/xxx, LU-478 */
1143         if (strncmp(real_path, "/dev/mapper", 11) != 0) {
1144                 dev = real_path + strlen(real_path);
1145                 while (--dev > real_path && isdigit(*dev))
1146                         *dev = 0;
1147
1148                 if (strncmp(real_path, "/dev/md", 7) == 0 && dev[0] == 'p')
1149                         *dev = 0;
1150         }
1151
1152         rc = stat(real_path, &stat_buf);
1153         if (rc) {
1154                 if (verbose)
1155                         fprintf(stderr, "warning: %s, device %s stat failed\n",
1156                                 strerror(errno), real_path);
1157                 return rc;
1158         }
1159
1160         major = major(stat_buf.st_rdev);
1161         minor = minor(stat_buf.st_rdev);
1162         rc = glob("/sys/block/*", GLOB_NOSORT, NULL, &glob_info);
1163         if (rc) {
1164                 if (verbose)
1165                         fprintf(stderr, "warning: failed to read entries under "
1166                                 "/sys/block\n");
1167                 globfree(&glob_info);
1168                 return rc;
1169         }
1170
1171         for (i = 0; i < glob_info.gl_pathc; i++){
1172                 snprintf(path, sizeof(path), "%s/dev", glob_info.gl_pathv[i]);
1173
1174                 rc = read_file(path, buf, sizeof(buf));
1175                 if (rc)
1176                         continue;
1177
1178                 if (buf[strlen(buf) - 1] == '\n')
1179                         buf[strlen(buf) - 1] = '\0';
1180
1181                 chk_major = strtok_r(buf, ":", &savept);
1182                 chk_minor = savept;
1183                 if (chk_major != NULL && major == atoi(chk_major) &&
1184                     chk_minor != NULL && minor == atoi(chk_minor))
1185                         break;
1186         }
1187
1188         if (i == glob_info.gl_pathc) {
1189                 if (verbose)
1190                         fprintf(stderr,"warning: device %s does not match any "
1191                                 "entry under /sys/block\n", real_path);
1192                 globfree(&glob_info);
1193                 return -EINVAL;
1194         }
1195
1196         /* Chop off "/dev" from path we found */
1197         path[strlen(glob_info.gl_pathv[i])] = '\0';
1198         globfree(&glob_info);
1199
1200 set_params:
1201         if (strncmp(real_path, "/dev/md", 7) == 0) {
1202                 snprintf(real_path, sizeof(real_path), "%s/%s", path,
1203                          STRIPE_CACHE_SIZE);
1204
1205                 rc = read_file(real_path, buf, sizeof(buf));
1206                 if (rc) {
1207                         if (verbose)
1208                                 fprintf(stderr, "warning: opening %s: %s\n",
1209                                         real_path, strerror(errno));
1210                         return 0;
1211                 }
1212
1213                 if (atoi(buf) >= mop->mo_md_stripe_cache_size)
1214                         return 0;
1215
1216                 if (strlen(buf) - 1 > 0) {
1217                         snprintf(buf, sizeof(buf), "%d",
1218                                  mop->mo_md_stripe_cache_size);
1219                         rc = write_file(real_path, buf);
1220                         if (rc != 0 && verbose)
1221                                 fprintf(stderr, "warning: opening %s: %s\n",
1222                                         real_path, strerror(errno));
1223                 }
1224                 /* Return since raid and disk tunables are different */
1225                 return rc;
1226         }
1227
1228         if (mop->mo_max_sectors_kb >= 0) {
1229                 snprintf(buf, sizeof(buf), "%d", mop->mo_max_sectors_kb);
1230         } else {
1231                 snprintf(real_path, sizeof(real_path), "%s/%s", path,
1232                          MAX_HW_SECTORS_KB_PATH);
1233                 rc = read_file(real_path, buf, sizeof(buf));
1234                 if (rc) {
1235                         if (verbose)
1236                                 fprintf(stderr, "warning: opening %s: %s\n",
1237                                         real_path, strerror(errno));
1238                         /* No MAX_HW_SECTORS_KB_PATH isn't necessary an
1239                          * error for some device. */
1240                         goto subdevs;
1241                 }
1242         }
1243
1244         if (strlen(buf) - 1 > 0) {
1245                 char oldbuf[32] = "", *end = NULL;
1246                 unsigned long long oldval, newval;
1247
1248                 snprintf(real_path, sizeof(real_path), "%s/%s", path,
1249                          MAX_SECTORS_KB_PATH);
1250                 rc = read_file(real_path, oldbuf, sizeof(oldbuf));
1251                 /* Only set new parameter if different from the old one. */
1252                 if (rc != 0 || strcmp(oldbuf, buf) == 0) {
1253                         /* No MAX_SECTORS_KB_PATH isn't necessary an
1254                          * error for some device. */
1255                         goto subdevs;
1256                 }
1257
1258                 newval = strtoull(buf, &end, 0);
1259                 if (newval == 0 || newval == ULLONG_MAX || end == buf)
1260                         goto subdevs;
1261
1262                 /* Don't increase IO request size limit past 16MB.  It is about
1263                  * PTLRPC_MAX_BRW_SIZE, but that isn't in a public header.
1264                  * Note that even though the block layer allows larger values,
1265                  * setting max_sectors_kb = 32768 causes crashes (LU-6974). */
1266                 if (mop->mo_max_sectors_kb < 0 && newval > 16 * 1024) {
1267                         newval = 16 * 1024;
1268                         snprintf(buf, sizeof(buf), "%llu", newval);
1269                 }
1270
1271                 oldval = strtoull(oldbuf, &end, 0);
1272                 /* Don't shrink the current limit. */
1273                 if (mop->mo_max_sectors_kb < 0 && oldval != ULLONG_MAX &&
1274                     newval <= oldval)
1275                         goto subdevs;
1276
1277                 rc = write_file(real_path, buf);
1278                 if (rc != 0) {
1279                         if (verbose)
1280                                 fprintf(stderr, "warning: writing to %s: %s\n",
1281                                         real_path, strerror(errno));
1282                         /* No MAX_SECTORS_KB_PATH isn't necessary an
1283                          * error for some device. */
1284                         goto subdevs;
1285                 }
1286                 fprintf(stderr, "%s: increased %s from %s to %s\n",
1287                         progname, real_path, oldbuf, buf);
1288         }
1289
1290 subdevs:
1291         /* Purposely ignore errors reported from set_blockdev_scheduler.
1292          * The worst that will happen is a block device with an "incorrect"
1293          * scheduler. */
1294         snprintf(real_path, sizeof(real_path), "%s/%s", path, SCHEDULER_PATH);
1295         set_blockdev_scheduler(real_path, DEFAULT_SCHEDULER);
1296
1297         /* if device is multipath device, tune its slave devices */
1298         glob_info.gl_pathc = 0;
1299         glob_info.gl_offs = 0;
1300         snprintf(real_path, sizeof(real_path), "%s/slaves/*", path);
1301         rc = glob(real_path, GLOB_NOSORT, NULL, &glob_info);
1302
1303         for (i = 0; rc == 0 && i < glob_info.gl_pathc; i++) {
1304                 slave = basename(glob_info.gl_pathv[i]);
1305                 snprintf(real_path, sizeof(real_path), "/dev/%s", slave);
1306                 rc = set_blockdev_tunables(real_path, mop);
1307         }
1308
1309         if (rc == GLOB_NOMATCH) {
1310                 /* no slave device is not an error */
1311                 rc = 0;
1312         } else if (rc && verbose) {
1313                 if (slave == NULL) {
1314                         fprintf(stderr, "warning: %s, failed to read"
1315                                 " entries under %s/slaves\n",
1316                                 strerror(errno), path);
1317                 } else {
1318                         fprintf(stderr, "unable to set tunables for"
1319                                 " slave device %s (slave would be"
1320                                 " unable to handle IO request from"
1321                                 " master %s)\n",
1322                                 real_path, source);
1323                 }
1324         }
1325         globfree(&glob_info);
1326
1327         return rc;
1328 }
1329
1330 int ldiskfs_tune_lustre(char *dev, struct mount_opts *mop)
1331 {
1332         return set_blockdev_tunables(dev, mop);
1333 }
1334
1335 int ldiskfs_label_lustre(struct mount_opts *mop)
1336 {
1337         char label_cmd[PATH_MAX];
1338         int rc;
1339
1340         snprintf(label_cmd, sizeof(label_cmd),
1341                  TUNE2FS" -f -L '%s' '%s' >/dev/null 2>&1",
1342                  mop->mo_ldd.ldd_svname, mop->mo_source);
1343         rc = run_command(label_cmd, sizeof(label_cmd));
1344
1345         return rc;
1346 }
1347
1348 int ldiskfs_rename_fsname(struct mkfs_opts *mop, const char *oldname)
1349 {
1350         struct mount_opts opts;
1351         struct lustre_disk_data *ldd = &mop->mo_ldd;
1352         char mntpt[] = "/tmp/mntXXXXXX";
1353         char *dev;
1354         int ret;
1355
1356         /* Change the filesystem label. */
1357         opts.mo_ldd = *ldd;
1358         opts.mo_source = mop->mo_device;
1359         ret = ldiskfs_label_lustre(&opts);
1360         if (ret) {
1361                 if (errno != 0)
1362                         ret = errno;
1363                 fprintf(stderr, "Can't change filesystem label: %s\n",
1364                         strerror(ret));
1365                 return ret;
1366         }
1367
1368         /* Mount this device temporarily in order to write these files */
1369         if (mkdtemp(mntpt) == NULL) {
1370                 if (errno != 0)
1371                         ret = errno;
1372                 else
1373                         ret = EINVAL;
1374                 fprintf(stderr, "Can't create temp mount point %s: %s\n",
1375                         mntpt, strerror(ret));
1376                 return ret;
1377         }
1378
1379 #ifdef HAVE_SELINUX
1380         /*
1381          * Append file context to mount options if SE Linux is enabled
1382          */
1383         if (is_selinux_enabled() > 0)
1384                 append_context_for_mount(mntpt, mop);
1385 #endif
1386
1387         if (mop->mo_flags & MO_IS_LOOP)
1388                 dev = mop->mo_loopdev;
1389         else
1390                 dev = mop->mo_device;
1391         ret = mount(dev, mntpt, MT_STR(ldd), 0, ldd->ldd_mount_opts);
1392         if (ret) {
1393                 if (errno != 0)
1394                         ret = errno;
1395                 fprintf(stderr, "Unable to mount %s: %s\n",
1396                         dev, strerror(ret));
1397                 if (ret == ENODEV)
1398                         fprintf(stderr, "Is the %s module available?\n",
1399                                 MT_STR(ldd));
1400                 goto out_rmdir;
1401         }
1402
1403         ret = lustre_rename_fsname(mop, mntpt, oldname);
1404         umount(mntpt);
1405
1406 out_rmdir:
1407         rmdir(mntpt);
1408         return ret;
1409 }
1410
1411 /* Enable quota accounting */
1412 int ldiskfs_enable_quota(struct mkfs_opts *mop)
1413 {
1414         char *dev;
1415         char cmd[512];
1416         int cmdsz = sizeof(cmd), ret;
1417
1418         if (is_e2fsprogs_feature_supp("-O quota") != 0) {
1419                 fprintf(stderr, "%s: \"-O quota\" is is not supported by "
1420                         "current e2fsprogs\n", progname);
1421                 return EINVAL;
1422         }
1423
1424         dev = mop->mo_device;
1425         if (mop->mo_flags & MO_IS_LOOP)
1426                 dev = mop->mo_loopdev;
1427
1428         /* Quota feature is already enabled? */
1429         if (is_feature_enabled("quota", dev)) {
1430                 vprint("Quota feature is already enabled.\n");
1431                 return 0;
1432         }
1433
1434         /* Turn on quota feature by "tune2fs -O quota" */
1435         snprintf(cmd, cmdsz, "%s -O quota %s", TUNE2FS, dev);
1436         ret = run_command(cmd, cmdsz);
1437         if (ret)
1438                 fprintf(stderr, "command:%s (%d)", cmd, ret);
1439
1440         return ret;
1441 }
1442
1443 int ldiskfs_init(void)
1444 {
1445         /* Required because full path to DEBUGFS is not specified */
1446         setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin", 0);
1447
1448         return 0;
1449 }
1450
1451 void ldiskfs_fini(void)
1452 {
1453         return;
1454 }
1455
1456 #ifndef PLUGIN_DIR
1457 struct module_backfs_ops ldiskfs_ops = {
1458         .init                   = ldiskfs_init,
1459         .fini                   = ldiskfs_fini,
1460         .read_ldd               = ldiskfs_read_ldd,
1461         .write_ldd              = ldiskfs_write_ldd,
1462         .erase_ldd              = ldiskfs_erase_ldd,
1463         .print_ldd_params       = ldiskfs_print_ldd_params,
1464         .is_lustre              = ldiskfs_is_lustre,
1465         .make_lustre            = ldiskfs_make_lustre,
1466         .prepare_lustre         = ldiskfs_prepare_lustre,
1467         .fix_mountopts          = ldiskfs_fix_mountopts,
1468         .tune_lustre            = ldiskfs_tune_lustre,
1469         .label_lustre           = ldiskfs_label_lustre,
1470         .enable_quota           = ldiskfs_enable_quota,
1471         .rename_fsname          = ldiskfs_rename_fsname,
1472 };
1473 #endif /* PLUGIN_DIR */