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