X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Futils%2Fmount_utils_ldiskfs.c;h=4c75200e73c7bbc1a6103beb2098692b47c86a81;hp=f863ac9760ad32a74fbcfca9b4a125ec46935dd7;hb=aeb887ab0d4b15d17f3b96bf0e7be3b746edcf8e;hpb=cfef7958178b4e2981a44b1977da6577cc152ce4 diff --git a/lustre/utils/mount_utils_ldiskfs.c b/lustre/utils/mount_utils_ldiskfs.c index f863ac9..4c75200 100644 --- a/lustre/utils/mount_utils_ldiskfs.c +++ b/lustre/utils/mount_utils_ldiskfs.c @@ -27,7 +27,7 @@ * 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/ @@ -47,6 +47,7 @@ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif +#include "mount_utils.h" #include #include #include @@ -78,12 +79,18 @@ #include #include #include -#include "mount_utils.h" + +#ifdef HAVE_SELINUX +#include +#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 @@ -91,6 +98,29 @@ extern char *progname; #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) { @@ -108,6 +138,14 @@ 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; @@ -150,6 +188,7 @@ int ldiskfs_write_ldd(struct mkfs_opts *mop) if (num < 1 && ferror(filep)) { fprintf(stderr, "%s: Unable to write to file (%s): %s\n", progname, filepnm, strerror(errno)); + fclose(filep); goto out_umnt; } fclose(filep); @@ -161,6 +200,25 @@ out_rmdir: return ret; } +static int readcmd(char *cmd, char *buf, int len) +{ + FILE *fp; + int red; + + fp = popen(cmd, "r"); + if (!fp) + return errno; + + red = fread(buf, 1, len, fp); + pclose(fp); + + /* strip trailing newline */ + if (buf[red - 1] == '\n') + buf[red - 1] = '\0'; + + return (red == 0) ? -ENOENT : 0; +} + int ldiskfs_read_ldd(char *dev, struct lustre_disk_data *mo_ldd) { char tmpdir[] = "/tmp/dirXXXXXX"; @@ -199,16 +257,19 @@ int ldiskfs_read_ldd(char *dev, struct lustre_disk_data *mo_ldd) 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); if (ret) verrprint("Failed to read old data (%d)\n", ret); + + /* 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); + return ret; } @@ -264,7 +325,7 @@ static int file_in_dev(char *file_name, char *dev_name) 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); @@ -323,7 +384,8 @@ static int is_e2fsprogs_feature_supp(const char *feature) 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, @@ -381,8 +443,8 @@ static void append_unique(char *buf, char *prefix, char *key, char *val, } } -static void enable_default_ext4_features(struct mkfs_opts *mop, char *anchor, - size_t maxbuflen, int user_spec) +static int enable_default_ext4_features(struct mkfs_opts *mop, char *anchor, + size_t maxbuflen, int user_spec) { if (IS_OST(&mop->mo_ldd)) { append_unique(anchor, user_spec ? "," : " -O ", @@ -413,7 +475,17 @@ static void enable_default_ext4_features(struct mkfs_opts *mop, char *anchor, /* The following options are only valid for ext4-based ldiskfs. * If --backfstype=ext3 is specified, do not enable them. */ if (mop->mo_ldd.ldd_mount_type == LDD_MT_EXT3) - return; + return 0; + + /* Enable quota by default */ + if (is_e2fsprogs_feature_supp("-O quota") == 0) { + append_unique(anchor, ",", "quota", NULL, maxbuflen); + } else { + fatal(); + fprintf(stderr, "\"-O quota\" must be supported by " + "e2fsprogs, please upgrade your e2fsprogs.\n"); + return EINVAL; + } /* Allow files larger than 2TB. Also needs LU-16, but not harmful. */ if (is_e2fsprogs_feature_supp("-O huge_file") == 0) @@ -439,6 +511,7 @@ static void enable_default_ext4_features(struct mkfs_opts *mop, char *anchor, } } /* Don't add any more "-O" options here, see last comment above */ + return 0; } /** @@ -634,13 +707,15 @@ int ldiskfs_make_lustre(struct mkfs_opts *mop) start = moveopts_to_end(start); maxbuflen = sizeof(mop->mo_mkfsopts) - (start - mop->mo_mkfsopts) - strlen(start); - enable_default_ext4_features(mop, start, maxbuflen, 1); + 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); - enable_default_ext4_features(mop, start, maxbuflen, 0); + ret = enable_default_ext4_features(mop, start, maxbuflen, 0); } + if (ret) + return ret; /* end handle -O mkfs options */ /* start handle -E mkfs options */ @@ -750,7 +825,7 @@ int ldiskfs_prepare_lustre(struct mkfs_opts *mop, return 0; } -int read_file(char *path, char *buf, int size) +int read_file(const char *path, char *buf, int size) { FILE *fd; @@ -768,7 +843,7 @@ int read_file(char *path, char *buf, int size) return 0; } -int write_file(char *path, char *buf) +int write_file(const char *path, const char *buf) { FILE *fd; @@ -781,10 +856,55 @@ int write_file(char *path, char *buf) 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 */ -int set_blockdev_tunables(char *source, struct mount_opts *mop, int fan_out) +int set_blockdev_tunables(char *source, struct mount_opts *mop) { glob_t glob_info = { 0 }; struct stat stat_buf; @@ -795,6 +915,7 @@ int set_blockdev_tunables(char *source, struct mount_opts *mop, int fan_out) char real_path[PATH_MAX] = {'\0'}; int i, rc = 0; int major, minor; + char *slave = NULL; if (!source) return -EINVAL; @@ -863,7 +984,8 @@ int set_blockdev_tunables(char *source, struct mount_opts *mop, int fan_out) chk_major = strtok_r(buf, ":", &savept); chk_minor = savept; - if (major == atoi(chk_major) &&minor == atoi(chk_minor)) + if (chk_major != NULL && major == atoi(chk_major) && + chk_minor != NULL && minor == atoi(chk_minor)) break; } @@ -933,45 +1055,48 @@ set_params: } } - if (fan_out) { - char *slave = NULL; - glob_info.gl_pathc = 0; - glob_info.gl_offs = 0; - /* if device is multipath device, tune its slave devices */ - 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, 0); - } + /* 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 (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); - } + 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); } - globfree(&glob_info); } + globfree(&glob_info); return rc; } int ldiskfs_tune_lustre(char *dev, struct mount_opts *mop) { - return set_blockdev_tunables(dev, mop, 1); + return set_blockdev_tunables(dev, mop); } int ldiskfs_label_lustre(struct mount_opts *mop) @@ -979,8 +1104,9 @@ int ldiskfs_label_lustre(struct mount_opts *mop) 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; @@ -999,8 +1125,10 @@ static char *absolute_path(char *devname) return NULL; if (devname[0] != '/') { - if (getcwd(buf, sizeof(buf) - 1) == NULL) + if (getcwd(buf, sizeof(buf) - 1) == NULL) { + free(path); return NULL; + } strcat(buf, "/"); strcat(buf, devname); } else { @@ -1061,6 +1189,65 @@ out: 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 */