Whamcloud - gitweb
LU-4961 lustre: move ioctls to lustre_ioctl.h
[fs/lustre-release.git] / lustre / utils / mount_utils_ldiskfs.c
index a157a2a..dfb9e6c 100644 (file)
@@ -27,7 +27,7 @@
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2013, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
 #include <lnet/lnetctl.h>
 #include <lustre_ver.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
@@ -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;
@@ -348,7 +386,7 @@ static int is_e2fsprogs_feature_supp(const char *feature)
                }
                ret = fread(supp_features, 1, sizeof(supp_features) - 1, fp);
                supp_features[ret] = '\0';
-               fclose(fp);
+               pclose(fp);
        }
        if (ret > 0 && strstr(supp_features,
                              strncmp(feature, "-O ", 3) ? feature : feature+3))
@@ -454,7 +492,7 @@ static int enable_default_ext4_features(struct mkfs_opts *mop, char *anchor,
                append_unique(anchor, ",", "huge_file", NULL, maxbuflen);
 
        /* Enable large block addresses if the LUN is over 2^32 blocks. */
-       if (mop->mo_device_sz / (L_BLOCK_SIZE >> 10) >= 0x100002000ULL &&
+       if (mop->mo_device_kb / (L_BLOCK_SIZE >> 10) >= 0x100002000ULL &&
            is_e2fsprogs_feature_supp("-O 64bit") == 0)
                append_unique(anchor, ",", "64bit", NULL, maxbuflen);
 
@@ -518,7 +556,7 @@ static char *moveopts_to_end(char *start)
 /* Build fs according to type */
 int ldiskfs_make_lustre(struct mkfs_opts *mop)
 {
-       __u64 device_sz = mop->mo_device_sz, block_count = 0;
+       __u64 device_kb = mop->mo_device_kb, block_count = 0;
        char mkfs_cmd[PATH_MAX];
        char buf[64];
        char *start;
@@ -527,26 +565,26 @@ int ldiskfs_make_lustre(struct mkfs_opts *mop)
        size_t maxbuflen;
 
        if (!(mop->mo_flags & MO_IS_LOOP)) {
-               mop->mo_device_sz = get_device_size(mop->mo_device);
+               mop->mo_device_kb = get_device_size(mop->mo_device);
 
-               if (mop->mo_device_sz == 0)
+               if (mop->mo_device_kb == 0)
                        return ENODEV;
 
                /* Compare to real size */
-               if (device_sz == 0 || device_sz > mop->mo_device_sz)
-                       device_sz = mop->mo_device_sz;
+               if (device_kb == 0 || device_kb > mop->mo_device_kb)
+                       device_kb = mop->mo_device_kb;
                else
-                       mop->mo_device_sz = device_sz;
+                       mop->mo_device_kb = device_kb;
        }
 
-       if (mop->mo_device_sz != 0) {
-               if (mop->mo_device_sz < 8096){
+       if (mop->mo_device_kb != 0) {
+               if (mop->mo_device_kb < 8096) {
                        fprintf(stderr, "%s: size of filesystem must be larger "
                                "than 8MB, but is set to %lldKB\n",
-                               progname, (long long)mop->mo_device_sz);
+                               progname, (long long)mop->mo_device_kb);
                        return EINVAL;
                }
-               block_count = mop->mo_device_sz / (L_BLOCK_SIZE >> 10);
+               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 */
@@ -560,20 +598,27 @@ int ldiskfs_make_lustre(struct mkfs_opts *mop)
                long inode_size = 0;
 
                /* Journal size in MB */
-               if (strstr(mop->mo_mkfsopts, "-J") == NULL) {
+               if (strstr(mop->mo_mkfsopts, "-J") == NULL &&
+                   device_kb > 1024 * 1024) {
                        /* Choose our own default journal size */
-                       long journal_sz = 0, max_sz;
-                       if (device_sz > 1024 * 1024) /* 1GB */
-                               journal_sz = (device_sz / 102400) * 4;
-                       /* cap journal size at 1GB */
-                       if (journal_sz > 1024L)
-                               journal_sz = 1024L;
-                       /* man mkfs.ext3 */
-                       max_sz = (102400 * L_BLOCK_SIZE) >> 20; /* 400MB */
-                       if (journal_sz > max_sz)
-                               journal_sz = max_sz;
-                       if (journal_sz) {
-                               sprintf(buf, " -J size=%ld", journal_sz);
+                       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));
                        }
@@ -631,18 +676,18 @@ int ldiskfs_make_lustre(struct mkfs_opts *mop)
                         * this, but it is impossible to know in advance. */
                        if (IS_OST(&mop->mo_ldd)) {
                                /* OST > 16TB assume average file size 1MB */
-                               if (device_sz > (16ULL << 30))
+                               if (device_kb > (16ULL << 30))
                                        bytes_per_inode = 1024 * 1024;
                                /* OST > 4TB assume average file size 512kB */
-                               else if (device_sz > (4ULL << 30))
+                               else if (device_kb > (4ULL << 30))
                                        bytes_per_inode = 512 * 1024;
                                /* OST > 1TB assume average file size 256kB */
-                               else if (device_sz > (1ULL << 30))
+                               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_sz > (10ULL << 20))
+                               else if (device_kb > (10ULL << 20))
                                        bytes_per_inode = 69905;
                        }
 
@@ -703,8 +748,8 @@ int ldiskfs_make_lustre(struct mkfs_opts *mop)
                 * descriptor blocks, but leave one block for the superblock.
                 * Only useful for filesystems with < 2^32 blocks due to resize
                 * limitations. */
-               if (IS_OST(&mop->mo_ldd) && mop->mo_device_sz > 100 * 1024 &&
-                   mop->mo_device_sz * 1024 / L_BLOCK_SIZE <= 0xffffffffULL) {
+               if (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;
@@ -787,7 +832,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;
 
@@ -805,7 +850,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;
 
@@ -818,10 +863,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;
@@ -832,6 +922,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;
@@ -900,7 +991,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;
        }
 
@@ -970,45 +1062,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)
@@ -1017,7 +1112,7 @@ int ldiskfs_label_lustre(struct mount_opts *mop)
        int rc;
 
        snprintf(label_cmd, sizeof(label_cmd),
-                TUNE2FS" -f -L %s %s >/dev/null 2>&1",
+                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));
 
@@ -1042,9 +1137,17 @@ static char *absolute_path(char *devname)
                        return NULL;
                }
                strcat(buf, "/");
-               strcat(buf, devname);
+               if (strlen(devname) > sizeof(buf)-strlen(buf)-1) {
+                       free(path);
+                       return NULL;
+               }
+               strncat(buf, devname, sizeof(buf)-strlen(buf)-1);
        } else {
-               strcpy(buf, devname);
+               if (strlen(devname) > sizeof(buf)-1) {
+                       free(path);
+                       return NULL;
+               }
+               strncpy(buf, devname, sizeof(buf));
        }
        /* truncate filename before calling realpath */
        ptr = strrchr(buf, '/');
@@ -1121,7 +1224,7 @@ static int is_feature_enabled(const char *feature, const char *devpath)
 
        ret = fread(enabled_features, 1, sizeof(enabled_features) - 1, fp);
        enabled_features[ret] = '\0';
-       fclose(fp);
+       pclose(fp);
 
        if (strstr(enabled_features, feature))
                return 1;