* GPL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*/
/*
#include <errno.h>
#include <string.h>
#include <sys/mount.h>
+#include <linux/fs.h>
#include <mntent.h>
#include <getopt.h>
#include "obdctl.h"
int fake = 0;
int force = 0;
int retry = 0;
-int md_stripe_cache_size = 2048;
+int md_stripe_cache_size = 16384;
char *progname = NULL;
void usage(FILE *out)
{ "relatime", 0, MS_RELATIME }, /* set file access time on read */
{ "norelatime",1,MS_RELATIME }, /* do not set file access time on read */
#endif
+#ifdef MS_STRICTATIME
+ { "strictatime",0,MS_STRICTATIME }, /* update access time strictly */
+#endif
{ "auto", 0, 0 }, /* Can be mounted using -a */
{ "noauto", 0, 0 }, /* Can only be mounted explicitly */
{ "nousers", 1, 0 }, /* Forbid ordinary user to mount */
return 0;
}
+static void append_option(char *options, const char *one)
+{
+ if (*options)
+ strcat(options, ",");
+ strcat(options, one);
+}
+
/* Replace options with subset of Lustre-specific options, and
fill in mount flags */
int parse_options(char *orig_options, int *flagp)
* manner */
arg = opt;
val = strchr(opt, '=');
- if (val != NULL) {
- if (strncmp(arg, "md_stripe_cache_size", 20) == 0) {
- md_stripe_cache_size = atoi(val + 1);
- } else if (strncmp(arg, "retry", 5) == 0) {
- retry = atoi(val + 1);
- if (retry > MAX_RETRIES)
- retry = MAX_RETRIES;
- else if (retry < 0)
- retry = 0;
- }
- } else if (strncmp(opt, "force", 5) == 0) {
+ /* please note that some ldiskfs mount options are also in the form
+ * of param=value. We should pay attention not to remove those
+ * mount options, see bug 22097. */
+ if (val && strncmp(arg, "md_stripe_cache_size", 20) == 0) {
+ md_stripe_cache_size = atoi(val + 1);
+ } else if (val && strncmp(arg, "retry", 5) == 0) {
+ retry = atoi(val + 1);
+ if (retry > MAX_RETRIES)
+ retry = MAX_RETRIES;
+ else if (retry < 0)
+ retry = 0;
+ } else if (val && strncmp(arg, "mgssec", 6) == 0) {
+ append_option(options, opt);
+ } else if (strcmp(opt, "force") == 0) {
//XXX special check for 'force' option
++force;
printf("force: %d\n", force);
} else if (parse_one_option(opt, flagp) == 0) {
/* pass this on as an option */
- if (*options)
- strcat(options, ",");
- strcat(options, opt);
+ append_option(options, opt);
}
}
+#ifdef MS_STRICTATIME
+ /* set strictatime to default if NOATIME or RELATIME
+ not given explicit */
+ if (!(*flagp & (MS_NOATIME | MS_RELATIME)))
+ *flagp |= MS_STRICTATIME;
+#endif
strcpy(orig_options, options);
free(options);
return 0;
if (fd == NULL)
return errno;
- fgets(buf, size, fd);
+ /* should not ignore fgets(3)'s return value */
+ if (!fgets(buf, size, fd)) {
+ fprintf(stderr, "reading from %s: %s", path, strerror(errno));
+ fclose(fd);
+ return 1;
+ }
fclose(fd);
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 */
-int set_blockdev_tunables(char *source)
+int set_blockdev_tunables(char *source, int fan_out)
{
- glob_t glob_info;
+ glob_t glob_info = { 0 };
struct stat stat_buf;
char *chk_major, *chk_minor;
char *savept, *dev;
* 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 */
- dev = real_path + strlen(real_path);
- while (--dev > real_path && isdigit(*dev))
- *dev = 0;
- if (strncmp(real_path, "/dev/md_", 8) == 0)
- *dev = 0;
+ /* 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;
+
+ if (strncmp(real_path, "/dev/md_", 8) == 0)
+ *dev = 0;
+ }
rc = stat(real_path, &stat_buf);
if (rc) {
if (verbose)
fprintf(stderr, "warning: failed to read entries under "
"/sys/block\n");
+ globfree(&glob_info);
return rc;
}
if (verbose)
fprintf(stderr, "warning: opening %s: %s\n",
real_path, strerror(errno));
- return rc;
+ return 0;
}
if (atoi(buf) >= md_stripe_cache_size)
if (verbose)
fprintf(stderr, "warning: opening %s: %s\n",
real_path, strerror(errno));
- return rc;
+ /* No MAX_HW_SECTORS_KB_PATH isn't necessary an
+ * error for some device. */
+ rc = 0;
}
if (strlen(buf) - 1 > 0) {
snprintf(real_path, sizeof(real_path), "%s/%s", path,
MAX_SECTORS_KB_PATH);
rc = write_file(real_path, buf);
- if (rc && verbose)
- fprintf(stderr, "warning: writing to %s: %s\n",
- real_path, strerror(errno));
+ if (rc) {
+ 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. */
+ rc = 0;
+ }
}
+
+ 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, 0);
+ }
+
+ 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);
+ }
+
return rc;
}
int main(int argc, char *const argv[])
{
char default_options[] = "";
- char *usource, *source, *target, *ptr;
+ char *usource, *source, *ptr;
+ char target[PATH_MAX] = {'\0'};
+ char real_path[PATH_MAX] = {'\0'};
+ char path[256], name[256];
+ FILE *f;
+ size_t sz;
char *options, *optcopy, *orig_options = default_options;
int i, nargs = 3, opt, rc, flags, optlen;
static struct option long_opt[] = {
usage(stderr);
}
+ /**
+ * Try to get the real path to the device, in case it is a
+ * symbolic link for instance
+ */
+ if (realpath(usource, real_path) != NULL) {
+ usource = real_path;
+
+ ptr = strrchr(real_path, '/');
+ if (ptr && strncmp(ptr, "/dm-", 4) == 0 && isdigit(*(ptr + 4))) {
+ snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptr+1);
+ if ((f = fopen(path, "r"))) {
+ /* read "<name>\n" from sysfs */
+ if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) {
+ name[sz - 1] = '\0';
+ snprintf(real_path, sizeof(real_path), "/dev/mapper/%s", name);
+ }
+ fclose(f);
+ }
+ }
+ }
+
source = convert_hostnames(usource);
if (!source) {
usage(stderr);
}
- target = argv[optind + 1];
- ptr = target + strlen(target) - 1;
- while ((ptr > target) && (*ptr == '/')) {
- *ptr = 0;
- ptr--;
+ if (realpath(argv[optind + 1], target) == NULL) {
+ rc = errno;
+ fprintf(stderr, "warning: %s: cannot resolve: %s\n",
+ argv[optind + 1], strerror(errno));
+ return rc;
}
if (verbose) {
printf("mounting device %s at %s, flags=%#x options=%s\n",
source, target, flags, optcopy);
- if (!strstr(usource, ":/") && set_blockdev_tunables(source)) {
+ if (!strstr(usource, ":/") && set_blockdev_tunables(source, 1)) {
if (verbose)
fprintf(stderr, "%s: unable to set tunables for %s"
" (may cause reduced IO performance)\n",
usource, target, strerror(errno));
if (errno == ENODEV)
fprintf(stderr, "Are the lustre modules loaded?\n"
- "Check /etc/modprobe.conf and /proc/filesystems"
- "\nNote 'alias lustre llite' should be removed"
- " from modprobe.conf\n");
+ "Check /etc/modprobe.conf and "
+ "/proc/filesystems\n");
if (errno == ENOTBLK)
fprintf(stderr, "Do you need -o loop?\n");
if (errno == ENOMEDIUM)
/* May as well try to clean up loop devs */
if (strncmp(usource, "/dev/loop", 9) == 0) {
char cmd[256];
+ int ret;
sprintf(cmd, "/sbin/losetup -d %s", usource);
- system(cmd);
+ if ((ret = system(cmd)) < 0)
+ rc = errno;
+ else if (ret > 0)
+ rc = WEXITSTATUS(ret);
}
} else if (!nomtab) {