* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, 2016, Intel Corporation.
+ * Copyright (c) 2012, 2017, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
+#include <dirent.h>
#include <fcntl.h>
#include <mntent.h>
-#include <glob.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/utsname.h>
+#include <sys/sysmacros.h>
#include <string.h>
#include <getopt.h>
#include <limits.h>
#include <ctype.h>
+#include <ext2fs/ext2fs.h>
+
#ifndef BLKGETSIZE64
#include <linux/fs.h> /* for BLKGETSIZE64 */
#endif
+#include <linux/major.h>
#include <linux/types.h>
#include <linux/version.h>
-#include <lnet/lnetctl.h>
-#include <lustre_ver.h>
-
-#ifdef HAVE_SELINUX
-#include <selinux/selinux.h>
-#endif
+#include <linux/lnet/lnetctl.h>
+#include <linux/lustre/lustre_ver.h>
+#include <libcfs/util/string.h>
#include "mount_utils.h"
extern char *progname;
-#define L_BLOCK_SIZE 4096
+static ext2_filsys backfs;
+static int open_flags = EXT2_FLAG_64BITS | EXT2_FLAG_SKIP_MMP |
+ EXT2_FLAG_IGNORE_SB_ERRORS | EXT2_FLAG_SUPER_ONLY;
+
/* keep it less than LL_FID_NAMELEN */
#define DUMMY_FILE_NAME_LEN 25
#define EXT3_DIRENT_SIZE DUMMY_FILE_NAME_LEN
static void append_unique(char *buf, char *prefix, char *key, char *val,
size_t maxbuflen);
-static int is_e2fsprogs_feature_supp(const char *feature);
+static bool is_e2fsprogs_feature_supp(const char *feature);
static void disp_old_e2fsprogs_msg(const char *feature, int make_backfs);
-/*
- * Concatenate context of the temporary mount point if selinux is enabled
- */
-#ifdef HAVE_SELINUX
-static void append_context_for_mount(char *mntpt, struct mkfs_opts *mop)
-{
- security_context_t fcontext;
-
- if (getfilecon(mntpt, &fcontext) < 0) {
- /* Continuing with default behaviour */
- fprintf(stderr, "%s: Get file context failed : %s\n",
- progname, strerror(errno));
- return;
- }
-
- if (fcontext != NULL) {
- append_unique(mop->mo_ldd.ldd_mount_opts,
- ",", "context", fcontext,
- sizeof(mop->mo_ldd.ldd_mount_opts));
- freecon(fcontext);
- }
-}
-#endif
-
-/* return canonicalized absolute pathname, even if the target file does not
- * exist, unlike realpath */
-static char *absolute_path(char *devname)
-{
- char buf[PATH_MAX + 1] = "";
- char *path;
- char *ptr;
- int len;
-
- path = malloc(sizeof(buf));
- if (path == NULL)
- return NULL;
-
- if (devname[0] != '/') {
- if (getcwd(buf, sizeof(buf) - 1) == NULL) {
- free(path);
- return NULL;
- }
- len = snprintf(path, sizeof(buf), "%s/%s", buf, devname);
- if (len >= sizeof(buf)) {
- free(path);
- return NULL;
- }
- } else {
- len = snprintf(path, sizeof(buf), "%s", devname);
- if (len >= sizeof(buf)) {
- free(path);
- return NULL;
- }
- }
-
- /* truncate filename before calling realpath */
- ptr = strrchr(path, '/');
- if (ptr == NULL) {
- free(path);
- return NULL;
- }
- *ptr = '\0';
- if (buf != realpath(path, buf)) {
- free(path);
- return NULL;
- }
- /* add the filename back */
- len = snprintf(path, PATH_MAX, "%s/%s", buf, ptr+1);
- if (len >= PATH_MAX) {
- free(path);
- return NULL;
- }
- return path;
-}
-
/* Determine if a device is a block device (as opposed to a file) */
static int is_block(char *devname)
{
int ret = 0;
char *devpath;
- devpath = absolute_path(devname);
- if (devpath == NULL) {
- fprintf(stderr, "%s: failed to resolve path to %s\n",
- progname, devname);
+ ret = cfs_abs_path(devname, &devpath);
+ if (ret != 0) {
+ fprintf(stderr, "%s: failed to resolve path '%s': %s\n",
+ progname, devname, strerror(-ret));
return -1;
}
return ret;
}
-static int is_feature_enabled(const char *feature, const char *devpath)
-{
- char cmd[PATH_MAX];
- FILE *fp;
- char enabled_features[4096] = "";
- int ret = 1;
-
- snprintf(cmd, sizeof(cmd), "%s -c -R features %s 2>&1",
- DEBUGFS, devpath);
-
- /* Using popen() instead of run_command() since debugfs does
- * not return proper error code if command is not supported */
- fp = popen(cmd, "r");
- if (!fp) {
- fprintf(stderr, "%s: %s\n", progname, strerror(errno));
- return 0;
- }
-
- ret = fread(enabled_features, 1, sizeof(enabled_features) - 1, fp);
- enabled_features[ret] = '\0';
- pclose(fp);
-
- if (strstr(enabled_features, feature))
- return 1;
- return 0;
-}
-
/* Write the server config files */
int ldiskfs_write_ldd(struct mkfs_opts *mop)
{
char mntpt[] = "/tmp/mntXXXXXX";
- char filepnm[128];
+ char filepnm[192];
char *dev;
FILE *filep;
int ret = 0;
return errno;
}
- /*
- * Append file context to mount options if SE Linux is enabled
- */
- #ifdef HAVE_SELINUX
- if (is_selinux_enabled() > 0)
- append_context_for_mount(mntpt, mop);
- #endif
-
dev = mop->mo_device;
if (mop->mo_flags & MO_IS_LOOP)
dev = mop->mo_loopdev;
/* Multiple mount protection enabled if failover node specified */
- if (mop->mo_flags & MO_FAILOVER &&
- !is_feature_enabled("mmp", dev)) {
- if (is_e2fsprogs_feature_supp("-O mmp") == 0) {
- char *command = filepnm;
-
- snprintf(command, sizeof(filepnm),
- TUNE2FS" -O mmp '%s' >/dev/null 2>&1", dev);
- ret = run_command(command, sizeof(filepnm));
- if (ret)
- fprintf(stderr,
- "%s: Unable to set 'mmp' on %s: %d\n",
- progname, dev, ret);
- } else
- disp_old_e2fsprogs_msg("mmp", 1);
+ if (mop->mo_flags & MO_FAILOVER) {
+ if (!backfs)
+ ext2fs_open(dev, open_flags, 0, 0,
+ unix_io_manager, &backfs);
+ if (!backfs || !ext2fs_has_feature_mmp(backfs->super)) {
+ if (is_e2fsprogs_feature_supp("-O mmp")) {
+ char *command = filepnm;
+
+ snprintf(command, sizeof(filepnm),
+ TUNE2FS" -O mmp '%s' >/dev/null 2>&1",
+ dev);
+ ret = run_command(command, sizeof(filepnm));
+ if (ret)
+ fprintf(stderr,
+ "%s: Unable to set 'mmp' "
+ "on %s: %d\n",
+ progname, dev, ret);
+ } else {
+ disp_old_e2fsprogs_msg("mmp", 1);
+ }
+ /* avoid stale cache after following operations */
+ if (backfs) {
+ ext2fs_close(backfs);
+ backfs = NULL;
+ }
+ }
}
ret = mount(dev, mntpt, MT_STR(&mop->mo_ldd), 0,
int ldiskfs_read_ldd(char *dev, struct lustre_disk_data *mo_ldd)
{
- char tmpdir[] = "/tmp/dirXXXXXX";
+ errcode_t retval;
+ ext2_ino_t ino;
+ ext2_file_t file;
+ unsigned int got;
char cmd[PATH_MAX];
- char filepnm[128];
- FILE *filep;
int ret = 0;
- int cmdsz = sizeof(cmd);
-
- /* Make a temporary directory to hold Lustre data files. */
- if (!mkdtemp(tmpdir)) {
- fprintf(stderr, "%s: Can't create temporary directory %s: %s\n",
- progname, tmpdir, strerror(errno));
- return errno;
- }
- /* TODO: it's worth observing the get_mountdata() function that is
- in mount_utils.c for getting the mountdata out of the
- filesystem */
-
- /* Construct debugfs command line. */
- snprintf(cmd, cmdsz, "%s -c -R 'dump /%s %s/mountdata' '%s'",
- DEBUGFS, MOUNT_DATA_FILE, tmpdir, dev);
-
- ret = run_command(cmd, cmdsz);
- if (ret)
- verrprint("%s: Unable to dump %s dir (%d)\n",
- progname, MOUNT_CONFIGS_DIR, ret);
-
- sprintf(filepnm, "%s/mountdata", tmpdir);
- filep = fopen(filepnm, "r");
- if (filep) {
- size_t num_read;
- vprint("Reading %s\n", MOUNT_DATA_FILE);
- num_read = fread(mo_ldd, sizeof(*mo_ldd), 1, filep);
- if (num_read < 1 && ferror(filep)) {
- fprintf(stderr, "%s: Unable to read from file %s: %s\n",
- progname, filepnm, strerror(errno));
+ if (!backfs) {
+ retval = ext2fs_open(dev, open_flags, 0, 0,
+ unix_io_manager, &backfs);
+ if (retval) {
+ fprintf(stderr, "Unable to open fs on %s\n", dev);
+ goto read_label;
}
- fclose(filep);
}
-
- snprintf(cmd, cmdsz, "rm -rf %s", tmpdir);
- run_command(cmd, cmdsz);
- if (ret)
- verrprint("Failed to read old data (%d)\n", ret);
-
+ retval = ext2fs_namei(backfs, EXT2_ROOT_INO, EXT2_ROOT_INO,
+ MOUNT_DATA_FILE, &ino);
+ if (retval) {
+ fprintf(stderr, "Error while looking up %s\n", MOUNT_DATA_FILE);
+ goto read_label;
+ }
+ retval = ext2fs_file_open(backfs, ino, 0, &file);
+ if (retval) {
+ fprintf(stderr, "Error while opening file %s\n",
+ MOUNT_DATA_FILE);
+ goto read_label;
+ }
+ retval = ext2fs_file_read(file, mo_ldd, sizeof(*mo_ldd), &got);
+ if (retval || got == 0)
+ fprintf(stderr, "Failed to read file %s\n", MOUNT_DATA_FILE);
+read_label:
/* As long as we at least have the label, we're good to go */
snprintf(cmd, sizeof(cmd), E2LABEL" %s", dev);
ret = readcmd(cmd, mo_ldd->ldd_svname, sizeof(mo_ldd->ldd_svname) - 1);
E2FSPROGS, feature);
#if !(HAVE_LDISKFSPROGS)
fprintf(stderr, "Please install the latest version of e2fsprogs from\n"
- "https://downloads.hpdd.intel.com/public/e2fsprogs/latest/\n"
+ "https://downloads.whamcloud.com/public/e2fsprogs/latest/\n"
"to enable this feature.\n");
#endif
if (make_backfs)
- fprintf(stderr, "Feature will not be enabled until %s"
- "is updated and '%s -O %s %%{device}' "
- "is run.\n\n", E2FSPROGS, TUNE2FS, feature);
+ fprintf(stderr,
+ "Feature will not be enabled until %s is updated and '%s -O %s %%{device}' is run.\n\n",
+ E2FSPROGS, TUNE2FS, feature);
}
/* Check whether the file exists in the device */
static int file_in_dev(char *file_name, char *dev_name)
{
- FILE *fp;
- char debugfs_cmd[256];
- unsigned int inode_num;
- int i;
-
- /* Construct debugfs command line. */
- snprintf(debugfs_cmd, sizeof(debugfs_cmd),
- "%s -c -R 'stat %s' '%s' 2>&1 | egrep '(Inode|unsupported)'",
- DEBUGFS, file_name, dev_name);
-
- fp = popen(debugfs_cmd, "r");
- if (!fp) {
- fprintf(stderr, "%s: %s\n", progname, strerror(errno));
- return 0;
- }
+ ext2_ino_t ino;
+ errcode_t retval;
- if (fscanf(fp, "Inode: %u", &inode_num) == 1) { /* exist */
- pclose(fp);
- return 1;
- }
- i = fread(debugfs_cmd, 1, sizeof(debugfs_cmd) - 1, fp);
- if (i) {
- debugfs_cmd[i] = 0;
- fprintf(stderr, "%s", debugfs_cmd);
- if (strstr(debugfs_cmd, "unsupported feature")) {
- disp_old_e2fsprogs_msg("an unknown", 0);
- }
- pclose(fp);
- return -1;
+ if (!backfs) {
+ retval = ext2fs_open(dev_name, open_flags, 0, 0,
+ unix_io_manager, &backfs);
+ if (retval)
+ return 0;
}
- pclose(fp);
+ retval = ext2fs_namei(backfs, EXT2_ROOT_INO, EXT2_ROOT_INO,
+ file_name, &ino);
+ if (!retval)
+ return 1;
+
return 0;
}
* Firstly we try to use "debugfs supported_features" command to check if
* the feature is supported. If this fails we try to set this feature with
* mke2fs to check for its support. */
-static int is_e2fsprogs_feature_supp(const char *feature)
+static bool is_e2fsprogs_feature_supp(const char *feature)
{
static char supp_features[4096] = "";
FILE *fp;
char cmd[PATH_MAX];
char imgname[] = "/tmp/test-img-XXXXXX";
- int fd = -1;
- int ret = 1;
+ int fd;
+ int ret;
if (supp_features[0] == '\0') {
snprintf(cmd, sizeof(cmd), "%s -c -R supported_features 2>&1",
fp = popen(cmd, "r");
if (!fp) {
fprintf(stderr, "%s: %s\n", progname, strerror(errno));
- return 0;
+ } else {
+ ret = fread(supp_features, 1,
+ sizeof(supp_features) - 1, fp);
+ supp_features[ret] = '\0';
+ pclose(fp);
}
- ret = fread(supp_features, 1, sizeof(supp_features) - 1, fp);
- supp_features[ret] = '\0';
- pclose(fp);
}
- if (ret > 0 && strstr(supp_features,
- strncmp(feature, "-O ", 3) ? feature : feature+3))
- return 0;
+
+ if (strstr(supp_features,
+ strncmp(feature, "-O ", 3) ? feature : feature + 3))
+ return true;
if ((fd = mkstemp(imgname)) < 0)
- return -1;
- else
- close(fd);
+ return false;
+
+ close(fd);
snprintf(cmd, sizeof(cmd), "%s -F %s %s 100 >/dev/null 2>&1",
MKE2FS, feature, imgname);
ret = system(cmd);
unlink(imgname);
- return ret;
+ return ret == 0;
}
-
/**
* append_unique: append @key or @key=@val pair to @buf only if @key does not
* exists
}
static int enable_default_ext4_features(struct mkfs_opts *mop, char *anchor,
- size_t maxbuflen, int user_spec)
+ size_t maxbuflen, bool user_spec)
{
+ unsigned long long blocks = mop->mo_device_kb / mop->mo_blocksize_kb;
+ bool enable_64bit = false;
+
+ /* Enable large block addresses if the LUN is over 2^32 blocks. */
+ if (blocks > 0xffffffffULL && is_e2fsprogs_feature_supp("-O 64bit"))
+ enable_64bit = true;
+
if (IS_OST(&mop->mo_ldd)) {
append_unique(anchor, user_spec ? "," : " -O ",
"extents", NULL, maxbuflen);
append_unique(anchor, user_spec ? "," : " -O ",
"dirdata", NULL, maxbuflen);
append_unique(anchor, ",", "uninit_bg", NULL, maxbuflen);
- append_unique(anchor, ",", "^extents", NULL, maxbuflen);
+ if (enable_64bit)
+ append_unique(anchor, ",", "extents", NULL, maxbuflen);
+ else
+ append_unique(anchor, ",", "^extents", NULL, maxbuflen);
} else {
append_unique(anchor, user_spec ? "," : " -O ",
"uninit_bg", NULL, maxbuflen);
/* Multiple mount protection enabled only if failover node specified */
if (mop->mo_flags & MO_FAILOVER) {
- if (is_e2fsprogs_feature_supp("-O mmp") == 0)
+ if (is_e2fsprogs_feature_supp("-O mmp"))
append_unique(anchor, ",", "mmp", NULL, maxbuflen);
else
disp_old_e2fsprogs_msg("mmp", 1);
}
/* Allow more than 65000 subdirectories */
- if (is_e2fsprogs_feature_supp("-O dir_nlink") == 0)
+ if (is_e2fsprogs_feature_supp("-O dir_nlink"))
append_unique(anchor, ",", "dir_nlink", NULL, maxbuflen);
/* The following options are only valid for ext4-based ldiskfs.
return 0;
/* Enable quota by default */
- if (is_e2fsprogs_feature_supp("-O quota") == 0) {
+ if (is_e2fsprogs_feature_supp("-O quota")) {
append_unique(anchor, ",", "quota", NULL, maxbuflen);
} else {
fatal();
}
/* Allow files larger than 2TB. Also needs LU-16, but not harmful. */
- if (is_e2fsprogs_feature_supp("-O huge_file") == 0)
+ if (is_e2fsprogs_feature_supp("-O huge_file"))
append_unique(anchor, ",", "huge_file", NULL, maxbuflen);
- /* Enable large block addresses if the LUN is over 2^32 blocks. */
- if (mop->mo_device_kb / (L_BLOCK_SIZE >> 10) >= 0x100002000ULL &&
- is_e2fsprogs_feature_supp("-O 64bit") == 0)
+ if (enable_64bit)
append_unique(anchor, ",", "64bit", NULL, maxbuflen);
+ if (blocks >= 0x1000000000 && is_e2fsprogs_feature_supp("-O meta_bg"))
+ append_unique(anchor, ",", "meta_bg", NULL, maxbuflen);
+
+ if (enable_64bit || strstr(mop->mo_mkfsopts, "meta_bg"))
+ append_unique(anchor, ",", "^resize_inode", NULL, maxbuflen);
+
+ /* Allow xattrs larger than one block, stored in a separate inode */
+ if (IS_MDT(&mop->mo_ldd) && is_e2fsprogs_feature_supp("-O ea_inode"))
+ append_unique(anchor, ",", "ea_inode", NULL, maxbuflen);
+
+ /* Allow more than 10M directory entries */
+ if (IS_MDT(&mop->mo_ldd) && is_e2fsprogs_feature_supp("-O large_dir"))
+ append_unique(anchor, ",", "large_dir", NULL, maxbuflen);
+
/* Cluster inode/block bitmaps and inode table for more efficient IO.
* Align the flex groups on a 1MB boundary for better performance. */
/* This -O feature needs to go last, since it adds the "-G" option. */
- if (is_e2fsprogs_feature_supp("-O flex_bg") == 0) {
+ if (is_e2fsprogs_feature_supp("-O flex_bg")) {
char tmp_buf[64];
append_unique(anchor, ",", "flex_bg", NULL, maxbuflen);
if (IS_OST(&mop->mo_ldd) &&
strstr(mop->mo_mkfsopts, "-G") == NULL) {
snprintf(tmp_buf, sizeof(tmp_buf), " -G %u",
- (1 << 20) / L_BLOCK_SIZE);
+ 1024 / mop->mo_blocksize_kb);
strscat(anchor, tmp_buf, maxbuflen);
}
}
/* Build fs according to type */
int ldiskfs_make_lustre(struct mkfs_opts *mop)
{
- __u64 device_kb = mop->mo_device_kb, block_count = 0;
char mkfs_cmd[PATH_MAX];
char buf[64];
char *start;
char *dev;
int ret = 0, ext_opts = 0;
+ bool enable_64bit = false;
+ long inode_size = 0;
size_t maxbuflen;
+ mop->mo_blocksize_kb = 4;
+
+ start = strstr(mop->mo_mkfsopts, "-b");
+ if (start) {
+ char *end = NULL;
+ long blocksize;
+
+ blocksize = strtol(start + 2, &end, 0);
+ if (end && (*end == 'k' || *end == 'K'))
+ blocksize *= 1024;
+ /* EXT4_MIN_BLOCK_SIZE || EXT4_MAX_BLOCK_SIZE */
+ if (blocksize < 1024 || blocksize > 65536) {
+ fprintf(stderr,
+ "%s: blocksize %lu not in 1024-65536 bytes, normally 4096 bytes\n",
+ progname, blocksize);
+ return EINVAL;
+ }
+
+ if ((blocksize & (blocksize - 1)) != 0) {
+ fprintf(stderr,
+ "%s: blocksize %lu not a power-of-two value\n",
+ progname, blocksize);
+ return EINVAL;
+ }
+ mop->mo_blocksize_kb = blocksize >> 10;
+ }
+
if (!(mop->mo_flags & MO_IS_LOOP)) {
- mop->mo_device_kb = get_device_size(mop->mo_device);
+ __u64 device_kb = get_device_size(mop->mo_device);
- if (mop->mo_device_kb == 0)
+ if (device_kb == 0)
return ENODEV;
/* Compare to real size */
- if (device_kb == 0 || device_kb > mop->mo_device_kb)
- device_kb = mop->mo_device_kb;
- else
+ if (mop->mo_device_kb == 0 || device_kb < mop->mo_device_kb)
mop->mo_device_kb = device_kb;
}
if (mop->mo_device_kb != 0) {
+ __u64 block_count;
+
if (mop->mo_device_kb < 32384) {
fprintf(stderr, "%s: size of filesystem must be larger "
"than 32MB, but is set to %lldKB\n",
progname, (long long)mop->mo_device_kb);
return EINVAL;
}
- block_count = mop->mo_device_kb / (L_BLOCK_SIZE >> 10);
- /* If the LUN size is just over 2^32 blocks, limit the
- * filesystem size to 2^32-1 blocks to avoid problems with
- * ldiskfs/mkfs not handling this size. Bug 22906 */
- if (block_count > 0xffffffffULL && block_count < 0x100002000ULL)
- block_count = 0xffffffffULL;
+ block_count = mop->mo_device_kb / mop->mo_blocksize_kb;
+ if (block_count > 0xffffffffULL) {
+ /* If the LUN size is just over 2^32 blocks, limit the
+ * filesystem size to 2^32-1 blocks to avoid problems
+ * with ldiskfs/mkfs not handling this well. b=22906
+ */
+ if (block_count < 0x100002000ULL)
+ mop->mo_device_kb =
+ 0xffffffffULL * mop->mo_blocksize_kb;
+ else
+ enable_64bit = true;
+ }
}
- if ((mop->mo_ldd.ldd_mount_type == LDD_MT_EXT3) ||
- (mop->mo_ldd.ldd_mount_type == LDD_MT_LDISKFS) ||
- (mop->mo_ldd.ldd_mount_type == LDD_MT_LDISKFS2)) {
- long inode_size = 0;
-
- /* Journal size in MB */
- if (strstr(mop->mo_mkfsopts, "-J") == NULL &&
- device_kb > 1024 * 1024) {
- /* Choose our own default journal size */
- long journal_mb = 0, max_mb;
-
- /* cap journal size at 4GB for MDT,
- * leave it at 400MB for OSTs. */
- if (IS_MDT(&mop->mo_ldd))
- max_mb = 4096;
- else if (IS_OST(&mop->mo_ldd))
- max_mb = 400;
- else /* Use mke2fs default size for MGS */
- max_mb = 0;
-
- /* Use at most 4% of device for journal */
- journal_mb = device_kb * 4 / (1024 * 100);
- if (journal_mb > max_mb)
- journal_mb = max_mb;
-
- if (journal_mb) {
- sprintf(buf, " -J size=%ld", journal_mb);
- strscat(mop->mo_mkfsopts, buf,
- sizeof(mop->mo_mkfsopts));
- }
+ if ((mop->mo_ldd.ldd_mount_type != LDD_MT_EXT3) &&
+ (mop->mo_ldd.ldd_mount_type != LDD_MT_LDISKFS) &&
+ (mop->mo_ldd.ldd_mount_type != LDD_MT_LDISKFS2)) {
+ fprintf(stderr, "%s: unsupported fs type: %d (%s)\n",
+ progname, mop->mo_ldd.ldd_mount_type,
+ MT_STR(&mop->mo_ldd));
+
+ return EINVAL;
+ }
+
+ /* Journal size in MB */
+ if (strstr(mop->mo_mkfsopts, "-J") == NULL &&
+ mop->mo_device_kb > 1024 * 1024) {
+ /* Choose our own default journal size */
+ long journal_mb = 0, max_mb;
+
+ /* cap journal size at 4GB for MDT, leave at 1GB for OSTs */
+ if (IS_MDT(&mop->mo_ldd))
+ max_mb = 4096;
+ else if (IS_OST(&mop->mo_ldd))
+ max_mb = 1024;
+ else /* Use mke2fs default size for MGS */
+ max_mb = 0;
+
+ /* Use at most 4% of device for journal */
+ journal_mb = mop->mo_device_kb * 4 / (1024 * 100);
+ if (journal_mb > max_mb)
+ journal_mb = max_mb;
+
+ if (journal_mb) {
+ snprintf(buf, sizeof(buf), " -J size=%ld", journal_mb);
+ strscat(mop->mo_mkfsopts, buf,
+ sizeof(mop->mo_mkfsopts));
}
+ }
- /*
- * The inode size is constituted by following elements
- * (assuming all files are in composite layout and has
- * 3 components):
- *
- * ldiskfs inode size: 156
- * extended attributes size, including:
- * ext4_xattr_header: 32
- * LOV EA size: 32(lov_comp_md_v1) +
- * 3 * 40(lov_comp_md_entry_v1) +
- * 3 * 32(lov_mds_md) +
- * stripes * 24(lov_ost_data) +
- * 16(xattr_entry) + 3(lov)
- * LMA EA size: 24(lustre_mdt_attrs) +
- * 16(xattr_entry) + 3(lma)
- * link EA size: 24(link_ea_header) + 18(link_ea_entry) +
- * (filename) + 16(xattr_entry) + 4(link)
- * and some margin for 4-byte alignment, ACLs and other EAs.
- *
- * If we say the average filename length is about 32 bytes,
- * the calculation looks like:
- * 156 + 32 + (32+3*(40 + 32)+24*N+19) + (24+19) +
- * (24+18+~32+20) + other <= 512*2^m, {m=0,1,2,3}
- */
- if (strstr(mop->mo_mkfsopts, "-I") == NULL) {
- if (IS_MDT(&mop->mo_ldd)) {
- if (mop->mo_stripe_count > 59)
- inode_size = 512; /* bz 7241 */
- /* see also "-i" below for EA blocks */
- else if (mop->mo_stripe_count > 16)
- inode_size = 2048;
- else
- inode_size = 1024;
- } else if (IS_OST(&mop->mo_ldd)) {
- /* We store MDS FID and necessary composite
- * layout information in the OST object EA. */
- inode_size = 512;
- }
+ /*
+ * The inode size is constituted by following elements
+ * (assuming all files are in composite layout and has
+ * 3 components):
+ *
+ * ldiskfs inode size: 160
+ * MDT extended attributes size, including:
+ * ext4_xattr_header: 32
+ * LOV EA size: 32(lov_comp_md_v1) +
+ * 3 * 40(lov_comp_md_entry_v1) +
+ * 3 * 32(lov_mds_md) +
+ * stripes * 24(lov_ost_data) +
+ * 16(xattr_entry) + 4("lov")
+ * LMA EA size: 24(lustre_mdt_attrs) +
+ * 16(xattr_entry) + 4("lma")
+ * SOM EA size: 24(lustre_som_attrs) +
+ * 16(xattr_entry) + 4("som")
+ * link EA size: 24(link_ea_header) + 18(link_ea_entry) +
+ * 16(filename) + 16(xattr_entry) + 4("link")
+ * and some margin for 4-byte alignment, ACLs and other EAs.
+ *
+ * If we say the average filename length is about 32 bytes,
+ * the calculation looks like:
+ * 160 + 32 + (32+3*(40+32)+24*stripes+20) + (24+20) + (24+20) +
+ * (24+20) + (~42+16+20) + other <= 512*2^m, {m=0,1,2,3}
+ */
+ if (strstr(mop->mo_mkfsopts, "-I") == NULL) {
+ if (IS_MDT(&mop->mo_ldd)) {
+ if (mop->mo_stripe_count > 59)
+ inode_size = 512; /* bz 7241 */
+ /* see also "-i" below for EA blocks */
+ else if (mop->mo_stripe_count > 16)
+ inode_size = 2048;
+ else
+ inode_size = 1024;
+ } else if (IS_OST(&mop->mo_ldd)) {
+ /* We store MDS FID and necessary composite
+ * layout information in the OST object EA:
+ * ldiskfs inode size: 160
+ * OST extended attributes size, including:
+ * ext4_xattr_header: 32
+ * LMA EA size: 24(lustre_mdt_attrs) +
+ * 16(xattr_entry) + 4("lma")
+ * FID EA size: 52(filter_fid) +
+ * 16(xattr_entry) + 4("fid")
+ * 160 + 32 + (24+20) + (52+20) = 308
+ */
+ inode_size = 512;
+ }
- if (inode_size > 0) {
- sprintf(buf, " -I %ld", inode_size);
- strscat(mop->mo_mkfsopts, buf,
- sizeof(mop->mo_mkfsopts));
- }
+ if (inode_size > 0) {
+ snprintf(buf, sizeof(buf), " -I %ld", inode_size);
+ strscat(mop->mo_mkfsopts, buf,
+ sizeof(mop->mo_mkfsopts));
}
+ }
- /* Bytes_per_inode: disk size / num inodes */
- if (strstr(mop->mo_mkfsopts, "-i") == NULL &&
- strstr(mop->mo_mkfsopts, "-N") == NULL) {
- long bytes_per_inode = 0;
-
- /* Allocate more inodes on MDT devices. There is
- * no data stored on the MDT, and very little extra
- * metadata beyond the inode. It could go down as
- * low as 1024 bytes, but this is conservative.
- * Account for external EA blocks for wide striping. */
- if (IS_MDT(&mop->mo_ldd)) {
- bytes_per_inode = inode_size + 1536;
-
- if (mop->mo_stripe_count > 59) {
- int extra = mop->mo_stripe_count * 24;
- extra = ((extra - 1) | 4095) + 1;
- bytes_per_inode += extra;
- }
- }
+ /* Bytes_per_inode: disk size / num inodes */
+ if (strstr(mop->mo_mkfsopts, "-i") == NULL &&
+ strstr(mop->mo_mkfsopts, "-N") == NULL) {
+ long bytes_per_inode = 0;
- /* Allocate fewer inodes on large OST devices. Most
- * filesystems can be much more aggressive than even
- * this, but it is impossible to know in advance. */
- if (IS_OST(&mop->mo_ldd)) {
- /* OST > 16TB assume average file size 1MB */
- if (device_kb > (16ULL << 30))
- bytes_per_inode = 1024 * 1024;
- /* OST > 4TB assume average file size 512kB */
- else if (device_kb > (4ULL << 30))
- bytes_per_inode = 512 * 1024;
- /* OST > 1TB assume average file size 256kB */
- else if (device_kb > (1ULL << 30))
- bytes_per_inode = 256 * 1024;
- /* OST > 10GB assume average file size 64kB,
- * plus a bit so that inodes will fit into a
- * 256x flex_bg without overflowing */
- else if (device_kb > (10ULL << 20))
- bytes_per_inode = 69905;
- }
+ /* Allocate more inodes on MDT devices. There is
+ * no data stored on the MDT, and very little extra
+ * metadata beyond the inode. It could go down as
+ * low as 1024 bytes, but this is conservative.
+ * Account for external EA blocks for wide striping.
+ */
+ if (IS_MDT(&mop->mo_ldd)) {
+ bytes_per_inode = inode_size + 1536;
+
+ if (mop->mo_stripe_count > 59) {
+ int extra = mop->mo_stripe_count * 24;
- if (bytes_per_inode > 0) {
- sprintf(buf, " -i %ld", bytes_per_inode);
- strscat(mop->mo_mkfsopts, buf,
- sizeof(mop->mo_mkfsopts));
+ extra = ((extra - 1) | 4095) + 1;
+ bytes_per_inode += extra;
}
}
- if (verbose < 2) {
- strscat(mop->mo_mkfsopts, " -q",
+ /* Allocate fewer inodes on large OST devices. Most
+ * filesystems can be much more aggressive than even
+ * this, but it is impossible to know in advance.
+ */
+ if (IS_OST(&mop->mo_ldd)) {
+ /* OST > 16TB assume average file size 1MB */
+ if (mop->mo_device_kb > (16ULL << 30))
+ bytes_per_inode = 1024 * 1024;
+ /* OST > 4TB assume average file size 512kB */
+ else if (mop->mo_device_kb > (4ULL << 30))
+ bytes_per_inode = 512 * 1024;
+ /* OST > 1TB assume average file size 256kB */
+ else if (mop->mo_device_kb > (1ULL << 30))
+ bytes_per_inode = 256 * 1024;
+ /* OST > 10GB assume average file size 64kB,
+ * plus a bit so that inodes will fit into a
+ * 256x flex_bg without overflowing.
+ */
+ else if (mop->mo_device_kb > (10ULL << 20))
+ bytes_per_inode = 69905;
+ }
+
+ if (bytes_per_inode > 0) {
+ snprintf(buf, sizeof(buf), " -i %ld", bytes_per_inode);
+ strscat(mop->mo_mkfsopts, buf,
sizeof(mop->mo_mkfsopts));
+ mop->mo_inode_size = bytes_per_inode;
}
+ }
- /* start handle -O mkfs options */
- if ((start = strstr(mop->mo_mkfsopts, "-O")) != NULL) {
- if (strstr(start + 2, "-O") != NULL) {
- fprintf(stderr,
- "%s: don't specify multiple -O options\n",
- progname);
- return EINVAL;
- }
- start = moveopts_to_end(start);
- maxbuflen = sizeof(mop->mo_mkfsopts) -
- (start - mop->mo_mkfsopts) - strlen(start);
- ret = enable_default_ext4_features(mop, start, maxbuflen, 1);
- } else {
- start = mop->mo_mkfsopts + strlen(mop->mo_mkfsopts),
- maxbuflen = sizeof(mop->mo_mkfsopts) -
- strlen(mop->mo_mkfsopts);
- ret = enable_default_ext4_features(mop, start, maxbuflen, 0);
+ if (verbose < 2)
+ strscat(mop->mo_mkfsopts, " -q", sizeof(mop->mo_mkfsopts));
+
+ /* start handle -O mkfs options */
+ start = strstr(mop->mo_mkfsopts, "-O");
+ if (start) {
+ if (strstr(start + 2, "-O") != NULL) {
+ fprintf(stderr,
+ "%s: don't specify multiple -O options\n",
+ progname);
+ return EINVAL;
}
- if (ret)
- return ret;
- /* end handle -O mkfs options */
-
- /* start handle -E mkfs options */
- if ((start = strstr(mop->mo_mkfsopts, "-E")) != NULL) {
- if (strstr(start + 2, "-E") != NULL) {
- fprintf(stderr,
- "%s: don't specify multiple -E options\n",
- progname);
- return EINVAL;
- }
- start = moveopts_to_end(start);
- maxbuflen = sizeof(mop->mo_mkfsopts) -
- (start - mop->mo_mkfsopts) - strlen(start);
- ext_opts = 1;
- } else {
- start = mop->mo_mkfsopts + strlen(mop->mo_mkfsopts);
- maxbuflen = sizeof(mop->mo_mkfsopts) -
- strlen(mop->mo_mkfsopts);
+ start = moveopts_to_end(start);
+ maxbuflen = sizeof(mop->mo_mkfsopts) -
+ (start - mop->mo_mkfsopts) - strlen(start);
+ ret = enable_default_ext4_features(mop, start, maxbuflen, 1);
+ } else {
+ start = mop->mo_mkfsopts + strlen(mop->mo_mkfsopts);
+ maxbuflen = sizeof(mop->mo_mkfsopts) - strlen(mop->mo_mkfsopts);
+ ret = enable_default_ext4_features(mop, start, maxbuflen, 0);
+ }
+ if (ret)
+ return ret;
+ /* end handle -O mkfs options */
+
+ /* start handle -E mkfs options */
+ start = strstr(mop->mo_mkfsopts, "-E");
+ if (start) {
+ if (strstr(start + 2, "-E") != NULL) {
+ fprintf(stderr,
+ "%s: don't specify multiple -E options\n",
+ progname);
+ return EINVAL;
}
+ start = moveopts_to_end(start);
+ maxbuflen = sizeof(mop->mo_mkfsopts) -
+ (start - mop->mo_mkfsopts) - strlen(start);
+ ext_opts = 1;
+ } else {
+ start = mop->mo_mkfsopts + strlen(mop->mo_mkfsopts);
+ maxbuflen = sizeof(mop->mo_mkfsopts) - strlen(mop->mo_mkfsopts);
+ }
- /* In order to align the filesystem metadata on 1MB boundaries,
- * give a resize value that will reserve a power-of-two group
- * descriptor blocks, but leave one block for the superblock.
- * Only useful for filesystems with < 2^32 blocks due to resize
- * limitations. */
- if (strstr(mop->mo_mkfsopts, "meta_bg") == NULL &&
- IS_OST(&mop->mo_ldd) && mop->mo_device_kb > 100 * 1024 &&
- mop->mo_device_kb * 1024 / L_BLOCK_SIZE <= 0xffffffffULL) {
- unsigned group_blocks = L_BLOCK_SIZE * 8;
- unsigned desc_per_block = L_BLOCK_SIZE / 32;
- unsigned resize_blks;
-
- resize_blks = (1ULL<<32) - desc_per_block*group_blocks;
- snprintf(buf, sizeof(buf), "%u", resize_blks);
- append_unique(start, ext_opts ? "," : " -E ",
- "resize", buf, maxbuflen);
- ext_opts = 1;
- }
+ /* In order to align the filesystem metadata on 1MB boundaries,
+ * give a resize value that will reserve a power-of-two group
+ * descriptor blocks, but leave one block for the superblock.
+ * Only useful for filesystems with < 2^32 blocks due to resize
+ * limitations.
+ */
+ if (!enable_64bit && strstr(mop->mo_mkfsopts, "meta_bg") == NULL &&
+ IS_OST(&mop->mo_ldd) && mop->mo_device_kb > 100 * 1024) {
+ unsigned int group_blocks = mop->mo_blocksize_kb * 8192;
+ unsigned int desc_per_block = mop->mo_blocksize_kb * 1024 / 32;
+ unsigned int resize_blks;
+
+ resize_blks = (1ULL<<32) - desc_per_block*group_blocks;
+ snprintf(buf, sizeof(buf), "%u", resize_blks);
+ append_unique(start, ext_opts ? "," : " -E ",
+ "resize", buf, maxbuflen);
+ ext_opts = 1;
+ }
- /* Avoid zeroing out the full journal - speeds up mkfs */
- if (is_e2fsprogs_feature_supp("-E lazy_journal_init") == 0)
- append_unique(start, ext_opts ? "," : " -E ",
- "lazy_journal_init", NULL, maxbuflen);
- /* end handle -E mkfs options */
+ /* Avoid zeroing out the full journal - speeds up mkfs */
+ if (is_e2fsprogs_feature_supp("-E lazy_journal_init"))
+ append_unique(start, ext_opts ? "," : " -E ",
+ "lazy_journal_init", NULL, maxbuflen);
+ /* end handle -E mkfs options */
- /* Allow reformat of full devices (as opposed to
- partitions.) We already checked for mounted dev. */
- strscat(mop->mo_mkfsopts, " -F", sizeof(mop->mo_mkfsopts));
+ /* Allow reformat of full devices (as opposed to partitions).
+ * We already checked for mounted dev.
+ */
+ strscat(mop->mo_mkfsopts, " -F", sizeof(mop->mo_mkfsopts));
- snprintf(mkfs_cmd, sizeof(mkfs_cmd),
- "%s -j -b %d -L %s ", MKE2FS, L_BLOCK_SIZE,
- mop->mo_ldd.ldd_svname);
- } else {
- fprintf(stderr,"%s: unsupported fs type: %d (%s)\n",
- progname, mop->mo_ldd.ldd_mount_type,
- MT_STR(&mop->mo_ldd));
- return EINVAL;
- }
+ snprintf(mkfs_cmd, sizeof(mkfs_cmd), "%s -j -b %d -L %s ", MKE2FS,
+ mop->mo_blocksize_kb * 1024, mop->mo_ldd.ldd_svname);
/* For loop device format the dev, not the filename */
dev = mop->mo_device;
vprint("formatting backing filesystem %s on %s\n",
MT_STR(&mop->mo_ldd), dev);
vprint("\ttarget name %s\n", mop->mo_ldd.ldd_svname);
- vprint("\t4k blocks %ju\n", (uintmax_t)block_count);
+ vprint("\tkilobytes %llu\n", mop->mo_device_kb);
vprint("\toptions %s\n", mop->mo_mkfsopts);
/* mkfs_cmd's trailing space is important! */
strscat(mkfs_cmd, mop->mo_mkfsopts, sizeof(mkfs_cmd));
strscat(mkfs_cmd, " ", sizeof(mkfs_cmd));
strscat(mkfs_cmd, dev, sizeof(mkfs_cmd));
- if (block_count != 0) {
- snprintf(buf, sizeof(buf), " %ju",
- (uintmax_t)block_count);
+ if (mop->mo_device_kb != 0) {
+ snprintf(buf, sizeof(buf), " %lluk",
+ (unsigned long long)mop->mo_device_kb);
strscat(mkfs_cmd, buf, sizeof(mkfs_cmd));
}
return rc < 0 ? errno : 0;
}
-static int set_blockdev_scheduler(const char *path, const char *scheduler)
+static int tune_md_stripe_cache_size(const char *sys_path,
+ struct mount_opts *mop)
{
- char buf[PATH_MAX], *s, *e, orig_sched[50];
+ char path[PATH_MAX];
+ unsigned long old_stripe_cache_size;
+ unsigned long new_stripe_cache_size;
+ char buf[3 * sizeof(old_stripe_cache_size) + 2];
int rc;
- /* Before setting the scheduler, we need to check to see if it's
- * already set to "noop". If it is, we don't want to override
- * that setting. If it's set to anything other than "noop", set
- * the scheduler to what has been passed in. */
+ if (mop->mo_md_stripe_cache_size <= 0)
+ return 0;
+
+ new_stripe_cache_size = mop->mo_md_stripe_cache_size;
+ snprintf(path, sizeof(path), "%s/%s", sys_path, STRIPE_CACHE_SIZE);
rc = read_file(path, buf, sizeof(buf));
- if (rc) {
+ if (rc != 0) {
if (verbose)
- fprintf(stderr, "%s: cannot open '%s': %s\n",
- progname, path, strerror(errno));
+ fprintf(stderr, "warning: cannot read '%s': %s\n",
+ path, strerror(errno));
return rc;
}
- /* The expected format of buf: noop anticipatory deadline [cfq] */
- s = strchr(buf, '[');
- e = strchr(buf, ']');
-
- /* If the format is not what we expect. Play it safe and error out. */
- if (s == NULL || e == NULL) {
- if (verbose)
- fprintf(stderr, "%s: cannot parse scheduler "
- "options for '%s'\n", progname, path);
- return -EINVAL;
- }
-
- snprintf(orig_sched, e - s, "%s", s + 1);
+ old_stripe_cache_size = strtoul(buf, NULL, 0);
+ if (old_stripe_cache_size == 0 || old_stripe_cache_size == ULONG_MAX)
+ return EINVAL;
- if (strcmp(orig_sched, "noop") == 0 ||
- strcmp(orig_sched, scheduler) == 0)
+ if (new_stripe_cache_size <= old_stripe_cache_size)
return 0;
- rc = write_file(path, scheduler);
- if (rc) {
+ snprintf(buf, sizeof(buf), "%lu", new_stripe_cache_size);
+ rc = write_file(path, buf);
+ if (rc != 0) {
if (verbose)
- fprintf(stderr, "%s: cannot set scheduler on "
- "'%s': %s\n", progname, path,
- strerror(errno));
+ fprintf(stderr, "warning: cannot write '%s': %s\n",
+ path, strerror(errno));
return rc;
- } else {
- fprintf(stderr, "%s: change scheduler of %s from %s to %s\n",
- progname, path, orig_sched, scheduler);
}
- return rc;
+ return 0;
}
-/* This is to tune the kernel for good SCSI performance.
- * For that we set the value of /sys/block/{dev}/queue/max_sectors_kb
- * to the value of /sys/block/{dev}/queue/max_hw_sectors_kb */
-static int set_blockdev_tunables(char *source, struct mount_opts *mop)
+static int tune_max_sectors_kb(const char *sys_path, struct mount_opts *mop)
{
- glob_t glob_info = { 0 };
- struct stat stat_buf;
- char *chk_major, *chk_minor;
- char *savept = NULL, *dev;
- char *ret_path;
- char buf[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
- char real_path[PATH_MAX] = {'\0'};
- int i, rc = 0;
- int major, minor;
- char *slave = NULL;
-
- if (!source)
- return -EINVAL;
-
- ret_path = realpath(source, real_path);
- if (ret_path == NULL) {
- if (verbose)
- fprintf(stderr, "warning: %s: cannot resolve: %s\n",
- source, strerror(errno));
- return -EINVAL;
+ char path[PATH_MAX];
+ unsigned long max_hw_sectors_kb;
+ unsigned long old_max_sectors_kb;
+ unsigned long new_max_sectors_kb;
+ char buf[3 * sizeof(old_max_sectors_kb) + 2];
+ int rc;
+
+ if (mop->mo_max_sectors_kb >= 0) {
+ new_max_sectors_kb = mop->mo_max_sectors_kb;
+ goto have_new_max_sectors_kb;
}
- if (strncmp(real_path, "/dev/loop", 9) == 0)
+ snprintf(path, sizeof(path), "%s/%s", sys_path, MAX_HW_SECTORS_KB_PATH);
+ rc = read_file(path, buf, sizeof(buf));
+ if (rc != 0) {
+ /* No MAX_HW_SECTORS_KB_PATH isn't necessary an
+ * error for some devices. */
return 0;
+ }
- if ((real_path[0] != '/') && (strpbrk(real_path, ",:") != NULL))
+ max_hw_sectors_kb = strtoul(buf, NULL, 0);
+ if (max_hw_sectors_kb == 0 || max_hw_sectors_kb == ULLONG_MAX) {
+ /* No digits at all or something weird. */
return 0;
+ }
- snprintf(path, sizeof(path), "/sys/block%s", real_path + 4);
- if (access(path, X_OK) == 0)
- goto set_params;
+ new_max_sectors_kb = max_hw_sectors_kb;
- /* The name of the device say 'X' specified in /dev/X may not
- * match any entry under /sys/block/. In that case we need to
- * match the major/minor number to find the entry under
- * sys/block corresponding to /dev/X */
+ /* Don't increase IO request size limit past 16MB. It is
+ * about PTLRPC_MAX_BRW_SIZE, but that isn't in a public
+ * header. Note that even though the block layer allows
+ * larger values, setting max_sectors_kb = 32768 causes
+ * crashes (LU-6974). */
+ if (new_max_sectors_kb > 16 * 1024)
+ new_max_sectors_kb = 16 * 1024;
- /* Don't chop tail digit on /dev/mapper/xxx, LU-478 */
- if (strncmp(real_path, "/dev/mapper", 11) != 0) {
- dev = real_path + strlen(real_path);
- while (--dev > real_path && isdigit(*dev))
- *dev = 0;
+have_new_max_sectors_kb:
+ snprintf(path, sizeof(path), "%s/%s", sys_path, MAX_SECTORS_KB_PATH);
+ rc = read_file(path, buf, sizeof(buf));
+ if (rc != 0) {
+ /* No MAX_SECTORS_KB_PATH isn't necessary an error for
+ * some devices. */
+ return 0;
+ }
- if (strncmp(real_path, "/dev/md", 7) == 0 && dev[0] == 'p')
- *dev = 0;
+ old_max_sectors_kb = strtoul(buf, NULL, 0);
+ if (old_max_sectors_kb == 0 || old_max_sectors_kb == ULLONG_MAX) {
+ /* No digits at all or something weird. */
+ return 0;
}
- rc = stat(real_path, &stat_buf);
- if (rc) {
+ if (new_max_sectors_kb <= old_max_sectors_kb)
+ return 0;
+
+ snprintf(buf, sizeof(buf), "%lu", new_max_sectors_kb);
+ rc = write_file(path, buf);
+ if (rc != 0) {
if (verbose)
- fprintf(stderr, "warning: %s, device %s stat failed\n",
- strerror(errno), real_path);
+ fprintf(stderr, "warning: cannot write '%s': %s\n",
+ path, strerror(errno));
return rc;
}
- major = major(stat_buf.st_rdev);
- minor = minor(stat_buf.st_rdev);
- rc = glob("/sys/block/*", GLOB_NOSORT, NULL, &glob_info);
- if (rc) {
+ fprintf(stderr, "%s: increased '%s' from %lu to %lu\n",
+ progname, path, old_max_sectors_kb, new_max_sectors_kb);
+
+ return 0;
+}
+
+static int tune_block_dev_scheduler(const char *sys_path, const char *new_sched)
+{
+ char path[PATH_MAX];
+ char buf[PATH_MAX];
+ char *s, *e;
+ char *old_sched;
+ int rc;
+
+ /* Before setting the scheduler, we need to check to see if
+ * it's already set to "noop". If it is then we don't want to
+ * override that setting. If it's set to anything other than
+ * "noop" then set the scheduler to what has been passed
+ * in. */
+
+ snprintf(path, sizeof(path), "%s/%s", sys_path, SCHEDULER_PATH);
+ rc = read_file(path, buf, sizeof(buf));
+ if (rc != 0) {
if (verbose)
- fprintf(stderr, "warning: failed to read entries under "
- "/sys/block\n");
- globfree(&glob_info);
+ fprintf(stderr, "%s: cannot read '%s': %s\n",
+ progname, path, strerror(errno));
+
return rc;
}
- for (i = 0; i < glob_info.gl_pathc; i++){
- snprintf(path, sizeof(path), "%s/dev", glob_info.gl_pathv[i]);
-
- rc = read_file(path, buf, sizeof(buf));
- if (rc)
- continue;
+ /* The expected format of buf: noop anticipatory deadline [cfq] */
+ s = strchr(buf, '[');
+ e = strchr(buf, ']');
- if (buf[strlen(buf) - 1] == '\n')
- buf[strlen(buf) - 1] = '\0';
+ /* If the format is not what we expect then be safe and error out. */
+ if (s == NULL || e == NULL || !(s < e)) {
+ if (verbose)
+ fprintf(stderr,
+ "%s: cannot parse scheduler options for '%s'\n",
+ progname, path);
- chk_major = strtok_r(buf, ":", &savept);
- chk_minor = savept;
- if (chk_major != NULL && major == atoi(chk_major) &&
- chk_minor != NULL && minor == atoi(chk_minor))
- break;
+ return EINVAL;
}
- if (i == glob_info.gl_pathc) {
+ old_sched = s + 1;
+ *e = '\0';
+
+ if (strcmp(old_sched, "noop") == 0 ||
+ strcmp(old_sched, "deadline") == 0 ||
+ strcmp(old_sched, "mq-deadline") == 0 ||
+ strstr(old_sched, new_sched) == 0)
+ return 0;
+
+ rc = write_file(path, new_sched);
+ if (rc != 0) {
if (verbose)
- fprintf(stderr,"warning: device %s does not match any "
- "entry under /sys/block\n", real_path);
- globfree(&glob_info);
- return -EINVAL;
+ fprintf(stderr,
+ "%s: cannot set scheduler on '%s': %s\n",
+ progname, path, strerror(errno));
+ return rc;
}
- /* Chop off "/dev" from path we found */
- path[strlen(glob_info.gl_pathv[i])] = '\0';
- globfree(&glob_info);
+ fprintf(stderr, "%s: changed scheduler of '%s' from %s to %s\n",
+ progname, path, old_sched, new_sched);
-set_params:
- if (strncmp(real_path, "/dev/md", 7) == 0) {
- snprintf(real_path, sizeof(real_path), "%s/%s", path,
- STRIPE_CACHE_SIZE);
+ return 0;
+}
- rc = read_file(real_path, buf, sizeof(buf));
- if (rc) {
- if (verbose)
- fprintf(stderr, "warning: opening %s: %s\n",
- real_path, strerror(errno));
- return 0;
- }
+static int tune_block_dev(const char *src, struct mount_opts *mop);
- if (atoi(buf) >= mop->mo_md_stripe_cache_size)
+static int tune_block_dev_slaves(const char *sys_path, struct mount_opts *mop)
+{
+ char slaves_path[PATH_MAX];
+ DIR *slaves_dir;
+ struct dirent *d;
+ int rc = 0;
+
+ snprintf(slaves_path, sizeof(slaves_path), "%s/slaves", sys_path);
+ slaves_dir = opendir(slaves_path);
+ if (slaves_dir == NULL) {
+ if (errno == ENOENT)
return 0;
- if (strlen(buf) - 1 > 0) {
- snprintf(buf, sizeof(buf), "%d",
- mop->mo_md_stripe_cache_size);
- rc = write_file(real_path, buf);
- if (rc != 0 && verbose)
- fprintf(stderr, "warning: opening %s: %s\n",
- real_path, strerror(errno));
- }
- /* Return since raid and disk tunables are different */
- return rc;
+ return errno;
}
- if (mop->mo_max_sectors_kb >= 0) {
- snprintf(buf, sizeof(buf), "%d", mop->mo_max_sectors_kb);
- } else {
- snprintf(real_path, sizeof(real_path), "%s/%s", path,
- MAX_HW_SECTORS_KB_PATH);
- rc = read_file(real_path, buf, sizeof(buf));
- if (rc) {
- if (verbose)
- fprintf(stderr, "warning: opening %s: %s\n",
- real_path, strerror(errno));
- /* No MAX_HW_SECTORS_KB_PATH isn't necessary an
- * error for some device. */
- goto subdevs;
- }
+ while ((d = readdir(slaves_dir)) != NULL) {
+ char path[PATH_MAX * 2];
+ int rc2;
+
+ if (d->d_type != DT_LNK)
+ continue;
+
+ snprintf(path, sizeof(path), "/dev/%s", d->d_name);
+ rc2 = tune_block_dev(path, mop);
+ if (rc2 != 0)
+ rc = rc2;
}
- if (strlen(buf) - 1 > 0) {
- char oldbuf[32] = "", *end = NULL;
- unsigned long long oldval, newval;
-
- snprintf(real_path, sizeof(real_path), "%s/%s", path,
- MAX_SECTORS_KB_PATH);
- rc = read_file(real_path, oldbuf, sizeof(oldbuf));
- /* Only set new parameter if different from the old one. */
- if (rc != 0 || strcmp(oldbuf, buf) == 0) {
- /* No MAX_SECTORS_KB_PATH isn't necessary an
- * error for some device. */
- goto subdevs;
- }
+ closedir(slaves_dir);
- newval = strtoull(buf, &end, 0);
- if (newval == 0 || newval == ULLONG_MAX || end == buf)
- goto subdevs;
-
- /* Don't increase IO request size limit past 16MB. It is about
- * PTLRPC_MAX_BRW_SIZE, but that isn't in a public header.
- * Note that even though the block layer allows larger values,
- * setting max_sectors_kb = 32768 causes crashes (LU-6974). */
- if (mop->mo_max_sectors_kb < 0 && newval > 16 * 1024) {
- newval = 16 * 1024;
- snprintf(buf, sizeof(buf), "%llu", newval);
- }
+ return rc;
+}
- oldval = strtoull(oldbuf, &end, 0);
- /* Don't shrink the current limit. */
- if (mop->mo_max_sectors_kb < 0 && oldval != ULLONG_MAX &&
- newval <= oldval)
- goto subdevs;
-
- rc = write_file(real_path, buf);
- if (rc != 0) {
- if (verbose)
- fprintf(stderr, "warning: writing to %s: %s\n",
- real_path, strerror(errno));
- /* No MAX_SECTORS_KB_PATH isn't necessary an
- * error for some device. */
- goto subdevs;
- }
- fprintf(stderr, "%s: increased %s from %s to %s\n",
- progname, real_path, oldbuf, buf);
+/* This is to tune the kernel for good SCSI performance.
+ * For that we set the value of /sys/block/{dev}/queue/max_sectors_kb
+ * to the value of /sys/block/{dev}/queue/max_hw_sectors_kb */
+static int tune_block_dev(const char *src, struct mount_opts *mop)
+{
+ struct stat st;
+ char sys_path[PATH_MAX];
+ char partition_path[PATH_MAX + sizeof("partition")];
+ char *real_sys_path = NULL;
+ int rc;
+
+ /*
+ * Don't apply block device tuning for MDT or MGT devices,
+ * since we don't need huge IO sizes to get good performance
+ */
+ if (!IS_OST(&mop->mo_ldd))
+ return 0;
+
+ if (src == NULL)
+ return EINVAL;
+
+ rc = stat(src, &st);
+ if (rc < 0) {
+ if (verbose)
+ fprintf(stderr, "warning: cannot stat '%s': %s\n",
+ src, strerror(errno));
+ return errno;
}
-subdevs:
- /* Purposely ignore errors reported from set_blockdev_scheduler.
- * The worst that will happen is a block device with an "incorrect"
- * scheduler. */
- snprintf(real_path, sizeof(real_path), "%s/%s", path, SCHEDULER_PATH);
- set_blockdev_scheduler(real_path, DEFAULT_SCHEDULER);
-
- /* if device is multipath device, tune its slave devices */
- glob_info.gl_pathc = 0;
- glob_info.gl_offs = 0;
- snprintf(real_path, sizeof(real_path), "%s/slaves/*", path);
- rc = glob(real_path, GLOB_NOSORT, NULL, &glob_info);
-
- for (i = 0; rc == 0 && i < glob_info.gl_pathc; i++) {
- slave = basename(glob_info.gl_pathv[i]);
- snprintf(real_path, sizeof(real_path), "/dev/%s", slave);
- rc = set_blockdev_tunables(real_path, mop);
+ if (!S_ISBLK(st.st_mode))
+ return 0;
+
+ if (major(st.st_rdev) == LOOP_MAJOR)
+ return 0;
+
+ snprintf(sys_path, sizeof(sys_path), "/sys/dev/block/%u:%u",
+ major(st.st_rdev), minor(st.st_rdev));
+
+ snprintf(partition_path, sizeof(partition_path), "%s/partition",
+ sys_path);
+
+ rc = access(partition_path, F_OK);
+ if (rc < 0) {
+ if (errno == ENOENT)
+ goto have_whole_dev;
+
+ if (verbose)
+ fprintf(stderr, "warning: cannot access '%s': %s\n",
+ partition_path, strerror(errno));
+ rc = errno;
+ goto out;
}
- if (rc == GLOB_NOMATCH) {
- /* no slave device is not an error */
- rc = 0;
- } else if (rc && verbose) {
- if (slave == NULL) {
- fprintf(stderr, "warning: %s, failed to read"
- " entries under %s/slaves\n",
- strerror(errno), path);
- } else {
- fprintf(stderr, "unable to set tunables for"
- " slave device %s (slave would be"
- " unable to handle IO request from"
- " master %s)\n",
- real_path, source);
- }
+ snprintf(sys_path, sizeof(sys_path), "/sys/dev/block/%u:%u/..",
+ major(st.st_rdev), minor(st.st_rdev));
+
+have_whole_dev:
+ /* Since we recurse on slave devices we resolve the sys_path to
+ * avoid path buffer overflows. */
+ real_sys_path = realpath(sys_path, NULL);
+ if (real_sys_path == NULL) {
+ if (verbose)
+ fprintf(stderr,
+ "warning: cannot resolve '%s': %s\n",
+ sys_path, strerror(errno));
+ rc = errno;
+ goto out;
+ }
+
+ if (major(st.st_rdev) == MD_MAJOR) {
+ rc = tune_md_stripe_cache_size(real_sys_path, mop);
+ } else {
+ /* Ignore errors from tune_max_sectors_kb() and
+ * tune_scheduler(). The worst that will happen is a block
+ * device with an "incorrect" scheduler. */
+ tune_max_sectors_kb(real_sys_path, mop);
+ tune_block_dev_scheduler(real_sys_path, DEFAULT_SCHEDULER);
+
+ /* If device is multipath device then tune its slave
+ * devices. */
+ rc = tune_block_dev_slaves(real_sys_path, mop);
}
- globfree(&glob_info);
+
+out:
+ free(real_sys_path);
return rc;
}
int ldiskfs_tune_lustre(char *dev, struct mount_opts *mop)
{
- return set_blockdev_tunables(dev, mop);
+ return tune_block_dev(dev, mop);
}
int ldiskfs_label_lustre(struct mount_opts *mop)
return ret;
}
-#ifdef HAVE_SELINUX
- /*
- * Append file context to mount options if SE Linux is enabled
- */
- if (is_selinux_enabled() > 0)
- append_context_for_mount(mntpt, mop);
-#endif
-
if (mop->mo_flags & MO_IS_LOOP)
dev = mop->mo_loopdev;
else
char cmd[512];
int cmdsz = sizeof(cmd), ret;
- if (is_e2fsprogs_feature_supp("-O quota") != 0) {
+ if (!is_e2fsprogs_feature_supp("-O quota")) {
fprintf(stderr, "%s: \"-O quota\" is is not supported by "
"current e2fsprogs\n", progname);
return EINVAL;
dev = mop->mo_loopdev;
/* Quota feature is already enabled? */
- if (is_feature_enabled("quota", dev)) {
+ if (!backfs)
+ ext2fs_open(dev, open_flags, 0, 0, unix_io_manager, &backfs);
+ if (backfs && ext2fs_has_feature_quota(backfs->super)) {
vprint("Quota feature is already enabled.\n");
return 0;
}
void ldiskfs_fini(void)
{
- return;
+ if (backfs) {
+ ext2fs_close(backfs);
+ backfs = NULL;
+ }
}
#ifndef PLUGIN_DIR