Whamcloud - gitweb
LU-10482 flr: enhance "lfs find" to add mirror options
[fs/lustre-release.git] / lustre / utils / lfs.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lustre/utils/lfs.c
33  *
34  * Author: Peter J. Braam <braam@clusterfs.com>
35  * Author: Phil Schwan <phil@clusterfs.com>
36  * Author: Robert Read <rread@clusterfs.com>
37  */
38
39 /* for O_DIRECTORY */
40 #ifndef _GNU_SOURCE
41 #define _GNU_SOURCE
42 #endif
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <inttypes.h>
47 #include <getopt.h>
48 #include <string.h>
49 #include <mntent.h>
50 #include <unistd.h>
51 #include <errno.h>
52 #include <err.h>
53 #include <pwd.h>
54 #include <grp.h>
55 #include <sys/ioctl.h>
56 #include <sys/quota.h>
57 #include <sys/time.h>
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 #include <sys/param.h>
61 #include <fcntl.h>
62 #include <dirent.h>
63 #include <time.h>
64 #include <ctype.h>
65 #include <zlib.h>
66 #include "lfs_project.h"
67
68 #include <libcfs/util/string.h>
69 #include <libcfs/util/ioctl.h>
70 #include <libcfs/util/parser.h>
71 #include <lustre/lustreapi.h>
72 #include <linux/lustre/lustre_ver.h>
73 #include <linux/lustre/lustre_param.h>
74 #include <linux/lnet/nidstr.h>
75
76 #ifndef ARRAY_SIZE
77 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
78 #endif /* !ARRAY_SIZE */
79
80 /* all functions */
81 static int lfs_find(int argc, char **argv);
82 static int lfs_getstripe(int argc, char **argv);
83 static int lfs_getdirstripe(int argc, char **argv);
84 static int lfs_setdirstripe(int argc, char **argv);
85 static int lfs_rmentry(int argc, char **argv);
86 static int lfs_osts(int argc, char **argv);
87 static int lfs_mdts(int argc, char **argv);
88 static int lfs_df(int argc, char **argv);
89 static int lfs_getname(int argc, char **argv);
90 static int lfs_check(int argc, char **argv);
91 #ifdef HAVE_SYS_QUOTA_H
92 static int lfs_setquota(int argc, char **argv);
93 static int lfs_quota(int argc, char **argv);
94 static int lfs_project(int argc, char **argv);
95 #endif
96 static int lfs_flushctx(int argc, char **argv);
97 static int lfs_cp(int argc, char **argv);
98 static int lfs_ls(int argc, char **argv);
99 static int lfs_poollist(int argc, char **argv);
100 static int lfs_changelog(int argc, char **argv);
101 static int lfs_changelog_clear(int argc, char **argv);
102 static int lfs_fid2path(int argc, char **argv);
103 static int lfs_path2fid(int argc, char **argv);
104 static int lfs_data_version(int argc, char **argv);
105 static int lfs_hsm_state(int argc, char **argv);
106 static int lfs_hsm_set(int argc, char **argv);
107 static int lfs_hsm_clear(int argc, char **argv);
108 static int lfs_hsm_action(int argc, char **argv);
109 static int lfs_hsm_archive(int argc, char **argv);
110 static int lfs_hsm_restore(int argc, char **argv);
111 static int lfs_hsm_release(int argc, char **argv);
112 static int lfs_hsm_remove(int argc, char **argv);
113 static int lfs_hsm_cancel(int argc, char **argv);
114 static int lfs_swap_layouts(int argc, char **argv);
115 static int lfs_mv(int argc, char **argv);
116 static int lfs_ladvise(int argc, char **argv);
117 static int lfs_mirror(int argc, char **argv);
118 static int lfs_mirror_list_commands(int argc, char **argv);
119 static int lfs_list_commands(int argc, char **argv);
120 static inline int lfs_mirror_resync(int argc, char **argv);
121 static inline int lfs_mirror_verify(int argc, char **argv);
122
123 enum setstripe_origin {
124         SO_SETSTRIPE,
125         SO_MIGRATE,
126         SO_MIRROR_CREATE,
127         SO_MIRROR_EXTEND,
128         SO_MIRROR_SPLIT,
129 };
130 static int lfs_setstripe_internal(int argc, char **argv,
131                                   enum setstripe_origin opc);
132
133 static inline int lfs_setstripe(int argc, char **argv)
134 {
135         return lfs_setstripe_internal(argc, argv, SO_SETSTRIPE);
136 }
137 static inline int lfs_setstripe_migrate(int argc, char **argv)
138 {
139         return lfs_setstripe_internal(argc, argv, SO_MIGRATE);
140 }
141 static inline int lfs_mirror_create(int argc, char **argv)
142 {
143         return lfs_setstripe_internal(argc, argv, SO_MIRROR_CREATE);
144 }
145 static inline int lfs_mirror_extend(int argc, char **argv)
146 {
147         return lfs_setstripe_internal(argc, argv, SO_MIRROR_EXTEND);
148 }
149 static inline int lfs_mirror_split(int argc, char **argv)
150 {
151         return lfs_setstripe_internal(argc, argv, SO_MIRROR_SPLIT);
152 }
153
154 /* Setstripe and migrate share mostly the same parameters */
155 #define SSM_CMD_COMMON(cmd) \
156         "usage: "cmd" [--component-end|-E <comp_end>]\n"                \
157         "                 [--stripe-count|-c <stripe_count>]\n"         \
158         "                 [--stripe-index|-i <start_ost_idx>]\n"        \
159         "                 [--stripe-size|-S <stripe_size>]\n"           \
160         "                 [--layout|-L <pattern>]\n"            \
161         "                 [--pool|-p <pool_name>]\n"                    \
162         "                 [--ost|-o <ost_indices>]\n"
163
164 #define SSM_HELP_COMMON \
165         "\tstripe_count: Number of OSTs to stripe over (0=fs default, -1 all)\n" \
166         "\tstart_ost_idx: OST index of first stripe (-1=default round robin)\n"\
167         "\tstripe_size:  Number of bytes on each OST (0=fs default)\n" \
168         "\t              Can be specified with K, M or G (for KB, MB, GB\n" \
169         "\t              respectively)\n"                               \
170         "\tpool_name:    Name of OST pool to use (default none)\n"      \
171         "\tlayout:       stripe pattern type: raid0, mdt (default raid0)\n"\
172         "\tost_indices:  List of OST indices, can be repeated multiple times\n"\
173         "\t              Indices be specified in a format of:\n"        \
174         "\t                -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n"        \
175         "\t              Or:\n"                                         \
176         "\t                -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n"  \
177         "\t              If --pool is set with --ost, then the OSTs\n"  \
178         "\t              must be the members of the pool.\n"            \
179         "\tcomp_end:     Extent end of component, start after previous end.\n"\
180         "\t              Can be specified with K, M or G (for KB, MB, GB\n" \
181         "\t              respectively, -1 for EOF). Must be a multiple of\n"\
182         "\t              stripe_size.\n"
183
184 #define MIRROR_CREATE_HELP                                                     \
185         "\tmirror_count: Number of mirrors to be created with the upcoming\n"  \
186         "\t              setstripe layout options\n"                           \
187         "\t              It defaults to 1 if not specified; if specified,\n"   \
188         "\t              it must follow the option without a space.\n"         \
189         "\t              The option can also be repeated multiple times to\n"  \
190         "\t              separate mirrors that have different layouts.\n"      \
191         "\tsetstripe options: Mirror layout\n"                                 \
192         "\t              It can be a plain layout or a composite layout.\n"    \
193         "\t              If not specified, the stripe options inherited\n"     \
194         "\t              from the previous component will be used.\n"          \
195         "\tparent:       Use default stripe options from parent directory\n"   \
196         "\tflags:        set flags to the component of the current mirror.\n"  \
197         "\t              Only \"prefer\" flag is supported so far.\n"
198
199 #define MIRROR_EXTEND_HELP                                                     \
200         MIRROR_CREATE_HELP                                                     \
201         "\tvictim_file:  The layout of victim_file will be split and used\n"   \
202         "\t              as a mirror added to the mirrored file.\n"            \
203         "\tno-verify:    This option indicates not to verify the mirror(s)\n"  \
204         "\t              from victim file(s) in case the victim file(s)\n"     \
205         "\t              contains the same data as the original mirrored\n"    \
206         "\t              file.\n"
207
208 #define MIRROR_EXTEND_USAGE                                                    \
209         "                 <--mirror-count|-N[mirror_count]>\n"                 \
210         "                 [setstripe options|--parent|-f <victim_file>]\n"     \
211         "                 [--no-verify]\n"
212
213 #define SETSTRIPE_USAGE                                                 \
214         SSM_CMD_COMMON("setstripe")                                     \
215         MIRROR_EXTEND_USAGE                                             \
216         "                 <directory|filename>\n"                       \
217         SSM_HELP_COMMON                                                 \
218         MIRROR_EXTEND_HELP
219
220 #define MIGRATE_USAGE                                                   \
221         SSM_CMD_COMMON("migrate  ")                                     \
222         "                 [--block|-b]\n"                               \
223         "                 [--non-block|-n]\n"                           \
224         "                 <filename>\n"                                 \
225         SSM_HELP_COMMON                                                 \
226         "\n"                                                            \
227         "\tblock:        Block file access during data migration (default)\n" \
228         "\tnon-block:    Abort migrations if concurrent access is detected\n" \
229
230 #define SETDIRSTRIPE_USAGE                                      \
231         "               [--mdt-count|-c stripe_count>\n"        \
232         "               [--mdt-index|-i mdt_index]\n"           \
233         "               [--mdt-hash|-H mdt_hash]\n"             \
234         "               [--default|-D] [--mode|-m mode] <dir>\n"        \
235         "\tstripe_count: stripe count of the striped directory\n"       \
236         "\tmdt_index: MDT index of first stripe\n"                      \
237         "\tmdt_hash:  hash type of the striped directory. mdt types:\n" \
238         "       fnv_1a_64 FNV-1a hash algorithm (default)\n"            \
239         "       all_char  sum of characters % MDT_COUNT (not recommended)\n" \
240         "\tdefault_stripe: set default dirstripe of the directory\n"    \
241         "\tmode: the mode of the directory\n"
242
243 /**
244  * command_t mirror_cmdlist - lfs mirror commands.
245  */
246 command_t mirror_cmdlist[] = {
247         { .pc_name = "create", .pc_func = lfs_mirror_create,
248           .pc_help = "Create a mirrored file.\n"
249                 "usage: lfs mirror create "
250                 "<--mirror-count|-N[mirror_count]> "
251                 "[setstripe options|--parent] ... <filename|directory>\n"
252           MIRROR_CREATE_HELP },
253         { .pc_name = "extend", .pc_func = lfs_mirror_extend,
254           .pc_help = "Extend a mirrored file.\n"
255                 "usage: lfs mirror extend "
256                 "<--mirror-count|-N[mirror_count]> [--no-verify] "
257                 "[setstripe options|--parent|-f <victim_file>] ... <filename>\n"
258           MIRROR_EXTEND_HELP },
259         { .pc_name = "split", .pc_func = lfs_mirror_split,
260           .pc_help = "Split a mirrored file.\n"
261         "usage: lfs mirror split <--mirror-id <mirror_id>> [--destroy|-d] "
262         "[-f <new_file>] <mirrored file>\n"
263         "\tmirror_id:    The numerical unique identifier for a mirror. It\n"
264         "\t              can be fetched by lfs getstripe command.\n"
265         "\tnew_file:     This option indicates the layout of the split\n"
266         "\t              mirror will be stored into. If not specified,\n"
267         "\t              a new file named <mirrored_file>.mirror~<mirror_id>\n"
268         "\t              will be used.\n" },
269         { .pc_name = "resync", .pc_func = lfs_mirror_resync,
270           .pc_help = "Resynchronizes out-of-sync mirrored file(s).\n"
271                 "usage: lfs mirror resync [--only <mirror_id[,...]>] "
272                 "<mirrored file> [<mirrored file2>...]\n"},
273         { .pc_name = "verify", .pc_func = lfs_mirror_verify,
274           .pc_help = "Verify mirrored file(s).\n"
275                 "usage: lfs mirror verify "
276                 "[--only <mirror_id,mirror_id2[,...]>] "
277                 "[--verbose|-v] <mirrored_file> [<mirrored_file2> ...]\n"},
278         { .pc_name = "--list-commands", .pc_func = lfs_mirror_list_commands,
279           .pc_help = "list commands supported by lfs mirror"},
280         { .pc_name = "help", .pc_func = Parser_help, .pc_help = "help" },
281         { .pc_name = "exit", .pc_func = Parser_quit, .pc_help = "quit" },
282         { .pc_name = "quit", .pc_func = Parser_quit, .pc_help = "quit" },
283         { .pc_help = NULL }
284 };
285
286 /* all available commands */
287 command_t cmdlist[] = {
288         {"setstripe", lfs_setstripe, 0,
289          "To create a file with specified striping/composite layout, or\n"
290          "create/replace the default layout on an existing directory:\n"
291          SSM_CMD_COMMON("setstripe")
292          "                 <directory|filename>\n"
293          " or\n"
294          "To add component(s) to an existing composite file:\n"
295          SSM_CMD_COMMON("setstripe --component-add")
296          SSM_HELP_COMMON
297          "To totally delete the default striping from an existing directory:\n"
298          "usage: setstripe -d <directory>\n"
299          " or\n"
300          "To delete the last component(s) from an existing composite file\n"
301          "(note that this will also delete any data in those components):\n"
302          "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
303          "                               [--component-flags|-F <comp_flags>]\n"
304          "                               <filename>\n"
305          "\tcomp_id:     Unique component ID to delete\n"
306          "\tcomp_flags:  'init' indicating all instantiated components\n"
307          "\t             '^init' indicating all uninstantiated components\n"
308          "\t-I and -F cannot be specified at the same time\n"},
309         {"getstripe", lfs_getstripe, 0,
310          "To list the layout pattern for a given file or files in a\n"
311          "directory or recursively for all files in a directory tree.\n"
312          "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
313          "                 [--stripe-count|-c] [--stripe-index|-i] [--fid|-F]\n"
314          "                 [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
315          "                 [--mdt-index|-m] [--recursive|-r] [--raw|-R]\n"
316          "                 [--layout|-L] [--generation|-g] [--yaml|-y]\n"
317          "                 [--component-id[=comp_id]|-I[comp_id]]\n"
318          "                 [--component-flags[=comp_flags]]\n"
319          "                 [--component-count]\n"
320          "                 [--component-start[=[+-]comp_start]]\n"
321          "                 [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
322          "                 <directory|filename> ..."},
323         {"setdirstripe", lfs_setdirstripe, 0,
324          "To create a striped directory on a specified MDT. This can only\n"
325          "be done on MDT0 with the right of administrator.\n"
326          "usage: setdirstripe [OPTION] <directory>\n"
327          SETDIRSTRIPE_USAGE},
328         {"getdirstripe", lfs_getdirstripe, 0,
329          "To list the layout pattern info for a given directory\n"
330          "or recursively for all directories in a directory tree.\n"
331          "usage: getdirstripe [--mdt-count|-c] [--mdt-index|-m|-i]\n"
332          "                    [--mdt-hash|-H] [--obd|-O <uuid>]\n"
333          "                    [--recursive|-r] [--yaml|-y]\n"
334          "                    [--default|-D] <dir> ..."},
335         {"mkdir", lfs_setdirstripe, 0,
336          "To create a striped directory on a specified MDT. This can only\n"
337          "be done on MDT0 with the right of administrator.\n"
338          "usage: mkdir [OPTION] <directory>\n"
339          SETDIRSTRIPE_USAGE},
340         {"rm_entry", lfs_rmentry, 0,
341          "To remove the name entry of the remote directory. Note: This\n"
342          "command will only delete the name entry, i.e. the remote directory\n"
343          "will become inaccessable after this command. This can only be done\n"
344          "by the administrator\n"
345          "usage: rm_entry <dir>\n"},
346         {"pool_list", lfs_poollist, 0,
347          "List pools or pool OSTs\n"
348          "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
349         {"find", lfs_find, 0,
350          "find files matching given attributes recursively in directory tree.\n"
351          "usage: find <directory|filename> ...\n"
352          "     [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
353          "     [[!] --mtime|-M [+-]N] [--maxdepth|-D N]\n"
354          "     [[!] --mdt-index|--mdt|-m <uuid|index,...>]\n"
355          "     [[!] --name|-n <pattern>] [[!] --ost|-O <uuid|index,...>]\n"
356          "     [--print|-P] [--print0|-0] [[!] --size|-s [+-]N[bkMGTPE]]\n"
357          "     [[!] --stripe-count|-c [+-]<stripes>]\n"
358          "     [[!] --stripe-index|-i <index,...>]\n"
359          "     [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
360          "     [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
361          "     [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
362          "     [[!] --projid <projid>]\n"
363          "     [[!] --layout|-L released,raid0,mdt]\n"
364          "     [[!] --component-count [+-]<comp_cnt>]\n"
365          "     [[!] --component-start [+-]N[kMGTPE]]\n"
366          "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
367          "     [[!] --component-flags <comp_flags>]\n"
368          "     [[!] --mirror-count|-N [+-]<n>]\n"
369          "     [[!] --mirror-state <[^]state>]\n"
370          "     [[!] --mdt-count|-T [+-]<stripes>]\n"
371          "     [[!] --mdt-hash|-H <hashtype>\n"
372          "\t !: used before an option indicates 'NOT' requested attribute\n"
373          "\t -: used before a value indicates less than requested value\n"
374          "\t +: used before a value indicates more than requested value\n"
375          "\thashtype:   hash type of the striped directory.\n"
376          "\t            fnv_1a_64 FNV-1a hash algorithm\n"
377          "\t            all_char  sum of characters % MDT_COUNT\n"},
378         {"check", lfs_check, 0,
379          "Display the status of MDS or OSTs (as specified in the command)\n"
380          "or all the servers (MDS and OSTs).\n"
381          "usage: check <osts|mds|servers>"},
382         {"osts", lfs_osts, 0, "list OSTs connected to client "
383          "[for specified path only]\n" "usage: osts [path]"},
384         {"mdts", lfs_mdts, 0, "list MDTs connected to client "
385          "[for specified path only]\n" "usage: mdts [path]"},
386         {"df", lfs_df, 0,
387          "report filesystem disk space usage or inodes usage"
388          "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
389          "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
390         {"getname", lfs_getname, 0, "list instances and specified mount points "
391          "[for specified path only]\n"
392          "Usage: getname [-h]|[path ...] "},
393 #ifdef HAVE_SYS_QUOTA_H
394         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
395          "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
396          "                -b <block-softlimit> -B <block-hardlimit>\n"
397          "                -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
398          "       setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
399          "                [--block-softlimit <block-softlimit>]\n"
400          "                [--block-hardlimit <block-hardlimit>]\n"
401          "                [--inode-softlimit <inode-softlimit>]\n"
402          "                [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
403          "       setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
404          "                [--block-grace <block-grace>]\n"
405          "                [--inode-grace <inode-grace>] <filesystem>\n"
406          "       -b can be used instead of --block-softlimit/--block-grace\n"
407          "       -B can be used instead of --block-hardlimit\n"
408          "       -i can be used instead of --inode-softlimit/--inode-grace\n"
409          "       -I can be used instead of --inode-hardlimit\n\n"
410          "Note: The total quota space will be split into many qunits and\n"
411          "      balanced over all server targets, the minimal qunit size is\n"
412          "      1M bytes for block space and 1K inodes for inode space.\n\n"
413          "      Quota space rebalancing process will stop when this mininum\n"
414          "      value is reached. As a result, quota exceeded can be returned\n"
415          "      while many targets still have 1MB or 1K inodes of spare\n"
416          "      quota space."},
417         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
418          "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
419                        "<ost_idx>]\n"
420          "             [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
421          "       quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
422         {"project", lfs_project, 0,
423          "Change or list project attribute for specified file or directory.\n"
424          "usage: project [-d|-r] <file|directory...>\n"
425          "         list project ID and flags on file(s) or directories\n"
426          "       project [-p id] [-s] [-r] <file|directory...>\n"
427          "         set project ID and/or inherit flag for specified file(s) or directories\n"
428          "       project -c [-d|-r [-p id] [-0]] <file|directory...>\n"
429          "         check project ID and flags on file(s) or directories, print outliers\n"
430          "       project -C [-r] [-k] <file|directory...>\n"
431          "         clear the project inherit flag and ID on the file or directory\n"
432         },
433 #endif
434         {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
435          "usage: flushctx [-k] [mountpoint...]"},
436         {"cp", lfs_cp, 0,
437          "Remote user copy files and directories.\n"
438          "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
439         {"ls", lfs_ls, 0,
440          "Remote user list directory contents.\n"
441          "usage: ls [OPTION]... [FILE]..."},
442         {"changelog", lfs_changelog, 0,
443          "Show the metadata changes on an MDT."
444          "\nusage: changelog <mdtname> [startrec [endrec]]"},
445         {"changelog_clear", lfs_changelog_clear, 0,
446          "Indicate that old changelog records up to <endrec> are no longer of "
447          "interest to consumer <id>, allowing the system to free up space.\n"
448          "An <endrec> of 0 means all records.\n"
449          "usage: changelog_clear <mdtname> <id> <endrec>"},
450         {"fid2path", lfs_fid2path, 0,
451          "Resolve the full path(s) for given FID(s). For a specific hardlink "
452          "specify link number <linkno>.\n"
453         /* "For a historical link name, specify changelog record <recno>.\n" */
454          "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
455                 /* [ --rec <recno> ] */ },
456         {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
457          "usage: path2fid [--parents] <path> ..."},
458         {"data_version", lfs_data_version, 0, "Display file data version for "
459          "a given path.\n" "usage: data_version -[n|r|w] <path>"},
460         {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
461          "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
462         {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
463          "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
464          "[--archived] [--lost] [--archive-id NUM] <file> ..."},
465         {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
466          "files.\n"
467          "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
468          "[--archived] [--lost] <file> ..."},
469         {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
470          "given files.\n" "usage: hsm_action <file> ..."},
471         {"hsm_archive", lfs_hsm_archive, 0,
472          "Archive file to external storage.\n"
473          "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
474          "<file> ..."},
475         {"hsm_restore", lfs_hsm_restore, 0,
476          "Restore file from external storage.\n"
477          "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
478         {"hsm_release", lfs_hsm_release, 0,
479          "Release files from Lustre.\n"
480          "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
481         {"hsm_remove", lfs_hsm_remove, 0,
482          "Remove file copy from external storage.\n"
483          "usage: hsm_remove [--filelist FILELIST] [--data DATA] "
484          "[--archive NUM]\n"
485          "                  (FILE [FILE ...] | "
486          "--mntpath MOUNTPATH FID [FID ...])\n"
487          "\n"
488          "Note: To remove an archived copy of a file already deleted from a "
489          "Lustre FS, the\n"
490          "--mntpath option and a list of FIDs must be specified"
491         },
492         {"hsm_cancel", lfs_hsm_cancel, 0,
493          "Cancel requests related to specified files.\n"
494          "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
495         {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
496          "usage: swap_layouts <path1> <path2>"},
497         {"migrate", lfs_setstripe_migrate, 0,
498          "migrate a directory between MDTs.\n"
499          "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
500          "<directory>\n"
501          "\tmdt_idx:      index of the destination MDT\n"
502          "\n"
503          "migrate file objects from one OST "
504          "layout\nto another (may be not safe with concurent writes).\n"
505          "usage: migrate  "
506          "[--stripe-count|-c] <stripe_count>\n"
507          "              [--stripe-index|-i] <start_ost_index>\n"
508          "              [--stripe-size|-S] <stripe_size>\n"
509          "              [--pool|-p] <pool_name>\n"
510          "              [--ost|-o] <ost_indices>\n"
511          "              [--block|-b]\n"
512          "              [--non-block|-n]\n"
513          "              <file|directory>\n"
514          "\tstripe_count:     number of OSTs to stripe a file over\n"
515          "\tstripe_ost_index: index of the first OST to stripe a file over\n"
516          "\tstripe_size:      number of bytes to store before moving to the next OST\n"
517          "\tpool_name:        name of the predefined pool of OSTs\n"
518          "\tost_indices:      OSTs to stripe over, in order\n"
519          "\tblock:            wait for the operation to return before continuing\n"
520          "\tnon-block:        do not wait for the operation to return.\n"},
521         {"mv", lfs_mv, 0,
522          "To move directories between MDTs. This command is deprecated, "
523          "use \"migrate\" instead.\n"
524          "usage: mv <directory|filename> [--mdt-index|-m] <mdt_index> "
525          "[--verbose|-v]\n"},
526         {"ladvise", lfs_ladvise, 0,
527          "Provide servers with advice about access patterns for a file.\n"
528          "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
529          "               [--background|-b] [--unset|-u]\n\n"
530          "               {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
531          "               {[--mode|-m [READ,WRITE]}\n"
532          "               <file> ...\n"},
533         {"mirror", lfs_mirror, mirror_cmdlist,
534          "lfs commands used to manage files with mirrored components:\n"
535          "lfs mirror create - create a mirrored file or directory\n"
536          "lfs mirror extend - add mirror(s) to an existing file\n"
537          "lfs mirror split  - split a mirror from an existing mirrored file\n"
538          "lfs mirror resync - resynchronize out-of-sync mirrored file(s)\n"
539          "lfs mirror verify - verify mirrored file(s)\n"},
540         {"help", Parser_help, 0, "help"},
541         {"exit", Parser_quit, 0, "quit"},
542         {"quit", Parser_quit, 0, "quit"},
543         {"--version", Parser_version, 0,
544          "output build version of the utility and exit"},
545         {"--list-commands", lfs_list_commands, 0,
546          "list commands supported by the utility and exit"},
547         { 0, 0, 0, NULL }
548 };
549
550
551 static int check_hashtype(const char *hashtype)
552 {
553         int i;
554
555         for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
556                 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
557                         return i;
558
559         return 0;
560 }
561
562
563 static const char *error_loc = "syserror";
564
565 enum {
566         MIGRATION_NONBLOCK      = 1 << 0,
567         MIGRATION_MIRROR        = 1 << 1,
568 };
569
570 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
571                                 struct llapi_layout *layout);
572
573 static int
574 migrate_open_files(const char *name, const struct llapi_stripe_param *param,
575                    struct llapi_layout *layout, int *fd_src, int *fd_tgt)
576 {
577         int                      fd = -1;
578         int                      fdv = -1;
579         int                      mdt_index;
580         int                      random_value;
581         char                     parent[PATH_MAX];
582         char                     volatile_file[PATH_MAX];
583         char                    *ptr;
584         int                      rc;
585         struct stat              st;
586         struct stat              stv;
587
588         if (param == NULL && layout == NULL) {
589                 error_loc = "layout information";
590                 return -EINVAL;
591         }
592
593         /* search for file directory pathname */
594         if (strlen(name) > sizeof(parent) - 1) {
595                 error_loc = "source file name";
596                 return -ERANGE;
597         }
598
599         strncpy(parent, name, sizeof(parent));
600         ptr = strrchr(parent, '/');
601         if (ptr == NULL) {
602                 if (getcwd(parent, sizeof(parent)) == NULL) {
603                         error_loc = "getcwd";
604                         return -errno;
605                 }
606         } else {
607                 if (ptr == parent) /* leading '/' */
608                         ptr = parent + 1;
609                 *ptr = '\0';
610         }
611
612         /* open file, direct io */
613         /* even if the file is only read, WR mode is nedeed to allow
614          * layout swap on fd */
615         fd = open(name, O_RDWR | O_DIRECT);
616         if (fd < 0) {
617                 rc = -errno;
618                 error_loc = "cannot open source file";
619                 return rc;
620         }
621
622         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
623         if (rc < 0) {
624                 error_loc = "cannot get MDT index";
625                 goto out;
626         }
627
628         do {
629                 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
630                 mode_t open_mode = S_IRUSR | S_IWUSR;
631
632                 random_value = random();
633                 rc = snprintf(volatile_file, sizeof(volatile_file),
634                               "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
635                               mdt_index, random_value);
636                 if (rc >= sizeof(volatile_file)) {
637                         rc = -ENAMETOOLONG;
638                         break;
639                 }
640
641                 /* create, open a volatile file, use caching (ie no directio) */
642                 if (param != NULL)
643                         fdv = llapi_file_open_param(volatile_file, open_flags,
644                                                     open_mode, param);
645                 else
646                         fdv = lfs_component_create(volatile_file, open_flags,
647                                                    open_mode, layout);
648         } while (fdv < 0 && (rc = fdv) == -EEXIST);
649
650         if (rc < 0) {
651                 error_loc = "cannot create volatile file";
652                 goto out;
653         }
654
655         /* In case the MDT does not support creation of volatile files
656          * we should try to unlink it. */
657         (void)unlink(volatile_file);
658
659         /* Not-owner (root?) special case.
660          * Need to set owner/group of volatile file like original.
661          * This will allow to pass related check during layout_swap.
662          */
663         rc = fstat(fd, &st);
664         if (rc != 0) {
665                 rc = -errno;
666                 error_loc = "cannot stat source file";
667                 goto out;
668         }
669
670         rc = fstat(fdv, &stv);
671         if (rc != 0) {
672                 rc = -errno;
673                 error_loc = "cannot stat volatile";
674                 goto out;
675         }
676
677         if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
678                 rc = fchown(fdv, st.st_uid, st.st_gid);
679                 if (rc != 0) {
680                         rc = -errno;
681                         error_loc = "cannot change ownwership of volatile";
682                         goto out;
683                 }
684         }
685
686 out:
687         if (rc < 0) {
688                 if (fd > 0)
689                         close(fd);
690                 if (fdv > 0)
691                         close(fdv);
692         } else {
693                 *fd_src = fd;
694                 *fd_tgt = fdv;
695                 error_loc = NULL;
696         }
697         return rc;
698 }
699
700 static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int))
701 {
702         struct llapi_layout *layout;
703         size_t   buf_size = 4 * 1024 * 1024;
704         void    *buf = NULL;
705         ssize_t  rsize = -1;
706         ssize_t  wsize = 0;
707         size_t   rpos = 0;
708         size_t   wpos = 0;
709         off_t    bufoff = 0;
710         int      rc;
711
712         layout = llapi_layout_get_by_fd(fd_src, 0);
713         if (layout != NULL) {
714                 uint64_t stripe_size;
715
716                 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
717                 if (rc == 0)
718                         buf_size = stripe_size;
719
720                 llapi_layout_free(layout);
721         }
722
723         /* Use a page-aligned buffer for direct I/O */
724         rc = posix_memalign(&buf, getpagesize(), buf_size);
725         if (rc != 0)
726                 return -rc;
727
728         while (1) {
729                 /* read new data only if we have written all
730                  * previously read data */
731                 if (wpos == rpos) {
732                         if (check_file) {
733                                 rc = check_file(fd_src);
734                                 if (rc < 0)
735                                         break;
736                         }
737
738                         rsize = read(fd_src, buf, buf_size);
739                         if (rsize < 0) {
740                                 rc = -errno;
741                                 break;
742                         }
743                         rpos += rsize;
744                         bufoff = 0;
745                 }
746                 /* eof ? */
747                 if (rsize == 0)
748                         break;
749
750                 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
751                 if (wsize < 0) {
752                         rc = -errno;
753                         break;
754                 }
755                 wpos += wsize;
756                 bufoff += wsize;
757         }
758
759         if (rc == 0) {
760                 rc = fsync(fd_dst);
761                 if (rc < 0)
762                         rc = -errno;
763         }
764
765         free(buf);
766         return rc;
767 }
768
769 static int migrate_copy_timestamps(int fd, int fdv)
770 {
771         struct stat st;
772
773         if (fstat(fd, &st) == 0) {
774                 struct timeval tv[2] = {
775                         {.tv_sec = st.st_atime},
776                         {.tv_sec = st.st_mtime}
777                 };
778
779                 return futimes(fdv, tv);
780         }
781
782         return -errno;
783 }
784
785 static int migrate_block(int fd, int fdv)
786 {
787         __u64   dv1;
788         int     gid;
789         int     rc;
790         int     rc2;
791
792         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
793         if (rc < 0) {
794                 error_loc = "cannot get dataversion";
795                 return rc;
796         }
797
798         do
799                 gid = random();
800         while (gid == 0);
801
802         /* The grouplock blocks all concurrent accesses to the file.
803          * It has to be taken after llapi_get_data_version as it would
804          * block it too. */
805         rc = llapi_group_lock(fd, gid);
806         if (rc < 0) {
807                 error_loc = "cannot get group lock";
808                 return rc;
809         }
810
811         rc = migrate_copy_data(fd, fdv, NULL);
812         if (rc < 0) {
813                 error_loc = "data copy failed";
814                 goto out_unlock;
815         }
816
817         /* Make sure we keep original atime/mtime values */
818         rc = migrate_copy_timestamps(fd, fdv);
819         if (rc < 0) {
820                 error_loc = "timestamp copy failed";
821                 goto out_unlock;
822         }
823
824         /* swap layouts
825          * for a migration we need to check data version on file did
826          * not change.
827          *
828          * Pass in gid=0 since we already own grouplock. */
829         rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
830                                            SWAP_LAYOUTS_CHECK_DV1);
831         if (rc == -EAGAIN) {
832                 error_loc = "file changed";
833                 goto out_unlock;
834         } else if (rc < 0) {
835                 error_loc = "cannot swap layout";
836                 goto out_unlock;
837         }
838
839 out_unlock:
840         rc2 = llapi_group_unlock(fd, gid);
841         if (rc2 < 0 && rc == 0) {
842                 error_loc = "unlock group lock";
843                 rc = rc2;
844         }
845
846         return rc;
847 }
848
849 /**
850  * Internal helper for migrate_copy_data(). Check lease and report error if
851  * need be.
852  *
853  * \param[in]  fd           File descriptor on which to check the lease.
854  *
855  * \retval 0       Migration can keep on going.
856  * \retval -errno  Error occurred, abort migration.
857  */
858 static int check_lease(int fd)
859 {
860         int rc;
861
862         rc = llapi_lease_check(fd);
863         if (rc > 0)
864                 return 0; /* llapi_check_lease returns > 0 on success. */
865
866         return -EBUSY;
867 }
868
869 static int migrate_nonblock(int fd, int fdv)
870 {
871         __u64   dv1;
872         __u64   dv2;
873         int     rc;
874
875         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
876         if (rc < 0) {
877                 error_loc = "cannot get data version";
878                 return rc;
879         }
880
881         rc = migrate_copy_data(fd, fdv, check_lease);
882         if (rc < 0) {
883                 error_loc = "data copy failed";
884                 return rc;
885         }
886
887         rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
888         if (rc != 0) {
889                 error_loc = "cannot get data version";
890                 return rc;
891         }
892
893         if (dv1 != dv2) {
894                 rc = -EAGAIN;
895                 error_loc = "source file changed";
896                 return rc;
897         }
898
899         /* Make sure we keep original atime/mtime values */
900         rc = migrate_copy_timestamps(fd, fdv);
901         if (rc < 0) {
902                 error_loc = "timestamp copy failed";
903                 return rc;
904         }
905
906         return 0;
907 }
908
909 static int lfs_component_set(char *fname, int comp_id,
910                              __u32 flags, __u32 neg_flags)
911 {
912         __u32 ids[2];
913         __u32 flags_array[2];
914         size_t count = 0;
915         int rc;
916
917         if (flags) {
918                 ids[count] = comp_id;
919                 flags_array[count] = flags;
920                 ++count;
921         }
922
923         if (neg_flags) {
924                 ids[count] = comp_id;
925                 flags_array[count] = neg_flags | LCME_FL_NEG;
926                 ++count;
927         }
928
929         rc = llapi_layout_file_comp_set(fname, ids, flags_array, count);
930         if (rc)
931                 fprintf(stderr,
932                         "%s: cannot change the flags of component '%#x' of file '%s': %x / ^(%x)\n",
933                         progname, comp_id, fname, flags, neg_flags);
934
935         return rc;
936 }
937
938 static int lfs_component_del(char *fname, __u32 comp_id,
939                              __u32 flags, __u32 neg_flags)
940 {
941         int     rc = 0;
942
943         if (flags && neg_flags)
944                 return -EINVAL;
945
946         if (!flags && neg_flags)
947                 flags = neg_flags | LCME_FL_NEG;
948
949         if ((flags && comp_id) || (!flags && !comp_id))
950                 return -EINVAL;
951
952         /* LCME_FL_INIT is the only supported flag in PFL */
953         if (flags) {
954                 if (flags & ~LCME_KNOWN_FLAGS) {
955                         fprintf(stderr,
956                                 "%s setstripe: unknown flags %#x\n",
957                                 progname, flags);
958                         return -EINVAL;
959                 }
960         } else if (comp_id > LCME_ID_MAX) {
961                 fprintf(stderr, "%s setstripe: invalid component id %u\n",
962                         progname, comp_id);
963                 return -EINVAL;
964         }
965
966         rc = llapi_layout_file_comp_del(fname, comp_id, flags);
967         if (rc)
968                 fprintf(stderr,
969                         "%s setstripe: cannot delete component %#x from '%s': %s\n",
970                         progname, comp_id, fname, strerror(errno));
971         return rc;
972 }
973
974 static int lfs_component_add(char *fname, struct llapi_layout *layout)
975 {
976         int     rc;
977
978         if (layout == NULL)
979                 return -EINVAL;
980
981         rc = llapi_layout_file_comp_add(fname, layout);
982         if (rc)
983                 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
984                         fname, strerror(errno));
985         return rc;
986 }
987
988 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
989                                 struct llapi_layout *layout)
990 {
991         struct stat     st;
992         int     fd;
993
994         if (layout == NULL)
995                 return -EINVAL;
996
997         fd = lstat(fname, &st);
998         if (fd == 0 && S_ISDIR(st.st_mode))
999                 open_flags = O_DIRECTORY | O_RDONLY;
1000
1001         fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
1002         if (fd < 0)
1003                 fprintf(stderr, "%s: cannot %s '%s': %s\n", progname,
1004                         S_ISDIR(st.st_mode) ?
1005                                 "set default composite layout for" :
1006                                 "create composite file",
1007                         fname, strerror(errno));
1008         return fd;
1009 }
1010
1011 static int lfs_migrate(char *name, __u64 migration_flags,
1012                        struct llapi_stripe_param *param,
1013                        struct llapi_layout *layout)
1014 {
1015         int fd = -1;
1016         int fdv = -1;
1017         int rc;
1018
1019         rc = migrate_open_files(name, param, layout, &fd, &fdv);
1020         if (rc < 0)
1021                 goto out;
1022
1023         if (!(migration_flags & MIGRATION_NONBLOCK)) {
1024                 /* Blocking mode (forced if servers do not support file lease).
1025                  * It is also the default mode, since we cannot distinguish
1026                  * between a broken lease and a server that does not support
1027                  * atomic swap/close (LU-6785) */
1028                 rc = migrate_block(fd, fdv);
1029                 goto out;
1030         }
1031
1032         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1033         if (rc < 0) {
1034                 error_loc = "cannot get lease";
1035                 goto out;
1036         }
1037
1038         rc = migrate_nonblock(fd, fdv);
1039         if (rc < 0) {
1040                 llapi_lease_release(fd);
1041                 goto out;
1042         }
1043
1044         /* Atomically put lease, swap layouts and close.
1045          * for a migration we need to check data version on file did
1046          * not change. */
1047         rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
1048         if (rc < 0) {
1049                 error_loc = "cannot swap layout";
1050                 goto out;
1051         }
1052
1053 out:
1054         if (fd >= 0)
1055                 close(fd);
1056
1057         if (fdv >= 0)
1058                 close(fdv);
1059
1060         if (rc < 0)
1061                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1062                         progname, name, error_loc, strerror(-rc));
1063         return rc;
1064 }
1065
1066 static int comp_str2flags(char *string, __u32 *flags, __u32 *neg_flags)
1067 {
1068         char *name;
1069
1070         if (string == NULL)
1071                 return -EINVAL;
1072
1073         *flags = 0;
1074         *neg_flags = 0;
1075         for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1076                 bool found = false;
1077                 int i;
1078
1079                 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1080                         __u32 comp_flag = comp_flags_table[i].cfn_flag;
1081                         const char *comp_name = comp_flags_table[i].cfn_name;
1082
1083                         if (strcmp(name, comp_name) == 0) {
1084                                 *flags |= comp_flag;
1085                                 found = true;
1086                         } else if (strncmp(name, "^", 1) == 0 &&
1087                                    strcmp(name + 1, comp_name) == 0) {
1088                                 *neg_flags |= comp_flag;
1089                                 found = true;
1090                         }
1091                 }
1092                 if (!found) {
1093                         llapi_printf(LLAPI_MSG_ERROR,
1094                                      "%s: component flag '%s' not supported\n",
1095                                      progname, name);
1096                         return -EINVAL;
1097                 }
1098         }
1099
1100         if (!*flags && !*neg_flags)
1101                 return -EINVAL;
1102
1103         /* don't allow to set and exclude the same flag */
1104         if (*flags & *neg_flags)
1105                 return -EINVAL;
1106
1107         return 0;
1108 }
1109
1110 static int mirror_str2state(char *string, __u16 *state, __u16 *neg_state)
1111 {
1112         if (string == NULL)
1113                 return -EINVAL;
1114
1115         *state = 0;
1116         *neg_state = 0;
1117
1118         if (strncmp(string, "^", 1) == 0) {
1119                 *neg_state = llapi_layout_string_flags(string + 1);
1120                 if (*neg_state != 0)
1121                         return 0;
1122         } else {
1123                 *state = llapi_layout_string_flags(string);
1124                 if (*state != 0)
1125                         return 0;
1126         }
1127
1128         llapi_printf(LLAPI_MSG_ERROR,
1129                      "%s: mirrored file state '%s' not supported\n",
1130                      progname, string);
1131         return -EINVAL;
1132 }
1133
1134 /**
1135  * struct mirror_args - Command-line arguments for mirror(s).
1136  * @m_count:  Number of mirrors to be created with this layout.
1137  * @m_flags:  Mirror level flags, only 'prefer' is supported.
1138  * @m_layout: Mirror layout.
1139  * @m_file:   A victim file. Its layout will be split and used as a mirror.
1140  * @m_next:   Point to the next node of the list.
1141  *
1142  * Command-line arguments for mirror(s) will be parsed and stored in
1143  * a linked list that consists of this structure.
1144  */
1145 struct mirror_args {
1146         __u32                   m_count;
1147         __u32                   m_flags;
1148         struct llapi_layout     *m_layout;
1149         const char              *m_file;
1150         struct mirror_args      *m_next;
1151 };
1152
1153 static int mirror_sanity_check_flags(struct llapi_layout *layout, void *unused)
1154 {
1155         uint32_t flags;
1156         int rc;
1157
1158         rc = llapi_layout_comp_flags_get(layout, &flags);
1159         if (rc)
1160                 return -errno;
1161
1162         if (flags & LCME_FL_NEG) {
1163                 fprintf(stderr, "error: %s: negative flags are not supported\n",
1164                         progname);
1165                 return -EINVAL;
1166         }
1167
1168         if (flags & LCME_FL_STALE) {
1169                 fprintf(stderr, "error: %s: setting '%s' is not supported\n",
1170                         progname, comp_flags_table[LCME_FL_STALE].cfn_name);
1171                 return -EINVAL;
1172         }
1173
1174         return LLAPI_LAYOUT_ITER_CONT;
1175 }
1176
1177 static inline int mirror_sanity_check_one(struct llapi_layout *layout)
1178 {
1179         uint64_t start, end;
1180         uint64_t pattern;
1181         int rc;
1182
1183         /* LU-10112: do not support dom+flr in phase 1 */
1184         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1185         if (rc)
1186                 return -errno;
1187
1188         rc = llapi_layout_pattern_get(layout, &pattern);
1189         if (rc)
1190                 return -errno;
1191
1192         if (pattern == LOV_PATTERN_MDT || pattern == LLAPI_LAYOUT_MDT) {
1193                 fprintf(stderr, "error: %s: doesn't support dom+flr for now\n",
1194                         progname);
1195                 return -ENOTSUP;
1196         }
1197
1198         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_LAST);
1199         if (rc)
1200                 return -errno;
1201
1202         rc = llapi_layout_comp_extent_get(layout, &start, &end);
1203         if (rc)
1204                 return -errno;
1205
1206         if (end != LUSTRE_EOF) {
1207                 fprintf(stderr, "error: %s: mirror layout doesn't reach eof\n",
1208                         progname);
1209                 return -EINVAL;
1210         }
1211
1212         rc = llapi_layout_comp_iterate(layout, mirror_sanity_check_flags, NULL);
1213         return rc;
1214 }
1215
1216 /**
1217  * enum mirror_flags - Flags for extending a mirrored file.
1218  * @MF_NO_VERIFY: Indicates not to verify the mirror(s) from victim file(s)
1219  *             in case the victim file(s) contains the same data as the
1220  *             original mirrored file.
1221  * @MF_DESTROY: Indicates to delete the mirror from the mirrored file.
1222  *
1223  * Flags for extending a mirrored file.
1224  */
1225 enum mirror_flags {
1226         MF_NO_VERIFY    = 0x1,
1227         MF_DESTROY      = 0x2,
1228 };
1229
1230 /**
1231  * mirror_create_sanity_check() - Check mirror list.
1232  * @list:  A linked list that stores the mirror arguments.
1233  *
1234  * This function does a sanity check on @list for creating
1235  * a mirrored file.
1236  *
1237  * Return: 0 on success or a negative error code on failure.
1238  */
1239 static int mirror_create_sanity_check(const char *fname,
1240                                       struct mirror_args *list)
1241 {
1242         int rc = 0;
1243         bool has_m_file = false;
1244         bool has_m_layout = false;
1245
1246         if (list == NULL)
1247                 return -EINVAL;
1248
1249         if (fname) {
1250                 struct llapi_layout *layout;
1251
1252                 layout = llapi_layout_get_by_path(fname, 0);
1253                 if (!layout) {
1254                         fprintf(stderr,
1255                                 "error: %s: file '%s' couldn't get layout\n",
1256                                 progname, fname);
1257                         return -ENODATA;
1258                 }
1259
1260                 rc = mirror_sanity_check_one(layout);
1261                 llapi_layout_free(layout);
1262
1263                 if (rc)
1264                         return rc;
1265         }
1266
1267         while (list != NULL) {
1268                 if (list->m_file != NULL) {
1269                         has_m_file = true;
1270                         llapi_layout_free(list->m_layout);
1271
1272                         list->m_layout =
1273                                 llapi_layout_get_by_path(list->m_file, 0);
1274                         if (list->m_layout == NULL) {
1275                                 fprintf(stderr,
1276                                         "error: %s: file '%s' has no layout\n",
1277                                         progname, list->m_file);
1278                                 return -ENODATA;
1279                         }
1280                 } else {
1281                         has_m_layout = true;
1282                         if (list->m_layout == NULL) {
1283                                 fprintf(stderr, "error: %s: no mirror layout\n",
1284                                         progname);
1285                                 return -EINVAL;
1286                         }
1287                 }
1288
1289                 rc = mirror_sanity_check_one(list->m_layout);
1290                 if (rc)
1291                         return rc;
1292
1293                 list = list->m_next;
1294         }
1295
1296         if (has_m_file && has_m_layout) {
1297                 fprintf(stderr, "error: %s: -f <victim_file> option should not "
1298                         "be specified with setstripe options or "
1299                         "--parent option\n", progname);
1300                 return -EINVAL;
1301         }
1302
1303         return 0;
1304 }
1305
1306 static int mirror_set_flags(struct llapi_layout *layout, void *cbdata)
1307 {
1308         __u32 mirror_flags = *(__u32 *)cbdata;
1309         uint32_t flags;
1310         int rc;
1311
1312         rc = llapi_layout_comp_flags_get(layout, &flags);
1313         if (rc < 0)
1314                 return rc;
1315
1316         if (!flags) {
1317                 rc = llapi_layout_comp_flags_set(layout, mirror_flags);
1318                 if (rc)
1319                         return rc;
1320         }
1321
1322         return LLAPI_LAYOUT_ITER_CONT;
1323 }
1324
1325 /**
1326  * mirror_create() - Create a mirrored file.
1327  * @fname:        The file to be created.
1328  * @mirror_list:  A linked list that stores the mirror arguments.
1329  *
1330  * This function creates a mirrored file @fname with the mirror(s)
1331  * from @mirror_list.
1332  *
1333  * Return: 0 on success or a negative error code on failure.
1334  */
1335 static int mirror_create(char *fname, struct mirror_args *mirror_list)
1336 {
1337         struct llapi_layout *layout = NULL;
1338         struct mirror_args *cur_mirror = NULL;
1339         uint16_t mirror_count = 0;
1340         int i = 0;
1341         int rc = 0;
1342
1343         rc = mirror_create_sanity_check(NULL, mirror_list);
1344         if (rc)
1345                 return rc;
1346
1347         cur_mirror = mirror_list;
1348         while (cur_mirror != NULL) {
1349                 rc = llapi_layout_comp_iterate(cur_mirror->m_layout,
1350                                                mirror_set_flags,
1351                                                &cur_mirror->m_flags);
1352                 if (rc) {
1353                         rc = -errno;
1354                         fprintf(stderr, "%s: failed to set mirror flags\n",
1355                                 progname);
1356                         goto error;
1357                 }
1358
1359                 for (i = 0; i < cur_mirror->m_count; i++) {
1360                         rc = llapi_layout_merge(&layout, cur_mirror->m_layout);
1361                         if (rc) {
1362                                 rc = -errno;
1363                                 fprintf(stderr, "error: %s: "
1364                                         "merge layout failed: %s\n",
1365                                         progname, strerror(errno));
1366                                 goto error;
1367                         }
1368                 }
1369                 mirror_count += cur_mirror->m_count;
1370                 cur_mirror = cur_mirror->m_next;
1371         }
1372
1373         if (layout == NULL) {
1374                 fprintf(stderr, "error: %s: layout is NULL\n", progname);
1375                 return -EINVAL;
1376         }
1377
1378         rc = llapi_layout_mirror_count_set(layout, mirror_count);
1379         if (rc) {
1380                 rc = -errno;
1381                 fprintf(stderr, "error: %s: set mirror count failed: %s\n",
1382                         progname, strerror(errno));
1383                 goto error;
1384         }
1385
1386         rc = lfs_component_create(fname, O_CREAT | O_WRONLY, 0644,
1387                                   layout);
1388         if (rc >= 0) {
1389                 close(rc);
1390                 rc = 0;
1391         }
1392
1393 error:
1394         llapi_layout_free(layout);
1395         return rc;
1396 }
1397
1398 /**
1399  * Compare files and check lease on @fd.
1400  *
1401  * \retval bytes number of bytes are the same
1402  */
1403 static ssize_t mirror_file_compare(int fd, int fdv)
1404 {
1405         const size_t buflen = 4 * 1024 * 1024; /* 4M */
1406         void *buf;
1407         ssize_t bytes_done = 0;
1408         ssize_t bytes_read = 0;
1409
1410         buf = malloc(buflen * 2);
1411         if (!buf)
1412                 return -ENOMEM;
1413
1414         while (1) {
1415                 if (!llapi_lease_check(fd)) {
1416                         bytes_done = -EBUSY;
1417                         break;
1418                 }
1419
1420                 bytes_read = read(fd, buf, buflen);
1421                 if (bytes_read <= 0)
1422                         break;
1423
1424                 if (bytes_read != read(fdv, buf + buflen, buflen))
1425                         break;
1426
1427                 /* XXX: should compute the checksum on each buffer and then
1428                  * compare checksum to avoid cache collision */
1429                 if (memcmp(buf, buf + buflen, bytes_read))
1430                         break;
1431
1432                 bytes_done += bytes_read;
1433         }
1434
1435         free(buf);
1436
1437         return bytes_done;
1438 }
1439
1440 static int mirror_extend_file(const char *fname, const char *victim_file,
1441                               enum mirror_flags mirror_flags)
1442 {
1443         int fd = -1;
1444         int fdv = -1;
1445         struct stat stbuf;
1446         struct stat stbuf_v;
1447         struct ll_ioc_lease *data = NULL;
1448         int rc;
1449
1450         fd = open(fname, O_RDWR);
1451         if (fd < 0) {
1452                 error_loc = "open source file";
1453                 rc = -errno;
1454                 goto out;
1455         }
1456
1457         fdv = open(victim_file, O_RDWR);
1458         if (fdv < 0) {
1459                 error_loc = "open target file";
1460                 rc = -errno;
1461                 goto out;
1462         }
1463
1464         if (fstat(fd, &stbuf) || fstat(fdv, &stbuf_v)) {
1465                 error_loc = "stat source or target file";
1466                 rc = -errno;
1467                 goto out;
1468         }
1469
1470         if (stbuf.st_dev != stbuf_v.st_dev) {
1471                 error_loc = "stat source and target file";
1472                 rc = -EXDEV;
1473                 goto out;
1474         }
1475
1476         /* mirrors should be of the same size */
1477         if (stbuf.st_size != stbuf_v.st_size) {
1478                 error_loc = "file sizes don't match";
1479                 rc = -EINVAL;
1480                 goto out;
1481         }
1482
1483         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1484         if (rc < 0) {
1485                 error_loc = "cannot get lease";
1486                 goto out;
1487         }
1488
1489         if (!(mirror_flags & MF_NO_VERIFY)) {
1490                 ssize_t ret;
1491                 /* mirrors should have the same contents */
1492                 ret = mirror_file_compare(fd, fdv);
1493                 if (ret != stbuf.st_size) {
1494                         error_loc = "file busy or contents don't match";
1495                         rc = ret < 0 ? ret : -EINVAL;
1496                         goto out;
1497                 }
1498         }
1499
1500         /* Get rid of caching pages from clients */
1501         rc = llapi_file_flush(fd);
1502         if (rc < 0) {
1503                 error_loc = "cannot get data version";
1504                 goto out;
1505         }
1506
1507         rc = llapi_file_flush(fdv);
1508         if (rc < 0) {
1509                 error_loc = "cannot get data version";
1510                 goto out;
1511
1512         }
1513
1514         /* Make sure we keep original atime/mtime values */
1515         rc = migrate_copy_timestamps(fd, fdv);
1516         if (rc < 0) {
1517                 error_loc = "cannot copy timestamp";
1518                 goto out;
1519         }
1520
1521         /* Atomically put lease, merge layouts and close. */
1522         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
1523         if (!data) {
1524                 error_loc = "memory allocation";
1525                 goto out;
1526         }
1527         data->lil_mode = LL_LEASE_UNLCK;
1528         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
1529         data->lil_count = 1;
1530         data->lil_ids[0] = fdv;
1531         rc = llapi_lease_set(fd, data);
1532         if (rc < 0) {
1533                 error_loc = "cannot merge layout";
1534                 goto out;
1535         } else if (rc == 0) {
1536                 rc = -EBUSY;
1537                 error_loc = "lost lease lock";
1538                 goto out;
1539         }
1540         rc = 0;
1541
1542 out:
1543         if (data)
1544                 free(data);
1545         if (fd >= 0)
1546                 close(fd);
1547         if (fdv >= 0)
1548                 close(fdv);
1549         if (!rc)
1550                 (void) unlink(victim_file);
1551         if (rc < 0)
1552                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1553                         progname, fname, error_loc, strerror(-rc));
1554         return rc;
1555 }
1556
1557 static int mirror_extend_layout(char *name, struct llapi_layout *layout)
1558 {
1559         struct ll_ioc_lease *data = NULL;
1560         int fd = -1;
1561         int fdv = -1;
1562         int rc;
1563
1564         rc = migrate_open_files(name, NULL, layout, &fd, &fdv);
1565         if (rc < 0)
1566                 goto out;
1567
1568         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1569         if (rc < 0) {
1570                 error_loc = "cannot get lease";
1571                 goto out;
1572         }
1573
1574         rc = migrate_nonblock(fd, fdv);
1575         if (rc < 0) {
1576                 llapi_lease_release(fd);
1577                 goto out;
1578         }
1579
1580         /* Atomically put lease, merge layouts and close. */
1581         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
1582         if (!data) {
1583                 error_loc = "memory allocation";
1584                 goto out;
1585         }
1586         data->lil_mode = LL_LEASE_UNLCK;
1587         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
1588         data->lil_count = 1;
1589         data->lil_ids[0] = fdv;
1590         rc = llapi_lease_set(fd, data);
1591         if (rc < 0) {
1592                 error_loc = "cannot merge layout";
1593                 goto out;
1594         } else if (rc == 0) {
1595                 rc = -EBUSY;
1596                 error_loc = "lost lease lock";
1597                 goto out;
1598         }
1599         rc = 0;
1600
1601 out:
1602         if (data)
1603                 free(data);
1604         if (fd >= 0)
1605                 close(fd);
1606         if (fdv >= 0)
1607                 close(fdv);
1608         if (rc < 0)
1609                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1610                         progname, name, error_loc, strerror(-rc));
1611         return rc;
1612 }
1613
1614 static int mirror_extend(char *fname, struct mirror_args *mirror_list,
1615                          enum mirror_flags mirror_flags)
1616 {
1617         int rc;
1618
1619         rc = mirror_create_sanity_check(fname, mirror_list);
1620         if (rc)
1621                 return rc;
1622
1623         while (mirror_list) {
1624                 if (mirror_list->m_file != NULL) {
1625                         rc = mirror_extend_file(fname, mirror_list->m_file,
1626                                                 mirror_flags);
1627                 } else {
1628                         __u32 mirror_count = mirror_list->m_count;
1629
1630                         while (mirror_count > 0) {
1631                                 rc = mirror_extend_layout(fname,
1632                                                         mirror_list->m_layout);
1633                                 if (rc)
1634                                         break;
1635
1636                                 --mirror_count;
1637                         }
1638                 }
1639                 if (rc)
1640                         break;
1641
1642                 mirror_list = mirror_list->m_next;
1643         }
1644
1645         return rc;
1646 }
1647
1648 static int verify_id(struct llapi_layout *layout, void *cbdata)
1649 {
1650         uint32_t id;
1651         int rc;
1652
1653         rc = llapi_layout_mirror_id_get(layout, &id);
1654         if (rc < 0)
1655                 return rc;
1656
1657         if ((__u16)id == *(__u16 *)cbdata)
1658                 return LLAPI_LAYOUT_ITER_STOP;
1659
1660         return LLAPI_LAYOUT_ITER_CONT;
1661 }
1662
1663 static int mirror_split(const char *fname, __u16 mirror_id,
1664                         enum mirror_flags mflags, const char *victim_file)
1665 {
1666         struct llapi_layout *layout;
1667         char parent[PATH_MAX];
1668         char victim[PATH_MAX];
1669         int flags = O_CREAT | O_EXCL | O_LOV_DELAY_CREATE | O_NOFOLLOW;
1670         char *ptr;
1671         struct ll_ioc_lease *data;
1672         uint16_t mirror_count;
1673         int mdt_index;
1674         int fd, fdv;
1675         int rc;
1676
1677         /* check fname contains mirror with mirror_id */
1678         layout = llapi_layout_get_by_path(fname, 0);
1679         if (!layout) {
1680                 fprintf(stderr,
1681                         "error %s: file '%s' couldn't get layout\n",
1682                         progname, fname);
1683                 return -EINVAL;
1684         }
1685
1686         rc = mirror_sanity_check_one(layout);
1687         if (rc)
1688                 goto free_layout;
1689
1690         rc = llapi_layout_mirror_count_get(layout, &mirror_count);
1691         if (rc) {
1692                 fprintf(stderr,
1693                         "error %s: file '%s' couldn't get mirror count\n",
1694                         progname, fname);
1695                 goto free_layout;
1696         }
1697         if (mirror_count < 2) {
1698                 fprintf(stderr,
1699                         "error %s: file '%s' has %d component, cannot split\n",
1700                         progname, fname, mirror_count);
1701                 goto free_layout;
1702         }
1703
1704         rc = llapi_layout_comp_iterate(layout, verify_id, &mirror_id);
1705         if (rc < 0) {
1706                 fprintf(stderr, "error %s: failed to iterate layout of '%s'\n",
1707                         progname, fname);
1708                 goto free_layout;
1709         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
1710                 fprintf(stderr,
1711                      "error %s: file '%s' does not contain mirror with id %u\n",
1712                         progname, fname, mirror_id);
1713                 goto free_layout;
1714         }
1715
1716         fd = open(fname, O_RDWR);
1717         if (fd < 0) {
1718                 fprintf(stderr,
1719                         "error %s: open file '%s' failed: %s\n",
1720                         progname, fname, strerror(errno));
1721                 goto free_layout;
1722         }
1723
1724         /* get victim file directory pathname */
1725         if (strlen(fname) > sizeof(parent) - 1) {
1726                 fprintf(stderr, "error %s: file name of '%s' too long\n",
1727                         progname, fname);
1728                 rc = -ERANGE;
1729                 goto free_layout;
1730         }
1731         strncpy(parent, fname, sizeof(parent));
1732         ptr = strrchr(parent, '/');
1733         if (ptr == NULL) {
1734                 if (getcwd(parent, sizeof(parent)) == NULL) {
1735                         fprintf(stderr, "error %s: getcwd failed: %s\n",
1736                                 progname, strerror(errno));
1737                         rc = -errno;
1738                         goto free_layout;
1739                 }
1740         } else {
1741                 if (ptr == parent)
1742                         ptr = parent + 1;
1743                 *ptr = '\0';
1744         }
1745
1746         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
1747         if (rc < 0) {
1748                 fprintf(stderr, "%s: cannot get MDT index of '%s'\n",
1749                         progname, fname);
1750                 goto free_layout;
1751         }
1752
1753         if (victim_file == NULL) {
1754                 /* use a temp file to store the splitted layout */
1755                 if (mflags & MF_DESTROY) {
1756                         fdv = llapi_create_volatile_idx(parent, mdt_index,
1757                                                         O_LOV_DELAY_CREATE);
1758                 } else {
1759                         snprintf(victim, sizeof(victim), "%s.mirror~%u",
1760                                  fname, mirror_id);
1761                         fdv = open(victim, flags, S_IRUSR | S_IWUSR);
1762                 }
1763         } else {
1764                 /* user specified victim file */
1765                 fdv = open(victim_file, flags, S_IRUSR | S_IWUSR);
1766         }
1767
1768         if (fdv < 0) {
1769                 fprintf(stderr,
1770                         "error %s: create victim file failed: %s\n",
1771                         progname, strerror(errno));
1772                 goto close_fd;
1773         }
1774
1775         /* get lease lock of fname */
1776         rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
1777         if (rc < 0) {
1778                 fprintf(stderr,
1779                         "error %s: cannot get lease of file '%s': %d\n",
1780                         progname, fname, rc);
1781                 goto close_victim;
1782         }
1783
1784         /* Atomatically put lease, split layouts and close. */
1785         data = malloc(offsetof(typeof(*data), lil_ids[2]));
1786         if (!data) {
1787                 rc = -ENOMEM;
1788                 goto close_victim;
1789         }
1790
1791         data->lil_mode = LL_LEASE_UNLCK;
1792         data->lil_flags = LL_LEASE_LAYOUT_SPLIT;
1793         data->lil_count = 2;
1794         data->lil_ids[0] = fdv;
1795         data->lil_ids[1] = mirror_id;
1796         rc = llapi_lease_set(fd, data);
1797         if (rc <= 0) {
1798                 if (rc == 0) /* lost lease lock */
1799                         rc = -EBUSY;
1800                 fprintf(stderr,
1801                         "error %s: cannot split '%s': %s\n",
1802                         progname, fname, strerror(-rc));
1803         } else {
1804                 rc = 0;
1805         }
1806         free(data);
1807
1808 close_victim:
1809         close(fdv);
1810 close_fd:
1811         close(fd);
1812 free_layout:
1813         llapi_layout_free(layout);
1814         return rc;
1815 }
1816
1817 /**
1818  * Parse a string containing an target index list into an array of integers.
1819  *
1820  * The input string contains a comma delimited list of individual
1821  * indices and ranges, for example "1,2-4,7". Add the indices into the
1822  * \a tgts array and remove duplicates.
1823  *
1824  * \param[out] tgts    array to store indices in
1825  * \param[in] size     size of \a tgts array
1826  * \param[in] offset   starting index in \a tgts
1827  * \param[in] arg      string containing OST index list
1828  *
1829  * \retval positive    number of indices in \a tgts
1830  * \retval -EINVAL     unable to parse \a arg
1831  */
1832 static int parse_targets(__u32 *tgts, int size, int offset, char *arg)
1833 {
1834         int rc;
1835         int nr = offset;
1836         int slots = size - offset;
1837         char *ptr = NULL;
1838         bool end_of_loop;
1839
1840         if (arg == NULL)
1841                 return -EINVAL;
1842
1843         end_of_loop = false;
1844         while (!end_of_loop) {
1845                 int start_index;
1846                 int end_index;
1847                 int i;
1848                 char *endptr = NULL;
1849
1850                 rc = -EINVAL;
1851
1852                 ptr = strchrnul(arg, ',');
1853
1854                 end_of_loop = *ptr == '\0';
1855                 *ptr = '\0';
1856
1857                 start_index = strtol(arg, &endptr, 0);
1858                 if (endptr == arg) /* no data at all */
1859                         break;
1860                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
1861                         break;
1862
1863                 end_index = start_index;
1864                 if (*endptr == '-') {
1865                         end_index = strtol(endptr + 1, &endptr, 0);
1866                         if (*endptr != '\0')
1867                                 break;
1868                         if (end_index < start_index)
1869                                 break;
1870                 }
1871
1872                 for (i = start_index; i <= end_index && slots > 0; i++) {
1873                         int j;
1874
1875                         /* remove duplicate */
1876                         for (j = 0; j < offset; j++) {
1877                                 if (tgts[j] == i)
1878                                         break;
1879                         }
1880                         if (j == offset) { /* no duplicate */
1881                                 tgts[nr++] = i;
1882                                 --slots;
1883                         }
1884                 }
1885                 if (slots == 0 && i < end_index)
1886                         break;
1887
1888                 *ptr = ',';
1889                 arg = ++ptr;
1890                 offset = nr;
1891                 rc = 0;
1892         }
1893         if (!end_of_loop && ptr != NULL)
1894                 *ptr = ',';
1895
1896         return rc < 0 ? rc : nr;
1897 }
1898
1899 struct lfs_setstripe_args {
1900         unsigned long long       lsa_comp_end;
1901         unsigned long long       lsa_stripe_size;
1902         long long                lsa_stripe_count;
1903         long long                lsa_stripe_off;
1904         __u32                    lsa_comp_flags;
1905         __u32                    lsa_comp_neg_flags;
1906         unsigned long long       lsa_pattern;
1907         int                      lsa_nr_tgts;
1908         __u32                   *lsa_tgts;
1909         char                    *lsa_pool_name;
1910 };
1911
1912 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1913 {
1914         memset(lsa, 0, sizeof(*lsa));
1915
1916         lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
1917         lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
1918         lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
1919         lsa->lsa_pattern = LLAPI_LAYOUT_RAID0;
1920         lsa->lsa_pool_name = NULL;
1921 }
1922
1923 /**
1924  * setstripe_args_init_inherit() - Initialize and inherit stripe options.
1925  * @lsa: Stripe options to be initialized and inherited.
1926  *
1927  * This function initializes stripe options in @lsa and inherit
1928  * stripe_size, stripe_count and OST pool_name options.
1929  *
1930  * Return: void.
1931  */
1932 static inline void setstripe_args_init_inherit(struct lfs_setstripe_args *lsa)
1933 {
1934         unsigned long long stripe_size;
1935         long long stripe_count;
1936         char *pool_name = NULL;
1937
1938         stripe_size = lsa->lsa_stripe_size;
1939         stripe_count = lsa->lsa_stripe_count;
1940         pool_name = lsa->lsa_pool_name;
1941
1942         setstripe_args_init(lsa);
1943
1944         lsa->lsa_stripe_size = stripe_size;
1945         lsa->lsa_stripe_count = stripe_count;
1946         lsa->lsa_pool_name = pool_name;
1947 }
1948
1949 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1950 {
1951         return (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT ||
1952                 lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ||
1953                 lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
1954                 lsa->lsa_pattern != LLAPI_LAYOUT_RAID0 ||
1955                 lsa->lsa_pool_name != NULL ||
1956                 lsa->lsa_comp_end != 0);
1957 }
1958
1959 /**
1960  * comp_args_to_layout() - Create or extend a composite layout.
1961  * @composite:       Pointer to the composite layout.
1962  * @lsa:             Stripe options for the new component.
1963  *
1964  * This function creates or extends a composite layout by adding a new
1965  * component with stripe options from @lsa.
1966  *
1967  * Return: 0 on success or an error code on failure.
1968  */
1969 static int comp_args_to_layout(struct llapi_layout **composite,
1970                                struct lfs_setstripe_args *lsa)
1971 {
1972         struct llapi_layout *layout = *composite;
1973         uint64_t prev_end = 0;
1974         int i = 0, rc;
1975
1976         if (layout == NULL) {
1977                 layout = llapi_layout_alloc();
1978                 if (layout == NULL) {
1979                         fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1980                                 strerror(errno));
1981                         return -ENOMEM;
1982                 }
1983                 *composite = layout;
1984         } else {
1985                 uint64_t start;
1986
1987                 /* Get current component extent, current component
1988                  * must be the tail component. */
1989                 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1990                 if (rc) {
1991                         fprintf(stderr, "Get comp extent failed. %s\n",
1992                                 strerror(errno));
1993                         return rc;
1994                 }
1995
1996                 rc = llapi_layout_comp_add(layout);
1997                 if (rc) {
1998                         fprintf(stderr, "Add component failed. %s\n",
1999                                 strerror(errno));
2000                         return rc;
2001                 }
2002         }
2003
2004         rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
2005         if (rc) {
2006                 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
2007                         prev_end, lsa->lsa_comp_end, strerror(errno));
2008                 return rc;
2009         }
2010
2011         /* Data-on-MDT component setting */
2012         if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
2013                 /* In case of Data-on-MDT patterns the only extra option
2014                  * applicable is stripe size option. */
2015                 if (lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
2016                         fprintf(stderr, "Option 'stripe-count' can't be "
2017                                 "specified with Data-on-MDT component: %lld\n",
2018                                 lsa->lsa_stripe_count);
2019                         return -EINVAL;
2020                 }
2021                 if (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT) {
2022                         fprintf(stderr, "Option 'stripe-size' can't be "
2023                                 "specified with Data-on-MDT component: %llu\n",
2024                                 lsa->lsa_stripe_size);
2025                         return -EINVAL;
2026                 }
2027                 if (lsa->lsa_nr_tgts != 0) {
2028                         fprintf(stderr, "Option 'ost-list' can't be specified "
2029                                 "with Data-on-MDT component: '%i'\n",
2030                                 lsa->lsa_nr_tgts);
2031                         return -EINVAL;
2032                 }
2033                 if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
2034                         fprintf(stderr, "Option 'stripe-offset' can't be "
2035                                 "specified with Data-on-MDT component: %lld\n",
2036                                 lsa->lsa_stripe_off);
2037                         return -EINVAL;
2038                 }
2039                 if (lsa->lsa_pool_name != 0) {
2040                         fprintf(stderr, "Option 'pool' can't be specified "
2041                                 "with Data-on-MDT component: '%s'\n",
2042                                 lsa->lsa_pool_name);
2043                         return -EINVAL;
2044                 }
2045
2046                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
2047                 if (rc) {
2048                         fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
2049                                 lsa->lsa_pattern, strerror(errno));
2050                         return rc;
2051                 }
2052                 /* Data-on-MDT component has always single stripe up to end */
2053                 lsa->lsa_stripe_size = lsa->lsa_comp_end;
2054         }
2055
2056         rc = llapi_layout_stripe_size_set(layout, lsa->lsa_stripe_size);
2057         if (rc) {
2058                 fprintf(stderr, "Set stripe size %llu failed: %s\n",
2059                         lsa->lsa_stripe_size, strerror(errno));
2060                 return rc;
2061         }
2062
2063         rc = llapi_layout_stripe_count_set(layout, lsa->lsa_stripe_count);
2064         if (rc) {
2065                 fprintf(stderr, "Set stripe count %lld failed: %s\n",
2066                         lsa->lsa_stripe_count, strerror(errno));
2067                 return rc;
2068         }
2069
2070         rc = llapi_layout_comp_flags_set(layout, lsa->lsa_comp_flags);
2071         if (rc) {
2072                 fprintf(stderr, "Set flags 0x%x failed: %s\n",
2073                         lsa->lsa_comp_flags, strerror(errno));
2074                 return rc;
2075         }
2076
2077         if (lsa->lsa_pool_name != NULL) {
2078                 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
2079                 if (rc) {
2080                         fprintf(stderr, "Set pool name: %s failed. %s\n",
2081                                 lsa->lsa_pool_name, strerror(errno));
2082                         return rc;
2083                 }
2084         } else {
2085                 rc = llapi_layout_pool_name_set(layout, "");
2086                 if (rc) {
2087                         fprintf(stderr, "Clear pool name failed: %s\n",
2088                                 strerror(errno));
2089                         return rc;
2090                 }
2091         }
2092
2093         if (lsa->lsa_nr_tgts > 0) {
2094                 if (lsa->lsa_stripe_count > 0 &&
2095                     lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
2096                     lsa->lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
2097                     lsa->lsa_nr_tgts != lsa->lsa_stripe_count) {
2098                         fprintf(stderr, "stripe_count(%lld) != nr_osts(%d)\n",
2099                                 lsa->lsa_stripe_count, lsa->lsa_nr_tgts);
2100                         return -EINVAL;
2101                 }
2102                 for (i = 0; i < lsa->lsa_nr_tgts; i++) {
2103                         rc = llapi_layout_ost_index_set(layout, i,
2104                                                         lsa->lsa_tgts[i]);
2105                         if (rc)
2106                                 break;
2107                 }
2108         } else if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
2109                 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
2110         }
2111         if (rc) {
2112                 fprintf(stderr, "Set ost index %d failed. %s\n",
2113                         i, strerror(errno));
2114                 return rc;
2115         }
2116
2117         return 0;
2118 }
2119
2120 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
2121  * end of the last component in the existing file, and adjust the
2122  * first extent start of the components to be added accordingly. */
2123 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
2124 {
2125         struct llapi_layout *head;
2126         uint64_t start, end, stripe_size, prev_end = 0;
2127         int rc;
2128
2129         if (layout == NULL) {
2130                 fprintf(stderr,
2131                         "%s setstripe: layout must be specified\n",
2132                         progname);
2133                 return -EINVAL;
2134         }
2135
2136         errno = 0;
2137         head = llapi_layout_get_by_path(fname, 0);
2138         if (head == NULL) {
2139                 fprintf(stderr,
2140                         "%s setstripe: cannot read layout from '%s': %s\n",
2141                         progname, fname, strerror(errno));
2142                 return -EINVAL;
2143         } else if (errno == ENODATA) {
2144                 /* file without LOVEA, this component-add will be turned
2145                  * into a component-create. */
2146                 llapi_layout_free(head);
2147                 return -ENODATA;
2148         } else if (!llapi_layout_is_composite(head)) {
2149                 fprintf(stderr, "%s setstripe: '%s' not a composite file\n",
2150                         progname, fname);
2151                 llapi_layout_free(head);
2152                 return -EINVAL;
2153         }
2154
2155         rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
2156         if (rc) {
2157                 fprintf(stderr, "%s setstripe: cannot get prev extent: %s\n",
2158                         progname, strerror(errno));
2159                 llapi_layout_free(head);
2160                 return rc;
2161         }
2162
2163         llapi_layout_free(head);
2164
2165         /* Make sure we use the first component of the layout to be added. */
2166         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
2167         if (rc < 0) {
2168                 fprintf(stderr,
2169                         "%s setstripe: cannot move component cursor: %s\n",
2170                         progname, strerror(errno));
2171                 return rc;
2172         }
2173
2174         rc = llapi_layout_comp_extent_get(layout, &start, &end);
2175         if (rc) {
2176                 fprintf(stderr, "%s setstripe: cannot get extent: %s\n",
2177                         progname, strerror(errno));
2178                 return rc;
2179         }
2180
2181         if (start > prev_end || end <= prev_end) {
2182                 fprintf(stderr,
2183                         "%s setstripe: first extent [%lu, %lu) not adjacent with extent end %lu\n",
2184                         progname, start, end, prev_end);
2185                 return -EINVAL;
2186         }
2187
2188         rc = llapi_layout_stripe_size_get(layout, &stripe_size);
2189         if (rc) {
2190                 fprintf(stderr, "%s setstripe: cannot get stripe size: %s\n",
2191                         progname, strerror(errno));
2192                 return rc;
2193         }
2194
2195         if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
2196             (prev_end & (stripe_size - 1))) {
2197                 fprintf(stderr,
2198                         "%s setstripe: stripe size %lu not aligned with %lu\n",
2199                         progname, stripe_size, prev_end);
2200                 return -EINVAL;
2201         }
2202
2203         rc = llapi_layout_comp_extent_set(layout, prev_end, end);
2204         if (rc) {
2205                 fprintf(stderr,
2206                         "%s setstripe: cannot set component extent [%lu, %lu): %s\n",
2207                         progname, prev_end, end, strerror(errno));
2208                 return rc;
2209         }
2210
2211         return 0;
2212 }
2213
2214 static inline bool arg_is_eof(char *arg)
2215 {
2216         return !strncmp(arg, "-1", strlen("-1")) ||
2217                !strncmp(arg, "EOF", strlen("EOF")) ||
2218                !strncmp(arg, "eof", strlen("eof"));
2219 }
2220
2221 /**
2222  * lfs_mirror_alloc() - Allocate a mirror argument structure.
2223  *
2224  * Return: Valid mirror_args pointer on success and
2225  *         NULL if memory allocation fails.
2226  */
2227 static struct mirror_args *lfs_mirror_alloc(void)
2228 {
2229         struct mirror_args *mirror = NULL;
2230
2231         while (1) {
2232                 mirror = calloc(1, sizeof(*mirror));
2233                 if (mirror != NULL)
2234                         break;
2235
2236                 sleep(1);
2237         }
2238
2239         return mirror;
2240 }
2241
2242 /**
2243  * lfs_mirror_free() - Free memory allocated for a mirror argument
2244  *                     structure.
2245  * @mirror: Previously allocated mirror argument structure by
2246  *          lfs_mirror_alloc().
2247  *
2248  * Free memory allocated for @mirror.
2249  *
2250  * Return: void.
2251  */
2252 static void lfs_mirror_free(struct mirror_args *mirror)
2253 {
2254         if (mirror->m_layout != NULL)
2255                 llapi_layout_free(mirror->m_layout);
2256         free(mirror);
2257 }
2258
2259 /**
2260  * lfs_mirror_list_free() - Free memory allocated for a mirror list.
2261  * @mirror_list: Previously allocated mirror list.
2262  *
2263  * Free memory allocated for @mirror_list.
2264  *
2265  * Return: void.
2266  */
2267 static void lfs_mirror_list_free(struct mirror_args *mirror_list)
2268 {
2269         struct mirror_args *next_mirror = NULL;
2270
2271         while (mirror_list != NULL) {
2272                 next_mirror = mirror_list->m_next;
2273                 lfs_mirror_free(mirror_list);
2274                 mirror_list = next_mirror;
2275         }
2276 }
2277
2278 enum {
2279         LFS_POOL_OPT = 3,
2280         LFS_COMP_COUNT_OPT,
2281         LFS_COMP_START_OPT,
2282         LFS_COMP_FLAGS_OPT,
2283         LFS_COMP_DEL_OPT,
2284         LFS_COMP_SET_OPT,
2285         LFS_COMP_ADD_OPT,
2286         LFS_COMP_USE_PARENT_OPT,
2287         LFS_COMP_NO_VERIFY_OPT,
2288         LFS_PROJID_OPT,
2289         LFS_MIRROR_FLAGS_OPT,
2290         LFS_MIRROR_ID_OPT,
2291         LFS_MIRROR_STATE_OPT,
2292 };
2293
2294 /* functions */
2295 static int lfs_setstripe_internal(int argc, char **argv,
2296                                   enum setstripe_origin opc)
2297 {
2298         struct lfs_setstripe_args        lsa;
2299         struct llapi_stripe_param       *param = NULL;
2300         struct find_param                migrate_mdt_param = {
2301                 .fp_max_depth = -1,
2302                 .fp_mdt_index = -1,
2303         };
2304         char                            *fname;
2305         int                              result;
2306         int                              result2 = 0;
2307         char                            *end;
2308         int                              c;
2309         int                              delete = 0;
2310         char                            *mdt_idx_arg = NULL;
2311         unsigned long long               size_units = 1;
2312         bool                             migrate_mode = false;
2313         bool                             migration_block = false;
2314         __u64                            migration_flags = 0;
2315         __u32                            osts[LOV_MAX_STRIPE_COUNT] = { 0 };
2316         int                              comp_del = 0, comp_set = 0;
2317         int                              comp_add = 0;
2318         __u32                            comp_id = 0;
2319         struct llapi_layout             *layout = NULL;
2320         struct llapi_layout             **lpp = &layout;
2321         bool                             mirror_mode = false;
2322         bool                             has_m_file = false;
2323         __u32                            mirror_count = 0;
2324         enum mirror_flags                mirror_flags = 0;
2325         struct mirror_args              *mirror_list = NULL;
2326         struct mirror_args              *new_mirror = NULL;
2327         struct mirror_args              *last_mirror = NULL;
2328         __u16                            mirror_id = 0;
2329         char                             cmd[PATH_MAX];
2330
2331         struct option long_opts[] = {
2332 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
2333         /* --block is only valid in migrate mode */
2334         { .val = 'b',   .name = "block",        .has_arg = no_argument },
2335         { .val = LFS_COMP_ADD_OPT,
2336                         .name = "comp-add",     .has_arg = no_argument },
2337         { .val = LFS_COMP_ADD_OPT,
2338                         .name = "component-add", .has_arg = no_argument },
2339         { .val = LFS_COMP_DEL_OPT,
2340                         .name = "comp-del",     .has_arg = no_argument },
2341         { .val = LFS_COMP_DEL_OPT,
2342                         .name = "component-del", .has_arg = no_argument },
2343         { .val = LFS_COMP_FLAGS_OPT,
2344                         .name = "comp-flags",   .has_arg = required_argument },
2345         { .val = LFS_COMP_FLAGS_OPT,
2346                         .name = "component-flags",
2347                                                 .has_arg = required_argument },
2348         { .val = LFS_COMP_SET_OPT,
2349                         .name = "comp-set",     .has_arg = no_argument },
2350         { .val = LFS_COMP_SET_OPT,
2351                         .name = "component-set",
2352                                                 .has_arg = no_argument},
2353         { .val = LFS_COMP_USE_PARENT_OPT,
2354                         .name = "parent",       .has_arg = no_argument},
2355         { .val = LFS_COMP_NO_VERIFY_OPT,
2356                         .name = "no-verify",    .has_arg = no_argument},
2357         { .val = LFS_MIRROR_FLAGS_OPT,
2358                         .name = "flags",        .has_arg = required_argument},
2359         { .val = LFS_MIRROR_ID_OPT,
2360                         .name = "mirror-id",    .has_arg = required_argument},
2361         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument},
2362         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument},
2363 /* find { .val = 'C',   .name = "ctime",        .has_arg = required_argument }*/
2364         { .val = 'd',   .name = "delete",       .has_arg = no_argument},
2365         { .val = 'd',   .name = "destroy",      .has_arg = no_argument},
2366         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument},
2367         { .val = 'E',   .name = "component-end",
2368                                                 .has_arg = required_argument},
2369         { .val = 'f',   .name = "file",         .has_arg = required_argument },
2370 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
2371 /* find { .val = 'g',   .name = "gid",          .has_arg = no_argument }, */
2372 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
2373 /* dirstripe { .val = 'H', .name = "mdt-hash",  .has_arg = required_argument }*/
2374         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument},
2375         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument},
2376         { .val = 'I',   .name = "comp-id",      .has_arg = required_argument},
2377         { .val = 'I',   .name = "component-id", .has_arg = required_argument},
2378         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
2379         { .val = 'm',   .name = "mdt",          .has_arg = required_argument},
2380         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument},
2381         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument},
2382         /* --non-block is only valid in migrate mode */
2383         { .val = 'n',   .name = "non-block",    .has_arg = no_argument },
2384         { .val = 'N',   .name = "mirror-count", .has_arg = optional_argument},
2385         { .val = 'o',   .name = "ost",          .has_arg = required_argument },
2386 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2387         { .val = 'o',   .name = "ost-list",     .has_arg = required_argument },
2388         { .val = 'o',   .name = "ost_list",     .has_arg = required_argument },
2389 #endif
2390         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
2391 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
2392 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
2393 /* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
2394 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
2395         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
2396         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
2397 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
2398 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
2399 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
2400 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
2401         /* --verbose is only valid in migrate mode */
2402         { .val = 'v',   .name = "verbose",      .has_arg = no_argument},
2403 /* getstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
2404         { .name = NULL } };
2405
2406         setstripe_args_init(&lsa);
2407
2408         migrate_mode = (opc == SO_MIGRATE);
2409         mirror_mode = (opc == SO_MIRROR_CREATE || opc == SO_MIRROR_EXTEND);
2410
2411         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
2412         progname = cmd;
2413         while ((c = getopt_long(argc, argv, "bc:dE:f:i:I:m:N::no:p:L:s:S:v",
2414                                 long_opts, NULL)) >= 0) {
2415                 switch (c) {
2416                 case 0:
2417                         /* Long options. */
2418                         break;
2419                 case LFS_COMP_ADD_OPT:
2420                         comp_add = 1;
2421                         break;
2422                 case LFS_COMP_DEL_OPT:
2423                         comp_del = 1;
2424                         break;
2425                 case LFS_COMP_FLAGS_OPT:
2426                         result = comp_str2flags(optarg, &lsa.lsa_comp_flags,
2427                                                 &lsa.lsa_comp_neg_flags);
2428                         if (result != 0)
2429                                 goto usage_error;
2430                         if (mirror_mode && lsa.lsa_comp_neg_flags) {
2431                                 fprintf(stderr, "%s: inverted flags are not supported\n",
2432                                         progname);
2433                                 goto usage_error;
2434                         }
2435                         if (lsa.lsa_comp_neg_flags & LCME_FL_STALE) {
2436                                 fprintf(stderr,
2437                                         "%s: cannot clear 'stale' flags from component. Please use lfs-mirror-resync(1) instead\n",
2438                                         progname);
2439                                 result = -EINVAL;
2440                                 goto error;
2441                         }
2442
2443                         break;
2444                 case LFS_COMP_SET_OPT:
2445                         comp_set = 1;
2446                         break;
2447                 case LFS_COMP_USE_PARENT_OPT:
2448                         if (!mirror_mode) {
2449                                 fprintf(stderr, "error: %s: --parent must be "
2450                                         "specified with --mirror-count|-N "
2451                                         "option\n", progname);
2452                                 goto usage_error;
2453                         }
2454                         setstripe_args_init(&lsa);
2455                         break;
2456                 case LFS_COMP_NO_VERIFY_OPT:
2457                         mirror_flags |= MF_NO_VERIFY;
2458                         break;
2459                 case LFS_MIRROR_ID_OPT:
2460                         mirror_id = strtoul(optarg, &end, 0);
2461                         if (*end != '\0' || mirror_id == 0) {
2462                                 fprintf(stderr,
2463                                         "%s %s: invalid mirror ID '%s'\n",
2464                                         progname, argv[0], optarg);
2465                                 goto usage_error;
2466                         }
2467                         break;
2468                 case LFS_MIRROR_FLAGS_OPT: {
2469                         __u32 flags;
2470
2471                         if (!mirror_mode || !last_mirror) {
2472                                 fprintf(stderr, "error: %s: --flags must be specified with --mirror-count|-N option\n",
2473                                         progname);
2474                                 goto usage_error;
2475                         }
2476
2477                         result = comp_str2flags(optarg, &last_mirror->m_flags,
2478                                                 &flags);
2479                         if (result != 0)
2480                                 goto usage_error;
2481
2482                         if (flags) {
2483                                 fprintf(stderr, "%s: inverted flags are not supported\n",
2484                                         progname);
2485                                 result = -EINVAL;
2486                                 goto usage_error;
2487                         }
2488                         if (last_mirror->m_flags & ~LCME_USER_FLAGS) {
2489                                 fprintf(stderr,
2490                                         "%s: unsupported mirror flags: %s\n",
2491                                         progname, optarg);
2492                                 result = -EINVAL;
2493                                 goto error;
2494                         }
2495                         break;
2496                 }
2497                 case 'b':
2498                         if (!migrate_mode) {
2499                                 fprintf(stderr,
2500                                         "%s %s: -b|--block valid only for migrate command\n",
2501                                         progname, argv[0]);
2502                                 goto usage_error;
2503                         }
2504                         migration_block = true;
2505                         break;
2506                 case 'c':
2507                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
2508                         if (*end != '\0') {
2509                                 fprintf(stderr,
2510                                         "%s %s: invalid stripe count '%s'\n",
2511                                         progname, argv[0], optarg);
2512                                 goto usage_error;
2513                         }
2514
2515                         if (lsa.lsa_stripe_count == -1)
2516                                 lsa.lsa_stripe_count = LLAPI_LAYOUT_WIDE;
2517                         break;
2518                 case 'd':
2519                         /* delete the default striping pattern */
2520                         delete = 1;
2521                         if (opc == SO_MIRROR_SPLIT) {
2522                                 if (has_m_file) {
2523                                         fprintf(stderr,
2524                                               "%s %s: -d cannot used with -f\n",
2525                                                 progname, argv[0]);
2526                                         goto usage_error;
2527                                 }
2528                                 mirror_flags |= MF_DESTROY;
2529                         }
2530                         break;
2531                 case 'E':
2532                         if (lsa.lsa_comp_end != 0) {
2533                                 result = comp_args_to_layout(lpp, &lsa);
2534                                 if (result) {
2535                                         fprintf(stderr,
2536                                                 "%s %s: invalid layout\n",
2537                                                 progname, argv[0]);
2538                                         goto usage_error;
2539                                 }
2540
2541                                 setstripe_args_init_inherit(&lsa);
2542                         }
2543
2544                         if (arg_is_eof(optarg)) {
2545                                 lsa.lsa_comp_end = LUSTRE_EOF;
2546                         } else {
2547                                 result = llapi_parse_size(optarg,
2548                                                         &lsa.lsa_comp_end,
2549                                                         &size_units, 0);
2550                                 if (result) {
2551                                         fprintf(stderr,
2552                                                 "%s %s: invalid component end '%s'\n",
2553                                                 progname, argv[0], optarg);
2554                                         goto usage_error;
2555                                 }
2556                         }
2557                         break;
2558                 case 'i':
2559                         lsa.lsa_stripe_off = strtol(optarg, &end, 0);
2560                         if (*end != '\0') {
2561                                 fprintf(stderr,
2562                                         "%s %s: invalid stripe offset '%s'\n",
2563                                         progname, argv[0], optarg);
2564                                 goto usage_error;
2565                         }
2566                         if (lsa.lsa_stripe_off == -1)
2567                                 lsa.lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2568                         break;
2569                 case 'I':
2570                         comp_id = strtoul(optarg, &end, 0);
2571                         if (*end != '\0' || comp_id == 0 ||
2572                             comp_id > LCME_ID_MAX) {
2573                                 fprintf(stderr,
2574                                         "%s %s: invalid component ID '%s'\n",
2575                                         progname, argv[0], optarg);
2576                                 goto usage_error;
2577                         }
2578                         break;
2579                 case 'f':
2580                         if (opc != SO_MIRROR_EXTEND && opc != SO_MIRROR_SPLIT) {
2581                                 fprintf(stderr,
2582                                         "error: %s: invalid option: %s\n",
2583                                         progname, argv[optopt + 1]);
2584                                 goto usage_error;
2585                         }
2586                         if (opc == SO_MIRROR_EXTEND) {
2587                                 if (last_mirror == NULL) {
2588                                         fprintf(stderr,
2589                                 "error: %s: '-N' must exist in front of '%s'\n",
2590                                                 progname, argv[optopt + 1]);
2591                                         goto usage_error;
2592                                 }
2593                                 last_mirror->m_file = optarg;
2594                                 last_mirror->m_count = 1;
2595                         } else {
2596                                 /* mirror split */
2597                                 if (mirror_list == NULL)
2598                                         mirror_list = lfs_mirror_alloc();
2599                                 mirror_list->m_file = optarg;
2600                         }
2601                         has_m_file = true;
2602                         break;
2603                 case 'L':
2604                         if (strcmp(argv[optind - 1], "mdt") == 0) {
2605                                 /* Can be only the first component */
2606                                 if (layout != NULL) {
2607                                         result = -EINVAL;
2608                                         fprintf(stderr, "error: 'mdt' layout "
2609                                                 "can be only the first one\n");
2610                                         goto error;
2611                                 }
2612                                 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
2613                                         result = -EFBIG;
2614                                         fprintf(stderr, "error: 'mdt' layout "
2615                                                 "size is too big\n");
2616                                         goto error;
2617                                 }
2618                                 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
2619                         } else if (strcmp(argv[optind - 1], "raid0") != 0) {
2620                                 result = -EINVAL;
2621                                 fprintf(stderr, "error: layout '%s' is "
2622                                         "unknown, supported layouts are: "
2623                                         "'mdt', 'raid0'\n", argv[optind]);
2624                                 goto error;
2625                         }
2626                         break;
2627                 case 'm':
2628                         if (!migrate_mode) {
2629                                 fprintf(stderr,
2630                                         "%s %s: -m|--mdt-index valid only for migrate command\n",
2631                                         progname, argv[0]);
2632                                 goto usage_error;
2633                         }
2634                         mdt_idx_arg = optarg;
2635                         break;
2636                 case 'n':
2637                         if (!migrate_mode) {
2638                                 fprintf(stderr,
2639                                         "%s %s: -n|--non-block valid only for migrate command\n",
2640                                         progname, argv[0]);
2641                                 goto usage_error;
2642                         }
2643                         migration_flags |= MIGRATION_NONBLOCK;
2644                         break;
2645                 case 'N':
2646                         if (opc == SO_SETSTRIPE) {
2647                                 opc = SO_MIRROR_CREATE;
2648                                 mirror_mode = true;
2649                         }
2650                         mirror_count = 1;
2651                         if (optarg != NULL) {
2652                                 mirror_count = strtoul(optarg, &end, 0);
2653                                 if (*end != '\0' || mirror_count == 0) {
2654                                         fprintf(stderr,
2655                                                 "error: %s: bad mirror count: %s\n",
2656                                                 progname, optarg);
2657                                         result = -EINVAL;
2658                                         goto error;
2659                                 }
2660                         }
2661
2662                         new_mirror = lfs_mirror_alloc();
2663                         new_mirror->m_count = mirror_count;
2664
2665                         if (mirror_list == NULL)
2666                                 mirror_list = new_mirror;
2667
2668                         if (last_mirror != NULL) {
2669                                 /* wrap up last mirror */
2670                                 if (lsa.lsa_comp_end == 0)
2671                                         lsa.lsa_comp_end = LUSTRE_EOF;
2672
2673                                 result = comp_args_to_layout(lpp, &lsa);
2674                                 if (result) {
2675                                         lfs_mirror_free(new_mirror);
2676                                         goto error;
2677                                 }
2678
2679                                 setstripe_args_init_inherit(&lsa);
2680
2681                                 last_mirror->m_next = new_mirror;
2682                         }
2683
2684                         last_mirror = new_mirror;
2685                         lpp = &last_mirror->m_layout;
2686                         break;
2687                 case 'o':
2688 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2689                         if (strcmp(argv[optind - 1], "--ost-list") == 0)
2690                                 fprintf(stderr, "warning: '--ost-list' is "
2691                                         "deprecated, use '--ost' instead\n");
2692 #endif
2693                         lsa.lsa_nr_tgts = parse_targets(osts,
2694                                                 sizeof(osts) / sizeof(__u32),
2695                                                 lsa.lsa_nr_tgts, optarg);
2696                         if (lsa.lsa_nr_tgts < 0) {
2697                                 fprintf(stderr,
2698                                         "%s %s: invalid OST target(s) '%s'\n",
2699                                         progname, argv[0], optarg);
2700                                 goto usage_error;
2701                         }
2702
2703                         lsa.lsa_tgts = osts;
2704                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
2705                                 lsa.lsa_stripe_off = osts[0];
2706                         break;
2707                 case 'p':
2708                         if (optarg == NULL)
2709                                 goto usage_error;
2710                         lsa.lsa_pool_name = optarg;
2711                         break;
2712                 case 'S':
2713                         result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
2714                                                   &size_units, 0);
2715                         if (result) {
2716                                 fprintf(stderr,
2717                                         "%s %s: invalid stripe size '%s'\n",
2718                                         progname, argv[0], optarg);
2719                                 goto usage_error;
2720                         }
2721                         break;
2722                 case 'v':
2723                         if (!migrate_mode) {
2724                                 fprintf(stderr,
2725                                         "%s %s: -v|--verbose valid only for migrate command\n",
2726                                         progname, argv[0]);
2727                                 goto usage_error;
2728                         }
2729                         migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
2730                         break;
2731                 default:
2732                         fprintf(stderr, "%s %s: unrecognized option '%s'\n",
2733                                 progname, argv[0], argv[optind - 1]);
2734                         goto usage_error;
2735                 }
2736         }
2737
2738         fname = argv[optind];
2739
2740         if (optind == argc) {
2741                 fprintf(stderr, "%s %s: FILE must be specified\n",
2742                         progname, argv[0]);
2743                 goto usage_error;
2744         }
2745
2746         if (mirror_mode && mirror_count == 0) {
2747                 fprintf(stderr,
2748                         "error: %s: --mirror-count|-N option is required\n",
2749                         progname);
2750                 result = -EINVAL;
2751                 goto error;
2752         }
2753
2754         if (mirror_mode) {
2755                 if (lsa.lsa_comp_end == 0)
2756                         lsa.lsa_comp_end = LUSTRE_EOF;
2757         }
2758
2759         if (lsa.lsa_comp_end != 0) {
2760                 result = comp_args_to_layout(lpp, &lsa);
2761                 if (result)
2762                         goto error;
2763         }
2764
2765         if (mirror_flags & MF_NO_VERIFY) {
2766                 if (opc != SO_MIRROR_EXTEND) {
2767                         fprintf(stderr,
2768                                 "error: %s: --no-verify is valid only for lfs mirror extend command\n",
2769                                 progname);
2770                         result = -EINVAL;
2771                         goto error;
2772                 } else if (!has_m_file) {
2773                         fprintf(stderr,
2774                                 "error: %s: --no-verify must be specified with -f <victim_file> option\n",
2775                                 progname);
2776                         result = -EINVAL;
2777                         goto error;
2778                 }
2779         }
2780
2781         /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
2782          * altered by user space tool, so we don't need to support the
2783          * --component-set for this moment. */
2784         if (comp_set && !comp_id) {
2785                 fprintf(stderr, "%s %s: --component-set doesn't have component-id set\n",
2786                         progname, argv[0]);
2787                 goto usage_error;
2788         }
2789
2790         if ((delete + comp_set + comp_del + comp_add) > 1) {
2791                 fprintf(stderr,
2792                         "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
2793                         progname, argv[0]);
2794                 goto usage_error;
2795         }
2796
2797         if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
2798                        lsa.lsa_comp_flags != 0 || layout != NULL)) {
2799                 fprintf(stderr,
2800                         "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
2801                         progname, argv[0]);
2802                 goto usage_error;
2803         }
2804
2805         if ((comp_set || comp_del) &&
2806             (setstripe_args_specified(&lsa) || layout != NULL)) {
2807                 fprintf(stderr,
2808                         "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
2809                         progname, argv[0]);
2810                 goto usage_error;
2811         }
2812
2813         if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
2814                 fprintf(stderr,
2815                         "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
2816                         progname, argv[0]);
2817                 goto usage_error;
2818         }
2819
2820         if (comp_add || comp_del) {
2821                 struct stat st;
2822
2823                 result = lstat(fname, &st);
2824                 if (result == 0 && S_ISDIR(st.st_mode)) {
2825                         fprintf(stderr,
2826                                 "%s setstripe: cannot use --component-add or --component-del for directory\n",
2827                                 progname);
2828                         goto usage_error;
2829                 }
2830
2831                 if (mirror_mode) {
2832                         fprintf(stderr, "error: %s: can't use --component-add "
2833                                 "or --component-del for mirror operation\n",
2834                                 progname);
2835                         goto usage_error;
2836                 }
2837         }
2838
2839         if (comp_add) {
2840                 if (layout == NULL) {
2841                         fprintf(stderr,
2842                                 "%s %s: option -E must be specified with --component-add\n",
2843                                 progname, argv[0]);
2844                         goto usage_error;
2845                 }
2846
2847                 result = adjust_first_extent(fname, layout);
2848                 if (result == -ENODATA)
2849                         comp_add = 0;
2850                 else if (result != 0)
2851                         goto error;
2852         }
2853
2854         if (mdt_idx_arg != NULL && optind > 3) {
2855                 fprintf(stderr,
2856                         "%s %s: option -m cannot be used with other options\n",
2857                         progname, argv[0]);
2858                 goto usage_error;
2859         }
2860
2861         if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
2862                 fprintf(stderr,
2863                         "%s %s: options --non-block and --block are mutually exclusive\n",
2864                         progname, argv[0]);
2865                 goto usage_error;
2866         }
2867
2868         if (!comp_del && !comp_set && comp_id != 0) {
2869                 fprintf(stderr,
2870                         "%s %s: option -I can only be used with --component-del\n",
2871                         progname, argv[0]);
2872                 goto usage_error;
2873         }
2874
2875         if (mdt_idx_arg != NULL) {
2876                 /* initialize migrate mdt parameters */
2877                 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
2878                 if (*end != '\0') {
2879                         fprintf(stderr, "%s %s: invalid MDT index '%s'\n",
2880                                 progname, argv[0], mdt_idx_arg);
2881                         goto usage_error;
2882                 }
2883                 migrate_mdt_param.fp_migrate = 1;
2884         } else if (layout == NULL) {
2885                 /* initialize stripe parameters */
2886                 param = calloc(1, offsetof(typeof(*param),
2887                                lsp_osts[lsa.lsa_nr_tgts]));
2888                 if (param == NULL) {
2889                         fprintf(stderr,
2890                                 "%s %s: cannot allocate memory for parameters: %s\n",
2891                                 progname, argv[0], strerror(ENOMEM));
2892                         result = -ENOMEM;
2893                         goto error;
2894                 }
2895
2896                 if (lsa.lsa_stripe_size != LLAPI_LAYOUT_DEFAULT)
2897                         param->lsp_stripe_size = lsa.lsa_stripe_size;
2898                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
2899                         if (lsa.lsa_stripe_count == LLAPI_LAYOUT_WIDE)
2900                                 param->lsp_stripe_count = -1;
2901                         else
2902                                 param->lsp_stripe_count = lsa.lsa_stripe_count;
2903                 }
2904                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
2905                         param->lsp_stripe_offset = -1;
2906                 else
2907                         param->lsp_stripe_offset = lsa.lsa_stripe_off;
2908                 param->lsp_pool = lsa.lsa_pool_name;
2909                 param->lsp_is_specific = false;
2910                 if (lsa.lsa_nr_tgts > 0) {
2911                         if (lsa.lsa_stripe_count > 0 &&
2912                             lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
2913                             lsa.lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
2914                             lsa.lsa_nr_tgts != lsa.lsa_stripe_count) {
2915                                 fprintf(stderr, "error: %s: stripe count %lld "
2916                                         "doesn't match the number of OSTs: %d\n"
2917                                         , argv[0], lsa.lsa_stripe_count,
2918                                         lsa.lsa_nr_tgts);
2919                                 free(param);
2920                                 goto usage_error;
2921                         }
2922
2923                         param->lsp_is_specific = true;
2924                         param->lsp_stripe_count = lsa.lsa_nr_tgts;
2925                         memcpy(param->lsp_osts, osts,
2926                                sizeof(*osts) * lsa.lsa_nr_tgts);
2927                 }
2928         }
2929
2930         for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
2931                 if (mdt_idx_arg != NULL) {
2932                         result = llapi_migrate_mdt(fname, &migrate_mdt_param);
2933                 } else if (migrate_mode) {
2934                         result = lfs_migrate(fname, migration_flags, param,
2935                                              layout);
2936                 } else if (comp_set != 0) {
2937                         result = lfs_component_set(fname, comp_id,
2938                                                    lsa.lsa_comp_flags,
2939                                                    lsa.lsa_comp_neg_flags);
2940                 } else if (comp_del != 0) {
2941                         result = lfs_component_del(fname, comp_id,
2942                                                    lsa.lsa_comp_flags,
2943                                                    lsa.lsa_comp_neg_flags);
2944                 } else if (comp_add != 0) {
2945                         result = lfs_component_add(fname, layout);
2946                 } else if (opc == SO_MIRROR_CREATE) {
2947                         result = mirror_create(fname, mirror_list);
2948                 } else if (opc == SO_MIRROR_EXTEND) {
2949                         result = mirror_extend(fname, mirror_list,
2950                                                mirror_flags);
2951                 } else if (opc == SO_MIRROR_SPLIT) {
2952                         if (mirror_id == 0) {
2953                                 fprintf(stderr,
2954                                         "%s %s: no mirror id is specified\n",
2955                                         progname, argv[0]);
2956                                 goto usage_error;
2957                         }
2958                         result = mirror_split(fname, mirror_id, mirror_flags,
2959                                               has_m_file ? mirror_list->m_file :
2960                                               NULL);
2961                 } else if (layout != NULL) {
2962                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
2963                                                       0644, layout);
2964                         if (result >= 0) {
2965                                 close(result);
2966                                 result = 0;
2967                         }
2968                 } else {
2969                         result = llapi_file_open_param(fname,
2970                                                        O_CREAT | O_WRONLY,
2971                                                        0644, param);
2972                         if (result >= 0) {
2973                                 close(result);
2974                                 result = 0;
2975                         }
2976                 }
2977                 if (result) {
2978                         /* Save the first error encountered. */
2979                         if (result2 == 0)
2980                                 result2 = result;
2981                         continue;
2982                 }
2983         }
2984
2985         free(param);
2986         llapi_layout_free(layout);
2987         lfs_mirror_list_free(mirror_list);
2988         return result2;
2989 usage_error:
2990         result = CMD_HELP;
2991 error:
2992         llapi_layout_free(layout);
2993         lfs_mirror_list_free(mirror_list);
2994         return result;
2995 }
2996
2997 static int lfs_poollist(int argc, char **argv)
2998 {
2999         if (argc != 2)
3000                 return CMD_HELP;
3001
3002         return llapi_poollist(argv[1]);
3003 }
3004
3005 static int set_time(time_t *time, time_t *set, char *str)
3006 {
3007         time_t t;
3008         int res = 0;
3009
3010         if (str[0] == '+')
3011                 res = 1;
3012         else if (str[0] == '-')
3013                 res = -1;
3014
3015         if (res)
3016                 str++;
3017
3018         t = strtol(str, NULL, 0);
3019         if (*time < t * 24 * 60 * 60) {
3020                 if (res)
3021                         str--;
3022                 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
3023                 return INT_MAX;
3024         }
3025
3026         *set = *time - t * 24 * 60 * 60;
3027         return res;
3028 }
3029 static int name2uid(unsigned int *id, const char *name)
3030 {
3031         struct passwd *passwd;
3032
3033         passwd = getpwnam(name);
3034         if (passwd == NULL)
3035                 return -ENOENT;
3036         *id = passwd->pw_uid;
3037
3038         return 0;
3039 }
3040
3041 static int name2gid(unsigned int *id, const char *name)
3042 {
3043         struct group *group;
3044
3045         group = getgrnam(name);
3046         if (group == NULL)
3047                 return -ENOENT;
3048         *id = group->gr_gid;
3049
3050         return 0;
3051 }
3052
3053 static inline int name2projid(unsigned int *id, const char *name)
3054 {
3055         return -ENOTSUP;
3056 }
3057
3058 static int uid2name(char **name, unsigned int id)
3059 {
3060         struct passwd *passwd;
3061
3062         passwd = getpwuid(id);
3063         if (passwd == NULL)
3064                 return -ENOENT;
3065         *name = passwd->pw_name;
3066
3067         return 0;
3068 }
3069
3070 static inline int gid2name(char **name, unsigned int id)
3071 {
3072         struct group *group;
3073
3074         group = getgrgid(id);
3075         if (group == NULL)
3076                 return -ENOENT;
3077         *name = group->gr_name;
3078
3079         return 0;
3080 }
3081
3082 static int name2layout(__u32 *layout, char *name)
3083 {
3084         char *ptr, *layout_name;
3085
3086         *layout = 0;
3087         for (ptr = name; ; ptr = NULL) {
3088                 layout_name = strtok(ptr, ",");
3089                 if (layout_name == NULL)
3090                         break;
3091                 if (strcmp(layout_name, "released") == 0)
3092                         *layout |= LOV_PATTERN_F_RELEASED;
3093                 else if (strcmp(layout_name, "raid0") == 0)
3094                         *layout |= LOV_PATTERN_RAID0;
3095                 else if (strcmp(layout_name, "mdt") == 0)
3096                         *layout |= LOV_PATTERN_MDT;
3097                 else
3098                         return -1;
3099         }
3100         return 0;
3101 }
3102
3103 static int lfs_find(int argc, char **argv)
3104 {
3105         int c, rc;
3106         int ret = 0;
3107         time_t t;
3108         struct find_param param = {
3109                 .fp_max_depth = -1,
3110                 .fp_quiet = 1,
3111         };
3112         struct option long_opts[] = {
3113         { .val = 'A',   .name = "atime",        .has_arg = required_argument },
3114         { .val = LFS_COMP_COUNT_OPT,
3115                         .name = "comp-count",   .has_arg = required_argument },
3116         { .val = LFS_COMP_COUNT_OPT,
3117                         .name = "component-count",
3118                                                 .has_arg = required_argument },
3119         { .val = LFS_COMP_FLAGS_OPT,
3120                         .name = "comp-flags",   .has_arg = required_argument },
3121         { .val = LFS_COMP_FLAGS_OPT,
3122                         .name = "component-flags",
3123                                                 .has_arg = required_argument },
3124         { .val = LFS_COMP_START_OPT,
3125                         .name = "comp-start",   .has_arg = required_argument },
3126         { .val = LFS_COMP_START_OPT,
3127                         .name = "component-start",
3128                                                 .has_arg = required_argument },
3129         { .val = LFS_MIRROR_STATE_OPT,
3130                         .name = "mirror-state", .has_arg = required_argument },
3131         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument },
3132         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument },
3133         { .val = 'C',   .name = "ctime",        .has_arg = required_argument },
3134 /* getstripe { .val = 'd', .name = "directory", .has_arg = no_argument }, */
3135         { .val = 'D',   .name = "maxdepth",     .has_arg = required_argument },
3136         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument },
3137         { .val = 'E',   .name = "component-end",
3138                                                 .has_arg = required_argument },
3139 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
3140         { .val = 'g',   .name = "gid",          .has_arg = required_argument },
3141         { .val = 'G',   .name = "group",        .has_arg = required_argument },
3142         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
3143         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument },
3144         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument },
3145 /* getstripe { .val = 'I', .name = "comp-id",   .has_arg = required_argument }*/
3146         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
3147         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
3148         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
3149         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument },
3150         { .val = 'M',   .name = "mtime",        .has_arg = required_argument },
3151         { .val = 'n',   .name = "name",         .has_arg = required_argument },
3152         { .val = 'N',   .name = "mirror-count", .has_arg = required_argument },
3153 /* find { .val = 'o'    .name = "or", .has_arg = no_argument }, like find(1) */
3154         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
3155         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
3156         /* no short option for pool yet, can be 'p' after 2.18 */
3157         { .val = LFS_POOL_OPT,
3158                         .name = "pool",         .has_arg = required_argument },
3159         { .val = '0',   .name = "print0",       .has_arg = no_argument },
3160         { .val = 'P',   .name = "print",        .has_arg = no_argument },
3161         { .val = LFS_PROJID_OPT,
3162                         .name = "projid",       .has_arg = required_argument },
3163 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
3164 /* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
3165 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
3166         { .val = 's',   .name = "size",         .has_arg = required_argument },
3167         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
3168         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
3169         { .val = 't',   .name = "type",         .has_arg = required_argument },
3170         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
3171         { .val = 'u',   .name = "uid",          .has_arg = required_argument },
3172         { .val = 'U',   .name = "user",         .has_arg = required_argument },
3173 /* getstripe { .val = 'v', .name = "verbose",   .has_arg = no_argument }, */
3174 /* getstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
3175         { .name = NULL } };
3176         int pathstart = -1;
3177         int pathend = -1;
3178         int neg_opt = 0;
3179         time_t *xtime;
3180         int *xsign;
3181         int isoption;
3182         char *endptr;
3183
3184         time(&t);
3185
3186         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
3187         while ((c = getopt_long_only(argc, argv,
3188                         "-0A:c:C:D:E:g:G:H:i:L:m:M:n:N:O:Ppqrs:S:t:T:u:U:v",
3189                         long_opts, NULL)) >= 0) {
3190                 xtime = NULL;
3191                 xsign = NULL;
3192                 if (neg_opt)
3193                         --neg_opt;
3194                 /* '!' is part of option */
3195                 /* when getopt_long_only() finds a string which is not
3196                  * an option nor a known option argument it returns 1
3197                  * in that case if we already have found pathstart and pathend
3198                  * (i.e. we have the list of pathnames),
3199                  * the only supported value is "!"
3200                  */
3201                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
3202                 if (!isoption && pathend != -1) {
3203                         fprintf(stderr, "err: %s: filename|dirname must either "
3204                                         "precede options or follow options\n",
3205                                         argv[0]);
3206                         ret = CMD_HELP;
3207                         goto err;
3208                 }
3209                 if (!isoption && pathstart == -1)
3210                         pathstart = optind - 1;
3211                 if (isoption && pathstart != -1 && pathend == -1)
3212                         pathend = optind - 2;
3213                 switch (c) {
3214                 case 0:
3215                         /* Long options. */
3216                         break;
3217                 case 1:
3218                         /* unknown; opt is "!" or path component,
3219                          * checking done above.
3220                          */
3221                         if (strcmp(optarg, "!") == 0)
3222                                 neg_opt = 2;
3223                         break;
3224                 case 'A':
3225                         xtime = &param.fp_atime;
3226                         xsign = &param.fp_asign;
3227                         param.fp_exclude_atime = !!neg_opt;
3228                         /* no break, this falls through to 'C' for ctime */
3229                 case 'C':
3230                         if (c == 'C') {
3231                                 xtime = &param.fp_ctime;
3232                                 xsign = &param.fp_csign;
3233                                 param.fp_exclude_ctime = !!neg_opt;
3234                         }
3235                         /* no break, this falls through to 'M' for mtime */
3236                 case 'M':
3237                         if (c == 'M') {
3238                                 xtime = &param.fp_mtime;
3239                                 xsign = &param.fp_msign;
3240                                 param.fp_exclude_mtime = !!neg_opt;
3241                         }
3242                         rc = set_time(&t, xtime, optarg);
3243                         if (rc == INT_MAX) {
3244                                 ret = -1;
3245                                 goto err;
3246                         }
3247                         if (rc)
3248                                 *xsign = rc;
3249                         break;
3250                 case LFS_COMP_COUNT_OPT:
3251                         if (optarg[0] == '+') {
3252                                 param.fp_comp_count_sign = -1;
3253                                 optarg++;
3254                         } else if (optarg[0] == '-') {
3255                                 param.fp_comp_count_sign =  1;
3256                                 optarg++;
3257                         }
3258
3259                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
3260                         if (*endptr != '\0') {
3261                                 fprintf(stderr, "error: bad component count "
3262                                         "'%s'\n", optarg);
3263                                 goto err;
3264                         }
3265                         param.fp_check_comp_count = 1;
3266                         param.fp_exclude_comp_count = !!neg_opt;
3267                         break;
3268                 case LFS_COMP_FLAGS_OPT:
3269                         rc = comp_str2flags(optarg, &param.fp_comp_flags,
3270                                             &param.fp_comp_neg_flags);
3271                         if (rc) {
3272                                 fprintf(stderr, "error: bad component flags "
3273                                         "'%s'\n", optarg);
3274                                 goto err;
3275                         }
3276                         param.fp_check_comp_flags = 1;
3277                         if (neg_opt) {
3278                                 __u32 flags = param.fp_comp_neg_flags;
3279                                 param.fp_comp_neg_flags = param.fp_comp_flags;
3280                                 param.fp_comp_flags = flags;
3281                         }
3282                         break;
3283                 case LFS_COMP_START_OPT:
3284                         if (optarg[0] == '+') {
3285                                 param.fp_comp_start_sign = -1;
3286                                 optarg++;
3287                         } else if (optarg[0] == '-') {
3288                                 param.fp_comp_start_sign =  1;
3289                                 optarg++;
3290                         }
3291
3292                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
3293                                               &param.fp_comp_start_units, 0);
3294                         if (rc) {
3295                                 fprintf(stderr, "error: bad component start "
3296                                         "'%s'\n", optarg);
3297                                 goto err;
3298                         }
3299                         param.fp_check_comp_start = 1;
3300                         param.fp_exclude_comp_start = !!neg_opt;
3301                         break;
3302                 case LFS_MIRROR_STATE_OPT:
3303                         rc = mirror_str2state(optarg, &param.fp_mirror_state,
3304                                               &param.fp_mirror_neg_state);
3305                         if (rc) {
3306                                 fprintf(stderr,
3307                                         "error: bad mirrored file state '%s'\n",
3308                                         optarg);
3309                                 goto err;
3310                         }
3311                         param.fp_check_mirror_state = 1;
3312                         if (neg_opt) {
3313                                 __u16 state = param.fp_mirror_neg_state;
3314                                 param.fp_mirror_neg_state =
3315                                         param.fp_mirror_state;
3316                                 param.fp_mirror_state = state;
3317                         }
3318                         break;
3319                 case 'c':
3320                         if (optarg[0] == '+') {
3321                                 param.fp_stripe_count_sign = -1;
3322                                 optarg++;
3323                         } else if (optarg[0] == '-') {
3324                                 param.fp_stripe_count_sign =  1;
3325                                 optarg++;
3326                         }
3327
3328                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
3329                         if (*endptr != '\0') {
3330                                 fprintf(stderr,"error: bad stripe_count '%s'\n",
3331                                         optarg);
3332                                 ret = -1;
3333                                 goto err;
3334                         }
3335                         param.fp_check_stripe_count = 1;
3336                         param.fp_exclude_stripe_count = !!neg_opt;
3337                         break;
3338                 case 'D':
3339                         param.fp_max_depth = strtol(optarg, 0, 0);
3340                         break;
3341                 case 'E':
3342                         if (optarg[0] == '+') {
3343                                 param.fp_comp_end_sign = -1;
3344                                 optarg++;
3345                         } else if (optarg[0] == '-') {
3346                                 param.fp_comp_end_sign =  1;
3347                                 optarg++;
3348                         }
3349
3350                         if (arg_is_eof(optarg)) {
3351                                 param.fp_comp_end = LUSTRE_EOF;
3352                                 param.fp_comp_end_units = 1;
3353                                 rc = 0;
3354                         } else {
3355                                 rc = llapi_parse_size(optarg,
3356                                                 &param.fp_comp_end,
3357                                                 &param.fp_comp_end_units, 0);
3358                         }
3359                         if (rc) {
3360                                 fprintf(stderr, "error: bad component end "
3361                                         "'%s'\n", optarg);
3362                                 goto err;
3363                         }
3364                         param.fp_check_comp_end = 1;
3365                         param.fp_exclude_comp_end = !!neg_opt;
3366                         break;
3367                 case 'g':
3368                 case 'G':
3369                         rc = name2gid(&param.fp_gid, optarg);
3370                         if (rc) {
3371                                 param.fp_gid = strtoul(optarg, &endptr, 10);
3372                                 if (*endptr != '\0') {
3373                                         fprintf(stderr, "Group/GID: %s cannot "
3374                                                 "be found.\n", optarg);
3375                                         ret = -1;
3376                                         goto err;
3377                                 }
3378                         }
3379                         param.fp_exclude_gid = !!neg_opt;
3380                         param.fp_check_gid = 1;
3381                         break;
3382                 case 'H':
3383                         param.fp_hash_type = check_hashtype(optarg);
3384                         if (param.fp_hash_type == 0) {
3385                                 fprintf(stderr, "error: bad hash_type '%s'\n",
3386                                         optarg);
3387                                 ret = -1;
3388                                 goto err;
3389                         }
3390                         param.fp_check_hash_type = 1;
3391                         param.fp_exclude_hash_type = !!neg_opt;
3392                         break;
3393                 case 'L':
3394                         ret = name2layout(&param.fp_layout, optarg);
3395                         if (ret)
3396                                 goto err;
3397                         param.fp_exclude_layout = !!neg_opt;
3398                         param.fp_check_layout = 1;
3399                         break;
3400                 case 'u':
3401                 case 'U':
3402                         rc = name2uid(&param.fp_uid, optarg);
3403                         if (rc) {
3404                                 param.fp_uid = strtoul(optarg, &endptr, 10);
3405                                 if (*endptr != '\0') {
3406                                         fprintf(stderr, "User/UID: %s cannot "
3407                                                 "be found.\n", optarg);
3408                                         ret = -1;
3409                                         goto err;
3410                                 }
3411                         }
3412                         param.fp_exclude_uid = !!neg_opt;
3413                         param.fp_check_uid = 1;
3414                         break;
3415                 case 'n':
3416                         param.fp_pattern = (char *)optarg;
3417                         param.fp_exclude_pattern = !!neg_opt;
3418                         break;
3419                 case 'N':
3420                         if (optarg[0] == '+') {
3421                                 param.fp_mirror_count_sign = -1;
3422                                 optarg++;
3423                         } else if (optarg[0] == '-') {
3424                                 param.fp_mirror_count_sign =  1;
3425                                 optarg++;
3426                         }
3427
3428                         param.fp_mirror_count = strtoul(optarg, &endptr, 0);
3429                         if (*endptr != '\0') {
3430                                 fprintf(stderr,
3431                                         "error: bad mirror count '%s'\n",
3432                                         optarg);
3433                                 goto err;
3434                         }
3435                         param.fp_check_mirror_count = 1;
3436                         param.fp_exclude_mirror_count = !!neg_opt;
3437                         break;
3438                 case 'm':
3439                 case 'i':
3440                 case 'O': {
3441                         char *buf, *token, *next, *p;
3442                         int len = 1;
3443                         void *tmp;
3444
3445                         buf = strdup(optarg);
3446                         if (buf == NULL) {
3447                                 ret = -ENOMEM;
3448                                 goto err;
3449                         }
3450
3451                         param.fp_exclude_obd = !!neg_opt;
3452
3453                         token = buf;
3454                         while (token && *token) {
3455                                 token = strchr(token, ',');
3456                                 if (token) {
3457                                         len++;
3458                                         token++;
3459                                 }
3460                         }
3461                         if (c == 'm') {
3462                                 param.fp_exclude_mdt = !!neg_opt;
3463                                 param.fp_num_alloc_mdts += len;
3464                                 tmp = realloc(param.fp_mdt_uuid,
3465                                               param.fp_num_alloc_mdts *
3466                                               sizeof(*param.fp_mdt_uuid));
3467                                 if (tmp == NULL) {
3468                                         ret = -ENOMEM;
3469                                         goto err_free;
3470                                 }
3471
3472                                 param.fp_mdt_uuid = tmp;
3473                         } else {
3474                                 param.fp_exclude_obd = !!neg_opt;
3475                                 param.fp_num_alloc_obds += len;
3476                                 tmp = realloc(param.fp_obd_uuid,
3477                                               param.fp_num_alloc_obds *
3478                                               sizeof(*param.fp_obd_uuid));
3479                                 if (tmp == NULL) {
3480                                         ret = -ENOMEM;
3481                                         goto err_free;
3482                                 }
3483
3484                                 param.fp_obd_uuid = tmp;
3485                         }
3486                         for (token = buf; token && *token; token = next) {
3487                                 struct obd_uuid *puuid;
3488                                 if (c == 'm') {
3489                                         puuid =
3490                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
3491                                 } else {
3492                                         puuid =
3493                                         &param.fp_obd_uuid[param.fp_num_obds++];
3494                                 }
3495                                 p = strchr(token, ',');
3496                                 next = 0;
3497                                 if (p) {
3498                                         *p = 0;
3499                                         next = p+1;
3500                                 }
3501
3502                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
3503                                         ret = -E2BIG;
3504                                         goto err_free;
3505                                 }
3506
3507                                 strncpy(puuid->uuid, token,
3508                                         sizeof(puuid->uuid));
3509                         }
3510 err_free:
3511                         if (buf)
3512                                 free(buf);
3513                         break;
3514                 }
3515 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 18, 53, 0)
3516                 case 'p':
3517 #endif
3518                 case LFS_POOL_OPT:
3519                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
3520                                 fprintf(stderr,
3521                                         "Pool name %s is too long (max %d)\n",
3522                                         optarg, LOV_MAXPOOLNAME);
3523                                 ret = -1;
3524                                 goto err;
3525                         }
3526                         /*
3527                          * We do check for empty pool because empty pool
3528                          * is used to find V1 LOV attributes
3529                          */
3530                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
3531                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
3532                         param.fp_exclude_pool = !!neg_opt;
3533                         param.fp_check_pool = 1;
3534                         break;
3535 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 14, 53, 0)
3536                 case 'p': /* want this for --pool, to match getstripe/find */
3537                         fprintf(stderr,
3538                                 "warning: -p deprecated, use --print0 or -0\n");
3539 #endif
3540                 case '0':
3541                         param.fp_zero_end = 1;
3542                         break;
3543                 case 'P': /* we always print, this option is a no-op */
3544                         break;
3545                 case LFS_PROJID_OPT:
3546                         rc = name2projid(&param.fp_projid, optarg);
3547                         if (rc) {
3548                                 param.fp_projid = strtoul(optarg, &endptr, 10);
3549                                 if (*endptr != '\0') {
3550                                         fprintf(stderr,
3551                                                 "Invalid project ID: %s",
3552                                                 optarg);
3553                                         ret = -1;
3554                                         goto err;
3555                                 }
3556                         }
3557                         param.fp_exclude_projid = !!neg_opt;
3558                         param.fp_check_projid = 1;
3559                         break;
3560                 case 's':
3561                         if (optarg[0] == '+') {
3562                                 param.fp_size_sign = -1;
3563                                 optarg++;
3564                         } else if (optarg[0] == '-') {
3565                                 param.fp_size_sign =  1;
3566                                 optarg++;
3567                         }
3568
3569                         ret = llapi_parse_size(optarg, &param.fp_size,
3570                                                &param.fp_size_units, 0);
3571                         if (ret) {
3572                                 fprintf(stderr, "error: bad file size '%s'\n",
3573                                         optarg);
3574                                 goto err;
3575                         }
3576                         param.fp_check_size = 1;
3577                         param.fp_exclude_size = !!neg_opt;
3578                         break;
3579                 case 'S':
3580                         if (optarg[0] == '+') {
3581                                 param.fp_stripe_size_sign = -1;
3582                                 optarg++;
3583                         } else if (optarg[0] == '-') {
3584                                 param.fp_stripe_size_sign =  1;
3585                                 optarg++;
3586                         }
3587
3588                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
3589                                                &param.fp_stripe_size_units, 0);
3590                         if (ret) {
3591                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
3592                                         optarg);
3593                                 goto err;
3594                         }
3595                         param.fp_check_stripe_size = 1;
3596                         param.fp_exclude_stripe_size = !!neg_opt;
3597                         break;
3598                 case 't':
3599                         param.fp_exclude_type = !!neg_opt;
3600                         switch (optarg[0]) {
3601                         case 'b':
3602                                 param.fp_type = S_IFBLK;
3603                                 break;
3604                         case 'c':
3605                                 param.fp_type = S_IFCHR;
3606                                 break;
3607                         case 'd':
3608                                 param.fp_type = S_IFDIR;
3609                                 break;
3610                         case 'f':
3611                                 param.fp_type = S_IFREG;
3612                                 break;
3613                         case 'l':
3614                                 param.fp_type = S_IFLNK;
3615                                 break;
3616                         case 'p':
3617                                 param.fp_type = S_IFIFO;
3618                                 break;
3619                         case 's':
3620                                 param.fp_type = S_IFSOCK;
3621                                 break;
3622                         default:
3623                                 fprintf(stderr, "error: %s: bad type '%s'\n",
3624                                         argv[0], optarg);
3625                                 ret = CMD_HELP;
3626                                 goto err;
3627                         };
3628                         break;
3629                 case 'T':
3630                         if (optarg[0] == '+') {
3631                                 param.fp_mdt_count_sign = -1;
3632                                 optarg++;
3633                         } else if (optarg[0] == '-') {
3634                                 param.fp_mdt_count_sign =  1;
3635                                 optarg++;
3636                         }
3637
3638                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
3639                         if (*endptr != '\0') {
3640                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
3641                                         optarg);
3642                                 ret = -1;
3643                                 goto err;
3644                         }
3645                         param.fp_check_mdt_count = 1;
3646                         param.fp_exclude_mdt_count = !!neg_opt;
3647                         break;
3648                 default:
3649                         ret = CMD_HELP;
3650                         goto err;
3651                 };
3652         }
3653
3654         if (pathstart == -1) {
3655                 fprintf(stderr, "error: %s: no filename|pathname\n",
3656                         argv[0]);
3657                 ret = CMD_HELP;
3658                 goto err;
3659         } else if (pathend == -1) {
3660                 /* no options */
3661                 pathend = argc;
3662         }
3663
3664         do {
3665                 rc = llapi_find(argv[pathstart], &param);
3666                 if (rc != 0 && ret == 0)
3667                         ret = rc;
3668         } while (++pathstart < pathend);
3669
3670         if (ret)
3671                 fprintf(stderr, "error: %s failed for %s.\n",
3672                         argv[0], argv[optind - 1]);
3673 err:
3674         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
3675                 free(param.fp_obd_uuid);
3676
3677         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
3678                 free(param.fp_mdt_uuid);
3679
3680         return ret;
3681 }
3682
3683 static int lfs_getstripe_internal(int argc, char **argv,
3684                                   struct find_param *param)
3685 {
3686         struct option long_opts[] = {
3687 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
3688         { .val = LFS_COMP_COUNT_OPT,
3689                         .name = "comp-count",   .has_arg = no_argument },
3690         { .val = LFS_COMP_COUNT_OPT,
3691                 .name = "component-count",      .has_arg = no_argument },
3692         { .val = LFS_COMP_FLAGS_OPT,
3693                         .name = "comp-flags",   .has_arg = optional_argument },
3694         { .val = LFS_COMP_FLAGS_OPT,
3695                 .name = "component-flags",      .has_arg = optional_argument },
3696         { .val = LFS_COMP_START_OPT,
3697                         .name = "comp-start",   .has_arg = optional_argument },
3698         { .val = LFS_COMP_START_OPT,
3699                 .name = "component-start",      .has_arg = optional_argument },
3700         { .val = 'c',   .name = "stripe-count", .has_arg = no_argument },
3701         { .val = 'c',   .name = "stripe_count", .has_arg = no_argument },
3702 /* find { .val = 'C',   .name = "ctime",        .has_arg = required_argument }*/
3703         { .val = 'd',   .name = "directory",    .has_arg = no_argument },
3704         { .val = 'D',   .name = "default",      .has_arg = no_argument },
3705         { .val = 'E',   .name = "comp-end",     .has_arg = optional_argument },
3706         { .val = 'E',   .name = "component-end", .has_arg = optional_argument },
3707         { .val = 'F',   .name = "fid",          .has_arg = no_argument },
3708         { .val = 'g',   .name = "generation",   .has_arg = no_argument },
3709 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
3710 /* dirstripe { .val = 'H', .name = "mdt-hash",  .has_arg = required_argument }*/
3711         { .val = 'i',   .name = "stripe-index", .has_arg = no_argument },
3712         { .val = 'i',   .name = "stripe_index", .has_arg = no_argument },
3713         { .val = 'I',   .name = "comp-id",      .has_arg = optional_argument },
3714         { .val = 'I',   .name = "component-id", .has_arg = optional_argument },
3715         { .val = 'L',   .name = "layout",       .has_arg = no_argument },
3716         { .val = 'm',   .name = "mdt",          .has_arg = no_argument },
3717         { .val = 'm',   .name = "mdt-index",    .has_arg = no_argument },
3718         { .val = 'm',   .name = "mdt_index",    .has_arg = no_argument },
3719 /* find { .val = 'M',   .name = "mtime",        .has_arg = required_argument }*/
3720 /* find { .val = 'n',   .name = "name",         .has_arg = required_argument }*/
3721         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
3722         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
3723         { .val = 'p',   .name = "pool",         .has_arg = no_argument },
3724 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
3725         { .val = 'q',   .name = "quiet",        .has_arg = no_argument },
3726         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
3727         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
3728         { .val = 'S',   .name = "stripe-size",  .has_arg = no_argument },
3729         { .val = 'S',   .name = "stripe_size",  .has_arg = no_argument },
3730 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
3731 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
3732 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
3733 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
3734         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
3735         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
3736         { .name = NULL } };
3737         int c, rc;
3738         char *end, *tmp;
3739
3740         while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
3741                                 long_opts, NULL)) != -1) {
3742                 switch (c) {
3743                 case 'c':
3744                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3745                                 param->fp_verbose |= VERBOSE_COUNT;
3746                                 param->fp_max_depth = 0;
3747                         }
3748                         break;
3749                 case LFS_COMP_COUNT_OPT:
3750                         param->fp_verbose |= VERBOSE_COMP_COUNT;
3751                         param->fp_max_depth = 0;
3752                         break;
3753                 case LFS_COMP_FLAGS_OPT:
3754                         if (optarg != NULL) {
3755                                 rc = comp_str2flags(optarg,
3756                                                     &param->fp_comp_flags,
3757                                                     &param->fp_comp_neg_flags);
3758                                 if (rc != 0) {
3759                                         fprintf(stderr, "error: %s bad "
3760                                                 "component flags '%s'.\n",
3761                                                 argv[0], optarg);
3762                                         return CMD_HELP;
3763                                 }
3764                                 param->fp_check_comp_flags = 1;
3765                         } else {
3766                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
3767                                 param->fp_max_depth = 0;
3768                         }
3769                         break;
3770                 case LFS_COMP_START_OPT:
3771                         if (optarg != NULL) {
3772                                 tmp = optarg;
3773                                 if (tmp[0] == '+') {
3774                                         param->fp_comp_start_sign = -1;
3775                                         tmp++;
3776                                 } else if (tmp[0] == '-') {
3777                                         param->fp_comp_start_sign = 1;
3778                                         tmp++;
3779                                 }
3780                                 rc = llapi_parse_size(tmp,
3781                                                 &param->fp_comp_start,
3782                                                 &param->fp_comp_start_units, 0);
3783                                 if (rc != 0) {
3784                                         fprintf(stderr, "error: %s bad "
3785                                                 "component start '%s'.\n",
3786                                                 argv[0], tmp);
3787                                         return CMD_HELP;
3788                                 } else {
3789                                         param->fp_check_comp_start = 1;
3790                                 }
3791                         } else {
3792                                 param->fp_verbose |= VERBOSE_COMP_START;
3793                                 param->fp_max_depth = 0;
3794                         }
3795                         break;
3796                 case 'd':
3797                         param->fp_max_depth = 0;
3798                         break;
3799                 case 'D':
3800                         param->fp_get_default_lmv = 1;
3801                         break;
3802                 case 'E':
3803                         if (optarg != NULL) {
3804                                 tmp = optarg;
3805                                 if (tmp[0] == '+') {
3806                                         param->fp_comp_end_sign = -1;
3807                                         tmp++;
3808                                 } else if (tmp[0] == '-') {
3809                                         param->fp_comp_end_sign = 1;
3810                                         tmp++;
3811                                 }
3812
3813                                 if (arg_is_eof(tmp)) {
3814                                         param->fp_comp_end = LUSTRE_EOF;
3815                                         param->fp_comp_end_units = 1;
3816                                         rc = 0;
3817                                 } else {
3818                                         rc = llapi_parse_size(tmp,
3819                                                 &param->fp_comp_end,
3820                                                 &param->fp_comp_end_units, 0);
3821                                 }
3822                                 if (rc != 0) {
3823                                         fprintf(stderr, "error: %s bad "
3824                                                 "component end '%s'.\n",
3825                                                 argv[0], tmp);
3826                                         return CMD_HELP;
3827                                 }
3828                                 param->fp_check_comp_end = 1;
3829                         } else {
3830                                 param->fp_verbose |= VERBOSE_COMP_END;
3831                                 param->fp_max_depth = 0;
3832                         }
3833                         break;
3834                 case 'F':
3835                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3836                                 param->fp_verbose |= VERBOSE_DFID;
3837                                 param->fp_max_depth = 0;
3838                         }
3839                         break;
3840                 case 'g':
3841                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3842                                 param->fp_verbose |= VERBOSE_GENERATION;
3843                                 param->fp_max_depth = 0;
3844                         }
3845                         break;
3846                 case 'i':
3847                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3848                                 param->fp_verbose |= VERBOSE_OFFSET;
3849                                 param->fp_max_depth = 0;
3850                         }
3851                         break;
3852                 case 'I':
3853                         if (optarg != NULL) {
3854                                 param->fp_comp_id = strtoul(optarg, &end, 0);
3855                                 if (*end != '\0' || param->fp_comp_id == 0 ||
3856                                     param->fp_comp_id > LCME_ID_MAX) {
3857                                         fprintf(stderr, "error: %s bad "
3858                                                 "component id '%s'\n",
3859                                                 argv[0], optarg);
3860                                         return CMD_HELP;
3861                                 } else {
3862                                         param->fp_check_comp_id = 1;
3863                                 }
3864                         } else {
3865                                 param->fp_max_depth = 0;
3866                                 param->fp_verbose |= VERBOSE_COMP_ID;
3867                         }
3868                         break;
3869                 case 'L':
3870                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3871                                 param->fp_verbose |= VERBOSE_LAYOUT;
3872                                 param->fp_max_depth = 0;
3873                         }
3874                         break;
3875 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3876                 case 'M':
3877                         fprintf(stderr, "warning: '-M' deprecated"
3878                                 ", use '--mdt-index' or '-m' instead\n");
3879 #endif
3880                 case 'm':
3881                         if (!(param->fp_verbose & VERBOSE_DETAIL))
3882                                 param->fp_max_depth = 0;
3883                         param->fp_verbose |= VERBOSE_MDTINDEX;
3884                         break;
3885                 case 'O':
3886                         if (param->fp_obd_uuid) {
3887                                 fprintf(stderr,
3888                                         "error: %s: only one obduuid allowed",
3889                                         argv[0]);
3890                                 return CMD_HELP;
3891                         }
3892                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
3893                         break;
3894                 case 'p':
3895                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3896                                 param->fp_verbose |= VERBOSE_POOL;
3897                                 param->fp_max_depth = 0;
3898                         }
3899                         break;
3900                 case 'q':
3901                         param->fp_quiet++;
3902                         break;
3903                 case 'r':
3904                         param->fp_recursive = 1;
3905                         break;
3906                 case 'R':
3907                         param->fp_raw = 1;
3908                         break;
3909                 case 'S':
3910                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3911                                 param->fp_verbose |= VERBOSE_SIZE;
3912                                 param->fp_max_depth = 0;
3913                         }
3914                         break;
3915                 case 'v':
3916                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
3917                         break;
3918                 case 'y':
3919                         param->fp_yaml = 1;
3920                         break;
3921                 default:
3922                         return CMD_HELP;
3923                 }
3924         }
3925
3926         if (optind >= argc)
3927                 return CMD_HELP;
3928
3929         if (param->fp_recursive)
3930                 param->fp_max_depth = -1;
3931         else if (param->fp_verbose & VERBOSE_DETAIL)
3932                 param->fp_max_depth = 1;
3933
3934         if (!param->fp_verbose)
3935                 param->fp_verbose = VERBOSE_DEFAULT;
3936         if (param->fp_quiet)
3937                 param->fp_verbose = VERBOSE_OBJID;
3938
3939         do {
3940                 rc = llapi_getstripe(argv[optind], param);
3941         } while (++optind < argc && !rc);
3942
3943         if (rc)
3944                 fprintf(stderr, "error: %s failed for %s.\n",
3945                         argv[0], argv[optind - 1]);
3946         return rc;
3947 }
3948
3949 static int lfs_tgts(int argc, char **argv)
3950 {
3951         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3952         struct find_param param;
3953         int index = 0, rc=0;
3954
3955         if (argc > 2)
3956                 return CMD_HELP;
3957
3958         if (argc == 2 && !realpath(argv[1], path)) {
3959                 rc = -errno;
3960                 fprintf(stderr, "error: invalid path '%s': %s\n",
3961                         argv[1], strerror(-rc));
3962                 return rc;
3963         }
3964
3965         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
3966                 /* Check if we have a mount point */
3967                 if (mntdir[0] == '\0')
3968                         continue;
3969
3970                 memset(&param, 0, sizeof(param));
3971                 if (!strcmp(argv[0], "mdts"))
3972                         param.fp_get_lmv = 1;
3973
3974                 rc = llapi_ostlist(mntdir, &param);
3975                 if (rc) {
3976                         fprintf(stderr, "error: %s: failed on %s\n",
3977                                 argv[0], mntdir);
3978                 }
3979                 if (path[0] != '\0')
3980                         break;
3981                 memset(mntdir, 0, PATH_MAX);
3982         }
3983
3984         return rc;
3985 }
3986
3987 static int lfs_getstripe(int argc, char **argv)
3988 {
3989         struct find_param param = { 0 };
3990
3991         param.fp_max_depth = 1;
3992         return lfs_getstripe_internal(argc, argv, &param);
3993 }
3994
3995 /* functions */
3996 static int lfs_getdirstripe(int argc, char **argv)
3997 {
3998         struct find_param param = { 0 };
3999         struct option long_opts[] = {
4000         { .val = 'c',   .name = "mdt-count",    .has_arg = no_argument },
4001         { .val = 'D',   .name = "default",      .has_arg = no_argument },
4002         { .val = 'H',   .name = "mdt-hash",     .has_arg = no_argument },
4003         { .val = 'i',   .name = "mdt-index",    .has_arg = no_argument },
4004         { .val = 'm',   .name = "mdt-index",    .has_arg = no_argument },
4005         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
4006         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
4007         { .val = 'T',   .name = "mdt-count",    .has_arg = no_argument },
4008         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
4009         { .name = NULL } };
4010         int c, rc;
4011
4012         param.fp_get_lmv = 1;
4013
4014         while ((c = getopt_long(argc, argv,
4015                                 "cDHimO:rtTy", long_opts, NULL)) != -1)
4016         {
4017                 switch (c) {
4018                 case 'c':
4019                 case 'T':
4020                         param.fp_verbose |= VERBOSE_COUNT;
4021                         break;
4022                 case 'D':
4023                         param.fp_get_default_lmv = 1;
4024                         break;
4025                 case 'i':
4026                 case 'm':
4027                         param.fp_verbose |= VERBOSE_OFFSET;
4028                         break;
4029 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
4030                 case 't':
4031                         fprintf(stderr, "warning: '-t' deprecated, "
4032                                 "use '--mdt-hash' or '-H' instead\n");
4033 #endif
4034                 case 'H':
4035                         param.fp_verbose |= VERBOSE_HASH_TYPE;
4036                         break;
4037                 case 'O':
4038                         if (param.fp_obd_uuid) {
4039                                 fprintf(stderr,
4040                                         "error: %s: only one obduuid allowed",
4041                                         argv[0]);
4042                                 return CMD_HELP;
4043                         }
4044                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
4045                         break;
4046                 case 'r':
4047                         param.fp_recursive = 1;
4048                         break;
4049                 case 'y':
4050                         param.fp_yaml = 1;
4051                         break;
4052                 default:
4053                         return CMD_HELP;
4054                 }
4055         }
4056
4057         if (optind >= argc)
4058                 return CMD_HELP;
4059
4060         if (param.fp_recursive)
4061                 param.fp_max_depth = -1;
4062
4063         if (!param.fp_verbose)
4064                 param.fp_verbose = VERBOSE_DEFAULT;
4065
4066         do {
4067                 rc = llapi_getstripe(argv[optind], &param);
4068         } while (++optind < argc && !rc);
4069
4070         if (rc)
4071                 fprintf(stderr, "error: %s failed for %s.\n",
4072                         argv[0], argv[optind - 1]);
4073         return rc;
4074 }
4075
4076 /* functions */
4077 static int lfs_setdirstripe(int argc, char **argv)
4078 {
4079         char                    *dname;
4080         int                     result;
4081         struct lfs_setstripe_args        lsa;
4082         struct llapi_stripe_param       *param = NULL;
4083         __u32                   mdts[LMV_MAX_STRIPE_COUNT] = { 0 };
4084         char                    *end;
4085         int                     c;
4086         char                    *mode_opt = NULL;
4087         bool                    default_stripe = false;
4088         mode_t                  mode = S_IRWXU | S_IRWXG | S_IRWXO;
4089         mode_t                  previous_mode = 0;
4090         bool                    delete = false;
4091
4092         struct option long_opts[] = {
4093         { .val = 'c',   .name = "count",        .has_arg = required_argument },
4094         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
4095         { .val = 'd',   .name = "delete",       .has_arg = no_argument },
4096         { .val = 'D',   .name = "default",      .has_arg = no_argument },
4097         { .val = 'D',   .name = "default_stripe", .has_arg = no_argument },
4098         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
4099         { .val = 'i',   .name = "mdt-index",    .has_arg = required_argument },
4100 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
4101         { .val = 'i',   .name = "index",        .has_arg = required_argument },
4102 #endif
4103         { .val = 'o',   .name = "mode",         .has_arg = required_argument },
4104 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
4105         { .val = 't',   .name = "hash-type",    .has_arg = required_argument },
4106 #endif
4107         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
4108         { .name = NULL } };
4109
4110         setstripe_args_init(&lsa);
4111
4112         while ((c = getopt_long(argc, argv, "c:dDi:H:m:o:t:T:", long_opts,
4113                                 NULL)) >= 0) {
4114                 switch (c) {
4115                 case 0:
4116                         /* Long options. */
4117                         break;
4118                 case 'c':
4119                 case 'T':
4120                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
4121                         if (*end != '\0') {
4122                                 fprintf(stderr,
4123                                         "%s %s: invalid stripe count '%s'\n",
4124                                         progname, argv[0], optarg);
4125                                 return CMD_HELP;
4126                         }
4127                         break;
4128                 case 'd':
4129                         delete = true;
4130                         default_stripe = true;
4131                         break;
4132                 case 'D':
4133                         default_stripe = true;
4134                         break;
4135 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
4136                 case 't':
4137                         fprintf(stderr, "warning: '--hash-type' and '-t' "
4138                               "deprecated, use '--mdt-hash' or '-H' instead\n");
4139 #endif
4140                 case 'H':
4141                         lsa.lsa_pattern = check_hashtype(optarg);
4142                         if (lsa.lsa_pattern == 0) {
4143                                 fprintf(stderr,
4144                                         "%s %s: bad stripe hash type '%s'\n",
4145                                         progname, argv[0], optarg);
4146                                 return CMD_HELP;
4147                         }
4148                         break;
4149                 case 'i':
4150 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
4151                         if (strcmp(argv[optind - 1], "--index") == 0)
4152                                 fprintf(stderr,
4153                                         "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
4154                                         progname, argv[0]);
4155 #endif
4156                         lsa.lsa_nr_tgts = parse_targets(mdts,
4157                                                 sizeof(mdts) / sizeof(__u32),
4158                                                 lsa.lsa_nr_tgts, optarg);
4159                         if (lsa.lsa_nr_tgts < 0) {
4160                                 fprintf(stderr,
4161                                         "%s %s: invalid MDT target(s) '%s'\n",
4162                                         progname, argv[0], optarg);
4163                                 return CMD_HELP;
4164                         }
4165
4166                         lsa.lsa_tgts = mdts;
4167                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4168                                 lsa.lsa_stripe_off = mdts[0];
4169                         break;
4170 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 16, 53, 0)
4171                 case 'm':
4172                         fprintf(stderr, "warning: '-m' is deprecated, "
4173                                 "use '--mode' or '-o' instead\n");
4174 #endif
4175                 case 'o':
4176                         mode_opt = optarg;
4177                         break;
4178                 default:
4179                         fprintf(stderr, "%s %s: unrecognized option '%s'\n",
4180                                 progname, argv[0], argv[optind - 1]);
4181                         return CMD_HELP;
4182                 }
4183         }
4184
4185         if (optind == argc) {
4186                 fprintf(stderr, "%s %s: DIR must be specified\n",
4187                         progname, argv[0]);
4188                 return CMD_HELP;
4189         }
4190
4191         if (!delete && lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT &&
4192             lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT) {
4193                 fprintf(stderr,
4194                         "%s %s: stripe offset and count must be specified\n",
4195                         progname, argv[0]);
4196                 return CMD_HELP;
4197         }
4198
4199         if (delete &&
4200             (lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
4201              lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)) {
4202                 fprintf(stderr,
4203                         "%s %s: cannot specify -d with -c or -i options\n",
4204                         progname, argv[0]);
4205                 return CMD_HELP;
4206         }
4207
4208         if (mode_opt != NULL) {
4209                 mode = strtoul(mode_opt, &end, 8);
4210                 if (*end != '\0') {
4211                         fprintf(stderr,
4212                                 "%s %s: bad MODE '%s'\n",
4213                                 progname, argv[0], mode_opt);
4214                         return CMD_HELP;
4215                 }
4216                 previous_mode = umask(0);
4217         }
4218
4219         /* initialize stripe parameters */
4220         param = calloc(1, offsetof(typeof(*param), lsp_osts[lsa.lsa_nr_tgts]));
4221         if (param == NULL) {
4222                 fprintf(stderr,
4223                         "%s %s: cannot allocate memory for parameters: %s\n",
4224                         progname, argv[0], strerror(ENOMEM));
4225                 return CMD_HELP;
4226         }
4227
4228         if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
4229                 param->lsp_stripe_count = lsa.lsa_stripe_count;
4230         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4231                 param->lsp_stripe_offset = -1;
4232         else
4233                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
4234         if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
4235                 param->lsp_stripe_pattern = lsa.lsa_pattern;
4236         else
4237                 param->lsp_stripe_pattern = LMV_HASH_TYPE_FNV_1A_64;
4238         param->lsp_pool = lsa.lsa_pool_name;
4239         param->lsp_is_specific = false;
4240         if (lsa.lsa_nr_tgts > 1) {
4241                 if (lsa.lsa_stripe_count > 0 &&
4242                     lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
4243                     lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
4244                         fprintf(stderr, "error: %s: stripe count %lld doesn't "
4245                                 "match the number of MDTs: %d\n",
4246                                 argv[0], lsa.lsa_stripe_count, lsa.lsa_nr_tgts);
4247                         free(param);
4248                         return CMD_HELP;
4249                 }
4250
4251                 param->lsp_is_specific = true;
4252                 param->lsp_stripe_count = lsa.lsa_nr_tgts;
4253                 memcpy(param->lsp_tgts, mdts, sizeof(*mdts) * lsa.lsa_nr_tgts);
4254         }
4255
4256         dname = argv[optind];
4257         do {
4258                 if (default_stripe)
4259                         result = llapi_dir_set_default_lmv(dname, param);
4260                 else
4261                         result = llapi_dir_create_param(dname, mode, param);
4262
4263                 if (result) {
4264                         fprintf(stderr,
4265                                 "%s setdirstripe: cannot create stripe dir '%s': %s\n",
4266                                 progname, dname, strerror(-result));
4267                         break;
4268                 }
4269                 dname = argv[++optind];
4270         } while (dname != NULL);
4271
4272         if (mode_opt != NULL)
4273                 umask(previous_mode);
4274
4275         free(param);
4276         return result;
4277 }
4278
4279 /* functions */
4280 static int lfs_rmentry(int argc, char **argv)
4281 {
4282         char *dname;
4283         int   index;
4284         int   result = 0;
4285
4286         if (argc <= 1) {
4287                 fprintf(stderr, "error: %s: missing dirname\n",
4288                         argv[0]);
4289                 return CMD_HELP;
4290         }
4291
4292         index = 1;
4293         dname = argv[index];
4294         while (dname != NULL) {
4295                 result = llapi_direntry_remove(dname);
4296                 if (result) {
4297                         fprintf(stderr, "error: %s: remove dir entry '%s' "
4298                                 "failed\n", argv[0], dname);
4299                         break;
4300                 }
4301                 dname = argv[++index];
4302         }
4303         return result;
4304 }
4305
4306 static int lfs_mv(int argc, char **argv)
4307 {
4308         struct  find_param param = {
4309                 .fp_max_depth = -1,
4310                 .fp_mdt_index = -1,
4311         };
4312         char   *end;
4313         int     c;
4314         int     rc = 0;
4315         struct option long_opts[] = {
4316         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
4317         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
4318         { .name = NULL } };
4319
4320         while ((c = getopt_long(argc, argv, "m:M:v", long_opts, NULL)) != -1) {
4321                 switch (c) {
4322 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
4323                 case 'M':
4324                         fprintf(stderr, "warning: '-M' deprecated"
4325                                 ", use '--mdt-index' or '-m' instead\n");
4326 #endif
4327                 case 'm':
4328                         param.fp_mdt_index = strtoul(optarg, &end, 0);
4329                         if (*end != '\0') {
4330                                 fprintf(stderr, "%s: invalid MDT index'%s'\n",
4331                                         argv[0], optarg);
4332                                 return CMD_HELP;
4333                         }
4334                         break;
4335                 case 'v':
4336                         param.fp_verbose = VERBOSE_DETAIL;
4337                         break;
4338                 default:
4339                         fprintf(stderr, "error: %s: unrecognized option '%s'\n",
4340                                 argv[0], argv[optind - 1]);
4341                         return CMD_HELP;
4342                 }
4343         }
4344
4345         if (param.fp_mdt_index == -1) {
4346                 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
4347                 return CMD_HELP;
4348         }
4349
4350         if (optind >= argc) {
4351                 fprintf(stderr, "%s: missing operand path\n", argv[0]);
4352                 return CMD_HELP;
4353         }
4354
4355         param.fp_migrate = 1;
4356         rc = llapi_migrate_mdt(argv[optind], &param);
4357         if (rc != 0)
4358                 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
4359                         argv[0], argv[optind], param.fp_mdt_index,
4360                         strerror(-rc));
4361         return rc;
4362 }
4363
4364 static int lfs_osts(int argc, char **argv)
4365 {
4366         return lfs_tgts(argc, argv);
4367 }
4368
4369 static int lfs_mdts(int argc, char **argv)
4370 {
4371         return lfs_tgts(argc, argv);
4372 }
4373
4374 #define COOK(value)                                                     \
4375 ({                                                                      \
4376         int radix = 0;                                                  \
4377         while (value > 1024) {                                          \
4378                 value /= 1024;                                          \
4379                 radix++;                                                \
4380         }                                                               \
4381         radix;                                                          \
4382 })
4383 #define UUF     "%-20s"
4384 #define CSF     "%11s"
4385 #define CDF     "%11llu"
4386 #define HDF     "%8.1f%c"
4387 #define RSF     "%4s"
4388 #define RDF     "%3d%%"
4389
4390 enum mntdf_flags {
4391         MNTDF_INODES    = 0x0001,
4392         MNTDF_COOKED    = 0x0002,
4393         MNTDF_LAZY      = 0x0004,
4394         MNTDF_VERBOSE   = 0x0008,
4395 };
4396
4397 static int showdf(char *mntdir, struct obd_statfs *stat,
4398                   char *uuid, enum mntdf_flags flags,
4399                   char *type, int index, int rc)
4400 {
4401         long long avail, used, total;
4402         double ratio = 0;
4403         char *suffix = "KMGTPEZY";
4404         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
4405         char tbuf[3 * sizeof(__u64)];
4406         char ubuf[3 * sizeof(__u64)];
4407         char abuf[3 * sizeof(__u64)];
4408         char rbuf[3 * sizeof(__u64)];
4409
4410         if (!uuid || !stat)
4411                 return -EINVAL;
4412
4413         switch (rc) {
4414         case 0:
4415                 if (flags & MNTDF_INODES) {
4416                         avail = stat->os_ffree;
4417                         used = stat->os_files - stat->os_ffree;
4418                         total = stat->os_files;
4419                 } else {
4420                         int shift = flags & MNTDF_COOKED ? 0 : 10;
4421
4422                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
4423                         used  = ((stat->os_blocks - stat->os_bfree) *
4424                                  stat->os_bsize) >> shift;
4425                         total = (stat->os_blocks * stat->os_bsize) >> shift;
4426                 }
4427
4428                 if ((used + avail) > 0)
4429                         ratio = (double)used / (double)(used + avail);
4430
4431                 if (flags & MNTDF_COOKED) {
4432                         int i;
4433                         double cook_val;
4434
4435                         cook_val = (double)total;
4436                         i = COOK(cook_val);
4437                         if (i > 0)
4438                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
4439                                          suffix[i - 1]);
4440                         else
4441                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
4442
4443                         cook_val = (double)used;
4444                         i = COOK(cook_val);
4445                         if (i > 0)
4446                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
4447                                          suffix[i - 1]);
4448                         else
4449                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
4450
4451                         cook_val = (double)avail;
4452                         i = COOK(cook_val);
4453                         if (i > 0)
4454                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
4455                                          suffix[i - 1]);
4456                         else
4457                                 snprintf(abuf, sizeof(abuf), CDF, avail);
4458                 } else {
4459                         snprintf(tbuf, sizeof(tbuf), CDF, total);
4460                         snprintf(ubuf, sizeof(tbuf), CDF, used);
4461                         snprintf(abuf, sizeof(tbuf), CDF, avail);
4462                 }
4463
4464                 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
4465                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
4466                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
4467                 if (type)
4468                         printf("[%s:%d]", type, index);
4469
4470                 if (stat->os_state) {
4471                         /*
4472                          * Each character represents the matching
4473                          * OS_STATE_* bit.
4474                          */
4475                         const char state_names[] = "DRSI";
4476                         __u32      state;
4477                         __u32      i;
4478
4479                         printf(" ");
4480                         for (i = 0, state = stat->os_state;
4481                              state && i < sizeof(state_names); i++) {
4482                                 if (!(state & (1 << i)))
4483                                         continue;
4484                                 printf("%c", state_names[i]);
4485                                 state ^= 1 << i;
4486                         }
4487                 }
4488
4489                 printf("\n");
4490                 break;
4491         case -ENODATA:
4492                 printf(UUF": inactive device\n", uuid);
4493                 break;
4494         default:
4495                 printf(UUF": %s\n", uuid, strerror(-rc));
4496                 break;
4497         }
4498
4499         return 0;
4500 }
4501
4502 struct ll_stat_type {
4503         int   st_op;
4504         char *st_name;
4505 };
4506
4507 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
4508 {
4509         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
4510         struct obd_uuid uuid_buf;
4511         char *poolname = NULL;
4512         struct ll_stat_type types[] = {
4513                 { .st_op = LL_STATFS_LMV,       .st_name = "MDT" },
4514                 { .st_op = LL_STATFS_LOV,       .st_name = "OST" },
4515                 { .st_name = NULL } };
4516         struct ll_stat_type *tp;
4517         __u64 ost_ffree = 0;
4518         __u32 index;
4519         __u32 type;
4520         int fd;
4521         int rc = 0;
4522         int rc2;
4523
4524         if (pool) {
4525                 poolname = strchr(pool, '.');
4526                 if (poolname != NULL) {
4527                         if (strncmp(fsname, pool, strlen(fsname))) {
4528                                 fprintf(stderr, "filesystem name incorrect\n");
4529                                 return -ENODEV;
4530                         }
4531                         poolname++;
4532                 } else
4533                         poolname = pool;
4534         }
4535
4536         fd = open(mntdir, O_RDONLY);
4537         if (fd < 0) {
4538                 rc = -errno;
4539                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
4540                         strerror(errno));
4541                 return rc;
4542         }
4543
4544         if (flags & MNTDF_INODES)
4545                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
4546                        "UUID", "Inodes", "IUsed", "IFree",
4547                        "IUse%", "Mounted on");
4548         else
4549                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
4550                        "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
4551                        "Used", "Available", "Use%", "Mounted on");
4552
4553         for (tp = types; tp->st_name != NULL; tp++) {
4554                 for (index = 0; ; index++) {
4555                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
4556                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
4557                         type = flags & MNTDF_LAZY ?
4558                                 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
4559                         rc2 = llapi_obd_fstatfs(fd, type, index,
4560                                                &stat_buf, &uuid_buf);
4561                         if (rc2 == -ENODEV)
4562                                 break;
4563                         if (rc2 == -EAGAIN)
4564                                 continue;
4565                         if (rc2 == -ENODATA) { /* Inactive device, OK. */
4566                                 if (!(flags & MNTDF_VERBOSE))
4567                                         continue;
4568                         } else if (rc2 < 0 && rc == 0) {
4569                                 rc = rc2;
4570                         }
4571
4572                         if (poolname && tp->st_op == LL_STATFS_LOV &&
4573                             llapi_search_ost(fsname, poolname,
4574                                              obd_uuid2str(&uuid_buf)) != 1)
4575                                 continue;
4576
4577                         /* the llapi_obd_statfs() call may have returned with
4578                          * an error, but if it filled in uuid_buf we will at
4579                          * lease use that to print out a message for that OBD.
4580                          * If we didn't get anything in the uuid_buf, then fill
4581                          * it in so that we can print an error message. */
4582                         if (uuid_buf.uuid[0] == '\0')
4583                                 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
4584                                          "%s%04x", tp->st_name, index);
4585                         showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
4586                                flags, tp->st_name, index, rc2);
4587
4588                         if (rc2 == 0) {
4589                                 if (tp->st_op == LL_STATFS_LMV) {
4590                                         sum.os_ffree += stat_buf.os_ffree;
4591                                         sum.os_files += stat_buf.os_files;
4592                                 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
4593                                         sum.os_blocks += stat_buf.os_blocks *
4594                                                 stat_buf.os_bsize;
4595                                         sum.os_bfree  += stat_buf.os_bfree *
4596                                                 stat_buf.os_bsize;
4597                                         sum.os_bavail += stat_buf.os_bavail *
4598                                                 stat_buf.os_bsize;
4599                                         ost_ffree += stat_buf.os_ffree;
4600                                 }
4601                         }
4602                 }
4603         }
4604
4605         close(fd);
4606
4607         /* If we don't have as many objects free on the OST as inodes
4608          * on the MDS, we reduce the total number of inodes to
4609          * compensate, so that the "inodes in use" number is correct.
4610          * Matches ll_statfs_internal() so the results are consistent. */
4611         if (ost_ffree < sum.os_ffree) {
4612                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
4613                 sum.os_ffree = ost_ffree;
4614         }
4615         printf("\n");
4616         showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
4617         printf("\n");
4618
4619         return rc;
4620 }
4621
4622 static int lfs_df(int argc, char **argv)
4623 {
4624         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
4625         enum mntdf_flags flags = 0;
4626         int c, rc = 0, index = 0;
4627         char fsname[PATH_MAX] = "", *pool_name = NULL;
4628         struct option long_opts[] = {
4629         { .val = 'h',   .name = "human-readable",
4630                                                 .has_arg = no_argument },
4631         { .val = 'i',   .name = "inodes",       .has_arg = no_argument },
4632         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
4633         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
4634         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
4635         { .name = NULL} };
4636
4637         while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
4638                 switch (c) {
4639                 case 'h':
4640                         flags |= MNTDF_COOKED;
4641                         break;
4642                 case 'i':
4643                         flags |= MNTDF_INODES;
4644                         break;
4645                 case 'l':
4646                         flags |= MNTDF_LAZY;
4647                         break;
4648                 case 'p':
4649                         pool_name = optarg;
4650                         break;
4651                 case 'v':
4652                         flags |= MNTDF_VERBOSE;
4653                         break;
4654                 default:
4655                         return CMD_HELP;
4656                 }
4657         }
4658         if (optind < argc && !realpath(argv[optind], path)) {
4659                 rc = -errno;
4660                 fprintf(stderr, "error: invalid path '%s': %s\n",
4661                         argv[optind], strerror(-rc));
4662                 return rc;
4663         }
4664
4665         while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
4666                 /* Check if we have a mount point */
4667                 if (mntdir[0] == '\0')
4668                         continue;
4669
4670                 rc = mntdf(mntdir, fsname, pool_name, flags);
4671                 if (rc || path[0] != '\0')
4672                         break;
4673                 fsname[0] = '\0'; /* avoid matching in next loop */
4674                 mntdir[0] = '\0'; /* avoid matching in next loop */
4675         }
4676
4677         return rc;
4678 }
4679
4680 static int lfs_getname(int argc, char **argv)
4681 {
4682         char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
4683         int rc = 0, index = 0, c;
4684         char buf[sizeof(struct obd_uuid)];
4685
4686         while ((c = getopt(argc, argv, "h")) != -1)
4687                 return CMD_HELP;
4688
4689         if (optind == argc) { /* no paths specified, get all paths. */
4690                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
4691                         rc = llapi_getname(mntdir, buf, sizeof(buf));
4692                         if (rc < 0) {
4693                                 fprintf(stderr,
4694                                         "cannot get name for `%s': %s\n",
4695                                         mntdir, strerror(-rc));
4696                                 break;
4697                         }
4698
4699                         printf("%s %s\n", buf, mntdir);
4700
4701                         path[0] = fsname[0] = mntdir[0] = 0;
4702                 }
4703         } else { /* paths specified, only attempt to search these. */
4704                 for (; optind < argc; optind++) {
4705                         rc = llapi_getname(argv[optind], buf, sizeof(buf));
4706                         if (rc < 0) {
4707                                 fprintf(stderr,
4708                                         "cannot get name for `%s': %s\n",
4709                                         argv[optind], strerror(-rc));
4710                                 break;
4711                         }
4712
4713                         printf("%s %s\n", buf, argv[optind]);
4714                 }
4715         }
4716         return rc;
4717 }
4718
4719 static int lfs_check(int argc, char **argv)
4720 {
4721         int rc;
4722         char mntdir[PATH_MAX] = {'\0'};
4723         int num_types = 1;
4724         char *obd_types[2];
4725         char obd_type1[4];
4726         char obd_type2[4];
4727
4728         if (argc != 2) {
4729                 fprintf(stderr, "%s check: server type must be specified\n",
4730                         progname);
4731                 return CMD_HELP;
4732         }
4733
4734         obd_types[0] = obd_type1;
4735         obd_types[1] = obd_type2;
4736
4737         if (strcmp(argv[1], "osts") == 0) {
4738                 strcpy(obd_types[0], "osc");
4739         } else if (strcmp(argv[1], "mds") == 0) {
4740                 strcpy(obd_types[0], "mdc");
4741         } else if (strcmp(argv[1], "servers") == 0) {
4742                 num_types = 2;
4743                 strcpy(obd_types[0], "osc");
4744                 strcpy(obd_types[1], "mdc");
4745         } else {
4746                 fprintf(stderr, "%s check: unrecognized option '%s'\n",
4747                         progname, argv[1]);
4748                 return CMD_HELP;
4749         }
4750
4751         rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
4752         if (rc < 0 || mntdir[0] == '\0') {
4753                 fprintf(stderr,
4754                         "%s check: cannot find mounted Lustre filesystem: %s\n",
4755                         progname, (rc < 0) ? strerror(-rc) : strerror(ENODEV));
4756                 return rc;
4757         }
4758
4759         rc = llapi_target_check(num_types, obd_types, mntdir);
4760         if (rc)
4761                 fprintf(stderr, "%s check: cannot check target '%s': %s\n",
4762                         progname, argv[1], strerror(-rc));
4763
4764         return rc;
4765
4766 }
4767
4768 #ifdef HAVE_SYS_QUOTA_H
4769 #define ARG2INT(nr, str, msg)                                           \
4770 do {                                                                    \
4771         char *endp;                                                     \
4772         nr = strtol(str, &endp, 0);                                     \
4773         if (*endp != '\0') {                                            \
4774                 fprintf(stderr, "%s: bad %s '%s'\n",                    \
4775                         progname, msg, str);                            \
4776                 return CMD_HELP;                                        \
4777         }                                                               \
4778 } while (0)
4779
4780 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
4781
4782 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
4783  * returns the value or ULONG_MAX on integer overflow or incorrect format
4784  * Notes:
4785  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
4786  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
4787  *        3. empty integer value is interpreted as 0
4788  */
4789 static unsigned long str2sec(const char* timestr)
4790 {
4791         const char spec[] = "smhdw";
4792         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
4793         unsigned long val = 0;
4794         char *tail;
4795
4796         if (strpbrk(timestr, spec) == NULL) {
4797                 /* no specifiers inside the time string,
4798                    should treat it as an integer value */
4799                 val = strtoul(timestr, &tail, 10);
4800                 return *tail ? ULONG_MAX : val;
4801         }
4802
4803         /* format string is XXwXXdXXhXXmXXs */
4804         while (*timestr) {
4805                 unsigned long v;
4806                 int ind;
4807                 char* ptr;
4808
4809                 v = strtoul(timestr, &tail, 10);
4810                 if (v == ULONG_MAX || *tail == '\0')
4811                         /* value too large (ULONG_MAX or more)
4812                            or missing specifier */
4813                         goto error;
4814
4815                 ptr = strchr(spec, *tail);
4816                 if (ptr == NULL)
4817                         /* unknown specifier */
4818                         goto error;
4819
4820                 ind = ptr - spec;
4821
4822                 /* check if product will overflow the type */
4823                 if (!(v < ULONG_MAX / mult[ind]))
4824                         goto error;
4825
4826                 ADD_OVERFLOW(val, mult[ind] * v);
4827                 if (val == ULONG_MAX)
4828                         goto error;
4829
4830                 timestr = tail + 1;
4831         }
4832
4833         return val;
4834
4835 error:
4836         return ULONG_MAX;
4837 }
4838
4839 #define ARG2ULL(nr, str, def_units)                                     \
4840 do {                                                                    \
4841         unsigned long long limit, units = def_units;                    \
4842         int rc;                                                         \
4843                                                                         \
4844         rc = llapi_parse_size(str, &limit, &units, 1);                  \
4845         if (rc < 0) {                                                   \
4846                 fprintf(stderr, "%s: invalid limit '%s'\n",             \
4847                         progname, str);                                 \
4848                 return CMD_HELP;                                        \
4849         }                                                               \
4850         nr = limit;                                                     \
4851 } while (0)
4852
4853 static inline int has_times_option(int argc, char **argv)
4854 {
4855         int i;
4856
4857         for (i = 1; i < argc; i++)
4858                 if (!strcmp(argv[i], "-t"))
4859                         return 1;
4860
4861         return 0;
4862 }
4863
4864 int lfs_setquota_times(int argc, char **argv)
4865 {
4866         int c, rc;
4867         struct if_quotactl qctl;
4868         char *mnt, *obd_type = (char *)qctl.obd_type;
4869         struct obd_dqblk *dqb = &qctl.qc_dqblk;
4870         struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
4871         struct option long_opts[] = {
4872         { .val = 'b',   .name = "block-grace",  .has_arg = required_argument },
4873         { .val = 'g',   .name = "group",        .has_arg = no_argument },
4874         { .val = 'i',   .name = "inode-grace",  .has_arg = required_argument },
4875         { .val = 'p',   .name = "projid",       .has_arg = no_argument },
4876         { .val = 't',   .name = "times",        .has_arg = no_argument },
4877         { .val = 'u',   .name = "user",         .has_arg = no_argument },
4878         { .name = NULL } };
4879         int qtype;
4880
4881         memset(&qctl, 0, sizeof(qctl));
4882         qctl.qc_cmd  = LUSTRE_Q_SETINFO;
4883         qctl.qc_type = ALLQUOTA;
4884
4885         while ((c = getopt_long(argc, argv, "b:gi:ptu",
4886                                 long_opts, NULL)) != -1) {
4887                 switch (c) {
4888                 case 'u':
4889                         qtype = USRQUOTA;
4890                         goto quota_type;
4891                 case 'g':
4892                         qtype = GRPQUOTA;
4893                         goto quota_type;
4894                 case 'p':
4895                         qtype = PRJQUOTA;
4896 quota_type:
4897                         if (qctl.qc_type != ALLQUOTA) {
4898                                 fprintf(stderr, "error: -u/g/p can't be used "
4899                                                 "more than once\n");
4900                                 return CMD_HELP;
4901                         }
4902                         qctl.qc_type = qtype;
4903                         break;
4904                 case 'b':
4905                         if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
4906                                 fprintf(stderr, "error: bad block-grace: %s\n",
4907                                         optarg);
4908                                 return CMD_HELP;
4909                         }
4910                         dqb->dqb_valid |= QIF_BTIME;
4911                         break;
4912                 case 'i':
4913                         if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
4914                                 fprintf(stderr, "error: bad inode-grace: %s\n",
4915                                         optarg);
4916                                 return CMD_HELP;
4917                         }
4918                         dqb->dqb_valid |= QIF_ITIME;
4919                         break;
4920                 case 't': /* Yes, of course! */
4921                         break;
4922                 default: /* getopt prints error message for us when opterr != 0 */
4923                         return CMD_HELP;
4924                 }
4925         }
4926
4927         if (qctl.qc_type == ALLQUOTA) {
4928                 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
4929                 return CMD_HELP;
4930         }
4931
4932         if (optind != argc - 1) {
4933                 fprintf(stderr, "error: unexpected parameters encountered\n");
4934                 return CMD_HELP;
4935         }
4936
4937         mnt = argv[optind];
4938         rc = llapi_quotactl(mnt, &qctl);
4939         if (rc) {
4940                 if (*obd_type)
4941                         fprintf(stderr, "%s %s ", obd_type,
4942                                 obd_uuid2str(&qctl.obd_uuid));
4943                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
4944                 return rc;
4945         }
4946
4947         return 0;
4948 }
4949
4950 #define BSLIMIT (1 << 0)
4951 #define BHLIMIT (1 << 1)
4952 #define ISLIMIT (1 << 2)
4953 #define IHLIMIT (1 << 3)
4954
4955 int lfs_setquota(int argc, char **argv)
4956 {
4957         int c, rc;
4958         struct if_quotactl qctl;
4959         char *mnt, *obd_type = (char *)qctl.obd_type;
4960         struct obd_dqblk *dqb = &qctl.qc_dqblk;
4961         struct option long_opts[] = {
4962         { .val = 'b',   .name = "block-softlimit",
4963                                                 .has_arg = required_argument },
4964         { .val = 'B',   .name = "block-hardlimit",
4965                                                 .has_arg = required_argument },
4966         { .val = 'g',   .name = "group",        .has_arg = required_argument },
4967         { .val = 'i',   .name = "inode-softlimit",
4968                                                 .has_arg = required_argument },
4969         { .val = 'I',   .name = "inode-hardlimit",
4970                                                 .has_arg = required_argument },
4971         { .val = 'p',   .name = "projid",       .has_arg = required_argument },
4972         { .val = 'u',   .name = "user",         .has_arg = required_argument },
4973         { .name = NULL } };
4974         unsigned limit_mask = 0;
4975         char *endptr;
4976         int qtype;
4977
4978         if (has_times_option(argc, argv))
4979                 return lfs_setquota_times(argc, argv);
4980
4981         memset(&qctl, 0, sizeof(qctl));
4982         qctl.qc_cmd  = LUSTRE_Q_SETQUOTA;
4983         qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
4984                                   * so it can be used as a marker that qc_type
4985                                   * isn't reinitialized from command line */
4986
4987         while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
4988                 long_opts, NULL)) != -1) {
4989                 switch (c) {
4990                 case 'u':
4991                         qtype = USRQUOTA;
4992                         rc = name2uid(&qctl.qc_id, optarg);
4993                         goto quota_type;
4994                 case 'g':
4995                         qtype = GRPQUOTA;
4996                         rc = name2gid(&qctl.qc_id, optarg);
4997                         goto quota_type;
4998                 case 'p':
4999                         qtype = PRJQUOTA;
5000                         rc = name2projid(&qctl.qc_id, optarg);
5001 quota_type:
5002                         if (qctl.qc_type != ALLQUOTA) {
5003                                 fprintf(stderr,
5004                                         "%s setquota: only one of -u, -g or -p may be specified\n",
5005                                         progname);
5006                                 return CMD_HELP;
5007                         }
5008                         qctl.qc_type = qtype;
5009                         if (rc) {
5010                                 qctl.qc_id = strtoul(optarg, &endptr, 10);
5011                                 if (*endptr != '\0') {
5012                                         fprintf(stderr,
5013                                                 "%s setquota: invalid id '%s'\n",
5014                                                 progname, optarg);
5015                                         return -1;
5016                                 }
5017                         }
5018                         break;
5019                 case 'b':
5020                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
5021                         dqb->dqb_bsoftlimit >>= 10;
5022                         limit_mask |= BSLIMIT;
5023                         if (dqb->dqb_bsoftlimit &&
5024                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
5025                                 fprintf(stderr,
5026                                         "%s setquota: warning: block softlimit '%llu' smaller than minimum qunit size\n"
5027                                         "See '%s help setquota' or Lustre manual for details\n",
5028                                         progname, dqb->dqb_bsoftlimit,
5029                                         progname);
5030                         break;
5031                 case 'B':
5032                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
5033                         dqb->dqb_bhardlimit >>= 10;
5034                         limit_mask |= BHLIMIT;
5035                         if (dqb->dqb_bhardlimit &&
5036                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
5037                                 fprintf(stderr,
5038                                         "%s setquota: warning: block hardlimit '%llu' smaller than minimum qunit size\n"
5039                                         "See '%s help setquota' or Lustre manual for details\n",
5040                                         progname, dqb->dqb_bhardlimit,
5041                                         progname);
5042                         break;
5043                 case 'i':
5044                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
5045                         limit_mask |= ISLIMIT;
5046                         if (dqb->dqb_isoftlimit &&
5047                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
5048                                 fprintf(stderr,
5049                                         "%s setquota: warning: inode softlimit '%llu' smaller than minimum qunit size\n"
5050                                         "See '%s help setquota' or Lustre manual for details\n",
5051                                         progname, dqb->dqb_isoftlimit,
5052                                         progname);
5053                         break;
5054                 case 'I':
5055                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
5056                         limit_mask |= IHLIMIT;
5057                         if (dqb->dqb_ihardlimit &&
5058                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
5059                                 fprintf(stderr,
5060                                         "%s setquota: warning: inode hardlimit '%llu' smaller than minimum qunit size\n"
5061                                         "See '%s help setquota' or Lustre manual for details\n",
5062                                         progname, dqb->dqb_ihardlimit,
5063                                         progname);
5064                         break;
5065                 default:
5066                         fprintf(stderr,
5067                                 "%s setquota: unrecognized option '%s'\n",
5068                                 progname, argv[optind - 1]);
5069                         return CMD_HELP;
5070                 }
5071         }
5072
5073         if (qctl.qc_type == ALLQUOTA) {
5074                 fprintf(stderr,
5075                         "%s setquota: either -u or -g must be specified\n",
5076                         progname);
5077                 return CMD_HELP;
5078         }
5079
5080         if (limit_mask == 0) {
5081                 fprintf(stderr,
5082                         "%s setquota: at least one limit must be specified\n",
5083                         progname);
5084                 return CMD_HELP;
5085         }
5086
5087         if (optind != argc - 1) {
5088                 fprintf(stderr,
5089                         "%s setquota: filesystem not specified or unexpected argument '%s'\n",
5090                         progname, argv[optind]);
5091                 return CMD_HELP;
5092         }
5093
5094         mnt = argv[optind];
5095
5096         if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
5097             (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
5098                 /* sigh, we can't just set blimits/ilimits */
5099                 struct if_quotactl tmp_qctl = {.qc_cmd  = LUSTRE_Q_GETQUOTA,
5100                                                .qc_type = qctl.qc_type,
5101                                                .qc_id   = qctl.qc_id};
5102
5103                 rc = llapi_quotactl(mnt, &tmp_qctl);
5104                 if (rc < 0)
5105                         return rc;
5106
5107                 if (!(limit_mask & BHLIMIT))
5108                         dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
5109                 if (!(limit_mask & BSLIMIT))
5110                         dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
5111                 if (!(limit_mask & IHLIMIT))
5112                         dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
5113                 if (!(limit_mask & ISLIMIT))
5114                         dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
5115
5116                 /* Keep grace times if we have got no softlimit arguments */
5117                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
5118                         dqb->dqb_valid |= QIF_BTIME;
5119                         dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
5120                 }
5121
5122                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
5123                         dqb->dqb_valid |= QIF_ITIME;
5124                         dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
5125                 }
5126         }
5127
5128         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
5129         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
5130
5131         rc = llapi_quotactl(mnt, &qctl);
5132         if (rc) {
5133                 if (*obd_type)
5134                         fprintf(stderr,
5135                                 "%s setquota: cannot quotactl '%s' '%s': %s",
5136                                 progname, obd_type,
5137                                 obd_uuid2str(&qctl.obd_uuid), strerror(-rc));
5138                 return rc;
5139         }
5140
5141         return 0;
5142 }
5143
5144 /* Converts seconds value into format string
5145  * result is returned in buf
5146  * Notes:
5147  *        1. result is in descenting order: 1w2d3h4m5s
5148  *        2. zero fields are not filled (except for p. 3): 5d1s
5149  *        3. zero seconds value is presented as "0s"
5150  */
5151 static char * __sec2str(time_t seconds, char *buf)
5152 {
5153         const char spec[] = "smhdw";
5154         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
5155         unsigned long c;
5156         char *tail = buf;
5157         int i;
5158
5159         for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
5160                 c = seconds / mult[i];
5161
5162                 if (c > 0 || (i == 0 && buf == tail))
5163                         tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
5164
5165                 seconds %= mult[i];
5166         }
5167
5168         return tail;
5169 }
5170
5171 static void sec2str(time_t seconds, char *buf, int rc)
5172 {
5173         char *tail = buf;
5174
5175         if (rc)
5176                 *tail++ = '[';
5177
5178         tail = __sec2str(seconds, tail);
5179
5180         if (rc && tail - buf < 39) {
5181                 *tail++ = ']';
5182                 *tail++ = 0;
5183         }
5184 }
5185
5186 static void diff2str(time_t seconds, char *buf, time_t now)
5187 {
5188
5189         buf[0] = 0;
5190         if (!seconds)
5191                 return;
5192         if (seconds <= now) {
5193                 strcpy(buf, "none");
5194                 return;
5195         }
5196         __sec2str(seconds - now, buf);
5197 }
5198
5199 static void print_quota_title(char *name, struct if_quotactl *qctl,
5200                               bool human_readable)
5201 {
5202         printf("Disk quotas for %s %s (%cid %u):\n",
5203                qtype_name(qctl->qc_type), name,
5204                *qtype_name(qctl->qc_type), qctl->qc_id);
5205         printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
5206                "Filesystem", human_readable ? "used" : "kbytes",
5207                "quota", "limit", "grace",
5208                "files", "quota", "limit", "grace");
5209 }
5210
5211 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
5212 {
5213         if (!h) {
5214                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
5215         } else {
5216                 if (num >> 40)
5217                         snprintf(buf, buflen, "%5.4gP",
5218                                  (double)num / ((__u64)1 << 40));
5219                 else if (num >> 30)
5220                         snprintf(buf, buflen, "%5.4gT",
5221                                  (double)num / (1 << 30));
5222                 else if (num >> 20)
5223                         snprintf(buf, buflen, "%5.4gG",
5224                                  (double)num / (1 << 20));
5225                 else if (num >> 10)
5226                         snprintf(buf, buflen, "%5.4gM",
5227                                  (double)num / (1 << 10));
5228                 else
5229                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
5230         }
5231 }
5232
5233 #define STRBUF_LEN      32
5234 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
5235                         int rc, bool h)
5236 {
5237         time_t now;
5238
5239         time(&now);
5240
5241         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
5242                 int bover = 0, iover = 0;
5243                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
5244                 char numbuf[3][STRBUF_LEN];
5245                 char timebuf[40];
5246                 char strbuf[STRBUF_LEN];
5247
5248                 if (dqb->dqb_bhardlimit &&
5249                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
5250                         bover = 1;
5251                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
5252                         if (dqb->dqb_btime > now) {
5253                                 bover = 2;
5254                         } else {
5255                                 bover = 3;
5256                         }
5257                 }
5258
5259                 if (dqb->dqb_ihardlimit &&
5260                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
5261                         iover = 1;
5262                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
5263                         if (dqb->dqb_itime > now) {
5264                                 iover = 2;
5265                         } else {
5266                                 iover = 3;
5267                         }
5268                 }
5269
5270
5271                 if (strlen(mnt) > 15)
5272                         printf("%s\n%15s", mnt, "");
5273                 else
5274                         printf("%15s", mnt);
5275
5276                 if (bover)
5277                         diff2str(dqb->dqb_btime, timebuf, now);
5278
5279                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
5280                            strbuf, sizeof(strbuf), h);
5281                 if (rc == -EREMOTEIO)
5282                         sprintf(numbuf[0], "%s*", strbuf);
5283                 else
5284                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
5285                                 "%s" : "[%s]", strbuf);
5286
5287                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
5288                 if (type == QC_GENERAL)
5289                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
5290                                 "%s" : "[%s]", strbuf);
5291                 else
5292                         sprintf(numbuf[1], "%s", "-");
5293
5294                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
5295                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
5296                         "%s" : "[%s]", strbuf);
5297
5298                 printf(" %7s%c %6s %7s %7s",
5299                        numbuf[0], bover ? '*' : ' ', numbuf[1],
5300                        numbuf[2], bover > 1 ? timebuf : "-");
5301
5302                 if (iover)
5303                         diff2str(dqb->dqb_itime, timebuf, now);
5304
5305                 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
5306                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
5307
5308                 if (type == QC_GENERAL)
5309                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
5310                                 "%ju" : "[%ju]",
5311                                 (uintmax_t)dqb->dqb_isoftlimit);
5312                 else
5313                         sprintf(numbuf[1], "%s", "-");
5314
5315                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
5316                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
5317
5318                 if (type != QC_OSTIDX)
5319                         printf(" %7s%c %6s %7s %7s",
5320                                numbuf[0], iover ? '*' : ' ', numbuf[1],
5321                                numbuf[2], iover > 1 ? timebuf : "-");
5322                 else
5323                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
5324                 printf("\n");
5325
5326         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
5327                    qctl->qc_cmd == Q_GETOINFO) {
5328                 char bgtimebuf[40];
5329                 char igtimebuf[40];
5330
5331                 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
5332                 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
5333                 printf("Block grace time: %s; Inode grace time: %s\n",
5334                        bgtimebuf, igtimebuf);
5335         }
5336 }
5337
5338 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
5339                            bool h, __u64 *total)
5340 {
5341         int rc = 0, rc1 = 0, count = 0;
5342         __u32 valid = qctl->qc_valid;
5343
5344         rc = llapi_get_obd_count(mnt, &count, is_mdt);
5345         if (rc) {
5346                 fprintf(stderr, "can not get %s count: %s\n",
5347                         is_mdt ? "mdt": "ost", strerror(-rc));
5348                 return rc;
5349         }
5350
5351         for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
5352                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
5353                 rc = llapi_quotactl(mnt, qctl);
5354                 if (rc) {
5355                         /* It is remote client case. */
5356                         if (rc == -EOPNOTSUPP) {
5357                                 rc = 0;
5358                                 goto out;
5359                         }
5360
5361                         if (!rc1)
5362                                 rc1 = rc;
5363                         fprintf(stderr, "quotactl %s%d failed.\n",
5364                                 is_mdt ? "mdt": "ost", qctl->qc_idx);
5365                         continue;
5366                 }
5367
5368                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
5369                             qctl->qc_valid, 0, h);
5370                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
5371                                    qctl->qc_dqblk.dqb_bhardlimit;
5372         }
5373 out:
5374         qctl->qc_valid = valid;
5375         return rc ? : rc1;
5376 }
5377
5378 static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
5379                            int verbose, int quiet, bool human_readable)
5380 {
5381         int rc1 = 0, rc2 = 0, rc3 = 0;
5382         char *obd_type = (char *)qctl->obd_type;
5383         char *obd_uuid = (char *)qctl->obd_uuid.uuid;
5384         __u64 total_ialloc = 0, total_balloc = 0;
5385         int inacc;
5386
5387         rc1 = llapi_quotactl(mnt, qctl);
5388         if (rc1 < 0) {
5389                 switch (rc1) {
5390                 case -ESRCH:
5391                         fprintf(stderr, "%s quotas are not enabled.\n",
5392                                 qtype_name(qctl->qc_type));
5393                         goto out;
5394                 case -EPERM:
5395                         fprintf(stderr, "Permission denied.\n");
5396                 case -ENODEV:
5397                 case -ENOENT:
5398                         /* We already got error message. */
5399                         goto out;
5400                 default:
5401                         fprintf(stderr, "Unexpected quotactl error: %s\n",
5402                                 strerror(-rc1));
5403                 }
5404         }
5405
5406         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
5407                 print_quota_title(name, qctl, human_readable);
5408
5409         if (rc1 && *obd_type)
5410                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
5411
5412         if (qctl->qc_valid != QC_GENERAL)
5413                 mnt = "";
5414
5415         inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA) &&
5416                 ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
5417                  (QIF_LIMITS|QIF_USAGE));
5418
5419         print_quota(mnt, qctl, QC_GENERAL, rc1, human_readable);
5420
5421         if (qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO &&
5422             verbose) {
5423                 char strbuf[STRBUF_LEN];
5424
5425                 rc2 = print_obd_quota(mnt, qctl, 1, human_readable,
5426                                       &total_ialloc);
5427                 rc3 = print_obd_quota(mnt, qctl, 0, human_readable,
5428                                       &total_balloc);
5429                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
5430                            human_readable);
5431                 printf("Total allocated inode limit: %ju, total "
5432                        "allocated block limit: %s\n", (uintmax_t)total_ialloc,
5433                        strbuf);
5434         }
5435
5436         if (rc1 || rc2 || rc3 || inacc)
5437                 printf("Some errors happened when getting quota info. "
5438                        "Some devices may be not working or deactivated. "
5439                        "The data in \"[]\" is inaccurate.\n");
5440 out:
5441         return rc1;
5442
5443 }
5444
5445 static int lfs_project(int argc, char **argv)
5446 {
5447         int ret = 0, err = 0, c, i;
5448         struct project_handle_control phc = { 0 };
5449         enum lfs_project_ops_t op;
5450
5451         phc.newline = true;
5452         phc.assign_projid = false;
5453         /* default action */
5454         op = LFS_PROJECT_LIST;
5455
5456         while ((c = getopt(argc, argv, "p:cCsdkr0")) != -1) {
5457                 switch (c) {
5458                 case 'c':
5459                         if (op != LFS_PROJECT_LIST) {
5460                                 fprintf(stderr,
5461                                         "%s: cannot specify '-c' '-C' '-s' together\n",
5462                                         progname);
5463                                 return CMD_HELP;
5464                         }
5465
5466                         op = LFS_PROJECT_CHECK;
5467                         break;
5468                 case 'C':
5469                         if (op != LFS_PROJECT_LIST) {
5470                                 fprintf(stderr,
5471                                         "%s: cannot specify '-c' '-C' '-s' together\n",
5472                                         progname);
5473                                 return CMD_HELP;
5474                         }
5475
5476                         op = LFS_PROJECT_CLEAR;
5477                         break;
5478                 case 's':
5479                         if (op != LFS_PROJECT_LIST) {
5480                                 fprintf(stderr,
5481                                         "%s: cannot specify '-c' '-C' '-s' together\n",
5482                                         progname);
5483                                 return CMD_HELP;
5484                         }
5485
5486                         phc.set_inherit = true;
5487                         op = LFS_PROJECT_SET;
5488                         break;
5489                 case 'd':
5490                         phc.dironly = true;
5491                         break;
5492                 case 'k':
5493                         phc.keep_projid = true;
5494                         break;
5495                 case 'r':
5496                         phc.recursive = true;
5497                         break;
5498                 case 'p':
5499                         phc.projid = strtoul(optarg, NULL, 0);
5500                         phc.assign_projid = true;
5501
5502                         break;
5503                 case '0':
5504                         phc.newline = false;
5505                         break;
5506                 default:
5507                         fprintf(stderr, "%s: invalid option '%c'\n",
5508                                 progname, optopt);
5509                         return CMD_HELP;
5510                 }
5511         }
5512
5513         if (phc.assign_projid && op == LFS_PROJECT_LIST) {
5514                 op = LFS_PROJECT_SET;
5515                 phc.set_projid = true;
5516         } else if (phc.assign_projid && op == LFS_PROJECT_SET) {
5517                 phc.set_projid = true;
5518         }
5519
5520         switch (op) {
5521         case LFS_PROJECT_CHECK:
5522                 if (phc.keep_projid) {
5523                         fprintf(stderr,
5524                                 "%s: '-k' is useless together with '-c'\n",
5525                                 progname);
5526                         return CMD_HELP;
5527                 }
5528                 break;
5529         case LFS_PROJECT_CLEAR:
5530                 if (!phc.newline) {
5531                         fprintf(stderr,
5532                                 "%s: '-0' is useless together with '-C'\n",
5533                                 progname);
5534                         return CMD_HELP;
5535                 }
5536                 if (phc.assign_projid) {
5537                         fprintf(stderr,
5538                                 "%s: '-p' is useless together with '-C'\n",
5539                                 progname);
5540                         return CMD_HELP;
5541                 }
5542                 break;
5543         case LFS_PROJECT_SET:
5544                 if (!phc.newline) {
5545                         fprintf(stderr,
5546                                 "%s: '-0' is useless together with '-s'\n",
5547                                 progname);
5548                         return CMD_HELP;
5549                 }
5550                 if (phc.keep_projid) {
5551                         fprintf(stderr,
5552                                 "%s: '-k' is useless together with '-s'\n",
5553                                 progname);
5554                         return CMD_HELP;
5555                 }
5556                 break;
5557         default:
5558                 if (!phc.newline) {
5559                         fprintf(stderr,
5560                                 "%s: '-0' is useless for list operations\n",
5561                                 progname);
5562                         return CMD_HELP;
5563                 }
5564                 break;
5565         }
5566
5567         argv += optind;
5568         argc -= optind;
5569         if (argc == 0) {
5570                 fprintf(stderr, "%s: missing file or directory target(s)\n",
5571                         progname);
5572                 return CMD_HELP;
5573         }
5574
5575         for (i = 0; i < argc; i++) {
5576                 switch (op) {
5577                 case LFS_PROJECT_CHECK:
5578                         err = lfs_project_check(argv[i], &phc);
5579                         break;
5580                 case LFS_PROJECT_LIST:
5581                         err = lfs_project_list(argv[i], &phc);
5582                         break;
5583                 case LFS_PROJECT_CLEAR:
5584                         err = lfs_project_clear(argv[i], &phc);
5585                         break;
5586                 case LFS_PROJECT_SET:
5587                         err = lfs_project_set(argv[i], &phc);
5588                         break;
5589                 default:
5590                         break;
5591                 }
5592                 if (err && !ret)
5593                         ret = err;
5594         }
5595
5596         return ret;
5597 }
5598
5599 static int lfs_quota(int argc, char **argv)
5600 {
5601         int c;
5602         char *mnt, *name = NULL;
5603         struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
5604                                     .qc_type = ALLQUOTA };
5605         char *obd_uuid = (char *)qctl.obd_uuid.uuid;
5606         int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
5607         char *endptr;
5608         __u32 valid = QC_GENERAL, idx = 0;
5609         bool human_readable = false;
5610         int qtype;
5611
5612         while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
5613                 switch (c) {
5614                 case 'u':
5615                         qtype = USRQUOTA;
5616                         goto quota_type;
5617                 case 'g':
5618                         qtype = GRPQUOTA;
5619                         goto quota_type;
5620                 case 'p':
5621                         qtype = PRJQUOTA;
5622 quota_type:
5623                         if (qctl.qc_type != ALLQUOTA) {
5624                                 fprintf(stderr,
5625                                         "%s quota: only one of -u, -g, or -p may be specified\n",
5626                                         progname);
5627                                 return CMD_HELP;
5628                         }
5629                         qctl.qc_type = qtype;
5630                         break;
5631                 case 't':
5632                         qctl.qc_cmd = LUSTRE_Q_GETINFO;
5633                         break;
5634                 case 'o':
5635                         valid = qctl.qc_valid = QC_UUID;
5636                         strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
5637                         break;
5638                 case 'i':
5639                         valid = qctl.qc_valid = QC_MDTIDX;
5640                         idx = qctl.qc_idx = atoi(optarg);
5641                         if (idx == 0 && *optarg != '0') {
5642                                 fprintf(stderr,
5643                                         "%s quota: invalid MDT index '%s'\n",
5644                                         progname, optarg);
5645                                 return CMD_HELP;
5646                         }
5647                         break;
5648                 case 'I':
5649                         valid = qctl.qc_valid = QC_OSTIDX;
5650                         idx = qctl.qc_idx = atoi(optarg);
5651                         if (idx == 0 && *optarg != '0') {
5652                                 fprintf(stderr,
5653                                         "%s quota: invalid OST index '%s'\n",
5654                                         progname, optarg);
5655                                 return CMD_HELP;
5656                         }
5657                         break;
5658                 case 'v':
5659                         verbose = 1;
5660                         break;
5661                 case 'q':
5662                         quiet = 1;
5663                         break;
5664                 case 'h':
5665                         human_readable = true;
5666                         break;
5667                 default:
5668                         fprintf(stderr, "%s quota: unrecognized option '%s'\n",
5669                                 progname, argv[optind - 1]);
5670                         return CMD_HELP;
5671                 }
5672         }
5673
5674         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
5675         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
5676             optind == argc - 1) {
5677
5678                 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
5679                 qctl.qc_valid = valid;
5680                 qctl.qc_idx = idx;
5681
5682                 for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) {
5683                         qctl.qc_type = qtype;
5684                         if (qtype == USRQUOTA) {
5685                                 qctl.qc_id = geteuid();
5686                                 rc = uid2name(&name, qctl.qc_id);
5687                         } else {
5688                                 qctl.qc_id = getegid();
5689                                 rc = gid2name(&name, qctl.qc_id);
5690                         }
5691                         if (rc)
5692                                 name = "<unknown>";
5693                         mnt = argv[optind];
5694                         rc1 = get_print_quota(mnt, name, &qctl, verbose, quiet,
5695                                               human_readable);
5696                         if (rc1 && !rc)
5697                                 rc = rc1;
5698                 }
5699         /* lfs quota -u username /path/to/lustre/mount */
5700         } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
5701                 /* options should be followed by u/g-name and mntpoint */
5702                 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
5703                         fprintf(stderr,
5704                                 "%s quota: name and mount point must be specified\n",
5705                                 progname);
5706                         return CMD_HELP;
5707                 }
5708
5709                 name = argv[optind++];
5710                 switch (qctl.qc_type) {
5711                 case USRQUOTA:
5712                         rc = name2uid(&qctl.qc_id, name);
5713                         break;
5714                 case GRPQUOTA:
5715                         rc = name2gid(&qctl.qc_id, name);
5716                         break;
5717                 case PRJQUOTA:
5718                         rc = name2projid(&qctl.qc_id, name);
5719                         break;
5720                 default:
5721                         rc = -ENOTSUP;
5722                         break;
5723                 }
5724                 if (rc) {
5725                         qctl.qc_id = strtoul(name, &endptr, 10);
5726                         if (*endptr != '\0') {
5727                                 fprintf(stderr, "%s quota: invalid id '%s'\n",
5728                                         progname, name);
5729                                 return CMD_HELP;
5730                         }
5731                 }
5732                 mnt = argv[optind];
5733                 rc = get_print_quota(mnt, name, &qctl, verbose, quiet,
5734                                      human_readable);
5735         } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
5736                 fprintf(stderr, "%s quota: missing quota info argument(s)\n",
5737                         progname);
5738                 return CMD_HELP;
5739         }
5740
5741         return rc;
5742 }
5743 #endif /* HAVE_SYS_QUOTA_H! */
5744
5745 static int flushctx_ioctl(char *mp)
5746 {
5747         int fd, rc;
5748
5749         fd = open(mp, O_RDONLY);
5750         if (fd == -1) {
5751                 fprintf(stderr, "flushctx: error open %s: %s\n",
5752                         mp, strerror(errno));
5753                 return -1;
5754         }
5755
5756         rc = ioctl(fd, LL_IOC_FLUSHCTX);
5757         if (rc == -1)
5758                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
5759                         mp, strerror(errno));
5760
5761         close(fd);
5762         return rc;
5763 }
5764
5765 static int lfs_flushctx(int argc, char **argv)
5766 {
5767         int     kdestroy = 0, c;
5768         char    mntdir[PATH_MAX] = {'\0'};
5769         int     index = 0;
5770         int     rc = 0;
5771
5772         while ((c = getopt(argc, argv, "k")) != -1) {
5773                 switch (c) {
5774                 case 'k':
5775                         kdestroy = 1;
5776                         break;
5777                 default:
5778                         fprintf(stderr, "error: %s: option '-%c' "
5779                                         "unrecognized\n", argv[0], c);
5780                         return CMD_HELP;
5781                 }
5782         }
5783
5784         if (kdestroy) {
5785             if ((rc = system("kdestroy > /dev/null")) != 0) {
5786                 rc = WEXITSTATUS(rc);
5787                 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
5788             }
5789         }
5790
5791         if (optind >= argc) {
5792                 /* flush for all mounted lustre fs. */
5793                 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
5794                         /* Check if we have a mount point */
5795                         if (mntdir[0] == '\0')
5796                                 continue;
5797
5798                         if (flushctx_ioctl(mntdir))
5799                                 rc = -1;
5800
5801                         mntdir[0] = '\0'; /* avoid matching in next loop */
5802                 }
5803         } else {
5804                 /* flush fs as specified */
5805                 while (optind < argc) {
5806                         if (flushctx_ioctl(argv[optind++]))
5807                                 rc = -1;
5808                 }
5809         }
5810         return rc;
5811 }
5812
5813 static int lfs_cp(int argc, char **argv)
5814 {
5815         fprintf(stderr, "remote client copy file(s).\n"
5816                 "obsolete, does not support it anymore.\n");
5817         return 0;
5818 }
5819
5820 static int lfs_ls(int argc, char **argv)
5821 {
5822         fprintf(stderr, "remote client lists directory contents.\n"
5823                 "obsolete, does not support it anymore.\n");
5824         return 0;
5825 }
5826
5827 static int lfs_changelog(int argc, char **argv)
5828 {
5829         void *changelog_priv;
5830         struct changelog_rec *rec;
5831         long long startrec = 0, endrec = 0;
5832         char *mdd;
5833         struct option long_opts[] = {
5834                 { .val = 'f', .name = "follow", .has_arg = no_argument },
5835                 { .name = NULL } };
5836         char short_opts[] = "f";
5837         int rc, follow = 0;
5838
5839         while ((rc = getopt_long(argc, argv, short_opts,
5840                 long_opts, NULL)) != -1) {
5841                 switch (rc) {
5842                 case 'f':
5843                         follow++;
5844                         break;
5845                 case '?':
5846                         return CMD_HELP;
5847                 default:
5848                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5849                                 argv[0], argv[optind - 1]);
5850                         return CMD_HELP;
5851                 }
5852         }
5853         if (optind >= argc)
5854                 return CMD_HELP;
5855
5856         mdd = argv[optind++];
5857         if (argc > optind)
5858                 startrec = strtoll(argv[optind++], NULL, 10);
5859         if (argc > optind)
5860                 endrec = strtoll(argv[optind++], NULL, 10);
5861
5862         rc = llapi_changelog_start(&changelog_priv,
5863                                    CHANGELOG_FLAG_BLOCK |
5864                                    CHANGELOG_FLAG_JOBID |
5865                                    CHANGELOG_FLAG_EXTRA_FLAGS |
5866                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
5867                                    mdd, startrec);
5868         if (rc < 0) {
5869                 fprintf(stderr, "Can't start changelog: %s\n",
5870                         strerror(errno = -rc));
5871                 return rc;
5872         }
5873
5874         rc = llapi_changelog_set_xflags(changelog_priv,
5875                                         CHANGELOG_EXTRA_FLAG_UIDGID |
5876                                         CHANGELOG_EXTRA_FLAG_NID |
5877                                         CHANGELOG_EXTRA_FLAG_OMODE |
5878                                         CHANGELOG_EXTRA_FLAG_XATTR);
5879         if (rc < 0) {
5880                 fprintf(stderr, "Can't set xflags for changelog: %s\n",
5881                         strerror(errno = -rc));
5882                 return rc;
5883         }
5884
5885         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
5886                 time_t secs;
5887                 struct tm ts;
5888
5889                 if (endrec && rec->cr_index > endrec) {
5890                         llapi_changelog_free(&rec);
5891                         break;
5892                 }
5893                 if (rec->cr_index < startrec) {
5894                         llapi_changelog_free(&rec);
5895                         continue;
5896                 }
5897
5898                 secs = rec->cr_time >> 30;
5899                 gmtime_r(&secs, &ts);
5900                 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
5901                        "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
5902                        changelog_type2str(rec->cr_type),
5903                        ts.tm_hour, ts.tm_min, ts.tm_sec,
5904                        (int)(rec->cr_time & ((1 << 30) - 1)),
5905                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
5906                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
5907
5908                 if (rec->cr_flags & CLF_JOBID) {
5909                         struct changelog_ext_jobid *jid =
5910                                 changelog_rec_jobid(rec);
5911
5912                         if (jid->cr_jobid[0] != '\0')
5913                                 printf(" j=%s", jid->cr_jobid);
5914                 }
5915
5916                 if (rec->cr_flags & CLF_EXTRA_FLAGS) {
5917                         struct changelog_ext_extra_flags *ef =
5918                                 changelog_rec_extra_flags(rec);
5919
5920                         printf(" ef=0x%llx", ef->cr_extra_flags);
5921
5922                         if (ef->cr_extra_flags & CLFE_UIDGID) {
5923                                 struct changelog_ext_uidgid *uidgid =
5924                                         changelog_rec_uidgid(rec);
5925
5926                                 printf(" u=%llu:%llu",
5927                                        uidgid->cr_uid, uidgid->cr_gid);
5928                         }
5929                         if (ef->cr_extra_flags & CLFE_NID) {
5930                                 struct changelog_ext_nid *nid =
5931                                         changelog_rec_nid(rec);
5932
5933                                 printf(" nid=%s",
5934                                        libcfs_nid2str(nid->cr_nid));
5935                         }
5936
5937                         if (ef->cr_extra_flags & CLFE_OPEN) {
5938                                 struct changelog_ext_openmode *omd =
5939                                         changelog_rec_openmode(rec);
5940                                 char mode[] = "---";
5941
5942                                 /* exec mode must be exclusive */
5943                                 if (omd->cr_openflags & MDS_FMODE_EXEC) {
5944                                         mode[2] = 'x';
5945                                 } else {
5946                                         if (omd->cr_openflags & FMODE_READ)
5947                                                 mode[0] = 'r';
5948                                         if (omd->cr_openflags &
5949                                             (FMODE_WRITE |
5950                                              MDS_OPEN_TRUNC |
5951                                              MDS_OPEN_APPEND))
5952                                                 mode[1] = 'w';
5953                                 }
5954
5955                                 if (strcmp(mode, "---") != 0)
5956                                         printf(" m=%s", mode);
5957
5958                         }
5959
5960                         if (ef->cr_extra_flags & CLFE_XATTR) {
5961                                 struct changelog_ext_xattr *xattr =
5962                                         changelog_rec_xattr(rec);
5963
5964                                 if (xattr->cr_xattr[0] != '\0')
5965                                         printf(" x=%s", xattr->cr_xattr);
5966                         }
5967                 }
5968
5969                 if (rec->cr_namelen)
5970                         printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
5971                                rec->cr_namelen, changelog_rec_name(rec));
5972
5973                 if (rec->cr_flags & CLF_RENAME) {
5974                         struct changelog_ext_rename *rnm =
5975                                 changelog_rec_rename(rec);
5976
5977                         if (!fid_is_zero(&rnm->cr_sfid))
5978                                 printf(" s="DFID" sp="DFID" %.*s",
5979                                        PFID(&rnm->cr_sfid),
5980                                        PFID(&rnm->cr_spfid),
5981                                        (int)changelog_rec_snamelen(rec),
5982                                        changelog_rec_sname(rec));
5983                 }
5984                 printf("\n");
5985
5986                 llapi_changelog_free(&rec);
5987         }
5988
5989         llapi_changelog_fini(&changelog_priv);
5990
5991         if (rc < 0)
5992                 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
5993
5994         return (rc == 1 ? 0 : rc);
5995 }
5996
5997 static int lfs_changelog_clear(int argc, char **argv)
5998 {
5999         long long endrec;
6000         int rc;
6001
6002         if (argc != 4)
6003                 return CMD_HELP;
6004
6005         endrec = strtoll(argv[3], NULL, 10);
6006
6007         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
6008
6009         if (rc == -EINVAL)
6010                 fprintf(stderr, "%s: record out of range: %llu\n",
6011                         argv[0], endrec);
6012         else if (rc == -ENOENT)
6013                 fprintf(stderr, "%s: no changelog user: %s\n",
6014                         argv[0], argv[2]);
6015         else if (rc)
6016                 fprintf(stderr, "%s error: %s\n", argv[0],
6017                         strerror(-rc));
6018
6019         if (rc)
6020                 errno = -rc;
6021
6022         return rc;
6023 }
6024
6025 static int lfs_fid2path(int argc, char **argv)
6026 {
6027         struct option long_opts[] = {
6028                 { .val = 'c',   .name = "cur",  .has_arg = no_argument },
6029                 { .val = 'l',   .name = "link", .has_arg = required_argument },
6030                 { .val = 'r',   .name = "rec",  .has_arg = required_argument },
6031                 { .name = NULL } };
6032         char  short_opts[] = "cl:r:";
6033         char *device, *fid, *path;
6034         long long recno = -1;
6035         int linkno = -1;
6036         int lnktmp;
6037         int printcur = 0;
6038         int rc = 0;
6039
6040         while ((rc = getopt_long(argc, argv, short_opts,
6041                 long_opts, NULL)) != -1) {
6042                 switch (rc) {
6043                 case 'c':
6044                         printcur++;
6045                         break;
6046                 case 'l':
6047                         linkno = strtol(optarg, NULL, 10);
6048                         break;
6049                 case 'r':
6050                         recno = strtoll(optarg, NULL, 10);
6051                         break;
6052                 case '?':
6053                         return CMD_HELP;
6054                 default:
6055                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
6056                                 argv[0], argv[optind - 1]);
6057                         return CMD_HELP;
6058                 }
6059         }
6060
6061         if (argc < 3)
6062                 return CMD_HELP;
6063
6064         device = argv[optind++];
6065         path = calloc(1, PATH_MAX);
6066         if (path == NULL) {
6067                 fprintf(stderr, "error: Not enough memory\n");
6068                 return -errno;
6069         }
6070
6071         rc = 0;
6072         while (optind < argc) {
6073                 fid = argv[optind++];
6074
6075                 lnktmp = (linkno >= 0) ? linkno : 0;
6076                 while (1) {
6077                         int oldtmp = lnktmp;
6078                         long long rectmp = recno;
6079                         int rc2;
6080                         rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
6081                                              &rectmp, &lnktmp);
6082                         if (rc2 < 0) {
6083                                 fprintf(stderr, "%s: error on FID %s: %s\n",
6084                                         argv[0], fid, strerror(errno = -rc2));
6085                                 if (rc == 0)
6086                                         rc = rc2;
6087                                 break;
6088                         }
6089
6090                         if (printcur)
6091                                 fprintf(stdout, "%lld ", rectmp);
6092                         if (device[0] == '/') {
6093                                 fprintf(stdout, "%s", device);
6094                                 if (device[strlen(device) - 1] != '/')
6095                                         fprintf(stdout, "/");
6096                         } else if (path[0] == '\0') {
6097                                 fprintf(stdout, "/");
6098                         }
6099                         fprintf(stdout, "%s\n", path);
6100
6101                         if (linkno >= 0)
6102                                 /* specified linkno */
6103                                 break;
6104                         if (oldtmp == lnktmp)
6105                                 /* no more links */
6106                                 break;
6107                 }
6108         }
6109
6110         free(path);
6111         return rc;
6112 }
6113
6114 static int lfs_path2fid(int argc, char **argv)
6115 {
6116         struct option long_opts[] = {
6117                 { .val = 'p', .name = "parents", .has_arg = no_argument },
6118                 { .name = NULL } };
6119         char            **path;
6120         const char        short_opts[] = "p";
6121         const char       *sep = "";
6122         struct lu_fid     fid;
6123         int               rc = 0;
6124         bool              show_parents = false;
6125
6126         while ((rc = getopt_long(argc, argv, short_opts,
6127                                  long_opts, NULL)) != -1) {
6128                 switch (rc) {
6129                 case 'p':
6130                         show_parents = true;
6131                         break;
6132                 default:
6133                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
6134                                 argv[0], argv[optind - 1]);
6135                         return CMD_HELP;
6136                 }
6137         }
6138
6139         if (optind > argc - 1)
6140                 return CMD_HELP;
6141         else if (optind < argc - 1)
6142                 sep = ": ";
6143
6144         rc = 0;
6145         for (path = argv + optind; *path != NULL; path++) {
6146                 int err = 0;
6147                 if (!show_parents) {
6148                         err = llapi_path2fid(*path, &fid);
6149                         if (!err)
6150                                 printf("%s%s"DFID"\n",
6151                                        *sep != '\0' ? *path : "", sep,
6152                                        PFID(&fid));
6153                 } else {
6154                         char            name[NAME_MAX + 1];
6155                         unsigned int    linkno = 0;
6156
6157                         while ((err = llapi_path2parent(*path, linkno, &fid,
6158                                                 name, sizeof(name))) == 0) {
6159                                 if (*sep != '\0' && linkno == 0)
6160                                         printf("%s%s", *path, sep);
6161
6162                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
6163                                        PFID(&fid), name);
6164                                 linkno++;
6165                         }
6166
6167                         /* err == -ENODATA is end-of-loop */
6168                         if (linkno > 0 && err == -ENODATA) {
6169                                 printf("\n");
6170                                 err = 0;
6171                         }
6172                 }
6173
6174                 if (err) {
6175                         fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
6176                                 argv[0], show_parents ? "parent " : "", *path,
6177                                 strerror(-err));
6178                         if (rc == 0) {
6179                                 rc = err;
6180                                 errno = -err;
6181                         }
6182                 }
6183         }
6184
6185         return rc;
6186 }
6187
6188 static int lfs_data_version(int argc, char **argv)
6189 {
6190         char *path;
6191         __u64 data_version;
6192         int fd;
6193         int rc;
6194         int c;
6195         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
6196
6197         if (argc < 2)
6198                 return CMD_HELP;
6199
6200         while ((c = getopt(argc, argv, "nrw")) != -1) {
6201                 switch (c) {
6202                 case 'n':
6203                         data_version_flags = 0;
6204                         break;
6205                 case 'r':
6206                         data_version_flags |= LL_DV_RD_FLUSH;
6207                         break;
6208                 case 'w':
6209                         data_version_flags |= LL_DV_WR_FLUSH;
6210                         break;
6211                 default:
6212                         return CMD_HELP;
6213                 }
6214         }
6215         if (optind == argc)
6216                 return CMD_HELP;
6217
6218         path = argv[optind];
6219         fd = open(path, O_RDONLY);
6220         if (fd < 0)
6221                 err(errno, "cannot open file %s", path);
6222
6223         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
6224         if (rc < 0)
6225                 err(errno, "cannot get version for %s", path);
6226         else
6227                 printf("%ju" "\n", (uintmax_t)data_version);
6228
6229         close(fd);
6230         return rc;
6231 }
6232
6233 static int lfs_hsm_state(int argc, char **argv)
6234 {
6235         int rc;
6236         int i = 1;
6237         char *path;
6238         struct hsm_user_state hus;
6239
6240         if (argc < 2)
6241                 return CMD_HELP;
6242
6243         do {
6244                 path = argv[i];
6245
6246                 rc = llapi_hsm_state_get(path, &hus);
6247                 if (rc) {
6248                         fprintf(stderr, "can't get hsm state for %s: %s\n",
6249                                 path, strerror(errno = -rc));
6250                         return rc;
6251                 }
6252
6253                 /* Display path name and status flags */
6254                 printf("%s: (0x%08x)", path, hus.hus_states);
6255
6256                 if (hus.hus_states & HS_RELEASED)
6257                         printf(" released");
6258                 if (hus.hus_states & HS_EXISTS)
6259                         printf(" exists");
6260                 if (hus.hus_states & HS_DIRTY)
6261                         printf(" dirty");
6262                 if (hus.hus_states & HS_ARCHIVED)
6263                         printf(" archived");
6264                 /* Display user-settable flags */
6265                 if (hus.hus_states & HS_NORELEASE)
6266                         printf(" never_release");
6267                 if (hus.hus_states & HS_NOARCHIVE)
6268                         printf(" never_archive");
6269                 if (hus.hus_states & HS_LOST)
6270                         printf(" lost_from_hsm");
6271
6272                 if (hus.hus_archive_id != 0)
6273                         printf(", archive_id:%d", hus.hus_archive_id);
6274                 printf("\n");
6275
6276         } while (++i < argc);
6277
6278         return 0;
6279 }
6280
6281 #define LFS_HSM_SET   0
6282 #define LFS_HSM_CLEAR 1
6283
6284 /**
6285  * Generic function to set or clear HSM flags.
6286  * Used by hsm_set and hsm_clear.
6287  *
6288  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
6289  */
6290 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
6291 {
6292         struct option long_opts[] = {
6293         { .val = 'A',   .name = "archived",     .has_arg = no_argument },
6294         { .val = 'a',   .name = "noarchive",    .has_arg = no_argument },
6295         { .val = 'd',   .name = "dirty",        .has_arg = no_argument },
6296         { .val = 'e',   .name = "exists",       .has_arg = no_argument },
6297         { .val = 'l',   .name = "lost",         .has_arg = no_argument },
6298         { .val = 'r',   .name = "norelease",    .has_arg = no_argument },
6299         { .val = 'i',   .name = "archive-id",   .has_arg = required_argument },
6300         { .name = NULL } };
6301         char short_opts[] = "lraAdei:";
6302         __u64 mask = 0;
6303         int c, rc;
6304         char *path;
6305         __u32 archive_id = 0;
6306         char *end = NULL;
6307
6308         if (argc < 3)
6309                 return CMD_HELP;
6310
6311         while ((c = getopt_long(argc, argv, short_opts,
6312                                 long_opts, NULL)) != -1) {
6313                 switch (c) {
6314                 case 'l':
6315                         mask |= HS_LOST;
6316                         break;
6317                 case 'a':
6318                         mask |= HS_NOARCHIVE;
6319                         break;
6320                 case 'A':
6321                         mask |= HS_ARCHIVED;
6322                         break;
6323                 case 'r':
6324                         mask |= HS_NORELEASE;
6325                         break;
6326                 case 'd':
6327                         mask |= HS_DIRTY;
6328                         break;
6329                 case 'e':
6330                         mask |= HS_EXISTS;
6331                         break;
6332                 case 'i':
6333                         archive_id = strtol(optarg, &end, 10);
6334                         if (*end != '\0') {
6335                                 fprintf(stderr, "invalid archive_id: '%s'\n",
6336                                         end);
6337                                 return CMD_HELP;
6338                         }
6339                         break;
6340                 case '?':
6341                         return CMD_HELP;
6342                 default:
6343                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
6344                                 argv[0], argv[optind - 1]);
6345                         return CMD_HELP;
6346                 }
6347         }
6348
6349         /* User should have specified a flag */
6350         if (mask == 0)
6351                 return CMD_HELP;
6352
6353         while (optind < argc) {
6354
6355                 path = argv[optind];
6356
6357                 /* If mode == 0, this means we apply the mask. */
6358                 if (mode == LFS_HSM_SET)
6359                         rc = llapi_hsm_state_set(path, mask, 0, archive_id);
6360                 else
6361                         rc = llapi_hsm_state_set(path, 0, mask, 0);
6362
6363                 if (rc != 0) {
6364                         fprintf(stderr, "Can't change hsm flags for %s: %s\n",
6365                                 path, strerror(errno = -rc));
6366                         return rc;
6367                 }
6368                 optind++;
6369         }
6370
6371         return 0;
6372 }
6373
6374 static int lfs_hsm_action(int argc, char **argv)
6375 {
6376         int                              rc;
6377         int                              i = 1;
6378         char                            *path;
6379         struct hsm_current_action        hca;
6380         struct hsm_extent                he;
6381         enum hsm_user_action             hua;
6382         enum hsm_progress_states         hps;
6383
6384         if (argc < 2)
6385                 return CMD_HELP;
6386
6387         do {
6388                 path = argv[i];
6389
6390                 rc = llapi_hsm_current_action(path, &hca);
6391                 if (rc) {
6392                         fprintf(stderr, "can't get hsm action for %s: %s\n",
6393                                 path, strerror(errno = -rc));
6394                         return rc;
6395                 }
6396                 he = hca.hca_location;
6397                 hua = hca.hca_action;
6398                 hps = hca.hca_state;
6399
6400                 printf("%s: %s", path, hsm_user_action2name(hua));
6401
6402                 /* Skip file without action */
6403                 if (hca.hca_action == HUA_NONE) {
6404                         printf("\n");
6405                         continue;
6406                 }
6407
6408                 printf(" %s ", hsm_progress_state2name(hps));
6409
6410                 if ((hps == HPS_RUNNING) &&
6411                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
6412                         printf("(%llu bytes moved)\n",
6413                                (unsigned long long)he.length);
6414                 else if ((he.offset + he.length) == LUSTRE_EOF)
6415                         printf("(from %llu to EOF)\n",
6416                                (unsigned long long)he.offset);
6417                 else
6418                         printf("(from %llu to %llu)\n",
6419                                (unsigned long long)he.offset,
6420                                (unsigned long long)(he.offset + he.length));
6421
6422         } while (++i < argc);
6423
6424         return 0;
6425 }
6426
6427 static int lfs_hsm_set(int argc, char **argv)
6428 {
6429         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
6430 }
6431
6432 static int lfs_hsm_clear(int argc, char **argv)
6433 {
6434         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
6435 }
6436
6437 /**
6438  * Check file state and return its fid, to be used by lfs_hsm_request().
6439  *
6440  * \param[in]     file      Path to file to check
6441  * \param[in,out] fid       Pointer to allocated lu_fid struct.
6442  * \param[in,out] last_dev  Pointer to last device id used.
6443  *
6444  * \return 0 on success.
6445  */
6446 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
6447                                 dev_t *last_dev)
6448 {
6449         struct stat     st;
6450         int             rc;
6451
6452         rc = lstat(file, &st);
6453         if (rc) {
6454                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
6455                 return -errno;
6456         }
6457         /* Checking for regular file as archiving as posix copytool
6458          * rejects archiving files other than regular files
6459          */
6460         if (!S_ISREG(st.st_mode)) {
6461                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
6462                 return CMD_HELP;
6463         }
6464         /* A request should be ... */
6465         if (*last_dev != st.st_dev && *last_dev != 0) {
6466                 fprintf(stderr, "All files should be "
6467                         "on the same filesystem: %s\n", file);
6468                 return -EINVAL;
6469         }
6470         *last_dev = st.st_dev;
6471
6472         rc = llapi_path2fid(file, fid);
6473         if (rc) {
6474                 fprintf(stderr, "Cannot read FID of %s: %s\n",
6475                         file, strerror(-rc));
6476                 return rc;
6477         }
6478         return 0;
6479 }
6480
6481 /* Fill an HSM HUR item with a given file name.
6482  *
6483  * If mntpath is set, then the filename is actually a FID, and no
6484  * lookup on the filesystem will be performed.
6485  *
6486  * \param[in]  hur         the user request to fill
6487  * \param[in]  idx         index of the item inside the HUR to fill
6488  * \param[in]  mntpath     mountpoint of Lustre
6489  * \param[in]  fname       filename (if mtnpath is NULL)
6490  *                         or FID (if mntpath is set)
6491  * \param[in]  last_dev    pointer to last device id used
6492  *
6493  * \retval 0 on success
6494  * \retval CMD_HELP or a negative errno on error
6495  */
6496 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
6497                          const char *mntpath, const char *fname,
6498                          dev_t *last_dev)
6499 {
6500         struct hsm_user_item *hui = &hur->hur_user_item[idx];
6501         int rc;
6502
6503         hui->hui_extent.length = -1;
6504
6505         if (mntpath != NULL) {
6506                 if (*fname == '[')
6507                         fname++;
6508                 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
6509                 if (rc == 3) {
6510                         rc = 0;
6511                 } else {
6512                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
6513                                 fname);
6514                         rc = -EINVAL;
6515                 }
6516         } else {
6517                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
6518         }
6519
6520         if (rc == 0)
6521                 hur->hur_request.hr_itemcount++;
6522
6523         return rc;
6524 }
6525
6526 static int lfs_hsm_request(int argc, char **argv, int action)
6527 {
6528         struct option long_opts[] = {
6529         { .val = 'a',   .name = "archive",      .has_arg = required_argument },
6530         { .val = 'D',   .name = "data",         .has_arg = required_argument },
6531         { .val = 'l',   .name = "filelist",     .has_arg = required_argument },
6532         { .val = 'm',   .name = "mntpath",      .has_arg = required_argument },
6533         { .name = NULL } };
6534         dev_t                    last_dev = 0;
6535         char                     short_opts[] = "l:D:a:m:";
6536         struct hsm_user_request *hur, *oldhur;
6537         int                      c, i;
6538         size_t                   len;
6539         int                      nbfile;
6540         char                    *line = NULL;
6541         char                    *filelist = NULL;
6542         char                     fullpath[PATH_MAX];
6543         char                    *opaque = NULL;
6544         int                      opaque_len = 0;
6545         int                      archive_id = 0;
6546         FILE                    *fp;
6547         int                      nbfile_alloc = 0;
6548         char                    *some_file = NULL;
6549         char                    *mntpath = NULL;
6550         int                      rc;
6551
6552         if (argc < 2)
6553                 return CMD_HELP;
6554
6555         while ((c = getopt_long(argc, argv, short_opts,
6556                                 long_opts, NULL)) != -1) {
6557                 switch (c) {
6558                 case 'l':
6559                         filelist = optarg;
6560                         break;
6561                 case 'D':
6562                         opaque = optarg;
6563                         break;
6564                 case 'a':
6565                         if (action != HUA_ARCHIVE &&
6566                             action != HUA_REMOVE) {
6567                                 fprintf(stderr,
6568                                         "error: -a is supported only "
6569                                         "when archiving or removing\n");
6570                                 return CMD_HELP;
6571                         }
6572                         archive_id = atoi(optarg);
6573                         break;
6574                 case 'm':
6575                         if (some_file == NULL) {
6576                                 mntpath = optarg;
6577                                 some_file = strdup(optarg);
6578                         }
6579                         break;
6580                 case '?':
6581                         return CMD_HELP;
6582                 default:
6583                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
6584                                 argv[0], argv[optind - 1]);
6585                         return CMD_HELP;
6586                 }
6587         }
6588
6589         /* All remaining args are files, so we have at least nbfile */
6590         nbfile = argc - optind;
6591
6592         if ((nbfile == 0) && (filelist == NULL))
6593                 return CMD_HELP;
6594
6595         if (opaque != NULL)
6596                 opaque_len = strlen(opaque);
6597
6598         /* Alloc the request structure with enough place to store all files
6599          * from command line. */
6600         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
6601         if (hur == NULL) {
6602                 fprintf(stderr, "Cannot create the request: %s\n",
6603                         strerror(errno));
6604                 return errno;
6605         }
6606         nbfile_alloc = nbfile;
6607
6608         hur->hur_request.hr_action = action;
6609         hur->hur_request.hr_archive_id = archive_id;
6610         hur->hur_request.hr_flags = 0;
6611
6612         /* All remaining args are files, add them */
6613         if (nbfile != 0 && some_file == NULL)
6614                 some_file = strdup(argv[optind]);
6615
6616         for (i = 0; i < nbfile; i++) {
6617                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
6618                                    &last_dev);
6619                 if (rc)
6620                         goto out_free;
6621         }
6622
6623         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
6624
6625         /* If a filelist was specified, read the filelist from it. */
6626         if (filelist != NULL) {
6627                 fp = fopen(filelist, "r");
6628                 if (fp == NULL) {
6629                         fprintf(stderr, "Cannot read the file list %s: %s\n",
6630                                 filelist, strerror(errno));
6631                         rc = -errno;
6632                         goto out_free;
6633                 }
6634
6635                 while ((rc = getline(&line, &len, fp)) != -1) {
6636                         /* If allocated buffer was too small, get something
6637                          * larger */
6638                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
6639                                 ssize_t size;
6640
6641                                 nbfile_alloc = nbfile_alloc * 2 + 1;
6642                                 oldhur = hur;
6643                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
6644                                                                    opaque_len);
6645                                 if (hur == NULL) {
6646                                         fprintf(stderr, "hsm: cannot allocate "
6647                                                 "the request: %s\n",
6648                                                 strerror(errno));
6649                                         hur = oldhur;
6650                                         rc = -errno;
6651                                         fclose(fp);
6652                                         goto out_free;
6653                                 }
6654                                 size = hur_len(oldhur);
6655                                 if (size < 0) {
6656                                         fprintf(stderr, "hsm: cannot allocate "
6657                                                 "%u files + %u bytes data\n",
6658                                             oldhur->hur_request.hr_itemcount,
6659                                             oldhur->hur_request.hr_data_len);
6660                                         free(hur);
6661                                         hur = oldhur;
6662                                         rc = -E2BIG;
6663                                         fclose(fp);
6664                                         goto out_free;
6665                                 }
6666                                 memcpy(hur, oldhur, size);
6667                                 free(oldhur);
6668                         }
6669
6670                         /* Chop CR */
6671                         if (line[strlen(line) - 1] == '\n')
6672                                 line[strlen(line) - 1] = '\0';
6673
6674                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
6675                                            mntpath, line, &last_dev);
6676                         if (rc) {
6677                                 fclose(fp);
6678                                 goto out_free;
6679                         }
6680
6681                         if (some_file == NULL) {
6682                                 some_file = line;
6683                                 line = NULL;
6684                         }
6685                 }
6686
6687                 rc = fclose(fp);
6688                 free(line);
6689         }
6690
6691         /* If a --data was used, add it to the request */
6692         hur->hur_request.hr_data_len = opaque_len;
6693         if (opaque != NULL)
6694                 memcpy(hur_data(hur), opaque, opaque_len);
6695
6696         /* Send the HSM request */
6697         if (realpath(some_file, fullpath) == NULL) {
6698                 fprintf(stderr, "Could not find path '%s': %s\n",
6699                         some_file, strerror(errno));
6700         }
6701         rc = llapi_hsm_request(fullpath, hur);
6702         if (rc) {
6703                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
6704                         some_file, strerror(-rc));
6705                 goto out_free;
6706         }
6707
6708 out_free:
6709         free(some_file);
6710         free(hur);
6711         return rc;
6712 }
6713
6714 static int lfs_hsm_archive(int argc, char **argv)
6715 {
6716         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
6717 }
6718
6719 static int lfs_hsm_restore(int argc, char **argv)
6720 {
6721         return lfs_hsm_request(argc, argv, HUA_RESTORE);
6722 }
6723
6724 static int lfs_hsm_release(int argc, char **argv)
6725 {
6726         return lfs_hsm_request(argc, argv, HUA_RELEASE);
6727 }
6728
6729 static int lfs_hsm_remove(int argc, char **argv)
6730 {
6731         return lfs_hsm_request(argc, argv, HUA_REMOVE);
6732 }
6733
6734 static int lfs_hsm_cancel(int argc, char **argv)
6735 {
6736         return lfs_hsm_request(argc, argv, HUA_CANCEL);
6737 }
6738
6739 static int lfs_swap_layouts(int argc, char **argv)
6740 {
6741         if (argc != 3)
6742                 return CMD_HELP;
6743
6744         return llapi_swap_layouts(argv[1], argv[2], 0, 0,
6745                                   SWAP_LAYOUTS_KEEP_MTIME |
6746                                   SWAP_LAYOUTS_KEEP_ATIME);
6747 }
6748
6749 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
6750
6751 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
6752
6753 int lfs_get_mode(const char *string)
6754 {
6755         enum lock_mode_user mode;
6756
6757         for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
6758                 if (lock_mode_names[mode] == NULL)
6759                         continue;
6760                 if (strcmp(string, lock_mode_names[mode]) == 0)
6761                         return mode;
6762         }
6763
6764         return -EINVAL;
6765 }
6766
6767 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
6768 {
6769         enum lu_ladvise_type advice;
6770
6771         for (advice = 0;
6772              advice < ARRAY_SIZE(ladvise_names); advice++) {
6773                 if (ladvise_names[advice] == NULL)
6774                         continue;
6775                 if (strcmp(string, ladvise_names[advice]) == 0)
6776                         return advice;
6777         }
6778
6779         return LU_LADVISE_INVALID;
6780 }
6781
6782 static int lfs_ladvise(int argc, char **argv)
6783 {
6784         struct option long_opts[] = {
6785         { .val = 'a',   .name = "advice",       .has_arg = required_argument },
6786         { .val = 'b',   .name = "background",   .has_arg = no_argument },
6787         { .val = 'e',   .name = "end",          .has_arg = required_argument },
6788         { .val = 'l',   .name = "length",       .has_arg = required_argument },
6789         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
6790         { .val = 's',   .name = "start",        .has_arg = required_argument },
6791         { .val = 'u',   .name = "unset",        .has_arg = no_argument },
6792         { .name = NULL } };
6793         char                     short_opts[] = "a:be:l:m:s:u";
6794         int                      c;
6795         int                      rc = 0;
6796         const char              *path;
6797         int                      fd;
6798         struct llapi_lu_ladvise  advice;
6799         enum lu_ladvise_type     advice_type = LU_LADVISE_INVALID;
6800         unsigned long long       start = 0;
6801         unsigned long long       end = LUSTRE_EOF;
6802         unsigned long long       length = 0;
6803         unsigned long long       size_units;
6804         unsigned long long       flags = 0;
6805         int                      mode = 0;
6806
6807         optind = 0;
6808         while ((c = getopt_long(argc, argv, short_opts,
6809                                 long_opts, NULL)) != -1) {
6810                 switch (c) {
6811                 case 'a':
6812                         advice_type = lfs_get_ladvice(optarg);
6813                         if (advice_type == LU_LADVISE_INVALID) {
6814                                 fprintf(stderr, "%s: invalid advice type "
6815                                         "'%s'\n", argv[0], optarg);
6816                                 fprintf(stderr, "Valid types:");
6817
6818                                 for (advice_type = 0;
6819                                      advice_type < ARRAY_SIZE(ladvise_names);
6820                                      advice_type++) {
6821                                         if (ladvise_names[advice_type] == NULL)
6822                                                 continue;
6823                                         fprintf(stderr, " %s",
6824                                                 ladvise_names[advice_type]);
6825                                 }
6826                                 fprintf(stderr, "\n");
6827
6828                                 return CMD_HELP;
6829                         }
6830                         break;
6831                 case 'b':
6832                         flags |= LF_ASYNC;
6833                         break;
6834                 case 'u':
6835                         flags |= LF_UNSET;
6836                         break;
6837                 case 'e':
6838                         size_units = 1;
6839                         rc = llapi_parse_size(optarg, &end,
6840                                               &size_units, 0);
6841                         if (rc) {
6842                                 fprintf(stderr, "%s: bad end offset '%s'\n",
6843                                         argv[0], optarg);
6844                                 return CMD_HELP;
6845                         }
6846                         break;
6847                 case 's':
6848                         size_units = 1;
6849                         rc = llapi_parse_size(optarg, &start,
6850                                               &size_units, 0);
6851                         if (rc) {
6852                                 fprintf(stderr, "%s: bad start offset "
6853                                         "'%s'\n", argv[0], optarg);
6854                                 return CMD_HELP;
6855                         }
6856                         break;
6857                 case 'l':
6858                         size_units = 1;
6859                         rc = llapi_parse_size(optarg, &length,
6860                                               &size_units, 0);
6861                         if (rc) {
6862                                 fprintf(stderr, "%s: bad length '%s'\n",
6863                                         argv[0], optarg);
6864                                 return CMD_HELP;
6865                         }
6866                         break;
6867                 case 'm':
6868                         mode = lfs_get_mode(optarg);
6869                         if (mode < 0) {
6870                                 fprintf(stderr, "%s: bad mode '%s', valid "
6871                                                  "modes are READ or WRITE\n",
6872                                         argv[0], optarg);
6873                                 return CMD_HELP;
6874                         }
6875                         break;
6876                 case '?':
6877                         return CMD_HELP;
6878                 default:
6879                         fprintf(stderr, "%s: option '%s' unrecognized\n",
6880                                 argv[0], argv[optind - 1]);
6881                         return CMD_HELP;
6882                 }
6883         }
6884
6885         if (advice_type == LU_LADVISE_INVALID) {
6886                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
6887                 fprintf(stderr, "Valid types:");
6888                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
6889                      advice_type++) {
6890                         if (ladvise_names[advice_type] == NULL)
6891                                 continue;
6892                         fprintf(stderr, " %s", ladvise_names[advice_type]);
6893                 }
6894                 fprintf(stderr, "\n");
6895                 return CMD_HELP;
6896         }
6897
6898         if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
6899                 fprintf(stderr, "%s: Lock no expand advice is a per file "
6900                                  "descriptor advice, so when called from lfs, "
6901                                  "it does nothing.\n", argv[0]);
6902                 return CMD_HELP;
6903         }
6904
6905         if (argc <= optind) {
6906                 fprintf(stderr, "%s: please give one or more file names\n",
6907                         argv[0]);
6908                 return CMD_HELP;
6909         }
6910
6911         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
6912                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
6913                         argv[0]);
6914                 return CMD_HELP;
6915         }
6916
6917         if (end == LUSTRE_EOF && length != 0)
6918                 end = start + length;
6919
6920         if (end <= start) {
6921                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
6922                         argv[0], start, end);
6923                 return CMD_HELP;
6924         }
6925
6926         if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
6927                 fprintf(stderr, "%s: mode is only valid with lockahead\n",
6928                         argv[0]);
6929                 return CMD_HELP;
6930         }
6931
6932         if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
6933                 fprintf(stderr, "%s: mode is required with lockahead\n",
6934                         argv[0]);
6935                 return CMD_HELP;
6936         }
6937
6938         while (optind < argc) {
6939                 int rc2;
6940
6941                 path = argv[optind++];
6942
6943                 fd = open(path, O_RDONLY);
6944                 if (fd < 0) {
6945                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
6946                                 argv[0], path, strerror(errno));
6947                         rc2 = -errno;
6948                         goto next;
6949                 }
6950
6951                 advice.lla_start = start;
6952                 advice.lla_end = end;
6953                 advice.lla_advice = advice_type;
6954                 advice.lla_value1 = 0;
6955                 advice.lla_value2 = 0;
6956                 advice.lla_value3 = 0;
6957                 advice.lla_value4 = 0;
6958                 if (advice_type == LU_LADVISE_LOCKAHEAD) {
6959                         advice.lla_lockahead_mode = mode;
6960                         advice.lla_peradvice_flags = flags;
6961                 }
6962
6963                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
6964                 close(fd);
6965                 if (rc2 < 0) {
6966                         fprintf(stderr, "%s: cannot give advice '%s' to file "
6967                                 "'%s': %s\n", argv[0],
6968                                 ladvise_names[advice_type],
6969                                 path, strerror(errno));
6970
6971                         goto next;
6972                 }
6973
6974 next:
6975                 if (rc == 0 && rc2 < 0)
6976                         rc = rc2;
6977         }
6978         return rc;
6979 }
6980
6981 /** The input string contains a comma delimited list of component ids and
6982  * ranges, for example "1,2-4,7".
6983  */
6984 static int parse_mirror_ids(__u16 *ids, int size, char *arg)
6985 {
6986         bool end_of_loop = false;
6987         char *ptr = NULL;
6988         int nr = 0;
6989         int rc;
6990
6991         if (arg == NULL)
6992                 return -EINVAL;
6993
6994         while (!end_of_loop) {
6995                 int start_index;
6996                 int end_index;
6997                 int i;
6998                 char *endptr = NULL;
6999
7000                 rc = -EINVAL;
7001                 ptr = strchrnul(arg, ',');
7002                 end_of_loop = *ptr == '\0';
7003                 *ptr = '\0';
7004
7005                 start_index = strtol(arg, &endptr, 0);
7006                 if (endptr == arg) /* no data at all */
7007                         break;
7008                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
7009                         break;
7010                 if (start_index < 0)
7011                         break;
7012
7013                 end_index = start_index;
7014                 if (*endptr == '-') {
7015                         end_index = strtol(endptr + 1, &endptr, 0);
7016                         if (*endptr != '\0')
7017                                 break;
7018                         if (end_index < start_index)
7019                                 break;
7020                 }
7021
7022                 for (i = start_index; i <= end_index && size > 0; i++) {
7023                         int j;
7024
7025                         /* remove duplicate */
7026                         for (j = 0; j < nr; j++) {
7027                                 if (ids[j] == i)
7028                                         break;
7029                         }
7030                         if (j == nr) { /* no duplicate */
7031                                 ids[nr++] = i;
7032                                 --size;
7033                         }
7034                 }
7035
7036                 if (size == 0 && i < end_index)
7037                         break;
7038
7039                 *ptr = ',';
7040                 arg = ++ptr;
7041                 rc = 0;
7042         }
7043         if (!end_of_loop && ptr != NULL)
7044                 *ptr = ',';
7045
7046         return rc < 0 ? rc : nr;
7047 }
7048
7049 /**
7050  * struct verify_mirror_id - Mirror id to be verified.
7051  * @mirror_id:   A specified mirror id.
7052  * @is_valid_id: @mirror_id is valid or not in the mirrored file.
7053  */
7054 struct verify_mirror_id {
7055         __u16 mirror_id;
7056         bool is_valid_id;
7057 };
7058
7059 /**
7060  * compare_mirror_ids() - Compare mirror ids.
7061  * @layout: Mirror component list.
7062  * @cbdata: Callback data in verify_mirror_id structure.
7063  *
7064  * This is a callback function called by llapi_layout_comp_iterate()
7065  * to compare the specified mirror id with the one in the current
7066  * component of @layout. If they are the same, then the specified
7067  * mirror id is valid.
7068  *
7069  * Return: a negative error code on failure or
7070  *         LLAPI_LAYOUT_ITER_CONT: Proceed iteration
7071  *         LLAPI_LAYOUT_ITER_STOP: Stop iteration
7072  */
7073 static inline
7074 int compare_mirror_ids(struct llapi_layout *layout, void *cbdata)
7075 {
7076         struct verify_mirror_id *mirror_id_cbdata =
7077                                  (struct verify_mirror_id *)cbdata;
7078         uint32_t mirror_id;
7079         int rc = 0;
7080
7081         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
7082         if (rc < 0) {
7083                 rc = -errno;
7084                 fprintf(stderr,
7085                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
7086                         progname, strerror(errno));
7087                 return rc;
7088         }
7089
7090         if (mirror_id_cbdata->mirror_id == mirror_id) {
7091                 mirror_id_cbdata->is_valid_id = true;
7092                 return LLAPI_LAYOUT_ITER_STOP;
7093         }
7094
7095         return LLAPI_LAYOUT_ITER_CONT;
7096 }
7097
7098 /**
7099  * verify_mirror_ids() - Verify specified mirror ids.
7100  * @fname:      Mirrored file name.
7101  * @mirror_ids: Specified mirror ids to be verified.
7102  * @ids_nr:     Number of specified mirror ids.
7103  *
7104  * This function verifies that specified @mirror_ids are valid
7105  * in the mirrored file @fname.
7106  *
7107  * Return: 0 on success or a negative error code on failure.
7108  */
7109 static inline
7110 int verify_mirror_ids(const char *fname, __u16 *mirror_ids, int ids_nr)
7111 {
7112         struct llapi_layout *layout = NULL;
7113         struct verify_mirror_id mirror_id_cbdata = { 0 };
7114         struct stat stbuf;
7115         uint32_t flr_state;
7116         int i;
7117         int fd;
7118         int rc = 0;
7119         int rc2 = 0;
7120
7121         if (ids_nr <= 0)
7122                 return -EINVAL;
7123
7124         if (stat(fname, &stbuf) < 0) {
7125                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
7126                         progname, fname, strerror(errno));
7127                 rc = -errno;
7128                 goto error;
7129         }
7130
7131         if (!S_ISREG(stbuf.st_mode)) {
7132                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
7133                         progname, fname);
7134                 rc = -EINVAL;
7135                 goto error;
7136         }
7137
7138         fd = open(fname, O_DIRECT | O_RDONLY);
7139         if (fd < 0) {
7140                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
7141                         progname, fname, strerror(errno));
7142                 rc = -errno;
7143                 goto error;
7144         }
7145
7146         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
7147         if (rc < 0) {
7148                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
7149                         progname, fname, strerror(errno));
7150                 goto close_fd;
7151         }
7152
7153         layout = llapi_layout_get_by_fd(fd, 0);
7154         if (layout == NULL) {
7155                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
7156                         progname, fname, strerror(errno));
7157                 rc = -errno;
7158                 llapi_lease_release(fd);
7159                 goto close_fd;
7160         }
7161
7162         rc = llapi_layout_flags_get(layout, &flr_state);
7163         if (rc < 0) {
7164                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
7165                         progname, fname, strerror(errno));
7166                 rc = -errno;
7167                 goto free_layout;
7168         }
7169
7170         flr_state &= LCM_FL_FLR_MASK;
7171         switch (flr_state) {
7172         case LCM_FL_NONE:
7173                 rc = -EINVAL;
7174                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
7175                         progname, fname, llapi_layout_flags_string(flr_state));
7176                 goto free_layout;
7177         default:
7178                 break;
7179         }
7180
7181         rc2 = 0;
7182         for (i = 0; i < ids_nr; i++) {
7183                 mirror_id_cbdata.mirror_id = mirror_ids[i];
7184                 mirror_id_cbdata.is_valid_id = false;
7185
7186                 rc = llapi_layout_comp_iterate(layout, compare_mirror_ids,
7187                                                &mirror_id_cbdata);
7188                 if (rc < 0) {
7189                         rc = -errno;
7190                         fprintf(stderr,
7191                                 "%s: '%s' failed to verify mirror id: %u.\n",
7192                                 progname, fname, mirror_ids[i]);
7193                         goto free_layout;
7194                 }
7195
7196                 if (!mirror_id_cbdata.is_valid_id) {
7197                         rc2 = -EINVAL;
7198                         fprintf(stderr,
7199                                 "%s: '%s' invalid specified mirror id: %u.\n",
7200                                 progname, fname, mirror_ids[i]);
7201                 }
7202         }
7203         rc = rc2;
7204
7205 free_layout:
7206         llapi_layout_free(layout);
7207         llapi_lease_release(fd);
7208 close_fd:
7209         close(fd);
7210 error:
7211         return rc;
7212 }
7213
7214 static inline
7215 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
7216                            __u16 *mirror_ids, int ids_nr)
7217 {
7218         struct llapi_resync_comp comp_array[1024] = { { 0 } };
7219         struct llapi_layout *layout;
7220         struct stat stbuf;
7221         uint32_t flr_state;
7222         int comp_size = 0;
7223         int idx;
7224         int fd;
7225         int rc;
7226
7227         if (stat(fname, &stbuf) < 0) {
7228                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
7229                         progname, fname, strerror(errno));
7230                 rc = -errno;
7231                 goto error;
7232         }
7233         if (!S_ISREG(stbuf.st_mode)) {
7234                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
7235                         progname, fname);
7236                 rc = -EINVAL;
7237                 goto error;
7238         }
7239
7240         fd = open(fname, O_DIRECT | O_RDWR);
7241         if (fd < 0) {
7242                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
7243                         progname, fname, strerror(errno));
7244                 rc = -errno;
7245                 goto error;
7246         }
7247
7248         ioc->lil_mode = LL_LEASE_WRLCK;
7249         ioc->lil_flags = LL_LEASE_RESYNC;
7250         rc = llapi_lease_set(fd, ioc);
7251         if (rc < 0) {
7252                 fprintf(stderr,
7253                         "%s: '%s' llapi_lease_set resync failed: %s.\n",
7254                         progname, fname, strerror(errno));
7255                 goto close_fd;
7256         }
7257
7258         layout = llapi_layout_get_by_fd(fd, 0);
7259         if (layout == NULL) {
7260                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
7261                         progname, fname, strerror(errno));
7262                 rc = -errno;
7263                 goto close_fd;
7264         }
7265
7266         rc = llapi_layout_flags_get(layout, &flr_state);
7267         if (rc) {
7268                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
7269                         progname, fname, strerror(errno));
7270                 rc = -errno;
7271                 goto close_fd;
7272         }
7273
7274         flr_state &= LCM_FL_FLR_MASK;
7275         switch (flr_state) {
7276         case LCM_FL_NONE:
7277                 rc = -EINVAL;
7278         case LCM_FL_RDONLY:
7279                 fprintf(stderr, "%s: '%s' file state error: %s\n", progname,
7280                         fname, llapi_layout_flags_string(flr_state));
7281                 goto close_fd;
7282         default:
7283                 break;
7284         }
7285
7286         /* get stale component info */
7287         comp_size = llapi_mirror_find_stale(layout, comp_array,
7288                                             ARRAY_SIZE(comp_array),
7289                                             mirror_ids, ids_nr);
7290         if (comp_size < 0) {
7291                 rc = comp_size;
7292                 goto close_fd;
7293         }
7294
7295         idx = 0;
7296         while (idx < comp_size) {
7297                 ssize_t result;
7298                 uint64_t end;
7299                 __u16 mirror_id;
7300                 int i;
7301
7302                 rc = llapi_lease_check(fd);
7303                 if (rc != LL_LEASE_WRLCK) {
7304                         fprintf(stderr, "%s: '%s' lost lease lock.\n",
7305                                 progname, fname);
7306                         goto close_fd;
7307                 }
7308
7309                 mirror_id = comp_array[idx].lrc_mirror_id;
7310                 end = comp_array[idx].lrc_end;
7311
7312                 /* try to combine adjacent component */
7313                 for (i = idx + 1; i < comp_size; i++) {
7314                         if (mirror_id != comp_array[i].lrc_mirror_id ||
7315                             end != comp_array[i].lrc_start)
7316                                 break;
7317                         end = comp_array[i].lrc_end;
7318                 }
7319
7320                 result = llapi_mirror_resync_one(fd, layout, mirror_id,
7321                                                  comp_array[idx].lrc_start,
7322                                                  end);
7323                 if (result < 0) {
7324                         fprintf(stderr, "%s: '%s' llapi_mirror_resync_one: "
7325                                 "%ld.\n", progname, fname, result);
7326                         rc = result;
7327                         goto close_fd;
7328                 } else if (result > 0) {
7329                         int j;
7330
7331                         /* mark synced components */
7332                         for (j = idx; j < i; j++)
7333                                 comp_array[j].lrc_synced = true;
7334                 }
7335
7336                 idx = i;
7337         }
7338
7339         /* prepare ioc for lease put */
7340         ioc->lil_mode = LL_LEASE_UNLCK;
7341         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
7342         ioc->lil_count = 0;
7343         for (idx = 0; idx < comp_size; idx++) {
7344                 if (comp_array[idx].lrc_synced) {
7345                         ioc->lil_ids[ioc->lil_count] = comp_array[idx].lrc_id;
7346                         ioc->lil_count++;
7347                 }
7348         }
7349
7350         llapi_layout_free(layout);
7351
7352         rc = llapi_lease_set(fd, ioc);
7353         if (rc <= 0) {
7354                 if (rc == 0) /* lost lease lock */
7355                         rc = -EBUSY;
7356                 fprintf(stderr, "%s: resync file '%s' failed: %s.\n",
7357                         progname, fname, strerror(errno));
7358                 goto close_fd;
7359         }
7360         /**
7361          * llapi_lease_set returns lease mode when it request to unlock
7362          * the lease lock
7363          */
7364         rc = 0;
7365
7366 close_fd:
7367         close(fd);
7368 error:
7369         return rc;
7370 }
7371
7372 static inline int lfs_mirror_resync(int argc, char **argv)
7373 {
7374         struct ll_ioc_lease *ioc = NULL;
7375         __u16 mirror_ids[128] = { 0 };
7376         int ids_nr = 0;
7377         int c;
7378         int rc = 0;
7379
7380         struct option long_opts[] = {
7381         { .val = 'o',   .name = "only",         .has_arg = required_argument },
7382         { .name = NULL } };
7383
7384         while ((c = getopt_long(argc, argv, "o:", long_opts, NULL)) >= 0) {
7385                 switch (c) {
7386                 case 'o':
7387                         rc = parse_mirror_ids(mirror_ids,
7388                                         sizeof(mirror_ids) / sizeof(__u16),
7389                                         optarg);
7390                         if (rc < 0) {
7391                                 fprintf(stderr,
7392                                         "%s: bad mirror ids '%s'.\n",
7393                                         argv[0], optarg);
7394                                 goto error;
7395                         }
7396                         ids_nr = rc;
7397                         break;
7398                 default:
7399                         fprintf(stderr, "%s: options '%s' unrecognized.\n",
7400                                 argv[0], argv[optind - 1]);
7401                         rc = -EINVAL;
7402                         goto error;
7403                 }
7404         }
7405
7406         if (argc == optind) {
7407                 fprintf(stderr, "%s: no file name given.\n", argv[0]);
7408                 rc = CMD_HELP;
7409                 goto error;
7410         }
7411
7412         if (ids_nr > 0 && argc > optind + 1) {
7413                 fprintf(stderr,
7414                     "%s: option '--only' cannot be used upon multiple files.\n",
7415                         argv[0]);
7416                 rc = CMD_HELP;
7417                 goto error;
7418
7419         }
7420
7421         if (ids_nr > 0) {
7422                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
7423                 if (rc < 0)
7424                         goto error;
7425         }
7426
7427         /* set the lease on the file */
7428         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
7429         if (ioc == NULL) {
7430                 fprintf(stderr, "%s: cannot alloc id array for ioc: %s.\n",
7431                         argv[0], strerror(errno));
7432                 rc = -errno;
7433                 goto error;
7434         }
7435
7436         for (; optind < argc; optind++) {
7437                 rc = lfs_mirror_resync_file(argv[optind], ioc,
7438                                             mirror_ids, ids_nr);
7439                 /* ignore previous file's error, continue with next file */
7440
7441                 /* reset ioc */
7442                 memset(ioc, 0, sizeof(__u32) * 4096);
7443         }
7444
7445         free(ioc);
7446 error:
7447         return rc;
7448 }
7449
7450 /**
7451  * struct verify_chunk - Mirror chunk to be verified.
7452  * @chunk:        [start, end) of the chunk.
7453  * @mirror_count: Number of mirror ids in @mirror_id array.
7454  * @mirror_id:    Array of valid mirror ids that cover the chunk.
7455  */
7456 struct verify_chunk {
7457         struct lu_extent chunk;
7458         unsigned int mirror_count;
7459         __u16 mirror_id[LUSTRE_MIRROR_COUNT_MAX];
7460 };
7461
7462 /**
7463  * print_chunks() - Print chunk information.
7464  * @fname:       Mirrored file name.
7465  * @chunks:      Array of chunks.
7466  * @chunk_count: Number of chunks in @chunks array.
7467  *
7468  * This function prints [start, end) of each chunk in @chunks
7469  * for mirrored file @fname, and also prints the valid mirror ids
7470  * that cover the chunk.
7471  *
7472  * Return: void.
7473  */
7474 static inline
7475 void print_chunks(const char *fname, struct verify_chunk *chunks,
7476                   int chunk_count)
7477 {
7478         int i;
7479         int j;
7480
7481         fprintf(stdout, "Chunks to be verified in %s:\n", fname);
7482         for (i = 0; i < chunk_count; i++) {
7483                 fprintf(stdout, DEXT, PEXT(&chunks[i].chunk));
7484
7485                 if (chunks[i].mirror_count == 0)
7486                         fprintf(stdout, "\t[");
7487                 else {
7488                         fprintf(stdout, "\t[%u", chunks[i].mirror_id[0]);
7489                         for (j = 1; j < chunks[i].mirror_count; j++)
7490                                 fprintf(stdout, ", %u", chunks[i].mirror_id[j]);
7491                 }
7492                 fprintf(stdout, "]\t%u\n", chunks[i].mirror_count);
7493         }
7494         fprintf(stdout, "\n");
7495 }
7496
7497 /**
7498  * print_checksums() - Print CRC-32 checksum values.
7499  * @chunk: A chunk and its corresponding valid mirror ids.
7500  * @crc:   CRC-32 checksum values on the chunk for each valid mirror.
7501  *
7502  * This function prints CRC-32 checksum values on @chunk for
7503  * each valid mirror that covers it.
7504  *
7505  * Return: void.
7506  */
7507 static inline
7508 void print_checksums(struct verify_chunk *chunk, unsigned long *crc)
7509 {
7510         int i;
7511
7512         fprintf(stdout,
7513                 "CRC-32 checksum value for chunk "DEXT":\n",
7514                 PEXT(&chunk->chunk));
7515         for (i = 0; i < chunk->mirror_count; i++)
7516                 fprintf(stdout, "Mirror %u:\t%#lx\n",
7517                         chunk->mirror_id[i], crc[i]);
7518         fprintf(stdout, "\n");
7519 }
7520
7521 /**
7522  * filter_mirror_id() - Filter specified mirror ids.
7523  * @chunks:      Array of chunks.
7524  * @chunk_count: Number of chunks in @chunks array.
7525  * @mirror_ids:  Specified mirror ids to be verified.
7526  * @ids_nr:      Number of specified mirror ids.
7527  *
7528  * This function scans valid mirror ids that cover each chunk in @chunks
7529  * and filters specified mirror ids.
7530  *
7531  * Return: void.
7532  */
7533 static inline
7534 void filter_mirror_id(struct verify_chunk *chunks, int chunk_count,
7535                       __u16 *mirror_ids, int ids_nr)
7536 {
7537         int i;
7538         int j;
7539         int k;
7540         __u16 valid_id[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
7541         unsigned int valid_count = 0;
7542
7543         for (i = 0; i < chunk_count; i++) {
7544                 if (chunks[i].mirror_count == 0)
7545                         continue;
7546
7547                 valid_count = 0;
7548                 for (j = 0; j < ids_nr; j++) {
7549                         for (k = 0; k < chunks[i].mirror_count; k++) {
7550                                 if (chunks[i].mirror_id[k] == mirror_ids[j]) {
7551                                         valid_id[valid_count] = mirror_ids[j];
7552                                         valid_count++;
7553                                         break;
7554                                 }
7555                         }
7556                 }
7557
7558                 memcpy(chunks[i].mirror_id, valid_id,
7559                        sizeof(__u16) * valid_count);
7560                 chunks[i].mirror_count = valid_count;
7561         }
7562 }
7563
7564 /**
7565  * lfs_mirror_prepare_chunk() - Find mirror chunks to be verified.
7566  * @layout:      Mirror component list.
7567  * @chunks:      Array of chunks.
7568  * @chunks_size: Array size of @chunks.
7569  *
7570  * This function scans the components in @layout from offset 0 to LUSTRE_EOF
7571  * to find out chunk segments and store them in @chunks array.
7572  *
7573  * The @mirror_id array in each element of @chunks will store the valid
7574  * mirror ids that cover the chunk. If a mirror component covering the
7575  * chunk has LCME_FL_STALE or LCME_FL_OFFLINE flag, then the mirror id
7576  * will not be stored into the @mirror_id array, and the chunk for that
7577  * mirror will not be verified.
7578  *
7579  * The @mirror_count in each element of @chunks will store the number of
7580  * mirror ids in @mirror_id array. If @mirror_count is 0, it indicates the
7581  * chunk is invalid in all of the mirrors. And if @mirror_count is 1, it
7582  * indicates the chunk is valid in only one mirror. In both cases, the
7583  * chunk will not be verified.
7584  *
7585  * Here is an example:
7586  *
7587  *  0      1M     2M     3M     4M           EOF
7588  *  +------+-------------+--------------------+
7589  *  |      |             |      S             |       mirror1
7590  *  +------+------+------+------+-------------+
7591  *  |             |   S  |   S  |             |       mirror2
7592  *  +-------------+------+------+-------------+
7593  *
7594  * prepared @chunks array will contain 5 elements:
7595  * (([0, 1M), [1, 2], 2),
7596  *  ([1M, 2M), [1, 2], 2),
7597  *  ([2M, 3M), [1], 1),
7598  *  ([3M, 4M], [], 0),
7599  *  ([4M, EOF), [2], 1))
7600  *
7601  * Return: the actual array size of @chunks on success
7602  *         or a negative error code on failure.
7603  */
7604 static inline
7605 int lfs_mirror_prepare_chunk(struct llapi_layout *layout,
7606                              struct verify_chunk *chunks,
7607                              size_t chunks_size)
7608 {
7609         uint64_t start;
7610         uint64_t end;
7611         uint32_t mirror_id;
7612         uint32_t flags;
7613         int idx = 0;
7614         int i = 0;
7615         int rc = 0;
7616
7617         memset(chunks, 0, sizeof(*chunks) * chunks_size);
7618
7619         while (1) {
7620                 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
7621                 if (rc < 0) {
7622                         fprintf(stderr,
7623                                 "%s: move to the first layout component: %s.\n",
7624                                 progname, strerror(errno));
7625                         goto error;
7626                 }
7627
7628                 i = 0;
7629                 rc = 0;
7630                 chunks[idx].chunk.e_end = LUSTRE_EOF;
7631                 while (rc == 0) {
7632                         rc = llapi_layout_comp_extent_get(layout, &start, &end);
7633                         if (rc < 0) {
7634                                 fprintf(stderr,
7635                                         "%s: llapi_layout_comp_extent_get failed: %s.\n",
7636                                         progname, strerror(errno));
7637                                 goto error;
7638                         }
7639
7640                         if (start > chunks[idx].chunk.e_start ||
7641                             end <= chunks[idx].chunk.e_start)
7642                                 goto next;
7643
7644                         if (end < chunks[idx].chunk.e_end)
7645                                 chunks[idx].chunk.e_end = end;
7646
7647                         rc = llapi_layout_comp_flags_get(layout, &flags);
7648                         if (rc < 0) {
7649                                 fprintf(stderr,
7650                                         "%s: llapi_layout_comp_flags_get failed: %s.\n",
7651                                         progname, strerror(errno));
7652                                 goto error;
7653                         }
7654
7655                         if (flags & LCME_FL_STALE || flags & LCME_FL_OFFLINE)
7656                                 goto next;
7657
7658                         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
7659                         if (rc < 0) {
7660                                 fprintf(stderr,
7661                                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
7662                                         progname, strerror(errno));
7663                                 goto error;
7664                         }
7665
7666                         chunks[idx].mirror_id[i] = mirror_id;
7667                         i++;
7668                         if (i >= ARRAY_SIZE(chunks[idx].mirror_id)) {
7669                                 fprintf(stderr,
7670                                         "%s: mirror_id array is too small.\n",
7671                                         progname);
7672                                 rc = -EINVAL;
7673                                 goto error;
7674                         }
7675
7676                 next:
7677                         rc = llapi_layout_comp_use(layout,
7678                                                    LLAPI_LAYOUT_COMP_USE_NEXT);
7679                         if (rc < 0) {
7680                                 fprintf(stderr,
7681                                         "%s: move to the next layout component: %s.\n",
7682                                         progname, strerror(errno));
7683                                 goto error;
7684                         }
7685                 } /* loop through all components */
7686
7687                 chunks[idx].mirror_count = i;
7688
7689                 if (chunks[idx].chunk.e_end == LUSTRE_EOF)
7690                         break;
7691
7692                 idx++;
7693                 if (idx >= chunks_size) {
7694                         fprintf(stderr, "%s: chunks array is too small.\n",
7695                                 progname);
7696                         rc = -EINVAL;
7697                         goto error;
7698                 }
7699
7700                 chunks[idx].chunk.e_start = chunks[idx - 1].chunk.e_end;
7701         }
7702
7703 error:
7704         return rc < 0 ? rc : idx + 1;
7705 }
7706
7707 /**
7708  * lfs_mirror_verify_chunk() - Verify a chunk.
7709  * @fd:        File descriptor of the mirrored file.
7710  * @file_size: Size of the mirrored file.
7711  * @chunk:     A chunk and its corresponding valid mirror ids.
7712  * @verbose:   Verbose mode.
7713  *
7714  * This function verifies a @chunk contains exactly the same data
7715  * ammong the mirrors that cover it.
7716  *
7717  * If @verbose is specified, then the function will print where the
7718  * differences are if the data do not match. Otherwise, it will
7719  * just return an error in that case.
7720  *
7721  * Return: 0 on success or a negative error code on failure.
7722  */
7723 static inline
7724 int lfs_mirror_verify_chunk(int fd, size_t file_size,
7725                             struct verify_chunk *chunk, int verbose)
7726 {
7727         const size_t buflen = 4 * 1024 * 1024; /* 4M */
7728         void *buf;
7729         size_t page_size = sysconf(_SC_PAGESIZE);
7730         ssize_t bytes_read;
7731         ssize_t bytes_done;
7732         size_t count;
7733         off_t pos;
7734         unsigned long crc;
7735         unsigned long crc_array[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
7736         int i;
7737         int rc = 0;
7738
7739         if (file_size == 0)
7740                 return 0;
7741
7742         rc = posix_memalign(&buf, page_size, buflen);
7743         if (rc) /* error code is returned directly */
7744                 return -rc;
7745
7746         if (verbose > 1) {
7747                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
7748                         PEXT(&chunk->chunk));
7749                 for (i = 0; i < chunk->mirror_count; i++)
7750                         fprintf(stdout, " %u", chunk->mirror_id[i]);
7751                 fprintf(stdout, "\n");
7752         }
7753
7754         bytes_done = 0;
7755         count = MIN(chunk->chunk.e_end, file_size) - chunk->chunk.e_start;
7756         pos = chunk->chunk.e_start;
7757         while (bytes_done < count) {
7758                 /* compute initial CRC-32 checksum */
7759                 crc = crc32(0L, Z_NULL, 0);
7760                 memset(crc_array, 0, sizeof(crc_array));
7761
7762                 bytes_read = 0;
7763                 for (i = 0; i < chunk->mirror_count; i++) {
7764                         bytes_read = llapi_mirror_read(fd, chunk->mirror_id[i],
7765                                                        buf, buflen, pos);
7766                         if (bytes_read < 0) {
7767                                 rc = bytes_read;
7768                                 fprintf(stderr,
7769                                         "%s: failed to read data from mirror %u: %s.\n",
7770                                         progname, chunk->mirror_id[i],
7771                                         strerror(-rc));
7772                                 goto error;
7773                         }
7774
7775                         /* compute new CRC-32 checksum */
7776                         crc_array[i] = crc32(crc, buf, bytes_read);
7777                 }
7778
7779                 if (verbose)
7780                         print_checksums(chunk, crc_array);
7781
7782                 /* compare CRC-32 checksum values */
7783                 for (i = 1; i < chunk->mirror_count; i++) {
7784                         if (crc_array[i] != crc_array[0]) {
7785                                 rc = -EINVAL;
7786                                 if (!verbose)
7787                                         goto error;
7788
7789                                 fprintf(stderr,
7790                                         "%s: chunk "DEXT" has different checksum value on mirror %u and mirror %u.\n",
7791                                         progname, PEXT(&chunk->chunk),
7792                                         chunk->mirror_id[0],
7793                                         chunk->mirror_id[i]);
7794                         }
7795                 }
7796
7797                 pos += bytes_read;
7798                 bytes_done += bytes_read;
7799         }
7800
7801         if (verbose > 1 && rc == 0) {
7802                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
7803                         PEXT(&chunk->chunk));
7804                 for (i = 0; i < chunk->mirror_count; i++)
7805                         fprintf(stdout, " %u", chunk->mirror_id[i]);
7806                 fprintf(stdout, " PASS\n\n");
7807         }
7808
7809 error:
7810         free(buf);
7811         return rc;
7812 }
7813
7814 /**
7815  * lfs_mirror_verify_file() - Verify a mirrored file.
7816  * @fname:      Mirrored file name.
7817  * @mirror_ids: Specified mirror ids to be verified.
7818  * @ids_nr:     Number of specified mirror ids.
7819  * @verbose:    Verbose mode.
7820  *
7821  * This function verifies that each SYNC mirror of a mirrored file
7822  * specified by @fname contains exactly the same data.
7823  *
7824  * If @mirror_ids is specified, then the function will verify the
7825  * mirrors specified by @mirror_ids contain exactly the same data.
7826  *
7827  * If @verbose is specified, then the function will print where the
7828  * differences are if the data do not match. Otherwise, it will
7829  * just return an error in that case.
7830  *
7831  * Return: 0 on success or a negative error code on failure.
7832  */
7833 static inline
7834 int lfs_mirror_verify_file(const char *fname, __u16 *mirror_ids, int ids_nr,
7835                            int verbose)
7836 {
7837         struct verify_chunk chunks_array[1024] = { };
7838         struct llapi_layout *layout = NULL;
7839         struct stat stbuf;
7840         uint32_t flr_state;
7841         int fd;
7842         int chunk_count = 0;
7843         int idx = 0;
7844         int rc = 0;
7845         int rc1 = 0;
7846         int rc2 = 0;
7847
7848         if (stat(fname, &stbuf) < 0) {
7849                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
7850                         progname, fname, strerror(errno));
7851                 rc = -errno;
7852                 goto error;
7853         }
7854
7855         if (!S_ISREG(stbuf.st_mode)) {
7856                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
7857                         progname, fname);
7858                 rc = -EINVAL;
7859                 goto error;
7860         }
7861
7862         if (stbuf.st_size == 0) {
7863                 if (verbose)
7864                         fprintf(stdout, "%s: '%s' file size is 0.\n",
7865                                 progname, fname);
7866                 rc = 0;
7867                 goto error;
7868         }
7869
7870         fd = open(fname, O_DIRECT | O_RDONLY);
7871         if (fd < 0) {
7872                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
7873                         progname, fname, strerror(errno));
7874                 rc = -errno;
7875                 goto error;
7876         }
7877
7878         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
7879         if (rc < 0) {
7880                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
7881                         progname, fname, strerror(errno));
7882                 goto close_fd;
7883         }
7884
7885         layout = llapi_layout_get_by_fd(fd, 0);
7886         if (layout == NULL) {
7887                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
7888                         progname, fname, strerror(errno));
7889                 rc = -errno;
7890                 llapi_lease_release(fd);
7891                 goto close_fd;
7892         }
7893
7894         rc = llapi_layout_flags_get(layout, &flr_state);
7895         if (rc < 0) {
7896                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
7897                         progname, fname, strerror(errno));
7898                 rc = -errno;
7899                 goto free_layout;
7900         }
7901
7902         flr_state &= LCM_FL_FLR_MASK;
7903         switch (flr_state) {
7904         case LCM_FL_NONE:
7905                 rc = -EINVAL;
7906                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
7907                         progname, fname, llapi_layout_flags_string(flr_state));
7908                 goto free_layout;
7909         default:
7910                 break;
7911         }
7912
7913         /* find out mirror chunks to be verified */
7914         chunk_count = lfs_mirror_prepare_chunk(layout, chunks_array,
7915                                                ARRAY_SIZE(chunks_array));
7916         if (chunk_count < 0) {
7917                 rc = chunk_count;
7918                 goto free_layout;
7919         }
7920
7921         if (ids_nr > 0)
7922                 /* filter specified mirror ids */
7923                 filter_mirror_id(chunks_array, chunk_count, mirror_ids, ids_nr);
7924
7925         if (verbose > 2)
7926                 print_chunks(fname, chunks_array, chunk_count);
7927
7928         for (idx = 0; idx < chunk_count; idx++) {
7929                 if (chunks_array[idx].chunk.e_start >= stbuf.st_size) {
7930                         if (verbose)
7931                                 fprintf(stdout,
7932                                         "%s: '%s' chunk "DEXT" exceeds file size %#llx: skipped\n",
7933                                         progname, fname,
7934                                         PEXT(&chunks_array[idx].chunk),
7935                                         (unsigned long long)stbuf.st_size);
7936                         break;
7937                 }
7938
7939                 if (chunks_array[idx].mirror_count == 0) {
7940                         fprintf(stderr,
7941                                 "%s: '%s' chunk "DEXT" is invalid in all of the mirrors: ",
7942                                 progname, fname,
7943                                 PEXT(&chunks_array[idx].chunk));
7944                         if (verbose) {
7945                                 fprintf(stderr, "skipped\n");
7946                                 continue;
7947                         }
7948                         rc = -EINVAL;
7949                         fprintf(stderr, "failed\n");
7950                         goto free_layout;
7951                 }
7952
7953                 if (chunks_array[idx].mirror_count == 1) {
7954                         if (verbose)
7955                                 fprintf(stdout,
7956                                         "%s: '%s' chunk "DEXT" is only valid in mirror %u: skipped\n",
7957                                         progname, fname,
7958                                         PEXT(&chunks_array[idx].chunk),
7959                                         chunks_array[idx].mirror_id[0]);
7960                         continue;
7961                 }
7962
7963                 rc = llapi_lease_check(fd);
7964                 if (rc != LL_LEASE_RDLCK) {
7965                         fprintf(stderr, "%s: '%s' lost lease lock.\n",
7966                                 progname, fname);
7967                         goto free_layout;
7968                 }
7969
7970                 /* verify one chunk */
7971                 rc1 = lfs_mirror_verify_chunk(fd, stbuf.st_size,
7972                                               &chunks_array[idx], verbose);
7973                 if (rc1 < 0) {
7974                         rc2 = rc1;
7975                         if (!verbose) {
7976                                 rc = rc1;
7977                                 goto free_layout;
7978                         }
7979                 }
7980         }
7981
7982         if (rc2 < 0)
7983                 rc = rc2;
7984
7985 free_layout:
7986         llapi_layout_free(layout);
7987         llapi_lease_release(fd);
7988 close_fd:
7989         close(fd);
7990 error:
7991         return rc;
7992 }
7993
7994 /**
7995  * lfs_mirror_verify() - Parse and execute lfs mirror verify command.
7996  * @argc: The count of lfs mirror verify command line arguments.
7997  * @argv: Array of strings for lfs mirror verify command line arguments.
7998  *
7999  * This function parses lfs mirror verify command and verifies the
8000  * specified mirrored file(s).
8001  *
8002  * Return: 0 on success or a negative error code on failure.
8003  */
8004 static inline int lfs_mirror_verify(int argc, char **argv)
8005 {
8006         __u16 mirror_ids[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
8007         int ids_nr = 0;
8008         int c;
8009         int verbose = 0;
8010         int rc = 0;
8011         int rc1 = 0;
8012         char cmd[PATH_MAX];
8013
8014         struct option long_opts[] = {
8015         { .val = 'o',   .name = "only",         .has_arg = required_argument },
8016         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
8017         { .name = NULL } };
8018
8019         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
8020         progname = cmd;
8021         while ((c = getopt_long(argc, argv, "o:v", long_opts, NULL)) >= 0) {
8022                 switch (c) {
8023                 case 'o':
8024                         rc = parse_mirror_ids(mirror_ids,
8025                                               ARRAY_SIZE(mirror_ids),
8026                                               optarg);
8027                         if (rc < 0) {
8028                                 fprintf(stderr,
8029                                         "%s: bad mirror ids '%s'.\n",
8030                                         progname, optarg);
8031                                 goto error;
8032                         }
8033                         ids_nr = rc;
8034                         if (ids_nr < 2) {
8035                                 fprintf(stderr,
8036                                         "%s: at least 2 mirror ids needed with '--only' option.\n",
8037                                         progname);
8038                                 rc = CMD_HELP;
8039                                 goto error;
8040                         }
8041                         break;
8042                 case 'v':
8043                         verbose++;
8044                         break;
8045                 default:
8046                         fprintf(stderr, "%s: options '%s' unrecognized.\n",
8047                                 progname, argv[optind - 1]);
8048                         rc = -EINVAL;
8049                         goto error;
8050                 }
8051         }
8052
8053         if (argc == optind) {
8054                 fprintf(stderr, "%s: no file name given.\n", progname);
8055                 rc = CMD_HELP;
8056                 goto error;
8057         }
8058
8059         if (ids_nr > 0 && argc > optind + 1) {
8060                 fprintf(stderr,
8061                         "%s: '--only' cannot be used upon multiple files.\n",
8062                         progname);
8063                 rc = CMD_HELP;
8064                 goto error;
8065
8066         }
8067
8068         if (ids_nr > 0) {
8069                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
8070                 if (rc < 0)
8071                         goto error;
8072         }
8073
8074         rc = 0;
8075         for (; optind < argc; optind++) {
8076                 rc1 = lfs_mirror_verify_file(argv[optind], mirror_ids, ids_nr,
8077                                              verbose);
8078                 if (rc1 < 0)
8079                         rc = rc1;
8080         }
8081 error:
8082         return rc;
8083 }
8084
8085 /**
8086  * lfs_mirror() - Parse and execute lfs mirror commands.
8087  * @argc: The count of lfs mirror command line arguments.
8088  * @argv: Array of strings for lfs mirror command line arguments.
8089  *
8090  * This function parses lfs mirror commands and performs the
8091  * corresponding functions specified in mirror_cmdlist[].
8092  *
8093  * Return: 0 on success or an error code on failure.
8094  */
8095 static int lfs_mirror(int argc, char **argv)
8096 {
8097         char cmd[PATH_MAX];
8098         int rc = 0;
8099
8100         setlinebuf(stdout);
8101
8102         Parser_init("lfs-mirror > ", mirror_cmdlist);
8103
8104         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
8105         progname = cmd;
8106         program_invocation_short_name = cmd;
8107         if (argc > 1)
8108                 rc = Parser_execarg(argc - 1, argv + 1, mirror_cmdlist);
8109         else
8110                 rc = Parser_commands();
8111
8112         return rc < 0 ? -rc : rc;
8113 }
8114
8115 /**
8116  * lfs_mirror_list_commands() - List lfs mirror commands.
8117  * @argc: The count of command line arguments.
8118  * @argv: Array of strings for command line arguments.
8119  *
8120  * This function lists lfs mirror commands defined in mirror_cmdlist[].
8121  *
8122  * Return: 0 on success.
8123  */
8124 static int lfs_mirror_list_commands(int argc, char **argv)
8125 {
8126         char buffer[81] = "";
8127
8128         Parser_list_commands(mirror_cmdlist, buffer, sizeof(buffer),
8129                              NULL, 0, 4);
8130
8131         return 0;
8132 }
8133
8134 static int lfs_list_commands(int argc, char **argv)
8135 {
8136         char buffer[81] = ""; /* 80 printable chars + terminating NUL */
8137
8138         Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
8139
8140         return 0;
8141 }
8142
8143 int main(int argc, char **argv)
8144 {
8145         int rc;
8146
8147         /* Ensure that liblustreapi constructor has run */
8148         if (!llapi_liblustreapi_initialized())
8149                 fprintf(stderr, "liblustreapi was not properly initialized\n");
8150
8151         setlinebuf(stdout);
8152         opterr = 0;
8153
8154         Parser_init("lfs > ", cmdlist);
8155
8156         progname = program_invocation_short_name; /* Used in error messages */
8157         if (argc > 1) {
8158                 llapi_set_command_name(argv[1]);
8159                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
8160                 llapi_clear_command_name();
8161         } else {
8162                 rc = Parser_commands();
8163         }
8164
8165         return rc < 0 ? -rc : rc;
8166 }
8167
8168 #ifdef _LUSTRE_IDL_H_
8169 /* Everything we need here should be included by lustreapi.h. */
8170 # error "lfs should not depend on lustre_idl.h"
8171 #endif /* _LUSTRE_IDL_H_ */