* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, Whamcloud, Inc.
+ * Copyright (c) 2012, 2013, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
+#include "mount_utils.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <lustre_param.h>
#include <lnet/lnetctl.h>
#include <lustre_ver.h>
-#include "mount_utils.h"
+
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
#define MAX_HW_SECTORS_KB_PATH "queue/max_hw_sectors_kb"
#define MAX_SECTORS_KB_PATH "queue/max_sectors_kb"
+#define SCHEDULER_PATH "queue/scheduler"
#define STRIPE_CACHE_SIZE "md/stripe_cache_size"
+#define DEFAULT_SCHEDULER "deadline"
+
extern char *progname;
#define L_BLOCK_SIZE 4096
#define DUMMY_FILE_NAME_LEN 25
#define EXT3_DIRENT_SIZE DUMMY_FILE_NAME_LEN
+/*
+ * Concatenate context of the temporary mount point iff selinux is enabled
+ */
+#ifdef HAVE_SELINUX
+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) {
+ strcat(mop->mo_ldd.ldd_mount_opts, ",context=");
+ strcat(mop->mo_ldd.ldd_mount_opts, fcontext);
+ freecon(fcontext);
+ }
+}
+#endif
+
/* Write the server config files */
int ldiskfs_write_ldd(struct mkfs_opts *mop)
{
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;
if (num_read < 1 && ferror(filep)) {
fprintf(stderr, "%s: Unable to read from file %s: %s\n",
progname, filepnm, strerror(errno));
- goto out_close;
}
+ fclose(filep);
}
-out_close:
- fclose(filep);
snprintf(cmd, cmdsz, "rm -rf %s", tmpdir);
run_command(cmd, cmdsz);
pclose(fp);
return 1;
}
- i = fread(debugfs_cmd, 1, sizeof(debugfs_cmd), fp);
+ i = fread(debugfs_cmd, 1, sizeof(debugfs_cmd) - 1, fp);
if (i) {
debugfs_cmd[i] = 0;
fprintf(stderr, "%s", debugfs_cmd);
fprintf(stderr, "%s: %s\n", progname, strerror(errno));
return 0;
}
- ret = fread(supp_features, 1, sizeof(supp_features), fp);
+ ret = fread(supp_features, 1, sizeof(supp_features) - 1, fp);
+ supp_features[ret] = '\0';
fclose(fp);
}
if (ret > 0 && strstr(supp_features,
return 0;
}
-int read_file(char *path, char *buf, int size)
+int read_file(const char *path, char *buf, int size)
{
FILE *fd;
return 0;
}
-int write_file(char *path, char *buf)
+int write_file(const char *path, const char *buf)
{
FILE *fd;
return 0;
}
+int set_blockdev_scheduler(const char *path, const char *scheduler)
+{
+ char buf[PATH_MAX], *c;
+ 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. */
+
+ rc = read_file(path, buf, sizeof(buf));
+ if (rc) {
+ if (verbose)
+ fprintf(stderr, "%s: cannot open '%s': %s\n",
+ progname, path, strerror(errno));
+ return rc;
+ }
+
+ /* The expected format of buf: noop anticipatory deadline [cfq] */
+ c = strchr(buf, '[');
+
+ /* If c is NULL, the format is not what we expect. Play it safe
+ * and error out. */
+ if (c == NULL) {
+ if (verbose)
+ fprintf(stderr, "%s: cannot parse scheduler "
+ "options for '%s'\n", progname, path);
+ return -EINVAL;
+ }
+
+ if (strncmp(c+1, "noop", 4) == 0)
+ return 0;
+
+ rc = write_file(path, scheduler);
+ if (rc) {
+ if (verbose)
+ fprintf(stderr, "%s: cannot set scheduler on "
+ "'%s': %s\n", progname, path,
+ strerror(errno));
+ return rc;
+ }
+
+ return rc;
+}
+
/* 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 */
}
}
+ /* 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 (fan_out) {
char *slave = NULL;
glob_info.gl_pathc = 0;
char label_cmd[PATH_MAX];
int rc;
- snprintf(label_cmd, sizeof(label_cmd), E2LABEL" %s %s",
- mop->mo_source, mop->mo_ldd.ldd_svname);
+ snprintf(label_cmd, sizeof(label_cmd),
+ TUNE2FS" -f -L '%s' '%s' >/dev/null 2>&1",
+ mop->mo_ldd.ldd_svname, mop->mo_source);
rc = run_command(label_cmd, sizeof(label_cmd));
return rc;
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 -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';
+ fclose(fp);
+
+ if (strstr(enabled_features, feature))
+ return 1;
+ return 0;
+}
+
+/* Enable quota accounting */
+int ldiskfs_enable_quota(struct mkfs_opts *mop)
+{
+ char *dev;
+ char cmd[512];
+ int cmdsz = sizeof(cmd), ret;
+
+ if (is_e2fsprogs_feature_supp("-O quota") != 0) {
+ fprintf(stderr, "%s: \"-O quota\" is is not supported by "
+ "current e2fsprogs\n", progname);
+ return EINVAL;
+ }
+
+ dev = mop->mo_device;
+ if (mop->mo_flags & MO_IS_LOOP)
+ dev = mop->mo_loopdev;
+
+ /* Quota feature is already enabled? */
+ if (is_feature_enabled("quota", dev)) {
+ vprint("Quota feature is already enabled.\n");
+ return 0;
+ }
+
+ /* Turn on quota feature by "tune2fs -O quota" */
+ snprintf(cmd, cmdsz, "%s -O quota %s", TUNE2FS, dev);
+ ret = run_command(cmd, cmdsz);
+ if (ret)
+ fprintf(stderr, "command:%s (%d)", cmd, ret);
+
+ return ret;
+}
+
int ldiskfs_init(void)
{
/* Required because full path to DEBUGFS is not specified */