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