From 93339415b8d74c0a2c74ee053aed23540b89bccb Mon Sep 17 00:00:00 2001 From: Prakash Surya Date: Mon, 4 Apr 2011 13:45:34 -0700 Subject: [PATCH] LU-64 Make "lfs getstripe" directory output consistent. "lfs getstripe" should report the global default for any fields with a value that means "use the default". This patch introduces the following functionality: 1. If "lfs getstripe" is called on a directory and finds that striping EA is not set, the filesystem's defaults are looked up and printed. 2. If the striping EA is set, but the striping count and/or striping size has a value that means "use the default" (count = 0 and/or size = 0), the filesystem's default for that specific striping attribute is looked up and printed. 3. A new option to "lfs getstripe" is introduced; the "--raw" or "-R" option. If this option is specified, the previous two checks are skipped. In other words, if the striping EA is not set, 0, 0, -1, will be printed for the striping count, size, and offset respectively. Also, if the striping EA is set, the values will be printed without first converting them into their respective defaults. This patch relies on the /proc filesystem to determine each filesystem's default striping attributes, and a cache is maintained which holds the default values for the last filesystem queried. See Also: Bugzilla #23802, https://bugzilla.lustre.org/show_bug.cgi?id=23802 Signed-off-by: Prakash Surya Change-Id: I9bf033f91411d2a6a55c3d4becb971ba20bb3c4b Reviewed-on: http://review.whamcloud.com/577 Tested-by: Hudson Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin --- lustre/doc/lfs.1 | 10 +- lustre/include/lustre/liblustreapi.h | 3 +- lustre/tests/sanity.sh | 118 ++++++++++++++++++++ lustre/utils/lfs.c | 8 +- lustre/utils/liblustreapi.c | 210 ++++++++++++++++++++++++++++++++--- 5 files changed, 329 insertions(+), 20 deletions(-) diff --git a/lustre/doc/lfs.1 b/lustre/doc/lfs.1 index 40ec5dc..5415367 100644 --- a/lustre/doc/lfs.1 +++ b/lustre/doc/lfs.1 @@ -27,7 +27,7 @@ lfs \- Lustre utility to create a file with specific striping pattern, find the .B lfs getstripe [--obd|-O ] [--quiet|-q] [--verbose|-v] \fB[--count | -c ] [--index | -i | --offset | -o ] \fB[--size | -s ] [--pool | -p ] [--directory | -d ] - \fB[--recursive | -r] ...\fR + \fB[--recursive | -r] [--raw|-R] ...\fR .br .B lfs setstripe [--size|-s stripe-size] [--count|-c stripe-cnt] \fB[--index|-i|--offset|-o start_ost_index ] [--pool|-p ] @@ -111,7 +111,7 @@ to that filesystem are displayed. .B getstripe [--obd|-O ] [--quiet|-q] [--verbose|-v] \fB[--count | -c ] [--index | -i | --offset | -o ] \fB[--pool | -p ] [--size | -s ] [--directory | -d ] - \fB[--recursive|-r] \fR + \fB[--recursive | -r ] [--raw | -R ] \fR .br List the striping information for a given filename or directory tree. By default the stripe count, size, and offset will be returned. If you @@ -124,6 +124,12 @@ or .B --pool can be used to return only the specific fields. .br +If the +.B --raw +option is specified, the stripe information is printed without substituting the +filesystem's default values for unspecified fields. If the striping EA is not +set, 0, 0, and -1 will be printed for the stripe count, size, and offset +respectively. In the case where you only want details about the files' object id information then the .B --quiet diff --git a/lustre/include/lustre/liblustreapi.h b/lustre/include/lustre/liblustreapi.h index 0c262c8..29931f1 100644 --- a/lustre/include/lustre/liblustreapi.h +++ b/lustre/include/lustre/liblustreapi.h @@ -138,7 +138,8 @@ struct find_param { exclude_atime:1, exclude_mtime:1, exclude_ctime:1, - get_mdt_index:1; + get_mdt_index:1, + raw:1; int verbose; int quiet; diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index d400b26..75506b6 100644 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -7666,6 +7666,124 @@ run_test 201c "Remove a pool ============================================" cleanup_pools $FSNAME +# usage: default_attr +default_attr() { + $LCTL get_param -n lov.$FSNAME-clilov-\*.stripe${1} +} + +# usage: trim +# Trims leading and trailing whitespace from the parameter string +trim() { + echo $@ +} + +# usage: check_default_stripe_attr +check_default_stripe_attr() { + # $GETSTRIPE returns trailing whitespace which needs to be trimmed off + ACTUAL=$(trim $($GETSTRIPE --$1 $DIR/$tdir)) + if [ $1 = "count" -o $1 = "size" ]; then + EXPECTED=`default_attr $1`; + else + # the 'stripeoffset' parameter prints as an unsigned int, so + # until this is fixed we hard-code -1 here + EXPECTED=-1; + fi + [ "x$ACTUAL" != "x$EXPECTED" ] && + error "$DIR/$tdir has stripe $1 '$ACTUAL', not '$EXPECTED'" +} + +# usage: check_raw_stripe_attr +check_raw_stripe_attr() { + # $GETSTRIPE returns trailing whitespace which needs to be trimmed off + ACTUAL=$(trim $($GETSTRIPE --raw --$1 $DIR/$tdir)) + if [ $1 = "count" -o $1 = "size" ]; then + EXPECTED=0; + else + EXPECTED=-1; + fi + [ "x$ACTUAL" != "x$EXPECTED" ] && + error "$DIR/$tdir has raw stripe $1 '$ACTUAL', not '$EXPECTED'" +} + + +test_204a() { + mkdir -p $DIR/$tdir + $SETSTRIPE --count 0 --size 0 --offset -1 $DIR/$tdir + + check_default_stripe_attr count + check_default_stripe_attr size + check_default_stripe_attr offset + + return 0 +} +run_test 204a "Print default stripe attributes =================" + +test_204b() { + mkdir -p $DIR/$tdir + $SETSTRIPE --count 1 $DIR/$tdir + + check_default_stripe_attr size + check_default_stripe_attr offset + + return 0 +} +run_test 204b "Print default stripe size and offset ===========" + +test_204c() { + mkdir -p $DIR/$tdir + $SETSTRIPE --size 65536 $DIR/$tdir + + check_default_stripe_attr count + check_default_stripe_attr offset + + return 0 +} +run_test 204c "Print default stripe count and offset ===========" + +test_204d() { + mkdir -p $DIR/$tdir + $SETSTRIPE --offset 0 $DIR/$tdir + + check_default_stripe_attr count + check_default_stripe_attr size + + return 0 +} +run_test 204d "Print default stripe count and size =============" + +test_204f() { + mkdir -p $DIR/$tdir + $SETSTRIPE --count 1 $DIR/$tdir + + check_raw_stripe_attr size + check_raw_stripe_attr offset + + return 0 +} +run_test 204f "Print raw stripe size and offset ===========" + +test_204g() { + mkdir -p $DIR/$tdir + $SETSTRIPE --size 65536 $DIR/$tdir + + check_raw_stripe_attr count + check_raw_stripe_attr offset + + return 0 +} +run_test 204g "Print raw stripe count and offset ===========" + +test_204h() { + mkdir -p $DIR/$tdir + $SETSTRIPE --offset 0 $DIR/$tdir + + check_raw_stripe_attr count + check_raw_stripe_attr size + + return 0 +} +run_test 204h "Print raw stripe count and size =============" + test_212() { size=`date +%s` size=$((size % 8192 + 1)) diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index 57f3ecc..39ab666 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -134,7 +134,8 @@ command_t cmdlist[] = { "usage: getstripe [--obd|-O ] [--quiet | -q] [--verbose | -v]\n" " [--count | -c ] [--index | -i | --offset | -o]\n" " [--size | -s ] [--pool | -p ] [--directory | -d]\n" - " [--mdt | -M] [--recursive | -r] ..."}, + " [--mdt | -M] [--recursive | -r] [--raw | -R]\n" + " ..."}, {"pool_list", lfs_poollist, 0, "List pools or pool OSTs\n" "usage: pool_list [.] | \n"}, @@ -809,7 +810,7 @@ static int lfs_getstripe(int argc, char **argv) param.maxdepth = 1; optind = 0; - while ((c = getopt_long(argc, argv, "cdhiMoO:pqrsv", + while ((c = getopt_long(argc, argv, "cdhiMoO:pqrRsv", long_opts, NULL)) != -1) { switch (c) { case 'O': @@ -861,6 +862,9 @@ static int lfs_getstripe(int argc, char **argv) case 'M': param.get_mdt_index = 1; break; + case 'R': + param.raw = 1; + break; case '?': return CMD_HELP; default: diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index 7f2e769..aec243b 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -1395,10 +1395,164 @@ int llapi_ostlist(char *path, struct find_param *param) return ret; } +/* + * Given a filesystem name, or a pathname of a file on a lustre filesystem, + * tries to determine the path to the filesystem's clilov directory under /proc + * + * fsname is limited to MTI_NAME_MAXLEN in lustre_idl.h + * The NUL terminator is compensated by the additional "%s" bytes. */ +#define LOV_LEN (sizeof("/proc/fs/lustre/lov/%s-clilov-*") + MTI_NAME_MAXLEN) +static int clilovpath(const char *fsname, const char *const pathname, + char *clilovpath) +{ + int rc; + char pattern[LOV_LEN]; + char buffer[PATH_MAX + 1]; + + if (fsname == NULL) { + if ((rc = llapi_search_fsname(pathname, buffer)) != 0) + return rc; + fsname = buffer; + } + + snprintf(pattern, sizeof(pattern), "/proc/fs/lustre/lov/%s-clilov-*", + fsname); + + if ((rc = first_match(pattern, buffer)) != 0) + return rc; + + strncpy(clilovpath, buffer, sizeof(buffer)); + + return 0; +} + +/* + * Given the path to a stripe attribute proc file, tries to open and + * read the attribute and return the value using the attr parameter + */ +static int sattr_read_attr(const char *const fpath, + unsigned int *attr) +{ + + FILE *f; + char line[PATH_MAX + 1]; + int rc = 0; + + if ((f = fopen(fpath, "r")) == NULL) { + llapi_err(LLAPI_MSG_ERROR, "Cannot open '%s'", fpath); + return errno; + } + + if (fgets(line, sizeof(line), f) != NULL) { + *attr = atoi(line); + } else { + llapi_err(LLAPI_MSG_ERROR, "Cannot read from '%s'", fpath); + rc = 1; + } + + fclose(f); + return rc; +} + +/* + * Tries to determine the default stripe attributes for a given filesystem. The + * filesystem to check should be specified by fsname, or will be determined + * using pathname. + */ +static int sattr_get_defaults(const char *const fsname, + const char *const pathname, + unsigned int *scount, + unsigned int *ssize, + unsigned int *soffset) +{ + int rc; + char dpath[PATH_MAX + 1]; + char fpath[PATH_MAX + 1]; + + if ((rc = clilovpath(fsname, pathname, dpath)) != 0) + return rc; + + if (scount) { + snprintf(fpath, PATH_MAX, "%s/stripecount", dpath); + if ((rc = sattr_read_attr(fpath, scount)) != 0) + return rc; + } + + if (ssize) { + snprintf(fpath, PATH_MAX, "%s/stripesize", dpath); + if ((rc = sattr_read_attr(fpath, ssize)) != 0) + return rc; + } + + if (soffset) { + snprintf(fpath, PATH_MAX, "%s/stripeoffset", dpath); + if ((rc = sattr_read_attr(fpath, soffset)) != 0) + return rc; + } + + return 0; +} + +/* + * Tries to gather the default stripe attributes for a given filesystem. If + * the attributes can be determined, they are cached for easy retreival the + * next time they are needed. Only a single filesystem's attributes are + * cached at a time. + */ +static int sattr_cache_get_defaults(const char *const fsname, + const char *const pathname, + unsigned int *scount, + unsigned int *ssize, + unsigned int *soffset) +{ + static struct { + char fsname[PATH_MAX + 1]; + unsigned int stripecount; + unsigned int stripesize; + unsigned int stripeoffset; + } cache = { + .fsname = {'\0'} + }; + + int rc; + char fsname_buf[PATH_MAX + 1]; + unsigned int tmp[3]; + + if (fsname == NULL) + llapi_search_fsname(pathname, fsname_buf); + else + strncpy(fsname_buf, fsname, PATH_MAX); + + if (strncmp(fsname_buf, cache.fsname, PATH_MAX) != 0) { + /* + * Ensure all 3 sattrs (count, size, and offset) are + * successfully retrieved and stored in tmp before writing to + * cache. + */ + if ((rc = sattr_get_defaults(fsname_buf, NULL, &tmp[0], + &tmp[1], &tmp[2])) != 0) + return rc; + + cache.stripecount = tmp[0]; + cache.stripesize = tmp[1]; + cache.stripeoffset = tmp[2]; + strncpy(cache.fsname, fsname_buf, PATH_MAX); + } + + if (scount) + *scount = cache.stripecount; + if (ssize) + *ssize = cache.stripesize; + if (soffset) + *soffset = cache.stripeoffset; + + return 0; +} + static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, struct lov_user_ost_data_v1 *objects, int is_dir, int verbose, int depth, - char *pool_name) + int raw, char *pool_name) { char *prefix = is_dir ? "" : "lmm_"; char nl = is_dir ? ' ' : '\n'; @@ -1425,22 +1579,48 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, if (verbose & ~VERBOSE_COUNT) llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_count: ", prefix); - if (is_dir) - llapi_printf(LLAPI_MSG_NORMAL, "%d%c", - lum->lmm_stripe_count == - (typeof(lum->lmm_stripe_count))(-1) ? -1 : - lum->lmm_stripe_count, nl); - else + if (is_dir) { + if (!raw && lum->lmm_stripe_count == 0) { + unsigned int scount; + if (sattr_cache_get_defaults(NULL, path, + &scount, NULL, + NULL) == 0) + llapi_printf(LLAPI_MSG_NORMAL, "%u%c", + scount, nl); + else + llapi_err(LLAPI_MSG_ERROR, + "Cannot determine default" + " stripe count."); + } else { + llapi_printf(LLAPI_MSG_NORMAL, "%d%c", + lum->lmm_stripe_count == + (typeof(lum->lmm_stripe_count))(-1) + ? -1 : lum->lmm_stripe_count, nl); + } + } else { llapi_printf(LLAPI_MSG_NORMAL, "%hd%c", (__s16)lum->lmm_stripe_count, nl); + } } if (verbose & VERBOSE_SIZE) { if (verbose & ~VERBOSE_SIZE) llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_size: ", prefix); - llapi_printf(LLAPI_MSG_NORMAL, "%u%c", lum->lmm_stripe_size, - nl); + if (is_dir && !raw && lum->lmm_stripe_size == 0) { + unsigned int ssize; + if (sattr_cache_get_defaults(NULL, path, NULL, &ssize, + NULL) == 0) + llapi_printf(LLAPI_MSG_NORMAL, "%u%c", ssize, + nl); + else + llapi_err(LLAPI_MSG_ERROR, + "Cannot determine default" + " stripe size."); + } else { + llapi_printf(LLAPI_MSG_NORMAL, "%u%c", + lum->lmm_stripe_size, nl); + } } if ((verbose & VERBOSE_DETAIL) && !is_dir) { @@ -1452,7 +1632,7 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, if (verbose & ~VERBOSE_OFFSET) llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_offset: ", prefix); - if (is_dir) + if (is_dir) llapi_printf(LLAPI_MSG_NORMAL, "%d%c", lum->lmm_stripe_offset == (typeof(lum->lmm_stripe_offset))(-1) ? -1 : @@ -1476,7 +1656,7 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path, void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name, struct lov_user_ost_data_v1 *objects, char *path, int is_dir, - int obdindex, int depth, int header) + int obdindex, int depth, int header, int raw) { int i, obdstripe = (obdindex != OBD_NOT_FOUND) ? 0 : 1; @@ -1490,8 +1670,8 @@ void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name, } if (obdstripe == 1) - lov_dump_user_lmm_header(lum, path, objects, is_dir, header, depth, - pool_name); + lov_dump_user_lmm_header(lum, path, objects, is_dir, header, + depth, raw, pool_name); if (!is_dir && (header & VERBOSE_OBJID)) { if (obdstripe == 1) @@ -1521,7 +1701,7 @@ void llapi_lov_dump_user_lmm(struct find_param *param, param->lmd->lmd_lmm.lmm_objects, path, is_dir, param->obdindex, param->maxdepth, - param->verbose); + param->verbose, param->raw); break; case LOV_USER_MAGIC_V3: { char pool_name[LOV_MAXPOOLNAME + 1]; @@ -1534,7 +1714,7 @@ void llapi_lov_dump_user_lmm(struct find_param *param, lov_dump_user_lmm_v1v3(¶m->lmd->lmd_lmm, pool_name, objects, path, is_dir, param->obdindex, param->maxdepth, - param->verbose); + param->verbose, param->raw); break; } default: -- 1.8.3.1