X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Futils%2Fmount_utils.c;h=ae0316e35ed662fd57e270658c10d6e61e7b6458;hb=3a1e40d92baeb54fa93d527af55105a1e3a4a289;hp=d6246565c34b2eb257d9c21a5087e7d8061457cd;hpb=b4efa1b2cbfd45f85439e1bb0a4c4eb719540dcd;p=fs%2Flustre-release.git diff --git a/lustre/utils/mount_utils.c b/lustre/utils/mount_utils.c index d624656..ae0316e 100644 --- a/lustre/utils/mount_utils.c +++ b/lustre/utils/mount_utils.c @@ -1,6 +1,4 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * +/* * GPL HEADER START * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -26,8 +24,9 @@ * GPL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. + * Copyright (c) 2012 Whamcloud, Inc. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -38,6 +37,7 @@ # include "config.h" #endif /* HAVE_CONFIG_H */ +#include "mount_utils.h" #include #include #include @@ -100,176 +100,622 @@ int run_command(char *cmd, int cmdsz) return rc; } -int get_mountdata(char *dev, struct lustre_disk_data *mo_ldd) +int add_param(char *buf, char *key, char *val) { + int end = sizeof(((struct lustre_disk_data *)0)->ldd_params); + int start = strlen(buf); + int keylen = 0; + + if (key) + keylen = strlen(key); + if (start + 1 + keylen + strlen(val) >= end) { + fprintf(stderr, "%s: params are too long-\n%s %s%s\n", + progname, buf, key ? key : "", val); + return 1; + } + + sprintf(buf + start, " %s%s", key ? key : "", val); + return 0; +} - char tmpdir[] = "/tmp/lustre_tmp.XXXXXX"; - char cmd[256]; - char filepnm[128]; - FILE *filep; - int ret = 0; - int ret2 = 0; - int cmdsz = sizeof(cmd); - - /* Make a temporary directory to hold Lustre data files. */ - if (!mkdtemp(tmpdir)) { - verrprint("%s: Can't create temporary directory %s: %s\n", - progname, tmpdir, strerror(errno)); - return errno; - } +int get_param(char *buf, char *key, char **val) +{ + int i, key_len = strlen(key); + char *ptr; - snprintf(cmd, cmdsz, "%s -c -R 'dump /%s %s/mountdata' %s", - DEBUGFS, MOUNT_DATA_FILE, tmpdir, dev); + ptr = strstr(buf, key); + if (ptr) { + *val = strdup(ptr + key_len); + if (*val == NULL) + return ENOMEM; - ret = run_command(cmd, cmdsz); - if (ret) { - verrprint("%s: Unable to dump %s dir (%d)\n", - progname, MOUNT_CONFIGS_DIR, ret); - goto out_rmdir; - } + for (i = 0; i < strlen(*val); i++) + if (((*val)[i] == ' ') || ((*val)[i] == '\0')) + break; - sprintf(filepnm, "%s/mountdata", tmpdir); - filep = fopen(filepnm, "r"); - if (filep) { - size_t num_read; - vprint("Reading %s\n", MOUNT_DATA_FILE); - num_read = fread(mo_ldd, sizeof(*mo_ldd), 1, filep); - if (num_read < 1 && ferror(filep)) { - fprintf(stderr, "%s: Unable to read from file (%s): %s\n", - progname, filepnm, strerror(errno)); - goto out_close; - } - } else { - verrprint("%s: Unable to read %d.%d config %s.\n", - progname, LUSTRE_MAJOR, LUSTRE_MINOR, filepnm); - goto out_close; - } + (*val)[i] = '\0'; + return 0; + } -out_close: - fclose(filep); - -out_rmdir: - snprintf(cmd, cmdsz, "rm -rf %s", tmpdir); - ret2 = run_command(cmd, cmdsz); - if (ret2) { - verrprint("Failed to remove temp dir %s (%d)\n", tmpdir, ret2); - /* failure return from run_command() is more important - * than the failure to remove a dir */ - if (!ret) - ret = ret2; - } + return ENOENT; +} - return ret; +char *strscat(char *dst, char *src, int buflen) +{ + dst[buflen - 1] = 0; + if (strlen(dst) + strlen(src) >= buflen) { + fprintf(stderr, "string buffer overflow (max %d): '%s' + '%s'" + "\n", buflen, dst, src); + exit(EOVERFLOW); + } + return strcat(dst, src); } -#define PARENT_URN "urn:uuid:2bb5bdbf-6c4b-11dc-9b8e-080020a9ed93" -#define PARENT_PRODUCT "Lustre" +char *strscpy(char *dst, char *src, int buflen) +{ + dst[0] = 0; + return strscat(dst, src, buflen); +} -static int stclient(char *type, char *arch) +int check_mtab_entry(char *spec1, char *spec2, char *mtpt, char *type) { + FILE *fp; + struct mntent *mnt; + + fp = setmntent(MOUNTED, "r"); + if (fp == NULL) + return 0; + + while ((mnt = getmntent(fp)) != NULL) { + if ((strcmp(mnt->mnt_fsname, spec1) == 0 || + strcmp(mnt->mnt_fsname, spec2) == 0) && + (mtpt == NULL || strcmp(mnt->mnt_dir, mtpt) == 0) && + (type == NULL || strcmp(mnt->mnt_type, type) == 0)) { + endmntent(fp); + return(EEXIST); + } + } + endmntent(fp); + + return 0; +} - char product[64]; - char *urn = NULL; - char cmd[1024]; - FILE *fp; - int i; - - if (strcmp(type, "Client") == 0) - urn = CLIENT_URN; - else if (strcmp(type, "MDS") == 0) - urn = MDS_URN; - else if (strcmp(type, "MGS") == 0) - urn = MGS_URN; - else if (strcmp(type, "OSS") == 0) - urn = OSS_URN; - - snprintf(product, 64, "Lustre %s %d.%d.%d", type, LUSTRE_MAJOR, - LUSTRE_MINOR, LUSTRE_PATCH); - - /* need to see if the entry exists first */ - snprintf(cmd, 1024, - "/opt/sun/servicetag/bin/stclient -f -t '%s' ", urn); - fp = popen(cmd, "r"); - if (!fp) { - if (verbose) - fprintf(stderr, "%s: trying to run stclient -f: %s\n", - progname, strerror(errno)); - return 0; - } +#define PROC_DIR "/proc/" +static int mtab_is_proc(const char *mtab) +{ + char path[16]; - i = fread(cmd, 1, sizeof(cmd), fp); - if (i) { - cmd[i] = 0; - if (strcmp(cmd, "Record not found\n") != 0) { - /* exists, just return */ - pclose(fp); - return 0; - } - } - pclose(fp); + if (readlink(mtab, path, sizeof(path)) < 0) + return 0; - snprintf(cmd, 1024, "/opt/sun/servicetag/bin/stclient -a -p '%s' " - "-e %d.%d.%d -t '%s' -S mount -F '%s' -P '%s' -m SUN " - "-A %s -z global", product, LUSTRE_MAJOR, LUSTRE_MINOR, - LUSTRE_PATCH, urn, PARENT_URN, PARENT_PRODUCT, arch); + if (strncmp(path, PROC_DIR, strlen(PROC_DIR))) + return 0; - return(run_command(cmd, sizeof(cmd))); + return 1; } -void register_service_tags(char *usource, char *source, char *target) +int update_mtab_entry(char *spec, char *mtpt, char *type, char *opts, + int flags, int freq, int pass) { - struct lustre_disk_data mo_ldd; - struct utsname utsname_buf; - struct stat stat_buf; - char stclient_loc[] = "/opt/sun/servicetag/bin/stclient"; - int rc; - - rc = stat(stclient_loc, &stat_buf); - - if (rc) { - if (errno != ENOENT && verbose) { - fprintf(stderr, - "%s: trying to stat stclient failed: %s\n", - progname, strerror(errno)); - } + FILE *fp; + struct mntent mnt; + int rc = 0; + + /* Don't update mtab if it is linked to any file in /proc direcotry.*/ + if (mtab_is_proc(MOUNTED)) + return 0; + + mnt.mnt_fsname = spec; + mnt.mnt_dir = mtpt; + mnt.mnt_type = type; + mnt.mnt_opts = opts ? opts : ""; + mnt.mnt_freq = freq; + mnt.mnt_passno = pass; + + fp = setmntent(MOUNTED, "a+"); + if (fp == NULL) { + fprintf(stderr, "%s: setmntent(%s): %s:", + progname, MOUNTED, strerror (errno)); + rc = 16; + } else { + if ((addmntent(fp, &mnt)) == 1) { + fprintf(stderr, "%s: addmntent: %s:", + progname, strerror (errno)); + rc = 16; + } + endmntent(fp); + } + + return rc; +} - return; - } +/* Search for opt in mntlist, returning true if found. + */ +static int in_mntlist(char *opt, char *mntlist) +{ + char *ml, *mlp, *item, *ctx = NULL; + + if (!(ml = strdup(mntlist))) { + fprintf(stderr, "%s: out of memory\n", progname); + exit(1); + } + mlp = ml; + while ((item = strtok_r(mlp, ",", &ctx))) { + if (!strcmp(opt, item)) + break; + mlp = NULL; + } + free(ml); + return (item != NULL); +} - /* call service tags stclient to show Lustre is in use on this system */ - rc = uname(&utsname_buf); - if (rc) { - if (verbose) - fprintf(stderr, - "%s: trying to get uname failed: %s, " - "inventory tags will not be created\n", - progname, strerror(errno)); - return; - } +/* Issue a message on stderr for every item in wanted_mountopts that is not + * present in mountopts. The justwarn boolean toggles between error and + * warning message. Return an error count. + */ +int check_mountfsoptions(char *mountopts, char *wanted_mountopts, + int justwarn) +{ + char *ml, *mlp, *item, *ctx = NULL; + int errors = 0; + + if (!(ml = strdup(wanted_mountopts))) { + fprintf(stderr, "%s: out of memory\n", progname); + exit(1); + } + mlp = ml; + while ((item = strtok_r(mlp, ",", &ctx))) { + if (!in_mntlist(item, mountopts)) { + fprintf(stderr, "%s: %s mount option `%s' is missing\n", + progname, justwarn ? "Warning: default" + : "Error: mandatory", item); + errors++; + } + mlp = NULL; + } + free(ml); + return errors; +} - /* client or server? */ - if (strchr(usource, ':')) { - stclient("Client", utsname_buf.machine); - } else { - /* first figure what type of device it is */ - rc = get_mountdata(source, &mo_ldd); - if (rc) { - if (verbose) - fprintf(stderr, - "%s: trying to read mountdata from %s " - "failed: %s, inventory tags will not " - "be created\n", - progname, target, strerror(errno)); - return; - } +/* Trim embedded white space, leading and trailing commas from string s. + */ +void trim_mountfsoptions(char *s) +{ + char *p; + + for (p = s; *p; ) { + if (isspace(*p)) { + memmove(p, p + 1, strlen(p + 1) + 1); + continue; + } + p++; + } + + while (s[0] == ',') + memmove(&s[0], &s[1], strlen(&s[1]) + 1); + + p = s + strlen(s) - 1; + while (p >= s && *p == ',') + *p-- = '\0'; +} + +/* Setup a file in the first unused loop_device */ +int loop_setup(struct mkfs_opts *mop) +{ + char loop_base[20]; + char l_device[64]; + int i, ret = 0; + + /* Figure out the loop device names */ + if (!access("/dev/loop0", F_OK | R_OK)) { + strcpy(loop_base, "/dev/loop\0"); + } else if (!access("/dev/loop/0", F_OK | R_OK)) { + strcpy(loop_base, "/dev/loop/\0"); + } else { + fprintf(stderr, "%s: can't access loop devices\n", progname); + return EACCES; + } + + /* Find unused loop device */ + for (i = 0; i < MAX_LOOP_DEVICES; i++) { + char cmd[PATH_MAX]; + int cmdsz = sizeof(cmd); + + sprintf(l_device, "%s%d", loop_base, i); + if (access(l_device, F_OK | R_OK)) + break; + snprintf(cmd, cmdsz, "losetup %s > /dev/null 2>&1", l_device); + ret = system(cmd); + + /* losetup gets 1 (ret=256) for non-set-up device */ + if (ret) { + /* Set up a loopback device to our file */ + snprintf(cmd, cmdsz, "losetup %s %s", l_device, + mop->mo_device); + ret = run_command(cmd, cmdsz); + if (ret == 256) + /* someone else picked up this loop device + * behind our back */ + continue; + if (ret) { + fprintf(stderr, "%s: error %d on losetup: %s\n", + progname, ret, strerror(ret)); + return ret; + } + strscpy(mop->mo_loopdev, l_device, + sizeof(mop->mo_loopdev)); + return ret; + } + } + + fprintf(stderr, "%s: out of loop devices!\n", progname); + return EMFILE; +} + +int loop_cleanup(struct mkfs_opts *mop) +{ + char cmd[150]; + int ret = 1; + if ((mop->mo_flags & MO_IS_LOOP) && *mop->mo_loopdev) { + sprintf(cmd, "losetup -d %s", mop->mo_loopdev); + ret = run_command(cmd, sizeof(cmd)); + } + return ret; +} + +int loop_format(struct mkfs_opts *mop) +{ + int fd; + + if (mop->mo_device_sz == 0) { + fatal(); + fprintf(stderr, "loop device requires a --device-size= " + "param\n"); + return EINVAL; + } + + fd = creat(mop->mo_device, S_IRUSR|S_IWUSR); + if (fd < 0) { + fatal(); + fprintf(stderr, "%s: Unable to create backing store: %s\n", + progname, strerror(errno)); + return errno; + } + + if (ftruncate(fd, mop->mo_device_sz * 1024) != 0) { + close(fd); + fatal(); + fprintf(stderr, "%s: Unable to truncate backing store: %s\n", + progname, strerror(errno)); + return errno; + } + + close(fd); + return 0; +} - if (IS_MDT(&mo_ldd)) - stclient("MDS", utsname_buf.machine); +/* Write the server config files */ +int osd_write_ldd(struct mkfs_opts *mop) +{ + struct lustre_disk_data *ldd = &mop->mo_ldd; + int ret; + + switch (ldd->ldd_mount_type) { +#ifdef HAVE_LDISKFS_OSD + case LDD_MT_LDISKFS: + case LDD_MT_LDISKFS2: + ret = ldiskfs_write_ldd(mop); + break; +#endif /* HAVE_LDISKFS_OSD */ +#ifdef HAVE_ZFS_OSD + case LDD_MT_ZFS: + ret = zfs_write_ldd(mop); + break; +#endif /* HAVE_ZFS_OSD */ + default: + fatal(); + fprintf(stderr, "unknown fs type %d '%s'\n", + ldd->ldd_mount_type, MT_STR(ldd)); + ret = EINVAL; + break; + } + + return ret; +} - if (IS_MGS(&mo_ldd)) - stclient("MGS", utsname_buf.machine); +/* Read the server config files */ +int osd_read_ldd(char *dev, struct lustre_disk_data *ldd) +{ + int ret; + + switch (ldd->ldd_mount_type) { +#ifdef HAVE_LDISKFS_OSD + case LDD_MT_LDISKFS: + case LDD_MT_LDISKFS2: + ret = ldiskfs_read_ldd(dev, ldd); + break; +#endif /* HAVE_LDISKFS_OSD */ +#ifdef HAVE_ZFS_OSD + case LDD_MT_ZFS: + ret = zfs_read_ldd(dev, ldd); + break; +#endif /* HAVE_ZFS_OSD */ + default: + fatal(); + fprintf(stderr, "unknown fs type %d '%s'\n", + ldd->ldd_mount_type, MT_STR(ldd)); + ret = EINVAL; + break; + } + + return ret; +} - if (IS_OST(&mo_ldd)) - stclient("OSS", utsname_buf.machine); - } +/* Was this device formatted for Lustre */ +int osd_is_lustre(char *dev, unsigned *mount_type) +{ + vprint("checking for existing Lustre data: "); + +#ifdef HAVE_LDISKFS_OSD + if (ldiskfs_is_lustre(dev, mount_type)) { + vprint("found\n"); + return 1; + } +#endif /* HAVE_LDISKFS_OSD */ +#ifdef HAVE_ZFS_OSD + if (zfs_is_lustre(dev, mount_type)) { + vprint("found\n"); + return 1; + } +#endif /* HAVE_ZFS_OSD */ + + vprint("not found\n"); + return 0; +} + +/* Build fs according to type */ +int osd_make_lustre(struct mkfs_opts *mop) +{ + struct lustre_disk_data *ldd = &mop->mo_ldd; + int ret; + + switch (ldd->ldd_mount_type) { +#ifdef HAVE_LDISKFS_OSD + case LDD_MT_LDISKFS: + case LDD_MT_LDISKFS2: + ret = ldiskfs_make_lustre(mop); + break; +#endif /* HAVE_LDISKFS_OSD */ +#ifdef HAVE_ZFS_OSD + case LDD_MT_ZFS: + ret = zfs_make_lustre(mop); + break; +#endif /* HAVE_ZFS_OSD */ + default: + fatal(); + fprintf(stderr, "unknown fs type %d '%s'\n", + ldd->ldd_mount_type, MT_STR(ldd)); + ret = EINVAL; + break; + } + + return ret; +} + +int osd_prepare_lustre(struct mkfs_opts *mop, + char *default_mountopts, int default_len, + char *always_mountopts, int always_len) +{ + struct lustre_disk_data *ldd = &mop->mo_ldd; + int ret; + + switch (ldd->ldd_mount_type) { +#ifdef HAVE_LDISKFS_OSD + case LDD_MT_LDISKFS: + case LDD_MT_LDISKFS2: + ret = ldiskfs_prepare_lustre(mop, + default_mountopts, default_len, + always_mountopts, always_len); + break; +#endif /* HAVE_LDISKFS_OSD */ +#ifdef HAVE_ZFS_OSD + case LDD_MT_ZFS: + ret = zfs_prepare_lustre(mop, + default_mountopts, default_len, + always_mountopts, always_len); + break; +#endif /* HAVE_ZFS_OSD */ + default: + fatal(); + fprintf(stderr, "unknown fs type %d '%s'\n", + ldd->ldd_mount_type, MT_STR(ldd)); + ret = EINVAL; + break; + } + + return ret; +} + +int osd_tune_lustre(char *dev, struct mount_opts *mop) +{ + struct lustre_disk_data *ldd = &mop->mo_ldd; + int ret; + + switch (ldd->ldd_mount_type) { +#ifdef HAVE_LDISKFS_OSD + case LDD_MT_LDISKFS: + case LDD_MT_LDISKFS2: + ret = ldiskfs_tune_lustre(dev, mop); + break; +#endif /* HAVE_LDISKFS_OSD */ +#ifdef HAVE_ZFS_OSD + case LDD_MT_ZFS: + ret = zfs_tune_lustre(dev, mop); + break; +#endif /* HAVE_ZFS_OSD */ + default: + fatal(); + fprintf(stderr, "unknown fs type %d '%s'\n", + ldd->ldd_mount_type, MT_STR(ldd)); + ret = EINVAL; + break; + } + + return ret; +} + +int osd_label_lustre(struct mount_opts *mop) +{ + struct lustre_disk_data *ldd = &mop->mo_ldd; + int ret; + + switch (ldd->ldd_mount_type) { +#ifdef HAVE_LDISKFS_OSD + case LDD_MT_LDISKFS: + case LDD_MT_LDISKFS2: + ret = ldiskfs_label_lustre(mop); + break; +#endif /* HAVE_LDISKFS_OSD */ +#ifdef HAVE_ZFS_OSD + case LDD_MT_ZFS: + ret = zfs_label_lustre(mop); + break; +#endif /* HAVE_ZFS_OSD */ + default: + fatal(); + fprintf(stderr, "unknown fs type %d '%s'\n", + ldd->ldd_mount_type, MT_STR(ldd)); + ret = EINVAL; + break; + } + + return ret; +} + +/* Enable quota accounting */ +int osd_enable_quota(struct mkfs_opts *mop) +{ + struct lustre_disk_data *ldd = &mop->mo_ldd; + int ret; + + switch (ldd->ldd_mount_type) { +#ifdef HAVE_LDISKFS_OSD + case LDD_MT_EXT3: + case LDD_MT_LDISKFS: + case LDD_MT_LDISKFS2: + ret = ldiskfs_enable_quota(mop); + break; +#endif /* HAVE_LDISKFS_OSD */ +#ifdef HAVE_ZFS_OSD + case LDD_MT_ZFS: + fprintf(stderr, "this option is only valid for ldiskfs\n"); + ret = EINVAL; + break; +#endif /* HAVE_ZFS_OSD */ + default: + fatal(); + fprintf(stderr, "unknown fs type %d '%s'\n", + ldd->ldd_mount_type, MT_STR(ldd)); + ret = EINVAL; + break; + } + + return ret; +} + +int osd_init(void) +{ + int ret = 0; + +#ifdef HAVE_LDISKFS_OSD + ret = ldiskfs_init(); + if (ret) + return ret; +#endif /* HAVE_LDISKFS_OSD */ +#ifdef HAVE_ZFS_OSD + ret = zfs_init(); + /* we want to be able to set up a ldiskfs-based filesystem w/o + * the ZFS modules installed, see ORI-425 */ + if (ret) + ret = 0; +#endif /* HAVE_ZFS_OSD */ + + return ret; +} + +void osd_fini(void) +{ +#ifdef HAVE_LDISKFS_OSD + ldiskfs_fini(); +#endif /* HAVE_LDISKFS_OSD */ +#ifdef HAVE_ZFS_OSD + zfs_fini(); +#endif /* HAVE_ZFS_OSD */ +} + +__u64 get_device_size(char* device) +{ + int ret, fd; + __u64 size = 0; + + fd = open(device, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "%s: cannot open %s: %s\n", + progname, device, strerror(errno)); + return 0; + } + +#ifdef BLKGETSIZE64 + /* size in bytes. bz5831 */ + ret = ioctl(fd, BLKGETSIZE64, (void*)&size); +#else + { + __u32 lsize = 0; + /* size in blocks */ + ret = ioctl(fd, BLKGETSIZE, (void*)&lsize); + size = (__u64)lsize * 512; + } +#endif + close(fd); + if (ret < 0) { + fprintf(stderr, "%s: size ioctl failed: %s\n", + progname, strerror(errno)); + return 0; + } + + vprint("device size = "LPU64"MB\n", size >> 20); + /* return value in KB */ + return size >> 10; +} + +int file_create(char *path, int size) +{ + int ret; + int fd; + + ret = access(path, F_OK); + if (ret == 0) { + ret = unlink(path); + if (ret != 0) + return errno; + } + + fd = creat(path, S_IRUSR|S_IWUSR); + if (fd < 0) { + fatal(); + fprintf(stderr, "%s: Unable to create backing store: %s\n", + progname, strerror(errno)); + return errno; + } + + ret = ftruncate(fd, size * 1024); + close(fd); + if (ret != 0) { + fatal(); + fprintf(stderr, "%s: Unable to truncate backing store: %s\n", + progname, strerror(errno)); + return errno; + } + + return 0; }