Whamcloud - gitweb
LU-3763 utils: set multipath devices recursively
[fs/lustre-release.git] / lustre / utils / mount_utils_ldiskfs.c
index 45c491e..4c75200 100644 (file)
 #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;
@@ -787,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;
 
@@ -805,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;
 
@@ -818,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;
@@ -832,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;
@@ -900,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;
        }
 
@@ -970,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)