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