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