X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Futils%2Flfs.c;h=68a74dabd172955306a0a3861717b13e9b2c7ebf;hp=da2477ec1166e08668c0adea7cdc8c0694f001d7;hb=b54b7ce43929ce7ff6e48cd219623c264ca6b6b3;hpb=00d14521ca1cd38a5fff82e1639ad3cc944ee13d diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index da2477e..68a74da 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -27,7 +27,6 @@ */ /* * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. * * lustre/utils/lfs.c * @@ -76,11 +75,8 @@ #include #include #include -#include - -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0]))) -#endif /* !ARRAY_SIZE */ +#include +#include "lstddef.h" /* all functions */ static int lfs_find(int argc, char **argv); @@ -88,6 +84,7 @@ static int lfs_getstripe(int argc, char **argv); static int lfs_getdirstripe(int argc, char **argv); static int lfs_setdirstripe(int argc, char **argv); static int lfs_rmentry(int argc, char **argv); +static int lfs_unlink_foreign(int argc, char **argv); static int lfs_osts(int argc, char **argv); static int lfs_mdts(int argc, char **argv); static int lfs_df(int argc, char **argv); @@ -137,9 +134,14 @@ static int lfs_pcc_state(int argc, char **argv); static int lfs_pcc(int argc, char **argv); static int lfs_pcc_list_commands(int argc, char **argv); static int lfs_migrate_to_dom(int fd, int fdv, char *name, - __u64 migration_flags, - struct llapi_stripe_param *param, - struct llapi_layout *layout); + __u64 migration_flags); + +struct pool_to_id_cbdata { + const char *pool; + __u32 id; +}; +static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata); +static int find_mirror_id_by_pool(struct llapi_layout *layout, void *cbdata); enum setstripe_origin { SO_SETSTRIPE, @@ -150,6 +152,7 @@ enum setstripe_origin { SO_MIRROR_SPLIT, SO_MIRROR_DELETE, }; + static int lfs_setstripe_internal(int argc, char **argv, enum setstripe_origin opc); @@ -157,22 +160,27 @@ static inline int lfs_setstripe(int argc, char **argv) { return lfs_setstripe_internal(argc, argv, SO_SETSTRIPE); } + static inline int lfs_setstripe_migrate(int argc, char **argv) { return lfs_setstripe_internal(argc, argv, SO_MIGRATE); } + static inline int lfs_mirror_create(int argc, char **argv) { return lfs_setstripe_internal(argc, argv, SO_MIRROR_CREATE); } + static inline int lfs_mirror_extend(int argc, char **argv) { return lfs_setstripe_internal(argc, argv, SO_MIRROR_EXTEND); } + static inline int lfs_mirror_split(int argc, char **argv) { return lfs_setstripe_internal(argc, argv, SO_MIRROR_SPLIT); } + static inline int lfs_mirror_delete(int argc, char **argv) { return lfs_setstripe_internal(argc, argv, SO_MIRROR_DELETE); @@ -180,111 +188,46 @@ static inline int lfs_mirror_delete(int argc, char **argv) /* Setstripe and migrate share mostly the same parameters */ #define SSM_CMD_COMMON(cmd) \ - "usage: "cmd" [--component-end|-E ]\n" \ - " [--stripe-count|-c ]\n" \ - " [--overstripe-count|-C ]\n" \ - " [--stripe-index|-i ]\n" \ - " [--stripe-size|-S ]\n" \ - " [--layout|-L ]\n" \ - " [--pool|-p ]\n" \ - " [--ost|-o ]\n" \ - " [--yaml|-y ]\n" \ - " [--copy=]\n" - -#define SSM_HELP_COMMON \ - "\tstripe_count: Number of OSTs to stripe over (0=fs default, -1 all)\n" \ - "\t Using -C instead of -c allows overstriping, which\n" \ - "\t will place more than one stripe per OST if\n" \ - "\t stripe_count is greater than the number of OSTs\n" \ - "\tstart_ost_idx: OST index of first stripe (-1=default round robin)\n"\ - "\tstripe_size: Number of bytes on each OST (0=fs default)\n" \ - "\t Can be specified with K, M or G (for KB, MB, GB\n" \ - "\t respectively)\n" \ - "\tpool_name: Name of OST pool to use (default none)\n" \ - "\tlayout: stripe pattern type: raid0, mdt (default raid0)\n"\ - "\tost_indices: List of OST indices, can be repeated multiple times\n"\ - "\t Indices be specified in a format of:\n" \ - "\t -o ,-,\n" \ - "\t Or:\n" \ - "\t -o -o - -o \n" \ - "\t If --pool is set with --ost, then the OSTs\n" \ - "\t must be the members of the pool.\n" \ - "\tcomp_end: Extent end of component, start after previous end.\n"\ - "\t Can be specified with K, M or G (for KB, MB, GB\n" \ - "\t respectively, -1 for EOF). Must be a multiple of\n"\ - "\t stripe_size.\n" \ - "\tyaml_template_file:\n" \ - "\t YAML layout template file, can't be used with -c,\n" \ - "\t -i, -S, -p, -o, or -E arguments.\n" \ - "\tlustre_src: Lustre file/dir whose layout info is used to set\n" \ - "\t another lustre file or directory, can't used with\n" \ - "\t -c, -i, -S, -p, -o, or -E arguments.\n" - -#define MIRROR_CREATE_HELP \ - "\tmirror_count: Number of mirrors to be created with the upcoming\n" \ - "\t setstripe layout options\n" \ - "\t It defaults to 1 if not specified; if specified,\n" \ - "\t it must follow the option without a space.\n" \ - "\t The option can also be repeated multiple times to\n" \ - "\t separate mirrors that have different layouts.\n" \ - "\tsetstripe options: Mirror layout\n" \ - "\t It can be a plain layout or a composite layout.\n" \ - "\t If not specified, the stripe options inherited\n" \ - "\t from the previous component will be used.\n" \ - "\tflags: set flags to the component of the current mirror.\n" \ - "\t Only \"prefer\" flag is supported so far.\n" - -#define MIRROR_EXTEND_HELP \ - MIRROR_CREATE_HELP \ - "\tvictim_file: The layout of victim_file will be split and used\n" \ - "\t as a mirror added to the mirrored file.\n" \ - "\tno-verify: This option indicates not to verify the mirror(s)\n" \ - "\t from victim file(s) in case the victim file(s)\n" \ - "\t contains the same data as the original mirrored\n" \ - "\t file.\n" - -#define MIRROR_EXTEND_USAGE \ - " <--mirror-count|-N[mirror_count]>\n" \ - " [setstripe options|-f ]\n" \ + "usage: "cmd" [--component-end|-E COMP_END]\n" \ + " [--copy=LUSTRE_SRC]\n" \ + " [--extension-size|--ext-size|-z SIZE]\n" \ + " [--help|-h] [--layout|-L PATTERN]\n" \ + " [--layout|-L PATTERN]\n" \ + " [--mirror-count|-N[MIRROR_COUNT]]\n" \ + " [--ost|-o OST_INDICES]\n" \ + " [--overstripe-count|-C STRIPE_COUNT]\n" \ + " [--pool|-p POOL_NAME]\n" \ + " [--stripe-count|-c STRIPE_COUNT]\n" \ + " [--stripe-index|-i START_OST_IDX]\n" \ + " [--stripe-size|-S STRIPE_SIZE]\n" \ + " [--yaml|-y YAML_TEMPLATE_FILE]\n" + +#define MIRROR_EXTEND_USAGE \ + " {--mirror-count|-N[MIRROR_COUNT]}\n" \ + " [SETSTRIPE_OPTIONS|-f|--file VICTIM_FILE]\n" \ " [--no-verify]\n" #define SETSTRIPE_USAGE \ SSM_CMD_COMMON("setstripe") \ MIRROR_EXTEND_USAGE \ - " \n" \ - SSM_HELP_COMMON \ - MIRROR_EXTEND_HELP + " DIRECTORY|FILENAME\n" #define MIGRATE_USAGE \ SSM_CMD_COMMON("migrate ") \ " [--block|-b] [--non-block|-n]\n" \ " [--non-direct|-D] [--verbose|-v]\n" \ - " \n" \ - SSM_HELP_COMMON \ - "\n" \ - "\tblock: Block file access during data migration (default)\n" \ - "\tnon-block: Abort migrations if concurrent access is detected\n" \ - "\tnon-direct: Do not use direct I/O to copy file contents\n" \ - "\tverbose: Print each filename as it is migrated\n" \ + " FILENAME\n" #define SETDIRSTRIPE_USAGE \ " [--mdt-count|-c stripe_count>\n" \ - " [--mdt-hash|-H mdt_hash]\n" \ + " [--help|-h] [--mdt-hash|-H mdt_hash]\n" \ " [--mdt-index|-i mdt_index[,mdt_index,...]\n" \ - " [--default|-D] [--mode|-o mode] \n" \ - "\tstripe_count: stripe count of the striped directory\n" \ - "\tmdt_index: MDT index of first stripe\n" \ - "\tmdt_hash: hash type of the striped directory. mdt types:\n" \ - " fnv_1a_64 FNV-1a hash algorithm (default)\n" \ - " all_char sum of characters % MDT_COUNT (not recommended)\n" \ - " space create subdirectories with balanced space usage\n" \ - "\tdefault_stripe: set default dirstripe of the directory\n" \ - "\tmode: the file access permission of the directory (octal)\n" \ - "To create dir with a foreign (free format) layout :\n" \ - "setdirstripe|mkdir --foreign[=] -x|-xattr " \ - "[--mode|-m mode] [--flags ] \n" \ - "\tmode: the mode of the directory\n" \ - "\tforeign_type: none or daos\n" + " [--default|-D] [--mode|-o mode]\n" \ + " [--max-inherit|-X max_inherit]\n" \ + " [--max-inherit-rr max_inherit_rr] \n" \ + "To create dir with a foreign (free format) layout :\n" \ + "setdirstripe|mkdir --foreign[=FOREIGN_TYPE] -x|-xattr STRING " \ + " [--mode|-o MODE] [--flags HEX] DIRECTORY\n" /** * command_t mirror_cmdlist - lfs mirror commands. @@ -292,54 +235,44 @@ static inline int lfs_mirror_delete(int argc, char **argv) command_t mirror_cmdlist[] = { { .pc_name = "create", .pc_func = lfs_mirror_create, .pc_help = "Create a mirrored file.\n" - "usage: lfs mirror create " - "<--mirror-count|-N[mirror_count]> " - "[setstripe options] ... ...\n" - MIRROR_CREATE_HELP }, + "usage: lfs mirror create --mirror-count|-N[MIRROR_COUNT]\n" + " [SETSTRIPE_OPTIONS] ... FILENAME|DIRECTORY ...\n" }, { .pc_name = "delete", .pc_func = lfs_mirror_delete, - .pc_help = "delete a mirror from a file.\n" - "usage: lfs mirror delete {--comp-id|-I |-p } ...\n" + .pc_help = "Delete a mirror from a file.\n" + "usage: lfs mirror delete {--mirror-id |\n" + "\t --component-id|--comp-id|-I COMP_ID |\n" + "\t -p } MIRRORED_FILE ...\n" }, { .pc_name = "extend", .pc_func = lfs_mirror_extend, .pc_help = "Extend a mirrored file.\n" "usage: lfs mirror extend " - "<--mirror-count|-N[mirror_count]> [--no-verify] " - "[setstripe options|-f ] ... ...\n" - MIRROR_EXTEND_HELP }, + "{--mirror-count|-N[MIRROR_COUNT]} [--no-verify] " + "[SETSTRIPE_OPTIONS|-f VICTIM_FILE] ... FILENAME ...\n" }, { .pc_name = "split", .pc_func = lfs_mirror_split, .pc_help = "Split a mirrored file.\n" - "usage: lfs mirror split <--mirror-id |\n" - "\t <--component-id|-I |-p > [--destroy|-d]\n" - "\t [-f ] ...\n" - "\tmirror_id: The numerical unique identifier for a mirror. It\n" - "\t can be fetched by lfs getstripe command.\n" - "\tcomp_id: Unique component ID within a mirror.\n" - "\tpool: Components on specified pool.\n" - "\tnew_file: This option indicates the layout of the split\n" - "\t mirror will be stored into. If not specified,\n" - "\t a new file named .mirror~\n" - "\t will be used.\n" }, + "usage: lfs mirror split {--mirror-id MIRROR_ID |\n" + "\t --component-id|-I COMP_ID|-p POOL} [--destroy|-d]\n" + "\t [-f NEW_FILE] MIRRORED_FILE ...\n" }, { .pc_name = "read", .pc_func = lfs_mirror_read, .pc_help = "Read the content of a specified mirror of a file.\n" - "usage: lfs mirror read <--mirror-id|-N " - "[--outfile|-o ] \n" }, + "usage: lfs mirror read {--mirror-id|-N MIRROR_ID}\n" + "\t\t[--outfile|-o ] \n" }, { .pc_name = "write", .pc_func = lfs_mirror_write, .pc_help = "Write to a specified mirror of a file.\n" - "usage: lfs mirror write <--mirror-id|-N " - "[--inputfile|-i ] \n" }, + "usage: lfs mirror write {--mirror-id|-N MIRROR_ID}\n" + "\t\t[--inputfile|-i ] \n" }, { .pc_name = "copy", .pc_func = lfs_mirror_copy, .pc_help = "Copy a specified mirror to other mirror(s) of a file.\n" - "usage: lfs mirror copy <--read-mirror|-i > " - "<--write-mirror|-o > \n" }, + "usage: lfs mirror copy {--read-mirror|-i MIRROR_ID0}\n" + "\t\t{--write-mirror|-o MIRROR_ID1[,...]} \n" }, { .pc_name = "resync", .pc_func = lfs_mirror_resync, .pc_help = "Resynchronizes out-of-sync mirrored file(s).\n" - "usage: lfs mirror resync [--only ] " - " [...]\n"}, + "usage: lfs mirror resync [--only MIRROR_ID[,...]>]\n" + "\t\t [...]\n" }, { .pc_name = "verify", .pc_func = lfs_mirror_verify, .pc_help = "Verify mirrored file(s).\n" - "usage: lfs mirror verify " - "[--only ] " - "[--verbose|-v] [ ...]\n"}, + "usage: lfs mirror verify [--only MIRROR_ID[,...]]\n" + "\t\t[--verbose|-v] [ ...]\n" }, { .pc_name = "list-commands", .pc_func = lfs_mirror_list_commands, .pc_help = "list commands supported by lfs mirror"}, { .pc_name = "help", .pc_func = Parser_help, .pc_help = "help" }, @@ -358,8 +291,7 @@ command_t pcc_cmdlist[] = { "\t-i: archive id for RW-PCC\n" }, { .pc_name = "attach_fid", .pc_func = lfs_pcc_attach_fid, .pc_help = "Attach given files into PCC by FID(s).\n" - "usage: lfs pcc attach_id <--id|-i NUM> <--mnt|-m mnt> " - " ...\n" + "usage: lfs pcc attach_id {--id|-i NUM} {--mnt|-m MOUNTPOINT} FID ...\n" "\t-i: archive id for RW-PCC\n" "\t-m: Lustre mount point\n" }, { .pc_name = "state", .pc_func = lfs_pcc_state, @@ -385,63 +317,69 @@ command_t cmdlist[] = { "To create a file with specified striping/composite layout, or\n" "create/replace the default layout on an existing directory:\n" SSM_CMD_COMMON("setstripe") - " [--mode ]\n" + " [--mode MODE]\n" " \n" " or\n" "To add component(s) to an existing composite file:\n" SSM_CMD_COMMON("setstripe --component-add") - SSM_HELP_COMMON "To totally delete the default striping from an existing directory:\n" - "usage: setstripe -d \n" + "usage: setstripe [--delete|-d] \n" " or\n" "To create a mirrored file or set s default mirror layout on a directory:\n" - "usage: setstripe -N[mirror_count] [STRIPE_OPTIONS] \n" + "usage: setstripe {--mirror-count|-N}[MIRROR_COUNT] [SETSTRIPE_OPTIONS] \n" " or\n" "To delete the last component(s) from an existing composite file\n" "(note that this will also delete any data in those components):\n" - "usage: setstripe --component-del [--component-id|-I ]\n" - " [--component-flags|-F ]\n" + "usage: setstripe --component-del [--component-id|-I COMP_ID]\n" + " [--component-flags|-F COMP_FLAGS]\n" " \n" - "\tcomp_id: Unique component ID to delete\n" - "\tcomp_flags: 'init' indicating all instantiated components\n" + "\tCOMP_ID: Unique component ID to delete\n" + "\tCOMP_FLAGS: 'init' indicating all instantiated components\n" "\t '^init' indicating all uninstantiated components\n" "\t-I and -F cannot be specified at the same time\n" + " or\n" + "To set or clear flags on a specific component\n" + "(note that this command can only be applied to mirrored files:\n" + "usage: setstripe --comp-set {-I COMP_ID|--comp-flags=COMP_FLAGS}\n" + " \n" + " or\n" "To create a file with a foreign (free format) layout:\n" - "usage: setstripe --foreign[=]\n" - " --xattr|-x [--flags ]\n" - " [--mode ] \n"}, + "usage: setstripe --foreign[=FOREIGN_TYPE]\n" + " --xattr|-x LAYOUT_STRING [--flags HEX]\n" + " [--mode MODE] \n"}, {"getstripe", lfs_getstripe, 0, "To list the layout pattern for a given file or files in a\n" "directory or recursively for all files in a directory tree.\n" - "usage: getstripe [--ost|-O ] [--quiet|-q] [--verbose|-v]\n" + "usage: getstripe [--ost|-O UUID] [--quiet|-q] [--verbose|-v]\n" " [--stripe-count|-c] [--stripe-index|-i] [--fid|-F]\n" " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n" " [--mdt-index|-m] [--recursive|-r] [--raw|-R]\n" " [--layout|-L] [--generation|-g] [--yaml|-y]\n" - " [--component-id[=comp_id]|-I[comp_id]]\n" - " [--component-flags[=comp_flags]]\n" + " [--help|-h] [--component-id|-I[=COMP_ID]]\n" + " [--component-flags[=COMP_FLAGS]]\n" " [--component-count]\n" " [--extension-size|--ext-size|-z]\n" - " [--component-start[=[+-]comp_start]]\n" - " [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n" - " [[!] --mirror-index=[+-] |\n" - " [!] --mirror-id=[+-]]\n" + " [--component-start[=[+-]COMP_START]]\n" + " [--component-end[=[+-]COMP_END]|-E[[+-]comp_end]]\n" + " [[!] --mirror-index=[+-]INDEX |\n" + " [!] --mirror-id=[+-]MIRROR_ID] [--mirror-count|-N]\n" " ..."}, {"setdirstripe", lfs_setdirstripe, 0, - "To create a striped directory on a specified MDT. This can only\n" - "be done on MDT0 with the right of administrator.\n" + "Create striped directory on specified MDT, same as mkdir.\n" + "May be restricted to root or group users, depending on settings.\n" "usage: setdirstripe [OPTION] \n" SETDIRSTRIPE_USAGE}, {"getdirstripe", lfs_getdirstripe, 0, "To list the layout pattern info for a given directory\n" "or recursively for all directories in a directory tree.\n" "usage: getdirstripe [--mdt-count|-c] [--mdt-index|-m|-i]\n" - " [--mdt-hash|-H] [--obd|-O ]\n" + " [--help|-h] [--mdt-hash|-H] [--obd|-O UUID]\n" " [--recursive|-r] [--yaml|-y]\n" - " [--verbose|-v] [--default|-D] ..."}, + " [--verbose|-v] [--default|-D]\n" + " [--max-inherit|-X]\n" + " [--max-inherit-rr] ..."}, {"mkdir", lfs_setdirstripe, 0, - "To create a striped directory on a specified MDT. This can only\n" - "be done on MDT0 with the right of administrator.\n" + "Create striped directory on specified MDT, same as setdirstripe.\n" "usage: mkdir [OPTION] \n" SETDIRSTRIPE_USAGE}, {"rm_entry", lfs_rmentry, 0, @@ -450,46 +388,48 @@ command_t cmdlist[] = { "will become inaccessable after this command. This can only be done\n" "by the administrator\n" "usage: rm_entry \n"}, + {"unlink_foreign", lfs_unlink_foreign, 0, + "To remove the foreign file/dir.\n" + "Note: This is for files/dirs prevented to be removed using\n" + "unlink/rmdir, but works also for regular ones\n" + "usage: unlink_foreign [ ...]\n"}, {"pool_list", lfs_poollist, 0, "List pools or pool OSTs\n" "usage: pool_list [.] | \n"}, {"find", lfs_find, 0, "find files matching given attributes recursively in directory tree.\n" "usage: find ...\n" - " [[!] --atime|-A [+-]N[smhdwy]] [[!] --ctime|-C [+-]N[smhdwy]]\n" - " [[!] --mtime|-M [+-]N[smhdwy]] [[!] --blocks|-b N]\n" - " [[!] --newer[XY] ]\n" - " [--maxdepth|-D N] [[!] --mdt-index|--mdt|-m ]\n" - " [[!] --name|-n ] [[!] --ost|-O ]\n" - " [--print|-P] [--print0|-0] [[!] --size|-s [+-]N[bkMGTPE]]\n" - " [[!] --stripe-count|-c [+-]]\n" - " [[!] --stripe-index|-i ]\n" - " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t ]\n" - " [[!] --gid|-g|--group|-G |]\n" - " [[!] --uid|-u|--user|-U |] [[!] --pool ]\n" - " [[!] --projid ]\n" - " [[!] --foreign[=]]\n" - " [[!] --layout|-L released,raid0,mdt]\n" - " [[!] --foreign[=]]\n" - " [[!] --component-count [+-]]\n" + " [[!] --atime|-A [+-]N[smhdwy]] [[!] --btime|-B [+-]N[smhdwy]]\n" + " [[!] --ctime|-C [+-]N[smhdwy]] [[!] --mtime|-M [+-]N[smhdwy]]\n" + " [[!] --blocks|-b N] [[!] --component-count [+-]]\n" " [[!] --component-start [+-]N[kMGTPE]]\n" " [[!] --component-end|-E [+-]N[kMGTPE]]\n" - " [[!] --component-flags ]\n" + " [[!] --component-flags {init,stale,prefer,offline,nosync,extension}]\n" + " [[!] --extension-size|--ext-size|-z [+-]N[kMGT]]\n" + " [[!] --foreign[=]]\n" + " [[!] --gid|-g|--group|-G |] [--help|-h]\n" + " [[!] --layout|-L released,raid0,mdt] [--lazy]\n" + " [--maxdepth|-D N] [[!] --mdt-count|-T [+-]]\n" + " [[!] --mdt-hash|-H <[^][blm],[^]fnv_1a_64,all_char,crush,...>\n" + " [[!] --mdt-index|--mdt|-m ]\n" " [[!] --mirror-count|-N [+-]]\n" " [[!] --mirror-state <[^]state>]\n" - " [[!] --mdt-count|-T [+-]]\n" - " [[!] --mdt-hash|-H \n" - " [[!] --mdt-index|-m ]\n" - "\t !: used before an option indicates 'NOT' requested attribute\n" - "\t -: used before a value indicates less than requested value\n" - "\t +: used before a value indicates more than requested value\n" - "\thashtype: hash type of the striped directory.\n" - "\t fnv_1a_64 FNV-1a hash algorithm\n" - "\t all_char sum of characters % MDT_COUNT\n"}, + " [[!] --name|-n ] [[!] --newer[XY] ]\n" + " [[!] --ost|-O ] [[!] --perm [/-]mode]\n" + " [[!] --pool ] [--print|-P] [--print0|-0] [--printf ]\n" + " [[!] --projid ] [[!] --size|-s [+-]N[bkMGTPE]]\n" + " [[!] --stripe-count|-c [+-]]\n" + " [[!] --stripe-index|-i ]\n" + " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t ]\n" + " [[!] --uid|-u|--user|-U |]\n" + "\t !: used before an option indicates 'NOT' requested attribute\n" + "\t -: used before a value indicates less than requested value\n" + "\t +: used before a value indicates more than requested value\n" + "\t ^: used before a flag indicates to exclude it\n"}, {"check", lfs_check, 0, "Display the status of MGTs, MDTs or OSTs (as specified in the command)\n" "or all the servers (MGTs, MDTs and OSTs).\n" - "usage: check "}, + "usage: check {mgts|osts|mdts|all}"}, {"osts", lfs_osts, 0, "list OSTs connected to client " "[for specified path only]\n" "usage: osts [path]"}, {"mdts", lfs_mdts, 0, "list MDTs connected to client " @@ -497,52 +437,21 @@ command_t cmdlist[] = { {"df", lfs_df, 0, "report filesystem disk space usage or inodes usage " "of each MDS and all OSDs or a batch belonging to a specific pool.\n" - "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p [.] [path]"}, + "Usage: df [--inodes|-i] [--human-readable|-h] [--lazy|-l]\n" + " [--pool|-p [.]] [path]"}, {"getname", lfs_getname, 0, "list instances and specified mount points [for specified path only]\n" "Usage: getname [--help|-h] [--instance|-i] [--fsname|-n] [path ...]"}, #ifdef HAVE_SYS_QUOTA_H {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n" - "usage: setquota <-u|-g|-p> ||||\n" - " -b -B \n" - " -i -I \n" - " setquota <-u|--user|-g|--group|-p|--projid> ||||\n" - " [--block-softlimit ]\n" - " [--block-hardlimit ]\n" - " [--inode-softlimit ]\n" - " [--inode-hardlimit ] \n" - " setquota [-t] <-u|--user|-g|--group|-p|--projid>\n" - " [--block-grace ]\n" - " [--inode-grace ] \n" - " setquota <-U|-G|-P>\n" - " -b -B \n" - " -i -I \n" - " setquota <-U|--default-usr|-G|--default-grp|-P|--default-prj>\n" - " [--block-softlimit ]\n" - " [--block-hardlimit ]\n" - " [--inode-softlimit ]\n" - " [--inode-hardlimit ] \n" - " setquota <-u|-g|-p> ||||\n" - " <-d|--default>\n" - " -b can be used instead of --block-softlimit/--block-grace\n" - " -B can be used instead of --block-hardlimit\n" - " -i can be used instead of --inode-softlimit/--inode-grace\n" - " -I can be used instead of --inode-hardlimit\n" - " -d can be used instead of --default\n\n" - "Note: The total quota space will be split into many qunits and\n" - " balanced over all server targets, the minimal qunit size is\n" - " 1M bytes for block space and 1K inodes for inode space.\n\n" - " The maximum quota grace time is 2^48 - 1 seconds.\n\n" - " Quota space rebalancing process will stop when this mininum\n" - " value is reached. As a result, quota exceeded can be returned\n" - " while many targets still have 1MB or 1K inodes of spare\n" - " quota space."}, - {"quota", lfs_quota, 0, "Display disk usage and limits.\n" - "usage: quota [-q] [-v] [-h] [-o |-i |-I " - "]\n" - " [<-u|-g|-p> ||||] \n" - " quota [-o |-i |-I ] -t <-u|-g|-p> \n" - " quota [-q] [-v] [h] <-U|-G|-P> "}, + "usage: setquota [-t][-D] {-u|-U|-g|-G|-p|-P} {-b|-B|-i|-I LIMIT} [--pool POOL] FILESYSTEM\n" + " setquota {-u|-g|-p} --delete FILESYSTEM\n"}, + {"quota", lfs_quota, 0, "Display disk usage and limits.\n" + "usage: quota [-q] [-v] [-h] [-o OBD_UUID|-i MDT_IDX|-I OST_IDX]\n" + " [{-u|-g|-p} UNAME|UID|GNAME|GID|PROJID]\n" + " [--pool ] \n" + " quota -t <-u|-g|-p> [--pool ] \n" + " quota [-q] [-v] [h] {-U|-G|-P} [--pool ] "}, {"project", lfs_project, 0, "Change or list project attribute for specified file or directory.\n" "usage: project [-d|-r] \n" @@ -551,30 +460,32 @@ command_t cmdlist[] = { " set project ID and/or inherit flag for specified file(s) or directories\n" " project -c [-d|-r [-p id] [-0]] \n" " check project ID and flags on file(s) or directories, print outliers\n" - " project -C [-r] [-k] \n" + " project -C [-d|-r] [-k] \n" " clear the project inherit flag and ID on the file or directory\n" }, #endif - {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n" - "usage: flushctx [-k] [mountpoint...]"}, - {"changelog", lfs_changelog, 0, - "Show the metadata changes on an MDT." - "\nusage: changelog [startrec [endrec]]"}, - {"changelog_clear", lfs_changelog_clear, 0, - "Indicate that old changelog records up to are no longer of " - "interest to consumer , allowing the system to free up space.\n" - "An of 0 means all records.\n" - "usage: changelog_clear "}, + {"flushctx", lfs_flushctx, 0, + "Flush security context for current user.\n" + "usage: flushctx [-k] [-r] [mountpoint...]"}, + {"changelog", lfs_changelog, 0, + "Show the metadata changes on an MDT." + "\nusage: changelog [startrec [endrec]]"}, + {"changelog_clear", lfs_changelog_clear, 0, + "Indicate that old changelog records up to are no longer of " + "interest to consumer , allowing the system to free up space.\n" + "An of 0 means all records.\n" + "usage: changelog_clear "}, {"fid2path", lfs_fid2path, 0, "Resolve the full path(s) for given FID(s). For a specific hardlink " "specify link number .\n" - "usage: fid2path [-c] [--link|-l ] ..."}, + "usage: fid2path [--print-fid|-f] [--print-link|-c] [--link|-l ] " + " ..."}, {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n" "usage: path2fid [--parents] ..."}, {"rmfid", lfs_rmfid, 0, "Remove file(s) by FID(s)\n" "usage: rmfid ..."}, {"data_version", lfs_data_version, 0, "Display file data version for " - "a given path.\n" "usage: data_version -[n|r|w] "}, + "a given path.\n" "usage: data_version [-n|-r|-w] "}, {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, " "undergoing actions) for given files.\n usage: hsm_state ..."}, {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n" @@ -613,53 +524,25 @@ command_t cmdlist[] = { {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n" "usage: swap_layouts "}, {"migrate", lfs_setstripe_migrate, 0, - "migrate a directory between MDTs.\n" - "usage: migrate [--mdt-count|-c] \n" - " [--mdt-hash|-H] \n" - " [--mdt-index|-m] \n" - " [--verbose|-v]\n" - " \n" - "\tmdt: MDTs to stripe over, if only one MDT is specified\n" - " it's the MDT index of first stripe\n" - "\tmdt_count: number of MDTs to stripe a directory over\n" - "\tmdt_hash: hash type of the striped directory. mdt types:\n" - " fnv_1a_64 FNV-1a hash algorithm (default)\n" - " all_char sum of characters % MDT_COUNT\n" + "migrate directories and their inodes between MDTs.\n" + "usage: migrate [--mdt-count|-c STRIPE_COUNT] [--directory|-d]\n" + " [--mdt-hash|-H HASH_TYPE]\n" + " [--mdt-index|-m START_MDT_INDEX] [--verbose|-v]\n" + " DIRECTORY\n" "\n" - "migrate file objects from one OST " - "layout\nto another (may be not safe with concurent writes).\n" - "usage: migrate " - "[--stripe-count|-c] \n" - "[--overstripe-count|-C] \n" - " [--stripe-index|-i] \n" - " [--stripe-size|-S] \n" - " [--pool|-p] \n" - " [--ost|-o] \n" - " [--block|-b]\n" - " [--non-block|-n]\n" - " [--non-direct|-D]\n" - " \n" - "\tstripe_count: number of OSTs to stripe a file over\n" - "\t Using -C instead of -c allows overstriping, which\n" - "\t will place more than one stripe per OST if\n" - "\t stripe_count is greater than the number of OSTs\n" - "\tstripe_ost_index: index of the first OST to stripe a file over\n" - "\tstripe_size: number of bytes to store before moving to the next OST\n" - "\tpool_name: name of the predefined pool of OSTs\n" - "\tost_indices: OSTs to stripe over, in order\n" - "\tblock: Block file access during data migration (default)\n" - "\tnon-block: Abort migrations if concurrent access is detected\n" - "\tnon-direct: do not use direct I/O to copy file contents.\n"}, + "migrate file objects from one OST layout to another\n" + "(may be not safe with concurent writes).\n" + MIGRATE_USAGE }, {"mv", lfs_mv, 0, "To move directories between MDTs. This command is deprecated, " "use \"migrate\" instead.\n" - "usage: mv [--mdt-index|-m] " + "usage: mv [--mdt-index|-m MDT_INDEX] " "[--verbose|-v]\n"}, {"ladvise", lfs_ladvise, 0, "Provide servers with advice about access patterns for a file.\n" "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n" " [--background|-b] [--unset|-u]\n\n" - " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n" + " {--end|-e END[kMGT]|--length|-l LENGTH[kMGT]}\n" " {[--mode|-m [READ,WRITE]}\n" " ...\n"}, {"mirror", lfs_mirror, mirror_cmdlist, @@ -703,12 +586,16 @@ command_t cmdlist[] = { { 0, 0, 0, NULL } }; - static int check_hashtype(const char *hashtype) { + int type_num = atoi(hashtype); int i; - for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++) + /* numeric hash type */ + if (hashtype && lmv_is_known_hash_type(type_num)) + return type_num; + /* string hash type */ + for (i = LMV_HASH_TYPE_ALL_CHARS; i < ARRAY_SIZE(mdt_hash_name); i++) if (strcmp(hashtype, mdt_hash_name[i]) == 0) return i; @@ -720,7 +607,7 @@ static uint32_t check_foreign_type_name(const char *foreign_type_name) uint32_t i; for (i = 0; i < LU_FOREIGN_TYPE_UNKNOWN; i++) { - if (lu_foreign_types[i].lft_name == NULL) + if (!lu_foreign_types[i].lft_name) break; if (strcmp(foreign_type_name, lu_foreign_types[i].lft_name) == 0) @@ -732,16 +619,6 @@ static uint32_t check_foreign_type_name(const char *foreign_type_name) static const char *error_loc = "syserror"; -enum { - MIGRATION_NONBLOCK = 0x0001, - MIGRATION_MIRROR = 0x0002, - MIGRATION_NONDIRECT = 0x0004, - MIGRATION_VERBOSE = 0x0008, -}; - -static int lfs_component_create(char *fname, int open_flags, mode_t open_mode, - struct llapi_layout *layout); - static int migrate_open_files(const char *name, __u64 migration_flags, const struct llapi_stripe_param *param, @@ -759,7 +636,7 @@ migrate_open_files(const char *name, __u64 migration_flags, struct stat st; struct stat stv; - if (param == NULL && layout == NULL) { + if (!param && !layout) { error_loc = "layout information"; return -EINVAL; } @@ -772,8 +649,8 @@ migrate_open_files(const char *name, __u64 migration_flags, strncpy(parent, name, sizeof(parent)); ptr = strrchr(parent, '/'); - if (ptr == NULL) { - if (getcwd(parent, sizeof(parent)) == NULL) { + if (!ptr) { + if (!getcwd(parent, sizeof(parent))) { error_loc = "getcwd"; return -errno; } @@ -783,14 +660,24 @@ migrate_open_files(const char *name, __u64 migration_flags, *ptr = '\0'; } - /* open file, direct io */ /* even if the file is only read, WR mode is nedeed to allow - * layout swap on fd */ - rflags = O_RDWR; - if (!(migration_flags & MIGRATION_NONDIRECT)) + * layout swap on fd + */ + /* Allow migrating even without the key on encrypted files */ + rflags = O_RDWR | O_NOATIME | O_FILE_ENC; + if (!(migration_flags & LLAPI_MIGRATION_NONDIRECT)) rflags |= O_DIRECT; +source_open: fd = open(name, rflags); if (fd < 0) { + /* If encrypted file without the key, + * retry mirror extend in O_DIRECT. + */ + if (errno == ENOKEY && !(rflags & O_DIRECT) && + migration_flags & LLAPI_MIGRATION_MIRROR) { + rflags |= O_DIRECT; + goto source_open; + } rc = -errno; error_loc = "cannot open source file"; return rc; @@ -803,25 +690,35 @@ migrate_open_files(const char *name, __u64 migration_flags, } do { - int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW; + int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW | + /* Allow migrating without the key on encrypted files */ + O_FILE_ENC; mode_t open_mode = S_IRUSR | S_IWUSR; + if (rflags & O_DIRECT) + open_flags |= O_DIRECT; random_value = random(); rc = snprintf(volatile_file, sizeof(volatile_file), - "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR, - mdt_index, random_value); + "%s/%s:%.4X:%.4X:fd=%.2d", parent, + LUSTRE_VOLATILE_HDR, mdt_index, + random_value, fd); if (rc >= sizeof(volatile_file)) { rc = -ENAMETOOLONG; break; } /* create, open a volatile file, use caching (ie no directio) */ - if (param != NULL) + if (layout) { + /* Returns -1 and sets errno on error: */ + fdv = llapi_layout_file_open(volatile_file, open_flags, + open_mode, layout); + if (fdv < 0) + fdv = -errno; + } else { + /* Does the right thing on error: */ fdv = llapi_file_open_param(volatile_file, open_flags, open_mode, param); - else - fdv = lfs_component_create(volatile_file, open_flags, - open_mode, layout); + } } while (fdv < 0 && (rc = fdv) == -EEXIST); if (rc < 0) { @@ -829,11 +726,14 @@ migrate_open_files(const char *name, __u64 migration_flags, goto out; } - /* In case the MDT does not support creation of volatile files - * we should try to unlink it. */ + /* + * In case the MDT does not support creation of volatile files + * we should try to unlink it. + */ (void)unlink(volatile_file); - /* Not-owner (root?) special case. + /* + * Not-owner (root?) special case. * Need to set owner/group of volatile file like original. * This will allow to pass related check during layout_swap. */ @@ -877,17 +777,16 @@ out: static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int)) { struct llapi_layout *layout; - size_t buf_size = 4 * 1024 * 1024; - void *buf = NULL; - ssize_t rsize = -1; - ssize_t wsize = 0; - size_t rpos = 0; - size_t wpos = 0; - off_t bufoff = 0; - int rc; + size_t buf_size = 4 * 1024 * 1024; + void *buf = NULL; + off_t pos = 0; + off_t data_end = 0; + size_t page_size = sysconf(_SC_PAGESIZE); + bool sparse; + int rc; layout = llapi_layout_get_by_fd(fd_src, 0); - if (layout != NULL) { + if (layout) { uint64_t stripe_size; rc = llapi_layout_stripe_size_get(layout, &stripe_size); @@ -898,74 +797,114 @@ static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int)) } /* Use a page-aligned buffer for direct I/O */ - rc = posix_memalign(&buf, getpagesize(), buf_size); + rc = posix_memalign(&buf, page_size, buf_size); if (rc != 0) return -rc; + sparse = llapi_file_is_sparse(fd_src); + if (sparse) { + rc = ftruncate(fd_dst, pos); + if (rc < 0) { + rc = -errno; + return rc; + } + } + while (1) { - /* read new data only if we have written all - * previously read data */ - if (wpos == rpos) { - if (check_file) { - rc = check_file(fd_src); + off_t data_off; + size_t to_read, to_write; + ssize_t rsize; + + if (sparse && pos >= data_end) { + size_t data_size; + + data_off = llapi_data_seek(fd_src, pos, &data_size); + if (data_off < 0) { + /* Non-fatal, switch to full copy */ + sparse = false; + continue; + } + /* hole at the end of file, truncate up to it */ + if (!data_size) { + rc = ftruncate(fd_dst, data_off); if (rc < 0) - break; + goto out; } + pos = data_off & ~(page_size - 1); + data_end = data_off + data_size; + to_read = ((data_end - pos - 1) | (page_size - 1)) + 1; + to_read = MIN(to_read, buf_size); + } else { + to_read = buf_size; + } - rsize = read(fd_src, buf, buf_size); - if (rsize < 0) { - rc = -errno; - break; - } - rpos += rsize; - bufoff = 0; + if (check_file) { + rc = check_file(fd_src); + if (rc < 0) + goto out; } - /* eof ? */ - if (rsize == 0) - break; - wsize = write(fd_dst, buf + bufoff, rpos - wpos); - if (wsize < 0) { + rsize = pread(fd_src, buf, to_read, pos); + if (rsize < 0) { rc = -errno; + goto out; + } + /* EOF */ + if (rsize == 0) break; + + to_write = rsize; + while (to_write > 0) { + ssize_t written; + + written = pwrite(fd_dst, buf, to_write, pos); + if (written < 0) { + rc = -errno; + goto out; + } + pos += written; + to_write -= written; } - wpos += wsize; - bufoff += wsize; + if (rc || rsize < to_read) + break; } - if (rc == 0) { - rc = fsync(fd_dst); - if (rc < 0) - rc = -errno; - } + rc = fsync(fd_dst); + if (rc < 0) + rc = -errno; +out: + /* Try to avoid page cache pollution after migration. */ + (void)posix_fadvise(fd_src, 0, 0, POSIX_FADV_DONTNEED); + (void)posix_fadvise(fd_dst, 0, 0, POSIX_FADV_DONTNEED); free(buf); return rc; } -static int migrate_copy_timestamps(int fd, int fdv) +static int migrate_set_timestamps(int fd, const struct stat *st) { - struct stat st; - - if (fstat(fd, &st) == 0) { - struct timeval tv[2] = { - {.tv_sec = st.st_atime}, - {.tv_sec = st.st_mtime} - }; - - return futimes(fdv, tv); - } + struct timeval tv[2] = { + {.tv_sec = st->st_atime}, + {.tv_sec = st->st_mtime} + }; - return -errno; + return futimes(fd, tv); } static int migrate_block(int fd, int fdv) { + struct stat st; __u64 dv1; int gid; int rc; int rc2; + rc = fstat(fd, &st); + if (rc < 0) { + error_loc = "cannot stat source file"; + return -errno; + } + rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH); if (rc < 0) { error_loc = "cannot get dataversion"; @@ -976,9 +915,11 @@ static int migrate_block(int fd, int fdv) gid = random(); while (gid == 0); - /* The grouplock blocks all concurrent accesses to the file. + /* + * The grouplock blocks all concurrent accesses to the file. * It has to be taken after llapi_get_data_version as it would - * block it too. */ + * block it too. + */ rc = llapi_group_lock(fd, gid); if (rc < 0) { error_loc = "cannot get group lock"; @@ -992,17 +933,19 @@ static int migrate_block(int fd, int fdv) } /* Make sure we keep original atime/mtime values */ - rc = migrate_copy_timestamps(fd, fdv); + rc = migrate_set_timestamps(fdv, &st); if (rc < 0) { - error_loc = "timestamp copy failed"; + error_loc = "set target file timestamp failed"; goto out_unlock; } - /* swap layouts + /* + * swap layouts * for a migration we need to check data version on file did * not change. * - * Pass in gid=0 since we already own grouplock. */ + * Pass in gid=0 since we already own grouplock. + */ rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0, SWAP_LAYOUTS_CHECK_DV1); if (rc == -EAGAIN) { @@ -1045,10 +988,17 @@ static int check_lease(int fd) static int migrate_nonblock(int fd, int fdv) { + struct stat st; __u64 dv1; __u64 dv2; int rc; + rc = fstat(fd, &st); + if (rc < 0) { + error_loc = "cannot stat source file"; + return -errno; + } + rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH); if (rc < 0) { error_loc = "cannot get data version"; @@ -1074,16 +1024,48 @@ static int migrate_nonblock(int fd, int fdv) } /* Make sure we keep original atime/mtime values */ - rc = migrate_copy_timestamps(fd, fdv); + rc = migrate_set_timestamps(fdv, &st); if (rc < 0) { - error_loc = "timestamp copy failed"; - return rc; + error_loc = "set target file timestamp failed"; + return -errno; } - return 0; } -static int lfs_component_set(char *fname, int comp_id, +static +int lfs_layout_compid_by_pool(char *fname, const char *pool, int *comp_id) +{ + struct pool_to_id_cbdata data = { .pool = pool }; + struct llapi_layout *layout = NULL; + int rc; + + layout = llapi_layout_get_by_path(fname, 0); + if (!layout) { + fprintf(stderr, + "error %s: file '%s' couldn't get layout: rc=%d\n", + progname, fname, errno); + rc = -errno; + goto free_layout; + } + rc = llapi_layout_sanity(layout, false, true); + if (rc < 0) { + llapi_layout_sanity_perror(errno); + goto free_layout; + } + rc = llapi_layout_comp_iterate(layout, find_comp_id_by_pool, &data); + if (rc < 0) + goto free_layout; + + *comp_id = data.id; + rc = 0; + +free_layout: + if (layout) + llapi_layout_free(layout); + return rc; +} + +static int lfs_component_set(char *fname, int comp_id, const char *pool, __u32 flags, __u32 neg_flags) { __u32 ids[2]; @@ -1091,6 +1073,18 @@ static int lfs_component_set(char *fname, int comp_id, size_t count = 0; int rc; + if (!comp_id) { + if (pool == NULL) { + fprintf(stderr, + "error %s: neither component id nor pool is specified\n", + progname); + return -EINVAL; + } + rc = lfs_layout_compid_by_pool(fname, pool, &comp_id); + if (rc) + return rc; + } + if (flags) { ids[count] = comp_id; flags_array[count] = flags; @@ -1099,9 +1093,9 @@ static int lfs_component_set(char *fname, int comp_id, if (neg_flags) { if (neg_flags & LCME_FL_STALE) { - fprintf(stderr, "%s: cannot clear 'stale' flags from " - "component. Please use lfs-mirror-resync(1) " - "instead\n", progname); + fprintf(stderr, + "%s: cannot clear 'stale' flags from component. Please use lfs-mirror-resync(1) instead\n", + progname); return -EINVAL; } @@ -1132,14 +1126,29 @@ static int lfs_component_del(char *fname, __u32 comp_id, { int rc = 0; - if (flags && neg_flags) + if (flags && neg_flags) { + fprintf(stderr, + "%s: cannot specify both positive and negative flags\n", + progname); return -EINVAL; + } if (!flags && neg_flags) flags = neg_flags | LCME_FL_NEG; - if ((flags && comp_id) || (!flags && !comp_id)) + if (flags && comp_id) { + fprintf(stderr, + "%s: cannot specify component ID and flags at the same time\n", + progname); + return -EINVAL; + } + + if (!flags && !comp_id) { + fprintf(stderr, + "%s: neither flags nor component ID is specified\n", + progname); return -EINVAL; + } if (flags) { if (flags & ~LCME_KNOWN_FLAGS) { @@ -1166,7 +1175,7 @@ static int lfs_component_add(char *fname, struct llapi_layout *layout) { int rc; - if (layout == NULL) + if (!layout) return -EINVAL; rc = llapi_layout_file_comp_add(fname, layout); @@ -1182,7 +1191,7 @@ static int lfs_component_create(char *fname, int open_flags, mode_t open_mode, struct stat st; int fd; - if (layout == NULL) + if (!layout) return -EINVAL; fd = lstat(fname, &st); @@ -1232,23 +1241,25 @@ static int lfs_migrate(char *name, __u64 migration_flags, goto out; } - /* if file has DoM layout already then migration is possible to + /* + * if file has DoM layout already then migration is possible to * the new layout with the same DoM component via swap layout, * if new layout used bigger DOM size, then mirroring is used */ if (dom_new > dom_cur) { - rc = lfs_migrate_to_dom(fd, fdv, name, migration_flags, param, - layout); + rc = lfs_migrate_to_dom(fd, fdv, name, migration_flags); if (rc) error_loc = "cannot migrate to DOM layout"; goto out_closed; } - if (!(migration_flags & MIGRATION_NONBLOCK)) { - /* Blocking mode (forced if servers do not support file lease). + if (!(migration_flags & LLAPI_MIGRATION_NONBLOCK)) { + /* + * Blocking mode (forced if servers do not support file lease). * It is also the default mode, since we cannot distinguish * between a broken lease and a server that does not support - * atomic swap/close (LU-6785) */ + * atomic swap/close (LU-6785) + */ rc = migrate_block(fd, fdv); goto out; } @@ -1265,9 +1276,11 @@ static int lfs_migrate(char *name, __u64 migration_flags, goto out; } - /* Atomically put lease, swap layouts and close. + /* + * Atomically put lease, swap layouts and close. * for a migration we need to check data version on file did - * not change. */ + * not change. + */ rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE); if (rc < 0) { error_loc = "cannot swap layout"; @@ -1284,7 +1297,7 @@ out_closed: if (rc < 0) fprintf(stderr, "error: %s: %s: %s: %s\n", progname, name, error_loc, strerror(-rc)); - else if (migration_flags & MIGRATION_VERBOSE) + else if (migration_flags & LLAPI_MIGRATION_VERBOSE) printf("%s\n", name); return rc; @@ -1293,13 +1306,24 @@ out_closed: static int comp_str2flags(char *string, __u32 *flags, __u32 *neg_flags) { char *name; - - if (string == NULL) - return -EINVAL; + char *dup_string = NULL; + int rc = 0; *flags = 0; *neg_flags = 0; - for (name = strtok(string, ","); name; name = strtok(NULL, ",")) { + + if (!string || !string[0]) + return -EINVAL; + + dup_string = strdup(string); + if (!dup_string) { + llapi_printf(LLAPI_MSG_ERROR, + "%s: insufficient memory\n", + progname); + return -ENOMEM; + } + + for (name = strtok(dup_string, ","); name; name = strtok(NULL, ",")) { bool found = false; int i; @@ -1320,23 +1344,87 @@ static int comp_str2flags(char *string, __u32 *flags, __u32 *neg_flags) llapi_printf(LLAPI_MSG_ERROR, "%s: component flag '%s' not supported\n", progname, name); - return -EINVAL; + rc = -EINVAL; + goto out_free; } } if (!*flags && !*neg_flags) - return -EINVAL; + rc = -EINVAL; /* don't allow to set and exclude the same flag */ if (*flags & *neg_flags) + rc = -EINVAL; + +out_free: + free(dup_string); + return rc; +} + +static int mdthash_input(char *string, __u32 *inflags, + __u32 *exflags, __u32 *type) +{ + char *name; + struct mhf_list { + char *name; + __u32 flag; + } mhflist[] = { + {"migrating", LMV_HASH_FLAG_MIGRATION}, + {"bad_type", LMV_HASH_FLAG_BAD_TYPE}, + {"badtype", LMV_HASH_FLAG_BAD_TYPE}, + {"lost_lmv", LMV_HASH_FLAG_LOST_LMV}, + {"lostlmv", LMV_HASH_FLAG_LOST_LMV}, + }; + + if (string == NULL) + return -EINVAL; + + *inflags = 0; + *exflags = 0; + *type = 0; + for (name = strtok(string, ","); name; name = strtok(NULL, ",")) { + bool found = false; + int i; + + for (i = 0; i < ARRAY_SIZE(mhflist); i++) { + if (strcmp(name, mhflist[i].name) == 0 || + name[0] == mhflist[i].name[0]) { + *inflags |= mhflist[i].flag; + found = true; + } else if (name[0] == '^' && + (strcmp(name + 1, mhflist[i].name) == 0 || + name[1] == mhflist[i].name[0])) { + *exflags |= mhflist[i].flag; + found = true; + } + } + if (!found) { + i = check_hashtype(name); + if (i > 0) { + *type |= 1 << i; + continue; + } + llapi_printf(LLAPI_MSG_ERROR, + "%s: invalid mdt_hash value '%s'\n", + progname, name); + return -EINVAL; + } + } + + /* don't allow to include and exclude the same flag */ + if (*inflags & *exflags) { + llapi_printf(LLAPI_MSG_ERROR, + "%s: include and exclude same flag '%s'\n", + progname, string); return -EINVAL; + } return 0; } static int mirror_str2state(char *string, __u16 *state, __u16 *neg_state) { - if (string == NULL) + if (!string) return -EINVAL; *state = 0; @@ -1375,6 +1463,7 @@ struct mirror_args { struct llapi_layout *m_layout; const char *m_file; struct mirror_args *m_next; + bool m_inherit; }; /** @@ -1404,16 +1493,17 @@ enum mirror_flags { * Return: 0 on success or a negative error code on failure. */ static int mirror_create_sanity_check(const char *fname, - struct mirror_args *list) + struct mirror_args *list, + bool check_fname) { int rc = 0; bool has_m_file = false; bool has_m_layout = false; - if (list == NULL) + if (!list) return -EINVAL; - if (fname) { + if (fname && check_fname) { struct llapi_layout *layout; layout = llapi_layout_get_by_path(fname, 0); @@ -1434,14 +1524,14 @@ static int mirror_create_sanity_check(const char *fname, } } - while (list != NULL) { - if (list->m_file != NULL) { + while (list) { + if (list->m_file) { has_m_file = true; llapi_layout_free(list->m_layout); list->m_layout = llapi_layout_get_by_path(list->m_file, 0); - if (list->m_layout == NULL) { + if (!list->m_layout) { fprintf(stderr, "error: %s: file '%s' has no layout\n", progname, list->m_file); @@ -1449,7 +1539,7 @@ static int mirror_create_sanity_check(const char *fname, } } else { has_m_layout = true; - if (list->m_layout == NULL) { + if (!list->m_layout) { fprintf(stderr, "error: %s: no mirror layout\n", progname); return -EINVAL; @@ -1512,12 +1602,12 @@ static int mirror_create(char *fname, struct mirror_args *mirror_list) int i = 0; int rc = 0; - rc = mirror_create_sanity_check(NULL, mirror_list); + rc = mirror_create_sanity_check(fname, mirror_list, false); if (rc) return rc; cur_mirror = mirror_list; - while (cur_mirror != NULL) { + while (cur_mirror) { rc = llapi_layout_comp_iterate(cur_mirror->m_layout, mirror_set_flags, &cur_mirror->m_flags); @@ -1532,8 +1622,8 @@ static int mirror_create(char *fname, struct mirror_args *mirror_list) rc = llapi_layout_merge(&layout, cur_mirror->m_layout); if (rc) { rc = -errno; - fprintf(stderr, "error: %s: " - "merge layout failed: %s\n", + fprintf(stderr, + "error: %s: merge layout failed: %s\n", progname, strerror(errno)); goto error; } @@ -1542,7 +1632,7 @@ static int mirror_create(char *fname, struct mirror_args *mirror_list) cur_mirror = cur_mirror->m_next; } - if (layout == NULL) { + if (!layout) { fprintf(stderr, "error: %s: layout is NULL\n", progname); return -EINVAL; } @@ -1596,8 +1686,10 @@ static ssize_t mirror_file_compare(int fd, int fdv) if (bytes_read != read(fdv, buf + buflen, buflen)) break; - /* XXX: should compute the checksum on each buffer and then - * compare checksum to avoid cache collision */ + /* + * XXX: should compute the checksum on each buffer and then + * compare checksum to avoid cache collision + */ if (memcmp(buf, buf + buflen, bytes_read)) break; @@ -1680,13 +1772,11 @@ static int mirror_extend_file(const char *fname, const char *victim_file, if (rc < 0) { error_loc = "cannot get data version"; goto out; - } - /* Make sure we keep original atime/mtime values */ - rc = migrate_copy_timestamps(fd, fdv); + rc = migrate_set_timestamps(fd, &stbuf); if (rc < 0) { - error_loc = "cannot copy timestamp"; + error_loc = "cannot set source file timestamp"; goto out; } @@ -1726,14 +1816,42 @@ out: return rc; } -static int mirror_extend_layout(char *name, struct llapi_layout *layout) +static int mirror_extend_layout(char *name, struct llapi_layout *m_layout, + bool inherit, uint32_t flags) { + struct llapi_layout *f_layout = NULL; struct ll_ioc_lease *data = NULL; + struct stat st; int fd = -1; int fdv = -1; - int rc; + int rc = 0; + + if (inherit) { + f_layout = llapi_layout_get_by_path(name, 0); + if (!f_layout) { + rc = -EINVAL; + fprintf(stderr, "%s: cannot get layout\n", progname); + goto out; + } + rc = llapi_layout_get_last_init_comp(f_layout); + if (rc) { + fprintf(stderr, "%s: cannot get the last init comp\n", + progname); + goto out; + } + rc = llapi_layout_mirror_inherit(f_layout, m_layout); + if (rc) { + fprintf(stderr, + "%s: cannot inherit from the last init comp\n", + progname); + goto out; + } + } - rc = migrate_open_files(name, 0, NULL, layout, &fd, &fdv); + llapi_layout_comp_flags_set(m_layout, flags); + rc = migrate_open_files(name, + LLAPI_MIGRATION_NONDIRECT | LLAPI_MIGRATION_MIRROR, + NULL, m_layout, &fd, &fdv); if (rc < 0) goto out; @@ -1743,12 +1861,24 @@ static int mirror_extend_layout(char *name, struct llapi_layout *layout) goto out; } + rc = fstat(fd, &st); + if (rc < 0) { + error_loc = "cannot stat source file"; + goto out; + } + rc = migrate_nonblock(fd, fdv); if (rc < 0) { llapi_lease_release(fd); goto out; } + rc = migrate_set_timestamps(fd, &st); + if (rc < 0) { + error_loc = "cannot set source file timestamp"; + goto out; + } + /* Atomically put lease, merge layouts and close. */ data = calloc(1, offsetof(typeof(*data), lil_ids[1])); if (!data) { @@ -1786,14 +1916,10 @@ out: static int mirror_extend(char *fname, struct mirror_args *mirror_list, enum mirror_flags mirror_flags) { - int rc; - - rc = mirror_create_sanity_check(fname, mirror_list); - if (rc) - return rc; + int rc = 0; while (mirror_list) { - if (mirror_list->m_file != NULL) { + if (mirror_list->m_file) { rc = mirror_extend_file(fname, mirror_list->m_file, mirror_flags); } else { @@ -1801,7 +1927,9 @@ static int mirror_extend(char *fname, struct mirror_args *mirror_list, while (mirror_count > 0) { rc = mirror_extend_layout(fname, - mirror_list->m_layout); + mirror_list->m_layout, + mirror_list->m_inherit, + mirror_list->m_flags); if (rc) break; @@ -1847,11 +1975,7 @@ static int find_comp_id(struct llapi_layout *layout, void *cbdata) return LLAPI_LAYOUT_ITER_CONT; } -struct pool_to_id_cbdata { - const char *pool; - __u32 id; -}; -static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata) +static int find_mirror_id_by_pool(struct llapi_layout *layout, void *cbdata) { char buf[LOV_MAXPOOLNAME + 1]; struct pool_to_id_cbdata *d = (void *)cbdata; @@ -1872,25 +1996,46 @@ static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata) return LLAPI_LAYOUT_ITER_STOP; } -struct collect_ids_data { - __u16 *cid_ids; - int cid_count; - __u16 cid_exclude; -}; - -static int collect_mirror_id(struct llapi_layout *layout, void *cbdata) +static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata) { - struct collect_ids_data *cid = cbdata; + char buf[LOV_MAXPOOLNAME + 1]; + struct pool_to_id_cbdata *d = (void *)cbdata; uint32_t id; int rc; - rc = llapi_layout_mirror_id_get(layout, &id); + rc = llapi_layout_pool_name_get(layout, buf, sizeof(buf)); if (rc < 0) return rc; + if (strcmp(d->pool, buf)) + return LLAPI_LAYOUT_ITER_CONT; + + rc = llapi_layout_comp_id_get(layout, &id); + if (rc < 0) + return rc; + d->id = id; + + return LLAPI_LAYOUT_ITER_STOP; +} + +struct collect_ids_data { + __u16 *cid_ids; + int cid_count; + __u16 cid_exclude; +}; + +static int collect_mirror_id(struct llapi_layout *layout, void *cbdata) +{ + struct collect_ids_data *cid = cbdata; + uint32_t id; + int rc; + + rc = llapi_layout_mirror_id_get(layout, &id); + if (rc < 0) + return rc; + + if ((__u16)id != cid->cid_exclude) { + int i; - if ((__u16)id != cid->cid_exclude) { - int i; - for (i = 0; i < cid->cid_count; i++) { /* already collected the mirror id */ if (id == cid->cid_ids[i]) @@ -1948,10 +2093,20 @@ static int mirror_split(const char *fname, __u32 id, const char *pool, char *ptr; struct ll_ioc_lease *data; uint16_t mirror_count; + __u32 mirror_id; int mdt_index; int fd, fdv; + bool purge = true; /* delete mirror by setting fdv=fd */ + bool is_encrypted; int rc; + if (victim_file && (strcmp(fname, victim_file) == 0)) { + fprintf(stderr, + "error %s: the source file '%s' and -f file are the same\n", + progname, fname); + return -EINVAL; + } + /* check fname contains mirror with mirror_id/comp_id */ layout = llapi_layout_get_by_path(fname, 0); if (!layout) { @@ -1984,27 +2139,48 @@ static int mirror_split(const char *fname, __u32 id, const char *pool, if (mflags & MF_COMP_POOL) { struct pool_to_id_cbdata data = { .pool = pool }; - rc = llapi_layout_comp_iterate(layout, find_comp_id_by_pool, + rc = llapi_layout_comp_iterate(layout, find_mirror_id_by_pool, &data); - id = data.id; + mirror_id = data.id; } else if (mflags & MF_COMP_ID) { rc = llapi_layout_comp_iterate(layout, find_comp_id, &id); - id = mirror_id_of(id); + mirror_id = mirror_id_of(id); } else { rc = llapi_layout_comp_iterate(layout, find_mirror_id, &id); + mirror_id = id; } if (rc < 0) { fprintf(stderr, "error %s: failed to iterate layout of '%s'\n", progname, fname); goto free_layout; } else if (rc == LLAPI_LAYOUT_ITER_CONT) { - fprintf(stderr, - "error %s: file '%s' does not contain mirror with id %u\n", - progname, fname, id); - goto free_layout; + if (mflags & MF_COMP_POOL) { + fprintf(stderr, + "error %s: file '%s' does not contain mirror with pool '%s'\n", + progname, fname, pool); + goto free_layout; + } else if (mflags & MF_COMP_ID) { + fprintf(stderr, + "error %s: file '%s' does not contain mirror with comp-id %u\n", + progname, fname, id); + goto free_layout; + } else { + fprintf(stderr, + "error %s: file '%s' does not contain mirror with id %u\n", + progname, fname, id); + goto free_layout; + } } - fd = open(fname, O_RDWR); + if (!victim_file && mflags & MF_DESTROY) + /* Allow mirror split even without the key on encrypted files, + * and in this case of a 'split -d', open file with O_DIRECT + * (no IOs will be done). + */ + fd = open(fname, O_RDWR | O_DIRECT | O_FILE_ENC); + else + fd = open(fname, O_RDWR); + if (fd < 0) { fprintf(stderr, "error %s: open file '%s' failed: %s\n", @@ -2021,8 +2197,8 @@ static int mirror_split(const char *fname, __u32 id, const char *pool, } strncpy(parent, fname, sizeof(parent)); ptr = strrchr(parent, '/'); - if (ptr == NULL) { - if (getcwd(parent, sizeof(parent)) == NULL) { + if (!ptr) { + if (!getcwd(parent, sizeof(parent))) { fprintf(stderr, "error %s: getcwd failed: %s\n", progname, strerror(errno)); rc = -errno; @@ -2041,10 +2217,23 @@ static int mirror_split(const char *fname, __u32 id, const char *pool, goto close_fd; } - if (victim_file == NULL) { + rc = llapi_file_is_encrypted(fd); + if (rc < 0) { + fprintf(stderr, "%s: cannot get flags of '%s': %d\n", + progname, fname, rc); + goto close_fd; + } + is_encrypted = rc; + +again: + if (!victim_file) { /* use a temp file to store the splitted layout */ if (mflags & MF_DESTROY) { - if (last_non_stale_mirror(id, layout)) { + char file_path[PATH_MAX]; + unsigned int rnumber; + int open_flags; + + if (last_non_stale_mirror(mirror_id, layout)) { rc = -EUCLEAN; fprintf(stderr, "%s: cannot destroy the last non-stale mirror of file '%s'\n", @@ -2052,15 +2241,62 @@ static int mirror_split(const char *fname, __u32 id, const char *pool, goto close_fd; } - fdv = llapi_create_volatile_idx(parent, mdt_index, - O_LOV_DELAY_CREATE); + if (purge) { + /* don't use volatile file for mirror destroy */ + fdv = fd; + } else { + /** + * try the old way to delete mirror using + * volatile file. + */ + do { + rnumber = random(); + rc = snprintf(file_path, + sizeof(file_path), + "%s/" LUSTRE_VOLATILE_HDR ":%.4X:%.4X:fd=%.2d", + parent, mdt_index, + rnumber, fd); + if (rc < 0 || + rc >= sizeof(file_path)) { + fdv = -ENAMETOOLONG; + break; + } + + open_flags = O_RDWR | + (O_LOV_DELAY_CREATE & ~O_ACCMODE) | + O_CREAT | O_EXCL | O_NOFOLLOW | + /* O_DIRECT for mirror split -d */ + O_DIRECT | + /* Allow split without the key */ + O_FILE_ENC; + fdv = open(file_path, open_flags, + S_IRUSR | S_IWUSR); + if (fdv < 0) + rc = -errno; + } while (fdv < 0 && rc == -EEXIST); + } } else { + if (is_encrypted) { + rc = -1; + fprintf(stderr, + "error %s: not permitted on encrypted file '%s': %d\n", + progname, fname, rc); + goto close_fd; + } + snprintf(victim, sizeof(victim), "%s.mirror~%u", - fname, id); + fname, mirror_id); fdv = open(victim, flags, S_IRUSR | S_IWUSR); } } else { /* user specified victim file */ + if (is_encrypted) { + rc = -1; + fprintf(stderr, + "error %s: not permitted on encrypted file '%s': %d\n", + progname, fname, rc); + goto close_fd; + } fdv = open(victim_file, flags, S_IRUSR | S_IWUSR); } @@ -2091,9 +2327,15 @@ static int mirror_split(const char *fname, __u32 id, const char *pool, data->lil_flags = LL_LEASE_LAYOUT_SPLIT; data->lil_count = 2; data->lil_ids[0] = fdv; - data->lil_ids[1] = id; + data->lil_ids[1] = mirror_id; rc = llapi_lease_set(fd, data); if (rc <= 0) { + if ((rc == -EINVAL || rc == -EBUSY) && purge) { + /* could be old MDS which prohibit fd==fdv */ + purge = false; + goto again; + + } if (rc == 0) /* lost lease lock */ rc = -EBUSY; fprintf(stderr, @@ -2105,7 +2347,8 @@ static int mirror_split(const char *fname, __u32 id, const char *pool, free(data); close_victim: - close(fdv); + if (!purge) + close(fdv); close_fd: close(fd); free_layout: @@ -2118,9 +2361,7 @@ int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc, __u16 *mirror_ids, int ids_nr); static int lfs_migrate_to_dom(int fd, int fdv, char *name, - __u64 migration_flags, - struct llapi_stripe_param *param, - struct llapi_layout *layout) + __u64 migration_flags) { struct ll_ioc_lease *data = NULL; int rc; @@ -2131,11 +2372,15 @@ static int lfs_migrate_to_dom(int fd, int fdv, char *name, goto out_close; } + rc = migrate_nonblock(fd, fdv); + if (rc < 0) + goto out_release; + /* Atomically put lease, merge layouts, resync and close. */ - data = calloc(1, offsetof(typeof(*data), lil_ids[1024])); + data = calloc(1, offsetof(typeof(*data), lil_ids[1])); if (!data) { error_loc = "memory allocation"; - goto out_close; + goto out_release; } data->lil_mode = LL_LEASE_UNLCK; data->lil_flags = LL_LEASE_LAYOUT_MERGE; @@ -2165,6 +2410,8 @@ static int lfs_migrate_to_dom(int fd, int fdv, char *name, error_loc = "cannot delete old layout"; goto out; +out_release: + llapi_lease_release(fd); out_close: close(fd); close(fdv); @@ -2172,7 +2419,7 @@ out: if (rc < 0) fprintf(stderr, "error: %s: %s: %s: %s\n", progname, name, error_loc, strerror(-rc)); - else if (migration_flags & MIGRATION_VERBOSE) + else if (migration_flags & LLAPI_MIGRATION_VERBOSE) printf("%s\n", name); if (data) free(data); @@ -2205,7 +2452,7 @@ static int parse_targets(__u32 *tgts, int size, int offset, char *arg, bool overstriped = false; bool end_of_loop; - if (arg == NULL) + if (!arg) return -EINVAL; end_of_loop = false; @@ -2222,16 +2469,19 @@ static int parse_targets(__u32 *tgts, int size, int offset, char *arg, end_of_loop = *ptr == '\0'; *ptr = '\0'; + errno = 0; start_index = strtol(arg, &endptr, 0); if (endptr == arg) /* no data at all */ break; - if (*endptr != '-' && *endptr != '\0') /* has invalid data */ + if (errno != 0 || start_index < -1 || + (*endptr != '-' && *endptr != '\0')) break; end_index = start_index; if (*endptr == '-') { + errno = 0; end_index = strtol(endptr + 1, &endptr, 0); - if (*endptr != '\0') + if (errno != 0 || *endptr != '\0' || end_index < -1) break; if (end_index < start_index) break; @@ -2265,7 +2515,7 @@ static int parse_targets(__u32 *tgts, int size, int offset, char *arg, offset = nr; rc = 0; } - if (!end_of_loop && ptr != NULL) + if (!end_of_loop && ptr) *ptr = ','; if (!overstriped && pattern) @@ -2343,6 +2593,33 @@ static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa) lsa->lsa_comp_end != 0); } +static int lsa_args_stripe_count_check(struct lfs_setstripe_args *lsa) +{ + if (lsa->lsa_nr_tgts) { + if (lsa->lsa_nr_tgts < 0 || + lsa->lsa_nr_tgts >= LOV_MAX_STRIPE_COUNT) { + fprintf(stderr, "Invalid nr_tgts(%d)\n", + lsa->lsa_nr_tgts); + errno = EINVAL; + return -1; + } + + if (lsa->lsa_stripe_count > 0 && + lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT && + lsa->lsa_stripe_count != LLAPI_LAYOUT_WIDE && + lsa->lsa_nr_tgts != lsa->lsa_stripe_count) { + fprintf(stderr, "stripe_count(%lld) != nr_tgts(%d)\n", + lsa->lsa_stripe_count, + lsa->lsa_nr_tgts); + errno = EINVAL; + return -1; + } + } + + return 0; + +} + /** * comp_args_to_layout() - Create or extend a composite layout. * @composite: Pointer to the composite layout. @@ -2351,6 +2628,8 @@ static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa) * This function creates or extends a composite layout by adding a new * component with stripe options from @lsa. * + * When modified, adjust llapi_stripe_param_verify() if needed as well. + * * Return: 0 on success or an error code on failure. */ static int comp_args_to_layout(struct llapi_layout **composite, @@ -2363,9 +2642,9 @@ static int comp_args_to_layout(struct llapi_layout **composite, int i = 0, rc; new_comp: - if (layout == NULL) { + if (!layout) { layout = llapi_layout_alloc(); - if (layout == NULL) { + if (!layout) { fprintf(stderr, "Alloc llapi_layout failed. %s\n", strerror(errno)); errno = ENOMEM; @@ -2376,8 +2655,10 @@ new_comp: } else { uint64_t start; - /* Get current component extent, current component - * must be the tail component. */ + /* + * Get current component extent, current component + * must be the tail component. + */ rc = llapi_layout_comp_extent_get(layout, &start, &prev_end); if (rc) { fprintf(stderr, "Get comp extent failed. %s\n", @@ -2385,13 +2666,12 @@ new_comp: return rc; } - if (lsa->lsa_first_comp) + if (lsa->lsa_first_comp) { prev_end = 0; - - if (lsa->lsa_first_comp) rc = llapi_layout_add_first_comp(layout); - else + } else { rc = llapi_layout_comp_add(layout); + } if (rc) { fprintf(stderr, "Add component failed. %s\n", strerror(errno)); @@ -2409,8 +2689,10 @@ new_comp: if (set_extent) { uint64_t comp_end = lsa->lsa_comp_end; - /* The extendable component is 0-length, so it can be removed - * if there is insufficient space to extend it. */ + /* + * The extendable component is 0-length, so it can be removed + * if there is insufficient space to extend it. + */ if (lsa->lsa_extension_comp) comp_end = prev_end; @@ -2427,39 +2709,50 @@ new_comp: /* Data-on-MDT component setting */ if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) { - /* In case of Data-on-MDT patterns the only extra option - * applicable is stripe size option. */ + /* Yaml support */ + if (lsa->lsa_stripe_count == 0) + lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT; + if (lsa->lsa_stripe_size == lsa->lsa_comp_end) + lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT; + if (lsa->lsa_stripe_off == -1 || + lsa->lsa_stripe_off == 0) + lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT; + /* + * In case of Data-on-MDT patterns the only extra option + * applicable is stripe size option. + */ if (lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) { - fprintf(stderr, "Option 'stripe-count' can't be " - "specified with Data-on-MDT component: %lld\n", + fprintf(stderr, + "Option 'stripe-count' can't be specified with Data-on-MDT component: %lld\n", lsa->lsa_stripe_count); errno = EINVAL; return -1; } - if (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT) { - fprintf(stderr, "Option 'stripe-size' can't be " - "specified with Data-on-MDT component: %llu\n", + if (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT && + lsa->lsa_stripe_size != lsa->lsa_comp_end - prev_end) { + fprintf(stderr, + "Option 'stripe-size' can't be specified with Data-on-MDT component: %llu\n", lsa->lsa_stripe_size); errno = EINVAL; return -1; } if (lsa->lsa_nr_tgts != 0) { - fprintf(stderr, "Option 'ost-list' can't be specified " - "with Data-on-MDT component: '%i'\n", + fprintf(stderr, + "Option 'ost-list' can't be specified with Data-on-MDT component: '%i'\n", lsa->lsa_nr_tgts); errno = EINVAL; return -1; } if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) { - fprintf(stderr, "Option 'stripe-offset' can't be " - "specified with Data-on-MDT component: %lld\n", + fprintf(stderr, + "Option 'stripe-offset' can't be specified with Data-on-MDT component: %lld\n", lsa->lsa_stripe_off); errno = EINVAL; return -1; } if (lsa->lsa_pool_name != 0) { - fprintf(stderr, "Option 'pool' can't be specified " - "with Data-on-MDT component: '%s'\n", + fprintf(stderr, + "Option 'pool' can't be specified with Data-on-MDT component: '%s'\n", lsa->lsa_pool_name); errno = EINVAL; return -1; @@ -2505,7 +2798,7 @@ new_comp: return rc; } - if (lsa->lsa_pool_name != NULL) { + if (lsa->lsa_pool_name) { rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name); if (rc) { fprintf(stderr, "Set pool name: %s failed. %s\n", @@ -2521,22 +2814,28 @@ new_comp: } } + rc = lsa_args_stripe_count_check(lsa); + if (rc) + return rc; + if (lsa->lsa_nr_tgts > 0) { - if (lsa->lsa_stripe_count > 0 && - lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT && - lsa->lsa_stripe_count != LLAPI_LAYOUT_WIDE && - lsa->lsa_nr_tgts != lsa->lsa_stripe_count) { - fprintf(stderr, "stripe_count(%lld) != nr_tgts(%d)\n", - lsa->lsa_stripe_count, - lsa->lsa_nr_tgts); - errno = EINVAL; - return -1; - } + bool found = false; + for (i = 0; i < lsa->lsa_nr_tgts; i++) { rc = llapi_layout_ost_index_set(layout, i, lsa->lsa_tgts[i]); if (rc) break; + + /* Make sure stripe offset is in OST list. */ + if (lsa->lsa_tgts[i] == lsa->lsa_stripe_off) + found = true; + } + if (!found) { + fprintf(stderr, "Invalid stripe offset '%lld', not in the target list", + lsa->lsa_stripe_off); + errno = EINVAL; + return -1; } } else if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT && lsa->lsa_stripe_off != -1) { @@ -2582,26 +2881,83 @@ static int build_component(struct llapi_layout **layout, return rc; } +static int build_prev_component(struct llapi_layout **layout, + struct lfs_setstripe_args *prev, + struct lfs_setstripe_args *lsa, + bool set_extent) +{ + int extension = lsa->lsa_comp_flags & LCME_FL_EXTENSION; + int rc; + + if (prev->lsa_stripe_size) { + if (extension) { + prev->lsa_comp_end = lsa->lsa_comp_end; + prev->lsa_extension_size = lsa->lsa_extension_size; + prev->lsa_extension_comp = true; + } + + rc = build_component(layout, prev, true); + if (rc) + return rc; + } + + /* + * Copy lsa to previous lsa; + * if this is an extension component, make the previous invalid; + */ + if (extension) + prev->lsa_stripe_size = 0; + else + *prev = *lsa; + + return 0; +} + +#ifndef LCME_TEMPLATE_FLAGS +#define LCME_TEMPLATE_FLAGS (LCME_FL_PREF_RW | LCME_FL_NOSYNC | \ + LCME_FL_EXTENSION) +#endif + static int build_layout_from_yaml_node(struct cYAML *node, struct llapi_layout **layout, struct lfs_setstripe_args *lsa, - __u32 *osts) + struct lfs_setstripe_args *prevp) { + struct lfs_setstripe_args prev = { 0 }; + __u32 *osts = lsa->lsa_tgts; char *string; int rc = 0; + if (!prevp) + prevp = &prev; + while (node) { + string = node->cy_string; + if (node->cy_type == CYAML_TYPE_OBJECT) { /* go deep to sub blocks */ + if (string && !strncmp(string, "component", 9) && + strncmp(string, "component0", 10) && + strncmp(string, "components", 10)) { + rc = build_prev_component(layout, prevp, lsa, + true); + if (rc) + return rc; + + /* initialize lsa. */ + setstripe_args_init(lsa); + lsa->lsa_first_comp = false; + lsa->lsa_tgts = osts; + } + rc = build_layout_from_yaml_node(node->cy_child, layout, - lsa, osts); + lsa, prevp); if (rc) return rc; } else { - if (node->cy_string == NULL) + if (!node->cy_string) return -EINVAL; - string = node->cy_string; /* skip leading lmm_ if present, to simplify parsing */ if (strncmp(string, "lmm_", 4) == 0) string += 4; @@ -2626,7 +2982,8 @@ static int build_layout_from_yaml_node(struct cYAML *node, &lsa->lsa_comp_neg_flags); if (rc) return rc; - /* Only template flags have meaning in + /* + * Only template flags have meaning in * the layout for a new file */ lsa->lsa_comp_flags &= LCME_TEMPLATE_FLAGS; @@ -2635,18 +2992,8 @@ static int build_layout_from_yaml_node(struct cYAML *node, if (!strcmp(string, "lcm_mirror_count")) { lsa->lsa_mirror_count = node->cy_valueint; } else if (!strcmp(string, "lcme_extent.e_start")) { - if (node->cy_valueint != 0 || *layout != NULL) { - rc = build_component(layout, lsa, true); - if (rc) - return rc; - } - if (node->cy_valueint == 0) lsa->lsa_first_comp = true; - - /* initialize lsa */ - setstripe_args_init(lsa); - lsa->lsa_tgts = osts; } else if (!strcmp(string, "lcme_extent.e_end")) { if (node->cy_valueint == -1) lsa->lsa_comp_end = LUSTRE_EOF; @@ -2656,6 +3003,9 @@ static int build_layout_from_yaml_node(struct cYAML *node, lsa->lsa_stripe_count = node->cy_valueint; } else if (!strcmp(string, "stripe_size")) { lsa->lsa_stripe_size = node->cy_valueint; + } else if (!strcmp(string, "extension_size")) { + lsa->lsa_extension_size = node->cy_valueint; + lsa->lsa_extension_comp = true; } else if (!strcmp(string, "stripe_offset")) { lsa->lsa_stripe_off = node->cy_valueint; } else if (!strcmp(string, "l_ost_idx")) { @@ -2667,6 +3017,15 @@ static int build_layout_from_yaml_node(struct cYAML *node, node = node->cy_next; } + if (prevp == &prev) { + rc = build_prev_component(layout, prevp, lsa, true); + if (rc) + return rc; + + if (!(lsa->lsa_comp_flags & LCME_FL_EXTENSION)) + rc = build_component(layout, lsa, *layout != NULL); + } + return rc; } @@ -2694,13 +3053,11 @@ static int lfs_comp_create_from_yaml(char *template, setstripe_args_init(lsa); lsa->lsa_tgts = osts; - rc = build_layout_from_yaml_node(tree, layout, lsa, osts); + rc = build_layout_from_yaml_node(tree, layout, lsa, NULL); if (rc) { fprintf(stderr, "%s: cannot build layout from YAML file %s.\n", progname, template); goto err; - } else { - rc = build_component(layout, lsa, *layout != NULL); } /* clean clean lsa */ setstripe_args_init(lsa); @@ -2734,18 +3091,22 @@ static int layout_extend_comp(struct llapi_layout *layout, rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT); if (rc < 0) { - fprintf(stderr, "%s setstripe: cannot move component cursor: " - "%s\n", progname, strerror(errno)); + fprintf(stderr, + "%s setstripe: cannot move component cursor: %s\n", + progname, strerror(errno)); return rc; } - /* Even if the @size will not be used below, this will fail if + /* + * Even if the @size will not be used below, this will fail if * this is not a SEL component - a good confirmation we are - * working on right components. */ + * working on right components. + */ rc = llapi_layout_extension_size_get(layout, &size); if (rc < 0) { - fprintf(stderr, "%s setstripe: cannot get component ext size: " - "%s\n", progname, strerror(errno)); + fprintf(stderr, + "%s setstripe: cannot get component ext size: %s\n", + progname, strerror(errno)); return rc; } @@ -2766,8 +3127,9 @@ static int layout_extend_comp(struct llapi_layout *layout, rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_PREV); if (rc < 0) { - fprintf(stderr, "%s setstripe: cannot move component cursor: " - "%s\n", progname, strerror(errno)); + fprintf(stderr, + "%s setstripe: cannot move component cursor: %s\n", + progname, strerror(errno)); return rc; } @@ -2799,38 +3161,44 @@ static int layout_adjust_first_extent(char *fname, struct llapi_layout *layout, uint64_t end; int rc, ret = 0; - if (layout == NULL) + if (!layout || !(comp_add || llapi_layout_is_composite(layout))) return 0; errno = 0; while (comp_add) { head = llapi_layout_get_by_path(fname, 0); - if (head == NULL) { + if (!head) { fprintf(stderr, - "%s setstripe: cannot read layout from '%s': " - "%s\n", progname, fname, strerror(errno)); + "%s setstripe: cannot read layout from '%s': %s\n", + progname, fname, strerror(errno)); return -EINVAL; } else if (errno == ENODATA) { - /* file without LOVEA, this component-add will be turned - * into a component-create. */ + /* + * file without LOVEA, this component-add will be turned + * into a component-create. + */ llapi_layout_free(head); ret = -ENODATA; - /* the new layout will be added to an empty one, it - * still needs to be adjusted below */ + /* + * the new layout will be added to an empty one, it + * still needs to be adjusted below + */ comp_add = 0; break; } else if (!llapi_layout_is_composite(head)) { - fprintf(stderr, "%s setstripe: '%s' not a composite " - "file\n", progname, fname); + fprintf(stderr, + "%s setstripe: '%s' not a composite file\n", + progname, fname); llapi_layout_free(head); return -EINVAL; } rc = llapi_layout_comp_extent_get(head, &start, &prev_end); if (rc) { - fprintf(stderr, "%s setstripe: cannot get prev " - "extent: %s\n", progname, strerror(errno)); + fprintf(stderr, + "%s setstripe: cannot get prev extent: %s\n", + progname, strerror(errno)); llapi_layout_free(head); return rc; } @@ -2863,16 +3231,16 @@ static int layout_adjust_first_extent(char *fname, struct llapi_layout *layout, } if (start > prev_end || end < prev_end) { - fprintf(stderr, "%s setstripe: first extent [%lu, %lu) not " - "adjacent with extent end %lu\n", + fprintf(stderr, + "%s setstripe: first extent [%lu, %lu) not adjacent with extent end %lu\n", progname, start, end, prev_end); return -EINVAL; } rc = llapi_layout_comp_extent_set(layout, prev_end, end); if (rc) { - fprintf(stderr, "%s setstripe: cannot set component extent " - "[%lu, %lu): %s\n", + fprintf(stderr, + "%s setstripe: cannot set component extent [%lu, %lu): %s\n", progname, prev_end, end, strerror(errno)); return rc; } @@ -2884,10 +3252,10 @@ static int mirror_adjust_first_extents(struct mirror_args *list) { int rc = 0; - if (list == NULL) + if (!list) return 0; - while (list != NULL) { + while (list) { rc = layout_adjust_first_extent(NULL, list->m_layout, false); if (rc) break; @@ -2916,8 +3284,10 @@ static struct mirror_args *lfs_mirror_alloc(void) while (1) { mirror = calloc(1, sizeof(*mirror)); - if (mirror != NULL) + if (mirror) { + mirror->m_inherit = false; break; + } sleep(1); } @@ -2937,7 +3307,7 @@ static struct mirror_args *lfs_mirror_alloc(void) */ static void lfs_mirror_free(struct mirror_args *mirror) { - if (mirror->m_layout != NULL) + if (mirror->m_layout) llapi_layout_free(mirror->m_layout); free(mirror); } @@ -2954,7 +3324,7 @@ static void lfs_mirror_list_free(struct mirror_args *mirror_list) { struct mirror_args *next_mirror = NULL; - while (mirror_list != NULL) { + while (mirror_list) { next_mirror = mirror_list->m_next; lfs_mirror_free(mirror_list); mirror_list = next_mirror; @@ -2962,6 +3332,7 @@ static void lfs_mirror_list_free(struct mirror_args *mirror_list) } enum { + LFS_SETQUOTA_DELETE = 1, LFS_POOL_OPT = 3, LFS_COMP_COUNT_OPT, LFS_COMP_START_OPT, @@ -2979,8 +3350,16 @@ enum { LFS_LAYOUT_FOREIGN_OPT, LFS_MODE_OPT, LFS_NEWERXY_OPT, + LFS_INHERIT_RR_OPT, + LFS_FIND_PERM, + LFS_PRINTF_OPT, }; +#ifndef LCME_USER_MIRROR_FLAGS +/* The mirror flags can be set by users at creation time. */ +#define LCME_USER_MIRROR_FLAGS (LCME_FL_PREF_RW) +#endif + /* functions */ static int lfs_setstripe_internal(int argc, char **argv, enum setstripe_origin opc) @@ -3033,6 +3412,7 @@ static int lfs_setstripe_internal(int argc, char **argv, /* find { .val = 'A', .name = "atime", .has_arg = required_argument }*/ /* --block is only valid in migrate mode */ { .val = 'b', .name = "block", .has_arg = no_argument }, +/* find { .val = 'B', .name = "btime", .has_arg = required_argument }*/ { .val = LFS_COMP_ADD_OPT, .name = "comp-add", .has_arg = no_argument }, { .val = LFS_COMP_ADD_OPT, @@ -3070,6 +3450,8 @@ static int lfs_setstripe_internal(int argc, char **argv, .has_arg = required_argument}, { .val = 'd', .name = "delete", .has_arg = no_argument}, { .val = 'd', .name = "destroy", .has_arg = no_argument}, + /* used with "lfs migrate -m" */ + { .val = 'd', .name = "directory", .has_arg = no_argument}, /* --non-direct is only valid in migrate mode */ { .val = 'D', .name = "non-direct", .has_arg = no_argument }, { .val = 'E', .name = "comp-end", .has_arg = required_argument}, @@ -3079,7 +3461,7 @@ static int lfs_setstripe_internal(int argc, char **argv, /* find { .val = 'F', .name = "fid", .has_arg = no_argument }, */ /* find { .val = 'g', .name = "gid", .has_arg = no_argument }, */ /* find { .val = 'G', .name = "group", .has_arg = required_argument }*/ -/* find { .val = 'h', .name = "help", .has_arg = no_argument }, */ + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'H', .name = "mdt-hash", .has_arg = required_argument}, { .val = 'i', .name = "stripe-index", .has_arg = required_argument}, { .val = 'i', .name = "stripe_index", .has_arg = required_argument}, @@ -3101,7 +3483,6 @@ static int lfs_setstripe_internal(int argc, char **argv, { .val = 'p', .name = "pool", .has_arg = required_argument }, /* find { .val = 'P', .name = "print", .has_arg = no_argument }, */ /* getstripe { .val = 'q', .name = "quiet", .has_arg = no_argument }, */ -/* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */ /* getstripe { .val = 'R', .name = "raw", .has_arg = no_argument }, */ { .val = 'S', .name = "stripe-size", .has_arg = required_argument }, { .val = 'S', .name = "stripe_size", .has_arg = required_argument }, @@ -3112,6 +3493,7 @@ static int lfs_setstripe_internal(int argc, char **argv, /* --verbose is only valid in migrate mode */ { .val = 'v', .name = "verbose", .has_arg = no_argument}, { .val = 'x', .name = "xattr", .has_arg = required_argument }, +/* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/ { .val = 'y', .name = "yaml", .has_arg = required_argument }, { .val = 'z', .name = "ext-size", .has_arg = required_argument}, { .val = 'z', .name = "extension-size", .has_arg = required_argument}, @@ -3130,7 +3512,7 @@ static int lfs_setstripe_internal(int argc, char **argv, snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]); progname = cmd; while ((c = getopt_long(argc, argv, - "bc:C:dDE:f:H:i:I:m:N::no:p:L:s:S:vx:y:z:", + "bc:C:dDE:f:hH:i:I:m:N::no:p:L:s:S:vx:y:z:", long_opts, NULL)) >= 0) { size_units = 1; switch (c) { @@ -3149,7 +3531,8 @@ static int lfs_setstripe_internal(int argc, char **argv, if (result != 0) goto usage_error; if (mirror_mode && lsa.lsa_comp_neg_flags) { - fprintf(stderr, "%s: inverted flags are not supported\n", + fprintf(stderr, + "%s: inverted flags are not supported\n", progname); goto usage_error; } @@ -3160,32 +3543,48 @@ static int lfs_setstripe_internal(int argc, char **argv, case LFS_COMP_NO_VERIFY_OPT: mirror_flags |= MF_NO_VERIFY; break; - case LFS_MIRROR_ID_OPT: - mirror_id = strtoul(optarg, &end, 0); - if (*end != '\0' || mirror_id == 0) { + case LFS_MIRROR_ID_OPT: { + unsigned long int id; + + errno = 0; + id = strtoul(optarg, &end, 0); + if (errno != 0 || *end != '\0' || id == 0 || + id > UINT16_MAX) { fprintf(stderr, "%s %s: invalid mirror ID '%s'\n", progname, argv[0], optarg); goto usage_error; } + + mirror_id = (__u16)id; break; + } case LFS_LAYOUT_FLAGS_OPT: { uint32_t neg_flags; /* check for numeric flags (foreign and mirror cases) */ if (setstripe_mode && !mirror_mode && !last_mirror) { + errno = 0; flags = strtoul(optarg, &end, 16); - if (*end != '\0') { + if (errno != 0 || *end != '\0' || + flags >= UINT32_MAX) { fprintf(stderr, - "%s %s: bad flags '%s'\n", + "%s %s: invalid hex flags '%s'\n", progname, argv[0], optarg); return CMD_HELP; } + if (!foreign_mode) { + fprintf(stderr, + "%s %s: hex flags must be specified with --foreign option\n", + progname, argv[0]); + return CMD_HELP; + } break; } if (!mirror_mode || !last_mirror) { - fprintf(stderr, "error: %s: --flags must be specified with --mirror-count|-N option\n", + fprintf(stderr, + "error: %s: --flags must be specified with --mirror-count|-N option\n", progname); goto usage_error; } @@ -3196,7 +3595,8 @@ static int lfs_setstripe_internal(int argc, char **argv, goto usage_error; if (neg_flags) { - fprintf(stderr, "%s: inverted flags are not supported\n", + fprintf(stderr, + "%s: inverted flags are not supported\n", progname); result = -EINVAL; goto usage_error; @@ -3211,7 +3611,7 @@ static int lfs_setstripe_internal(int argc, char **argv, break; } case LFS_LAYOUT_FOREIGN_OPT: - if (optarg != NULL) { + if (optarg) { /* check pure numeric */ type = strtoul(optarg, &end, 0); if (*end) { @@ -3224,13 +3624,18 @@ static int lfs_setstripe_internal(int argc, char **argv, optarg); return CMD_HELP; } + } else if (type >= UINT32_MAX) { + fprintf(stderr, + "%s %s: invalid foreign type '%s'\n", + progname, argv[0], optarg); + return CMD_HELP; } } foreign_mode = true; break; case LFS_MODE_OPT: mode_opt = optarg; - if (mode_opt != NULL) { + if (mode_opt) { mode = strtoul(mode_opt, &end, 8); if (*end != '\0') { fprintf(stderr, @@ -3255,11 +3660,20 @@ static int lfs_setstripe_internal(int argc, char **argv, migration_block = true; break; case 'C': + if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) { + fprintf(stderr, + "%s %s: -C|--overstripe-count incompatible with DoM layout\n", + progname, argv[0]); + goto usage_error; + } lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING; - /* fall through */ + fallthrough; case 'c': + errno = 0; lsa.lsa_stripe_count = strtoul(optarg, &end, 0); - if (*end != '\0') { + if (errno != 0 || *end != '\0'|| optarg == end || + lsa.lsa_stripe_count < -1 || + lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) { fprintf(stderr, "%s %s: invalid stripe count '%s'\n", progname, argv[0], optarg); @@ -3270,27 +3684,30 @@ static int lfs_setstripe_internal(int argc, char **argv, lsa.lsa_stripe_count = LLAPI_LAYOUT_WIDE; break; case 'd': - /* delete the default striping pattern */ - delete = 1; - if (opc == SO_MIRROR_SPLIT) { - if (has_m_file) { - fprintf(stderr, - "%s %s: -d cannot used with -f\n", - progname, argv[0]); - goto usage_error; + if (migrate_mode) { + migrate_mdt_param.fp_max_depth = 1; + } else { + /* delete the default striping pattern */ + delete = 1; + if (opc == SO_MIRROR_SPLIT) { + if (has_m_file) { + fprintf(stderr, + "%s %s: -d cannot used with -f\n", + progname, argv[0]); + goto usage_error; + } + mirror_flags |= MF_DESTROY; } - mirror_flags |= MF_DESTROY; } break; case 'D': if (!migrate_mode) { fprintf(stderr, - "%s %s: -D|--non-direct is valid " - "only for migrate command\n", + "%s %s: -D|--non-direct is valid only for migrate command\n", progname, argv[0]); goto usage_error; } - migration_flags |= MIGRATION_NONDIRECT; + migration_flags |= LLAPI_MIGRATION_NONDIRECT; break; case 'E': if (lsa.lsa_comp_end != 0) { @@ -3308,9 +3725,13 @@ static int lfs_setstripe_internal(int argc, char **argv, lsa.lsa_comp_end = LUSTRE_EOF; } else { result = llapi_parse_size(optarg, - &lsa.lsa_comp_end, - &size_units, 0); - if (result) { + &lsa.lsa_comp_end, + &size_units, 0); + /* assume units of KB if too small */ + if (lsa.lsa_comp_end < 4096) + lsa.lsa_comp_end *= 1024; + if (result || + lsa.lsa_comp_end & (LOV_MIN_STRIPE_SIZE - 1)) { fprintf(stderr, "%s %s: invalid component end '%s'\n", progname, argv[0], optarg); @@ -3320,7 +3741,8 @@ static int lfs_setstripe_internal(int argc, char **argv, break; case 'H': if (!migrate_mode) { - fprintf(stderr, "--mdt-hash is valid only for migrate command\n"); + fprintf(stderr, + "--mdt-hash is valid only for migrate command\n"); return CMD_HELP; } @@ -3333,8 +3755,11 @@ static int lfs_setstripe_internal(int argc, char **argv, } break; case 'i': + errno = 0; lsa.lsa_stripe_off = strtol(optarg, &end, 0); - if (*end != '\0') { + if (errno != 0 || *end != '\0' || optarg == end || + lsa.lsa_stripe_off < -1 || + lsa.lsa_stripe_off > LOV_V1_INSANE_STRIPE_COUNT) { fprintf(stderr, "%s %s: invalid stripe offset '%s'\n", progname, argv[0], optarg); @@ -3361,7 +3786,7 @@ static int lfs_setstripe_internal(int argc, char **argv, goto usage_error; } if (opc == SO_MIRROR_EXTEND) { - if (last_mirror == NULL) { + if (!last_mirror) { fprintf(stderr, "error: %s: '-N' must exist in front of '%s'\n", progname, argv[optopt + 1]); @@ -3371,7 +3796,7 @@ static int lfs_setstripe_internal(int argc, char **argv, last_mirror->m_count = 1; } else { /* mirror split */ - if (mirror_list == NULL) + if (!mirror_list) mirror_list = lfs_mirror_alloc(); mirror_list->m_file = optarg; } @@ -3380,24 +3805,25 @@ static int lfs_setstripe_internal(int argc, char **argv, case 'L': if (strcmp(argv[optind - 1], "mdt") == 0) { /* Can be only the first component */ - if (layout != NULL) { + if (layout) { result = -EINVAL; - fprintf(stderr, "error: 'mdt' layout " - "can be only the first one\n"); + fprintf(stderr, + "error: 'mdt' layout can be only the first one\n"); goto error; } if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */ result = -EFBIG; - fprintf(stderr, "error: 'mdt' layout " - "size is too big\n"); + fprintf(stderr, + "error: 'mdt' layout size is too big\n"); goto error; } lsa.lsa_pattern = LLAPI_LAYOUT_MDT; + lsa.lsa_stripe_size = LLAPI_LAYOUT_DEFAULT; } else if (strcmp(argv[optind - 1], "raid0") != 0) { result = -EINVAL; - fprintf(stderr, "error: layout '%s' is " - "unknown, supported layouts are: " - "'mdt', 'raid0'\n", argv[optind]); + fprintf(stderr, + "error: layout '%s' is unknown, supported layouts are: 'mdt', 'raid0'\n", + argv[optind]); goto error; } break; @@ -3414,9 +3840,9 @@ static int lfs_setstripe_internal(int argc, char **argv, lsa.lsa_nr_tgts, optarg, NULL); if (lsa.lsa_nr_tgts < 0) { fprintf(stderr, - "%s %s: invalid MDT target(s) '%s'\n", - progname, argv[0], optarg); - return CMD_HELP; + "%s: invalid MDT target(s) '%s'\n", + progname, optarg); + goto usage_error; } lsa.lsa_tgts = tgts; @@ -3430,7 +3856,7 @@ static int lfs_setstripe_internal(int argc, char **argv, progname, argv[0]); goto usage_error; } - migration_flags |= MIGRATION_NONBLOCK; + migration_flags |= LLAPI_MIGRATION_NONBLOCK; break; case 'N': if (opc == SO_SETSTRIPE) { @@ -3438,9 +3864,12 @@ static int lfs_setstripe_internal(int argc, char **argv, mirror_mode = true; } mirror_count = 1; - if (optarg != NULL) { + if (optarg) { + errno = 0; mirror_count = strtoul(optarg, &end, 0); - if (*end != '\0' || mirror_count == 0) { + if (errno != 0 || *end != '\0' || + mirror_count == 0 || + mirror_count > LUSTRE_MIRROR_COUNT_MAX) { fprintf(stderr, "error: %s: bad mirror count: %s\n", progname, optarg); @@ -3452,11 +3881,13 @@ static int lfs_setstripe_internal(int argc, char **argv, new_mirror = lfs_mirror_alloc(); new_mirror->m_count = mirror_count; - if (mirror_list == NULL) + if (!mirror_list) mirror_list = new_mirror; - if (last_mirror != NULL) { + if (last_mirror) { /* wrap up last mirror */ + if (!setstripe_args_specified(&lsa)) + last_mirror->m_inherit = true; if (lsa.lsa_comp_end == 0) lsa.lsa_comp_end = LUSTRE_EOF; @@ -3477,10 +3908,17 @@ static int lfs_setstripe_internal(int argc, char **argv, case 'o': #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0) if (strcmp(argv[optind - 1], "--ost-list") == 0) - fprintf(stderr, "warning: '--ost-list' is " - "deprecated, use '--ost' instead\n"); + fprintf(stderr, + "warning: '--ost-list' is deprecated, use '--ost' instead\n"); #endif - /* -o allows overstriping, and must note it because + if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) { + fprintf(stderr, + "%s %s: -o|--ost incompatible with DoM layout\n", + progname, argv[0]); + goto usage_error; + } + /* + * -o allows overstriping, and must note it because * parse_targets is shared with MDT striping, which * does not allow duplicates */ @@ -3501,7 +3939,7 @@ static int lfs_setstripe_internal(int argc, char **argv, lsa.lsa_stripe_off = tgts[0]; break; case 'p': - if (optarg == NULL) + if (!optarg) goto usage_error; lsa.lsa_pool_name = optarg; @@ -3513,7 +3951,11 @@ static int lfs_setstripe_internal(int argc, char **argv, case 'S': result = llapi_parse_size(optarg, &lsa.lsa_stripe_size, &size_units, 0); - if (result) { + /* assume units of KB if too small to be valid */ + if (lsa.lsa_stripe_size < 4096) + lsa.lsa_stripe_size *= 1024; + if (result || + lsa.lsa_stripe_size & (LOV_MIN_STRIPE_SIZE - 1)) { fprintf(stderr, "%s %s: invalid stripe size '%s'\n", progname, argv[0], optarg); @@ -3528,7 +3970,7 @@ static int lfs_setstripe_internal(int argc, char **argv, goto usage_error; } migrate_mdt_param.fp_verbose = VERBOSE_DETAIL; - migration_flags = MIGRATION_VERBOSE; + migration_flags = LLAPI_MIGRATION_VERBOSE; break; case 'x': xattr = optarg; @@ -3551,8 +3993,9 @@ static int lfs_setstripe_internal(int argc, char **argv, lsa.lsa_extension_comp = true; break; default: - fprintf(stderr, "%s %s: unrecognized option '%s'\n", - progname, argv[0], argv[optind - 1]); + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + case 'h': goto usage_error; } } @@ -3565,8 +4008,14 @@ static int lfs_setstripe_internal(int argc, char **argv, goto usage_error; } + /* lfs migrate $filename should keep the file's layout by default */ + if (migrate_mode && !layout && !from_yaml && + !setstripe_args_specified(&lsa) && !lsa.lsa_pool_name) + from_copy = true; + if (xattr && !foreign_mode) { - /* only print a warning as this is harmless and will be ignored + /* + * only print a warning as this is harmless and will be ignored */ fprintf(stderr, "%s %s: xattr has been specified for non-foreign layout\n", @@ -3597,6 +4046,8 @@ static int lfs_setstripe_internal(int argc, char **argv, } if (mirror_mode) { + if (!setstripe_args_specified(&lsa)) + last_mirror->m_inherit = true; if (lsa.lsa_comp_end == 0) lsa.lsa_comp_end = LUSTRE_EOF; } @@ -3627,8 +4078,9 @@ static int lfs_setstripe_internal(int argc, char **argv, } } - if (comp_set && !comp_id) { - fprintf(stderr, "%s %s: --component-set doesn't have component-id set\n", + if (comp_set && !comp_id && !lsa.lsa_pool_name) { + fprintf(stderr, + "%s %s: --component-set doesn't have component-id set\n", progname, argv[0]); goto usage_error; } @@ -3675,15 +4127,15 @@ static int lfs_setstripe_internal(int argc, char **argv, } if (mirror_mode) { - fprintf(stderr, "error: %s: can't use --component-add " - "or --component-del for mirror operation\n", + fprintf(stderr, + "error: %s: can't use --component-add or --component-del for mirror operation\n", progname); goto usage_error; } } if (comp_add) { - if (layout == NULL) { + if (!layout) { fprintf(stderr, "%s %s: option -E must be specified with --component-add\n", progname, argv[0]); @@ -3691,21 +4143,6 @@ static int lfs_setstripe_internal(int argc, char **argv, } } - if (layout != NULL || mirror_list != NULL) { - if (mirror_list) - result = mirror_adjust_first_extents(mirror_list); - else - result = layout_adjust_first_extent(fname, layout, - comp_add); - if (result == -ENODATA) - comp_add = 0; - else if (result != 0) { - fprintf(stderr, "error: %s: invalid layout\n", - progname); - goto error; - } - } - if (from_yaml && from_copy) { fprintf(stderr, "%s: can't specify --yaml and --copy together\n", @@ -3715,13 +4152,13 @@ static int lfs_setstripe_internal(int argc, char **argv, if ((from_yaml || from_copy) && (setstripe_args_specified(&lsa) || layout != NULL)) { - fprintf(stderr, "error: %s: can't specify --yaml with " - "-c, -S, -i, -o, -p or -E options.\n", + fprintf(stderr, + "error: %s: can't specify --yaml or --copy with -c, -S, -i, -o, -p or -E options.\n", argv[0]); goto error; } - if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) { + if ((migration_flags & LLAPI_MIGRATION_NONBLOCK) && migration_block) { fprintf(stderr, "%s %s: options --non-block and --block are mutually exclusive\n", progname, argv[0]); @@ -3762,7 +4199,7 @@ static int lfs_setstripe_internal(int argc, char **argv, if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0) lmu->lum_hash_type = lsa.lsa_pattern; else - lmu->lum_hash_type = LMV_HASH_TYPE_DEFAULT; + lmu->lum_hash_type = LMV_HASH_TYPE_UNKNOWN; if (lsa.lsa_pool_name) { strncpy(lmu->lum_pool_name, lsa.lsa_pool_name, sizeof(lmu->lum_pool_name) - 1); @@ -3792,11 +4229,14 @@ static int lfs_setstripe_internal(int argc, char **argv, migrate_mdt_param.fp_lmv_md = lmu; migrate_mdt_param.fp_migrate = 1; - } else if (layout == NULL) { + } else if (!layout) { + if (lsa_args_stripe_count_check(&lsa)) + goto usage_error; + /* initialize stripe parameters */ param = calloc(1, offsetof(typeof(*param), lsp_osts[lsa.lsa_nr_tgts])); - if (param == NULL) { + if (!param) { fprintf(stderr, "%s %s: cannot allocate memory for parameters: %s\n", progname, argv[0], strerror(ENOMEM)); @@ -3826,19 +4266,8 @@ static int lfs_setstripe_internal(int argc, char **argv, } param->lsp_pool = lsa.lsa_pool_name; param->lsp_is_specific = false; - if (lsa.lsa_nr_tgts > 0) { - if (lsa.lsa_stripe_count > 0 && - lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT && - lsa.lsa_stripe_count != LLAPI_LAYOUT_WIDE && - lsa.lsa_nr_tgts != lsa.lsa_stripe_count) { - fprintf(stderr, - "error: %s: stripe count %lld doesn't match the number of OSTs: %d\n", - argv[0], lsa.lsa_stripe_count, - lsa.lsa_nr_tgts); - free(param); - goto usage_error; - } + if (lsa.lsa_nr_tgts > 0) { param->lsp_is_specific = true; param->lsp_stripe_count = lsa.lsa_nr_tgts; memcpy(param->lsp_osts, tgts, @@ -3851,22 +4280,41 @@ static int lfs_setstripe_internal(int argc, char **argv, result = lfs_comp_create_from_yaml(template, &layout, &lsa, tgts); if (result) { - fprintf(stderr, "error: %s: can't create composite " - "layout from template file %s\n", + fprintf(stderr, + "error: %s: can't create composite layout from template file %s\n", argv[0], template); goto error; } - } else if (from_copy) { - layout = llapi_layout_get_by_path(template, 0); - if (layout == NULL) { - fprintf(stderr, - "%s: can't create composite layout from file %s.\n", - progname, template); + } + + if (layout != NULL || mirror_list != NULL) { + if (mirror_list) + result = mirror_adjust_first_extents(mirror_list); + else + result = layout_adjust_first_extent(fname, layout, + comp_add); + if (result == -ENODATA) + comp_add = 0; + else if (result != 0) { + fprintf(stderr, "error: %s: invalid layout\n", + progname); goto error; } } for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) { + if (from_copy) { + layout = llapi_layout_get_by_path(template ?: fname, 0); + if (!layout) { + fprintf(stderr, + "%s: can't create composite layout from file %s: %s\n", + progname, template ?: fname, + strerror(errno)); + result = -errno; + goto error; + } + } + if (migrate_mdt_mode) { result = llapi_migrate_mdt(fname, &migrate_mdt_param); } else if (migrate_mode) { @@ -3874,6 +4322,7 @@ static int lfs_setstripe_internal(int argc, char **argv, layout); } else if (comp_set != 0) { result = lfs_component_set(fname, comp_id, + lsa.lsa_pool_name, lsa.lsa_comp_flags, lsa.lsa_comp_neg_flags); } else if (comp_del != 0) { @@ -3890,7 +4339,7 @@ static int lfs_setstripe_internal(int argc, char **argv, } else if (opc == SO_MIRROR_SPLIT || opc == SO_MIRROR_DELETE) { if (!mirror_id && !comp_id && !lsa.lsa_pool_name) { fprintf(stderr, - "%s: no mirror specified to delete from '%s'\n", + "%s: no mirror id, component id, or pool name specified to delete from '%s'\n", progname, fname); goto usage_error; } @@ -3900,11 +4349,17 @@ static int lfs_setstripe_internal(int argc, char **argv, comp_id = mirror_id; else mirror_flags |= MF_COMP_ID; + if (has_m_file && !strcmp(fname, mirror_list->m_file)) { + fprintf(stderr, + "%s: the file specified by -f cannot be same as the source file '%s'\n", + progname, fname); + goto usage_error; + } result = mirror_split(fname, comp_id, lsa.lsa_pool_name, mirror_flags, has_m_file ? mirror_list->m_file : NULL); - } else if (layout != NULL) { + } else if (layout) { result = lfs_component_create(fname, O_CREAT | O_WRONLY, mode, layout); if (result >= 0) { @@ -3935,7 +4390,7 @@ static int lfs_setstripe_internal(int argc, char **argv, } } - if (mode_opt != NULL) + if (mode_opt) umask(previous_umask); free(param); @@ -3953,26 +4408,27 @@ error: static int lfs_poollist(int argc, char **argv) { - if (argc != 2) - return CMD_HELP; + if (argc != 2) + return CMD_HELP; - return llapi_poollist(argv[1]); + return llapi_poollist(argv[1]); } +#define FP_DEFAULT_TIME_MARGIN (24 * 60 * 60) static time_t set_time(struct find_param *param, time_t *time, time_t *set, char *str) { long long t = 0; - int res = 0; + int sign = 0; char *endptr = "AD"; char *timebuf; if (str[0] == '+') - res = 1; + sign = 1; else if (str[0] == '-') - res = -1; + sign = -1; - if (res) + if (sign) str++; for (timebuf = str; *endptr && *(endptr + 1); timebuf = endptr + 1) { @@ -3982,16 +4438,25 @@ static time_t set_time(struct find_param *param, time_t *time, time_t *set, switch (*endptr) { case 'y': unit *= 52; /* 52 weeks + 1 day below */ - case 'w': /* fallthrough */ + fallthrough; + case 'w': unit *= 7; + if (param->fp_time_margin == FP_DEFAULT_TIME_MARGIN) + param->fp_time_margin *= (1 + unit / 52); + unit += (*endptr == 'y'); /* +1 day for 365 days/year */ + fallthrough; case '\0': /* days are default unit if none used */ - case 'd': /* fallthrough */ - unit = (unit + (*endptr == 'y')) * 24; - case 'h': /* fallthrough */ + fallthrough; + case 'd': + unit *= 24; + fallthrough; + case 'h': unit *= 60; - case 'm': /* fallthrough */ + fallthrough; + case 'm': unit *= 60; - case 's': /* fallthrough */ + fallthrough; + case 's': break; /* don't need to multiply by 1 for seconds */ default: @@ -4008,7 +4473,7 @@ static time_t set_time(struct find_param *param, time_t *time, time_t *set, t += val * unit; } if (*time < t) { - if (res != 0) + if (sign != 0) str--; fprintf(stderr, "%s find: bad time '%s': too large\n", progname, str); @@ -4017,7 +4482,23 @@ static time_t set_time(struct find_param *param, time_t *time, time_t *set, *set = *time - t; - return res; + return sign; +} + +static int str2quotaid(__u32 *id, const char *arg) +{ + unsigned long int projid_tmp = 0; + char *endptr = NULL; + + projid_tmp = strtoul(arg, &endptr, 10); + if (*endptr != '\0') + return -EINVAL; + /* UINT32_MAX is not allowed - see projid_valid()/INVALID_PROJID */ + if (projid_tmp >= UINT32_MAX) + return -ERANGE; + + *id = projid_tmp; + return 0; } static int name2uid(unsigned int *id, const char *name) @@ -4025,7 +4506,7 @@ static int name2uid(unsigned int *id, const char *name) struct passwd *passwd; passwd = getpwnam(name); - if (passwd == NULL) + if (!passwd) return -ENOENT; *id = passwd->pw_uid; @@ -4037,7 +4518,7 @@ static int name2gid(unsigned int *id, const char *name) struct group *group; group = getgrnam(name); - if (group == NULL) + if (!group) return -ENOENT; *id = group->gr_gid; @@ -4054,7 +4535,7 @@ static int uid2name(char **name, unsigned int id) struct passwd *passwd; passwd = getpwuid(id); - if (passwd == NULL) + if (!passwd) return -ENOENT; *name = passwd->pw_name; @@ -4066,7 +4547,7 @@ static inline int gid2name(char **name, unsigned int id) struct group *group; group = getgrgid(id); - if (group == NULL) + if (!group) return -ENOENT; *name = group->gr_name; @@ -4080,7 +4561,7 @@ static int name2layout(__u32 *layout, char *name) *layout = 0; for (ptr = name; ; ptr = NULL) { layout_name = strtok(ptr, ","); - if (layout_name == NULL) + if (!layout_name) break; if (strcmp(layout_name, "released") == 0) *layout |= LOV_PATTERN_F_RELEASED; @@ -4096,6 +4577,234 @@ static int name2layout(__u32 *layout, char *name) return 0; } +static int parse_symbolic(const char *input, mode_t *outmode, const char **end) +{ + int loop; + int user, group, other; + int who, all; + char c, op; + mode_t perm; + mode_t usermask; + mode_t previous_flags; + + user = group = other = 0; + all = 0; + loop = 1; + perm = 0; + previous_flags = 0; + *end = input; + usermask = 0; + + while (loop) { + switch (*input) { + case 'u': + user = 1; + break; + case 'g': + group = 1; + break; + case 'o': + other = 1; + break; + case 'a': + user = group = other = 1; + all = 1; + break; + default: + loop = 0; + } + + if (loop) + input++; + } + + who = user || group || other; + if (!who) { + /* get the umask */ + usermask = umask(0022); + umask(usermask); + usermask &= 07777; + } + + if (*input == '-' || *input == '+' || *input == '=') + op = *input++; + else + /* operation is required */ + return -1; + + /* get the flags in *outmode */ + switch (*input) { + case 'u': + previous_flags = (*outmode & 0700); + perm |= user ? previous_flags : 0; + perm |= group ? (previous_flags >> 3) : 0; + perm |= other ? (previous_flags >> 6) : 0; + input++; + goto write_perm; + case 'g': + previous_flags = (*outmode & 0070); + perm |= user ? (previous_flags << 3) : 0; + perm |= group ? previous_flags : 0; + perm |= other ? (previous_flags >> 3) : 0; + input++; + goto write_perm; + case 'o': + previous_flags = (*outmode & 0007); + perm |= user ? (previous_flags << 6) : 0; + perm |= group ? (previous_flags << 3) : 0; + perm |= other ? previous_flags : 0; + input++; + goto write_perm; + default: + break; + } + + /* this part is optional, + * if empty perm = 0 and *outmode is not modified + */ + loop = 1; + while (loop) { + c = *input; + switch (c) { + case 'r': + perm |= user ? 0400 : 0; + perm |= group ? 0040 : 0; + perm |= other ? 0004 : 0; + /* set read permission for uog except for umask's + * permissions + */ + perm |= who ? 0 : (0444 & ~usermask); + break; + case 'w': + perm |= user ? 0200 : 0; + perm |= group ? 0020 : 0; + perm |= other ? 0002 : 0; + /* set write permission for uog except for umask' + * permissions + */ + perm |= who ? 0 : (0222 & ~usermask); + break; + case 'x': + perm |= user ? 0100 : 0; + perm |= group ? 0010 : 0; + perm |= other ? 0001 : 0; + /* set execute permission for uog except for umask' + * permissions + */ + perm |= who ? 0 : (0111 & ~usermask); + break; + case 'X': + /* + * Adds execute permission to 'u', 'g' and/or 'g' if + * specified and either 'u', 'g' or 'o' already has + * execute permissions. + */ + if ((*outmode & 0111) != 0) { + perm |= user ? 0100 : 0; + perm |= group ? 0010 : 0; + perm |= other ? 0001 : 0; + perm |= !who ? 0111 : 0; + } + break; + case 's': + /* s is ignored if o is given, but it's not an error */ + if (other && !group && !user) + break; + perm |= user ? S_ISUID : 0; + perm |= group ? S_ISGID : 0; + break; + case 't': + /* 't' should be used when 'a' is given + * or who is empty + */ + perm |= (!who || all) ? S_ISVTX : 0; + /* using ugo with t is not an error */ + break; + default: + loop = 0; + break; + } + if (loop) + input++; + } + +write_perm: + /* uog flags should be only one character long */ + if (previous_flags && (*input != '\0' && *input != ',')) + return -1; + + switch (op) { + case '-': + /* remove the flags from outmode */ + *outmode &= ~perm; + break; + case '+': + /* add the flags to outmode */ + *outmode |= perm; + break; + case '=': + /* set the flags of outmode to perm */ + if (perm != 0) + *outmode = perm; + break; + } + + *end = input; + return 0; +} + +static int str2mode_t(const char *input, mode_t *outmode) +{ + int ret; + const char *iter; + + ret = 0; + + if (*input >= '0' && *input <= '7') { + /* parse octal representation */ + char *end; + + iter = input; + + /* look for invalid digits in octal representation */ + while (isdigit(*iter)) + if (*iter++ > '7') + return -1; + + errno = 0; + *outmode = strtoul(input, &end, 8); + + if (errno != 0 || *outmode > 07777) { + *outmode = 0; + ret = -1; + } + + } else if (*input == '8' || *input == '9') { + /* error: invalid octal number */ + ret = -1; + } else { + /* parse coma seperated list of symbolic representation */ + int rc; + const char *end; + + *outmode = 0; + rc = 0; + end = NULL; + + do { + rc = parse_symbolic(input, outmode, &end); + if (rc) + return -1; + + input = end+1; + } while (*end == ','); + + if (*end != '\0') + ret = -1; + } + return ret; +} + static int lfs_find(int argc, char **argv) { int c, rc; @@ -4104,11 +4813,13 @@ static int lfs_find(int argc, char **argv) struct find_param param = { .fp_max_depth = -1, .fp_quiet = 1, - .fp_time_margin = 24 * 60 * 60, + .fp_time_margin = FP_DEFAULT_TIME_MARGIN, }; - struct option long_opts[] = { + struct option long_opts[] = { { .val = 'A', .name = "atime", .has_arg = required_argument }, { .val = 'b', .name = "blocks", .has_arg = required_argument }, + { .val = 'B', .name = "btime", .has_arg = required_argument }, + { .val = 'B', .name = "Btime", .has_arg = required_argument }, { .val = LFS_COMP_COUNT_OPT, .name = "comp-count", .has_arg = required_argument }, { .val = LFS_COMP_COUNT_OPT, @@ -4126,8 +4837,6 @@ static int lfs_find(int argc, char **argv) .has_arg = required_argument }, { .val = LFS_MIRROR_STATE_OPT, .name = "mirror-state", .has_arg = required_argument }, - { .val = LFS_LAYOUT_FOREIGN_OPT, - .name = "foreign", .has_arg = optional_argument}, { .val = LFS_NEWERXY_OPT, .name = "newer", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, @@ -4137,23 +4846,49 @@ static int lfs_find(int argc, char **argv) { .val = LFS_NEWERXY_OPT, .name = "newerac", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, + .name = "newerab", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, .name = "newerma", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, .name = "newermm", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, .name = "newermc", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, + .name = "newermb", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, .name = "newerca", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, .name = "newercm", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, .name = "newercc", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, + .name = "newercb", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerba", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerbm", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerbc", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerbb", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerBa", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerBm", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerBc", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerBB", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, .name = "newerat", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, .name = "newermt", .has_arg = required_argument}, { .val = LFS_NEWERXY_OPT, .name = "newerct", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerbt", .has_arg = required_argument}, + { .val = LFS_NEWERXY_OPT, + .name = "newerBt", .has_arg = required_argument}, { .val = 'c', .name = "stripe-count", .has_arg = required_argument }, { .val = 'c', .name = "stripe_count", .has_arg = required_argument }, { .val = 'C', .name = "ctime", .has_arg = required_argument }, @@ -4167,6 +4902,7 @@ static int lfs_find(int argc, char **argv) .name = "foreign", .has_arg = optional_argument}, { .val = 'g', .name = "gid", .has_arg = required_argument }, { .val = 'G', .name = "group", .has_arg = required_argument }, + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'H', .name = "mdt-hash", .has_arg = required_argument }, { .val = 'i', .name = "stripe-index", .has_arg = required_argument }, { .val = 'i', .name = "stripe_index", .has_arg = required_argument }, @@ -4182,11 +4918,15 @@ static int lfs_find(int argc, char **argv) /* find { .val = 'o' .name = "or", .has_arg = no_argument }, like find(1) */ { .val = 'O', .name = "obd", .has_arg = required_argument }, { .val = 'O', .name = "ost", .has_arg = required_argument }, + { .val = LFS_FIND_PERM, + .name = "perm", .has_arg = required_argument }, /* no short option for pool yet, can be 'p' after 2.18 */ { .val = LFS_POOL_OPT, .name = "pool", .has_arg = required_argument }, { .val = '0', .name = "print0", .has_arg = no_argument }, { .val = 'P', .name = "print", .has_arg = no_argument }, + { .val = LFS_PRINTF_OPT, + .name = "printf", .has_arg = required_argument }, { .val = LFS_PROJID_OPT, .name = "projid", .has_arg = required_argument }, /* getstripe { .val = 'q', .name = "quiet", .has_arg = no_argument }, */ @@ -4199,11 +4939,10 @@ static int lfs_find(int argc, char **argv) { .val = 'T', .name = "mdt-count", .has_arg = required_argument }, { .val = 'u', .name = "uid", .has_arg = required_argument }, { .val = 'U', .name = "user", .has_arg = required_argument }, +/* getstripe { .val = 'v', .name = "verbose", .has_arg = no_argument }, */ { .val = 'z', .name = "extension-size", .has_arg = required_argument }, { .val = 'z', .name = "ext-size", .has_arg = required_argument }, -/* getstripe { .val = 'v', .name = "verbose", .has_arg = no_argument }, */ -/* getstripe { .val = 'y', .name = "yaml", .has_arg = no_argument }, */ { .name = NULL } }; int optidx = 0; int pathstart = -1; @@ -4219,47 +4958,58 @@ static int lfs_find(int argc, char **argv) /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */ while ((c = getopt_long_only(argc, argv, - "-0A:b:c:C:D:E:g:G:H:i:L:m:M:n:N:O:Ppqrs:S:t:T:u:U:vz:", - long_opts, &optidx)) >= 0) { - xtime = NULL; - xsign = NULL; - if (neg_opt) - --neg_opt; - /* '!' is part of option */ - /* when getopt_long_only() finds a string which is not - * an option nor a known option argument it returns 1 - * in that case if we already have found pathstart and pathend - * (i.e. we have the list of pathnames), - * the only supported value is "!" - */ - isoption = (c != 1) || (strcmp(optarg, "!") == 0); - if (!isoption && pathend != -1) { - fprintf(stderr, "err: %s: filename|dirname must either " - "precede options or follow options\n", - argv[0]); - ret = CMD_HELP; - goto err; - } - if (!isoption && pathstart == -1) - pathstart = optind - 1; - if (isoption && pathstart != -1 && pathend == -1) - pathend = optind - 2; - switch (c) { - case 0: - /* Long options. */ - break; - case 1: - /* unknown; opt is "!" or path component, - * checking done above. - */ - if (strcmp(optarg, "!") == 0) - neg_opt = 2; - break; + "-0A:b:B:c:C:D:E:g:G:hH:i:L:m:M:n:N:O:Ppqrs:S:t:T:u:U:z:", + long_opts, &optidx)) >= 0) { + xtime = NULL; + xsign = NULL; + if (neg_opt) + --neg_opt; + /* '!' is part of option */ + /* + * when getopt_long_only() finds a string which is not + * an option nor a known option argument it returns 1 + * in that case if we already have found pathstart and pathend + * (i.e. we have the list of pathnames), + * the only supported value is "!" + */ + isoption = (c != 1) || (strcmp(optarg, "!") == 0); + if (!isoption && pathend != -1) { + fprintf(stderr, + "err: %s: filename|dirname must either precede options or follow options\n", + argv[0]); + ret = CMD_HELP; + goto err; + } + if (!isoption && pathstart == -1) + pathstart = optind - 1; + if (isoption && pathstart != -1 && pathend == -1) + pathend = optind - 2; + switch (c) { + case 0: + /* Long options. */ + break; + case 1: + /* + * unknown; opt is "!" or path component, + * checking done above. + */ + if (strcmp(optarg, "!") == 0) + neg_opt = 2; + break; case 'A': xtime = ¶m.fp_atime; xsign = ¶m.fp_asign; param.fp_exclude_atime = !!neg_opt; + /* no break, this falls through to 'B' for btime */ + fallthrough; + case 'B': + if (c == 'B') { + xtime = ¶m.fp_btime; + xsign = ¶m.fp_bsign; + param.fp_exclude_btime = !!neg_opt; + } /* no break, this falls through to 'C' for ctime */ + fallthrough; case 'C': if (c == 'C') { xtime = ¶m.fp_ctime; @@ -4267,6 +5017,7 @@ static int lfs_find(int argc, char **argv) param.fp_exclude_ctime = !!neg_opt; } /* no break, this falls through to 'M' for mtime */ + fallthrough; case 'M': if (c == 'M') { xtime = ¶m.fp_mtime; @@ -4310,10 +5061,13 @@ static int lfs_find(int argc, char **argv) optarg++; } + errno = 0; param.fp_comp_count = strtoul(optarg, &endptr, 0); - if (*endptr != '\0') { - fprintf(stderr, "error: bad component count " - "'%s'\n", optarg); + if (errno != 0 || *endptr != '\0' || + param.fp_comp_count > UINT32_MAX) { + fprintf(stderr, + "error: bad component count '%s'\n", + optarg); goto err; } param.fp_check_comp_count = 1; @@ -4323,13 +5077,15 @@ static int lfs_find(int argc, char **argv) rc = comp_str2flags(optarg, ¶m.fp_comp_flags, ¶m.fp_comp_neg_flags); if (rc) { - fprintf(stderr, "error: bad component flags " - "'%s'\n", optarg); + fprintf(stderr, + "error: bad component flags '%s'\n", + optarg); goto err; } param.fp_check_comp_flags = 1; if (neg_opt) { __u32 flags = param.fp_comp_neg_flags; + param.fp_comp_neg_flags = param.fp_comp_flags; param.fp_comp_flags = flags; } @@ -4346,8 +5102,9 @@ static int lfs_find(int argc, char **argv) rc = llapi_parse_size(optarg, ¶m.fp_comp_start, ¶m.fp_comp_start_units, 0); if (rc) { - fprintf(stderr, "error: bad component start " - "'%s'\n", optarg); + fprintf(stderr, + "error: bad component start '%s'\n", + optarg); goto err; } param.fp_check_comp_start = 1; @@ -4365,32 +5122,44 @@ static int lfs_find(int argc, char **argv) param.fp_check_mirror_state = 1; if (neg_opt) { __u16 state = param.fp_mirror_neg_state; + param.fp_mirror_neg_state = param.fp_mirror_state; param.fp_mirror_state = state; } break; - case 'c': - if (optarg[0] == '+') { + case 'c': + if (optarg[0] == '+') { param.fp_stripe_count_sign = -1; - optarg++; - } else if (optarg[0] == '-') { + optarg++; + } else if (optarg[0] == '-') { param.fp_stripe_count_sign = 1; - optarg++; - } + optarg++; + } + errno = 0; param.fp_stripe_count = strtoul(optarg, &endptr, 0); - if (*endptr != '\0') { - fprintf(stderr,"error: bad stripe_count '%s'\n", - optarg); - ret = -1; - goto err; - } + if (errno != 0 || *endptr != '\0' || + param.fp_stripe_count > LOV_MAX_STRIPE_COUNT) { + fprintf(stderr, + "error: bad stripe_count '%s'\n", + optarg); + ret = -1; + goto err; + } param.fp_check_stripe_count = 1; param.fp_exclude_stripe_count = !!neg_opt; - break; + break; case 'D': + errno = 0; param.fp_max_depth = strtol(optarg, 0, 0); + if (errno != 0 || param.fp_max_depth < 0) { + fprintf(stderr, + "error: bad maxdepth '%s'\n", + optarg); + ret = -1; + goto err; + } break; case 'E': if (optarg[0] == '+') { @@ -4409,10 +5178,14 @@ static int lfs_find(int argc, char **argv) rc = llapi_parse_size(optarg, ¶m.fp_comp_end, ¶m.fp_comp_end_units, 0); + /* assume units of KB if too small */ + if (param.fp_comp_end < 4096) + param.fp_comp_end *= 1024; } if (rc) { - fprintf(stderr, "error: bad component end " - "'%s'\n", optarg); + fprintf(stderr, + "error: bad component end '%s'\n", + optarg); goto err; } param.fp_check_comp_end = 1; @@ -4422,7 +5195,7 @@ static int lfs_find(int argc, char **argv) /* all types by default */ uint32_t type = LU_FOREIGN_TYPE_UNKNOWN; - if (optarg != NULL) { + if (optarg) { /* check pure numeric */ type = strtoul(optarg, &endptr, 0); if (*endptr) { @@ -4435,6 +5208,11 @@ static int lfs_find(int argc, char **argv) optarg); return CMD_HELP; } + } else if (type >= UINT32_MAX) { + fprintf(stderr, + "%s %s: invalid foreign type '%s'\n", + progname, argv[0], optarg); + return CMD_HELP; } } param.fp_foreign_type = type; @@ -4503,6 +5281,24 @@ static int lfs_find(int argc, char **argv) } ref = mktime(&tm); + } else if (y == 'b' || y == 'B') { + lstatx_t stx; + + rc = llapi_get_lum_file(optarg, NULL, &stx, + NULL, 0); + if (rc || !(stx.stx_mask & STATX_BTIME)) { + if (!(stx.stx_mask & STATX_BTIME)) + ret = -EOPNOTSUPP; + else + ret = -errno; + fprintf(stderr, + "%s: get btime failed '%s': %s\n", + progname, optarg, + strerror(-ret)); + goto err; + } + + ref = stx.stx_btime.tv_sec; } else { struct stat statbuf; @@ -4544,6 +5340,10 @@ static int lfs_find(int argc, char **argv) case 'c': xidx = NEWERXY_CTIME; break; + case 'b': + case 'B': + xidx = NEWERXY_BTIME; + break; default: fprintf(stderr, "%s: invalid X argument: '%c'\n", @@ -4570,26 +5370,27 @@ static int lfs_find(int argc, char **argv) case 'G': rc = name2gid(¶m.fp_gid, optarg); if (rc) { - param.fp_gid = strtoul(optarg, &endptr, 10); - if (*endptr != '\0') { - fprintf(stderr, "Group/GID: %s cannot " - "be found.\n", optarg); - ret = -1; - goto err; - } - } + if (str2quotaid(¶m.fp_gid, optarg)) { + fprintf(stderr, + "Group/GID: %s cannot be found.\n", + optarg); + ret = -1; + goto err; + } + } param.fp_exclude_gid = !!neg_opt; param.fp_check_gid = 1; - break; + break; case 'H': - param.fp_hash_type = check_hashtype(optarg); - if (param.fp_hash_type == 0) { - fprintf(stderr, "error: bad hash_type '%s'\n", - optarg); + rc = mdthash_input(optarg, ¶m.fp_hash_inflags, + ¶m.fp_hash_exflags, + ¶m.fp_hash_type); + if (rc) { ret = -1; goto err; } - param.fp_check_hash_type = 1; + if (param.fp_hash_inflags || param.fp_hash_exflags) + param.fp_check_hash_flag = 1; param.fp_exclude_hash_type = !!neg_opt; break; case 'l': @@ -4606,21 +5407,21 @@ static int lfs_find(int argc, char **argv) case 'U': rc = name2uid(¶m.fp_uid, optarg); if (rc) { - param.fp_uid = strtoul(optarg, &endptr, 10); - if (*endptr != '\0') { - fprintf(stderr, "User/UID: %s cannot " - "be found.\n", optarg); - ret = -1; - goto err; - } - } + if (str2quotaid(¶m.fp_uid, optarg)) { + fprintf(stderr, + "User/UID: %s cannot be found.\n", + optarg); + ret = -1; + goto err; + } + } param.fp_exclude_uid = !!neg_opt; param.fp_check_uid = 1; - break; - case 'n': + break; + case 'n': param.fp_pattern = (char *)optarg; param.fp_exclude_pattern = !!neg_opt; - break; + break; case 'N': if (optarg[0] == '+') { param.fp_mirror_count_sign = -1; @@ -4630,8 +5431,10 @@ static int lfs_find(int argc, char **argv) optarg++; } + errno = 0; param.fp_mirror_count = strtoul(optarg, &endptr, 0); - if (*endptr != '\0') { + if (errno != 0 || *endptr != '\0' || + param.fp_mirror_count > LUSTRE_MIRROR_COUNT_MAX) { fprintf(stderr, "error: bad mirror count '%s'\n", optarg); @@ -4640,56 +5443,57 @@ static int lfs_find(int argc, char **argv) param.fp_check_mirror_count = 1; param.fp_exclude_mirror_count = !!neg_opt; break; - case 'm': - case 'i': - case 'O': { - char *buf, *token, *next, *p; - int len = 1; - void *tmp; - - buf = strdup(optarg); - if (buf == NULL) { - ret = -ENOMEM; - goto err; - } + case 'm': + case 'i': + case 'O': { + char *buf, *token, *next, *p; + int len = 1; + void *tmp; + + buf = strdup(optarg); + if (!buf) { + ret = -ENOMEM; + goto err; + } param.fp_exclude_obd = !!neg_opt; - token = buf; - while (token && *token) { - token = strchr(token, ','); - if (token) { - len++; - token++; - } - } - if (c == 'm') { + token = buf; + while (token && *token) { + token = strchr(token, ','); + if (token) { + len++; + token++; + } + } + if (c == 'm') { param.fp_exclude_mdt = !!neg_opt; param.fp_num_alloc_mdts += len; tmp = realloc(param.fp_mdt_uuid, param.fp_num_alloc_mdts * sizeof(*param.fp_mdt_uuid)); - if (tmp == NULL) { + if (!tmp) { ret = -ENOMEM; goto err_free; } param.fp_mdt_uuid = tmp; - } else { + } else { param.fp_exclude_obd = !!neg_opt; param.fp_num_alloc_obds += len; tmp = realloc(param.fp_obd_uuid, param.fp_num_alloc_obds * sizeof(*param.fp_obd_uuid)); - if (tmp == NULL) { + if (!tmp) { ret = -ENOMEM; goto err_free; } param.fp_obd_uuid = tmp; - } - for (token = buf; token && *token; token = next) { + } + for (token = buf; token && *token; token = next) { struct obd_uuid *puuid; + if (c == 'm') { puuid = ¶m.fp_mdt_uuid[param.fp_num_mdts++]; @@ -4697,12 +5501,12 @@ static int lfs_find(int argc, char **argv) puuid = ¶m.fp_obd_uuid[param.fp_num_obds++]; } - p = strchr(token, ','); - next = 0; - if (p) { - *p = 0; - next = p+1; - } + p = strchr(token, ','); + next = 0; + if (p) { + *p = 0; + next = p+1; + } if (strlen(token) > sizeof(puuid->uuid) - 1) { ret = -E2BIG; @@ -4747,13 +5551,15 @@ err_free: break; case 'P': /* we always print, this option is a no-op */ break; + case LFS_PRINTF_OPT: + param.fp_format_printf_str = optarg; + break; case LFS_PROJID_OPT: rc = name2projid(¶m.fp_projid, optarg); if (rc) { - param.fp_projid = strtoul(optarg, &endptr, 10); - if (*endptr != '\0') { + if (str2quotaid(¶m.fp_projid, optarg)) { fprintf(stderr, - "Invalid project ID: %s", + "Invalid project ID: %s\n", optarg); ret = -1; goto err; @@ -4792,6 +5598,9 @@ err_free: ret = llapi_parse_size(optarg, ¶m.fp_stripe_size, ¶m.fp_stripe_size_units, 0); + /* assume units of KB if too small to be valid */ + if (param.fp_stripe_size < 4096) + param.fp_stripe_size *= 1024; if (ret) { fprintf(stderr, "error: bad stripe_size '%s'\n", optarg); @@ -4825,29 +5634,49 @@ err_free: param.fp_type = S_IFSOCK; break; default: - fprintf(stderr, "error: %s: bad type '%s'\n", - argv[0], optarg); + fprintf(stderr, "%s: bad type '%s'\n", + progname, optarg); ret = CMD_HELP; goto err; - }; + } break; - case 'T': - if (optarg[0] == '+') { - param.fp_mdt_count_sign = -1; + case LFS_FIND_PERM: + param.fp_exclude_perm = !!neg_opt; + param.fp_perm_sign = LFS_FIND_PERM_EXACT; + if (*optarg == '/') { + param.fp_perm_sign = LFS_FIND_PERM_ANY; optarg++; - } else if (optarg[0] == '-') { - param.fp_mdt_count_sign = 1; + } else if (*optarg == '-') { + param.fp_perm_sign = LFS_FIND_PERM_ALL; optarg++; } - param.fp_mdt_count = strtoul(optarg, &endptr, 0); - if (*endptr != '\0') { - fprintf(stderr, "error: bad mdt_count '%s'\n", + if (str2mode_t(optarg, ¶m.fp_perm)) { + fprintf(stderr, "error: invalid mode '%s'\n", optarg); ret = -1; goto err; } - param.fp_check_mdt_count = 1; + break; + case 'T': + if (optarg[0] == '+') { + param.fp_mdt_count_sign = -1; + optarg++; + } else if (optarg[0] == '-') { + param.fp_mdt_count_sign = 1; + optarg++; + } + + errno = 0; + param.fp_mdt_count = strtoul(optarg, &endptr, 0); + if (errno != 0 || *endptr != '\0' || + param.fp_mdt_count >= UINT32_MAX) { + fprintf(stderr, "error: bad mdt_count '%s'\n", + optarg); + ret = -1; + goto err; + } + param.fp_check_mdt_count = 1; param.fp_exclude_mdt_count = !!neg_opt; break; case 'z': @@ -4872,10 +5701,15 @@ err_free: param.fp_exclude_ext_size = !!neg_opt; break; default: + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + case 'h': ret = CMD_HELP; goto err; - }; + } } + if (!param.fp_verbose) + param.fp_verbose = VERBOSE_DEFAULT; if (pathstart == -1) { fprintf(stderr, "error: %s: no filename|pathname\n", @@ -4906,7 +5740,7 @@ err: if (param.fp_mdt_uuid && param.fp_num_alloc_mdts) free(param.fp_mdt_uuid); - return ret; + return ret; } static int lfs_getstripe_internal(int argc, char **argv, @@ -4915,6 +5749,8 @@ static int lfs_getstripe_internal(int argc, char **argv, struct option long_opts[] = { /* find { .val = 'A', .name = "atime", .has_arg = required_argument }*/ /* find { .val = 'b', .name = "blocks", .has_arg = required_argument }*/ +/* find { .val = 'B', .name = "btime", .has_arg = required_argument }*/ +/* find { .val = 'B', .name = "Btime", .has_arg = required_argument }*/ { .val = LFS_COMP_COUNT_OPT, .name = "comp-count", .has_arg = no_argument }, { .val = LFS_COMP_COUNT_OPT, @@ -4941,6 +5777,7 @@ static int lfs_getstripe_internal(int argc, char **argv, { .val = 'F', .name = "fid", .has_arg = no_argument }, { .val = 'g', .name = "generation", .has_arg = no_argument }, /* find { .val = 'G', .name = "group", .has_arg = required_argument }*/ + { .val = 'h', .name = "help", .has_arg = no_argument }, /* dirstripe { .val = 'H', .name = "mdt-hash", .has_arg = required_argument }*/ { .val = 'i', .name = "stripe-index", .has_arg = no_argument }, { .val = 'i', .name = "stripe_index", .has_arg = no_argument }, @@ -4968,6 +5805,7 @@ static int lfs_getstripe_internal(int argc, char **argv, /* find { .val = 'u', .name = "uid", .has_arg = required_argument }*/ /* find { .val = 'U', .name = "user", .has_arg = required_argument }*/ { .val = 'v', .name = "verbose", .has_arg = no_argument }, +/* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/ { .val = 'y', .name = "yaml", .has_arg = no_argument }, { .val = 'z', .name = "extension-size", .has_arg = no_argument }, { .val = 'z', .name = "ext-size", .has_arg = no_argument }, @@ -5014,13 +5852,13 @@ static int lfs_getstripe_internal(int argc, char **argv, param->fp_max_depth = 0; break; case LFS_COMP_FLAGS_OPT: - if (optarg != NULL) { + if (optarg) { rc = comp_str2flags(optarg, ¶m->fp_comp_flags, ¶m->fp_comp_neg_flags); if (rc != 0) { - fprintf(stderr, "error: %s bad " - "component flags '%s'.\n", + fprintf(stderr, + "error: %s bad component flags '%s'.\n", argv[0], optarg); return CMD_HELP; } @@ -5031,7 +5869,7 @@ static int lfs_getstripe_internal(int argc, char **argv, } break; case LFS_COMP_START_OPT: - if (optarg != NULL) { + if (optarg) { tmp = optarg; if (tmp[0] == '+') { param->fp_comp_start_sign = -1; @@ -5044,19 +5882,20 @@ static int lfs_getstripe_internal(int argc, char **argv, ¶m->fp_comp_start, ¶m->fp_comp_start_units, 0); if (rc != 0) { - fprintf(stderr, "error: %s bad " - "component start '%s'.\n", + fprintf(stderr, + "error: %s bad component start '%s'.\n", argv[0], tmp); return CMD_HELP; - } else { - param->fp_check_comp_start = 1; } + param->fp_check_comp_start = 1; } else { param->fp_verbose |= VERBOSE_COMP_START; param->fp_max_depth = 0; } break; - case LFS_MIRROR_INDEX_OPT: + case LFS_MIRROR_INDEX_OPT: { + unsigned long int mirror_index; + if (optarg[0] == '+') { param->fp_mirror_index_sign = -1; optarg++; @@ -5065,14 +5904,19 @@ static int lfs_getstripe_internal(int argc, char **argv, optarg++; } - param->fp_mirror_index = strtoul(optarg, &end, 0); - if (*end != '\0' || (param->fp_mirror_index == 0 && + errno = 0; + mirror_index = strtoul(optarg, &end, 0); + if (errno != 0 || *end != '\0' || + mirror_index > UINT16_MAX || (mirror_index == 0 && param->fp_mirror_index_sign == 0 && neg_opt == 0)) { fprintf(stderr, "%s %s: invalid mirror index '%s'\n", progname, argv[0], optarg); return CMD_HELP; } + + param->fp_mirror_index = (__u16)mirror_index; + if (param->fp_mirror_id != 0) { fprintf(stderr, "%s %s: can't specify both mirror index and mirror ID\n", @@ -5082,7 +5926,10 @@ static int lfs_getstripe_internal(int argc, char **argv, param->fp_check_mirror_index = 1; param->fp_exclude_mirror_index = !!neg_opt; break; - case LFS_MIRROR_ID_OPT: + } + case LFS_MIRROR_ID_OPT: { + unsigned long int mirror_id; + if (optarg[0] == '+') { param->fp_mirror_id_sign = -1; optarg++; @@ -5091,14 +5938,19 @@ static int lfs_getstripe_internal(int argc, char **argv, optarg++; } - param->fp_mirror_id = strtoul(optarg, &end, 0); - if (*end != '\0' || (param->fp_mirror_id == 0 && + errno = 0; + mirror_id = strtoul(optarg, &end, 0); + if (errno != 0 || *end != '\0' || + mirror_id > UINT16_MAX || (mirror_id == 0 && param->fp_mirror_id_sign == 0 && neg_opt == 0)) { fprintf(stderr, "%s %s: invalid mirror ID '%s'\n", progname, argv[0], optarg); return CMD_HELP; } + + param->fp_mirror_id = (__u16)mirror_id; + if (param->fp_mirror_index != 0) { fprintf(stderr, "%s %s: can't specify both mirror index and mirror ID\n", @@ -5108,6 +5960,7 @@ static int lfs_getstripe_internal(int argc, char **argv, param->fp_check_mirror_id = 1; param->fp_exclude_mirror_id = !!neg_opt; break; + } case 'd': param->fp_max_depth = 0; break; @@ -5115,7 +5968,7 @@ static int lfs_getstripe_internal(int argc, char **argv, param->fp_get_default_lmv = 1; break; case 'E': - if (optarg != NULL) { + if (optarg) { tmp = optarg; if (tmp[0] == '+') { param->fp_comp_end_sign = -1; @@ -5133,10 +5986,13 @@ static int lfs_getstripe_internal(int argc, char **argv, rc = llapi_parse_size(tmp, ¶m->fp_comp_end, ¶m->fp_comp_end_units, 0); + /* assume units of KB if too small */ + if (param->fp_comp_end < 4096) + param->fp_comp_end *= 1024; } if (rc != 0) { - fprintf(stderr, "error: %s bad " - "component end '%s'.\n", + fprintf(stderr, + "error: %s bad component end '%s'.\n", argv[0], tmp); return CMD_HELP; } @@ -5165,17 +6021,16 @@ static int lfs_getstripe_internal(int argc, char **argv, } break; case 'I': - if (optarg != NULL) { + if (optarg) { param->fp_comp_id = strtoul(optarg, &end, 0); if (*end != '\0' || param->fp_comp_id == 0 || param->fp_comp_id > LCME_ID_MAX) { - fprintf(stderr, "error: %s bad " - "component id '%s'\n", + fprintf(stderr, + "error: %s bad component id '%s'\n", argv[0], optarg); return CMD_HELP; - } else { - param->fp_check_comp_id = 1; } + param->fp_check_comp_id = 1; } else { param->fp_max_depth = 0; param->fp_verbose |= VERBOSE_COMP_ID; @@ -5189,8 +6044,8 @@ static int lfs_getstripe_internal(int argc, char **argv, break; #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0) case 'M': - fprintf(stderr, "warning: '-M' deprecated" - ", use '--mdt-index' or '-m' instead\n"); + fprintf(stderr, + "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n"); #endif case 'm': if (!(param->fp_verbose & VERBOSE_DETAIL)) @@ -5246,6 +6101,9 @@ static int lfs_getstripe_internal(int argc, char **argv, } break; default: + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + case 'h': return CMD_HELP; } } @@ -5284,40 +6142,40 @@ static int lfs_getstripe_internal(int argc, char **argv, static int lfs_tgts(int argc, char **argv) { - char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'}; - struct find_param param; - int index = 0, rc=0; + char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'}; + struct find_param param; + int index = 0, rc = 0; - if (argc > 2) - return CMD_HELP; + if (argc > 2) + return CMD_HELP; - if (argc == 2 && !realpath(argv[1], path)) { - rc = -errno; - fprintf(stderr, "error: invalid path '%s': %s\n", - argv[1], strerror(-rc)); - return rc; - } + if (argc == 2 && !realpath(argv[1], path)) { + rc = -errno; + fprintf(stderr, "error: invalid path '%s': %s\n", + argv[1], strerror(-rc)); + return rc; + } - while (!llapi_search_mounts(path, index++, mntdir, NULL)) { - /* Check if we have a mount point */ - if (mntdir[0] == '\0') - continue; + while (!llapi_search_mounts(path, index++, mntdir, NULL)) { + /* Check if we have a mount point */ + if (mntdir[0] == '\0') + continue; - memset(¶m, 0, sizeof(param)); - if (!strcmp(argv[0], "mdts")) + memset(¶m, 0, sizeof(param)); + if (!strcmp(argv[0], "mdts")) param.fp_get_lmv = 1; - rc = llapi_ostlist(mntdir, ¶m); - if (rc) { - fprintf(stderr, "error: %s: failed on %s\n", - argv[0], mntdir); - } - if (path[0] != '\0') - break; - memset(mntdir, 0, PATH_MAX); - } + rc = llapi_ostlist(mntdir, ¶m); + if (rc) { + fprintf(stderr, "error: %s: failed on %s\n", + argv[0], mntdir); + } + if (path[0] != '\0') + break; + memset(mntdir, 0, PATH_MAX); + } - return rc; + return rc; } static int lfs_getstripe(int argc, char **argv) @@ -5333,24 +6191,27 @@ static int lfs_getdirstripe(int argc, char **argv) { struct find_param param = { 0 }; struct option long_opts[] = { - { .val = 'c', .name = "mdt-count", .has_arg = no_argument }, - { .val = 'D', .name = "default", .has_arg = no_argument }, - { .val = 'H', .name = "mdt-hash", .has_arg = no_argument }, - { .val = 'i', .name = "mdt-index", .has_arg = no_argument }, - { .val = 'm', .name = "mdt-index", .has_arg = no_argument }, - { .val = 'O', .name = "obd", .has_arg = required_argument }, - { .val = 'r', .name = "recursive", .has_arg = no_argument }, - { .val = 'T', .name = "mdt-count", .has_arg = no_argument }, - { .val = 'v', .name = "verbose", .has_arg = no_argument }, - { .val = 'y', .name = "yaml", .has_arg = no_argument }, + { .val = 'c', .name = "mdt-count", .has_arg = no_argument }, + { .val = 'D', .name = "default", .has_arg = no_argument }, + { .val = 'h', .name = "help", .has_arg = no_argument }, + { .val = 'H', .name = "mdt-hash", .has_arg = no_argument }, + { .val = 'i', .name = "mdt-index", .has_arg = no_argument }, + { .val = 'm', .name = "mdt-index", .has_arg = no_argument }, + { .val = 'O', .name = "obd", .has_arg = required_argument }, + { .val = 'r', .name = "recursive", .has_arg = no_argument }, + { .val = 'T', .name = "mdt-count", .has_arg = no_argument }, + { .val = 'v', .name = "verbose", .has_arg = no_argument }, + { .val = 'X', .name = "max-inherit", .has_arg = no_argument }, + { .val = 'y', .name = "yaml", .has_arg = no_argument }, + { .val = LFS_INHERIT_RR_OPT, + .name = "max-inherit-rr", .has_arg = no_argument }, { .name = NULL } }; int c, rc; param.fp_get_lmv = 1; while ((c = getopt_long(argc, argv, - "cDHimO:rtTvy", long_opts, NULL)) != -1) - { + "cDhHimO:rtTvXy", long_opts, NULL)) != -1) { switch (c) { case 'c': case 'T': @@ -5359,23 +6220,25 @@ static int lfs_getdirstripe(int argc, char **argv) case 'D': param.fp_get_default_lmv = 1; break; - case 'i': - case 'm': - param.fp_verbose |= VERBOSE_STRIPE_OFFSET; - break; #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0) case 't': - fprintf(stderr, "warning: '-t' deprecated, " - "use '--mdt-hash' or '-H' instead\n"); + fprintf(stderr, + "warning: '-t' deprecated, use '--mdt-hash' or '-H' instead\n"); + fallthrough; #endif case 'H': param.fp_verbose |= VERBOSE_HASH_TYPE; break; + case 'i': + fallthrough; + case 'm': + param.fp_verbose |= VERBOSE_STRIPE_OFFSET; + break; case 'O': if (param.fp_obd_uuid) { fprintf(stderr, - "error: %s: only one obduuid allowed", - argv[0]); + "%s: only one obduuid allowed", + progname); return CMD_HELP; } param.fp_obd_uuid = (struct obd_uuid *)optarg; @@ -5386,12 +6249,20 @@ static int lfs_getdirstripe(int argc, char **argv) case 'v': param.fp_verbose |= VERBOSE_DETAIL; break; + case 'X': + param.fp_verbose |= VERBOSE_INHERIT; + break; + case LFS_INHERIT_RR_OPT: + param.fp_verbose |= VERBOSE_INHERIT_RR; + break; case 'y': param.fp_yaml = 1; break; default: - fprintf(stderr, "%s %s: unrecognized option '%s'\n", - progname, argv[0], argv[optind - 1]); + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + fallthrough; + case 'h': return CMD_HELP; } } @@ -5421,13 +6292,14 @@ enum mntdf_flags { MNTDF_LAZY = 0x0004, MNTDF_VERBOSE = 0x0008, MNTDF_SHOW = 0x0010, + MNTDF_DECIMAL = 0x0020, }; -#define COOK(value) \ +#define COOK(value, base) \ ({ \ int radix = 0; \ - while (value > 1024) { \ - value /= 1024; \ + while (value > base) { \ + value /= base; \ radix++; \ } \ radix; \ @@ -5457,7 +6329,8 @@ static inline int obd_statfs_ratio(const struct obd_statfs *st, bool inodes) return (ratio - (int)ratio) > 0 ? (int)(ratio + 1) : (int)ratio; } -/* This is to identify various problem states for "lfs df" if .osn_err = true, +/* + * This is to identify various problem states for "lfs df" if .osn_err = true, * so only show flags reflecting those states by default. Informational states * are only shown with "-v" and use lower-case names to distinguish them. * UNUSED[12] were for "EROFS = 30" until 1.6 but are now available for use. @@ -5467,15 +6340,15 @@ static struct obd_statfs_state_names { const char osn_name; bool osn_err; } oss_names[] = { - { .osn_state = OS_STATE_DEGRADED, .osn_name = 'D', .osn_err = true }, - { .osn_state = OS_STATE_READONLY, .osn_name = 'R', .osn_err = true }, - { .osn_state = OS_STATE_NOPRECREATE, .osn_name = 'N', .osn_err = true }, - { .osn_state = OS_STATE_UNUSED1, .osn_name = '?', .osn_err = true }, - { .osn_state = OS_STATE_UNUSED2, .osn_name = '?', .osn_err = true }, - { .osn_state = OS_STATE_ENOSPC, .osn_name = 'S', .osn_err = true }, - { .osn_state = OS_STATE_ENOINO, .osn_name = 'I', .osn_err = true }, - { .osn_state = OS_STATE_SUM, .osn_name = 'a', /* aggregate */ }, - { .osn_state = OS_STATE_NONROT, .osn_name = 'f', /* flash */ }, + { .osn_state = OS_STATFS_DEGRADED, .osn_name = 'D', .osn_err = true }, + { .osn_state = OS_STATFS_READONLY, .osn_name = 'R', .osn_err = true }, + { .osn_state = OS_STATFS_NOPRECREATE,.osn_name = 'N', .osn_err = true }, + { .osn_state = OS_STATFS_UNUSED1, .osn_name = '?', .osn_err = true }, + { .osn_state = OS_STATFS_UNUSED2, .osn_name = '?', .osn_err = true }, + { .osn_state = OS_STATFS_ENOSPC, .osn_name = 'S', .osn_err = true }, + { .osn_state = OS_STATFS_ENOINO, .osn_name = 'I', .osn_err = true }, + { .osn_state = OS_STATFS_SUM, .osn_name = 'a', /* aggregate */ }, + { .osn_state = OS_STATFS_NONROT, .osn_name = 'f', /* flash */ }, }; static int showdf(char *mntdir, struct obd_statfs *stat, @@ -5484,7 +6357,7 @@ static int showdf(char *mntdir, struct obd_statfs *stat, { long long avail, used, total; int ratio = 0; - char *suffix = "KMGTPEZY"; + char *suffix = flags & MNTDF_DECIMAL ? "kMGTPEZY" : "KMGTPEZY"; /* Note if we have >2^64 bytes/fs these buffers will need to be grown */ char tbuf[3 * sizeof(__u64)]; char ubuf[3 * sizeof(__u64)]; @@ -5512,11 +6385,12 @@ static int showdf(char *mntdir, struct obd_statfs *stat, ratio = obd_statfs_ratio(stat, flags & MNTDF_INODES); if (flags & MNTDF_COOKED) { - int i; + int base = flags & MNTDF_DECIMAL ? 1000 : 1024; double cook_val; + int i; cook_val = (double)total; - i = COOK(cook_val); + i = COOK(cook_val, base); if (i > 0) snprintf(tbuf, sizeof(tbuf), HDF, cook_val, suffix[i - 1]); @@ -5524,7 +6398,7 @@ static int showdf(char *mntdir, struct obd_statfs *stat, snprintf(tbuf, sizeof(tbuf), CDF, total); cook_val = (double)used; - i = COOK(cook_val); + i = COOK(cook_val, base); if (i > 0) snprintf(ubuf, sizeof(ubuf), HDF, cook_val, suffix[i - 1]); @@ -5532,7 +6406,7 @@ static int showdf(char *mntdir, struct obd_statfs *stat, snprintf(ubuf, sizeof(ubuf), CDF, used); cook_val = (double)avail; - i = COOK(cook_val); + i = COOK(cook_val, base); if (i > 0) snprintf(abuf, sizeof(abuf), HDF, cook_val, suffix[i - 1]); @@ -5613,7 +6487,7 @@ static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags, if (pool) { poolname = strchr(pool, '.'); - if (poolname != NULL) { + if (poolname) { if (strncmp(fsname, pool, strlen(fsname))) { fprintf(stderr, "filesystem name incorrect\n"); return -ENODEV; @@ -5649,13 +6523,14 @@ static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags, if (!(tp->st_op & ops)) continue; - for (index = 0; ; index++) { + for (index = 0; index < LOV_ALL_STRIPES && + (!lsb || lsb->sb_count < LL_STATFS_MAX); index++) { memset(&stat_buf, 0, sizeof(struct obd_statfs)); memset(&uuid_buf, 0, sizeof(struct obd_uuid)); type = flags & MNTDF_LAZY ? tp->st_op | LL_STATFS_NODELAY : tp->st_op; rc2 = llapi_obd_fstatfs(fd, type, index, - &stat_buf, &uuid_buf); + &stat_buf, &uuid_buf); if (rc2 == -ENODEV) break; if (rc2 == -EAGAIN) @@ -5667,7 +6542,8 @@ static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags, rc = rc2; } - /* If we have OSTs then don't report MDT block counts. + /* + * If we have OSTs then don't report MDT block counts. * For MDT-only filesystems the expectation is that all * layouts have a DoM component. For filesystems with * OSTs, files are not necessarily going to store data @@ -5686,11 +6562,13 @@ static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags, obd_uuid2str(&uuid_buf)) != 1) continue; - /* the llapi_obd_statfs() call may have returned with + /* + * the llapi_obd_fstatfs() call may have returned with * an error, but if it filled in uuid_buf we will at * lease use that to print out a message for that OBD. * If we didn't get anything in the uuid_buf, then fill - * it in so that we can print an error message. */ + * it in so that we can print an error message. + */ if (uuid_buf.uuid[0] == '\0') snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid), "%s%04x", tp->st_name, index); @@ -5725,7 +6603,8 @@ static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags, close(fd); - /* If we have _some_ OSTs, but don't have as many free objects on the + /* + * If we have _some_ OSTs, but don't have as many free objects on the * OST as inodes on the MDTs, reduce the reported number of inodes * to compensate, so that the "inodes in use" number is correct. * This should be kept in sync with ll_statfs_internal(). @@ -5743,6 +6622,10 @@ static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags, return rc; } +enum { + LAYOUT_INHERIT_UNSET = -2, +}; + /* functions */ static int lfs_setdirstripe(int argc, char **argv) { @@ -5759,7 +6642,9 @@ static int lfs_setdirstripe(int argc, char **argv) mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; mode_t previous_mode = 0; char *xattr = NULL; - __u32 type = LU_FOREIGN_TYPE_DAOS, flags = 0; + __u32 type = LU_FOREIGN_TYPE_SYMLINK, flags = 0; + int max_inherit = LAYOUT_INHERIT_UNSET; + int max_inherit_rr = LAYOUT_INHERIT_UNSET; struct option long_opts[] = { { .val = 'c', .name = "count", .has_arg = required_argument }, { .val = 'c', .name = "mdt-count", .has_arg = required_argument }, @@ -5770,6 +6655,7 @@ static int lfs_setdirstripe(int argc, char **argv) .name = "flags", .has_arg = required_argument }, { .val = LFS_LAYOUT_FOREIGN_OPT, .name = "foreign", .has_arg = optional_argument}, + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'H', .name = "mdt-hash", .has_arg = required_argument }, #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 17, 53, 0) { .val = 'i', .name = "mdt-index", .has_arg = required_argument }, @@ -5787,14 +6673,17 @@ static int lfs_setdirstripe(int argc, char **argv) { .val = 't', .name = "hash-type", .has_arg = required_argument }, #endif { .val = 'T', .name = "mdt-count", .has_arg = required_argument }, -/* setstripe { .val = 'y', .name = "yaml", .has_arg = no_argument }, */ { .val = 'x', .name = "xattr", .has_arg = required_argument }, + { .val = 'X', .name = "max-inherit", .has_arg = required_argument }, + { .val = LFS_INHERIT_RR_OPT, + .name = "max-inherit-rr", .has_arg = required_argument}, +/* setstripe { .val = 'y', .name = "yaml", .has_arg = no_argument }, */ { .name = NULL } }; int result = 0; setstripe_args_init(&lsa); - while ((c = getopt_long(argc, argv, "c:dDi:H:m:o:t:T:x:", + while ((c = getopt_long(argc, argv, "c:dDi:hH:m:o:t:T:x:X:", long_opts, NULL)) >= 0) { switch (c) { case 0: @@ -5802,11 +6691,14 @@ static int lfs_setdirstripe(int argc, char **argv) break; case 'c': case 'T': + errno = 0; lsa.lsa_stripe_count = strtoul(optarg, &end, 0); - if (*end != '\0') { + if (errno != 0 || *end != '\0' || + lsa.lsa_stripe_count < -1 || + lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) { fprintf(stderr, - "%s %s: invalid stripe count '%s'\n", - progname, argv[0], optarg); + "%s: invalid stripe count '%s'\n", + progname, optarg); return CMD_HELP; } break; @@ -5818,7 +6710,7 @@ static int lfs_setdirstripe(int argc, char **argv) default_stripe = true; break; case LFS_LAYOUT_FOREIGN_OPT: - if (optarg != NULL) { + if (optarg) { /* check pure numeric */ type = strtoul(optarg, &end, 0); if (*end) { @@ -5831,29 +6723,43 @@ static int lfs_setdirstripe(int argc, char **argv) optarg); return CMD_HELP; } + } else if (type >= UINT32_MAX) { + fprintf(stderr, + "%s %s: invalid foreign type '%s'\n", + progname, argv[0], optarg); + return CMD_HELP; } } foreign_mode = true; break; case LFS_LAYOUT_FLAGS_OPT: + errno = 0; flags = strtoul(optarg, &end, 16); - if (*end != '\0') { + if (errno != 0 || *end != '\0' || + flags >= UINT32_MAX) { fprintf(stderr, - "%s %s: bad flags '%s'\n", + "%s %s: invalid hex flags '%s'\n", progname, argv[0], optarg); return CMD_HELP; } + if (!foreign_mode) { + fprintf(stderr, + "%s %s: hex flags must be specified with --foreign option\n", + progname, argv[0]); + return CMD_HELP; + } break; #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0) case 't': - fprintf(stderr, "warning: '--hash-type' and '-t' " - "deprecated, use '--mdt-hash' or '-H' instead\n"); + fprintf(stderr, + "warning: '--hash-type' and '-t' deprecated, use '--mdt-hash' or '-H' instead\n"); + fallthrough; #endif case 'H': lsa.lsa_pattern = check_hashtype(optarg); if (lsa.lsa_pattern == 0) { fprintf(stderr, - "%s %s: bad stripe hash type '%s'\n", + "%s %s: bad directory hash type '%s'\n", progname, argv[0], optarg); return CMD_HELP; } @@ -5884,8 +6790,8 @@ static int lfs_setdirstripe(int argc, char **argv) break; #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 15, 53, 0) case 'm': - fprintf(stderr, "warning: '-m' is deprecated, " - "use '--mode' or '-o' instead\n"); + fprintf(stderr, + "warning: '-m' is deprecated, use '--mode' or '-o' instead\n"); #endif case 'o': mode_opt = optarg; @@ -5893,9 +6799,59 @@ static int lfs_setdirstripe(int argc, char **argv) case 'x': xattr = optarg; break; + case 'X': + errno = 0; + max_inherit = strtol(optarg, &end, 10); + if (errno != 0 || *end != '\0' || max_inherit < -2) { + fprintf(stderr, + "%s %s: invalid max-inherit '%s'\n", + progname, argv[0], optarg); + return CMD_HELP; + } + if (max_inherit == 0) { + max_inherit = LMV_INHERIT_NONE; + } else if (max_inherit == -1) { + max_inherit = LMV_INHERIT_UNLIMITED; + } else if (max_inherit > LMV_INHERIT_MAX) { + fprintf(stderr, + "%s %s: max-inherit %d exceeds maximum %u\n", + progname, argv[0], max_inherit, + LMV_INHERIT_MAX); + return CMD_HELP; + } + break; + case LFS_INHERIT_RR_OPT: + if (!default_stripe) { + fprintf(stderr, + "%s %s: '--max-inherit-rr' must be specified with '-D'\n", + progname, argv[0]); + return CMD_HELP; + } + errno = 0; + max_inherit_rr = strtol(optarg, &end, 10); + if (errno != 0 || *end != '\0' || max_inherit_rr < -2) { + fprintf(stderr, + "%s %s: invalid max-inherit-rr '%s'\n", + progname, argv[0], optarg); + return CMD_HELP; + } + if (max_inherit_rr == 0) { + max_inherit_rr = LMV_INHERIT_RR_NONE; + } else if (max_inherit_rr == -1) { + max_inherit_rr = LMV_INHERIT_RR_UNLIMITED; + } else if (max_inherit_rr > LMV_INHERIT_RR_MAX) { + fprintf(stderr, + "%s %s: max-inherit-rr %d exceeds maximum %u\n", + progname, argv[0], max_inherit_rr, + LMV_INHERIT_RR_MAX); + return CMD_HELP; + } + break; default: - fprintf(stderr, "%s %s: unrecognized option '%s'\n", - progname, argv[0], argv[optind - 1]); + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + fallthrough; + case 'h': return CMD_HELP; } } @@ -5907,7 +6863,8 @@ static int lfs_setdirstripe(int argc, char **argv) } if (xattr && !foreign_mode) { - /* only print a warning as this is armless and will be + /* + * only print a warning as this is armless and will be * ignored */ fprintf(stderr, @@ -5930,10 +6887,9 @@ static int lfs_setdirstripe(int argc, char **argv) if (!delete && lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT && lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT && !foreign_mode) { - fprintf(stderr, - "%s %s: stripe offset and count must be specified\n", - progname, argv[0]); - return CMD_HELP; + /* if no parameters set, create directory on least-used MDTs */ + lsa.lsa_stripe_off = LMV_OFFSET_DEFAULT; + lsa.lsa_stripe_count = 1; } if (delete && @@ -5945,7 +6901,7 @@ static int lfs_setdirstripe(int argc, char **argv) return CMD_HELP; } - if (mode_opt != NULL) { + if (mode_opt) { mode = strtoul(mode_opt, &end, 8); if (*end != '\0') { fprintf(stderr, @@ -5956,6 +6912,30 @@ static int lfs_setdirstripe(int argc, char **argv) previous_mode = umask(0); } + /* check max-inherit and warn user in some cases */ + if (default_stripe && + (lsa.lsa_stripe_count < 0 || lsa.lsa_stripe_count > 1)) { + if (max_inherit == LMV_INHERIT_UNLIMITED) + fprintf(stderr, + "%s %s: unrecommended max-inherit=-1 when default stripe-count=%lld\n", + progname, argv[0], lsa.lsa_stripe_count); + else if (max_inherit > LMV_INHERIT_DEFAULT_STRIPED + 2 && + max_inherit != LMV_INHERIT_NONE) + fprintf(stderr, + "%s %s: unrecommended max-inherit=%d when default stripe-count=%lld\n", + progname, argv[0], max_inherit, + lsa.lsa_stripe_count); + } + + if (max_inherit_rr != LAYOUT_INHERIT_UNSET && + lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT && + lsa.lsa_stripe_off != LMV_OFFSET_DEFAULT) { + fprintf(stderr, + "%s %s: max-inherit-rr needs mdt-index=-1, not %lld\n", + progname, argv[0], lsa.lsa_stripe_off); + return CMD_HELP; + } + /* foreign LMV/dir case */ if (foreign_mode) { if (argc > optind + 1) { @@ -5982,25 +6962,45 @@ static int lfs_setdirstripe(int argc, char **argv) param = calloc(1, offsetof(typeof(*param), lsp_tgts[lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ? lsa.lsa_stripe_count : lsa.lsa_nr_tgts])); - if (param == NULL) { + if (!param) { fprintf(stderr, "%s %s: cannot allocate memory for parameters: %s\n", progname, argv[0], strerror(ENOMEM)); return CMD_HELP; } + /* if "lfs setdirstripe -D -i -1" is used, assume 1-stripe directory */ + if (default_stripe && lsa.lsa_stripe_off == LMV_OFFSET_DEFAULT && + (lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT || + lsa.lsa_stripe_count == 0)) + lsa.lsa_stripe_count = 1; if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) param->lsp_stripe_count = lsa.lsa_stripe_count; if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT) - param->lsp_stripe_offset = -1; + param->lsp_stripe_offset = LMV_OFFSET_DEFAULT; else param->lsp_stripe_offset = lsa.lsa_stripe_off; if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0) param->lsp_stripe_pattern = lsa.lsa_pattern; else - param->lsp_stripe_pattern = LMV_HASH_TYPE_DEFAULT; + param->lsp_stripe_pattern = LMV_HASH_TYPE_UNKNOWN; param->lsp_pool = lsa.lsa_pool_name; param->lsp_is_specific = false; + if (max_inherit == LAYOUT_INHERIT_UNSET) { + if (lsa.lsa_stripe_count == 0 || lsa.lsa_stripe_count == 1) + max_inherit = LMV_INHERIT_DEFAULT_PLAIN; + else + max_inherit = LMV_INHERIT_DEFAULT_STRIPED; + } + param->lsp_max_inherit = max_inherit; + if (default_stripe) { + + if (max_inherit_rr == LAYOUT_INHERIT_UNSET) + max_inherit_rr = LMV_INHERIT_RR_DEFAULT; + param->lsp_max_inherit_rr = max_inherit_rr; + } + if (strcmp(argv[0], "mkdir") == 0) + param->lsp_is_create = true; if (lsa.lsa_nr_tgts > 1) { if (lsa.lsa_stripe_count > 0 && lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT && @@ -6036,7 +7036,7 @@ static int lfs_setdirstripe(int argc, char **argv) progname, dname, strerror(-result)); } while (!result && (dname = argv[++optind])); - if (mode_opt != NULL) + if (mode_opt) umask(previous_mode); free(param); @@ -6058,11 +7058,12 @@ static int lfs_rmentry(int argc, char **argv) index = 1; dname = argv[index]; - while (dname != NULL) { + while (dname) { result = llapi_direntry_remove(dname); if (result) { - fprintf(stderr, "error: %s: remove dir entry '%s' " - "failed\n", argv[0], dname); + fprintf(stderr, + "error: %s: remove dir entry '%s' failed\n", + argv[0], dname); break; } dname = argv[++index]; @@ -6070,6 +7071,33 @@ static int lfs_rmentry(int argc, char **argv) return result; } +static int lfs_unlink_foreign(int argc, char **argv) +{ + char *name; + int index; + int result = 0; + + if (argc <= 1) { + fprintf(stderr, "error: %s: missing pathname\n", + argv[0]); + return CMD_HELP; + } + + index = 1; + name = argv[index]; + while (name != NULL) { + result = llapi_unlink_foreign(name); + if (result) { + fprintf(stderr, + "error: %s: unlink foreign entry '%s' failed\n", + argv[0], name); + break; + } + name = argv[++index]; + } + return result; +} + static int lfs_mv(int argc, char **argv) { struct lmv_user_md lmu = { LMV_USER_MAGIC }; @@ -6090,12 +7118,14 @@ static int lfs_mv(int argc, char **argv) switch (c) { #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0) case 'M': - fprintf(stderr, "warning: '-M' deprecated" - ", use '--mdt-index' or '-m' instead\n"); + fprintf(stderr, + "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n"); #endif case 'm': + errno = 0; lmu.lum_stripe_offset = strtoul(optarg, &end, 0); - if (*end != '\0') { + if (errno != 0 || *end != '\0' || + lmu.lum_stripe_offset >= UINT32_MAX) { fprintf(stderr, "%s mv: bad MDT index '%s'\n", progname, optarg); return CMD_HELP; @@ -6122,6 +7152,7 @@ static int lfs_mv(int argc, char **argv) return CMD_HELP; } + lmu.lum_hash_type = LMV_HASH_TYPE_UNKNOWN; /* initialize migrate mdt parameters */ param.fp_lmv_md = &lmu; @@ -6129,19 +7160,19 @@ static int lfs_mv(int argc, char **argv) rc = llapi_migrate_mdt(argv[optind], ¶m); if (rc != 0) fprintf(stderr, "%s mv: cannot migrate '%s' to MDT%04x: %s\n", - progname, argv[optind], param.fp_mdt_index, + progname, argv[optind], lmu.lum_stripe_offset, strerror(-rc)); return rc; } static int lfs_osts(int argc, char **argv) { - return lfs_tgts(argc, argv); + return lfs_tgts(argc, argv); } static int lfs_mdts(int argc, char **argv) { - return lfs_tgts(argc, argv); + return lfs_tgts(argc, argv); } static int lfs_df(int argc, char **argv) @@ -6149,21 +7180,24 @@ static int lfs_df(int argc, char **argv) char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'}; enum mntdf_flags flags = MNTDF_SHOW; int ops = LL_STATFS_LMV | LL_STATFS_LOV; - int c, rc = 0, index = 0; + int c, rc = 0, rc1 = 0, index = 0, arg_idx = 0; char fsname[PATH_MAX] = "", *pool_name = NULL; struct option long_opts[] = { - { .val = 'h', .name = "human-readable", - .has_arg = no_argument }, + { .val = 'h', .name = "human-readable", .has_arg = no_argument }, + { .val = 'H', .name = "si", .has_arg = no_argument }, { .val = 'i', .name = "inodes", .has_arg = no_argument }, { .val = 'l', .name = "lazy", .has_arg = no_argument }, { .val = 'p', .name = "pool", .has_arg = required_argument }, { .val = 'v', .name = "verbose", .has_arg = no_argument }, { .name = NULL} }; - while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "hHilp:v", long_opts, NULL)) != -1) { switch (c) { case 'h': - flags |= MNTDF_COOKED; + flags = (flags & ~MNTDF_DECIMAL) | MNTDF_COOKED; + break; + case 'H': + flags |= MNTDF_COOKED | MNTDF_DECIMAL; break; case 'i': flags |= MNTDF_INODES; @@ -6178,29 +7212,80 @@ static int lfs_df(int argc, char **argv) flags |= MNTDF_VERBOSE; break; default: + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); return CMD_HELP; } } - if (optind < argc && !realpath(argv[optind], path)) { - rc = -errno; - fprintf(stderr, "error: invalid path '%s': %s\n", - argv[optind], strerror(-rc)); + + /* Handle case where path is not specified */ + if (optind == argc) { + while (!llapi_search_mounts(path, index++, mntdir, fsname)) { + /* Check if we have a mount point */ + if (mntdir[0] == '\0') + continue; + + rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL); + if (rc || path[0] != '\0') + break; + + fsname[0] = '\0'; /* avoid matching in next loop */ + mntdir[0] = '\0'; /* avoid matching in next loop */ + path[0] = '\0'; /* clean for next loop */ + } return rc; } - while (!llapi_search_mounts(path, index++, mntdir, fsname)) { - /* Check if we have a mount point */ - if (mntdir[0] == '\0') + /* Loop through all the remaining arguments. These are Lustre FS + * paths. + */ + for (arg_idx = optind; arg_idx <= argc - 1; arg_idx++) { + bool valid = false; + + fsname[0] = '\0'; /* start clean */ + mntdir[0] = '\0'; /* start clean */ + path[0] = '\0'; /* start clean */ + + /* path does not exists at all */ + if (!realpath(argv[arg_idx], path)) { + rc = -errno; + fprintf(stderr, "error: invalid path '%s': %s\n", + argv[arg_idx], strerror(-rc)); + /* save first seen error */ + if (!rc1) + rc1 = rc; + continue; + } - rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL); - if (rc || path[0] != '\0') - break; - fsname[0] = '\0'; /* avoid matching in next loop */ - mntdir[0] = '\0'; /* avoid matching in next loop */ + /* path exists but may not be a Lustre filesystem */ + while (!llapi_search_mounts(path, index++, mntdir, fsname)) { + /* Check if we have a mount point */ + if (mntdir[0] == '\0') + continue; + + rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL); + if (rc || path[0] != '\0') { + valid = true; + + /* save first seen error */ + if (!rc1) + rc1 = rc; + break; + } + } + + if (!valid) { + llapi_printf(LLAPI_MSG_ERROR, + "%s:%s Not a Lustre filesystem\n", + argv[0], argv[arg_idx]); + /* save first seen error */ + if (!rc1) + rc1 = -EOPNOTSUPP; + } } - return rc; + return rc1; } static int print_instance(const char *mntdir, char *buf, size_t buflen, @@ -6211,7 +7296,8 @@ static int print_instance(const char *mntdir, char *buf, size_t buflen, if (opt_fsname == opt_instance) { /* both true or both false */ rc = llapi_getname(mntdir, buf, buflen); } else if (opt_fsname) { - /* llapi_search_mounts() fills @buf with fsname, but that is not + /* + * llapi_search_mounts() fills @buf with fsname, but that is not * called if explicit paths are specified on the command-line */ if (buf[0] == '\0') @@ -6253,8 +7339,11 @@ static int lfs_getname(int argc, char **argv) case 'n': opt_fsname = true; break; - case 'h': default: + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + fallthrough; + case 'h': return CMD_HELP; } } @@ -6328,7 +7417,7 @@ static int lfs_check(int argc, char **argv) return CMD_HELP; } - rc = llapi_search_mounts(NULL, 0, mntdir, NULL); + rc = llapi_search_mounts(NULL, 0, mntdir, NULL); if (rc < 0 || mntdir[0] == '\0') { fprintf(stderr, "%s check: cannot find mounted Lustre filesystem: %s\n", @@ -6342,22 +7431,12 @@ static int lfs_check(int argc, char **argv) progname, argv[1], strerror(-rc)); return rc; - } #ifdef HAVE_SYS_QUOTA_H -#define ARG2INT(nr, str, msg) \ -do { \ - char *endp; \ - nr = strtol(str, &endp, 0); \ - if (*endp != '\0') { \ - fprintf(stderr, "%s: bad %s '%s'\n", \ - progname, msg, str); \ - return CMD_HELP; \ - } \ -} while (0) - -#define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b) +#define ADD_OVERFLOW(a, b) \ + ((((a) + (b)) < (a)) ? \ + ((a) = ULONG_MAX) : ((a) = (a) + (b))) /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value * returns the value or ULONG_MAX on integer overflow or incorrect format @@ -6366,54 +7445,58 @@ do { \ * 2. specifiers may be encountered multiple times (2s3s is 5 seconds) * 3. empty integer value is interpreted as 0 */ -static unsigned long str2sec(const char* timestr) +static unsigned long str2sec(const char *timestr) { - const char spec[] = "smhdw"; - const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60}; - unsigned long val = 0; - char *tail; + const char spec[] = "smhdw"; + const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60}; + unsigned long val = 0; + char *tail; - if (strpbrk(timestr, spec) == NULL) { - /* no specifiers inside the time string, - should treat it as an integer value */ - val = strtoul(timestr, &tail, 10); - return *tail ? ULONG_MAX : val; - } + if (strpbrk(timestr, spec) == NULL) { + /* + * no specifiers inside the time string, + * should treat it as an integer value + */ + val = strtoul(timestr, &tail, 10); + return *tail ? ULONG_MAX : val; + } - /* format string is XXwXXdXXhXXmXXs */ - while (*timestr) { - unsigned long v; - int ind; - char* ptr; + /* format string is XXwXXdXXhXXmXXs */ + while (*timestr) { + unsigned long v; + int ind; + char *ptr; - v = strtoul(timestr, &tail, 10); - if (v == ULONG_MAX || *tail == '\0') - /* value too large (ULONG_MAX or more) - or missing specifier */ - goto error; + v = strtoul(timestr, &tail, 10); + if (v == ULONG_MAX || *tail == '\0') + /* + * value too large (ULONG_MAX or more) + * or missing specifier + */ + goto error; - ptr = strchr(spec, *tail); - if (ptr == NULL) - /* unknown specifier */ - goto error; + ptr = strchr(spec, *tail); + if (!ptr) + /* unknown specifier */ + goto error; - ind = ptr - spec; + ind = ptr - spec; - /* check if product will overflow the type */ - if (!(v < ULONG_MAX / mult[ind])) - goto error; + /* check if product will overflow the type */ + if (!(v < ULONG_MAX / mult[ind])) + goto error; - ADD_OVERFLOW(val, mult[ind] * v); - if (val == ULONG_MAX) - goto error; + ADD_OVERFLOW(val, mult[ind] * v); + if (val == ULONG_MAX) + goto error; - timestr = tail + 1; - } + timestr = tail + 1; + } - return val; + return val; error: - return ULONG_MAX; + return ULONG_MAX; } #define ARG2ULL(nr, str, def_units) \ @@ -6432,37 +7515,64 @@ do { \ static inline int has_times_option(int argc, char **argv) { - int i; + int i; + + for (i = 1; i < argc; i++) + if (!strcmp(argv[i], "-t")) + return 1; + + return 0; +} + +static inline int lfs_verify_poolarg(char *pool) +{ + if (strnlen(optarg, LOV_MAXPOOLNAME + 1) > LOV_MAXPOOLNAME) { + fprintf(stderr, + "Pool name '%.*s' is longer than %d\n", + LOV_MAXPOOLNAME, pool, LOV_MAXPOOLNAME); + return 1; + } + return 0; +} - for (i = 1; i < argc; i++) - if (!strcmp(argv[i], "-t")) - return 1; +/* special grace time, only notify the user when its quota is over soft limit + * but doesn't block new writes until the hard limit is reached. + */ +#define NOTIFY_GRACE "notify" +#define NOTIFY_GRACE_TIME LQUOTA_GRACE_MASK - return 0; +#ifndef toqb +static inline __u64 lustre_stoqb(size_t space) +{ + return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS; } +#else +#define lustre_stoqb toqb +#endif -int lfs_setquota_times(int argc, char **argv) +int lfs_setquota_times(int argc, char **argv, struct if_quotactl *qctl) { - int c, rc; - struct if_quotactl qctl; - char *mnt, *obd_type = (char *)qctl.obd_type; - struct obd_dqblk *dqb = &qctl.qc_dqblk; - struct obd_dqinfo *dqi = &qctl.qc_dqinfo; - struct option long_opts[] = { + int c, rc; + char *mnt, *obd_type = (char *)qctl->obd_type; + struct obd_dqblk *dqb = &qctl->qc_dqblk; + struct obd_dqinfo *dqi = &qctl->qc_dqinfo; + struct option long_opts[] = { { .val = 'b', .name = "block-grace", .has_arg = required_argument }, { .val = 'g', .name = "group", .has_arg = no_argument }, + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'i', .name = "inode-grace", .has_arg = required_argument }, { .val = 'p', .name = "projid", .has_arg = no_argument }, { .val = 't', .name = "times", .has_arg = no_argument }, { .val = 'u', .name = "user", .has_arg = no_argument }, + { .val = LFS_POOL_OPT, + .name = "pool", .has_arg = required_argument }, { .name = NULL } }; int qtype; - memset(&qctl, 0, sizeof(qctl)); - qctl.qc_cmd = LUSTRE_Q_SETINFO; - qctl.qc_type = ALLQUOTA; + qctl->qc_cmd = LUSTRE_Q_SETINFO; + qctl->qc_type = ALLQUOTA; - while ((c = getopt_long(argc, argv, "b:gi:ptu", + while ((c = getopt_long(argc, argv, "b:ghi:ptu", long_opts, NULL)) != -1) { switch (c) { case 'u': @@ -6474,84 +7584,109 @@ int lfs_setquota_times(int argc, char **argv) case 'p': qtype = PRJQUOTA; quota_type: - if (qctl.qc_type != ALLQUOTA) { - fprintf(stderr, "error: -u/g/p can't be used " - "more than once\n"); + if (qctl->qc_type != ALLQUOTA) { + fprintf(stderr, + "%s: -u/g/p cannot be used more than once\n", + progname); return CMD_HELP; } - qctl.qc_type = qtype; - break; - case 'b': - if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) { - fprintf(stderr, "error: bad block-grace: %s\n", - optarg); - return CMD_HELP; - } - dqb->dqb_valid |= QIF_BTIME; - break; - case 'i': - if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) { - fprintf(stderr, "error: bad inode-grace: %s\n", - optarg); - return CMD_HELP; - } - dqb->dqb_valid |= QIF_ITIME; - break; - case 't': /* Yes, of course! */ - break; - default: /* getopt prints error message for us when opterr != 0 */ - return CMD_HELP; - } - } - - if (qctl.qc_type == ALLQUOTA) { - fprintf(stderr, "error: neither -u, -g nor -p specified\n"); - return CMD_HELP; - } - - if (optind != argc - 1) { - fprintf(stderr, "error: unexpected parameters encountered\n"); - return CMD_HELP; - } - - if ((dqb->dqb_valid | QIF_BTIME && dqi->dqi_bgrace >= UINT_MAX) || - (dqb->dqb_valid | QIF_ITIME && dqi->dqi_igrace >= UINT_MAX)) { - fprintf(stderr, "error: grace time is too large\n"); - return CMD_HELP; - } - - mnt = argv[optind]; - rc = llapi_quotactl(mnt, &qctl); - if (rc) { - if (*obd_type) - fprintf(stderr, "%s %s ", obd_type, - obd_uuid2str(&qctl.obd_uuid)); - fprintf(stderr, "setquota failed: %s\n", strerror(-rc)); - return rc; - } - - return 0; -} - -#define BSLIMIT (1 << 0) -#define BHLIMIT (1 << 1) -#define ISLIMIT (1 << 2) -#define IHLIMIT (1 << 3) - -int lfs_setquota(int argc, char **argv) -{ - int c, rc = 0; - struct if_quotactl qctl; - char *mnt, *obd_type = (char *)qctl.obd_type; - struct obd_dqblk *dqb = &qctl.qc_dqblk; - struct option long_opts[] = { + qctl->qc_type = qtype; + break; + case 'b': + if (strncmp(optarg, NOTIFY_GRACE, + strlen(NOTIFY_GRACE)) == 0) { + dqi->dqi_bgrace = NOTIFY_GRACE_TIME; + } else { + dqi->dqi_bgrace = str2sec(optarg); + if (dqi->dqi_bgrace >= NOTIFY_GRACE_TIME) { + fprintf(stderr, + "%s: bad block-grace: %s\n", + progname, optarg); + return CMD_HELP; + } + } + dqb->dqb_valid |= QIF_BTIME; + break; + case 'i': + if (strncmp(optarg, NOTIFY_GRACE, + strlen(NOTIFY_GRACE)) == 0) { + dqi->dqi_igrace = NOTIFY_GRACE_TIME; + } else { + dqi->dqi_igrace = str2sec(optarg); + if (dqi->dqi_igrace >= NOTIFY_GRACE_TIME) { + fprintf(stderr, + "%s: bad inode-grace: %s\n", + progname, optarg); + return CMD_HELP; + } + } + dqb->dqb_valid |= QIF_ITIME; + break; + case 't': /* Yes, of course! */ + break; + case LFS_POOL_OPT: + if (lfs_verify_poolarg(optarg)) + return -1; + strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME); + qctl->qc_cmd = LUSTRE_Q_SETINFOPOOL; + break; + /* getopt prints error message for us when opterr != 0 */ + default: + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + fallthrough; + case 'h': + return CMD_HELP; + } + } + + if (qctl->qc_type == ALLQUOTA) { + fprintf(stderr, "%s: neither -u, -g nor -p specified\n", + progname); + return CMD_HELP; + } + + if (optind != argc - 1) { + fprintf(stderr, "%s: unexpected parameter '%s'\n", + progname, argv[optind + 1]); + return CMD_HELP; + } + + mnt = argv[optind]; + rc = llapi_quotactl(mnt, qctl); + if (rc) { + if (*obd_type) + fprintf(stderr, "%s %s ", obd_type, + obd_uuid2str(&qctl->obd_uuid)); + fprintf(stderr, "setquota failed: %s\n", strerror(-rc)); + return rc; + } + + return 0; +} + +#define BSLIMIT (1 << 0) +#define BHLIMIT (1 << 1) +#define ISLIMIT (1 << 2) +#define IHLIMIT (1 << 3) + +int lfs_setquota(int argc, char **argv) +{ + int c, rc = 0; + struct if_quotactl *qctl; + char *mnt, *obd_type; + struct obd_dqblk *dqb; + struct option long_opts[] = { { .val = 'b', .name = "block-softlimit", .has_arg = required_argument }, { .val = 'B', .name = "block-hardlimit", .has_arg = required_argument }, { .val = 'd', .name = "default", .has_arg = no_argument }, + { .val = LFS_SETQUOTA_DELETE, + .name = "delete", .has_arg = no_argument }, { .val = 'g', .name = "group", .has_arg = required_argument }, { .val = 'G', .name = "default-grp", .has_arg = no_argument }, + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'i', .name = "inode-softlimit", .has_arg = required_argument }, { .val = 'I', .name = "inode-hardlimit", @@ -6560,80 +7695,103 @@ int lfs_setquota(int argc, char **argv) { .val = 'P', .name = "default-prj", .has_arg = no_argument }, { .val = 'u', .name = "user", .has_arg = required_argument }, { .val = 'U', .name = "default-usr", .has_arg = no_argument }, + { .val = LFS_POOL_OPT, + .name = "pool", .has_arg = required_argument }, { .name = NULL } }; - unsigned limit_mask = 0; - char *endptr; + unsigned int limit_mask = 0; bool use_default = false; - int qtype; + int qtype, qctl_len; - if (has_times_option(argc, argv)) - return lfs_setquota_times(argc, argv); + qctl_len = sizeof(*qctl) + LOV_MAXPOOLNAME + 1; + qctl = malloc(qctl_len); + if (!qctl) + return -ENOMEM; - memset(&qctl, 0, sizeof(qctl)); - qctl.qc_cmd = LUSTRE_Q_SETQUOTA; - qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota, - * so it can be used as a marker that qc_type - * isn't reinitialized from command line */ + memset(qctl, 0, qctl_len); + obd_type = (char *)qctl->obd_type; + dqb = &qctl->qc_dqblk; - while ((c = getopt_long(argc, argv, "b:B:dg:Gi:I:p:Pu:U", + if (has_times_option(argc, argv)) { + rc = lfs_setquota_times(argc, argv, qctl); + goto out; + } + + qctl->qc_cmd = LUSTRE_Q_SETQUOTA; + qctl->qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota, + * so it can be used as a marker that qc_type + * isn't reinitialized from command line + */ + while ((c = getopt_long(argc, argv, "b:B:dDg:Ghi:I:p:Pu:U", long_opts, NULL)) != -1) { switch (c) { case 'U': - qctl.qc_cmd = LUSTRE_Q_SETDEFAULT; + qctl->qc_cmd = LUSTRE_Q_SETDEFAULT; qtype = USRQUOTA; - qctl.qc_id = 0; + qctl->qc_id = 0; goto quota_type_def; case 'u': qtype = USRQUOTA; - rc = name2uid(&qctl.qc_id, optarg); + rc = name2uid(&qctl->qc_id, optarg); goto quota_type; case 'G': - qctl.qc_cmd = LUSTRE_Q_SETDEFAULT; + qctl->qc_cmd = LUSTRE_Q_SETDEFAULT; qtype = GRPQUOTA; - qctl.qc_id = 0; + qctl->qc_id = 0; goto quota_type_def; - case 'g': + case 'g': qtype = GRPQUOTA; - rc = name2gid(&qctl.qc_id, optarg); + rc = name2gid(&qctl->qc_id, optarg); goto quota_type; case 'P': - qctl.qc_cmd = LUSTRE_Q_SETDEFAULT; + qctl->qc_cmd = LUSTRE_Q_SETDEFAULT; qtype = PRJQUOTA; - qctl.qc_id = 0; + qctl->qc_id = 0; goto quota_type_def; case 'p': qtype = PRJQUOTA; - rc = name2projid(&qctl.qc_id, optarg); + rc = name2projid(&qctl->qc_id, optarg); quota_type: if (rc) { - qctl.qc_id = strtoul(optarg, &endptr, 10); - if (*endptr != '\0') { - fprintf(stderr, "%s setquota: invalid" - " id '%s'\n", progname, optarg); - return -1; + if (str2quotaid(&qctl->qc_id, optarg)) { + fprintf(stderr, + "%s setquota: invalid id '%s'\n", + progname, optarg); + rc = -1; + goto out; } } - if (qctl.qc_id == 0) { - fprintf(stderr, "%s setquota: can't set quota" - " for root usr/group/project.\n", + if (qctl->qc_id == 0) { + fprintf(stderr, + "%s setquota: can't set quota for root usr/group/project.\n", progname); - return -1; + rc = -1; + goto out; } quota_type_def: - if (qctl.qc_type != ALLQUOTA) { + if (qctl->qc_type != ALLQUOTA) { fprintf(stderr, - "%s setquota: only one of -u, -U, -g," - " -G, -p or -P may be specified\n", + "%s setquota: only one of -u, -U, -g, -G, -p or -P may be specified\n", progname); - return CMD_HELP; + rc = CMD_HELP; + goto out; } - qctl.qc_type = qtype; + qctl->qc_type = qtype; break; +#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0) case 'd': - qctl.qc_cmd = LUSTRE_Q_SETDEFAULT; +#if LUSTRE_VERSION_CODE > OBD_OCD_VERSION(2, 15, 53, 0) + fprintf(stderr, "'-d' deprecatd, use '-D' or '--default'\n"); +#endif + /* falltrrough */ +#endif + case 'D': use_default = true; + qctl->qc_cmd = LUSTRE_Q_SETDEFAULT; + break; + case LFS_SETQUOTA_DELETE: + qctl->qc_cmd = LUSTRE_Q_DELETEQID; break; case 'b': ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024); @@ -6642,8 +7800,7 @@ quota_type_def: if (dqb->dqb_bsoftlimit && dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */ fprintf(stderr, - "%s setquota: warning: block softlimit '%llu' smaller than minimum qunit size\n" - "See '%s help setquota' or Lustre manual for details\n", + "%s setquota: warning: block softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n", progname, (unsigned long long)dqb->dqb_bsoftlimit, progname); @@ -6667,8 +7824,7 @@ quota_type_def: if (dqb->dqb_isoftlimit && dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */ fprintf(stderr, - "%s setquota: warning: inode softlimit '%llu' smaller than minimum qunit size\n" - "See '%s help setquota' or Lustre manual for details\n", + "%s setquota: warning: inode softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n", progname, (unsigned long long)dqb->dqb_isoftlimit, progname); @@ -6679,58 +7835,83 @@ quota_type_def: if (dqb->dqb_ihardlimit && dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */ fprintf(stderr, - "%s setquota: warning: inode hardlimit '%llu' smaller than minimum qunit size\n" - "See '%s help setquota' or Lustre manual for details\n", + "%s setquota: warning: inode hardlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n", progname, (unsigned long long)dqb->dqb_ihardlimit, progname); break; + case LFS_POOL_OPT: + if (lfs_verify_poolarg(optarg)) { + rc = -1; + goto out; + } + strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME); + qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_SETDEFAULT ? + LUSTRE_Q_SETDEFAULT_POOL : + LUSTRE_Q_SETQUOTAPOOL; + break; default: fprintf(stderr, "%s setquota: unrecognized option '%s'\n", progname, argv[optind - 1]); - return CMD_HELP; + fallthrough; + case 'h': + rc = CMD_HELP; + goto out; } } - if (qctl.qc_type == ALLQUOTA) { + if (qctl->qc_type == ALLQUOTA) { fprintf(stderr, "%s setquota: either -u or -g must be specified\n", progname); - return CMD_HELP; + rc = CMD_HELP; + goto out; } - if (!use_default && limit_mask == 0) { + if (!use_default && qctl->qc_cmd != LUSTRE_Q_DELETEQID && + limit_mask == 0) { fprintf(stderr, "%s setquota: at least one limit must be specified\n", progname); - return CMD_HELP; + rc = CMD_HELP; + goto out; } - if (use_default && limit_mask != 0) { + if ((use_default || qctl->qc_cmd == LUSTRE_Q_DELETEQID) && + limit_mask != 0) { fprintf(stderr, - "%s setquota: limits should not be specified when" - " using default quota\n", + "%s setquota: limits should not be specified when using default quota or deleting quota ID\n", progname); - return CMD_HELP; + rc = CMD_HELP; + goto out; } - if (use_default && qctl.qc_id == 0) { + if (use_default && qctl->qc_id == 0) { fprintf(stderr, - "%s setquota: can not set default quota for root" - " user/group/project\n", + "%s setquota: can not set default quota for root user/group/project\n", progname); - return CMD_HELP; + rc = CMD_HELP; + goto out; + } + + if (qctl->qc_cmd == LUSTRE_Q_DELETEQID && qctl->qc_id == 0) { + fprintf(stderr, + "%s setquota: can not delete root user/group/project\n", + progname); + rc = CMD_HELP; + goto out; } if (optind != argc - 1) { fprintf(stderr, "%s setquota: filesystem not specified or unexpected argument '%s'\n", progname, argv[optind]); - return CMD_HELP; + rc = CMD_HELP; + goto out; } - mnt = argv[optind]; + mnt = argv[optind]; if (use_default) { dqb->dqb_bhardlimit = 0; @@ -6740,52 +7921,77 @@ quota_type_def: dqb->dqb_itime = 0; dqb->dqb_btime = 0; dqb->dqb_valid |= QIF_LIMITS | QIF_TIMES; + /* do not set inode limits for Pool Quotas */ + if (qctl->qc_cmd == LUSTRE_Q_SETDEFAULT_POOL) + dqb->dqb_valid ^= QIF_ILIMITS | QIF_ITIME; } else if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) || (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) { /* sigh, we can't just set blimits/ilimits */ - struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA, - .qc_type = qctl.qc_type, - .qc_id = qctl.qc_id}; + struct if_quotactl *tmp_qctl; - rc = llapi_quotactl(mnt, &tmp_qctl); - if (rc < 0) - return rc; + tmp_qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1); + if (!tmp_qctl) + goto out; + + if (qctl->qc_cmd == LUSTRE_Q_SETQUOTAPOOL) { + tmp_qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL; + strncpy(tmp_qctl->qc_poolname, qctl->qc_poolname, + LOV_MAXPOOLNAME); + } else { + tmp_qctl->qc_cmd = LUSTRE_Q_GETQUOTA; + } + tmp_qctl->qc_type = qctl->qc_type; + tmp_qctl->qc_id = qctl->qc_id; + + rc = llapi_quotactl(mnt, tmp_qctl); + if (rc < 0) { + free(tmp_qctl); + goto out; + } if (!(limit_mask & BHLIMIT)) - dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit; + dqb->dqb_bhardlimit = tmp_qctl->qc_dqblk.dqb_bhardlimit; if (!(limit_mask & BSLIMIT)) - dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit; + dqb->dqb_bsoftlimit = tmp_qctl->qc_dqblk.dqb_bsoftlimit; if (!(limit_mask & IHLIMIT)) - dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit; + dqb->dqb_ihardlimit = tmp_qctl->qc_dqblk.dqb_ihardlimit; if (!(limit_mask & ISLIMIT)) - dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit; + dqb->dqb_isoftlimit = tmp_qctl->qc_dqblk.dqb_isoftlimit; /* Keep grace times if we have got no softlimit arguments */ if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) { dqb->dqb_valid |= QIF_BTIME; - dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime; + dqb->dqb_btime = tmp_qctl->qc_dqblk.dqb_btime; } if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) { dqb->dqb_valid |= QIF_ITIME; - dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime; + dqb->dqb_itime = tmp_qctl->qc_dqblk.dqb_itime; } + free(tmp_qctl); } dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0; dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0; - rc = llapi_quotactl(mnt, &qctl); + rc = llapi_quotactl(mnt, qctl); if (rc) { if (*obd_type) fprintf(stderr, - "%s setquota: cannot quotactl '%s' '%s': %s", + "%s setquota: cannot quotactl '%s' '%s': %s\n", progname, obd_type, - obd_uuid2str(&qctl.obd_uuid), strerror(-rc)); - return rc; + obd_uuid2str(&qctl->obd_uuid), strerror(-rc)); + else + fprintf(stderr, + "%s setquota: quotactl failed: %s\n", + progname, strerror(-rc)); } +out: + if (rc) + fprintf(stderr, "setquota failed: %s\n", strerror(-rc)); - return 0; + free(qctl); + return rc; } /* Converts seconds value into format string @@ -6795,7 +8001,7 @@ quota_type_def: * 2. zero fields are not filled (except for p. 3): 5d1s * 3. zero seconds value is presented as "0s" */ -static char * __sec2str(time_t seconds, char *buf) +static char *__sec2str(time_t seconds, char *buf) { const char spec[] = "smhdw"; const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60}; @@ -6818,30 +8024,29 @@ static char * __sec2str(time_t seconds, char *buf) static void sec2str(time_t seconds, char *buf, int rc) { - char *tail = buf; + char *tail = buf; - if (rc) - *tail++ = '['; + if (rc) + *tail++ = '['; - tail = __sec2str(seconds, tail); + tail = __sec2str(seconds, tail); - if (rc && tail - buf < 39) { - *tail++ = ']'; - *tail++ = 0; - } + if (rc && tail - buf < 39) { + *tail++ = ']'; + *tail++ = 0; + } } static void diff2str(time_t seconds, char *buf, time_t now) { - - buf[0] = 0; - if (!seconds) - return; - if (seconds <= now) { - strcpy(buf, "none"); - return; - } - __sec2str(seconds - now, buf); + buf[0] = 0; + if (!seconds) + return; + if (seconds <= now) { + strcpy(buf, "none"); + return; + } + __sec2str(seconds - now, buf); } static void print_quota_title(char *name, struct if_quotactl *qctl, @@ -6885,7 +8090,20 @@ static void kbytes2str(__u64 num, char *buf, int buflen, bool h) } } -#define STRBUF_LEN 32 +#ifdef HAVE_NATIVE_CLIENT +/* In the current Lustre implementation, the grace time is either the time + * or the timestamp to be used after some quota ID exceeds the soft limt, + * 48 bits should be enough, its high 16 bits can be used as quota flags. + */ +#define LQUOTA_GRACE_BITS 48 +#define LQUOTA_GRACE_MASK ((1ULL << LQUOTA_GRACE_BITS) - 1) +#define LQUOTA_GRACE_MAX LQUOTA_GRACE_MASK +#define LQUOTA_GRACE(t) (t & LQUOTA_GRACE_MASK) +#define LQUOTA_FLAG(t) (t >> LQUOTA_GRACE_BITS) +#define LQUOTA_GRACE_FLAG(t, f) ((__u64)t | (__u64)f << LQUOTA_GRACE_BITS) +#endif + +#define STRBUF_LEN 24 static void print_quota(char *mnt, struct if_quotactl *qctl, int type, int rc, bool h, bool show_default) { @@ -6894,35 +8112,34 @@ static void print_quota(char *mnt, struct if_quotactl *qctl, int type, time(&now); if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA || - qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) { + qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL || + qctl->qc_cmd == LUSTRE_Q_GETDEFAULT || + qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL) { int bover = 0, iover = 0; struct obd_dqblk *dqb = &qctl->qc_dqblk; - char numbuf[3][STRBUF_LEN]; + char numbuf[3][STRBUF_LEN + 2]; /* 2 for brackets or wildcard */ char timebuf[40]; char strbuf[STRBUF_LEN]; if (dqb->dqb_bhardlimit && lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) { - bover = 1; - } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) { - if (dqb->dqb_btime > now) { - bover = 2; - } else { - bover = 3; - } - } - - if (dqb->dqb_ihardlimit && - dqb->dqb_curinodes >= dqb->dqb_ihardlimit) { - iover = 1; - } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) { - if (dqb->dqb_itime > now) { + bover = 1; + } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) { + if (dqb->dqb_btime > now) + bover = 2; + else + bover = 3; + } + + if (dqb->dqb_ihardlimit && + dqb->dqb_curinodes >= dqb->dqb_ihardlimit) { + iover = 1; + } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) { + if (dqb->dqb_itime > now) iover = 2; - } else { + else iover = 3; - } - } - + } if (strlen(mnt) > 15) printf("%s\n%15s", mnt, ""); @@ -6961,7 +8178,6 @@ static void print_quota(char *mnt, struct if_quotactl *qctl, int type, numbuf[0], bover ? '*' : ' ', numbuf[1], numbuf[2], bover > 1 ? timebuf : "-"); - if (iover) diff2str(dqb->dqb_itime, timebuf, now); else if (show_default) @@ -6991,48 +8207,135 @@ static void print_quota(char *mnt, struct if_quotactl *qctl, int type, else printf(" %7s %7s %7s %7s", "-", "-", "-", "-"); printf("\n"); + } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO || LUSTRE_Q_GETINFOPOOL || + qctl->qc_cmd == Q_GETOINFO) { + char bgtimebuf[40]; + char igtimebuf[40]; + + if (qctl->qc_dqinfo.dqi_bgrace == NOTIFY_GRACE_TIME) + strncpy(bgtimebuf, NOTIFY_GRACE, 40); + else + sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc); + if (qctl->qc_dqinfo.dqi_igrace == NOTIFY_GRACE_TIME) + strncpy(igtimebuf, NOTIFY_GRACE, 40); + else + sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc); + + printf("Block grace time: %s; Inode grace time: %s\n", + bgtimebuf, igtimebuf); + } +} + +static int tgt_name2index(const char *tgtname, unsigned int *idx) +{ + char *dash, *endp; - } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO || - qctl->qc_cmd == Q_GETOINFO) { - char bgtimebuf[40]; - char igtimebuf[40]; + /* format is "lustre-OST0001" */ + dash = memchr(tgtname, '-', LUSTRE_MAXFSNAME + 1); + if (!dash) { + fprintf(stderr, "wrong tgtname format '%s'\n", tgtname); + return -EINVAL; + } + dash += 4; + + *idx = strtoul(dash, &endp, 16); + if (*idx > 0xffff) { + fprintf(stderr, "wrong index %s\n", tgtname); + return -ERANGE; + } - sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc); - sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc); - printf("Block grace time: %s; Inode grace time: %s\n", - bgtimebuf, igtimebuf); - } + return 0; } static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt, bool h, __u64 *total) { - int rc = 0, rc1 = 0, count = 0; - __u32 valid = qctl->qc_valid; + int rc = 0, rc1 = 0, count = 0, i = 0; + char **list = NULL, *buffer = NULL; + __u32 valid = qctl->qc_valid; + + if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL && is_mdt) + return 0; + + /* Is it correct for the case OST0000, OST0002, OST0003 - + * we will ask OST0001 that is absent and won't ask OST0003? */ + rc = llapi_get_obd_count(mnt, &count, is_mdt); + if (rc) { + fprintf(stderr, "can not get %s count: %s\n", + is_mdt ? "mdt" : "ost", strerror(-rc)); + return rc; + } - rc = llapi_get_obd_count(mnt, &count, is_mdt); - if (rc) { - fprintf(stderr, "can not get %s count: %s\n", - is_mdt ? "mdt": "ost", strerror(-rc)); - return rc; - } + if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) { + char fname[PATH_MAX]; + char fsname[LUSTRE_MAXFSNAME + 1]; + int bufsize = sizeof(struct obd_uuid) * count; + + rc = llapi_search_fsname(mnt, fsname); + if (rc) { + fprintf(stderr, "cannot get fsname for mountpoint %s\n", + mnt); + goto out; + } + buffer = malloc(bufsize + sizeof(*list) * count); + if (!buffer) + return -ENOMEM; + list = (char **)(buffer + bufsize); + snprintf(fname, PATH_MAX, "%s.%s", fsname, qctl->qc_poolname); + count = llapi_get_poolmembers(fname, list, count, + buffer, bufsize); + if (count <= 0) + goto out; + } + + for (i = 0; i < count; i++) { + if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) { + unsigned int index; - for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) { - qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX; - rc = llapi_quotactl(mnt, qctl); - if (rc) { + if (tgt_name2index(list[i], &index)) + continue; + qctl->qc_idx = index; + } else { + qctl->qc_idx = i; + } + + qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX; + rc = llapi_quotactl(mnt, qctl); + if (rc) { /* It is remote client case. */ if (rc == -EOPNOTSUPP) { - rc = 0; - goto out; - } + rc = 0; + goto out; + } - if (!rc1) - rc1 = rc; - fprintf(stderr, "quotactl %s%d failed.\n", - is_mdt ? "mdt": "ost", qctl->qc_idx); - continue; - } + /* no target for this index yet */ + if (rc == -ENODEV) { + rc = 0; + continue; + } + + /* inactive target */ + if (rc == -ENODATA) { + char name[UUID_MAX+8]; + + snprintf(name, sizeof(name), "%s[inact]", + obd_uuid2str(&qctl->obd_uuid)); + memset(&qctl->qc_dqinfo, 0, + sizeof(qctl->qc_dqinfo)); + memset(&qctl->qc_dqblk, 0, + sizeof(qctl->qc_dqblk)); + print_quota(name, qctl, qctl->qc_valid, 0, h, + false); + rc = 0; + continue; + } + + if (!rc1) + rc1 = rc; + fprintf(stderr, "quotactl %s%d failed.\n", + is_mdt ? "mdt" : "ost", qctl->qc_idx); + continue; + } print_quota(obd_uuid2str(&qctl->obd_uuid), qctl, qctl->qc_valid, 0, h, false); @@ -7040,6 +8343,8 @@ static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt, qctl->qc_dqblk.dqb_bhardlimit; } out: + if (buffer) + free(buffer); qctl->qc_valid = valid; return rc ? : rc1; } @@ -7098,6 +8403,8 @@ static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl, } if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA || + qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL || + qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL || qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) && !quiet) print_quota_title(name, qctl, human_readable, show_default); @@ -7107,14 +8414,16 @@ static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl, if (qctl->qc_valid != QC_GENERAL) mnt = ""; - inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA) && + inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || + qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) && ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) != (QIF_LIMITS|QIF_USAGE)); print_quota(mnt, qctl, QC_GENERAL, rc1, human_readable, show_default); if (!show_default && verbose && - qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO) { + qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO && + qctl->qc_cmd != LUSTRE_Q_GETINFOPOOL) { char strbuf[STRBUF_LEN]; rc2 = print_obd_quota(mnt, qctl, 1, human_readable, @@ -7123,9 +8432,8 @@ static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl, &total_balloc); kbytes2str(total_balloc, strbuf, sizeof(strbuf), human_readable); - printf("Total allocated inode limit: %ju, total " - "allocated block limit: %s\n", (uintmax_t)total_ialloc, - strbuf); + printf("Total allocated inode limit: %ju, total allocated block limit: %s\n", + (uintmax_t)total_ialloc, strbuf); } if (use_default_for_blk) @@ -7137,9 +8445,7 @@ static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl, *qtype_name(qctl->qc_type), qctl->qc_id); if (rc1 || rc2 || rc3 || inacc) - printf("Some errors happened when getting quota info. " - "Some devices may be not working or deactivated. " - "The data in \"[]\" is inaccurate.\n"); + printf("Some errors happened when getting quota info. Some devices may be not working or deactivated. The data in \"[]\" is inaccurate.\n"); out: if (rc1) return rc1; @@ -7207,7 +8513,13 @@ static int lfs_project(int argc, char **argv) phc.recursive = true; break; case 'p': - phc.projid = strtoul(optarg, NULL, 0); + if (str2quotaid(&phc.projid, optarg)) { + fprintf(stderr, + "Invalid project ID: %s\n", + optarg); + return CMD_HELP; + } + phc.assign_projid = true; break; @@ -7311,17 +8623,31 @@ static int lfs_quota(int argc, char **argv) { int c; char *mnt, *name = NULL; - struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA, - .qc_type = ALLQUOTA }; - char *obd_uuid = (char *)qctl.obd_uuid.uuid; + struct if_quotactl *qctl; + char *obd_uuid; int rc = 0, rc1 = 0, verbose = 0, quiet = 0; - char *endptr; __u32 valid = QC_GENERAL, idx = 0; bool human_readable = false; bool show_default = false; int qtype; + bool show_pools = false; + struct option long_opts[] = { + { .val = LFS_POOL_OPT, .name = "pool", .has_arg = optional_argument }, + { .name = NULL } }; + char **poollist = NULL; + char *buf = NULL; + int poolcount, i; + + qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1); + if (!qctl) + return -ENOMEM; - while ((c = getopt(argc, argv, "gGi:I:o:pPqtuUvh")) != -1) { + qctl->qc_cmd = LUSTRE_Q_GETQUOTA; + qctl->qc_type = ALLQUOTA; + obd_uuid = (char *)qctl->obd_uuid.uuid; + + while ((c = getopt_long(argc, argv, "gGi:I:o:pPqtuUvh", + long_opts, NULL)) != -1) { switch (c) { case 'U': show_default = true; @@ -7338,185 +8664,253 @@ static int lfs_quota(int argc, char **argv) case 'p': qtype = PRJQUOTA; quota_type: - if (qctl.qc_type != ALLQUOTA) { + if (qctl->qc_type != ALLQUOTA) { fprintf(stderr, "%s quota: only one of -u, -g, or -p may be specified\n", progname); - return CMD_HELP; + rc = CMD_HELP; + goto out; } - qctl.qc_type = qtype; + qctl->qc_type = qtype; + break; + case 't': + qctl->qc_cmd = LUSTRE_Q_GETINFO; + break; + case 'o': + valid = qctl->qc_valid = QC_UUID; + snprintf(obd_uuid, sizeof(*obd_uuid), "%s", optarg); break; - case 't': - qctl.qc_cmd = LUSTRE_Q_GETINFO; - break; - case 'o': - valid = qctl.qc_valid = QC_UUID; - snprintf(obd_uuid, sizeof(qctl.obd_uuid), "%s", optarg); - break; case 'i': - valid = qctl.qc_valid = QC_MDTIDX; - idx = qctl.qc_idx = atoi(optarg); + valid = qctl->qc_valid = QC_MDTIDX; + idx = qctl->qc_idx = atoi(optarg); if (idx == 0 && *optarg != '0') { fprintf(stderr, "%s quota: invalid MDT index '%s'\n", progname, optarg); - return CMD_HELP; + rc = CMD_HELP; + goto out; } break; case 'I': - valid = qctl.qc_valid = QC_OSTIDX; - idx = qctl.qc_idx = atoi(optarg); + valid = qctl->qc_valid = QC_OSTIDX; + idx = qctl->qc_idx = atoi(optarg); if (idx == 0 && *optarg != '0') { fprintf(stderr, "%s quota: invalid OST index '%s'\n", progname, optarg); - return CMD_HELP; + rc = CMD_HELP; + goto out; } break; - case 'v': - verbose = 1; - break; - case 'q': - quiet = 1; - break; + case 'v': + verbose = 1; + break; + case 'q': + quiet = 1; + break; case 'h': human_readable = true; break; + case LFS_POOL_OPT: + if ((!optarg) && (argv[optind] != NULL) && + (argv[optind][0] != '-') && + (argv[optind][0] != '/')) { + optarg = argv[optind++]; + if (lfs_verify_poolarg(optarg)) { + rc = -EINVAL; + goto out; + } + strncpy(qctl->qc_poolname, optarg, + LOV_MAXPOOLNAME); + if (qctl->qc_cmd == LUSTRE_Q_GETINFO) + qctl->qc_cmd = LUSTRE_Q_GETINFOPOOL; + else + qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL; + break; + } + + /* optarg is NULL */ + show_pools = true; + qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL; + break; default: fprintf(stderr, "%s quota: unrecognized option '%s'\n", progname, argv[optind - 1]); - return CMD_HELP; + rc = CMD_HELP; + goto out; } } - /* current uid/gid info for "lfs quota /path/to/lustre/mount" */ - if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA && - optind == argc - 1 && !show_default) { - - qctl.qc_cmd = LUSTRE_Q_GETQUOTA; - qctl.qc_idx = idx; + /* current uid/gid info for "lfs quota /path/to/lustre/mount" */ + if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA || + qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) && + qctl->qc_type == ALLQUOTA && + optind == argc - 1 && !show_default) { + qctl->qc_idx = idx; for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) { - qctl.qc_type = qtype; - qctl.qc_valid = valid; + qctl->qc_type = qtype; + qctl->qc_valid = valid; if (qtype == USRQUOTA) { - qctl.qc_id = geteuid(); - rc = uid2name(&name, qctl.qc_id); + qctl->qc_id = geteuid(); + rc = uid2name(&name, qctl->qc_id); } else { - qctl.qc_id = getegid(); - rc = gid2name(&name, qctl.qc_id); - memset(&qctl.qc_dqblk, 0, - sizeof(qctl.qc_dqblk)); + qctl->qc_id = getegid(); + rc = gid2name(&name, qctl->qc_id); + memset(&qctl->qc_dqblk, 0, + sizeof(qctl->qc_dqblk)); } if (rc) name = ""; mnt = argv[optind]; - rc1 = get_print_quota(mnt, name, &qctl, verbose, quiet, + rc1 = get_print_quota(mnt, name, qctl, verbose, quiet, human_readable, show_default); if (rc1 && !rc) rc = rc1; } - return rc; + goto out; /* lfs quota -u username /path/to/lustre/mount */ - } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) { + } else if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || + qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) { /* options should be followed by u/g-name and mntpoint */ if ((!show_default && optind + 2 != argc) || (show_default && optind + 1 != argc) || - qctl.qc_type == ALLQUOTA) { + qctl->qc_type == ALLQUOTA) { fprintf(stderr, "%s quota: name and mount point must be specified\n", progname); - return CMD_HELP; + rc = CMD_HELP; + goto out; } if (!show_default) { name = argv[optind++]; - switch (qctl.qc_type) { + switch (qctl->qc_type) { case USRQUOTA: - rc = name2uid(&qctl.qc_id, name); + rc = name2uid(&qctl->qc_id, name); break; case GRPQUOTA: - rc = name2gid(&qctl.qc_id, name); + rc = name2gid(&qctl->qc_id, name); break; case PRJQUOTA: - rc = name2projid(&qctl.qc_id, name); + rc = name2projid(&qctl->qc_id, name); break; default: rc = -ENOTSUP; break; } } else { - qctl.qc_valid = QC_GENERAL; - qctl.qc_cmd = LUSTRE_Q_GETDEFAULT; - qctl.qc_id = 0; + qctl->qc_valid = QC_GENERAL; + qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ? + LUSTRE_Q_GETDEFAULT_POOL : + LUSTRE_Q_GETDEFAULT; + qctl->qc_id = 0; } if (rc) { - qctl.qc_id = strtoul(name, &endptr, 10); - if (*endptr != '\0') { + if (str2quotaid(&qctl->qc_id, name)) { fprintf(stderr, "%s quota: invalid id '%s'\n", progname, name); - return CMD_HELP; + rc = CMD_HELP; + goto out; } } - } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) { + } else if (optind + 1 != argc || qctl->qc_type == ALLQUOTA) { fprintf(stderr, "%s quota: missing quota info argument(s)\n", progname); - return CMD_HELP; + rc = CMD_HELP; + goto out; } mnt = argv[optind]; - rc = get_print_quota(mnt, name, &qctl, verbose, quiet, + if (show_pools) { + char *p; + + i = 0; + rc = llapi_get_poolbuf(mnt, &buf, &poollist, &poolcount); + if (rc) + goto out; + + for (i = 0; i < poolcount; i++) { + p = memchr(poollist[i], '.', MAXNAMLEN); + if (!p) { + fprintf(stderr, "bad string format %.*s\n", + MAXNAMLEN, poollist[i]); + rc = -EINVAL; + goto out; + } + p++; + printf("Quotas for pool: %s\n", p); + strncpy(qctl->qc_poolname, p, LOV_MAXPOOLNAME); + rc = get_print_quota(mnt, name, qctl, verbose, quiet, + human_readable, show_default); + if (rc) + break; + } + goto out; + } + + rc = get_print_quota(mnt, name, qctl, verbose, quiet, human_readable, show_default); +out: + free(buf); + free(qctl); return rc; } #endif /* HAVE_SYS_QUOTA_H! */ static int flushctx_ioctl(char *mp) { - int fd, rc; + int fd, rc; - fd = open(mp, O_RDONLY); - if (fd == -1) { - fprintf(stderr, "flushctx: error open %s: %s\n", - mp, strerror(errno)); - return -1; - } + fd = open(mp, O_RDONLY); + if (fd == -1) { + fprintf(stderr, "flushctx: error open %s: %s\n", + mp, strerror(errno)); + return -1; + } - rc = ioctl(fd, LL_IOC_FLUSHCTX); - if (rc == -1) - fprintf(stderr, "flushctx: error ioctl %s: %s\n", - mp, strerror(errno)); + rc = ioctl(fd, LL_IOC_FLUSHCTX); + if (rc == -1) + fprintf(stderr, "flushctx: error ioctl %s: %s\n", + mp, strerror(errno)); - close(fd); - return rc; + close(fd); + return rc; } static int lfs_flushctx(int argc, char **argv) { - int kdestroy = 0, c; + int kdestroy = 0, reap = 0, c; char mntdir[PATH_MAX] = {'\0'}; int index = 0; int rc = 0; - while ((c = getopt(argc, argv, "k")) != -1) { - switch (c) { - case 'k': - kdestroy = 1; - break; - default: - fprintf(stderr, "error: %s: option '-%c' " - "unrecognized\n", argv[0], c); - return CMD_HELP; - } - } - - if (kdestroy) { - if ((rc = system("kdestroy > /dev/null")) != 0) { - rc = WEXITSTATUS(rc); - fprintf(stderr, "error destroying tickets: %d, continuing\n", rc); - } - } + while ((c = getopt(argc, argv, "kr")) != -1) { + switch (c) { + case 'k': + kdestroy = 1; + break; + case 'r': + reap = 1; + break; + default: + fprintf(stderr, + "error: %s: option '-%c' unrecognized\n", + argv[0], c); + return CMD_HELP; + } + } + + if (kdestroy) { + rc = system("kdestroy > /dev/null"); + if (rc) { + rc = WEXITSTATUS(rc); + fprintf(stderr, + "error destroying tickets: %d, continuing\n", + rc); + } + } if (optind >= argc) { /* flush for all mounted lustre fs. */ @@ -7530,14 +8924,23 @@ static int lfs_flushctx(int argc, char **argv) mntdir[0] = '\0'; /* avoid matching in next loop */ } - } else { - /* flush fs as specified */ - while (optind < argc) { - if (flushctx_ioctl(argv[optind++])) - rc = -1; - } - } - return rc; + } else { + /* flush fs as specified */ + while (optind < argc) { + if (flushctx_ioctl(argv[optind++])) + rc = -1; + } + } + + if (reap) { + rc = system("keyctl reap > /dev/null"); + if (rc != 0) { + rc = WEXITSTATUS(rc); + fprintf(stderr, "error reaping keyring: %d\n", rc); + } + } + + return rc; } static int lfs_changelog(int argc, char **argv) @@ -7554,28 +8957,45 @@ static int lfs_changelog(int argc, char **argv) while ((rc = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { - switch (rc) { - case 'f': - follow++; - break; - default: + switch (rc) { + case 'f': + follow++; + break; + default: fprintf(stderr, "%s changelog: unrecognized option '%s'\n", progname, argv[optind - 1]); - return CMD_HELP; - } - } + return CMD_HELP; + } + } if (optind >= argc) { fprintf(stderr, "%s changelog: mdtname must be specified\n", progname); return CMD_HELP; } - mdd = argv[optind++]; - if (argc > optind) - startrec = strtoll(argv[optind++], NULL, 10); - if (argc > optind) - endrec = strtoll(argv[optind++], NULL, 10); + mdd = argv[optind++]; + if (argc > optind) { + errno = 0; + startrec = strtoll(argv[optind++], NULL, 10); + if (errno != 0 || startrec < 0) { + fprintf(stderr, + "%s changelog: bad startrec\n", + progname); + return CMD_HELP; + } + } + + if (argc > optind) { + errno = 0; + endrec = strtoll(argv[optind++], NULL, 10); + if (errno != 0 || endrec < 0) { + fprintf(stderr, + "%s changelog: bad endrec\n", + progname); + return CMD_HELP; + } + } rc = llapi_changelog_start(&changelog_priv, CHANGELOG_FLAG_BLOCK | @@ -7675,7 +9095,6 @@ static int lfs_changelog(int argc, char **argv) if (strcmp(mode, "---") != 0) printf(" m=%s", mode); - } if (ef->cr_extra_flags & CLFE_XATTR) { @@ -7687,9 +9106,11 @@ static int lfs_changelog(int argc, char **argv) } } + if (!fid_is_zero(&rec->cr_pfid)) + printf(" p="DFID, PFID(&rec->cr_pfid)); if (rec->cr_namelen) - printf(" p="DFID" %.*s", PFID(&rec->cr_pfid), - rec->cr_namelen, changelog_rec_name(rec)); + printf(" %.*s", rec->cr_namelen, + changelog_rec_name(rec)); if (rec->cr_flags & CLF_RENAME) { struct changelog_ext_rename *rnm = @@ -7724,7 +9145,14 @@ static int lfs_changelog_clear(int argc, char **argv) if (argc != 4) return CMD_HELP; + errno = 0; endrec = strtoll(argv[3], NULL, 10); + if (errno != 0 || endrec < 0) { + fprintf(stderr, + "%s: bad endrec '%s'\n", + argv[0], argv[3]); + return CMD_HELP; + } rc = llapi_changelog_clear(argv[1], argv[2], endrec); @@ -7744,31 +9172,49 @@ static int lfs_changelog_clear(int argc, char **argv) return rc; } +static void rstripc(char *str, int c) +{ + char *end = str + strlen(str); + + for (; str < end && end[-1] == c; --end) + end[-1] = '\0'; +} + static int lfs_fid2path(int argc, char **argv) { struct option long_opts[] = { { .val = 'c', .name = "cur", .has_arg = no_argument }, + { .val = 'c', .name = "current", .has_arg = no_argument }, + { .val = 'c', .name = "print-link", .has_arg = no_argument }, + { .val = 'f', .name = "print-fid", .has_arg = no_argument }, { .val = 'l', .name = "link", .has_arg = required_argument }, - { .val = 'r', .name = "rec", .has_arg = required_argument }, { .name = NULL } }; - char short_opts[] = "cl:r:"; - char *device, *fid, *path; + char short_opts[] = "cfl:pr:"; + bool print_link = false; + bool print_fid = false; + bool print_mnt_dir; + char mnt_dir[PATH_MAX] = ""; + int mnt_fd = -1; + char *path_or_fsname; long long recno = -1; int linkno = -1; - int lnktmp; - int printcur = 0; - int rc = 0; char *endptr = NULL; + int rc = 0; + int c; + int i; - while ((rc = getopt_long(argc, argv, short_opts, - long_opts, NULL)) != -1) { - switch (rc) { + while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { + switch (c) { case 'c': - printcur++; + print_link = true; + break; + case 'f': + print_fid = true; break; case 'l': + errno = 0; linkno = strtol(optarg, &endptr, 10); - if (*endptr != '\0') { + if (errno != 0 || *endptr != '\0' || linkno < 0) { fprintf(stderr, "%s fid2path: invalid linkno '%s'\n", progname, optarg); @@ -7776,8 +9222,13 @@ static int lfs_fid2path(int argc, char **argv) } break; case 'r': + /* recno is something to do with changelogs + * that was never implemented. We just pass it + * through for the MDT to ignore. + */ + errno = 0; recno = strtoll(optarg, &endptr, 10); - if (*endptr != '\0') { + if (errno != 0 || *endptr != '\0' || recno < 0) { fprintf(stderr, "%s fid2path: invalid recno '%s'\n", progname, optarg); @@ -7792,64 +9243,110 @@ static int lfs_fid2path(int argc, char **argv) } } - if (argc < 3) { + if (argc - optind < 2) { + fprintf(stderr, + "Usage: %s fid2path FSNAME|ROOT FID...\n", + progname); + return CMD_HELP; + } + + path_or_fsname = argv[optind]; + + if (*path_or_fsname == '/') { + print_mnt_dir = true; + rc = llapi_search_mounts(path_or_fsname, 0, mnt_dir, NULL); + } else { + print_mnt_dir = false; + rc = llapi_search_rootpath(mnt_dir, path_or_fsname); + } + + if (rc < 0) { fprintf(stderr, - "%s fid2path: and ... must be specified\n", - progname); - return CMD_HELP; + "%s fid2path: cannot resolve mount point for '%s': %s\n", + progname, path_or_fsname, strerror(-rc)); + goto out; } - device = argv[optind++]; - path = calloc(1, PATH_MAX); - if (path == NULL) { - rc = -errno; + mnt_fd = open(mnt_dir, O_RDONLY | O_DIRECTORY); + if (mnt_fd < 0) { fprintf(stderr, - "%s fid2path: cannot allocate memory for path: %s\n", - progname, strerror(-rc)); - return rc; + "%s fid2path: cannot open mount point for '%s': %s\n", + progname, path_or_fsname, strerror(-rc)); + goto out; } - rc = 0; - while (optind < argc) { - fid = argv[optind++]; + /* Strip trailing slashes from mnt_dir. */ + rstripc(mnt_dir + 1, '/'); - lnktmp = (linkno >= 0) ? linkno : 0; + for (i = optind + 1; i < argc; i++) { + const char *fid_str = argv[i]; + struct lu_fid fid; + int rc2; + + rc2 = llapi_fid_parse(fid_str, &fid, NULL); + if (rc2 < 0) { + fprintf(stderr, + "%s fid2path: invalid FID '%s'\n", + progname, fid_str); + if (rc == 0) + rc = rc2; + + continue; + } + + int linktmp = (linkno >= 0) ? linkno : 0; while (1) { - int oldtmp = lnktmp; + int oldtmp = linktmp; long long rectmp = recno; - int rc2; - rc2 = llapi_fid2path(device, fid, path, PATH_MAX, - &rectmp, &lnktmp); + char path_buf[PATH_MAX]; + + rc2 = llapi_fid2path_at(mnt_fd, &fid, + path_buf, sizeof(path_buf), &rectmp, &linktmp); if (rc2 < 0) { fprintf(stderr, - "%s fid2path: cannot find '%s': %s\n", - progname, fid, strerror(errno = -rc2)); + "%s fid2path: cannot find %s %s: %s\n", + progname, path_or_fsname, fid_str, + strerror(-rc2)); if (rc == 0) rc = rc2; break; } - if (printcur) - fprintf(stdout, "%lld ", rectmp); - if (device[0] == '/') { - fprintf(stdout, "%s", device); - if (device[strlen(device) - 1] != '/') - fprintf(stdout, "/"); - } else if (path[0] == '\0') { - fprintf(stdout, "/"); - } - fprintf(stdout, "%s\n", path); + if (print_fid) + printf("%s ", fid_str); + + if (print_link) + printf("%d ", linktmp); + + /* You may think this looks wrong or weird (and it is!) + * but we are actually trying to preserve the old quirky + * behaviors (enforced by our old quirky tests!) that + * make lfs so much fun to work on: + * + * lustre 0x200000007:0x1:0x0 => "/" + * /mnt/lustre 0x200000007:0x1:0x0 => "/mnt/lustre//" + * + * Note that llapi_fid2path() returns "" for the root + * FID. */ + + printf("%s%s%s\n", + print_mnt_dir ? mnt_dir : "", + (print_mnt_dir || *path_buf == '\0') ? "/" : "", + path_buf); if (linkno >= 0) /* specified linkno */ break; - if (oldtmp == lnktmp) + + if (oldtmp == linktmp) /* no more links */ break; } } +out: + if (!(mnt_fd < 0)) + close(mnt_fd); - free(path); return rc; } @@ -7883,13 +9380,14 @@ static int lfs_path2fid(int argc, char **argv) fprintf(stderr, "%s path2fid: FILE... must be specified\n", progname); return CMD_HELP; - } - else if (optind < argc - 1) + } else if (optind < argc - 1) { sep = ": "; + } rc = 0; for (path = argv + optind; *path != NULL; path++) { int err = 0; + if (!show_parents) { err = llapi_path2fid(*path, &fid); if (!err) @@ -7937,28 +9435,29 @@ static int lfs_path2fid(int argc, char **argv) static int lfs_rmfid_and_show_errors(const char *device, struct fid_array *fa) { - int rc, rc2 = 0, k; + int rc, rc2, k; rc = llapi_rmfid(device, fa); - if (rc) { - fprintf(stderr, "rmfid(): rc = %d\n", rc); + if (rc < 0) { + fprintf(stderr, "%s rmfid: cannot remove FIDs: %s\n", + progname, strerror(-rc)); return rc; } for (k = 0; k < fa->fa_nr; k++) { - rc = (__s32)fa->fa_fids[k].f_ver; - if (!IS_ERR_VALUE(rc)) - continue; - if (!rc2 && rc) - rc2 = rc; - if (!rc) + rc2 = (__s32)fa->fa_fids[k].f_ver; + if (!IS_ERR_VALUE(rc2)) continue; + + if (rc == 0) + rc = rc2; + fa->fa_fids[k].f_ver = 0; - fprintf(stderr, "rmfid("DFID"): rc = %d\n", - PFID(&fa->fa_fids[k]), rc); + fprintf(stderr, "%s rmfid: cannot remove "DFID": %s\n", + progname, PFID(&fa->fa_fids[k]), strerror(-rc2)); } - return rc2; + return rc; } static int lfs_rmfid(int argc, char **argv) @@ -7976,7 +9475,7 @@ static int lfs_rmfid(int argc, char **argv) nr = argc - optind; fa = malloc(offsetof(struct fid_array, fa_fids[nr + 1])); - if (fa == NULL) + if (!fa) return -ENOMEM; fa->fa_nr = 0; @@ -8013,20 +9512,20 @@ static int lfs_rmfid(int argc, char **argv) static int lfs_data_version(int argc, char **argv) { - char *path; + int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */ __u64 data_version; + char *path; int fd; int rc; int c; - int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */ if (argc < 2) { - fprintf(stderr, "%s data_version: FILE must be specified\n", + fprintf(stderr, "%s: FILE must be specified\n", progname); return CMD_HELP; } - while ((c = getopt(argc, argv, "nrw")) != -1) { + while ((c = getopt(argc, argv, "hnrw")) != -1) { switch (c) { case 'n': data_version_flags = 0; @@ -8041,6 +9540,8 @@ static int lfs_data_version(int argc, char **argv) fprintf(stderr, "%s data_version: unrecognized option '%s'\n", progname, argv[optind - 1]); + fallthrough; + case 'h': return CMD_HELP; } } @@ -8135,11 +9636,11 @@ static int lfs_hsm_change_flags(int argc, char **argv, int mode) { .val = 'a', .name = "noarchive", .has_arg = no_argument }, { .val = 'd', .name = "dirty", .has_arg = no_argument }, { .val = 'e', .name = "exists", .has_arg = no_argument }, + { .val = 'h', .name = "help", .has_arg = no_argument }, + { .val = 'i', .name = "archive-id", .has_arg = required_argument }, { .val = 'l', .name = "lost", .has_arg = no_argument }, { .val = 'r', .name = "norelease", .has_arg = no_argument }, - { .val = 'i', .name = "archive-id", .has_arg = required_argument }, { .name = NULL } }; - char short_opts[] = "lraAdei:"; __u64 mask = 0; int c, rc; char *path; @@ -8149,7 +9650,7 @@ static int lfs_hsm_change_flags(int argc, char **argv, int mode) if (argc < 3) return CMD_HELP; - while ((c = getopt_long(argc, argv, short_opts, + while ((c = getopt_long(argc, argv, "aAdehi:lr", long_opts, NULL)) != -1) { switch (c) { case 'l': @@ -8171,18 +9672,20 @@ static int lfs_hsm_change_flags(int argc, char **argv, int mode) mask |= HS_EXISTS; break; case 'i': + errno = 0; archive_id = strtol(optarg, &end, 10); - if (*end != '\0') { - fprintf(stderr, "invalid archive_id: '%s'\n", - end); + if (errno != 0 || *end != '\0' || archive_id < 0) { + fprintf(stderr, + "%s: invalid archive_id: '%s'\n", + progname, end); return CMD_HELP; } break; - case '?': - return CMD_HELP; default: - fprintf(stderr, "error: %s: option '%s' unrecognized\n", - argv[0], argv[optind - 1]); + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + fallthrough; + case 'h': return CMD_HELP; } } @@ -8192,7 +9695,6 @@ static int lfs_hsm_change_flags(int argc, char **argv, int mode) return CMD_HELP; while (optind < argc) { - path = argv[optind]; /* If mode == 0, this means we apply the mask. */ @@ -8295,7 +9797,8 @@ static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid, fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno)); return -errno; } - /* Checking for regular file as archiving as posix copytool + /* + * Checking for regular file as archiving as posix copytool * rejects archiving files other than regular files */ if (!S_ISREG(st.st_mode)) { @@ -8304,8 +9807,9 @@ static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid, } /* A request should be ... */ if (*last_dev != st.st_dev && *last_dev != 0) { - fprintf(stderr, "All files should be " - "on the same filesystem: %s\n", file); + fprintf(stderr, + "All files should be on the same filesystem: %s\n", + file); return -EINVAL; } *last_dev = st.st_dev; @@ -8343,7 +9847,7 @@ static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx, hui->hui_extent.length = -1; - if (mntpath != NULL) { + if (mntpath) { rc = llapi_fid_parse(fname, &hui->hui_fid, NULL); if (rc) fprintf(stderr, "hsm: '%s' is not a valid FID\n", @@ -8363,31 +9867,31 @@ static int lfs_hsm_request(int argc, char **argv, int action) struct option long_opts[] = { { .val = 'a', .name = "archive", .has_arg = required_argument }, { .val = 'D', .name = "data", .has_arg = required_argument }, + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'l', .name = "filelist", .has_arg = required_argument }, { .val = 'm', .name = "mntpath", .has_arg = required_argument }, { .name = NULL } }; - dev_t last_dev = 0; - char short_opts[] = "l:D:a:m:"; - struct hsm_user_request *hur, *oldhur; - int c, i; - size_t len; - int nbfile; - char *line = NULL; - char *filelist = NULL; - char fullpath[PATH_MAX]; - char *opaque = NULL; - int opaque_len = 0; - int archive_id = 0; - FILE *fp; - int nbfile_alloc = 0; - char *some_file = NULL; - char *mntpath = NULL; - int rc; + dev_t last_dev = 0; + struct hsm_user_request *hur, *oldhur; + int c, i; + size_t len; + int nbfile; + char *line = NULL; + char *filelist = NULL; + char fullpath[PATH_MAX]; + char *opaque = NULL; + int opaque_len = 0; + int archive_id = 0; + FILE *fp; + int nbfile_alloc = 0; + char *some_file = NULL; + char *mntpath = NULL; + int rc; if (argc < 2) return CMD_HELP; - while ((c = getopt_long(argc, argv, short_opts, + while ((c = getopt_long(argc, argv, "a:D:hl:m:", long_opts, NULL)) != -1) { switch (c) { case 'l': @@ -8400,23 +9904,22 @@ static int lfs_hsm_request(int argc, char **argv, int action) if (action != HUA_ARCHIVE && action != HUA_REMOVE) { fprintf(stderr, - "error: -a is supported only " - "when archiving or removing\n"); + "error: -a is supported only when archiving or removing\n"); return CMD_HELP; } archive_id = atoi(optarg); break; case 'm': - if (some_file == NULL) { + if (!some_file) { mntpath = optarg; some_file = strdup(optarg); } break; - case '?': - return CMD_HELP; default: - fprintf(stderr, "error: %s: option '%s' unrecognized\n", - argv[0], argv[optind - 1]); + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + fallthrough; + case 'h': return CMD_HELP; } } @@ -8424,16 +9927,18 @@ static int lfs_hsm_request(int argc, char **argv, int action) /* All remaining args are files, so we have at least nbfile */ nbfile = argc - optind; - if ((nbfile == 0) && (filelist == NULL)) + if ((nbfile == 0) && (!filelist)) return CMD_HELP; - if (opaque != NULL) + if (opaque) opaque_len = strlen(opaque); - /* Alloc the request structure with enough place to store all files - * from command line. */ + /* + * Alloc the request structure with enough place to store all files + * from command line. + */ hur = llapi_hsm_user_request_alloc(nbfile, opaque_len); - if (hur == NULL) { + if (!hur) { fprintf(stderr, "Cannot create the request: %s\n", strerror(errno)); return errno; @@ -8458,9 +9963,9 @@ static int lfs_hsm_request(int argc, char **argv, int action) /* from here stop using nb_file, use hur->hur_request.hr_itemcount */ /* If a filelist was specified, read the filelist from it. */ - if (filelist != NULL) { + if (filelist) { fp = fopen(filelist, "r"); - if (fp == NULL) { + if (!fp) { fprintf(stderr, "Cannot read the file list %s: %s\n", filelist, strerror(errno)); rc = -errno; @@ -8468,8 +9973,10 @@ static int lfs_hsm_request(int argc, char **argv, int action) } while ((rc = getline(&line, &len, fp)) != -1) { - /* If allocated buffer was too small, get something - * larger */ + /* + * If allocated buffer was too small, get something + * larger + */ if (nbfile_alloc <= hur->hur_request.hr_itemcount) { ssize_t size; @@ -8477,9 +9984,9 @@ static int lfs_hsm_request(int argc, char **argv, int action) oldhur = hur; hur = llapi_hsm_user_request_alloc(nbfile_alloc, opaque_len); - if (hur == NULL) { - fprintf(stderr, "hsm: cannot allocate " - "the request: %s\n", + if (!hur) { + fprintf(stderr, + "hsm: cannot allocate the request: %s\n", strerror(errno)); hur = oldhur; rc = -errno; @@ -8488,10 +9995,10 @@ static int lfs_hsm_request(int argc, char **argv, int action) } size = hur_len(oldhur); if (size < 0) { - fprintf(stderr, "hsm: cannot allocate " - "%u files + %u bytes data\n", - oldhur->hur_request.hr_itemcount, - oldhur->hur_request.hr_data_len); + fprintf(stderr, + "hsm: cannot allocate %u files + %u bytes data\n", + oldhur->hur_request.hr_itemcount, + oldhur->hur_request.hr_data_len); free(hur); hur = oldhur; rc = -E2BIG; @@ -8513,7 +10020,7 @@ static int lfs_hsm_request(int argc, char **argv, int action) goto out_free; } - if (some_file == NULL) { + if (!some_file) { some_file = line; line = NULL; } @@ -8525,7 +10032,7 @@ static int lfs_hsm_request(int argc, char **argv, int action) /* If a --data was used, add it to the request */ hur->hur_request.hr_data_len = opaque_len; - if (opaque != NULL) + if (opaque) memcpy(hur_data(hur), opaque, opaque_len); /* Send the HSM request */ @@ -8592,7 +10099,7 @@ int lfs_get_mode(const char *string) for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) { if (lock_mode_names[mode] == NULL) continue; - if (strcmp(string, lock_mode_names[mode]) == 0) + if (strcasecmp(string, lock_mode_names[mode]) == 0) return mode; } @@ -8620,34 +10127,33 @@ static int lfs_ladvise(int argc, char **argv) { .val = 'a', .name = "advice", .has_arg = required_argument }, { .val = 'b', .name = "background", .has_arg = no_argument }, { .val = 'e', .name = "end", .has_arg = required_argument }, + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'l', .name = "length", .has_arg = required_argument }, { .val = 'm', .name = "mode", .has_arg = required_argument }, { .val = 's', .name = "start", .has_arg = required_argument }, { .val = 'u', .name = "unset", .has_arg = no_argument }, { .name = NULL } }; - char short_opts[] = "a:be:l:m:s:u"; - int c; - int rc = 0; - const char *path; - int fd; - struct llapi_lu_ladvise advice; - enum lu_ladvise_type advice_type = LU_LADVISE_INVALID; - unsigned long long start = 0; - unsigned long long end = LUSTRE_EOF; - unsigned long long length = 0; - unsigned long long size_units; - unsigned long long flags = 0; - int mode = 0; + struct llapi_lu_ladvise advice; + enum lu_ladvise_type advice_type = LU_LADVISE_INVALID; + unsigned long long start = 0; + unsigned long long end = LUSTRE_EOF; + unsigned long long length = 0; + unsigned long long size_units; + unsigned long long flags = 0; + int c, fd, rc = 0; + const char *path; + int mode = 0; optind = 0; - while ((c = getopt_long(argc, argv, short_opts, + while ((c = getopt_long(argc, argv, "a:be:hl:m:s:u", long_opts, NULL)) != -1) { switch (c) { case 'a': advice_type = lfs_get_ladvice(optarg); if (advice_type == LU_LADVISE_INVALID) { - fprintf(stderr, "%s: invalid advice type " - "'%s'\n", argv[0], optarg); + fprintf(stderr, + "%s: invalid advice type '%s'\n", + progname, optarg); fprintf(stderr, "Valid types:"); for (advice_type = 0; @@ -8684,8 +10190,9 @@ static int lfs_ladvise(int argc, char **argv) rc = llapi_parse_size(optarg, &start, &size_units, 0); if (rc) { - fprintf(stderr, "%s: bad start offset " - "'%s'\n", argv[0], optarg); + fprintf(stderr, + "%s: bad start offset '%s'\n", + argv[0], optarg); return CMD_HELP; } break; @@ -8702,17 +10209,17 @@ static int lfs_ladvise(int argc, char **argv) case 'm': mode = lfs_get_mode(optarg); if (mode < 0) { - fprintf(stderr, "%s: bad mode '%s', valid " - "modes are READ or WRITE\n", + fprintf(stderr, + "%s: bad mode '%s', valid modes are READ or WRITE\n", argv[0], optarg); return CMD_HELP; } break; - case '?': - return CMD_HELP; default: - fprintf(stderr, "%s: option '%s' unrecognized\n", - argv[0], argv[optind - 1]); + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + fallthrough; + case 'h': return CMD_HELP; } } @@ -8731,9 +10238,9 @@ static int lfs_ladvise(int argc, char **argv) } if (advice_type == LU_LADVISE_LOCKNOEXPAND) { - fprintf(stderr, "%s: Lock no expand advice is a per file " - "descriptor advice, so when called from lfs, " - "it does nothing.\n", argv[0]); + fprintf(stderr, + "%s: Lock no expand advice is a per file descriptor advice, so when called from lfs, it does nothing.\n", + argv[0]); return CMD_HELP; } @@ -8798,9 +10305,9 @@ static int lfs_ladvise(int argc, char **argv) rc2 = llapi_ladvise(fd, flags, 1, &advice); close(fd); if (rc2 < 0) { - fprintf(stderr, "%s: cannot give advice '%s' to file " - "'%s': %s\n", argv[0], - ladvise_names[advice_type], + fprintf(stderr, + "%s: cannot give advice '%s' to file '%s': %s\n", + argv[0], ladvise_names[advice_type], path, strerror(errno)); goto next; @@ -8848,8 +10355,9 @@ static int lfs_heat_get(int argc, char **argv) rc2 = llapi_heat_get(fd, heat); close(fd); if (rc2 < 0) { - fprintf(stderr, "%s: cannot get heat of file '%s'" - ": %s\n", argv[0], path, strerror(errno)); + fprintf(stderr, + "%s: cannot get heat of file '%s': %s\n", + argv[0], path, strerror(errno)); goto next; } @@ -8870,6 +10378,7 @@ static int lfs_heat_set(int argc, char **argv) { struct option long_opts[] = { { .val = 'c', .name = "clear", .has_arg = no_argument }, + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'o', .name = "off", .has_arg = no_argument }, { .val = 'O', .name = "on", .has_arg = no_argument }, { .name = NULL } }; @@ -8883,7 +10392,7 @@ static int lfs_heat_set(int argc, char **argv) return CMD_HELP; optind = 0; - while ((c = getopt_long(argc, argv, "coO", long_opts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "choO", long_opts, NULL)) != -1) { switch (c) { case 'c': flags |= LU_HEAT_FLAG_CLEAR; @@ -8895,11 +10404,11 @@ static int lfs_heat_set(int argc, char **argv) case 'O': flags &= ~LU_HEAT_FLAG_OFF; break; - case '?': - return CMD_HELP; default: - fprintf(stderr, "%s: option '%s' unrecognized\n", - argv[0], argv[optind - 1]); + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + fallthrough; + case 'h': return CMD_HELP; } } @@ -8924,8 +10433,9 @@ static int lfs_heat_set(int argc, char **argv) rc2 = llapi_heat_set(fd, flags); close(fd); if (rc2 < 0) { - fprintf(stderr, "%s: cannot setflags heat of file '%s'" - ": %s\n", argv[0], path, strerror(errno)); + fprintf(stderr, + "%s: cannot setflags heat of file '%s': %s\n", + argv[0], path, strerror(errno)); goto next; } next: @@ -8935,7 +10445,8 @@ next: return rc; } -/** The input string contains a comma delimited list of component ids and +/** + * The input string contains a comma delimited list of component ids and * ranges, for example "1,2-4,7". */ static int parse_mirror_ids(__u16 *ids, int size, char *arg) @@ -8945,7 +10456,7 @@ static int parse_mirror_ids(__u16 *ids, int size, char *arg) int nr = 0; int rc; - if (arg == NULL) + if (!arg) return -EINVAL; while (!end_of_loop) { @@ -8997,7 +10508,7 @@ static int parse_mirror_ids(__u16 *ids, int size, char *arg) arg = ++ptr; rc = 0; } - if (!end_of_loop && ptr != NULL) + if (!end_of_loop && ptr) *ptr = ','; return rc < 0 ? rc : nr; @@ -9108,7 +10619,7 @@ int verify_mirror_ids(const char *fname, __u16 *mirror_ids, int ids_nr) } layout = llapi_layout_get_by_fd(fd, 0); - if (layout == NULL) { + if (!layout) { fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n", progname, fname, strerror(errno)); rc = -errno; @@ -9197,7 +10708,8 @@ int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc, goto error; } - fd = open(fname, O_DIRECT | O_RDWR); + /* Allow mirror resync even without the key on encrypted files */ + fd = open(fname, O_DIRECT | O_RDWR | O_FILE_ENC); if (fd < 0) { fprintf(stderr, "%s: cannot open '%s': %s.\n", progname, fname, strerror(errno)); @@ -9206,7 +10718,7 @@ int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc, } layout = llapi_layout_get_by_fd(fd, 0); - if (layout == NULL) { + if (!layout) { fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n", progname, fname, strerror(errno)); rc = -errno; @@ -9274,6 +10786,13 @@ int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc, fprintf(stderr, "%s: '%s' llapi_mirror_resync_many: %s.\n", progname, fname, strerror(-rc)); + rc = migrate_set_timestamps(fd, &stbuf); + if (rc < 0) { + fprintf(stderr, "%s: '%s' cannot set timestamps: %s\n", + progname, fname, strerror(-rc)); + goto free_layout; + } + /* need to do the lease unlock even resync fails */ ioc->lil_mode = LL_LEASE_UNLCK; ioc->lil_flags = LL_LEASE_RESYNC_DONE; @@ -9294,9 +10813,14 @@ int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc, /* rc2 == 0 means lost lease lock */ if (rc2 == 0 && rc == 0) rc = -EBUSY; + else + rc = rc2; fprintf(stderr, "%s: resync file '%s' failed: %s.\n", progname, fname, rc2 == 0 ? "lost lease lock" : strerror(-rc2)); + + llapi_lease_release(fd); + goto free_layout; } free_layout: @@ -9309,17 +10833,17 @@ error: static inline int lfs_mirror_resync(int argc, char **argv) { + struct option long_opts[] = { + { .val = 'h', .name = "help", .has_arg = no_argument }, + { .val = 'o', .name = "only", .has_arg = required_argument }, + { .name = NULL } }; struct ll_ioc_lease *ioc = NULL; __u16 mirror_ids[128] = { 0 }; int ids_nr = 0; int c; int rc = 0; - struct option long_opts[] = { - { .val = 'o', .name = "only", .has_arg = required_argument }, - { .name = NULL } }; - - while ((c = getopt_long(argc, argv, "o:", long_opts, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "ho:", long_opts, NULL)) >= 0) { switch (c) { case 'o': rc = parse_mirror_ids(mirror_ids, @@ -9334,9 +10858,11 @@ static inline int lfs_mirror_resync(int argc, char **argv) ids_nr = rc; break; default: - fprintf(stderr, "%s: options '%s' unrecognized.\n", - argv[0], argv[optind - 1]); - rc = -EINVAL; + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + fallthrough; + case 'h': + rc = CMD_HELP; goto error; } } @@ -9353,7 +10879,6 @@ static inline int lfs_mirror_resync(int argc, char **argv) argv[0]); rc = CMD_HELP; goto error; - } if (ids_nr > 0) { @@ -9364,7 +10889,7 @@ static inline int lfs_mirror_resync(int argc, char **argv) /* set the lease on the file */ ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1); - if (ioc == NULL) { + if (!ioc) { fprintf(stderr, "%s: cannot alloc id array for ioc: %s.\n", argv[0], strerror(errno)); rc = -errno; @@ -9391,7 +10916,7 @@ static inline int verify_mirror_id_by_fd(int fd, __u16 mirror_id) int rc; layout = llapi_layout_get_by_fd(fd, 0); - if (layout == NULL) { + if (!layout) { fprintf(stderr, "could not get layout.\n"); return -EINVAL; } @@ -9419,22 +10944,16 @@ static inline int verify_mirror_id_by_fd(int fd, __u16 mirror_id) * \retval 1 not the same file * \retval <0 error code */ -static inline int check_same_file(const char *f1, const char *f2) +static inline int check_same_file(int fd, const char *f2) { struct stat stbuf1; struct stat stbuf2; - if (stat(f1, &stbuf1) < 0) { - fprintf(stderr, "%s: cannot stat file '%s': %s\n", - progname, f1, strerror(errno)); + if (fstat(fd, &stbuf1) < 0) return -errno; - } - if (stat(f2, &stbuf2) < 0) { - fprintf(stderr, "%s: cannot stat file '%s': %s\n", - progname, f2, strerror(errno)); - return -errno; - } + if (stat(f2, &stbuf2) < 0) + return 1; if (stbuf1.st_rdev == stbuf2.st_rdev && stbuf1.st_ino == stbuf2.st_ino) @@ -9456,30 +10975,40 @@ static inline int lfs_mirror_read(int argc, char **argv) const size_t buflen = 4 << 20; off_t pos; struct option long_opts[] = { + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'N', .name = "mirror-id", .has_arg = required_argument }, { .val = 'o', .name = "outfile", .has_arg = required_argument }, { .name = NULL } }; - while ((c = getopt_long(argc, argv, "N:o:", long_opts, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "hN:o:", long_opts, NULL)) >= 0) { char *end; switch (c) { - case 'N': - mirror_id = strtoul(optarg, &end, 0); - if (*end != '\0' || mirror_id == 0) { + case 'N': { + unsigned long int id; + + errno = 0; + id = strtoul(optarg, &end, 0); + if (errno != 0 || *end != '\0' || id == 0 || + id > UINT16_MAX) { fprintf(stderr, "%s %s: invalid mirror ID '%s'\n", progname, argv[0], optarg); return rc; } + + mirror_id = (__u16)id; break; + } case 'o': outfile = optarg; break; default: - fprintf(stderr, "%s: option '%s' unrecognized.\n", + fprintf(stderr, "%s: unrecognized option '%s'\n", progname, argv[optind - 1]); - return -EINVAL; + fallthrough; + case 'h': + return CMD_HELP; } } @@ -9500,19 +11029,6 @@ static inline int lfs_mirror_read(int argc, char **argv) /* open mirror file */ fname = argv[optind]; - - if (outfile) { - rc = check_same_file(fname, outfile); - if (rc == 0) { - fprintf(stderr, - "%s %s: output file cannot be the mirrored file\n", - progname, argv[0]); - return -EINVAL; - } - if (rc < 0) - return rc; - } - fd = open(fname, O_DIRECT | O_RDONLY); if (fd < 0) { fprintf(stderr, "%s %s: cannot open '%s': %s\n", @@ -9529,7 +11045,7 @@ static inline int lfs_mirror_read(int argc, char **argv) goto close_fd; } - /* open output file */ + /* open output file - O_EXCL ensures output is not the same as input */ if (outfile) { outfd = open(outfile, O_EXCL | O_WRONLY | O_CREAT, 0644); if (outfd < 0) { @@ -9623,32 +11139,41 @@ static inline int lfs_mirror_write(int argc, char **argv) off_t pos; size_t page_size = sysconf(_SC_PAGESIZE); struct ll_ioc_lease_id ioc; - struct option long_opts[] = { - { .val = 'N', .name = "mirror-id", .has_arg = required_argument }, + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'i', .name = "inputfile", .has_arg = required_argument }, + { .val = 'N', .name = "mirror-id", .has_arg = required_argument }, { .name = NULL } }; - while ((c = getopt_long(argc, argv, "N:i:", long_opts, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "hi:N:", long_opts, NULL)) >= 0) { char *end; switch (c) { - case 'N': - mirror_id = strtoul(optarg, &end, 0); - if (*end != '\0' || mirror_id == 0) { + case 'N': { + unsigned long int id; + + errno = 0; + id = strtoul(optarg, &end, 0); + if (errno != 0 || *end != '\0' || id == 0 || + id > UINT16_MAX) { fprintf(stderr, "%s %s: invalid mirror ID '%s'\n", progname, argv[0], optarg); return rc; } + + mirror_id = (__u16)id; break; + } case 'i': inputfile = optarg; break; default: - fprintf(stderr, "%s: option '%s' unrecognized\n", + fprintf(stderr, "%s: unrecognized option '%s'\n", progname, argv[optind - 1]); - return -EINVAL; + fallthrough; + case 'h': + return CMD_HELP; } } @@ -9669,19 +11194,6 @@ static inline int lfs_mirror_write(int argc, char **argv) /* open mirror file */ fname = argv[optind]; - - if (inputfile) { - rc = check_same_file(fname, inputfile); - if (rc == 0) { - fprintf(stderr, - "%s %s: input file cannot be the mirrored file\n", - progname, argv[0]); - return -EINVAL; - } - if (rc < 0) - return rc; - } - fd = open(fname, O_DIRECT | O_WRONLY); if (fd < 0) { fprintf(stderr, "%s %s: cannot open '%s': %s\n", @@ -9700,6 +11212,16 @@ static inline int lfs_mirror_write(int argc, char **argv) /* open input file */ if (inputfile) { + rc = check_same_file(fd, inputfile); + if (rc == 0) { + fprintf(stderr, + "%s %s: input file cannot be the mirrored file\n", + progname, argv[0]); + goto close_fd; + } + if (rc < 0) + goto close_fd; + inputfd = open(inputfile, O_RDONLY, 0644); if (inputfd < 0) { fprintf(stderr, "%s %s: cannot open file '%s': %s\n", @@ -9817,7 +11339,7 @@ static inline int get_other_mirror_ids(int fd, __u16 *ids, __u16 exclude_id) int rc; layout = llapi_layout_get_by_fd(fd, 0); - if (layout == NULL) { + if (!layout) { fprintf(stderr, "could not get layout\n"); return -EINVAL; } @@ -9834,6 +11356,10 @@ static inline int get_other_mirror_ids(int fd, __u16 *ids, __u16 exclude_id) return cid.cid_count; } +#ifndef MIRROR_ID_NEG +#define MIRROR_ID_NEG 0x8000 +#endif + static inline int lfs_mirror_copy(int argc, char **argv) { int rc = CMD_HELP; @@ -9850,25 +11376,35 @@ static inline int lfs_mirror_copy(int argc, char **argv) ssize_t copied; struct ll_ioc_lease *ioc = NULL; struct ll_ioc_lease_id *resync_ioc; - struct option long_opts[] = { + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'i', .name = "read-mirror", .has_arg = required_argument }, { .val = 'o', .name = "write-mirror", .has_arg = required_argument }, { .name = NULL } }; + char cmd[PATH_MAX]; - while ((c = getopt_long(argc, argv, "i:o:", long_opts, NULL)) >= 0) { + snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]); + progname = cmd; + while ((c = getopt_long(argc, argv, "hi:o:", long_opts, NULL)) >= 0) { char *end; switch (c) { - case 'i': - read_mirror_id = strtoul(optarg, &end, 0); - if (*end != '\0' || read_mirror_id == 0) { + case 'i': { + unsigned long int id; + + errno = 0; + id = strtoul(optarg, &end, 0); + if (errno != 0 || *end != '\0' || id == 0 || + id > UINT16_MAX) { fprintf(stderr, - "%s %s: invalid read mirror ID '%s'\n", - progname, argv[0], optarg); + "%s: invalid read mirror ID '%s'\n", + progname, optarg); return rc; } + + read_mirror_id = (__u16)id; break; + } case 'o': if (!strcmp(optarg, "-1")) { /* specify all other mirrors */ @@ -9883,9 +11419,11 @@ static inline int lfs_mirror_copy(int argc, char **argv) } break; default: - fprintf(stderr, "%s: option '%s' unrecognized\n", + fprintf(stderr, "%s: unrecognized option '%s'\n", progname, argv[optind - 1]); - return -EINVAL; + fallthrough; + case 'h': + return CMD_HELP; } } @@ -9963,7 +11501,7 @@ static inline int lfs_mirror_copy(int argc, char **argv) } ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1); - if (ioc == NULL) { + if (!ioc) { fprintf(stderr, "%s %s: cannot alloc comp id array for ioc: %s\n", progname, argv[0], strerror(errno)); @@ -9973,7 +11511,7 @@ static inline int lfs_mirror_copy(int argc, char **argv) /* get stale component info */ layout = llapi_layout_get_by_fd(fd, 0); - if (layout == NULL) { + if (!layout) { fprintf(stderr, "%s %s: failed to get layout of '%s': %s\n", progname, argv[0], fname, strerror(errno)); rc = -errno; @@ -10050,6 +11588,7 @@ close_fd: return rc; } + /** * struct verify_chunk - Mirror chunk to be verified. * @chunk: [start, end) of the chunk. @@ -10108,13 +11647,13 @@ void print_chunks(const char *fname, struct verify_chunk *chunks, * Return: void. */ static inline -void print_checksums(struct verify_chunk *chunk, unsigned long *crc) +void print_checksums(struct verify_chunk *chunk, unsigned long *crc, + unsigned long long pos, unsigned long long len) { int i; fprintf(stdout, - "CRC-32 checksum value for chunk "DEXT":\n", - PEXT(&chunk->chunk)); + "CRC-32 checksum value for chunk "DEXT":\n", pos, pos + len); for (i = 0; i < chunk->mirror_count; i++) fprintf(stdout, "Mirror %u:\t%#lx\n", chunk->mirror_id[i], crc[i]); @@ -10266,8 +11805,6 @@ int lfs_mirror_prepare_chunk(struct llapi_layout *layout, goto error; } - chunks[idx].mirror_id[i] = mirror_id; - i++; if (i >= ARRAY_SIZE(chunks[idx].mirror_id)) { fprintf(stderr, "%s: mirror_id array is too small.\n", @@ -10275,8 +11812,10 @@ int lfs_mirror_prepare_chunk(struct llapi_layout *layout, rc = -EINVAL; goto error; } + chunks[idx].mirror_id[i] = mirror_id; + i++; - next: +next: rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT); if (rc < 0) { @@ -10380,7 +11919,7 @@ int lfs_mirror_verify_chunk(int fd, size_t file_size, } if (verbose) - print_checksums(chunk, crc_array); + print_checksums(chunk, crc_array, pos, buflen); /* compare CRC-32 checksum values */ for (i = 1; i < chunk->mirror_count; i++) { @@ -10468,7 +12007,8 @@ int lfs_mirror_verify_file(const char *fname, __u16 *mirror_ids, int ids_nr, goto error; } - fd = open(fname, O_DIRECT | O_RDONLY); + /* Allow mirror verify even without the key on encrypted files */ + fd = open(fname, O_DIRECT | O_RDONLY | O_FILE_ENC); if (fd < 0) { fprintf(stderr, "%s: cannot open '%s': %s.\n", progname, fname, strerror(errno)); @@ -10484,7 +12024,7 @@ int lfs_mirror_verify_file(const char *fname, __u16 *mirror_ids, int ids_nr, } layout = llapi_layout_get_by_fd(fd, 0); - if (layout == NULL) { + if (!layout) { fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n", progname, fname, strerror(errno)); rc = -errno; @@ -10613,13 +12153,14 @@ static inline int lfs_mirror_verify(int argc, char **argv) char cmd[PATH_MAX]; struct option long_opts[] = { + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'o', .name = "only", .has_arg = required_argument }, { .val = 'v', .name = "verbose", .has_arg = no_argument }, { .name = NULL } }; snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]); progname = cmd; - while ((c = getopt_long(argc, argv, "o:v", long_opts, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "ho:v", long_opts, NULL)) >= 0) { switch (c) { case 'o': rc = parse_mirror_ids(mirror_ids, @@ -10644,9 +12185,11 @@ static inline int lfs_mirror_verify(int argc, char **argv) verbose++; break; default: - fprintf(stderr, "%s: option '%s' unrecognized.\n", + fprintf(stderr, "%s: unrecognized option '%s'\n", progname, argv[optind - 1]); - rc = -EINVAL; + fallthrough; + case 'h': + rc = CMD_HELP; goto error; } } @@ -10663,7 +12206,6 @@ static inline int lfs_mirror_verify(int argc, char **argv) progname); rc = CMD_HELP; goto error; - } if (ids_nr > 0) { @@ -10738,20 +12280,22 @@ static int lfs_getsom(int argc, char **argv) enum lfs_som_type type = LFS_SOM_ATTR_ALL; int rc = 0, c; - while ((c = getopt(argc, argv, "sbf")) != -1) { + while ((c = getopt(argc, argv, "bfhs")) != -1) { switch (c) { - case 's': - type = LFS_SOM_SIZE; - break; case 'b': type = LFS_SOM_BLOCKS; break; case 'f': type = LFS_SOM_FLAGS; break; + case 's': + type = LFS_SOM_SIZE; + break; default: - fprintf(stderr, "%s: invalid option '%c'\n", - progname, optopt); + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + fallthrough; + case 'h': return CMD_HELP; } } @@ -10824,6 +12368,7 @@ static int lfs_mirror_list_commands(int argc, char **argv) static int lfs_pcc_attach(int argc, char **argv) { struct option long_opts[] = { + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'i', .name = "id", .has_arg = required_argument }, { .name = NULL } }; int c; @@ -10835,22 +12380,25 @@ static int lfs_pcc_attach(int argc, char **argv) enum lu_pcc_type type = LU_PCC_READWRITE; optind = 0; - while ((c = getopt_long(argc, argv, "i:", + while ((c = getopt_long(argc, argv, "hi:", long_opts, NULL)) != -1) { switch (c) { case 'i': + errno = 0; archive_id = strtoul(optarg, &end, 0); - if (*end != '\0' || archive_id == 0) { - fprintf(stderr, "error: %s: bad archive ID " - "'%s'\n", argv[0], optarg); + if (errno != 0 || *end != '\0' || + archive_id == 0 || archive_id > UINT32_MAX) { + fprintf(stderr, + "error: %s: bad archive ID '%s'\n", + progname, optarg); return CMD_HELP; } break; - case '?': - return CMD_HELP; default: - fprintf(stderr, "%s: option '%s' unrecognized\n", - argv[0], argv[optind - 1]); + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + fallthrough; + case 'h': return CMD_HELP; } } @@ -10870,7 +12418,7 @@ static int lfs_pcc_attach(int argc, char **argv) int rc2; path = argv[optind++]; - if (realpath(path, fullpath) == NULL) { + if (!realpath(path, fullpath)) { fprintf(stderr, "%s: could not find path '%s': %s\n", argv[0], path, strerror(errno)); if (rc == 0) @@ -10880,9 +12428,9 @@ static int lfs_pcc_attach(int argc, char **argv) rc2 = llapi_pcc_attach(fullpath, archive_id, type); if (rc2 < 0) { - fprintf(stderr, "%s: cannot attach '%s' to PCC " - "with archive ID '%u': %s\n", argv[0], - path, archive_id, strerror(-rc2)); + fprintf(stderr, + "%s: cannot attach '%s' to PCC with archive ID '%u': %s\n", + argv[0], path, archive_id, strerror(-rc2)); if (rc == 0) rc = rc2; } @@ -10893,38 +12441,41 @@ static int lfs_pcc_attach(int argc, char **argv) static int lfs_pcc_attach_fid(int argc, char **argv) { struct option long_opts[] = { + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'i', .name = "id", .has_arg = required_argument }, { .val = 'm', .name = "mnt", .has_arg = required_argument }, { .name = NULL } }; - char short_opts[] = "i:m:"; - int c; - int rc = 0; - __u32 archive_id = 0; - char *end; - const char *mntpath = NULL; - const char *fidstr; - enum lu_pcc_type type = LU_PCC_READWRITE; + int c; + int rc = 0; + __u32 archive_id = 0; + char *end; + const char *mntpath = NULL; + const char *fidstr; + enum lu_pcc_type type = LU_PCC_READWRITE; optind = 0; - while ((c = getopt_long(argc, argv, short_opts, + while ((c = getopt_long(argc, argv, "hi:m:", long_opts, NULL)) != -1) { switch (c) { case 'i': + errno = 0; archive_id = strtoul(optarg, &end, 0); - if (*end != '\0') { - fprintf(stderr, "error: %s: bad archive ID " - "'%s'\n", argv[0], optarg); + if (errno != 0 || *end != '\0' || + archive_id > UINT32_MAX) { + fprintf(stderr, + "error: %s: bad archive ID '%s'\n", + argv[0], optarg); return CMD_HELP; } break; case 'm': mntpath = optarg; break; - case '?': - return CMD_HELP; default: - fprintf(stderr, "%s: option '%s' unrecognized\n", - argv[0], argv[optind - 1]); + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + fallthrough; + case 'h': return CMD_HELP; } } @@ -10934,7 +12485,7 @@ static int lfs_pcc_attach_fid(int argc, char **argv) return CMD_HELP; } - if (mntpath == NULL) { + if (!mntpath) { fprintf(stderr, "%s: must specify Lustre mount point\n", argv[0]); return CMD_HELP; @@ -10953,9 +12504,10 @@ static int lfs_pcc_attach_fid(int argc, char **argv) rc2 = llapi_pcc_attach_fid_str(mntpath, fidstr, archive_id, type); if (rc2 < 0) { - fprintf(stderr, "%s: cannot attach '%s' on '%s' to PCC " - "with archive ID '%u': %s\n", argv[0], - fidstr, mntpath, archive_id, strerror(rc2)); + fprintf(stderr, + "%s: cannot attach '%s' on '%s' to PCC with archive ID '%u': %s\n", + argv[0], fidstr, mntpath, archive_id, + strerror(rc2)); } if (rc == 0 && rc2 < 0) rc = rc2; @@ -10966,27 +12518,27 @@ static int lfs_pcc_attach_fid(int argc, char **argv) static int lfs_pcc_detach(int argc, char **argv) { struct option long_opts[] = { + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'k', .name = "keep", .has_arg = no_argument }, { .name = NULL } }; - char short_opts[] = "k"; - int c; - int rc = 0; - const char *path; - char fullpath[PATH_MAX]; - __u32 detach_opt = PCC_DETACH_OPT_UNCACHE; + int c; + int rc = 0; + const char *path; + char fullpath[PATH_MAX]; + __u32 detach_opt = PCC_DETACH_OPT_UNCACHE; optind = 0; - while ((c = getopt_long(argc, argv, short_opts, + while ((c = getopt_long(argc, argv, "hk", long_opts, NULL)) != -1) { switch (c) { case 'k': detach_opt = PCC_DETACH_OPT_NONE; break; - case '?': - return CMD_HELP; default: - fprintf(stderr, "%s: option '%s' unrecognized\n", - argv[0], argv[optind - 1]); + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + fallthrough; + case 'h': return CMD_HELP; } } @@ -10995,7 +12547,7 @@ static int lfs_pcc_detach(int argc, char **argv) int rc2; path = argv[optind++]; - if (realpath(path, fullpath) == NULL) { + if (!realpath(path, fullpath)) { fprintf(stderr, "%s: could not find path '%s': %s\n", argv[0], path, strerror(errno)); if (rc == 0) @@ -11006,8 +12558,9 @@ static int lfs_pcc_detach(int argc, char **argv) rc2 = llapi_pcc_detach_file(fullpath, detach_opt); if (rc2 < 0) { rc2 = -errno; - fprintf(stderr, "%s: cannot detach '%s' from PCC: " - "%s\n", argv[0], path, strerror(errno)); + fprintf(stderr, + "%s: cannot detach '%s' from PCC: %s\n", + argv[0], path, strerror(errno)); if (rc == 0) rc = rc2; } @@ -11018,27 +12571,27 @@ static int lfs_pcc_detach(int argc, char **argv) static int lfs_pcc_detach_fid(int argc, char **argv) { struct option long_opts[] = { + { .val = 'h', .name = "help", .has_arg = no_argument }, { .val = 'k', .name = "keep", .has_arg = no_argument }, { .name = NULL } }; - char short_opts[] = "k"; - int c; - int rc = 0; - const char *fid; - const char *mntpath; - __u32 detach_opt = PCC_DETACH_OPT_UNCACHE; + int c; + int rc = 0; + const char *fid; + const char *mntpath; + __u32 detach_opt = PCC_DETACH_OPT_UNCACHE; optind = 0; - while ((c = getopt_long(argc, argv, short_opts, + while ((c = getopt_long(argc, argv, "hk", long_opts, NULL)) != -1) { switch (c) { case 'k': detach_opt = PCC_DETACH_OPT_NONE; break; - case '?': - return CMD_HELP; default: - fprintf(stderr, "%s: option '%s' unrecognized\n", - argv[0], argv[optind - 1]); + fprintf(stderr, "%s: unrecognized option '%s'\n", + progname, argv[optind - 1]); + fallthrough; + case 'h': return CMD_HELP; } } @@ -11052,9 +12605,9 @@ static int lfs_pcc_detach_fid(int argc, char **argv) rc2 = llapi_pcc_detach_fid_str(mntpath, fid, detach_opt); if (rc2 < 0) { - fprintf(stderr, "%s: cannot detach '%s' on '%s' " - "from PCC: %s\n", argv[0], fid, mntpath, - strerror(-rc2)); + fprintf(stderr, + "%s: cannot detach '%s' on '%s' from PCC: %s\n", + argv[0], fid, mntpath, strerror(-rc2)); if (rc == 0) rc = rc2; } @@ -11064,16 +12617,16 @@ static int lfs_pcc_detach_fid(int argc, char **argv) static int lfs_pcc_state(int argc, char **argv) { - int rc = 0; - const char *path; - char fullpath[PATH_MAX]; - struct lu_pcc_state state; + int rc = 0; + const char *path; + char fullpath[PATH_MAX]; + struct lu_pcc_state state; optind = 1; if (argc <= 1) { fprintf(stderr, "%s: must specify one or more file names\n", - argv[0]); + progname); return CMD_HELP; } @@ -11081,7 +12634,7 @@ static int lfs_pcc_state(int argc, char **argv) int rc2; path = argv[optind++]; - if (realpath(path, fullpath) == NULL) { + if (!realpath(path, fullpath)) { fprintf(stderr, "%s: could not find path '%s': %s\n", argv[0], path, strerror(errno)); if (rc == 0) @@ -11093,8 +12646,9 @@ static int lfs_pcc_state(int argc, char **argv) if (rc2 < 0) { if (rc == 0) rc = rc2; - fprintf(stderr, "%s: cannot get PCC state of '%s': " - "%s\n", argv[0], path, strerror(-rc2)); + fprintf(stderr, + "%s: cannot get PCC state of '%s': %s\n", + argv[0], path, strerror(-rc2)); continue; }