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