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