Whamcloud - gitweb
LU-13425 lfs: support numeric hash type by "lfs migrate -H"
[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 <sys/xattr.h>
62 #include <fcntl.h>
63 #include <dirent.h>
64 #include <time.h>
65 #include <ctype.h>
66 #include <zlib.h>
67 #include <libgen.h>
68 #include <asm/byteorder.h>
69 #include "lfs_project.h"
70
71 #include <libcfs/util/string.h>
72 #include <libcfs/util/ioctl.h>
73 #include <libcfs/util/parser.h>
74 #include <libcfs/util/string.h>
75 #include <lustre/lustreapi.h>
76 #include <linux/lustre/lustre_ver.h>
77 #include <linux/lustre/lustre_param.h>
78 #include <linux/lnet/nidstr.h>
79 #include <lnetconfig/cyaml.h>
80
81 #ifndef ARRAY_SIZE
82 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
83 #endif /* !ARRAY_SIZE */
84
85 /* all functions */
86 static int lfs_find(int argc, char **argv);
87 static int lfs_getstripe(int argc, char **argv);
88 static int lfs_getdirstripe(int argc, char **argv);
89 static int lfs_setdirstripe(int argc, char **argv);
90 static int lfs_rmentry(int argc, char **argv);
91 static int lfs_osts(int argc, char **argv);
92 static int lfs_mdts(int argc, char **argv);
93 static int lfs_df(int argc, char **argv);
94 static int lfs_getname(int argc, char **argv);
95 static int lfs_check(int argc, char **argv);
96 #ifdef HAVE_SYS_QUOTA_H
97 static int lfs_setquota(int argc, char **argv);
98 static int lfs_quota(int argc, char **argv);
99 static int lfs_project(int argc, char **argv);
100 #endif
101 static int lfs_flushctx(int argc, char **argv);
102 static int lfs_poollist(int argc, char **argv);
103 static int lfs_changelog(int argc, char **argv);
104 static int lfs_changelog_clear(int argc, char **argv);
105 static int lfs_fid2path(int argc, char **argv);
106 static int lfs_path2fid(int argc, char **argv);
107 static int lfs_rmfid(int argc, char **argv);
108 static int lfs_data_version(int argc, char **argv);
109 static int lfs_hsm_state(int argc, char **argv);
110 static int lfs_hsm_set(int argc, char **argv);
111 static int lfs_hsm_clear(int argc, char **argv);
112 static int lfs_hsm_action(int argc, char **argv);
113 static int lfs_hsm_archive(int argc, char **argv);
114 static int lfs_hsm_restore(int argc, char **argv);
115 static int lfs_hsm_release(int argc, char **argv);
116 static int lfs_hsm_remove(int argc, char **argv);
117 static int lfs_hsm_cancel(int argc, char **argv);
118 static int lfs_swap_layouts(int argc, char **argv);
119 static int lfs_mv(int argc, char **argv);
120 static int lfs_ladvise(int argc, char **argv);
121 static int lfs_getsom(int argc, char **argv);
122 static int lfs_heat_get(int argc, char **argv);
123 static int lfs_heat_set(int argc, char **argv);
124 static int lfs_mirror(int argc, char **argv);
125 static int lfs_mirror_list_commands(int argc, char **argv);
126 static int lfs_list_commands(int argc, char **argv);
127 static inline int lfs_mirror_resync(int argc, char **argv);
128 static inline int lfs_mirror_verify(int argc, char **argv);
129 static inline int lfs_mirror_read(int argc, char **argv);
130 static inline int lfs_mirror_write(int argc, char **argv);
131 static inline int lfs_mirror_copy(int argc, char **argv);
132 static int lfs_pcc_attach(int argc, char **argv);
133 static int lfs_pcc_attach_fid(int argc, char **argv);
134 static int lfs_pcc_detach(int argc, char **argv);
135 static int lfs_pcc_detach_fid(int argc, char **argv);
136 static int lfs_pcc_state(int argc, char **argv);
137 static int lfs_pcc(int argc, char **argv);
138 static int lfs_pcc_list_commands(int argc, char **argv);
139 static int lfs_migrate_to_dom(int fd, int fdv, char *name,
140                               __u64 migration_flags,
141                               struct llapi_stripe_param *param,
142                               struct llapi_layout *layout);
143
144 enum setstripe_origin {
145         SO_SETSTRIPE,
146         SO_MIGRATE,
147         SO_MIGRATE_MDT,
148         SO_MIRROR_CREATE,
149         SO_MIRROR_EXTEND,
150         SO_MIRROR_SPLIT,
151         SO_MIRROR_DELETE,
152 };
153 static int lfs_setstripe_internal(int argc, char **argv,
154                                   enum setstripe_origin opc);
155
156 static inline int lfs_setstripe(int argc, char **argv)
157 {
158         return lfs_setstripe_internal(argc, argv, SO_SETSTRIPE);
159 }
160 static inline int lfs_setstripe_migrate(int argc, char **argv)
161 {
162         return lfs_setstripe_internal(argc, argv, SO_MIGRATE);
163 }
164 static inline int lfs_mirror_create(int argc, char **argv)
165 {
166         return lfs_setstripe_internal(argc, argv, SO_MIRROR_CREATE);
167 }
168 static inline int lfs_mirror_extend(int argc, char **argv)
169 {
170         return lfs_setstripe_internal(argc, argv, SO_MIRROR_EXTEND);
171 }
172 static inline int lfs_mirror_split(int argc, char **argv)
173 {
174         return lfs_setstripe_internal(argc, argv, SO_MIRROR_SPLIT);
175 }
176 static inline int lfs_mirror_delete(int argc, char **argv)
177 {
178         return lfs_setstripe_internal(argc, argv, SO_MIRROR_DELETE);
179 }
180
181 /* Setstripe and migrate share mostly the same parameters */
182 #define SSM_CMD_COMMON(cmd) \
183         "usage: "cmd" [--component-end|-E <comp_end>]\n"                \
184         "                 [--stripe-count|-c <stripe_count>]\n"         \
185         "                 [--overstripe-count|-C <stripe_count>]\n"     \
186         "                 [--stripe-index|-i <start_ost_idx>]\n"        \
187         "                 [--stripe-size|-S <stripe_size>]\n"           \
188         "                 [--layout|-L <pattern>]\n"                    \
189         "                 [--mirror_count|-N[mirror_count]]\n"          \
190         "                 [--ost|-o <ost_indices>]\n"                   \
191         "                 [--pool|-p <pool_name>]\n"                    \
192         "                 [--yaml|-y <yaml_template_file>]\n"           \
193         "                 [--copy=<lustre_src>]\n"
194
195 #define SSM_HELP_COMMON \
196         "\tstripe_count: Number of OSTs to stripe over (0=fs default, -1 all)\n" \
197         "\t              Using -C instead of -c allows overstriping, which\n" \
198         "\t              will place more than one stripe per OST if\n" \
199         "\t              stripe_count is greater than the number of OSTs\n" \
200         "\tstart_ost_idx: OST index of first stripe (-1=default round robin)\n"\
201         "\tstripe_size:  Number of bytes on each OST (0=fs default)\n" \
202         "\t              Can be specified with K, M or G (for KB, MB, GB\n" \
203         "\t              respectively)\n"                               \
204         "\tpool_name:    Name of OST pool to use (default none)\n"      \
205         "\tlayout:       stripe pattern type: raid0, mdt (default raid0)\n"\
206         "\tost_indices:  List of OST indices, can be repeated multiple times\n"\
207         "\t              Indices be specified in a format of:\n"        \
208         "\t                -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n"        \
209         "\t              Or:\n"                                         \
210         "\t                -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n"  \
211         "\t              If --pool is set with --ost then the OSTs\n"   \
212         "\t              must be the members of the pool.\n"            \
213         "\tcomp_end:     Extent end of component, start after previous end.\n"\
214         "\t              Can be specified with K, M or G (for KB, MB, GB\n" \
215         "\t              respectively, -1 for EOF). Must be a multiple of\n"\
216         "\t              stripe_size.\n"                                      \
217         "\tyaml_template_file:\n"                                             \
218         "\t              YAML layout template file, can't be used with -c,\n" \
219         "\t              -i, -S, -p, -o, or -E arguments.\n"                  \
220         "\tlustre_src:   Lustre file/dir whose layout info is used to set\n"  \
221         "\t              another lustre file or directory, can't used with\n" \
222         "\t              -c, -i, -S, -p, -o, or -E arguments.\n"
223
224 #define MIRROR_CREATE_HELP                                                     \
225         "\tmirror_count: Number of mirrors to be created with the upcoming\n"  \
226         "\t              setstripe layout options\n"                           \
227         "\t              It defaults to 1 if not specified; if specified,\n"   \
228         "\t              it must follow the option without a space.\n"         \
229         "\t              The option can also be repeated multiple times to\n"  \
230         "\t              separate mirrors that have different layouts.\n"      \
231         "\tSETSTRIPE_OPTIONS: Mirror layout as with 'setstripe'\n"             \
232         "\t              It can be a plain layout or a composite layout.\n"    \
233         "\t              If not specified, the stripe options inherited\n"     \
234         "\t              from the previous component will be used.\n"          \
235         "\tflags:        set flags to the component of the current mirror.\n"  \
236         "\t              Only \"prefer\" flag is supported so far.\n"
237
238 #define MIRROR_EXTEND_HELP                                                     \
239         MIRROR_CREATE_HELP                                                     \
240         "\tvictim_file:  The layout of victim_file will be split and used\n"   \
241         "\t              as a mirror added to the mirrored file.\n"            \
242         "\tno-verify:    This option indicates not to verify the mirror(s)\n"  \
243         "\t              from victim file(s) in case the victim file(s)\n"     \
244         "\t              contains the same data as the original mirrored\n"    \
245         "\t              file.\n"
246
247 #define MIRROR_EXTEND_USAGE                                                    \
248         "                 {--mirror-count|-N[mirror_count]}\n"                 \
249         "                 [SETSTRIPE_OPTIONS|-f|--file <victim_file>]\n"       \
250         "                 [--no-verify]\n"
251
252 #define SETSTRIPE_USAGE                                                 \
253         SSM_CMD_COMMON("setstripe")                                     \
254         MIRROR_EXTEND_USAGE                                             \
255         "                 <directory|filename>\n"                       \
256         SSM_HELP_COMMON                                                 \
257         MIRROR_EXTEND_HELP
258
259 #define MIGRATE_USAGE                                                   \
260         SSM_CMD_COMMON("migrate  ")                                     \
261         "                 [--block|-b] [--non-block|-n]\n"              \
262         "                 [--non-direct|-D] [--verbose|-v]\n"           \
263         "                 <filename>\n"                                 \
264         SSM_HELP_COMMON                                                 \
265         "\n"                                                            \
266         "\tblock:        Block file access during data migration (default)\n" \
267         "\tnon-block:    Abort migrations if concurrent access is detected\n" \
268         "\tnon-direct:   Do not use direct I/O to copy file contents\n" \
269         "\tverbose:      Print each filename as it is migrated\n"       \
270
271 #define SETDIRSTRIPE_USAGE                                              \
272         "               [--mdt-count|-c stripe_count>\n"                \
273         "               [--mdt-hash|-H mdt_hash]\n"                     \
274         "               [--mdt-index|-i mdt_index[,mdt_index,...]\n"    \
275         "               [--default|-D] [--mode|-o mode] <dir>\n"        \
276         "\tstripe_count: stripe count of the striped directory\n"       \
277         "\tmdt_index: MDT index of first stripe\n"                      \
278         "\tmdt_hash:  hash type of the striped directory. mdt types:\n" \
279         "       crush     CRUSH hash algorithm (default)\n" \
280         "       fnv_1a_64 FNV-1a hash algorithm\n"              \
281         "       all_char  sum of characters % MDT_COUNT (not recommended)\n" \
282         "\tdefault_stripe: set default dirstripe of the directory\n"    \
283         "\tmode: the file access permission of the directory (octal)\n" \
284         "To create dir with a foreign (free format) layout :\n" \
285         "setdirstripe|mkdir --foreign[=<foreign_type>] -x|-xattr <string> " \
286                 "[--mode|-o mode] [--flags <hex>] <dir>\n" \
287         "\tmode: the mode of the directory\n" \
288         "\tforeign_type: none or daos\n"
289
290 /**
291  * command_t mirror_cmdlist - lfs mirror commands.
292  */
293 command_t mirror_cmdlist[] = {
294         { .pc_name = "create", .pc_func = lfs_mirror_create,
295           .pc_help = "Create a mirrored file.\n"
296                 "usage: lfs mirror create "
297                 "<--mirror-count|-N[mirror_count]> "
298                 "[SETSTRIPE_OPTIONS] ... <filename|directory> ...\n"
299           MIRROR_CREATE_HELP },
300         { .pc_name = "delete", .pc_func = lfs_mirror_delete,
301           .pc_help = "delete a mirror from a file.\n"
302                 "usage: lfs mirror delete {--comp-id|-I <comp_id>|-p <pool>} <mirrored_file> ...\n"
303         },
304         { .pc_name = "extend", .pc_func = lfs_mirror_extend,
305           .pc_help = "Extend a mirrored file.\n"
306                 "usage: lfs mirror extend "
307                 "<--mirror-count|-N[mirror_count]> [--no-verify] "
308                 "[SETSTRIPE_OPTIONS|-f <victim_file>] ... <filename> ...\n"
309           MIRROR_EXTEND_HELP },
310         { .pc_name = "split", .pc_func = lfs_mirror_split,
311           .pc_help = "Split a mirrored file.\n"
312         "usage: lfs mirror split <--mirror-id <mirror_id> |\n"
313         "\t             <--component-id|-I <comp_id>|-p <pool>> [--destroy|-d]\n"
314         "\t             [-f <new_file>] <mirrored_file> ...\n"
315         "\tmirror_id:   The numerical unique identifier for a mirror. It\n"
316         "\t             can be fetched by lfs getstripe command.\n"
317         "\tcomp_id:     Unique component ID within a mirror.\n"
318         "\tpool:        Components on specified pool.\n"
319         "\tnew_file:    This option indicates the layout of the split\n"
320         "\t             mirror will be stored into. If not specified,\n"
321         "\t             a new file named <mirrored_file>.mirror~<mirror_id>\n"
322         "\t             will be used.\n" },
323         { .pc_name = "read", .pc_func = lfs_mirror_read,
324           .pc_help = "Read the content of a specified mirror of a file.\n"
325                 "usage: lfs mirror read <--mirror-id|-N <mirror_id> "
326                 "[--outfile|-o <output_file>] <mirrored_file>\n" },
327         { .pc_name = "write", .pc_func = lfs_mirror_write,
328           .pc_help = "Write to a specified mirror of a file.\n"
329                 "usage: lfs mirror write <--mirror-id|-N <mirror_id> "
330                 "[--inputfile|-i <input_file>] <mirrored_file>\n" },
331         { .pc_name = "copy", .pc_func = lfs_mirror_copy,
332           .pc_help = "Copy a specified mirror to other mirror(s) of a file.\n"
333                 "usage: lfs mirror copy <--read-mirror|-i <id0>> "
334                 "<--write-mirror|-o <id1,id2>> <mirrored_file>\n" },
335         { .pc_name = "resync", .pc_func = lfs_mirror_resync,
336           .pc_help = "Resynchronizes out-of-sync mirrored file(s).\n"
337                 "usage: lfs mirror resync [--only <mirror_id[,...]>] "
338                 "<mirrored file> [<mirrored file2>...]\n"},
339         { .pc_name = "verify", .pc_func = lfs_mirror_verify,
340           .pc_help = "Verify mirrored file(s).\n"
341                 "usage: lfs mirror verify "
342                 "[--only <mirror_id,mirror_id2[,...]>] "
343                 "[--verbose|-v] <mirrored_file> [<mirrored_file2> ...]\n"},
344         { .pc_name = "list-commands", .pc_func = lfs_mirror_list_commands,
345           .pc_help = "list commands supported by lfs mirror"},
346         { .pc_name = "help", .pc_func = Parser_help, .pc_help = "help" },
347         { .pc_name = "exit", .pc_func = Parser_quit, .pc_help = "quit" },
348         { .pc_name = "quit", .pc_func = Parser_quit, .pc_help = "quit" },
349         { .pc_help = NULL }
350 };
351
352 /**
353  * command_t pcc_cmdlist - lfs pcc commands.
354  */
355 command_t pcc_cmdlist[] = {
356         { .pc_name = "attach", .pc_func = lfs_pcc_attach,
357           .pc_help = "Attach given files to the Persistent Client Cache.\n"
358                 "usage: lfs pcc attach <--id|-i NUM> <file> ...\n"
359                 "\t-i: archive id for RW-PCC\n" },
360         { .pc_name = "attach_fid", .pc_func = lfs_pcc_attach_fid,
361           .pc_help = "Attach given files into PCC by FID(s).\n"
362                 "usage: lfs pcc attach_id <--id|-i NUM> <--mnt|-m mnt> "
363                 "<fid> ...\n"
364                 "\t-i: archive id for RW-PCC\n"
365                 "\t-m: Lustre mount point\n" },
366         { .pc_name = "state", .pc_func = lfs_pcc_state,
367           .pc_help = "Display the PCC state for given files.\n"
368                 "usage: lfs pcc state <file> ...\n" },
369         { .pc_name = "detach", .pc_func = lfs_pcc_detach,
370           .pc_help = "Detach given files from the Persistent Client Cache.\n"
371                 "usage: lfs pcc detach <file> ...\n" },
372         { .pc_name = "detach_fid", .pc_func = lfs_pcc_detach_fid,
373           .pc_help = "Detach given files from PCC by FID(s).\n"
374                 "usage: lfs pcc detach_fid <mntpath> <fid>...\n" },
375         { .pc_name = "list-commands", .pc_func = lfs_pcc_list_commands,
376           .pc_help = "list commands supported by lfs pcc"},
377         { .pc_name = "help", .pc_func = Parser_help, .pc_help = "help" },
378         { .pc_name = "exit", .pc_func = Parser_quit, .pc_help = "quit" },
379         { .pc_name = "quit", .pc_func = Parser_quit, .pc_help = "quit" },
380         { .pc_help = NULL }
381 };
382
383 /* all available commands */
384 command_t cmdlist[] = {
385         {"setstripe", lfs_setstripe, 0,
386          "To create a file with specified striping/composite layout, or\n"
387          "create/replace the default layout on an existing directory:\n"
388          SSM_CMD_COMMON("setstripe")
389          "                 [--mode <mode>]\n"
390          "                 <directory|filename>\n"
391          " or\n"
392          "To add component(s) to an existing composite file:\n"
393          SSM_CMD_COMMON("setstripe --component-add")
394          SSM_HELP_COMMON
395          "To totally delete the default striping from an existing directory:\n"
396          "usage: setstripe [--delete|-d] <directory>\n"
397          " or\n"
398          "To create a mirrored file or set s default mirror layout on a directory:\n"
399          "usage: setstripe {--mirror-count|-N}[mirror_count] [SETSTRIPE_OPTIONS] <directory|filename>\n"
400          " or\n"
401          "To delete the last component(s) from an existing composite file\n"
402          "(note that this will also delete any data in those components):\n"
403          "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
404          "                               [--component-flags|-F <comp_flags>]\n"
405          "                               <filename>\n"
406          "\tcomp_id:     Unique component ID to delete\n"
407          "\tcomp_flags:  'init' indicating all instantiated components\n"
408          "\t             '^init' indicating all uninstantiated components\n"
409          "\t-I and -F cannot be specified at the same time\n"
410          "To create a file with a foreign (free format) layout:\n"
411          "usage: setstripe --foreign[=<foreign_type>]\n"
412          "                 --xattr|-x <layout_string> [--flags <hex>]\n"
413          "                 [--mode <mode>] <filename>\n"},
414         {"getstripe", lfs_getstripe, 0,
415          "To list the layout pattern for a given file or files in a\n"
416          "directory or recursively for all files in a directory tree.\n"
417          "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
418          "                 [--stripe-count|-c] [--stripe-index|-i] [--fid|-F]\n"
419          "                 [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
420          "                 [--mdt-index|-m] [--recursive|-r] [--raw|-R]\n"
421          "                 [--layout|-L] [--generation|-g] [--yaml|-y]\n"
422          "                 [--component-id[=comp_id]|-I[comp_id]]\n"
423          "                 [--component-flags[=comp_flags]]\n"
424          "                 [--component-count]\n"
425          "                 [--extension-size|--ext-size|-z]\n"
426          "                 [--component-start[=[+-]comp_start]]\n"
427          "                 [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
428          "                 [[!] --mirror-index=[+-]<index> |\n"
429          "                  [!] --mirror-id=[+-]<id>]\n"
430          "                 <directory|filename> ..."},
431         {"setdirstripe", lfs_setdirstripe, 0,
432          "To create a striped directory on a specified MDT. This can only\n"
433          "be done on MDT0 with the right of administrator.\n"
434          "usage: setdirstripe [OPTION] <directory>\n"
435          SETDIRSTRIPE_USAGE},
436         {"getdirstripe", lfs_getdirstripe, 0,
437          "To list the layout pattern info for a given directory\n"
438          "or recursively for all directories in a directory tree.\n"
439          "usage: getdirstripe [--mdt-count|-c] [--mdt-index|-m|-i]\n"
440          "                    [--mdt-hash|-H] [--obd|-O <uuid>]\n"
441          "                    [--recursive|-r] [--yaml|-y]\n"
442          "                    [--verbose|-v] [--default|-D] <dir> ..."},
443         {"mkdir", lfs_setdirstripe, 0,
444          "To create a striped directory on a specified MDT. This can only\n"
445          "be done on MDT0 with the right of administrator.\n"
446          "usage: mkdir [OPTION] <directory>\n"
447          SETDIRSTRIPE_USAGE},
448         {"rm_entry", lfs_rmentry, 0,
449          "To remove the name entry of the remote directory. Note: This\n"
450          "command will only delete the name entry, i.e. the remote directory\n"
451          "will become inaccessable after this command. This can only be done\n"
452          "by the administrator\n"
453          "usage: rm_entry <dir>\n"},
454         {"pool_list", lfs_poollist, 0,
455          "List pools or pool OSTs\n"
456          "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
457         {"find", lfs_find, 0,
458          "find files matching given attributes recursively in directory tree.\n"
459          "usage: find <directory|filename> ...\n"
460          "     [[!] --atime|-A [+-]N[smhdwy]] [[!] --ctime|-C [+-]N[smhdwy]]\n"
461          "     [[!] --mtime|-M [+-]N[smhdwy]] [[!] --blocks|-b N]\n"
462          "     [[!] --newer[XY] <reference>]\n"
463          "     [--maxdepth|-D N] [[!] --mdt-index|--mdt|-m <uuid|index,...>]\n"
464          "     [[!] --name|-n <pattern>] [[!] --ost|-O <uuid|index,...>]\n"
465          "     [--print|-P] [--print0|-0] [[!] --size|-s [+-]N[bkMGTPE]]\n"
466          "     [[!] --stripe-count|-c [+-]<stripes>]\n"
467          "     [[!] --stripe-index|-i <index,...>]\n"
468          "     [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
469          "     [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
470          "     [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
471          "     [[!] --projid <projid>]\n"
472          "     [[!] --foreign[=<foreign_type>]]\n"
473          "     [[!] --layout|-L released,raid0,mdt]\n"
474          "     [[!] --foreign[=<foreign_type>]]\n"
475          "     [[!] --component-count [+-]<comp_cnt>]\n"
476          "     [[!] --component-start [+-]N[kMGTPE]]\n"
477          "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
478          "     [[!] --component-flags {init,stale,prefer,offline,nosync,extension}]\n"
479          "     [[!] --mirror-count|-N [+-]<n>]\n"
480          "     [[!] --mirror-state <[^]state>]\n"
481          "     [[!] --mdt-count|-T [+-]<stripes>]\n"
482          "     [[!] --mdt-hash|-H <hashtype>\n"
483          "     [[!] --mdt-index|-m <uuid|index,...>]\n"
484          "\t !: used before an option indicates 'NOT' requested attribute\n"
485          "\t -: used before a value indicates less than requested value\n"
486          "\t +: used before a value indicates more than requested value\n"
487          "\thashtype:   hash type of the striped directory.\n"
488          "\t            fnv_1a_64 FNV-1a hash algorithm\n"
489          "\t            all_char  sum of characters % MDT_COUNT\n"},
490         {"check", lfs_check, 0,
491          "Display the status of MGTs, MDTs or OSTs (as specified in the command)\n"
492          "or all the servers (MGTs, MDTs and OSTs).\n"
493          "usage: check <mgts|osts|mdts|all>"},
494         {"osts", lfs_osts, 0, "list OSTs connected to client "
495          "[for specified path only]\n" "usage: osts [path]"},
496         {"mdts", lfs_mdts, 0, "list MDTs connected to client "
497          "[for specified path only]\n" "usage: mdts [path]"},
498         {"df", lfs_df, 0,
499          "report filesystem disk space usage or inodes usage "
500          "of each MDS and all OSDs or a batch belonging to a specific pool.\n"
501          "Usage: df [--inodes|-i] [--human-readable|-h] [--lazy|-l]\n"
502          "          [--pool|-p <fsname>[.<pool>]] [path]"},
503         {"getname", lfs_getname, 0,
504          "list instances and specified mount points [for specified path only]\n"
505          "Usage: getname [--help|-h] [--instance|-i] [--fsname|-n] [path ...]"},
506 #ifdef HAVE_SYS_QUOTA_H
507         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
508          "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
509          "                -b <block-softlimit> -B <block-hardlimit>\n"
510          "                -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
511          "       setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
512          "                [--block-softlimit <block-softlimit>]\n"
513          "                [--block-hardlimit <block-hardlimit>]\n"
514          "                [--inode-softlimit <inode-softlimit>]\n"
515          "                [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
516          "       setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
517          "                [--block-grace 'notify'|<block-grace>]\n"
518          "                [--inode-grace 'notify'|<inode-grace>] <filesystem>\n"
519          "       setquota <-U|-G|-P>\n"
520          "                -b <block-softlimit> -B <block-hardlimit>\n"
521          "                -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
522          "       setquota <-U|--default-usr|-G|--default-grp|-P|--default-prj>\n"
523          "                [--block-softlimit <block-softlimit>]\n"
524          "                [--block-hardlimit <block-hardlimit>]\n"
525          "                [--inode-softlimit <inode-softlimit>]\n"
526          "                [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
527          "       setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
528          "                <-d|--default>\n"
529          "       -b can be used instead of --block-softlimit/--block-grace\n"
530          "       -B can be used instead of --block-hardlimit\n"
531          "       -i can be used instead of --inode-softlimit/--inode-grace\n"
532          "       -I can be used instead of --inode-hardlimit\n"
533          "       -d can be used instead of --default\n\n"
534          "Note: The total quota space will be split into many qunits and\n"
535          "      balanced over all server targets, the minimal qunit size is\n"
536          "      1M bytes for block space and 1K inodes for inode space.\n\n"
537          "      The maximum quota grace time is 2^48 - 1 seconds.\n\n"
538          "      Quota space rebalancing process will stop when this mininum\n"
539          "      value is reached. As a result, quota exceeded can be returned\n"
540          "      while many targets still have 1MB or 1K inodes of spare\n"
541          "      quota space.\n\n"
542          "      When setting the grace time, 'notify' can be used as grace to\n"
543          "      be notified after the quota is over soft limit but prevents\n"
544          "      the soft limit from becoming the hard limit."},
545         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
546          "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
547                        "<ost_idx>]\n"
548          "             [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
549          "       quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>\n"
550         "        quota [-q] [-v] [h] <-U|-G|-P> <filesystem>"},
551         {"project", lfs_project, 0,
552          "Change or list project attribute for specified file or directory.\n"
553          "usage: project [-d|-r] <file|directory...>\n"
554          "         list project ID and flags on file(s) or directories\n"
555          "       project [-p id] [-s] [-r] <file|directory...>\n"
556          "         set project ID and/or inherit flag for specified file(s) or directories\n"
557          "       project -c [-d|-r [-p id] [-0]] <file|directory...>\n"
558          "         check project ID and flags on file(s) or directories, print outliers\n"
559          "       project -C [-r] [-k] <file|directory...>\n"
560          "         clear the project inherit flag and ID on the file or directory\n"
561         },
562 #endif
563         {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
564          "usage: flushctx [-k] [mountpoint...]"},
565         {"changelog", lfs_changelog, 0,
566          "Show the metadata changes on an MDT."
567          "\nusage: changelog <mdtname> [startrec [endrec]]"},
568         {"changelog_clear", lfs_changelog_clear, 0,
569          "Indicate that old changelog records up to <endrec> are no longer of "
570          "interest to consumer <id>, allowing the system to free up space.\n"
571          "An <endrec> of 0 means all records.\n"
572          "usage: changelog_clear <mdtname> <id> <endrec>"},
573         {"fid2path", lfs_fid2path, 0,
574          "Resolve the full path(s) for given FID(s). For a specific hardlink "
575          "specify link number <linkno>.\n"
576          "usage: fid2path [-c] [--link|-l <linkno>] <fsname|root> <fid> ..."},
577         {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
578          "usage: path2fid [--parents] <path> ..."},
579         {"rmfid", lfs_rmfid, 0, "Remove file(s) by FID(s)\n"
580          "usage: rmfid <fsname|rootpath> <fid> ..."},
581         {"data_version", lfs_data_version, 0, "Display file data version for "
582          "a given path.\n" "usage: data_version [-n|-r|-w] <path>"},
583         {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
584          "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
585         {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
586          "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
587          "[--archived] [--lost] [--archive-id NUM] <file> ..."},
588         {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
589          "files.\n"
590          "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
591          "[--archived] [--lost] <file> ..."},
592         {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
593          "given files.\n" "usage: hsm_action <file> ..."},
594         {"hsm_archive", lfs_hsm_archive, 0,
595          "Archive file to external storage.\n"
596          "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
597          "<file> ..."},
598         {"hsm_restore", lfs_hsm_restore, 0,
599          "Restore file from external storage.\n"
600          "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
601         {"hsm_release", lfs_hsm_release, 0,
602          "Release files from Lustre.\n"
603          "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
604         {"hsm_remove", lfs_hsm_remove, 0,
605          "Remove file copy from external storage.\n"
606          "usage: hsm_remove [--filelist FILELIST] [--data DATA] "
607          "[--archive NUM]\n"
608          "                  (FILE [FILE ...] | "
609          "--mntpath MOUNTPATH FID [FID ...])\n"
610          "\n"
611          "Note: To remove an archived copy of a file already deleted from a "
612          "Lustre FS, the\n"
613          "--mntpath option and a list of FIDs must be specified"
614         },
615         {"hsm_cancel", lfs_hsm_cancel, 0,
616          "Cancel requests related to specified files.\n"
617          "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
618         {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
619          "usage: swap_layouts <path1> <path2>"},
620         {"migrate", lfs_setstripe_migrate, 0,
621          "migrate a directory between MDTs.\n"
622          "usage: migrate [--mdt-count|-c] <stripe_count>\n"
623          "               [--mdt-hash|-H] <hash_type>\n"
624          "               [--mdt-index|-m] <start_mdt_index>\n"
625          "               [--verbose|-v]\n"
626          "               <directory>\n"
627          "\tmdt:        MDTs to stripe over, if only one MDT is specified\n"
628          "                      it's the MDT index of first stripe\n"
629          "\tmdt_count:  number of MDTs to stripe a directory over\n"
630          "\tmdt_hash:   hash type of the striped directory. mdt types:\n"
631          "              all_char  (type 1)sum of characters % MDT_COUNT\n"
632          "              fnv_1a_64 (type 2)FNV-1a hash algorithm (default)\n"
633          "              crush     (type 3)CRUSH hash algorithm\n"
634          "\n"
635          "migrate file objects from one OST "
636          "layout\nto another (may be not safe with concurent writes).\n"
637          "usage: migrate  "
638          "[--stripe-count|-c] <stripe_count>\n"
639          "[--overstripe-count|-C] <stripe_count>\n"
640          "              [--stripe-index|-i] <start_ost_index>\n"
641          "              [--stripe-size|-S] <stripe_size>\n"
642          "              [--pool|-p] <pool_name>\n"
643          "              [--ost|-o] <ost_indices>\n"
644          "              [--block|-b]\n"
645          "              [--non-block|-n]\n"
646          "              [--non-direct|-D]\n"
647          "              <file|directory>\n"
648          "\tstripe_count:     number of OSTs to stripe a file over\n"
649          "\t              Using -C instead of -c allows overstriping, which\n"
650          "\t              will place more than one stripe per OST if\n"
651          "\t              stripe_count is greater than the number of OSTs\n"
652          "\tstripe_ost_index: index of the first OST to stripe a file over\n"
653          "\tstripe_size:      number of bytes to store before moving to the next OST\n"
654          "\tpool_name:        name of the predefined pool of OSTs\n"
655          "\tost_indices:      OSTs to stripe over, in order\n"
656          "\tblock:        Block file access during data migration (default)\n"
657          "\tnon-block:    Abort migrations if concurrent access is detected\n"
658          "\tnon-direct:       do not use direct I/O to copy file contents.\n"},
659         {"mv", lfs_mv, 0,
660          "To move directories between MDTs. This command is deprecated, "
661          "use \"migrate\" instead.\n"
662          "usage: mv <directory|filename> [--mdt-index|-m] <mdt_index> "
663          "[--verbose|-v]\n"},
664         {"ladvise", lfs_ladvise, 0,
665          "Provide servers with advice about access patterns for a file.\n"
666          "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
667          "               [--background|-b] [--unset|-u]\n\n"
668          "               {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
669          "               {[--mode|-m [READ,WRITE]}\n"
670          "               <file> ...\n"},
671         {"mirror", lfs_mirror, mirror_cmdlist,
672          "lfs commands used to manage files with mirrored components:\n"
673          "lfs mirror create - create a mirrored file or directory\n"
674          "lfs mirror extend - add mirror(s) to an existing file\n"
675          "lfs mirror split  - split a mirror from an existing mirrored file\n"
676          "lfs mirror resync - resynchronize out-of-sync mirrored file(s)\n"
677          "lfs mirror read   - read a mirror content of a mirrored file\n"
678          "lfs mirror write  - write to a mirror of a mirrored file\n"
679          "lfs mirror copy   - copy a mirror to other mirror(s) of a file\n"
680          "lfs mirror verify - verify mirrored file(s)\n"},
681         {"getsom", lfs_getsom, 0, "To list the SOM info for a given file.\n"
682          "usage: getsom [-s] [-b] [-f] <path>\n"
683          "\t-s: Only show the size value of the SOM data for a given file\n"
684          "\t-b: Only show the blocks value of the SOM data for a given file\n"
685          "\t-f: Only show the flags value of the SOM data for a given file\n"},
686         {"heat_get", lfs_heat_get, 0,
687          "To get heat of files.\n"
688          "usage: heat_get <file> ...\n"},
689         {"heat_set", lfs_heat_set, 0,
690          "To set heat flags of files.\n"
691          "usage: heat_set [--clear|-c] [--off|-o] [--on|-O] <file> ...\n"
692          "\t--clear|-c: Clear file heat for given files\n"
693          "\t--off|-o:   Turn off file heat for given files\n"
694          "\t--on|-O:    Turn on file heat for given files\n"},
695         {"pcc", lfs_pcc, pcc_cmdlist,
696          "lfs commands used to interact with PCC features:\n"
697          "lfs pcc attach - attach given files to Persistent Client Cache\n"
698          "lfs pcc attach_fid - attach given files into PCC by FID(s)\n"
699          "lfs pcc state  - display the PCC state for given files\n"
700          "lfs pcc detach - detach given files from Persistent Client Cache\n"
701          "lfs pcc detach_fid - detach given files from PCC by FID(s)\n"},
702         {"help", Parser_help, 0, "help"},
703         {"exit", Parser_quit, 0, "quit"},
704         {"quit", Parser_quit, 0, "quit"},
705         {"--version", Parser_version, 0,
706          "output build version of the utility and exit"},
707         {"--list-commands", lfs_list_commands, 0,
708          "list commands supported by the utility and exit"},
709         { 0, 0, 0, NULL }
710 };
711
712
713 static int check_hashtype(const char *hashtype)
714 {
715         int type_num = atoi(hashtype);
716         int i;
717
718         /* numeric hash type */
719         if (hashtype && strlen(hashtype) == 1 &&
720             (type_num > 0 && type_num < LMV_HASH_TYPE_MAX))
721                 return type_num;
722         /* string hash type */
723         for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
724                 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
725                         return i;
726
727         return 0;
728 }
729
730 static uint32_t check_foreign_type_name(const char *foreign_type_name)
731 {
732         uint32_t i;
733
734         for (i = 0; i < LU_FOREIGN_TYPE_UNKNOWN; i++) {
735                 if (lu_foreign_types[i].lft_name == NULL)
736                         break;
737                 if (strcmp(foreign_type_name,
738                            lu_foreign_types[i].lft_name) == 0)
739                         return lu_foreign_types[i].lft_type;
740         }
741
742         return LU_FOREIGN_TYPE_UNKNOWN;
743 }
744
745 static const char *error_loc = "syserror";
746
747 enum {
748         MIGRATION_NONBLOCK      = 0x0001,
749         MIGRATION_MIRROR        = 0x0002,
750         MIGRATION_NONDIRECT     = 0x0004,
751         MIGRATION_VERBOSE       = 0x0008,
752 };
753
754 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
755                                 struct llapi_layout *layout);
756
757 static int
758 migrate_open_files(const char *name, __u64 migration_flags,
759                    const struct llapi_stripe_param *param,
760                    struct llapi_layout *layout, int *fd_src, int *fd_tgt)
761 {
762         int                      fd = -1;
763         int                      fdv = -1;
764         int                      rflags;
765         int                      mdt_index;
766         int                      random_value;
767         char                     parent[PATH_MAX];
768         char                     volatile_file[PATH_MAX];
769         char                    *ptr;
770         int                      rc;
771         struct stat              st;
772         struct stat              stv;
773
774         if (param == NULL && layout == NULL) {
775                 error_loc = "layout information";
776                 return -EINVAL;
777         }
778
779         /* search for file directory pathname */
780         if (strlen(name) > sizeof(parent) - 1) {
781                 error_loc = "source file name";
782                 return -ERANGE;
783         }
784
785         strncpy(parent, name, sizeof(parent));
786         ptr = strrchr(parent, '/');
787         if (ptr == NULL) {
788                 if (getcwd(parent, sizeof(parent)) == NULL) {
789                         error_loc = "getcwd";
790                         return -errno;
791                 }
792         } else {
793                 if (ptr == parent) /* leading '/' */
794                         ptr = parent + 1;
795                 *ptr = '\0';
796         }
797
798         /* open file, direct io */
799         /* even if the file is only read, WR mode is nedeed to allow
800          * layout swap on fd */
801         rflags = O_RDWR;
802         if (!(migration_flags & MIGRATION_NONDIRECT))
803                 rflags |= O_DIRECT;
804         fd = open(name, rflags);
805         if (fd < 0) {
806                 rc = -errno;
807                 error_loc = "cannot open source file";
808                 return rc;
809         }
810
811         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
812         if (rc < 0) {
813                 error_loc = "cannot get MDT index";
814                 goto out;
815         }
816
817         do {
818                 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
819                 mode_t open_mode = S_IRUSR | S_IWUSR;
820
821                 random_value = random();
822                 rc = snprintf(volatile_file, sizeof(volatile_file),
823                               "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
824                               mdt_index, random_value);
825                 if (rc >= sizeof(volatile_file)) {
826                         rc = -ENAMETOOLONG;
827                         break;
828                 }
829
830                 /* create, open a volatile file, use caching (ie no directio) */
831                 if (layout)
832                         fdv = lfs_component_create(volatile_file, open_flags,
833                                                    open_mode, layout);
834                 else
835                         fdv = llapi_file_open_param(volatile_file, open_flags,
836                                                     open_mode, param);
837         } while (fdv < 0 && (rc = fdv) == -EEXIST);
838
839         if (rc < 0) {
840                 error_loc = "cannot create volatile file";
841                 goto out;
842         }
843
844         /* In case the MDT does not support creation of volatile files
845          * we should try to unlink it. */
846         (void)unlink(volatile_file);
847
848         /* Not-owner (root?) special case.
849          * Need to set owner/group of volatile file like original.
850          * This will allow to pass related check during layout_swap.
851          */
852         rc = fstat(fd, &st);
853         if (rc != 0) {
854                 rc = -errno;
855                 error_loc = "cannot stat source file";
856                 goto out;
857         }
858
859         rc = fstat(fdv, &stv);
860         if (rc != 0) {
861                 rc = -errno;
862                 error_loc = "cannot stat volatile";
863                 goto out;
864         }
865
866         if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
867                 rc = fchown(fdv, st.st_uid, st.st_gid);
868                 if (rc != 0) {
869                         rc = -errno;
870                         error_loc = "cannot change ownwership of volatile";
871                         goto out;
872                 }
873         }
874
875 out:
876         if (rc < 0) {
877                 if (fd > 0)
878                         close(fd);
879                 if (fdv > 0)
880                         close(fdv);
881         } else {
882                 *fd_src = fd;
883                 *fd_tgt = fdv;
884                 error_loc = NULL;
885         }
886         return rc;
887 }
888
889 static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int))
890 {
891         struct llapi_layout *layout;
892         size_t   buf_size = 4 * 1024 * 1024;
893         void    *buf = NULL;
894         ssize_t  rsize = -1;
895         ssize_t  wsize = 0;
896         size_t   rpos = 0;
897         size_t   wpos = 0;
898         off_t    bufoff = 0;
899         int      rc;
900
901         layout = llapi_layout_get_by_fd(fd_src, 0);
902         if (layout != NULL) {
903                 uint64_t stripe_size;
904
905                 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
906                 if (rc == 0)
907                         buf_size = stripe_size;
908
909                 llapi_layout_free(layout);
910         }
911
912         /* Use a page-aligned buffer for direct I/O */
913         rc = posix_memalign(&buf, getpagesize(), buf_size);
914         if (rc != 0)
915                 return -rc;
916
917         while (1) {
918                 /* read new data only if we have written all
919                  * previously read data */
920                 if (wpos == rpos) {
921                         if (check_file) {
922                                 rc = check_file(fd_src);
923                                 if (rc < 0)
924                                         break;
925                         }
926
927                         rsize = read(fd_src, buf, buf_size);
928                         if (rsize < 0) {
929                                 rc = -errno;
930                                 break;
931                         }
932                         rpos += rsize;
933                         bufoff = 0;
934                 }
935                 /* eof ? */
936                 if (rsize == 0)
937                         break;
938
939                 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
940                 if (wsize < 0) {
941                         rc = -errno;
942                         break;
943                 }
944                 wpos += wsize;
945                 bufoff += wsize;
946         }
947
948         if (rc == 0) {
949                 rc = fsync(fd_dst);
950                 if (rc < 0)
951                         rc = -errno;
952         }
953
954         free(buf);
955         return rc;
956 }
957
958 static int migrate_copy_timestamps(int fd, int fdv)
959 {
960         struct stat st;
961
962         if (fstat(fd, &st) == 0) {
963                 struct timeval tv[2] = {
964                         {.tv_sec = st.st_atime},
965                         {.tv_sec = st.st_mtime}
966                 };
967
968                 return futimes(fdv, tv);
969         }
970
971         return -errno;
972 }
973
974 static int migrate_block(int fd, int fdv)
975 {
976         __u64   dv1;
977         int     gid;
978         int     rc;
979         int     rc2;
980
981         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
982         if (rc < 0) {
983                 error_loc = "cannot get dataversion";
984                 return rc;
985         }
986
987         do
988                 gid = random();
989         while (gid == 0);
990
991         /* The grouplock blocks all concurrent accesses to the file.
992          * It has to be taken after llapi_get_data_version as it would
993          * block it too. */
994         rc = llapi_group_lock(fd, gid);
995         if (rc < 0) {
996                 error_loc = "cannot get group lock";
997                 return rc;
998         }
999
1000         rc = migrate_copy_data(fd, fdv, NULL);
1001         if (rc < 0) {
1002                 error_loc = "data copy failed";
1003                 goto out_unlock;
1004         }
1005
1006         /* Make sure we keep original atime/mtime values */
1007         rc = migrate_copy_timestamps(fd, fdv);
1008         if (rc < 0) {
1009                 error_loc = "timestamp copy failed";
1010                 goto out_unlock;
1011         }
1012
1013         /* swap layouts
1014          * for a migration we need to check data version on file did
1015          * not change.
1016          *
1017          * Pass in gid=0 since we already own grouplock. */
1018         rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
1019                                            SWAP_LAYOUTS_CHECK_DV1);
1020         if (rc == -EAGAIN) {
1021                 error_loc = "file changed";
1022                 goto out_unlock;
1023         } else if (rc < 0) {
1024                 error_loc = "cannot swap layout";
1025                 goto out_unlock;
1026         }
1027
1028 out_unlock:
1029         rc2 = llapi_group_unlock(fd, gid);
1030         if (rc2 < 0 && rc == 0) {
1031                 error_loc = "unlock group lock";
1032                 rc = rc2;
1033         }
1034
1035         return rc;
1036 }
1037
1038 /**
1039  * Internal helper for migrate_copy_data(). Check lease and report error if
1040  * need be.
1041  *
1042  * \param[in]  fd           File descriptor on which to check the lease.
1043  *
1044  * \retval 0       Migration can keep on going.
1045  * \retval -errno  Error occurred, abort migration.
1046  */
1047 static int check_lease(int fd)
1048 {
1049         int rc;
1050
1051         rc = llapi_lease_check(fd);
1052         if (rc > 0)
1053                 return 0; /* llapi_check_lease returns > 0 on success. */
1054
1055         return -EBUSY;
1056 }
1057
1058 static int migrate_nonblock(int fd, int fdv)
1059 {
1060         __u64   dv1;
1061         __u64   dv2;
1062         int     rc;
1063
1064         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
1065         if (rc < 0) {
1066                 error_loc = "cannot get data version";
1067                 return rc;
1068         }
1069
1070         rc = migrate_copy_data(fd, fdv, check_lease);
1071         if (rc < 0) {
1072                 error_loc = "data copy failed";
1073                 return rc;
1074         }
1075
1076         rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
1077         if (rc != 0) {
1078                 error_loc = "cannot get data version";
1079                 return rc;
1080         }
1081
1082         if (dv1 != dv2) {
1083                 rc = -EAGAIN;
1084                 error_loc = "source file changed";
1085                 return rc;
1086         }
1087
1088         /* Make sure we keep original atime/mtime values */
1089         rc = migrate_copy_timestamps(fd, fdv);
1090         if (rc < 0) {
1091                 error_loc = "timestamp copy failed";
1092                 return rc;
1093         }
1094
1095         return 0;
1096 }
1097
1098 static int lfs_component_set(char *fname, int comp_id,
1099                              __u32 flags, __u32 neg_flags)
1100 {
1101         __u32 ids[2];
1102         __u32 flags_array[2];
1103         size_t count = 0;
1104         int rc;
1105
1106         if (flags) {
1107                 ids[count] = comp_id;
1108                 flags_array[count] = flags;
1109                 ++count;
1110         }
1111
1112         if (neg_flags) {
1113                 if (neg_flags & LCME_FL_STALE) {
1114                         fprintf(stderr, "%s: cannot clear 'stale' flags from "
1115                                 "component. Please use lfs-mirror-resync(1) "
1116                                 "instead\n", progname);
1117                         return -EINVAL;
1118                 }
1119
1120                 ids[count] = comp_id;
1121                 flags_array[count] = neg_flags | LCME_FL_NEG;
1122                 ++count;
1123         }
1124
1125         rc = llapi_layout_file_comp_set(fname, ids, flags_array, count);
1126         if (rc) {
1127                 if (errno == EUCLEAN) {
1128                         rc = -errno;
1129                         fprintf(stderr,
1130                                 "%s: cannot set 'stale' flag on component '%#x' of the last non-stale mirror of '%s'\n",
1131                                 progname, comp_id, fname);
1132                 } else {
1133                         fprintf(stderr,
1134                                 "%s: cannot change the flags of component '%#x' of file '%s': %x / ^(%x)\n",
1135                                 progname, comp_id, fname, flags, neg_flags);
1136                 }
1137         }
1138
1139         return rc;
1140 }
1141
1142 static int lfs_component_del(char *fname, __u32 comp_id,
1143                              __u32 flags, __u32 neg_flags)
1144 {
1145         int     rc = 0;
1146
1147         if (flags && neg_flags)
1148                 return -EINVAL;
1149
1150         if (!flags && neg_flags)
1151                 flags = neg_flags | LCME_FL_NEG;
1152
1153         if ((flags && comp_id) || (!flags && !comp_id))
1154                 return -EINVAL;
1155
1156         if (flags) {
1157                 if (flags & ~LCME_KNOWN_FLAGS) {
1158                         fprintf(stderr,
1159                                 "%s setstripe: unknown flags %#x\n",
1160                                 progname, flags);
1161                         return -EINVAL;
1162                 }
1163         } else if (comp_id > LCME_ID_MAX) {
1164                 fprintf(stderr, "%s setstripe: invalid component id %u\n",
1165                         progname, comp_id);
1166                 return -EINVAL;
1167         }
1168
1169         rc = llapi_layout_file_comp_del(fname, comp_id, flags);
1170         if (rc)
1171                 fprintf(stderr,
1172                         "%s setstripe: cannot delete component %#x from '%s': %s\n",
1173                         progname, comp_id, fname, strerror(errno));
1174         return rc;
1175 }
1176
1177 static int lfs_component_add(char *fname, struct llapi_layout *layout)
1178 {
1179         int     rc;
1180
1181         if (layout == NULL)
1182                 return -EINVAL;
1183
1184         rc = llapi_layout_file_comp_add(fname, layout);
1185         if (rc)
1186                 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
1187                         fname, strerror(errno));
1188         return rc;
1189 }
1190
1191 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
1192                                 struct llapi_layout *layout)
1193 {
1194         struct stat     st;
1195         int     fd;
1196
1197         if (layout == NULL)
1198                 return -EINVAL;
1199
1200         fd = lstat(fname, &st);
1201         if (fd == 0 && S_ISDIR(st.st_mode))
1202                 open_flags = O_DIRECTORY | O_RDONLY;
1203
1204         fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
1205         if (fd < 0)
1206                 fprintf(stderr, "%s: cannot %s '%s': %s\n", progname,
1207                         S_ISDIR(st.st_mode) ?
1208                                 "set default composite layout for" :
1209                                 "create composite file",
1210                         fname, strerror(errno));
1211         return fd;
1212 }
1213
1214 static int lfs_migrate(char *name, __u64 migration_flags,
1215                        struct llapi_stripe_param *param,
1216                        struct llapi_layout *layout)
1217 {
1218         struct llapi_layout *existing;
1219         uint64_t dom_new, dom_cur;
1220         int fd = -1;
1221         int fdv = -1;
1222         int rc;
1223
1224         rc = migrate_open_files(name, migration_flags, param, layout,
1225                                 &fd, &fdv);
1226         if (rc < 0)
1227                 goto out;
1228
1229         rc = llapi_layout_dom_size(layout, &dom_new);
1230         if (rc) {
1231                 error_loc = "cannot get new layout DoM size";
1232                 goto out;
1233         }
1234         /* special case for migration to DOM layout*/
1235         existing = llapi_layout_get_by_fd(fd, 0);
1236         if (!existing) {
1237                 error_loc = "cannot get existing layout";
1238                 goto out;
1239         }
1240
1241         rc = llapi_layout_dom_size(existing, &dom_cur);
1242         if (rc) {
1243                 error_loc = "cannot get current layout DoM size";
1244                 goto out;
1245         }
1246
1247         /* if file has DoM layout already then migration is possible to
1248          * the new layout with the same DoM component via swap layout,
1249          * if new layout used bigger DOM size, then mirroring is used
1250          */
1251         if (dom_new > dom_cur) {
1252                 rc = lfs_migrate_to_dom(fd, fdv, name, migration_flags, param,
1253                                         layout);
1254                 if (rc)
1255                         error_loc = "cannot migrate to DOM layout";
1256                 goto out_closed;
1257         }
1258
1259         if (!(migration_flags & MIGRATION_NONBLOCK)) {
1260                 /* Blocking mode (forced if servers do not support file lease).
1261                  * It is also the default mode, since we cannot distinguish
1262                  * between a broken lease and a server that does not support
1263                  * atomic swap/close (LU-6785) */
1264                 rc = migrate_block(fd, fdv);
1265                 goto out;
1266         }
1267
1268         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1269         if (rc < 0) {
1270                 error_loc = "cannot get lease";
1271                 goto out;
1272         }
1273
1274         rc = migrate_nonblock(fd, fdv);
1275         if (rc < 0) {
1276                 llapi_lease_release(fd);
1277                 goto out;
1278         }
1279
1280         /* Atomically put lease, swap layouts and close.
1281          * for a migration we need to check data version on file did
1282          * not change. */
1283         rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
1284         if (rc < 0) {
1285                 error_loc = "cannot swap layout";
1286                 goto out;
1287         }
1288
1289 out:
1290         if (fd >= 0)
1291                 close(fd);
1292
1293         if (fdv >= 0)
1294                 close(fdv);
1295 out_closed:
1296         if (rc < 0)
1297                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1298                         progname, name, error_loc, strerror(-rc));
1299         else if (migration_flags & MIGRATION_VERBOSE)
1300                 printf("%s\n", name);
1301
1302         return rc;
1303 }
1304
1305 static int comp_str2flags(char *string, __u32 *flags, __u32 *neg_flags)
1306 {
1307         char *name;
1308
1309         if (string == NULL)
1310                 return -EINVAL;
1311
1312         *flags = 0;
1313         *neg_flags = 0;
1314         for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1315                 bool found = false;
1316                 int i;
1317
1318                 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1319                         __u32 comp_flag = comp_flags_table[i].cfn_flag;
1320                         const char *comp_name = comp_flags_table[i].cfn_name;
1321
1322                         if (strcmp(name, comp_name) == 0) {
1323                                 *flags |= comp_flag;
1324                                 found = true;
1325                         } else if (strncmp(name, "^", 1) == 0 &&
1326                                    strcmp(name + 1, comp_name) == 0) {
1327                                 *neg_flags |= comp_flag;
1328                                 found = true;
1329                         }
1330                 }
1331                 if (!found) {
1332                         llapi_printf(LLAPI_MSG_ERROR,
1333                                      "%s: component flag '%s' not supported\n",
1334                                      progname, name);
1335                         return -EINVAL;
1336                 }
1337         }
1338
1339         if (!*flags && !*neg_flags)
1340                 return -EINVAL;
1341
1342         /* don't allow to set and exclude the same flag */
1343         if (*flags & *neg_flags)
1344                 return -EINVAL;
1345
1346         return 0;
1347 }
1348
1349 static int mirror_str2state(char *string, __u16 *state, __u16 *neg_state)
1350 {
1351         if (string == NULL)
1352                 return -EINVAL;
1353
1354         *state = 0;
1355         *neg_state = 0;
1356
1357         if (strncmp(string, "^", 1) == 0) {
1358                 *neg_state = llapi_layout_string_flags(string + 1);
1359                 if (*neg_state != 0)
1360                         return 0;
1361         } else {
1362                 *state = llapi_layout_string_flags(string);
1363                 if (*state != 0)
1364                         return 0;
1365         }
1366
1367         llapi_printf(LLAPI_MSG_ERROR,
1368                      "%s: mirrored file state '%s' not supported\n",
1369                      progname, string);
1370         return -EINVAL;
1371 }
1372
1373 /**
1374  * struct mirror_args - Command-line arguments for mirror(s).
1375  * @m_count:  Number of mirrors to be created with this layout.
1376  * @m_flags:  Mirror level flags, only 'prefer' is supported.
1377  * @m_layout: Mirror layout.
1378  * @m_file:   A victim file. Its layout will be split and used as a mirror.
1379  * @m_next:   Point to the next node of the list.
1380  *
1381  * Command-line arguments for mirror(s) will be parsed and stored in
1382  * a linked list that consists of this structure.
1383  */
1384 struct mirror_args {
1385         __u32                   m_count;
1386         __u32                   m_flags;
1387         struct llapi_layout     *m_layout;
1388         const char              *m_file;
1389         struct mirror_args      *m_next;
1390 };
1391
1392 /**
1393  * enum mirror_flags - Flags for extending a mirrored file.
1394  * @MF_NO_VERIFY: Indicates not to verify the mirror(s) from victim file(s)
1395  *             in case the victim file(s) contains the same data as the
1396  *             original mirrored file.
1397  * @MF_DESTROY: Indicates to delete the mirror from the mirrored file.
1398  * @MF_COMP_ID: specified component id instead of mirror id
1399  *
1400  * Flags for extending a mirrored file.
1401  */
1402 enum mirror_flags {
1403         MF_NO_VERIFY    = 0x1,
1404         MF_DESTROY      = 0x2,
1405         MF_COMP_ID      = 0x4,
1406         MF_COMP_POOL    = 0x8,
1407 };
1408
1409 /**
1410  * mirror_create_sanity_check() - Check mirror list.
1411  * @list:  A linked list that stores the mirror arguments.
1412  *
1413  * This function does a sanity check on @list for creating
1414  * a mirrored file.
1415  *
1416  * Return: 0 on success or a negative error code on failure.
1417  */
1418 static int mirror_create_sanity_check(const char *fname,
1419                                       struct mirror_args *list)
1420 {
1421         int rc = 0;
1422         bool has_m_file = false;
1423         bool has_m_layout = false;
1424
1425         if (list == NULL)
1426                 return -EINVAL;
1427
1428         if (fname) {
1429                 struct llapi_layout *layout;
1430
1431                 layout = llapi_layout_get_by_path(fname, 0);
1432                 if (!layout) {
1433                         fprintf(stderr,
1434                                 "error: %s: file '%s' couldn't get layout\n",
1435                                 progname, fname);
1436                         return -ENODATA;
1437                 }
1438
1439                 rc = llapi_layout_sanity(layout, false, true);
1440
1441                 llapi_layout_free(layout);
1442
1443                 if (rc) {
1444                         llapi_layout_sanity_perror(rc);
1445                         return rc;
1446                 }
1447         }
1448
1449         while (list != NULL) {
1450                 if (list->m_file != NULL) {
1451                         has_m_file = true;
1452                         llapi_layout_free(list->m_layout);
1453
1454                         list->m_layout =
1455                                 llapi_layout_get_by_path(list->m_file, 0);
1456                         if (list->m_layout == NULL) {
1457                                 fprintf(stderr,
1458                                         "error: %s: file '%s' has no layout\n",
1459                                         progname, list->m_file);
1460                                 return -ENODATA;
1461                         }
1462                 } else {
1463                         has_m_layout = true;
1464                         if (list->m_layout == NULL) {
1465                                 fprintf(stderr, "error: %s: no mirror layout\n",
1466                                         progname);
1467                                 return -EINVAL;
1468                         }
1469                 }
1470
1471                 rc = llapi_layout_sanity(list->m_layout, false, true);
1472                 if (rc) {
1473                         llapi_layout_sanity_perror(rc);
1474                         return rc;
1475                 }
1476
1477                 list = list->m_next;
1478         }
1479
1480         if (has_m_file && has_m_layout) {
1481                 fprintf(stderr,
1482                         "error: %s: -f <victim_file> option should not be specified with setstripe options\n",
1483                         progname);
1484                 return -EINVAL;
1485         }
1486
1487         return 0;
1488 }
1489
1490 static int mirror_set_flags(struct llapi_layout *layout, void *cbdata)
1491 {
1492         __u32 mirror_flags = *(__u32 *)cbdata;
1493         uint32_t flags;
1494         int rc;
1495
1496         rc = llapi_layout_comp_flags_get(layout, &flags);
1497         if (rc < 0)
1498                 return rc;
1499
1500         if (!flags) {
1501                 rc = llapi_layout_comp_flags_set(layout, mirror_flags);
1502                 if (rc)
1503                         return rc;
1504         }
1505
1506         return LLAPI_LAYOUT_ITER_CONT;
1507 }
1508
1509 /**
1510  * mirror_create() - Create a mirrored file.
1511  * @fname:        The file to be created.
1512  * @mirror_list:  A linked list that stores the mirror arguments.
1513  *
1514  * This function creates a mirrored file @fname with the mirror(s)
1515  * from @mirror_list.
1516  *
1517  * Return: 0 on success or a negative error code on failure.
1518  */
1519 static int mirror_create(char *fname, struct mirror_args *mirror_list)
1520 {
1521         struct llapi_layout *layout = NULL;
1522         struct mirror_args *cur_mirror = NULL;
1523         uint16_t mirror_count = 0;
1524         int i = 0;
1525         int rc = 0;
1526
1527         rc = mirror_create_sanity_check(NULL, mirror_list);
1528         if (rc)
1529                 return rc;
1530
1531         cur_mirror = mirror_list;
1532         while (cur_mirror != NULL) {
1533                 rc = llapi_layout_comp_iterate(cur_mirror->m_layout,
1534                                                mirror_set_flags,
1535                                                &cur_mirror->m_flags);
1536                 if (rc) {
1537                         rc = -errno;
1538                         fprintf(stderr, "%s: failed to set mirror flags\n",
1539                                 progname);
1540                         goto error;
1541                 }
1542
1543                 for (i = 0; i < cur_mirror->m_count; i++) {
1544                         rc = llapi_layout_merge(&layout, cur_mirror->m_layout);
1545                         if (rc) {
1546                                 rc = -errno;
1547                                 fprintf(stderr, "error: %s: "
1548                                         "merge layout failed: %s\n",
1549                                         progname, strerror(errno));
1550                                 goto error;
1551                         }
1552                 }
1553                 mirror_count += cur_mirror->m_count;
1554                 cur_mirror = cur_mirror->m_next;
1555         }
1556
1557         if (layout == NULL) {
1558                 fprintf(stderr, "error: %s: layout is NULL\n", progname);
1559                 return -EINVAL;
1560         }
1561
1562         rc = llapi_layout_mirror_count_set(layout, mirror_count);
1563         if (rc) {
1564                 rc = -errno;
1565                 fprintf(stderr, "error: %s: set mirror count failed: %s\n",
1566                         progname, strerror(errno));
1567                 goto error;
1568         }
1569
1570         rc = lfs_component_create(fname, O_CREAT | O_WRONLY, 0666,
1571                                   layout);
1572         if (rc >= 0) {
1573                 close(rc);
1574                 rc = 0;
1575         }
1576
1577 error:
1578         llapi_layout_free(layout);
1579         return rc;
1580 }
1581
1582 /**
1583  * Compare files and check lease on @fd.
1584  *
1585  * \retval bytes number of bytes are the same
1586  */
1587 static ssize_t mirror_file_compare(int fd, int fdv)
1588 {
1589         const size_t buflen = 4 * 1024 * 1024; /* 4M */
1590         void *buf;
1591         ssize_t bytes_done = 0;
1592         ssize_t bytes_read = 0;
1593
1594         buf = malloc(buflen * 2);
1595         if (!buf)
1596                 return -ENOMEM;
1597
1598         while (1) {
1599                 if (!llapi_lease_check(fd)) {
1600                         bytes_done = -EBUSY;
1601                         break;
1602                 }
1603
1604                 bytes_read = read(fd, buf, buflen);
1605                 if (bytes_read <= 0)
1606                         break;
1607
1608                 if (bytes_read != read(fdv, buf + buflen, buflen))
1609                         break;
1610
1611                 /* XXX: should compute the checksum on each buffer and then
1612                  * compare checksum to avoid cache collision */
1613                 if (memcmp(buf, buf + buflen, bytes_read))
1614                         break;
1615
1616                 bytes_done += bytes_read;
1617         }
1618
1619         free(buf);
1620
1621         return bytes_done;
1622 }
1623
1624 static int mirror_extend_file(const char *fname, const char *victim_file,
1625                               enum mirror_flags mirror_flags)
1626 {
1627         int fd = -1;
1628         int fdv = -1;
1629         struct stat stbuf;
1630         struct stat stbuf_v;
1631         struct ll_ioc_lease *data = NULL;
1632         int rc;
1633
1634         fd = open(fname, O_RDWR);
1635         if (fd < 0) {
1636                 error_loc = "open source file";
1637                 rc = -errno;
1638                 goto out;
1639         }
1640
1641         fdv = open(victim_file, O_RDWR);
1642         if (fdv < 0) {
1643                 error_loc = "open target file";
1644                 rc = -errno;
1645                 goto out;
1646         }
1647
1648         if (fstat(fd, &stbuf) || fstat(fdv, &stbuf_v)) {
1649                 error_loc = "stat source or target file";
1650                 rc = -errno;
1651                 goto out;
1652         }
1653
1654         if (stbuf.st_dev != stbuf_v.st_dev) {
1655                 error_loc = "stat source and target file";
1656                 rc = -EXDEV;
1657                 goto out;
1658         }
1659
1660         /* mirrors should be of the same size */
1661         if (stbuf.st_size != stbuf_v.st_size) {
1662                 error_loc = "file sizes don't match";
1663                 rc = -EINVAL;
1664                 goto out;
1665         }
1666
1667         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1668         if (rc < 0) {
1669                 error_loc = "cannot get lease";
1670                 goto out;
1671         }
1672
1673         if (!(mirror_flags & MF_NO_VERIFY)) {
1674                 ssize_t ret;
1675                 /* mirrors should have the same contents */
1676                 ret = mirror_file_compare(fd, fdv);
1677                 if (ret != stbuf.st_size) {
1678                         error_loc = "file busy or contents don't match";
1679                         rc = ret < 0 ? ret : -EINVAL;
1680                         goto out;
1681                 }
1682         }
1683
1684         /* Get rid of caching pages from clients */
1685         rc = llapi_file_flush(fd);
1686         if (rc < 0) {
1687                 error_loc = "cannot get data version";
1688                 goto out;
1689         }
1690
1691         rc = llapi_file_flush(fdv);
1692         if (rc < 0) {
1693                 error_loc = "cannot get data version";
1694                 goto out;
1695
1696         }
1697
1698         /* Make sure we keep original atime/mtime values */
1699         rc = migrate_copy_timestamps(fd, fdv);
1700         if (rc < 0) {
1701                 error_loc = "cannot copy timestamp";
1702                 goto out;
1703         }
1704
1705         /* Atomically put lease, merge layouts and close. */
1706         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
1707         if (!data) {
1708                 error_loc = "memory allocation";
1709                 goto out;
1710         }
1711         data->lil_mode = LL_LEASE_UNLCK;
1712         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
1713         data->lil_count = 1;
1714         data->lil_ids[0] = fdv;
1715         rc = llapi_lease_set(fd, data);
1716         if (rc < 0) {
1717                 error_loc = "cannot merge layout";
1718                 goto out;
1719         } else if (rc == 0) {
1720                 rc = -EBUSY;
1721                 error_loc = "lost lease lock";
1722                 goto out;
1723         }
1724         rc = 0;
1725
1726 out:
1727         if (data)
1728                 free(data);
1729         if (fd >= 0)
1730                 close(fd);
1731         if (fdv >= 0)
1732                 close(fdv);
1733         if (!rc)
1734                 (void) unlink(victim_file);
1735         if (rc < 0)
1736                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1737                         progname, fname, error_loc, strerror(-rc));
1738         return rc;
1739 }
1740
1741 static int mirror_extend_layout(char *name, struct llapi_layout *layout)
1742 {
1743         struct ll_ioc_lease *data = NULL;
1744         int fd = -1;
1745         int fdv = -1;
1746         int rc;
1747
1748         rc = migrate_open_files(name, 0, NULL, layout, &fd, &fdv);
1749         if (rc < 0)
1750                 goto out;
1751
1752         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1753         if (rc < 0) {
1754                 error_loc = "cannot get lease";
1755                 goto out;
1756         }
1757
1758         rc = migrate_nonblock(fd, fdv);
1759         if (rc < 0) {
1760                 llapi_lease_release(fd);
1761                 goto out;
1762         }
1763
1764         /* Atomically put lease, merge layouts and close. */
1765         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
1766         if (!data) {
1767                 error_loc = "memory allocation";
1768                 goto out;
1769         }
1770         data->lil_mode = LL_LEASE_UNLCK;
1771         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
1772         data->lil_count = 1;
1773         data->lil_ids[0] = fdv;
1774         rc = llapi_lease_set(fd, data);
1775         if (rc < 0) {
1776                 error_loc = "cannot merge layout";
1777                 goto out;
1778         } else if (rc == 0) {
1779                 rc = -EBUSY;
1780                 error_loc = "lost lease lock";
1781                 goto out;
1782         }
1783         rc = 0;
1784
1785 out:
1786         if (data)
1787                 free(data);
1788         if (fd >= 0)
1789                 close(fd);
1790         if (fdv >= 0)
1791                 close(fdv);
1792         if (rc < 0)
1793                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1794                         progname, name, error_loc, strerror(-rc));
1795         return rc;
1796 }
1797
1798 static int mirror_extend(char *fname, struct mirror_args *mirror_list,
1799                          enum mirror_flags mirror_flags)
1800 {
1801         int rc;
1802
1803         rc = mirror_create_sanity_check(fname, mirror_list);
1804         if (rc)
1805                 return rc;
1806
1807         while (mirror_list) {
1808                 if (mirror_list->m_file != NULL) {
1809                         rc = mirror_extend_file(fname, mirror_list->m_file,
1810                                                 mirror_flags);
1811                 } else {
1812                         __u32 mirror_count = mirror_list->m_count;
1813
1814                         while (mirror_count > 0) {
1815                                 rc = mirror_extend_layout(fname,
1816                                                         mirror_list->m_layout);
1817                                 if (rc)
1818                                         break;
1819
1820                                 --mirror_count;
1821                         }
1822                 }
1823                 if (rc)
1824                         break;
1825
1826                 mirror_list = mirror_list->m_next;
1827         }
1828
1829         return rc;
1830 }
1831
1832 static int find_mirror_id(struct llapi_layout *layout, void *cbdata)
1833 {
1834         uint32_t id;
1835         int rc;
1836
1837         rc = llapi_layout_mirror_id_get(layout, &id);
1838         if (rc < 0)
1839                 return rc;
1840
1841         if ((__u16)id == *(__u16 *)cbdata)
1842                 return LLAPI_LAYOUT_ITER_STOP;
1843
1844         return LLAPI_LAYOUT_ITER_CONT;
1845 }
1846
1847 static int find_comp_id(struct llapi_layout *layout, void *cbdata)
1848 {
1849         uint32_t id;
1850         int rc;
1851
1852         rc = llapi_layout_comp_id_get(layout, &id);
1853         if (rc < 0)
1854                 return rc;
1855
1856         if (id == *(__u32 *)cbdata)
1857                 return LLAPI_LAYOUT_ITER_STOP;
1858
1859         return LLAPI_LAYOUT_ITER_CONT;
1860 }
1861
1862 struct pool_to_id_cbdata {
1863         const char *pool;
1864         __u32 id;
1865 };
1866 static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata)
1867 {
1868         char buf[LOV_MAXPOOLNAME + 1];
1869         struct pool_to_id_cbdata *d = (void *)cbdata;
1870         uint32_t id;
1871         int rc;
1872
1873         rc = llapi_layout_pool_name_get(layout, buf, sizeof(buf));
1874         if (rc < 0)
1875                 return rc;
1876         if (strcmp(d->pool, buf))
1877                 return LLAPI_LAYOUT_ITER_CONT;
1878
1879         rc = llapi_layout_mirror_id_get(layout, &id);
1880         if (rc < 0)
1881                 return rc;
1882         d->id = id;
1883
1884         return LLAPI_LAYOUT_ITER_STOP;
1885 }
1886
1887 struct collect_ids_data {
1888         __u16   *cid_ids;
1889         int     cid_count;
1890         __u16   cid_exclude;
1891 };
1892
1893 static int collect_mirror_id(struct llapi_layout *layout, void *cbdata)
1894 {
1895         struct collect_ids_data *cid = cbdata;
1896         uint32_t id;
1897         int rc;
1898
1899         rc = llapi_layout_mirror_id_get(layout, &id);
1900         if (rc < 0)
1901                 return rc;
1902
1903         if ((__u16)id != cid->cid_exclude) {
1904                 int i;
1905
1906                 for (i = 0; i < cid->cid_count; i++) {
1907                         /* already collected the mirror id */
1908                         if (id == cid->cid_ids[i])
1909                                 return LLAPI_LAYOUT_ITER_CONT;
1910                 }
1911                 cid->cid_ids[cid->cid_count] = id;
1912                 cid->cid_count++;
1913         }
1914
1915         return LLAPI_LAYOUT_ITER_CONT;
1916 }
1917
1918 /**
1919  * last_non_stale_mirror() - Check if a mirror is the last non-stale mirror.
1920  * @mirror_id: Mirror id to be checked.
1921  * @layout:    Mirror component list.
1922  *
1923  * This function checks if a mirror with specified @mirror_id is the last
1924  * non-stale mirror of a layout @layout.
1925  *
1926  * Return: true or false.
1927  */
1928 static inline
1929 bool last_non_stale_mirror(__u16 mirror_id, struct llapi_layout *layout)
1930 {
1931         __u16 mirror_ids[128] = { 0 };
1932         struct collect_ids_data cid = { .cid_ids = mirror_ids,
1933                                         .cid_count = 0,
1934                                         .cid_exclude = mirror_id, };
1935         int i;
1936
1937         llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
1938
1939         for (i = 0; i < cid.cid_count; i++) {
1940                 struct llapi_resync_comp comp_array[1024] = { { 0 } };
1941                 int comp_size = 0;
1942
1943                 comp_size = llapi_mirror_find_stale(layout, comp_array,
1944                                                     ARRAY_SIZE(comp_array),
1945                                                     &mirror_ids[i], 1);
1946                 if (comp_size == 0)
1947                         return false;
1948         }
1949
1950         return true;
1951 }
1952
1953 static int mirror_split(const char *fname, __u32 id, const char *pool,
1954                         enum mirror_flags mflags, const char *victim_file)
1955 {
1956         struct llapi_layout *layout;
1957         char parent[PATH_MAX];
1958         char victim[PATH_MAX];
1959         int flags = O_CREAT | O_EXCL | O_LOV_DELAY_CREATE | O_NOFOLLOW;
1960         char *ptr;
1961         struct ll_ioc_lease *data;
1962         uint16_t mirror_count;
1963         int mdt_index;
1964         int fd, fdv;
1965         int rc;
1966
1967         /* check fname contains mirror with mirror_id/comp_id */
1968         layout = llapi_layout_get_by_path(fname, 0);
1969         if (!layout) {
1970                 fprintf(stderr,
1971                         "error %s: file '%s' couldn't get layout\n",
1972                         progname, fname);
1973                 return -EINVAL;
1974         }
1975
1976         rc = llapi_layout_sanity(layout, false, true);
1977         if (rc) {
1978                 llapi_layout_sanity_perror(rc);
1979                 goto free_layout;
1980         }
1981
1982         rc = llapi_layout_mirror_count_get(layout, &mirror_count);
1983         if (rc) {
1984                 fprintf(stderr,
1985                         "error %s: file '%s' couldn't get mirror count\n",
1986                         progname, fname);
1987                 goto free_layout;
1988         }
1989         if (mirror_count < 2) {
1990                 fprintf(stderr,
1991                         "error %s: file '%s' has %d component, cannot split\n",
1992                         progname, fname, mirror_count);
1993                 goto free_layout;
1994         }
1995
1996         if (mflags & MF_COMP_POOL) {
1997                 struct pool_to_id_cbdata data = { .pool = pool };
1998
1999                 rc = llapi_layout_comp_iterate(layout, find_comp_id_by_pool,
2000                                                &data);
2001                 id = data.id;
2002         } else if (mflags & MF_COMP_ID) {
2003                 rc = llapi_layout_comp_iterate(layout, find_comp_id, &id);
2004                 id = mirror_id_of(id);
2005         } else {
2006                 rc = llapi_layout_comp_iterate(layout, find_mirror_id, &id);
2007         }
2008         if (rc < 0) {
2009                 fprintf(stderr, "error %s: failed to iterate layout of '%s'\n",
2010                         progname, fname);
2011                 goto free_layout;
2012         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
2013                 fprintf(stderr,
2014                      "error %s: file '%s' does not contain mirror with id %u\n",
2015                         progname, fname, id);
2016                 goto free_layout;
2017         }
2018
2019         fd = open(fname, O_RDWR);
2020         if (fd < 0) {
2021                 fprintf(stderr,
2022                         "error %s: open file '%s' failed: %s\n",
2023                         progname, fname, strerror(errno));
2024                 goto free_layout;
2025         }
2026
2027         /* get victim file directory pathname */
2028         if (strlen(fname) > sizeof(parent) - 1) {
2029                 fprintf(stderr, "error %s: file name of '%s' too long\n",
2030                         progname, fname);
2031                 rc = -ERANGE;
2032                 goto close_fd;
2033         }
2034         strncpy(parent, fname, sizeof(parent));
2035         ptr = strrchr(parent, '/');
2036         if (ptr == NULL) {
2037                 if (getcwd(parent, sizeof(parent)) == NULL) {
2038                         fprintf(stderr, "error %s: getcwd failed: %s\n",
2039                                 progname, strerror(errno));
2040                         rc = -errno;
2041                         goto close_fd;
2042                 }
2043         } else {
2044                 if (ptr == parent)
2045                         ptr = parent + 1;
2046                 *ptr = '\0';
2047         }
2048
2049         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
2050         if (rc < 0) {
2051                 fprintf(stderr, "%s: cannot get MDT index of '%s'\n",
2052                         progname, fname);
2053                 goto close_fd;
2054         }
2055
2056         if (victim_file == NULL) {
2057                 /* use a temp file to store the splitted layout */
2058                 if (mflags & MF_DESTROY) {
2059                         if (last_non_stale_mirror(id, layout)) {
2060                                 rc = -EUCLEAN;
2061                                 fprintf(stderr,
2062                                         "%s: cannot destroy the last non-stale mirror of file '%s'\n",
2063                                         progname, fname);
2064                                 goto close_fd;
2065                         }
2066
2067                         fdv = llapi_create_volatile_idx(parent, mdt_index,
2068                                                         O_LOV_DELAY_CREATE);
2069                 } else {
2070                         snprintf(victim, sizeof(victim), "%s.mirror~%u",
2071                                  fname, id);
2072                         fdv = open(victim, flags, S_IRUSR | S_IWUSR);
2073                 }
2074         } else {
2075                 /* user specified victim file */
2076                 fdv = open(victim_file, flags, S_IRUSR | S_IWUSR);
2077         }
2078
2079         if (fdv < 0) {
2080                 fprintf(stderr,
2081                         "error %s: create victim file failed: %s\n",
2082                         progname, strerror(errno));
2083                 goto close_fd;
2084         }
2085
2086         /* get lease lock of fname */
2087         rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
2088         if (rc < 0) {
2089                 fprintf(stderr,
2090                         "error %s: cannot get lease of file '%s': %d\n",
2091                         progname, fname, rc);
2092                 goto close_victim;
2093         }
2094
2095         /* Atomatically put lease, split layouts and close. */
2096         data = malloc(offsetof(typeof(*data), lil_ids[2]));
2097         if (!data) {
2098                 rc = -ENOMEM;
2099                 goto close_victim;
2100         }
2101
2102         data->lil_mode = LL_LEASE_UNLCK;
2103         data->lil_flags = LL_LEASE_LAYOUT_SPLIT;
2104         data->lil_count = 2;
2105         data->lil_ids[0] = fdv;
2106         data->lil_ids[1] = id;
2107         rc = llapi_lease_set(fd, data);
2108         if (rc <= 0) {
2109                 if (rc == 0) /* lost lease lock */
2110                         rc = -EBUSY;
2111                 fprintf(stderr,
2112                         "error %s: cannot split '%s': %s\n",
2113                         progname, fname, strerror(-rc));
2114         } else {
2115                 rc = 0;
2116         }
2117         free(data);
2118
2119 close_victim:
2120         close(fdv);
2121 close_fd:
2122         close(fd);
2123 free_layout:
2124         llapi_layout_free(layout);
2125         return rc;
2126 }
2127
2128 static inline
2129 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
2130                            __u16 *mirror_ids, int ids_nr);
2131
2132 static int lfs_migrate_to_dom(int fd, int fdv, char *name,
2133                               __u64 migration_flags,
2134                               struct llapi_stripe_param *param,
2135                               struct llapi_layout *layout)
2136 {
2137         struct ll_ioc_lease *data = NULL;
2138         int rc;
2139
2140         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
2141         if (rc < 0) {
2142                 error_loc = "cannot get lease";
2143                 goto out_close;
2144         }
2145
2146         /* Atomically put lease, merge layouts, resync and close. */
2147         data = calloc(1, offsetof(typeof(*data), lil_ids[1024]));
2148         if (!data) {
2149                 error_loc = "memory allocation";
2150                 goto out_close;
2151         }
2152         data->lil_mode = LL_LEASE_UNLCK;
2153         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
2154         data->lil_count = 1;
2155         data->lil_ids[0] = fdv;
2156         rc = llapi_lease_set(fd, data);
2157         if (rc < 0) {
2158                 error_loc = "cannot merge layout";
2159                 goto out_close;
2160         } else if (rc == 0) {
2161                 rc = -EBUSY;
2162                 error_loc = "lost lease lock";
2163                 goto out_close;
2164         }
2165         close(fd);
2166         close(fdv);
2167
2168         rc = lfs_mirror_resync_file(name, data, NULL, 0);
2169         if (rc) {
2170                 error_loc = "cannot resync file";
2171                 goto out;
2172         }
2173
2174         /* delete first mirror now */
2175         rc = mirror_split(name, 1, NULL, MF_DESTROY, NULL);
2176         if (rc < 0)
2177                 error_loc = "cannot delete old layout";
2178         goto out;
2179
2180 out_close:
2181         close(fd);
2182         close(fdv);
2183 out:
2184         if (rc < 0)
2185                 fprintf(stderr, "error: %s: %s: %s: %s\n",
2186                         progname, name, error_loc, strerror(-rc));
2187         else if (migration_flags & MIGRATION_VERBOSE)
2188                 printf("%s\n", name);
2189         if (data)
2190                 free(data);
2191         return rc;
2192 }
2193
2194 /**
2195  * Parse a string containing an target index list into an array of integers.
2196  *
2197  * The input string contains a comma delimited list of individual
2198  * indices and ranges, for example "1,2-4,7". Add the indices into the
2199  * \a tgts array and remove duplicates.
2200  *
2201  * \param[out] tgts             array to store indices in
2202  * \param[in] size              size of \a tgts array
2203  * \param[in] offset            starting index in \a tgts
2204  * \param[in] arg               string containing OST index list
2205  * \param[in/out] overstriping  index list may contain duplicates
2206  *
2207  * \retval positive    number of indices in \a tgts
2208  * \retval -EINVAL     unable to parse \a arg
2209  */
2210 static int parse_targets(__u32 *tgts, int size, int offset, char *arg,
2211                          unsigned long long *pattern)
2212 {
2213         int rc;
2214         int nr = offset;
2215         int slots = size - offset;
2216         char *ptr = NULL;
2217         bool overstriped = false;
2218         bool end_of_loop;
2219
2220         if (arg == NULL)
2221                 return -EINVAL;
2222
2223         end_of_loop = false;
2224         while (!end_of_loop) {
2225                 int start_index = 0;
2226                 int end_index = 0;
2227                 int i;
2228                 char *endptr = NULL;
2229
2230                 rc = -EINVAL;
2231
2232                 ptr = strchrnul(arg, ',');
2233
2234                 end_of_loop = *ptr == '\0';
2235                 *ptr = '\0';
2236
2237                 start_index = strtol(arg, &endptr, 0);
2238                 if (endptr == arg) /* no data at all */
2239                         break;
2240                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
2241                         break;
2242
2243                 end_index = start_index;
2244                 if (*endptr == '-') {
2245                         end_index = strtol(endptr + 1, &endptr, 0);
2246                         if (*endptr != '\0')
2247                                 break;
2248                         if (end_index < start_index)
2249                                 break;
2250                 }
2251
2252                 for (i = start_index; i <= end_index && slots > 0; i++) {
2253                         int j;
2254
2255                         /* remove duplicate */
2256                         for (j = 0; j < offset; j++) {
2257                                 if (tgts[j] == i && pattern &&
2258                                     *pattern == LLAPI_LAYOUT_OVERSTRIPING)
2259                                         overstriped = true;
2260                                 else if (tgts[j] == i)
2261                                         return -EINVAL;
2262                         }
2263
2264                         j = offset;
2265
2266                         if (j == offset) { /* check complete */
2267                                 tgts[nr++] = i;
2268                                 --slots;
2269                         }
2270                 }
2271
2272                 if (slots == 0 && i < end_index)
2273                         break;
2274
2275                 *ptr = ',';
2276                 arg = ++ptr;
2277                 offset = nr;
2278                 rc = 0;
2279         }
2280         if (!end_of_loop && ptr != NULL)
2281                 *ptr = ',';
2282
2283         if (!overstriped && pattern)
2284                 *pattern = LLAPI_LAYOUT_DEFAULT;
2285
2286         return rc < 0 ? rc : nr;
2287 }
2288
2289 struct lfs_setstripe_args {
2290         unsigned long long       lsa_comp_end;
2291         unsigned long long       lsa_stripe_size;
2292         unsigned long long       lsa_extension_size;
2293         long long                lsa_stripe_count;
2294         long long                lsa_stripe_off;
2295         __u32                    lsa_comp_flags;
2296         __u32                    lsa_comp_neg_flags;
2297         unsigned long long       lsa_pattern;
2298         unsigned int             lsa_mirror_count;
2299         int                      lsa_nr_tgts;
2300         bool                     lsa_first_comp;
2301         bool                     lsa_extension_comp;
2302         __u32                   *lsa_tgts;
2303         char                    *lsa_pool_name;
2304 };
2305
2306 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
2307 {
2308         unsigned int mirror_count = lsa->lsa_mirror_count;
2309         bool first_comp = lsa->lsa_first_comp;
2310
2311         memset(lsa, 0, sizeof(*lsa));
2312
2313         lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
2314         lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
2315         lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2316         lsa->lsa_pattern = LLAPI_LAYOUT_RAID0;
2317         lsa->lsa_pool_name = NULL;
2318
2319         lsa->lsa_mirror_count = mirror_count;
2320         lsa->lsa_first_comp = first_comp;
2321 }
2322
2323 /**
2324  * setstripe_args_init_inherit() - Initialize and inherit stripe options.
2325  * @lsa: Stripe options to be initialized and inherited.
2326  *
2327  * This function initializes stripe options in @lsa and inherit
2328  * stripe_size, stripe_count and OST pool_name options.
2329  *
2330  * Return: void.
2331  */
2332 static inline void setstripe_args_init_inherit(struct lfs_setstripe_args *lsa)
2333 {
2334         unsigned long long stripe_size;
2335         long long stripe_count;
2336         char *pool_name = NULL;
2337
2338         stripe_size = lsa->lsa_stripe_size;
2339         stripe_count = lsa->lsa_stripe_count;
2340         pool_name = lsa->lsa_pool_name;
2341
2342         setstripe_args_init(lsa);
2343
2344         lsa->lsa_stripe_size = stripe_size;
2345         lsa->lsa_stripe_count = stripe_count;
2346         lsa->lsa_pool_name = pool_name;
2347 }
2348
2349 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
2350 {
2351         return (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT ||
2352                 lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ||
2353                 lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
2354                 lsa->lsa_pattern != LLAPI_LAYOUT_RAID0 ||
2355                 lsa->lsa_comp_end != 0);
2356 }
2357
2358 /**
2359  * comp_args_to_layout() - Create or extend a composite layout.
2360  * @composite:       Pointer to the composite layout.
2361  * @lsa:             Stripe options for the new component.
2362  *
2363  * This function creates or extends a composite layout by adding a new
2364  * component with stripe options from @lsa.
2365  *
2366  * Return: 0 on success or an error code on failure.
2367  */
2368 static int comp_args_to_layout(struct llapi_layout **composite,
2369                                struct lfs_setstripe_args *lsa,
2370                                bool set_extent)
2371 {
2372         struct llapi_layout *layout = *composite;
2373         uint64_t prev_end = 0;
2374         uint64_t size;
2375         int i = 0, rc;
2376
2377 new_comp:
2378         if (layout == NULL) {
2379                 layout = llapi_layout_alloc();
2380                 if (layout == NULL) {
2381                         fprintf(stderr, "Alloc llapi_layout failed. %s\n",
2382                                 strerror(errno));
2383                         errno = ENOMEM;
2384                         return -1;
2385                 }
2386                 *composite = layout;
2387                 lsa->lsa_first_comp = true;
2388         } else {
2389                 uint64_t start;
2390
2391                 /* Get current component extent, current component
2392                  * must be the tail component. */
2393                 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
2394                 if (rc) {
2395                         fprintf(stderr, "Get comp extent failed. %s\n",
2396                                 strerror(errno));
2397                         return rc;
2398                 }
2399
2400                 if (lsa->lsa_first_comp)
2401                         prev_end = 0;
2402
2403                 if (lsa->lsa_first_comp)
2404                         rc = llapi_layout_add_first_comp(layout);
2405                 else
2406                         rc = llapi_layout_comp_add(layout);
2407                 if (rc) {
2408                         fprintf(stderr, "Add component failed. %s\n",
2409                                 strerror(errno));
2410                         return rc;
2411                 }
2412         }
2413
2414         rc = llapi_layout_comp_flags_set(layout, lsa->lsa_comp_flags);
2415         if (rc) {
2416                 fprintf(stderr, "Set flags 0x%x failed: %s\n",
2417                         lsa->lsa_comp_flags, strerror(errno));
2418                 return rc;
2419         }
2420
2421         if (set_extent) {
2422                 uint64_t comp_end = lsa->lsa_comp_end;
2423
2424                 /* The extendable component is 0-length, so it can be removed
2425                  * if there is insufficient space to extend it. */
2426                 if (lsa->lsa_extension_comp)
2427                         comp_end = prev_end;
2428
2429                 rc = llapi_layout_comp_extent_set(layout, prev_end,
2430                                                   comp_end);
2431                 if (rc) {
2432                         fprintf(stderr, "Set extent [%lu, %lu) failed. %s\n",
2433                                 prev_end, comp_end, strerror(errno));
2434                         return rc;
2435                 }
2436         }
2437         /* reset lsa_first_comp */
2438         lsa->lsa_first_comp = false;
2439
2440         /* Data-on-MDT component setting */
2441         if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
2442                 /* In case of Data-on-MDT patterns the only extra option
2443                  * applicable is stripe size option. */
2444                 if (lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
2445                         fprintf(stderr, "Option 'stripe-count' can't be "
2446                                 "specified with Data-on-MDT component: %lld\n",
2447                                 lsa->lsa_stripe_count);
2448                         errno = EINVAL;
2449                         return -1;
2450                 }
2451                 if (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT) {
2452                         fprintf(stderr, "Option 'stripe-size' can't be "
2453                                 "specified with Data-on-MDT component: %llu\n",
2454                                 lsa->lsa_stripe_size);
2455                         errno = EINVAL;
2456                         return -1;
2457                 }
2458                 if (lsa->lsa_nr_tgts != 0) {
2459                         fprintf(stderr, "Option 'ost-list' can't be specified "
2460                                 "with Data-on-MDT component: '%i'\n",
2461                                 lsa->lsa_nr_tgts);
2462                         errno = EINVAL;
2463                         return -1;
2464                 }
2465                 if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
2466                         fprintf(stderr, "Option 'stripe-offset' can't be "
2467                                 "specified with Data-on-MDT component: %lld\n",
2468                                 lsa->lsa_stripe_off);
2469                         errno = EINVAL;
2470                         return -1;
2471                 }
2472                 if (lsa->lsa_pool_name != 0) {
2473                         fprintf(stderr, "Option 'pool' can't be specified "
2474                                 "with Data-on-MDT component: '%s'\n",
2475                                 lsa->lsa_pool_name);
2476                         errno = EINVAL;
2477                         return -1;
2478                 }
2479
2480                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
2481                 if (rc) {
2482                         fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
2483                                 lsa->lsa_pattern,
2484                                 strerror(errno));
2485                         return rc;
2486                 }
2487                 /* Data-on-MDT component has always single stripe up to end */
2488                 lsa->lsa_stripe_size = lsa->lsa_comp_end;
2489         } else if (lsa->lsa_pattern == LLAPI_LAYOUT_OVERSTRIPING) {
2490                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
2491                 if (rc) {
2492                         fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
2493                                 lsa->lsa_pattern,
2494                                 strerror(errno));
2495                         return rc;
2496                 }
2497         }
2498
2499         size = lsa->lsa_comp_flags & LCME_FL_EXTENSION ?
2500                 lsa->lsa_extension_size : lsa->lsa_stripe_size;
2501
2502         if (lsa->lsa_comp_flags & LCME_FL_EXTENSION)
2503                 rc = llapi_layout_extension_size_set(layout, size);
2504         else
2505                 rc = llapi_layout_stripe_size_set(layout, size);
2506
2507         if (rc) {
2508                 fprintf(stderr, "Set stripe size %lu failed: %s\n",
2509                         size, strerror(errno));
2510                 return rc;
2511         }
2512
2513         rc = llapi_layout_stripe_count_set(layout, lsa->lsa_stripe_count);
2514         if (rc) {
2515                 fprintf(stderr, "Set stripe count %lld failed: %s\n",
2516                         lsa->lsa_stripe_count, strerror(errno));
2517                 return rc;
2518         }
2519
2520         if (lsa->lsa_pool_name != NULL) {
2521                 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
2522                 if (rc) {
2523                         fprintf(stderr, "Set pool name: %s failed. %s\n",
2524                                 lsa->lsa_pool_name, strerror(errno));
2525                         return rc;
2526                 }
2527         } else {
2528                 rc = llapi_layout_pool_name_set(layout, "");
2529                 if (rc) {
2530                         fprintf(stderr, "Clear pool name failed: %s\n",
2531                                 strerror(errno));
2532                         return rc;
2533                 }
2534         }
2535
2536         if (lsa->lsa_nr_tgts > 0) {
2537                 if (lsa->lsa_stripe_count > 0 &&
2538                     lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
2539                     lsa->lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
2540                     lsa->lsa_nr_tgts != lsa->lsa_stripe_count) {
2541                         fprintf(stderr, "stripe_count(%lld) != nr_tgts(%d)\n",
2542                                 lsa->lsa_stripe_count,
2543                                 lsa->lsa_nr_tgts);
2544                         errno = EINVAL;
2545                         return -1;
2546                 }
2547                 for (i = 0; i < lsa->lsa_nr_tgts; i++) {
2548                         rc = llapi_layout_ost_index_set(layout, i,
2549                                                         lsa->lsa_tgts[i]);
2550                         if (rc)
2551                                 break;
2552                 }
2553         } else if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT &&
2554                    lsa->lsa_stripe_off != -1) {
2555                 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
2556         }
2557         if (rc) {
2558                 fprintf(stderr, "Set ost index %d failed. %s\n",
2559                         i, strerror(errno));
2560                 return rc;
2561         }
2562
2563         /* Create the second, virtual component of extension space */
2564         if (lsa->lsa_extension_comp) {
2565                 lsa->lsa_comp_flags |= LCME_FL_EXTENSION;
2566                 lsa->lsa_extension_comp = false;
2567                 goto new_comp;
2568         }
2569
2570         return rc;
2571 }
2572
2573 static int build_component(struct llapi_layout **layout,
2574                            struct lfs_setstripe_args *lsa, bool set_extent)
2575 {
2576         int rc;
2577
2578         rc = comp_args_to_layout(layout, lsa, set_extent);
2579         if (rc)
2580                 return rc;
2581
2582         if (lsa->lsa_mirror_count > 0) {
2583                 rc = llapi_layout_mirror_count_set(*layout,
2584                                                    lsa->lsa_mirror_count);
2585                 if (rc)
2586                         return rc;
2587
2588                 rc = llapi_layout_flags_set(*layout, LCM_FL_RDONLY);
2589                 if (rc)
2590                         return rc;
2591                 lsa->lsa_mirror_count = 0;
2592         }
2593
2594         return rc;
2595 }
2596
2597 static int build_layout_from_yaml_node(struct cYAML *node,
2598                                        struct llapi_layout **layout,
2599                                        struct lfs_setstripe_args *lsa,
2600                                        __u32 *osts)
2601 {
2602         char *string;
2603         int rc = 0;
2604
2605         while (node) {
2606                 if (node->cy_type == CYAML_TYPE_OBJECT) {
2607                         /* go deep to sub blocks */
2608                         rc = build_layout_from_yaml_node(node->cy_child, layout,
2609                                                          lsa, osts);
2610                         if (rc)
2611                                 return rc;
2612                 } else {
2613                         if (node->cy_string == NULL)
2614                                 return -EINVAL;
2615
2616                         string = node->cy_string;
2617                         /* skip leading lmm_ if present, to simplify parsing */
2618                         if (strncmp(string, "lmm_", 4) == 0)
2619                                 string += 4;
2620
2621                         if (node->cy_type == CYAML_TYPE_STRING) {
2622                                 if (!strcmp(string, "lcme_extent.e_end")) {
2623                                         if (!strcmp(node->cy_valuestring, "EOF") ||
2624                                             !strcmp(node->cy_valuestring, "eof"))
2625                                                 lsa->lsa_comp_end = LUSTRE_EOF;
2626                                 } else if (!strcmp(string, "pool")) {
2627                                         lsa->lsa_pool_name = node->cy_valuestring;
2628                                 } else if (!strcmp(string, "pattern")) {
2629                                         if (!strcmp(node->cy_valuestring, "mdt"))
2630                                                 lsa->lsa_pattern = LLAPI_LAYOUT_MDT;
2631                                         if (!strcmp(node->cy_valuestring,
2632                                                     "raid0,overstriped"))
2633                                                 lsa->lsa_pattern =
2634                                                         LLAPI_LAYOUT_OVERSTRIPING;
2635                                 } else if (!strcmp(string, "lcme_flags")) {
2636                                         rc = comp_str2flags(node->cy_valuestring,
2637                                                             &lsa->lsa_comp_flags,
2638                                                             &lsa->lsa_comp_neg_flags);
2639                                         if (rc)
2640                                                 return rc;
2641                                         /* Only template flags have meaning in
2642                                          * the layout for a new file
2643                                          */
2644                                         lsa->lsa_comp_flags &= LCME_TEMPLATE_FLAGS;
2645                                 }
2646                         } else if (node->cy_type == CYAML_TYPE_NUMBER) {
2647                                 if (!strcmp(string, "lcm_mirror_count")) {
2648                                         lsa->lsa_mirror_count = node->cy_valueint;
2649                                 } else if (!strcmp(string, "lcme_extent.e_start")) {
2650                                         if (node->cy_valueint != 0 || *layout != NULL) {
2651                                                 rc = build_component(layout, lsa, true);
2652                                                 if (rc)
2653                                                         return rc;
2654                                         }
2655
2656                                         if (node->cy_valueint == 0)
2657                                                 lsa->lsa_first_comp = true;
2658
2659                                         /* initialize lsa */
2660                                         setstripe_args_init(lsa);
2661                                         lsa->lsa_tgts = osts;
2662                                 } else if (!strcmp(string, "lcme_extent.e_end")) {
2663                                         if (node->cy_valueint == -1)
2664                                                 lsa->lsa_comp_end = LUSTRE_EOF;
2665                                         else
2666                                                 lsa->lsa_comp_end = node->cy_valueint;
2667                                 } else if (!strcmp(string, "stripe_count")) {
2668                                         lsa->lsa_stripe_count = node->cy_valueint;
2669                                 } else if (!strcmp(string, "stripe_size")) {
2670                                         lsa->lsa_stripe_size = node->cy_valueint;
2671                                 } else if (!strcmp(string, "stripe_offset")) {
2672                                         lsa->lsa_stripe_off = node->cy_valueint;
2673                                 } else if (!strcmp(string, "l_ost_idx")) {
2674                                         osts[lsa->lsa_nr_tgts] = node->cy_valueint;
2675                                         lsa->lsa_nr_tgts++;
2676                                 }
2677                         }
2678                 }
2679                 node = node->cy_next;
2680         }
2681
2682         return rc;
2683 }
2684
2685 static int lfs_comp_create_from_yaml(char *template,
2686                                      struct llapi_layout **layout,
2687                                      struct lfs_setstripe_args *lsa,
2688                                      __u32 *osts)
2689 {
2690         struct cYAML *tree = NULL, *err_rc = NULL;
2691         int rc = 0;
2692
2693         tree = cYAML_build_tree(template, NULL, 0, &err_rc, false);
2694         if (!tree) {
2695                 fprintf(stderr, "%s: cannot parse YAML file %s\n",
2696                         progname, template);
2697                 cYAML_build_error(-EINVAL, -1, "yaml", "from comp yaml",
2698                                   "can't parse", &err_rc);
2699                 cYAML_print_tree2file(stderr, err_rc);
2700                 cYAML_free_tree(err_rc);
2701                 rc = -EINVAL;
2702                 goto err;
2703         }
2704
2705         /* initialize lsa for plain file */
2706         setstripe_args_init(lsa);
2707         lsa->lsa_tgts = osts;
2708
2709         rc = build_layout_from_yaml_node(tree, layout, lsa, osts);
2710         if (rc) {
2711                 fprintf(stderr, "%s: cannot build layout from YAML file %s.\n",
2712                         progname, template);
2713                 goto err;
2714         } else {
2715                 rc = build_component(layout, lsa, *layout != NULL);
2716         }
2717         /* clean clean lsa */
2718         setstripe_args_init(lsa);
2719
2720 err:
2721         if (tree)
2722                 cYAML_free_tree(tree);
2723         return rc;
2724 }
2725
2726 /**
2727  * Get the extension size from the next (SEL) component and extend the
2728  * current component on it. The start of the next component is to be
2729  * adjusted as well.
2730  *
2731  * \param[in] layout    the current layout
2732  * \param[in] start     the start of the current component
2733  * \param[in,out] end   the end of the current component
2734  * \param[in] offset    the offset to adjust the end position to instead of
2735  *                      extension size
2736  *
2737  * \retval 0            - extended successfully
2738  * \retval < 0          - error
2739  */
2740 static int layout_extend_comp(struct llapi_layout *layout,
2741                               uint64_t start, uint64_t *end,
2742                               uint64_t offset)
2743 {
2744         uint64_t size, next_start, next_end;
2745         int rc;
2746
2747         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
2748         if (rc < 0) {
2749                 fprintf(stderr, "%s setstripe: cannot move component cursor: "
2750                         "%s\n", progname, strerror(errno));
2751                 return rc;
2752         }
2753
2754         /* Even if the @size will not be used below, this will fail if
2755          * this is not a SEL component - a good confirmation we are
2756          * working on right components. */
2757         rc = llapi_layout_extension_size_get(layout, &size);
2758         if (rc < 0) {
2759                 fprintf(stderr, "%s setstripe: cannot get component ext size: "
2760                         "%s\n", progname, strerror(errno));
2761                 return rc;
2762         }
2763
2764         rc = llapi_layout_comp_extent_get(layout, &next_start, &next_end);
2765         if (rc) {
2766                 fprintf(stderr, "%s setstripe: cannot get extent: %s\n",
2767                         progname, strerror(errno));
2768                 return rc;
2769         }
2770
2771         next_start += offset ?: size;
2772         rc = llapi_layout_comp_extent_set(layout, next_start, next_end);
2773         if (rc) {
2774                 fprintf(stderr, "%s setstripe: cannot set extent: %s\n",
2775                         progname, strerror(errno));
2776                 return rc;
2777         }
2778
2779         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_PREV);
2780         if (rc < 0) {
2781                 fprintf(stderr, "%s setstripe: cannot move component cursor: "
2782                         "%s\n", progname, strerror(errno));
2783                 return rc;
2784         }
2785
2786         *end += offset ?: size;
2787         rc = llapi_layout_comp_extent_set(layout, start, *end);
2788         if (rc) {
2789                 fprintf(stderr, "%s setstripe: cannot set extent: %s\n",
2790                         progname, strerror(errno));
2791                 return rc;
2792         }
2793
2794         return 0;
2795 }
2796
2797 /**
2798  * In 'lfs setstripe --component-add' mode, we need to fetch the extent
2799  * end of the last component in the existing file, and adjust the
2800  * first extent start of the components to be added accordingly.
2801  *
2802  * In the create mode, we need to check if the first component is an extendable
2803  * SEL component and extend its length to the extension size (first component
2804  * of the PFL file is initialised at the create time, cannot be 0-lenght.
2805  */
2806 static int layout_adjust_first_extent(char *fname, struct llapi_layout *layout,
2807                                       bool comp_add)
2808 {
2809         struct llapi_layout *head;
2810         uint64_t start = 0, prev_end = 0;
2811         uint64_t end;
2812         int rc, ret = 0;
2813
2814         if (layout == NULL)
2815                 return 0;
2816
2817         errno = 0;
2818         while (comp_add) {
2819                 head = llapi_layout_get_by_path(fname, 0);
2820                 if (head == NULL) {
2821                         fprintf(stderr,
2822                                 "%s setstripe: cannot read layout from '%s': "
2823                                 "%s\n", progname, fname, strerror(errno));
2824                         return -EINVAL;
2825                 } else if (errno == ENODATA) {
2826                         /* file without LOVEA, this component-add will be turned
2827                          * into a component-create. */
2828                         llapi_layout_free(head);
2829                         ret = -ENODATA;
2830
2831                         /* the new layout will be added to an empty one, it
2832                          * still needs to be adjusted below */
2833                         comp_add = 0;
2834                         break;
2835                 } else if (!llapi_layout_is_composite(head)) {
2836                         fprintf(stderr, "%s setstripe: '%s' not a composite "
2837                                 "file\n", progname, fname);
2838                         llapi_layout_free(head);
2839                         return -EINVAL;
2840                 }
2841
2842                 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
2843                 if (rc) {
2844                         fprintf(stderr, "%s setstripe: cannot get prev "
2845                                 "extent: %s\n", progname, strerror(errno));
2846                         llapi_layout_free(head);
2847                         return rc;
2848                 }
2849
2850                 llapi_layout_free(head);
2851                 break;
2852         }
2853
2854         /* Make sure we use the first component of the layout to be added. */
2855         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
2856         if (rc < 0) {
2857                 fprintf(stderr,
2858                         "%s setstripe: cannot move component cursor: %s\n",
2859                         progname, strerror(errno));
2860                 return rc;
2861         }
2862
2863         rc = llapi_layout_comp_extent_get(layout, &start, &end);
2864         if (rc) {
2865                 fprintf(stderr, "%s setstripe: cannot get extent: %s\n",
2866                         progname, strerror(errno));
2867                 return rc;
2868         }
2869
2870         if (start == 0 && end == 0) {
2871                 rc = layout_extend_comp(layout, start, &end,
2872                                         comp_add ? prev_end : 0);
2873                 if (rc)
2874                         return rc;
2875         }
2876
2877         if (start > prev_end || end < prev_end) {
2878                 fprintf(stderr, "%s setstripe: first extent [%lu, %lu) not "
2879                         "adjacent with extent end %lu\n",
2880                         progname, start, end, prev_end);
2881                 return -EINVAL;
2882         }
2883
2884         rc = llapi_layout_comp_extent_set(layout, prev_end, end);
2885         if (rc) {
2886                 fprintf(stderr, "%s setstripe: cannot set component extent "
2887                         "[%lu, %lu): %s\n",
2888                         progname, prev_end, end, strerror(errno));
2889                 return rc;
2890         }
2891
2892         return ret;
2893 }
2894
2895 static int mirror_adjust_first_extents(struct mirror_args *list)
2896 {
2897         int rc = 0;
2898
2899         if (list == NULL)
2900                 return 0;
2901
2902         while (list != NULL) {
2903                 rc = layout_adjust_first_extent(NULL, list->m_layout, false);
2904                 if (rc)
2905                         break;
2906                 list = list->m_next;
2907         }
2908
2909         return rc;
2910 }
2911
2912 static inline bool arg_is_eof(char *arg)
2913 {
2914         return !strncmp(arg, "-1", strlen("-1")) ||
2915                !strncmp(arg, "EOF", strlen("EOF")) ||
2916                !strncmp(arg, "eof", strlen("eof"));
2917 }
2918
2919 /**
2920  * lfs_mirror_alloc() - Allocate a mirror argument structure.
2921  *
2922  * Return: Valid mirror_args pointer on success and
2923  *         NULL if memory allocation fails.
2924  */
2925 static struct mirror_args *lfs_mirror_alloc(void)
2926 {
2927         struct mirror_args *mirror = NULL;
2928
2929         while (1) {
2930                 mirror = calloc(1, sizeof(*mirror));
2931                 if (mirror != NULL)
2932                         break;
2933
2934                 sleep(1);
2935         }
2936
2937         return mirror;
2938 }
2939
2940 /**
2941  * lfs_mirror_free() - Free memory allocated for a mirror argument
2942  *                     structure.
2943  * @mirror: Previously allocated mirror argument structure by
2944  *          lfs_mirror_alloc().
2945  *
2946  * Free memory allocated for @mirror.
2947  *
2948  * Return: void.
2949  */
2950 static void lfs_mirror_free(struct mirror_args *mirror)
2951 {
2952         if (mirror->m_layout != NULL)
2953                 llapi_layout_free(mirror->m_layout);
2954         free(mirror);
2955 }
2956
2957 /**
2958  * lfs_mirror_list_free() - Free memory allocated for a mirror list.
2959  * @mirror_list: Previously allocated mirror list.
2960  *
2961  * Free memory allocated for @mirror_list.
2962  *
2963  * Return: void.
2964  */
2965 static void lfs_mirror_list_free(struct mirror_args *mirror_list)
2966 {
2967         struct mirror_args *next_mirror = NULL;
2968
2969         while (mirror_list != NULL) {
2970                 next_mirror = mirror_list->m_next;
2971                 lfs_mirror_free(mirror_list);
2972                 mirror_list = next_mirror;
2973         }
2974 }
2975
2976 enum {
2977         LFS_POOL_OPT = 3,
2978         LFS_COMP_COUNT_OPT,
2979         LFS_COMP_START_OPT,
2980         LFS_COMP_FLAGS_OPT,
2981         LFS_COMP_DEL_OPT,
2982         LFS_COMP_SET_OPT,
2983         LFS_COMP_ADD_OPT,
2984         LFS_COMP_NO_VERIFY_OPT,
2985         LFS_PROJID_OPT,
2986         LFS_LAYOUT_FLAGS_OPT, /* used for mirror and foreign flags */
2987         LFS_MIRROR_ID_OPT,
2988         LFS_MIRROR_STATE_OPT,
2989         LFS_LAYOUT_COPY,
2990         LFS_MIRROR_INDEX_OPT,
2991         LFS_LAYOUT_FOREIGN_OPT,
2992         LFS_MODE_OPT,
2993         LFS_NEWERXY_OPT,
2994 };
2995
2996 /* functions */
2997 static int lfs_setstripe_internal(int argc, char **argv,
2998                                   enum setstripe_origin opc)
2999 {
3000         struct lfs_setstripe_args        lsa = { 0 };
3001         struct llapi_stripe_param       *param = NULL;
3002         struct find_param                migrate_mdt_param = {
3003                 .fp_max_depth = -1,
3004                 .fp_mdt_index = -1,
3005         };
3006         char                            *fname;
3007         int                              result = 0;
3008         int                              result2 = 0;
3009         char                            *end;
3010         int                              c;
3011         int                              delete = 0;
3012         unsigned long long               size_units = 1;
3013         bool                             migrate_mode = false;
3014         bool                             migrate_mdt_mode = false;
3015         bool                             setstripe_mode = false;
3016         bool                             migration_block = false;
3017         __u64                            migration_flags = 0;
3018         __u32                            tgts[LOV_MAX_STRIPE_COUNT] = { 0 };
3019         int                              comp_del = 0, comp_set = 0;
3020         int                              comp_add = 0;
3021         __u32                            comp_id = 0;
3022         struct llapi_layout             *layout = NULL;
3023         struct llapi_layout             **lpp = &layout;
3024         bool                             mirror_mode = false;
3025         bool                             has_m_file = false;
3026         __u32                            mirror_count = 0;
3027         enum mirror_flags                mirror_flags = 0;
3028         struct mirror_args              *mirror_list = NULL;
3029         struct mirror_args              *new_mirror = NULL;
3030         struct mirror_args              *last_mirror = NULL;
3031         __u16                            mirror_id = 0;
3032         char                             cmd[PATH_MAX];
3033         bool from_yaml = false;
3034         bool from_copy = false;
3035         char *template = NULL;
3036         bool foreign_mode = false;
3037         char *xattr = NULL;
3038         uint32_t type = LU_FOREIGN_TYPE_NONE, flags = 0;
3039         char *mode_opt = NULL;
3040         mode_t previous_umask = 0;
3041         mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
3042
3043         struct option long_opts[] = {
3044 /* find { .val = '0',   .name = "null",         .has_arg = no_argument }, */
3045 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
3046         /* --block is only valid in migrate mode */
3047         { .val = 'b',   .name = "block",        .has_arg = no_argument },
3048         { .val = LFS_COMP_ADD_OPT,
3049                         .name = "comp-add",     .has_arg = no_argument },
3050         { .val = LFS_COMP_ADD_OPT,
3051                         .name = "component-add", .has_arg = no_argument },
3052         { .val = LFS_COMP_DEL_OPT,
3053                         .name = "comp-del",     .has_arg = no_argument },
3054         { .val = LFS_COMP_DEL_OPT,
3055                         .name = "component-del", .has_arg = no_argument },
3056         { .val = LFS_COMP_FLAGS_OPT,
3057                         .name = "comp-flags",   .has_arg = required_argument },
3058         { .val = LFS_COMP_FLAGS_OPT,
3059                         .name = "component-flags",
3060                                                 .has_arg = required_argument },
3061         { .val = LFS_COMP_SET_OPT,
3062                         .name = "comp-set",     .has_arg = no_argument },
3063         { .val = LFS_COMP_SET_OPT,
3064                         .name = "component-set",
3065                                                 .has_arg = no_argument},
3066         { .val = LFS_COMP_NO_VERIFY_OPT,
3067                         .name = "no-verify",    .has_arg = no_argument},
3068         { .val = LFS_LAYOUT_FLAGS_OPT,
3069                         .name = "flags",        .has_arg = required_argument},
3070         { .val = LFS_LAYOUT_FOREIGN_OPT,
3071                         .name = "foreign",      .has_arg = optional_argument},
3072         { .val = LFS_MIRROR_ID_OPT,
3073                         .name = "mirror-id",    .has_arg = required_argument},
3074         { .val = LFS_MODE_OPT,
3075                         .name = "mode",         .has_arg = required_argument},
3076         { .val = LFS_LAYOUT_COPY,
3077                         .name = "copy",         .has_arg = required_argument},
3078         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument},
3079         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument},
3080         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument},
3081         { .val = 'C',   .name = "overstripe-count",
3082                                                 .has_arg = required_argument},
3083         { .val = 'd',   .name = "delete",       .has_arg = no_argument},
3084         { .val = 'd',   .name = "destroy",      .has_arg = no_argument},
3085         /* --non-direct is only valid in migrate mode */
3086         { .val = 'D',   .name = "non-direct",   .has_arg = no_argument },
3087         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument},
3088         { .val = 'E',   .name = "component-end",
3089                                                 .has_arg = required_argument},
3090         { .val = 'f',   .name = "file",         .has_arg = required_argument },
3091 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
3092 /* find { .val = 'g',   .name = "gid",          .has_arg = no_argument }, */
3093 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
3094 /* find { .val = 'h',   .name = "help",         .has_arg = no_argument }, */
3095         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument},
3096         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument},
3097         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument},
3098         { .val = 'I',   .name = "comp-id",      .has_arg = required_argument},
3099         { .val = 'I',   .name = "component-id", .has_arg = required_argument},
3100 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
3101         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
3102         { .val = 'm',   .name = "mdt",          .has_arg = required_argument},
3103         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument},
3104         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument},
3105         /* --non-block is only valid in migrate mode */
3106         { .val = 'n',   .name = "non-block",    .has_arg = no_argument },
3107         { .val = 'N',   .name = "mirror-count", .has_arg = optional_argument},
3108         { .val = 'o',   .name = "ost",          .has_arg = required_argument },
3109 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3110         { .val = 'o',   .name = "ost-list",     .has_arg = required_argument },
3111         { .val = 'o',   .name = "ost_list",     .has_arg = required_argument },
3112 #endif
3113         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
3114 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
3115 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
3116 /* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
3117 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
3118         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
3119         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
3120 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
3121 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
3122 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
3123 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
3124         /* --verbose is only valid in migrate mode */
3125         { .val = 'v',   .name = "verbose",      .has_arg = no_argument},
3126         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
3127         { .val = 'y',   .name = "yaml",         .has_arg = required_argument },
3128         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument},
3129         { .val = 'z',   .name = "extension-size", .has_arg = required_argument},
3130         { .name = NULL } };
3131
3132         setstripe_args_init(&lsa);
3133
3134         migrate_mode = (opc == SO_MIGRATE);
3135         mirror_mode = (opc == SO_MIRROR_CREATE || opc == SO_MIRROR_EXTEND);
3136         setstripe_mode = (opc == SO_SETSTRIPE);
3137         if (opc == SO_MIRROR_DELETE) {
3138                 delete = 1;
3139                 mirror_flags = MF_DESTROY;
3140         }
3141
3142         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
3143         progname = cmd;
3144         while ((c = getopt_long(argc, argv,
3145                                 "bc:C:dDE:f:H:i:I:m:N::no:p:L:s:S:vx:y:z:",
3146                                 long_opts, NULL)) >= 0) {
3147                 size_units = 1;
3148                 switch (c) {
3149                 case 0:
3150                         /* Long options. */
3151                         break;
3152                 case LFS_COMP_ADD_OPT:
3153                         comp_add = 1;
3154                         break;
3155                 case LFS_COMP_DEL_OPT:
3156                         comp_del = 1;
3157                         break;
3158                 case LFS_COMP_FLAGS_OPT:
3159                         result = comp_str2flags(optarg, &lsa.lsa_comp_flags,
3160                                                 &lsa.lsa_comp_neg_flags);
3161                         if (result != 0)
3162                                 goto usage_error;
3163                         if (mirror_mode && lsa.lsa_comp_neg_flags) {
3164                                 fprintf(stderr, "%s: inverted flags are not supported\n",
3165                                         progname);
3166                                 goto usage_error;
3167                         }
3168                         break;
3169                 case LFS_COMP_SET_OPT:
3170                         comp_set = 1;
3171                         break;
3172                 case LFS_COMP_NO_VERIFY_OPT:
3173                         mirror_flags |= MF_NO_VERIFY;
3174                         break;
3175                 case LFS_MIRROR_ID_OPT:
3176                         mirror_id = strtoul(optarg, &end, 0);
3177                         if (*end != '\0' || mirror_id == 0) {
3178                                 fprintf(stderr,
3179                                         "%s %s: invalid mirror ID '%s'\n",
3180                                         progname, argv[0], optarg);
3181                                 goto usage_error;
3182                         }
3183                         break;
3184                 case LFS_LAYOUT_FLAGS_OPT: {
3185                         uint32_t neg_flags;
3186
3187                         /* check for numeric flags (foreign and mirror cases) */
3188                         if (setstripe_mode && !mirror_mode && !last_mirror) {
3189                                 flags = strtoul(optarg, &end, 16);
3190                                 if (*end != '\0') {
3191                                         fprintf(stderr,
3192                                                 "%s %s: bad flags '%s'\n",
3193                                                 progname, argv[0], optarg);
3194                                         return CMD_HELP;
3195                                 }
3196                                 break;
3197                         }
3198
3199                         if (!mirror_mode || !last_mirror) {
3200                                 fprintf(stderr, "error: %s: --flags must be specified with --mirror-count|-N option\n",
3201                                         progname);
3202                                 goto usage_error;
3203                         }
3204
3205                         result = comp_str2flags(optarg, &last_mirror->m_flags,
3206                                                 &neg_flags);
3207                         if (result != 0)
3208                                 goto usage_error;
3209
3210                         if (neg_flags) {
3211                                 fprintf(stderr, "%s: inverted flags are not supported\n",
3212                                         progname);
3213                                 result = -EINVAL;
3214                                 goto usage_error;
3215                         }
3216                         if (last_mirror->m_flags & ~LCME_USER_MIRROR_FLAGS) {
3217                                 fprintf(stderr,
3218                                         "%s: unsupported mirror flags: %s\n",
3219                                         progname, optarg);
3220                                 result = -EINVAL;
3221                                 goto error;
3222                         }
3223                         break;
3224                 }
3225                 case LFS_LAYOUT_FOREIGN_OPT:
3226                         if (optarg != NULL) {
3227                                 /* check pure numeric */
3228                                 type = strtoul(optarg, &end, 0);
3229                                 if (*end) {
3230                                         /* check name */
3231                                         type = check_foreign_type_name(optarg);
3232                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
3233                                                 fprintf(stderr,
3234                                                         "%s %s: unrecognized foreign type '%s'\n",
3235                                                         progname, argv[0],
3236                                                         optarg);
3237                                                 return CMD_HELP;
3238                                         }
3239                                 }
3240                         }
3241                         foreign_mode = true;
3242                         break;
3243                 case LFS_MODE_OPT:
3244                         mode_opt = optarg;
3245                         if (mode_opt != NULL) {
3246                                 mode = strtoul(mode_opt, &end, 8);
3247                                 if (*end != '\0') {
3248                                         fprintf(stderr,
3249                                                 "%s %s: bad mode '%s'\n",
3250                                                 progname, argv[0], mode_opt);
3251                                         return CMD_HELP;
3252                                 }
3253                                 previous_umask = umask(0);
3254                         }
3255                         break;
3256                 case LFS_LAYOUT_COPY:
3257                         from_copy = true;
3258                         template = optarg;
3259                         break;
3260                 case 'b':
3261                         if (!migrate_mode) {
3262                                 fprintf(stderr,
3263                                         "%s %s: -b|--block valid only for migrate command\n",
3264                                         progname, argv[0]);
3265                                 goto usage_error;
3266                         }
3267                         migration_block = true;
3268                         break;
3269                 case 'C':
3270                         if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) {
3271                                 fprintf(stderr,
3272                                         "%s %s: -C|--overstripe-count incompatible with DoM layout\n",
3273                                         progname, argv[0]);
3274                                 goto usage_error;
3275                         }
3276                         lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
3277                         /* fall through */
3278                 case 'c':
3279                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
3280                         if (*end != '\0') {
3281                                 fprintf(stderr,
3282                                         "%s %s: invalid stripe count '%s'\n",
3283                                         progname, argv[0], optarg);
3284                                 goto usage_error;
3285                         }
3286
3287                         if (lsa.lsa_stripe_count == -1)
3288                                 lsa.lsa_stripe_count = LLAPI_LAYOUT_WIDE;
3289                         break;
3290                 case 'd':
3291                         /* delete the default striping pattern */
3292                         delete = 1;
3293                         if (opc == SO_MIRROR_SPLIT) {
3294                                 if (has_m_file) {
3295                                         fprintf(stderr,
3296                                               "%s %s: -d cannot used with -f\n",
3297                                                 progname, argv[0]);
3298                                         goto usage_error;
3299                                 }
3300                                 mirror_flags |= MF_DESTROY;
3301                         }
3302                         break;
3303                 case 'D':
3304                         if (!migrate_mode) {
3305                                 fprintf(stderr,
3306                                         "%s %s: -D|--non-direct is valid "
3307                                         "only for migrate command\n",
3308                                         progname, argv[0]);
3309                                 goto usage_error;
3310                         }
3311                         migration_flags |= MIGRATION_NONDIRECT;
3312                         break;
3313                 case 'E':
3314                         if (lsa.lsa_comp_end != 0) {
3315                                 result = comp_args_to_layout(lpp, &lsa, true);
3316                                 if (result) {
3317                                         fprintf(stderr, "%s: invalid layout\n",
3318                                                 progname);
3319                                         goto usage_error;
3320                                 }
3321
3322                                 setstripe_args_init_inherit(&lsa);
3323                         }
3324
3325                         if (arg_is_eof(optarg)) {
3326                                 lsa.lsa_comp_end = LUSTRE_EOF;
3327                         } else {
3328                                 result = llapi_parse_size(optarg,
3329                                                         &lsa.lsa_comp_end,
3330                                                         &size_units, 0);
3331                                 if (result) {
3332                                         fprintf(stderr,
3333                                                 "%s %s: invalid component end '%s'\n",
3334                                                 progname, argv[0], optarg);
3335                                         goto usage_error;
3336                                 }
3337                         }
3338                         break;
3339                 case 'H':
3340                         if (!migrate_mode) {
3341                                 fprintf(stderr, "--mdt-hash is valid only for migrate command\n");
3342                                 return CMD_HELP;
3343                         }
3344
3345                         lsa.lsa_pattern = check_hashtype(optarg);
3346                         if (lsa.lsa_pattern == 0) {
3347                                 fprintf(stderr,
3348                                         "%s %s: bad stripe hash type '%s'\n",
3349                                         progname, argv[0], optarg);
3350                                 return CMD_HELP;
3351                         }
3352                         break;
3353                 case 'i':
3354                         lsa.lsa_stripe_off = strtol(optarg, &end, 0);
3355                         if (*end != '\0') {
3356                                 fprintf(stderr,
3357                                         "%s %s: invalid stripe offset '%s'\n",
3358                                         progname, argv[0], optarg);
3359                                 goto usage_error;
3360                         }
3361                         if (lsa.lsa_stripe_off == -1)
3362                                 lsa.lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
3363                         break;
3364                 case 'I':
3365                         comp_id = strtoul(optarg, &end, 0);
3366                         if (*end != '\0' || comp_id == 0 ||
3367                             comp_id > LCME_ID_MAX) {
3368                                 fprintf(stderr,
3369                                         "%s %s: invalid component ID '%s'\n",
3370                                         progname, argv[0], optarg);
3371                                 goto usage_error;
3372                         }
3373                         break;
3374                 case 'f':
3375                         if (opc != SO_MIRROR_EXTEND && opc != SO_MIRROR_SPLIT) {
3376                                 fprintf(stderr,
3377                                         "error: %s: invalid option: %s\n",
3378                                         progname, argv[optopt + 1]);
3379                                 goto usage_error;
3380                         }
3381                         if (opc == SO_MIRROR_EXTEND) {
3382                                 if (last_mirror == NULL) {
3383                                         fprintf(stderr,
3384                                 "error: %s: '-N' must exist in front of '%s'\n",
3385                                                 progname, argv[optopt + 1]);
3386                                         goto usage_error;
3387                                 }
3388                                 last_mirror->m_file = optarg;
3389                                 last_mirror->m_count = 1;
3390                         } else {
3391                                 /* mirror split */
3392                                 if (mirror_list == NULL)
3393                                         mirror_list = lfs_mirror_alloc();
3394                                 mirror_list->m_file = optarg;
3395                         }
3396                         has_m_file = true;
3397                         break;
3398                 case 'L':
3399                         if (strcmp(argv[optind - 1], "mdt") == 0) {
3400                                 /* Can be only the first component */
3401                                 if (layout != NULL) {
3402                                         result = -EINVAL;
3403                                         fprintf(stderr, "error: 'mdt' layout "
3404                                                 "can be only the first one\n");
3405                                         goto error;
3406                                 }
3407                                 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
3408                                         result = -EFBIG;
3409                                         fprintf(stderr, "error: 'mdt' layout "
3410                                                 "size is too big\n");
3411                                         goto error;
3412                                 }
3413                                 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
3414                         } else if (strcmp(argv[optind - 1], "raid0") != 0) {
3415                                 result = -EINVAL;
3416                                 fprintf(stderr, "error: layout '%s' is "
3417                                         "unknown, supported layouts are: "
3418                                         "'mdt', 'raid0'\n", argv[optind]);
3419                                 goto error;
3420                         }
3421                         break;
3422                 case 'm':
3423                         if (!migrate_mode) {
3424                                 fprintf(stderr,
3425                                         "%s %s: -m|--mdt-index is valid only for migrate command\n",
3426                                         progname, argv[0]);
3427                                 goto usage_error;
3428                         }
3429                         migrate_mdt_mode = true;
3430                         lsa.lsa_nr_tgts = parse_targets(tgts,
3431                                                 sizeof(tgts) / sizeof(__u32),
3432                                                 lsa.lsa_nr_tgts, optarg, NULL);
3433                         if (lsa.lsa_nr_tgts < 0) {
3434                                 fprintf(stderr,
3435                                         "%s %s: invalid MDT target(s) '%s'\n",
3436                                         progname, argv[0], optarg);
3437                                 return CMD_HELP;
3438                         }
3439
3440                         lsa.lsa_tgts = tgts;
3441                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
3442                                 lsa.lsa_stripe_off = tgts[0];
3443                         break;
3444                 case 'n':
3445                         if (!migrate_mode) {
3446                                 fprintf(stderr,
3447                                         "%s %s: -n|--non-block valid only for migrate command\n",
3448                                         progname, argv[0]);
3449                                 goto usage_error;
3450                         }
3451                         migration_flags |= MIGRATION_NONBLOCK;
3452                         break;
3453                 case 'N':
3454                         if (opc == SO_SETSTRIPE) {
3455                                 opc = SO_MIRROR_CREATE;
3456                                 mirror_mode = true;
3457                         }
3458                         mirror_count = 1;
3459                         if (optarg != NULL) {
3460                                 mirror_count = strtoul(optarg, &end, 0);
3461                                 if (*end != '\0' || mirror_count == 0) {
3462                                         fprintf(stderr,
3463                                                 "error: %s: bad mirror count: %s\n",
3464                                                 progname, optarg);
3465                                         result = -EINVAL;
3466                                         goto error;
3467                                 }
3468                         }
3469
3470                         new_mirror = lfs_mirror_alloc();
3471                         new_mirror->m_count = mirror_count;
3472
3473                         if (mirror_list == NULL)
3474                                 mirror_list = new_mirror;
3475
3476                         if (last_mirror != NULL) {
3477                                 /* wrap up last mirror */
3478                                 if (lsa.lsa_comp_end == 0)
3479                                         lsa.lsa_comp_end = LUSTRE_EOF;
3480
3481                                 result = comp_args_to_layout(lpp, &lsa, true);
3482                                 if (result) {
3483                                         lfs_mirror_free(new_mirror);
3484                                         goto error;
3485                                 }
3486
3487                                 setstripe_args_init_inherit(&lsa);
3488
3489                                 last_mirror->m_next = new_mirror;
3490                         }
3491
3492                         last_mirror = new_mirror;
3493                         lpp = &last_mirror->m_layout;
3494                         break;
3495                 case 'o':
3496 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3497                         if (strcmp(argv[optind - 1], "--ost-list") == 0)
3498                                 fprintf(stderr, "warning: '--ost-list' is "
3499                                         "deprecated, use '--ost' instead\n");
3500 #endif
3501                         if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) {
3502                                 fprintf(stderr,
3503                                         "%s %s: -o|--ost incompatible with DoM layout\n",
3504                                         progname, argv[0]);
3505                                 goto usage_error;
3506                         }
3507                         /* -o allows overstriping, and must note it because
3508                          * parse_targets is shared with MDT striping, which
3509                          * does not allow duplicates
3510                          */
3511                         lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
3512                         lsa.lsa_nr_tgts = parse_targets(tgts,
3513                                                 sizeof(tgts) / sizeof(__u32),
3514                                                 lsa.lsa_nr_tgts, optarg,
3515                                                 &lsa.lsa_pattern);
3516                         if (lsa.lsa_nr_tgts < 0) {
3517                                 fprintf(stderr,
3518                                         "%s %s: invalid OST target(s) '%s'\n",
3519                                         progname, argv[0], optarg);
3520                                 goto usage_error;
3521                         }
3522
3523                         lsa.lsa_tgts = tgts;
3524                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
3525                                 lsa.lsa_stripe_off = tgts[0];
3526                         break;
3527                 case 'p':
3528                         if (optarg == NULL)
3529                                 goto usage_error;
3530                         lsa.lsa_pool_name = optarg;
3531
3532                         if (strlen(lsa.lsa_pool_name) == 0 ||
3533                             strncmp(lsa.lsa_pool_name, "none",
3534                                     LOV_MAXPOOLNAME) == 0)
3535                                 lsa.lsa_pool_name = NULL;
3536                         break;
3537                 case 'S':
3538                         result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
3539                                                   &size_units, 0);
3540                         if (result) {
3541                                 fprintf(stderr,
3542                                         "%s %s: invalid stripe size '%s'\n",
3543                                         progname, argv[0], optarg);
3544                                 goto usage_error;
3545                         }
3546                         break;
3547                 case 'v':
3548                         if (!migrate_mode) {
3549                                 fprintf(stderr,
3550                                         "%s %s: -v|--verbose valid only for migrate command\n",
3551                                         progname, argv[0]);
3552                                 goto usage_error;
3553                         }
3554                         migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
3555                         migration_flags = MIGRATION_VERBOSE;
3556                         break;
3557                 case 'x':
3558                         xattr = optarg;
3559                         break;
3560                 case 'y':
3561                         from_yaml = true;
3562                         template = optarg;
3563                         break;
3564                 case 'z':
3565                         result = llapi_parse_size(optarg,
3566                                                   &lsa.lsa_extension_size,
3567                                                   &size_units, 0);
3568                         if (result) {
3569                                 fprintf(stderr,
3570                                         "%s %s: invalid extension size '%s'\n",
3571                                         progname, argv[0], optarg);
3572                                 goto usage_error;
3573                         }
3574
3575                         lsa.lsa_extension_comp = true;
3576                         break;
3577                 default:
3578                         fprintf(stderr, "%s %s: unrecognized option '%s'\n",
3579                                 progname, argv[0], argv[optind - 1]);
3580                         goto usage_error;
3581                 }
3582         }
3583
3584         fname = argv[optind];
3585
3586         if (optind == argc) {
3587                 fprintf(stderr, "%s %s: FILE must be specified\n",
3588                         progname, argv[0]);
3589                 goto usage_error;
3590         }
3591
3592         /* lfs migrate $filename should keep the file's layout by default */
3593         if (migrate_mode && !setstripe_args_specified(&lsa) && !layout &&
3594             !from_yaml)
3595                 from_copy = true;
3596
3597         if (xattr && !foreign_mode) {
3598                 /* only print a warning as this is harmless and will be ignored
3599                  */
3600                 fprintf(stderr,
3601                         "%s %s: xattr has been specified for non-foreign layout\n",
3602                         progname, argv[0]);
3603         } else if (foreign_mode && !xattr) {
3604                 fprintf(stderr,
3605                         "%s %s: xattr must be provided in foreign mode\n",
3606                         progname, argv[0]);
3607                 goto usage_error;
3608         }
3609
3610         if (foreign_mode && (!setstripe_mode || comp_add | comp_del ||
3611             comp_set || comp_id || delete || from_copy ||
3612             setstripe_args_specified(&lsa) || lsa.lsa_nr_tgts ||
3613             lsa.lsa_tgts)) {
3614                 fprintf(stderr,
3615                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
3616                         progname, argv[0]);
3617                 return CMD_HELP;
3618         }
3619
3620         if (mirror_mode && mirror_count == 0) {
3621                 fprintf(stderr,
3622                         "error: %s: --mirror-count|-N option is required\n",
3623                         progname);
3624                 result = -EINVAL;
3625                 goto error;
3626         }
3627
3628         if (mirror_mode) {
3629                 if (lsa.lsa_comp_end == 0)
3630                         lsa.lsa_comp_end = LUSTRE_EOF;
3631         }
3632
3633         if (lsa.lsa_comp_end != 0) {
3634                 result = comp_args_to_layout(lpp, &lsa, true);
3635                 if (result) {
3636                         fprintf(stderr, "error: %s: invalid layout\n",
3637                                 progname);
3638                         result = -EINVAL;
3639                         goto error;
3640                 }
3641         }
3642
3643         if (mirror_flags & MF_NO_VERIFY) {
3644                 if (opc != SO_MIRROR_EXTEND) {
3645                         fprintf(stderr,
3646                                 "error: %s: --no-verify is valid only for lfs mirror extend command\n",
3647                                 progname);
3648                         result = -EINVAL;
3649                         goto error;
3650                 } else if (!has_m_file) {
3651                         fprintf(stderr,
3652                                 "error: %s: --no-verify must be specified with -f <victim_file> option\n",
3653                                 progname);
3654                         result = -EINVAL;
3655                         goto error;
3656                 }
3657         }
3658
3659         if (comp_set && !comp_id) {
3660                 fprintf(stderr, "%s %s: --component-set doesn't have component-id set\n",
3661                         progname, argv[0]);
3662                 goto usage_error;
3663         }
3664
3665         if ((delete + comp_set + comp_del + comp_add) > 1) {
3666                 fprintf(stderr,
3667                         "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
3668                         progname, argv[0]);
3669                 goto usage_error;
3670         }
3671
3672         if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
3673                        lsa.lsa_comp_flags != 0 || layout != NULL)) {
3674                 fprintf(stderr,
3675                         "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
3676                         progname, argv[0]);
3677                 goto usage_error;
3678         }
3679
3680         if ((comp_set || comp_del) &&
3681             (setstripe_args_specified(&lsa) || layout != NULL)) {
3682                 fprintf(stderr,
3683                         "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
3684                         progname, argv[0]);
3685                 goto usage_error;
3686         }
3687
3688         if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
3689                 fprintf(stderr,
3690                         "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
3691                         progname, argv[0]);
3692                 goto usage_error;
3693         }
3694
3695         if (comp_add || comp_del) {
3696                 struct stat st;
3697
3698                 result = lstat(fname, &st);
3699                 if (result == 0 && S_ISDIR(st.st_mode)) {
3700                         fprintf(stderr,
3701                                 "%s setstripe: cannot use --component-add or --component-del for directory\n",
3702                                 progname);
3703                         goto usage_error;
3704                 }
3705
3706                 if (mirror_mode) {
3707                         fprintf(stderr, "error: %s: can't use --component-add "
3708                                 "or --component-del for mirror operation\n",
3709                                 progname);
3710                         goto usage_error;
3711                 }
3712         }
3713
3714         if (comp_add) {
3715                 if (layout == NULL) {
3716                         fprintf(stderr,
3717                                 "%s %s: option -E must be specified with --component-add\n",
3718                                 progname, argv[0]);
3719                         goto usage_error;
3720                 }
3721         }
3722
3723         if (layout != NULL || mirror_list != NULL) {
3724                 if (mirror_list)
3725                         result = mirror_adjust_first_extents(mirror_list);
3726                 else
3727                         result = layout_adjust_first_extent(fname, layout,
3728                                                             comp_add);
3729                 if (result == -ENODATA)
3730                         comp_add = 0;
3731                 else if (result != 0) {
3732                         fprintf(stderr, "error: %s: invalid layout\n",
3733                                 progname);
3734                         goto error;
3735                 }
3736         }
3737
3738         if (from_yaml && from_copy) {
3739                 fprintf(stderr,
3740                         "%s: can't specify --yaml and --copy together\n",
3741                         progname);
3742                 goto error;
3743         }
3744
3745         if ((from_yaml || from_copy) &&
3746             (setstripe_args_specified(&lsa) || layout != NULL)) {
3747                 fprintf(stderr, "error: %s: can't specify --yaml or --copy with"
3748                         " -c, -S, -i, -o, -p or -E options.\n",
3749                         argv[0]);
3750                 goto error;
3751         }
3752
3753         if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
3754                 fprintf(stderr,
3755                         "%s %s: options --non-block and --block are mutually exclusive\n",
3756                         progname, argv[0]);
3757                 goto usage_error;
3758         }
3759
3760         if (!comp_del && !comp_set && opc != SO_MIRROR_SPLIT &&
3761             opc != SO_MIRROR_DELETE && comp_id != 0) {
3762                 fprintf(stderr,
3763                         "%s: option -I can only be used with --component-del or --component-set or lfs mirror split\n",
3764                         progname);
3765                 goto usage_error;
3766         }
3767
3768         if (migrate_mdt_mode) {
3769                 struct lmv_user_md *lmu;
3770
3771                 /* initialize migrate mdt parameters */
3772                 lmu = calloc(1, lmv_user_md_size(lsa.lsa_nr_tgts,
3773                                                  LMV_USER_MAGIC_SPECIFIC));
3774                 if (!lmu) {
3775                         fprintf(stderr,
3776                                 "%s %s: cannot allocate memory for lmv_user_md: %s\n",
3777                                 progname, argv[0], strerror(ENOMEM));
3778                         result = -ENOMEM;
3779                         goto error;
3780                 }
3781                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
3782                         lmu->lum_stripe_count = lsa.lsa_stripe_count;
3783                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT) {
3784                         fprintf(stderr,
3785                                 "%s %s: migrate should specify MDT index\n",
3786                                 progname, argv[0]);
3787                         free(lmu);
3788                         goto usage_error;
3789                 }
3790                 lmu->lum_stripe_offset = lsa.lsa_stripe_off;
3791                 if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
3792                         lmu->lum_hash_type = lsa.lsa_pattern;
3793                 else
3794                         lmu->lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
3795                 if (lsa.lsa_pool_name) {
3796                         strncpy(lmu->lum_pool_name, lsa.lsa_pool_name,
3797                                 sizeof(lmu->lum_pool_name) - 1);
3798                         lmu->lum_pool_name[sizeof(lmu->lum_pool_name) - 1] = 0;
3799                 }
3800                 if (lsa.lsa_nr_tgts > 1) {
3801                         int i;
3802
3803                         if (lsa.lsa_stripe_count > 0 &&
3804                             lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
3805                             lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
3806                                 fprintf(stderr,
3807                                         "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
3808                                         progname, lsa.lsa_stripe_count,
3809                                         lsa.lsa_nr_tgts);
3810                                 free(lmu);
3811                                 goto usage_error;
3812                         }
3813
3814                         lmu->lum_magic = LMV_USER_MAGIC_SPECIFIC;
3815                         lmu->lum_stripe_count = lsa.lsa_nr_tgts;
3816                         for (i = 0; i < lsa.lsa_nr_tgts; i++)
3817                                 lmu->lum_objects[i].lum_mds = lsa.lsa_tgts[i];
3818                 } else {
3819                         lmu->lum_magic = LMV_USER_MAGIC;
3820                 }
3821
3822                 migrate_mdt_param.fp_lmv_md = lmu;
3823                 migrate_mdt_param.fp_migrate = 1;
3824         } else if (layout == NULL) {
3825                 /* initialize stripe parameters */
3826                 param = calloc(1, offsetof(typeof(*param),
3827                                lsp_osts[lsa.lsa_nr_tgts]));
3828                 if (param == NULL) {
3829                         fprintf(stderr,
3830                                 "%s %s: cannot allocate memory for parameters: %s\n",
3831                                 progname, argv[0], strerror(ENOMEM));
3832                         result = -ENOMEM;
3833                         goto error;
3834                 }
3835
3836                 if (lsa.lsa_stripe_size != LLAPI_LAYOUT_DEFAULT)
3837                         param->lsp_stripe_size = lsa.lsa_stripe_size;
3838                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
3839                         if (lsa.lsa_stripe_count == LLAPI_LAYOUT_WIDE)
3840                                 param->lsp_stripe_count = -1;
3841                         else
3842                                 param->lsp_stripe_count = lsa.lsa_stripe_count;
3843                 }
3844                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
3845                         param->lsp_stripe_offset = -1;
3846                 else
3847                         param->lsp_stripe_offset = lsa.lsa_stripe_off;
3848                 param->lsp_stripe_pattern =
3849                                 llapi_pattern_to_lov(lsa.lsa_pattern);
3850                 if (param->lsp_stripe_pattern == EINVAL) {
3851                         fprintf(stderr, "error: %s: invalid stripe pattern\n",
3852                                 argv[0]);
3853                         free(param);
3854                         goto usage_error;
3855                 }
3856                 param->lsp_pool = lsa.lsa_pool_name;
3857                 param->lsp_is_specific = false;
3858                 if (lsa.lsa_nr_tgts > 0) {
3859                         if (lsa.lsa_stripe_count > 0 &&
3860                             lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
3861                             lsa.lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
3862                             lsa.lsa_nr_tgts != lsa.lsa_stripe_count) {
3863                                 fprintf(stderr,
3864                                         "error: %s: stripe count %lld doesn't match the number of OSTs: %d\n",
3865                                         argv[0], lsa.lsa_stripe_count,
3866                                         lsa.lsa_nr_tgts);
3867                                 free(param);
3868                                 goto usage_error;
3869                         }
3870
3871                         param->lsp_is_specific = true;
3872                         param->lsp_stripe_count = lsa.lsa_nr_tgts;
3873                         memcpy(param->lsp_osts, tgts,
3874                                sizeof(*tgts) * lsa.lsa_nr_tgts);
3875                 }
3876         }
3877
3878         if (from_yaml) {
3879                 /* generate a layout from a YAML template */
3880                 result = lfs_comp_create_from_yaml(template, &layout,
3881                                                    &lsa, tgts);
3882                 if (result) {
3883                         fprintf(stderr, "error: %s: can't create composite "
3884                                 "layout from template file %s\n",
3885                                 argv[0], template);
3886                         goto error;
3887                 }
3888         }
3889
3890         for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
3891                 if (from_copy) {
3892                         layout = llapi_layout_get_by_path(template ?: fname, 0);
3893                         if (layout == NULL) {
3894                                 fprintf(stderr, "%s: can't create composite "
3895                                         "layout from file %s.\n",
3896                                         progname, template ?: fname);
3897                                 goto error;
3898                         }
3899                 }
3900
3901                 if (migrate_mdt_mode) {
3902                         result = llapi_migrate_mdt(fname, &migrate_mdt_param);
3903                 } else if (migrate_mode) {
3904                         result = lfs_migrate(fname, migration_flags, param,
3905                                              layout);
3906                 } else if (comp_set != 0) {
3907                         result = lfs_component_set(fname, comp_id,
3908                                                    lsa.lsa_comp_flags,
3909                                                    lsa.lsa_comp_neg_flags);
3910                 } else if (comp_del != 0) {
3911                         result = lfs_component_del(fname, comp_id,
3912                                                    lsa.lsa_comp_flags,
3913                                                    lsa.lsa_comp_neg_flags);
3914                 } else if (comp_add != 0) {
3915                         result = lfs_component_add(fname, layout);
3916                 } else if (opc == SO_MIRROR_CREATE) {
3917                         result = mirror_create(fname, mirror_list);
3918                 } else if (opc == SO_MIRROR_EXTEND) {
3919                         result = mirror_extend(fname, mirror_list,
3920                                                mirror_flags);
3921                 } else if (opc == SO_MIRROR_SPLIT || opc == SO_MIRROR_DELETE) {
3922                         if (!mirror_id && !comp_id && !lsa.lsa_pool_name) {
3923                                 fprintf(stderr,
3924                                         "%s: no mirror specified to delete from '%s'\n",
3925                                         progname, fname);
3926                                 goto usage_error;
3927                         }
3928                         if (lsa.lsa_pool_name)
3929                                 mirror_flags |= MF_COMP_POOL;
3930                         else if (mirror_id != 0)
3931                                 comp_id = mirror_id;
3932                         else
3933                                 mirror_flags |= MF_COMP_ID;
3934                         result = mirror_split(fname, comp_id, lsa.lsa_pool_name,
3935                                               mirror_flags,
3936                                               has_m_file ? mirror_list->m_file :
3937                                               NULL);
3938                 } else if (layout != NULL) {
3939                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
3940                                                       mode, layout);
3941                         if (result >= 0) {
3942                                 close(result);
3943                                 result = 0;
3944                         }
3945                 } else if (foreign_mode) {
3946                         result = llapi_file_create_foreign(fname, mode, type,
3947                                                            flags, xattr);
3948                         if (result >= 0) {
3949                                 close(result);
3950                                 result = 0;
3951                         }
3952                 } else {
3953                         result = llapi_file_open_param(fname,
3954                                                        O_CREAT | O_WRONLY,
3955                                                        mode, param);
3956                         if (result >= 0) {
3957                                 close(result);
3958                                 result = 0;
3959                         }
3960                 }
3961                 if (result) {
3962                         /* Save the first error encountered. */
3963                         if (result2 == 0)
3964                                 result2 = result;
3965                         continue;
3966                 }
3967         }
3968
3969         if (mode_opt != NULL)
3970                 umask(previous_umask);
3971
3972         free(param);
3973         free(migrate_mdt_param.fp_lmv_md);
3974         llapi_layout_free(layout);
3975         lfs_mirror_list_free(mirror_list);
3976         return result2;
3977 usage_error:
3978         result = CMD_HELP;
3979 error:
3980         llapi_layout_free(layout);
3981         lfs_mirror_list_free(mirror_list);
3982         return result;
3983 }
3984
3985 static int lfs_poollist(int argc, char **argv)
3986 {
3987         if (argc != 2)
3988                 return CMD_HELP;
3989
3990         return llapi_poollist(argv[1]);
3991 }
3992
3993 static time_t set_time(struct find_param *param, time_t *time, time_t *set,
3994                        char *str)
3995 {
3996         long long t = 0;
3997         int res = 0;
3998         char *endptr = "AD";
3999         char *timebuf;
4000
4001         if (str[0] == '+')
4002                 res = 1;
4003         else if (str[0] == '-')
4004                 res = -1;
4005
4006         if (res)
4007                 str++;
4008
4009         for (timebuf = str; *endptr && *(endptr + 1); timebuf = endptr + 1) {
4010                 long long val = strtoll(timebuf, &endptr, 0);
4011                 int unit = 1;
4012
4013                 switch (*endptr) {
4014                 case  'y':
4015                         unit *= 52; /* 52 weeks + 1 day below */
4016                 case  'w':      /* fallthrough */
4017                         unit *= 7;
4018                 case '\0': /* days are default unit if none used */
4019                 case  'd':      /* fallthrough */
4020                         unit = (unit + (*endptr == 'y')) * 24;
4021                 case  'h':      /* fallthrough */
4022                         unit *= 60;
4023                 case  'm':      /* fallthrough */
4024                         unit *= 60;
4025                 case  's':      /* fallthrough */
4026                         break;
4027                         /* don't need to multiply by 1 for seconds */
4028                 default:
4029                         fprintf(stderr,
4030                                 "%s find: bad time string '%s': %s\n",
4031                                 progname, timebuf, strerror(EINVAL));
4032                         return LONG_MAX;
4033                 }
4034
4035                 if (param->fp_time_margin == 0 ||
4036                     (*endptr && unit < param->fp_time_margin))
4037                         param->fp_time_margin = unit;
4038
4039                 t += val * unit;
4040         }
4041         if (*time < t) {
4042                 if (res != 0)
4043                         str--;
4044                 fprintf(stderr, "%s find: bad time '%s': too large\n",
4045                         progname, str);
4046                 return LONG_MAX;
4047         }
4048
4049         *set = *time - t;
4050
4051         return res;
4052 }
4053
4054 static int name2uid(unsigned int *id, const char *name)
4055 {
4056         struct passwd *passwd;
4057
4058         passwd = getpwnam(name);
4059         if (passwd == NULL)
4060                 return -ENOENT;
4061         *id = passwd->pw_uid;
4062
4063         return 0;
4064 }
4065
4066 static int name2gid(unsigned int *id, const char *name)
4067 {
4068         struct group *group;
4069
4070         group = getgrnam(name);
4071         if (group == NULL)
4072                 return -ENOENT;
4073         *id = group->gr_gid;
4074
4075         return 0;
4076 }
4077
4078 static inline int name2projid(unsigned int *id, const char *name)
4079 {
4080         return -ENOTSUP;
4081 }
4082
4083 static int uid2name(char **name, unsigned int id)
4084 {
4085         struct passwd *passwd;
4086
4087         passwd = getpwuid(id);
4088         if (passwd == NULL)
4089                 return -ENOENT;
4090         *name = passwd->pw_name;
4091
4092         return 0;
4093 }
4094
4095 static inline int gid2name(char **name, unsigned int id)
4096 {
4097         struct group *group;
4098
4099         group = getgrgid(id);
4100         if (group == NULL)
4101                 return -ENOENT;
4102         *name = group->gr_name;
4103
4104         return 0;
4105 }
4106
4107 static int name2layout(__u32 *layout, char *name)
4108 {
4109         char *ptr, *layout_name;
4110
4111         *layout = 0;
4112         for (ptr = name; ; ptr = NULL) {
4113                 layout_name = strtok(ptr, ",");
4114                 if (layout_name == NULL)
4115                         break;
4116                 if (strcmp(layout_name, "released") == 0)
4117                         *layout |= LOV_PATTERN_F_RELEASED;
4118                 else if (strcmp(layout_name, "raid0") == 0)
4119                         *layout |= LOV_PATTERN_RAID0;
4120                 else if (strcmp(layout_name, "mdt") == 0)
4121                         *layout |= LOV_PATTERN_MDT;
4122                 else if (strcmp(layout_name, "overstriping") == 0)
4123                         *layout |= LOV_PATTERN_OVERSTRIPING;
4124                 else
4125                         return -1;
4126         }
4127         return 0;
4128 }
4129
4130 static int lfs_find(int argc, char **argv)
4131 {
4132         int c, rc;
4133         int ret = 0;
4134         time_t t;
4135         struct find_param param = {
4136                 .fp_max_depth = -1,
4137                 .fp_quiet = 1,
4138                 .fp_time_margin = 24 * 60 * 60,
4139         };
4140         struct option long_opts[] = {
4141         { .val = 'A',   .name = "atime",        .has_arg = required_argument },
4142         { .val = 'b',   .name = "blocks",       .has_arg = required_argument },
4143         { .val = LFS_COMP_COUNT_OPT,
4144                         .name = "comp-count",   .has_arg = required_argument },
4145         { .val = LFS_COMP_COUNT_OPT,
4146                         .name = "component-count",
4147                                                 .has_arg = required_argument },
4148         { .val = LFS_COMP_FLAGS_OPT,
4149                         .name = "comp-flags",   .has_arg = required_argument },
4150         { .val = LFS_COMP_FLAGS_OPT,
4151                         .name = "component-flags",
4152                                                 .has_arg = required_argument },
4153         { .val = LFS_COMP_START_OPT,
4154                         .name = "comp-start",   .has_arg = required_argument },
4155         { .val = LFS_COMP_START_OPT,
4156                         .name = "component-start",
4157                                                 .has_arg = required_argument },
4158         { .val = LFS_MIRROR_STATE_OPT,
4159                         .name = "mirror-state", .has_arg = required_argument },
4160         { .val = LFS_LAYOUT_FOREIGN_OPT,
4161                         .name = "foreign",      .has_arg = optional_argument},
4162         { .val = LFS_NEWERXY_OPT,
4163                         .name = "newer",        .has_arg = required_argument},
4164         { .val = LFS_NEWERXY_OPT,
4165                         .name = "neweraa",      .has_arg = required_argument},
4166         { .val = LFS_NEWERXY_OPT,
4167                         .name = "neweram",      .has_arg = required_argument},
4168         { .val = LFS_NEWERXY_OPT,
4169                         .name = "newerac",      .has_arg = required_argument},
4170         { .val = LFS_NEWERXY_OPT,
4171                         .name = "newerma",      .has_arg = required_argument},
4172         { .val = LFS_NEWERXY_OPT,
4173                         .name = "newermm",      .has_arg = required_argument},
4174         { .val = LFS_NEWERXY_OPT,
4175                         .name = "newermc",      .has_arg = required_argument},
4176         { .val = LFS_NEWERXY_OPT,
4177                         .name = "newerca",      .has_arg = required_argument},
4178         { .val = LFS_NEWERXY_OPT,
4179                         .name = "newercm",      .has_arg = required_argument},
4180         { .val = LFS_NEWERXY_OPT,
4181                         .name = "newercc",      .has_arg = required_argument},
4182         { .val = LFS_NEWERXY_OPT,
4183                         .name = "newerat",      .has_arg = required_argument},
4184         { .val = LFS_NEWERXY_OPT,
4185                         .name = "newermt",      .has_arg = required_argument},
4186         { .val = LFS_NEWERXY_OPT,
4187                         .name = "newerct",      .has_arg = required_argument},
4188         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument },
4189         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument },
4190         { .val = 'C',   .name = "ctime",        .has_arg = required_argument },
4191 /* getstripe { .val = 'd', .name = "directory", .has_arg = no_argument }, */
4192         { .val = 'D',   .name = "maxdepth",     .has_arg = required_argument },
4193         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument },
4194         { .val = 'E',   .name = "component-end",
4195                                                 .has_arg = required_argument },
4196 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
4197         { .val = LFS_LAYOUT_FOREIGN_OPT,
4198                         .name = "foreign",      .has_arg = optional_argument},
4199         { .val = 'g',   .name = "gid",          .has_arg = required_argument },
4200         { .val = 'G',   .name = "group",        .has_arg = required_argument },
4201         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
4202         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument },
4203         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument },
4204 /* getstripe { .val = 'I', .name = "comp-id",   .has_arg = required_argument }*/
4205         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
4206         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
4207         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
4208         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
4209         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument },
4210         { .val = 'M',   .name = "mtime",        .has_arg = required_argument },
4211         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4212         { .val = 'N',   .name = "mirror-count", .has_arg = required_argument },
4213 /* find { .val = 'o'    .name = "or", .has_arg = no_argument }, like find(1) */
4214         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
4215         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
4216         /* no short option for pool yet, can be 'p' after 2.18 */
4217         { .val = LFS_POOL_OPT,
4218                         .name = "pool",         .has_arg = required_argument },
4219         { .val = '0',   .name = "print0",       .has_arg = no_argument },
4220         { .val = 'P',   .name = "print",        .has_arg = no_argument },
4221         { .val = LFS_PROJID_OPT,
4222                         .name = "projid",       .has_arg = required_argument },
4223 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
4224 /* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
4225 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
4226         { .val = 's',   .name = "size",         .has_arg = required_argument },
4227         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
4228         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
4229         { .val = 't',   .name = "type",         .has_arg = required_argument },
4230         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
4231         { .val = 'u',   .name = "uid",          .has_arg = required_argument },
4232         { .val = 'U',   .name = "user",         .has_arg = required_argument },
4233         { .val = 'z',   .name = "extension-size",
4234                                                 .has_arg = required_argument },
4235         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument },
4236 /* getstripe { .val = 'v', .name = "verbose",   .has_arg = no_argument }, */
4237 /* getstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
4238         { .name = NULL } };
4239         int optidx = 0;
4240         int pathstart = -1;
4241         int pathend = -1;
4242         int pathbad = -1;
4243         int neg_opt = 0;
4244         time_t *xtime;
4245         int *xsign;
4246         int isoption;
4247         char *endptr;
4248
4249         time(&t);
4250
4251         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
4252         while ((c = getopt_long_only(argc, argv,
4253                         "-0A:b:c:C:D:E:g:G:H:i:L:m:M:n:N:O:Ppqrs:S:t:T:u:U:vz:",
4254                         long_opts, &optidx)) >= 0) {
4255                 xtime = NULL;
4256                 xsign = NULL;
4257                 if (neg_opt)
4258                         --neg_opt;
4259                 /* '!' is part of option */
4260                 /* when getopt_long_only() finds a string which is not
4261                  * an option nor a known option argument it returns 1
4262                  * in that case if we already have found pathstart and pathend
4263                  * (i.e. we have the list of pathnames),
4264                  * the only supported value is "!"
4265                  */
4266                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
4267                 if (!isoption && pathend != -1) {
4268                         fprintf(stderr, "err: %s: filename|dirname must either "
4269                                         "precede options or follow options\n",
4270                                         argv[0]);
4271                         ret = CMD_HELP;
4272                         goto err;
4273                 }
4274                 if (!isoption && pathstart == -1)
4275                         pathstart = optind - 1;
4276                 if (isoption && pathstart != -1 && pathend == -1)
4277                         pathend = optind - 2;
4278                 switch (c) {
4279                 case 0:
4280                         /* Long options. */
4281                         break;
4282                 case 1:
4283                         /* unknown; opt is "!" or path component,
4284                          * checking done above.
4285                          */
4286                         if (strcmp(optarg, "!") == 0)
4287                                 neg_opt = 2;
4288                         break;
4289                 case 'A':
4290                         xtime = &param.fp_atime;
4291                         xsign = &param.fp_asign;
4292                         param.fp_exclude_atime = !!neg_opt;
4293                         /* no break, this falls through to 'C' for ctime */
4294                 case 'C':
4295                         if (c == 'C') {
4296                                 xtime = &param.fp_ctime;
4297                                 xsign = &param.fp_csign;
4298                                 param.fp_exclude_ctime = !!neg_opt;
4299                         }
4300                         /* no break, this falls through to 'M' for mtime */
4301                 case 'M':
4302                         if (c == 'M') {
4303                                 xtime = &param.fp_mtime;
4304                                 xsign = &param.fp_msign;
4305                                 param.fp_exclude_mtime = !!neg_opt;
4306                         }
4307                         rc = set_time(&param, &t, xtime, optarg);
4308                         if (rc == LONG_MAX) {
4309                                 ret = -1;
4310                                 goto err;
4311                         }
4312                         if (rc)
4313                                 *xsign = rc;
4314                         break;
4315                 case 'b':
4316                         if (optarg[0] == '+') {
4317                                 param.fp_blocks_sign = -1;
4318                                 optarg++;
4319                         } else if (optarg[0] == '-') {
4320                                 param.fp_blocks_sign =  1;
4321                                 optarg++;
4322                         }
4323
4324                         param.fp_blocks_units = 1024;
4325                         ret = llapi_parse_size(optarg, &param.fp_blocks,
4326                                                &param.fp_blocks_units, 0);
4327                         if (ret) {
4328                                 fprintf(stderr, "error: bad blocks '%s'\n",
4329                                         optarg);
4330                                 goto err;
4331                         }
4332                         param.fp_check_blocks = 1;
4333                         param.fp_exclude_blocks = !!neg_opt;
4334                         break;
4335                 case LFS_COMP_COUNT_OPT:
4336                         if (optarg[0] == '+') {
4337                                 param.fp_comp_count_sign = -1;
4338                                 optarg++;
4339                         } else if (optarg[0] == '-') {
4340                                 param.fp_comp_count_sign =  1;
4341                                 optarg++;
4342                         }
4343
4344                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
4345                         if (*endptr != '\0') {
4346                                 fprintf(stderr, "error: bad component count "
4347                                         "'%s'\n", optarg);
4348                                 goto err;
4349                         }
4350                         param.fp_check_comp_count = 1;
4351                         param.fp_exclude_comp_count = !!neg_opt;
4352                         break;
4353                 case LFS_COMP_FLAGS_OPT:
4354                         rc = comp_str2flags(optarg, &param.fp_comp_flags,
4355                                             &param.fp_comp_neg_flags);
4356                         if (rc) {
4357                                 fprintf(stderr, "error: bad component flags "
4358                                         "'%s'\n", optarg);
4359                                 goto err;
4360                         }
4361                         param.fp_check_comp_flags = 1;
4362                         if (neg_opt) {
4363                                 __u32 flags = param.fp_comp_neg_flags;
4364                                 param.fp_comp_neg_flags = param.fp_comp_flags;
4365                                 param.fp_comp_flags = flags;
4366                         }
4367                         break;
4368                 case LFS_COMP_START_OPT:
4369                         if (optarg[0] == '+') {
4370                                 param.fp_comp_start_sign = -1;
4371                                 optarg++;
4372                         } else if (optarg[0] == '-') {
4373                                 param.fp_comp_start_sign =  1;
4374                                 optarg++;
4375                         }
4376
4377                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
4378                                               &param.fp_comp_start_units, 0);
4379                         if (rc) {
4380                                 fprintf(stderr, "error: bad component start "
4381                                         "'%s'\n", optarg);
4382                                 goto err;
4383                         }
4384                         param.fp_check_comp_start = 1;
4385                         param.fp_exclude_comp_start = !!neg_opt;
4386                         break;
4387                 case LFS_MIRROR_STATE_OPT:
4388                         rc = mirror_str2state(optarg, &param.fp_mirror_state,
4389                                               &param.fp_mirror_neg_state);
4390                         if (rc) {
4391                                 fprintf(stderr,
4392                                         "error: bad mirrored file state '%s'\n",
4393                                         optarg);
4394                                 goto err;
4395                         }
4396                         param.fp_check_mirror_state = 1;
4397                         if (neg_opt) {
4398                                 __u16 state = param.fp_mirror_neg_state;
4399                                 param.fp_mirror_neg_state =
4400                                         param.fp_mirror_state;
4401                                 param.fp_mirror_state = state;
4402                         }
4403                         break;
4404                 case 'c':
4405                         if (optarg[0] == '+') {
4406                                 param.fp_stripe_count_sign = -1;
4407                                 optarg++;
4408                         } else if (optarg[0] == '-') {
4409                                 param.fp_stripe_count_sign =  1;
4410                                 optarg++;
4411                         }
4412
4413                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
4414                         if (*endptr != '\0') {
4415                                 fprintf(stderr,"error: bad stripe_count '%s'\n",
4416                                         optarg);
4417                                 ret = -1;
4418                                 goto err;
4419                         }
4420                         param.fp_check_stripe_count = 1;
4421                         param.fp_exclude_stripe_count = !!neg_opt;
4422                         break;
4423                 case 'D':
4424                         param.fp_max_depth = strtol(optarg, 0, 0);
4425                         break;
4426                 case 'E':
4427                         if (optarg[0] == '+') {
4428                                 param.fp_comp_end_sign = -1;
4429                                 optarg++;
4430                         } else if (optarg[0] == '-') {
4431                                 param.fp_comp_end_sign =  1;
4432                                 optarg++;
4433                         }
4434
4435                         if (arg_is_eof(optarg)) {
4436                                 param.fp_comp_end = LUSTRE_EOF;
4437                                 param.fp_comp_end_units = 1;
4438                                 rc = 0;
4439                         } else {
4440                                 rc = llapi_parse_size(optarg,
4441                                                 &param.fp_comp_end,
4442                                                 &param.fp_comp_end_units, 0);
4443                         }
4444                         if (rc) {
4445                                 fprintf(stderr, "error: bad component end "
4446                                         "'%s'\n", optarg);
4447                                 goto err;
4448                         }
4449                         param.fp_check_comp_end = 1;
4450                         param.fp_exclude_comp_end = !!neg_opt;
4451                         break;
4452                 case LFS_LAYOUT_FOREIGN_OPT: {
4453                         /* all types by default */
4454                         uint32_t type = LU_FOREIGN_TYPE_UNKNOWN;
4455
4456                         if (optarg != NULL) {
4457                                 /* check pure numeric */
4458                                 type = strtoul(optarg, &endptr, 0);
4459                                 if (*endptr) {
4460                                         /* check name */
4461                                         type = check_foreign_type_name(optarg);
4462                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
4463                                                 fprintf(stderr,
4464                                                         "%s %s: unknown foreign type '%s'\n",
4465                                                         progname, argv[0],
4466                                                         optarg);
4467                                                 return CMD_HELP;
4468                                         }
4469                                 }
4470                         }
4471                         param.fp_foreign_type = type;
4472                         param.fp_check_foreign = 1;
4473                         param.fp_exclude_foreign = !!neg_opt;
4474                         break;
4475                 }
4476                 case LFS_NEWERXY_OPT: {
4477                         char x = 'm';
4478                         char y = 'm';
4479                         int xidx;
4480                         int negidx;
4481                         time_t *newery;
4482                         time_t ref = time(NULL);
4483
4484                         /* no need to check bad options, they won't get here */
4485                         if (strlen(long_opts[optidx].name) == 7) {
4486                                 x = long_opts[optidx].name[5];
4487                                 y = long_opts[optidx].name[6];
4488                         }
4489
4490                         if (y == 't') {
4491                                 static const char *const fmts[] = {
4492                                         "%Y-%m-%d %H:%M:%S",
4493                                         "%Y-%m-%d %H:%M",
4494                                         "%Y-%m-%d",
4495                                         "%H:%M:%S", /* sometime today */
4496                                         "%H:%M",
4497                                         "@%s",
4498                                         "%s",
4499                                         NULL };
4500                                 struct tm tm;
4501                                 bool found = false;
4502                                 int i;
4503
4504                                 for (i = 0; fmts[i] != NULL; i++) {
4505                                         char *ptr;
4506
4507                                         /* Init for times relative to today */
4508                                         if (strncmp(fmts[i], "%H", 2) == 0)
4509                                                 localtime_r(&ref, &tm);
4510                                         else
4511                                                 memset(&tm, 0, sizeof(tm));
4512                                         ptr = strptime(optarg, fmts[i], &tm);
4513                                         /* Skip spaces */
4514                                         while (ptr && isspace(*ptr))
4515                                                 ptr++;
4516                                         if (ptr == optarg + strlen(optarg)) {
4517                                                 found = true;
4518                                                 break;
4519                                         }
4520                                 }
4521
4522                                 if (!found) {
4523                                         fprintf(stderr,
4524                                                 "%s: invalid time '%s'\n",
4525                                                 progname, optarg);
4526                                         fprintf(stderr,
4527                                                 "supported formats are:\n  ");
4528                                         for (i = 0; fmts[i] != NULL; i++)
4529                                                 fprintf(stderr, "'%s', ",
4530                                                         fmts[i]);
4531                                         fprintf(stderr, "\n");
4532                                         ret = -EINVAL;
4533                                         goto err;
4534                                 }
4535
4536                                 ref = mktime(&tm);
4537                         } else {
4538                                 struct stat statbuf;
4539
4540                                 if (stat(optarg, &statbuf) < 0) {
4541                                         fprintf(stderr,
4542                                                 "%s: cannot stat file '%s': %s\n",
4543                                                 progname, optarg,
4544                                                 strerror(errno));
4545                                         ret = -errno;
4546                                         goto err;
4547                                 }
4548
4549                                 switch (y) {
4550                                 case 'a':
4551                                         ref = statbuf.st_atime;
4552                                         break;
4553                                 case 'm':
4554                                         ref = statbuf.st_mtime;
4555                                         break;
4556                                 case 'c':
4557                                         ref = statbuf.st_ctime;
4558                                         break;
4559                                 default:
4560                                         fprintf(stderr,
4561                                                 "%s: invalid Y argument: '%c'\n",
4562                                                 progname, x);
4563                                         ret = -EINVAL;
4564                                         goto err;
4565                                 }
4566                         }
4567
4568                         switch (x) {
4569                         case 'a':
4570                                 xidx = NEWERXY_ATIME;
4571                                 break;
4572                         case 'm':
4573                                 xidx = NEWERXY_MTIME;
4574                                 break;
4575                         case 'c':
4576                                 xidx = NEWERXY_CTIME;
4577                                 break;
4578                         default:
4579                                 fprintf(stderr,
4580                                         "%s: invalid X argument: '%c'\n",
4581                                         progname, x);
4582                                 ret = -EINVAL;
4583                                 goto err;
4584                         }
4585
4586                         negidx = !!neg_opt;
4587                         newery = &param.fp_newery[xidx][negidx];
4588
4589                         if (*newery == 0) {
4590                                 *newery = ref;
4591                         } else {
4592                                 if (negidx)
4593                                         *newery = *newery > ref ? ref : *newery;
4594                                 else
4595                                         *newery = *newery > ref ? *newery : ref;
4596                         }
4597                         param.fp_newerxy = 1;
4598                         break;
4599                 }
4600                 case 'g':
4601                 case 'G':
4602                         rc = name2gid(&param.fp_gid, optarg);
4603                         if (rc) {
4604                                 param.fp_gid = strtoul(optarg, &endptr, 10);
4605                                 if (*endptr != '\0') {
4606                                         fprintf(stderr, "Group/GID: %s cannot "
4607                                                 "be found.\n", optarg);
4608                                         ret = -1;
4609                                         goto err;
4610                                 }
4611                         }
4612                         param.fp_exclude_gid = !!neg_opt;
4613                         param.fp_check_gid = 1;
4614                         break;
4615                 case 'H':
4616                         param.fp_hash_type = check_hashtype(optarg);
4617                         if (param.fp_hash_type == 0) {
4618                                 fprintf(stderr, "error: bad hash_type '%s'\n",
4619                                         optarg);
4620                                 ret = -1;
4621                                 goto err;
4622                         }
4623                         param.fp_check_hash_type = 1;
4624                         param.fp_exclude_hash_type = !!neg_opt;
4625                         break;
4626                 case 'l':
4627                         param.fp_lazy = 1;
4628                         break;
4629                 case 'L':
4630                         ret = name2layout(&param.fp_layout, optarg);
4631                         if (ret)
4632                                 goto err;
4633                         param.fp_exclude_layout = !!neg_opt;
4634                         param.fp_check_layout = 1;
4635                         break;
4636                 case 'u':
4637                 case 'U':
4638                         rc = name2uid(&param.fp_uid, optarg);
4639                         if (rc) {
4640                                 param.fp_uid = strtoul(optarg, &endptr, 10);
4641                                 if (*endptr != '\0') {
4642                                         fprintf(stderr, "User/UID: %s cannot "
4643                                                 "be found.\n", optarg);
4644                                         ret = -1;
4645                                         goto err;
4646                                 }
4647                         }
4648                         param.fp_exclude_uid = !!neg_opt;
4649                         param.fp_check_uid = 1;
4650                         break;
4651                 case 'n':
4652                         param.fp_pattern = (char *)optarg;
4653                         param.fp_exclude_pattern = !!neg_opt;
4654                         break;
4655                 case 'N':
4656                         if (optarg[0] == '+') {
4657                                 param.fp_mirror_count_sign = -1;
4658                                 optarg++;
4659                         } else if (optarg[0] == '-') {
4660                                 param.fp_mirror_count_sign =  1;
4661                                 optarg++;
4662                         }
4663
4664                         param.fp_mirror_count = strtoul(optarg, &endptr, 0);
4665                         if (*endptr != '\0') {
4666                                 fprintf(stderr,
4667                                         "error: bad mirror count '%s'\n",
4668                                         optarg);
4669                                 goto err;
4670                         }
4671                         param.fp_check_mirror_count = 1;
4672                         param.fp_exclude_mirror_count = !!neg_opt;
4673                         break;
4674                 case 'm':
4675                 case 'i':
4676                 case 'O': {
4677                         char *buf, *token, *next, *p;
4678                         int len = 1;
4679                         void *tmp;
4680
4681                         buf = strdup(optarg);
4682                         if (buf == NULL) {
4683                                 ret = -ENOMEM;
4684                                 goto err;
4685                         }
4686
4687                         param.fp_exclude_obd = !!neg_opt;
4688
4689                         token = buf;
4690                         while (token && *token) {
4691                                 token = strchr(token, ',');
4692                                 if (token) {
4693                                         len++;
4694                                         token++;
4695                                 }
4696                         }
4697                         if (c == 'm') {
4698                                 param.fp_exclude_mdt = !!neg_opt;
4699                                 param.fp_num_alloc_mdts += len;
4700                                 tmp = realloc(param.fp_mdt_uuid,
4701                                               param.fp_num_alloc_mdts *
4702                                               sizeof(*param.fp_mdt_uuid));
4703                                 if (tmp == NULL) {
4704                                         ret = -ENOMEM;
4705                                         goto err_free;
4706                                 }
4707
4708                                 param.fp_mdt_uuid = tmp;
4709                         } else {
4710                                 param.fp_exclude_obd = !!neg_opt;
4711                                 param.fp_num_alloc_obds += len;
4712                                 tmp = realloc(param.fp_obd_uuid,
4713                                               param.fp_num_alloc_obds *
4714                                               sizeof(*param.fp_obd_uuid));
4715                                 if (tmp == NULL) {
4716                                         ret = -ENOMEM;
4717                                         goto err_free;
4718                                 }
4719
4720                                 param.fp_obd_uuid = tmp;
4721                         }
4722                         for (token = buf; token && *token; token = next) {
4723                                 struct obd_uuid *puuid;
4724                                 if (c == 'm') {
4725                                         puuid =
4726                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
4727                                 } else {
4728                                         puuid =
4729                                         &param.fp_obd_uuid[param.fp_num_obds++];
4730                                 }
4731                                 p = strchr(token, ',');
4732                                 next = 0;
4733                                 if (p) {
4734                                         *p = 0;
4735                                         next = p+1;
4736                                 }
4737
4738                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
4739                                         ret = -E2BIG;
4740                                         goto err_free;
4741                                 }
4742
4743                                 strncpy(puuid->uuid, token,
4744                                         sizeof(puuid->uuid));
4745                         }
4746 err_free:
4747                         if (buf)
4748                                 free(buf);
4749                         break;
4750                 }
4751 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 18, 53, 0)
4752                 case 'p':
4753 #endif
4754                 case LFS_POOL_OPT:
4755                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
4756                                 fprintf(stderr,
4757                                         "Pool name %s is too long (max %d)\n",
4758                                         optarg, LOV_MAXPOOLNAME);
4759                                 ret = -1;
4760                                 goto err;
4761                         }
4762                         /*
4763                          * We do check for empty pool because empty pool
4764                          * is used to find V1 LOV attributes
4765                          */
4766                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
4767                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
4768                         param.fp_exclude_pool = !!neg_opt;
4769                         param.fp_check_pool = 1;
4770                         break;
4771 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 14, 53, 0)
4772                 case 'p': /* want this for --pool, to match getstripe/find */
4773                         fprintf(stderr,
4774                                 "warning: -p deprecated, use --print0 or -0\n");
4775 #endif
4776                 case '0':
4777                         param.fp_zero_end = 1;
4778                         break;
4779                 case 'P': /* we always print, this option is a no-op */
4780                         break;
4781                 case LFS_PROJID_OPT:
4782                         rc = name2projid(&param.fp_projid, optarg);
4783                         if (rc) {
4784                                 param.fp_projid = strtoul(optarg, &endptr, 10);
4785                                 if (*endptr != '\0') {
4786                                         fprintf(stderr,
4787                                                 "Invalid project ID: %s",
4788                                                 optarg);
4789                                         ret = -1;
4790                                         goto err;
4791                                 }
4792                         }
4793                         param.fp_exclude_projid = !!neg_opt;
4794                         param.fp_check_projid = 1;
4795                         break;
4796                 case 's':
4797                         if (optarg[0] == '+') {
4798                                 param.fp_size_sign = -1;
4799                                 optarg++;
4800                         } else if (optarg[0] == '-') {
4801                                 param.fp_size_sign =  1;
4802                                 optarg++;
4803                         }
4804
4805                         ret = llapi_parse_size(optarg, &param.fp_size,
4806                                                &param.fp_size_units, 0);
4807                         if (ret) {
4808                                 fprintf(stderr, "error: bad file size '%s'\n",
4809                                         optarg);
4810                                 goto err;
4811                         }
4812                         param.fp_check_size = 1;
4813                         param.fp_exclude_size = !!neg_opt;
4814                         break;
4815                 case 'S':
4816                         if (optarg[0] == '+') {
4817                                 param.fp_stripe_size_sign = -1;
4818                                 optarg++;
4819                         } else if (optarg[0] == '-') {
4820                                 param.fp_stripe_size_sign =  1;
4821                                 optarg++;
4822                         }
4823
4824                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
4825                                                &param.fp_stripe_size_units, 0);
4826                         if (ret) {
4827                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
4828                                         optarg);
4829                                 goto err;
4830                         }
4831                         param.fp_check_stripe_size = 1;
4832                         param.fp_exclude_stripe_size = !!neg_opt;
4833                         break;
4834                 case 't':
4835                         param.fp_exclude_type = !!neg_opt;
4836                         switch (optarg[0]) {
4837                         case 'b':
4838                                 param.fp_type = S_IFBLK;
4839                                 break;
4840                         case 'c':
4841                                 param.fp_type = S_IFCHR;
4842                                 break;
4843                         case 'd':
4844                                 param.fp_type = S_IFDIR;
4845                                 break;
4846                         case 'f':
4847                                 param.fp_type = S_IFREG;
4848                                 break;
4849                         case 'l':
4850                                 param.fp_type = S_IFLNK;
4851                                 break;
4852                         case 'p':
4853                                 param.fp_type = S_IFIFO;
4854                                 break;
4855                         case 's':
4856                                 param.fp_type = S_IFSOCK;
4857                                 break;
4858                         default:
4859                                 fprintf(stderr, "error: %s: bad type '%s'\n",
4860                                         argv[0], optarg);
4861                                 ret = CMD_HELP;
4862                                 goto err;
4863                         };
4864                         break;
4865                 case 'T':
4866                         if (optarg[0] == '+') {
4867                                 param.fp_mdt_count_sign = -1;
4868                                 optarg++;
4869                         } else if (optarg[0] == '-') {
4870                                 param.fp_mdt_count_sign =  1;
4871                                 optarg++;
4872                         }
4873
4874                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
4875                         if (*endptr != '\0') {
4876                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
4877                                         optarg);
4878                                 ret = -1;
4879                                 goto err;
4880                         }
4881                         param.fp_check_mdt_count = 1;
4882                         param.fp_exclude_mdt_count = !!neg_opt;
4883                         break;
4884                 case 'z':
4885                         if (optarg[0] == '+') {
4886                                 param.fp_ext_size_sign = -1;
4887                                 optarg++;
4888                         } else if (optarg[0] == '-') {
4889                                 param.fp_ext_size_sign =  1;
4890                                 optarg++;
4891                         }
4892
4893                         ret = llapi_parse_size(optarg, &param.fp_ext_size,
4894                                                &param.fp_ext_size_units, 0);
4895                         if (ret) {
4896                                 fprintf(stderr, "error: bad ext-size '%s'\n",
4897                                         optarg);
4898                                 goto err;
4899                         }
4900                         param.fp_ext_size /= SEL_UNIT_SIZE;
4901                         param.fp_ext_size_units /= SEL_UNIT_SIZE;
4902                         param.fp_check_ext_size = 1;
4903                         param.fp_exclude_ext_size = !!neg_opt;
4904                         break;
4905                 default:
4906                         ret = CMD_HELP;
4907                         goto err;
4908                 };
4909         }
4910
4911         if (pathstart == -1) {
4912                 fprintf(stderr, "error: %s: no filename|pathname\n",
4913                         argv[0]);
4914                 ret = CMD_HELP;
4915                 goto err;
4916         } else if (pathend == -1) {
4917                 /* no options */
4918                 pathend = argc;
4919         }
4920
4921         do {
4922                 rc = llapi_find(argv[pathstart], &param);
4923                 if (rc && !ret) {
4924                         ret = rc;
4925                         pathbad = pathstart;
4926                 }
4927         } while (++pathstart < pathend);
4928
4929         if (ret)
4930                 fprintf(stderr, "%s: failed for '%s': %s\n",
4931                         progname, argv[pathbad], strerror(-rc));
4932
4933 err:
4934         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
4935                 free(param.fp_obd_uuid);
4936
4937         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
4938                 free(param.fp_mdt_uuid);
4939
4940         return ret;
4941 }
4942
4943 static int lfs_getstripe_internal(int argc, char **argv,
4944                                   struct find_param *param)
4945 {
4946         struct option long_opts[] = {
4947 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
4948 /* find { .val = 'b',   .name = "blocks",       .has_arg = required_argument }*/
4949         { .val = LFS_COMP_COUNT_OPT,
4950                         .name = "comp-count",   .has_arg = no_argument },
4951         { .val = LFS_COMP_COUNT_OPT,
4952                 .name = "component-count",      .has_arg = no_argument },
4953         { .val = LFS_COMP_FLAGS_OPT,
4954                         .name = "comp-flags",   .has_arg = optional_argument },
4955         { .val = LFS_COMP_FLAGS_OPT,
4956                 .name = "component-flags",      .has_arg = optional_argument },
4957         { .val = LFS_COMP_START_OPT,
4958                         .name = "comp-start",   .has_arg = optional_argument },
4959         { .val = LFS_COMP_START_OPT,
4960                 .name = "component-start",      .has_arg = optional_argument },
4961         { .val = LFS_MIRROR_INDEX_OPT,
4962                 .name = "mirror-index",         .has_arg = required_argument },
4963         { .val = LFS_MIRROR_ID_OPT,
4964                 .name = "mirror-id",            .has_arg = required_argument },
4965         { .val = 'c',   .name = "stripe-count", .has_arg = no_argument },
4966         { .val = 'c',   .name = "stripe_count", .has_arg = no_argument },
4967 /* find { .val = 'C',   .name = "ctime",        .has_arg = required_argument }*/
4968         { .val = 'd',   .name = "directory",    .has_arg = no_argument },
4969         { .val = 'D',   .name = "default",      .has_arg = no_argument },
4970         { .val = 'E',   .name = "comp-end",     .has_arg = optional_argument },
4971         { .val = 'E',   .name = "component-end", .has_arg = optional_argument },
4972         { .val = 'F',   .name = "fid",          .has_arg = no_argument },
4973         { .val = 'g',   .name = "generation",   .has_arg = no_argument },
4974 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
4975 /* dirstripe { .val = 'H', .name = "mdt-hash",  .has_arg = required_argument }*/
4976         { .val = 'i',   .name = "stripe-index", .has_arg = no_argument },
4977         { .val = 'i',   .name = "stripe_index", .has_arg = no_argument },
4978         { .val = 'I',   .name = "comp-id",      .has_arg = optional_argument },
4979         { .val = 'I',   .name = "component-id", .has_arg = optional_argument },
4980 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
4981         { .val = 'L',   .name = "layout",       .has_arg = no_argument },
4982         { .val = 'm',   .name = "mdt",          .has_arg = no_argument },
4983         { .val = 'm',   .name = "mdt-index",    .has_arg = no_argument },
4984         { .val = 'm',   .name = "mdt_index",    .has_arg = no_argument },
4985 /* find { .val = 'M',   .name = "mtime",        .has_arg = required_argument }*/
4986 /* find { .val = 'n',   .name = "name",         .has_arg = required_argument }*/
4987         { .val = 'N',   .name = "mirror-count", .has_arg = no_argument },
4988         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
4989         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
4990         { .val = 'p',   .name = "pool",         .has_arg = no_argument },
4991 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
4992         { .val = 'q',   .name = "quiet",        .has_arg = no_argument },
4993         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
4994         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
4995         { .val = 'S',   .name = "stripe-size",  .has_arg = no_argument },
4996         { .val = 'S',   .name = "stripe_size",  .has_arg = no_argument },
4997 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
4998 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
4999 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
5000 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
5001         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
5002         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
5003         { .val = 'z',   .name = "extension-size", .has_arg = no_argument },
5004         { .val = 'z',   .name = "ext-size",     .has_arg = no_argument },
5005         { .name = NULL } };
5006         int c, rc;
5007         int neg_opt = 0;
5008         int pathstart = -1, pathend = -1;
5009         int isoption;
5010         char *end, *tmp;
5011
5012         while ((c = getopt_long(argc, argv,
5013                         "-cdDE::FghiI::LmMNoO:pqrRsSvyz",
5014                         long_opts, NULL)) != -1) {
5015                 if (neg_opt)
5016                         --neg_opt;
5017
5018                 /* '!' is part of option */
5019                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
5020                 if (!isoption && pathend != -1) {
5021                         fprintf(stderr,
5022                                 "error: %s: filename|dirname must either precede options or follow options\n",
5023                                 argv[0]);
5024                         return CMD_HELP;
5025                 }
5026                 if (!isoption && pathstart == -1)
5027                         pathstart = optind - 1;
5028                 if (isoption && pathstart != -1 && pathend == -1)
5029                         pathend = optind - 2;
5030
5031                 switch (c) {
5032                 case 1:
5033                         /* unknown: opt is "!" */
5034                         if (strcmp(optarg, "!") == 0)
5035                                 neg_opt = 2;
5036                         break;
5037                 case 'c':
5038                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5039                                 param->fp_verbose |= VERBOSE_COUNT;
5040                                 param->fp_max_depth = 0;
5041                         }
5042                         break;
5043                 case LFS_COMP_COUNT_OPT:
5044                         param->fp_verbose |= VERBOSE_COMP_COUNT;
5045                         param->fp_max_depth = 0;
5046                         break;
5047                 case LFS_COMP_FLAGS_OPT:
5048                         if (optarg != NULL) {
5049                                 rc = comp_str2flags(optarg,
5050                                                     &param->fp_comp_flags,
5051                                                     &param->fp_comp_neg_flags);
5052                                 if (rc != 0) {
5053                                         fprintf(stderr, "error: %s bad "
5054                                                 "component flags '%s'.\n",
5055                                                 argv[0], optarg);
5056                                         return CMD_HELP;
5057                                 }
5058                                 param->fp_check_comp_flags = 1;
5059                         } else {
5060                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
5061                                 param->fp_max_depth = 0;
5062                         }
5063                         break;
5064                 case LFS_COMP_START_OPT:
5065                         if (optarg != NULL) {
5066                                 tmp = optarg;
5067                                 if (tmp[0] == '+') {
5068                                         param->fp_comp_start_sign = -1;
5069                                         tmp++;
5070                                 } else if (tmp[0] == '-') {
5071                                         param->fp_comp_start_sign = 1;
5072                                         tmp++;
5073                                 }
5074                                 rc = llapi_parse_size(tmp,
5075                                                 &param->fp_comp_start,
5076                                                 &param->fp_comp_start_units, 0);
5077                                 if (rc != 0) {
5078                                         fprintf(stderr, "error: %s bad "
5079                                                 "component start '%s'.\n",
5080                                                 argv[0], tmp);
5081                                         return CMD_HELP;
5082                                 } else {
5083                                         param->fp_check_comp_start = 1;
5084                                 }
5085                         } else {
5086                                 param->fp_verbose |= VERBOSE_COMP_START;
5087                                 param->fp_max_depth = 0;
5088                         }
5089                         break;
5090                 case LFS_MIRROR_INDEX_OPT:
5091                         if (optarg[0] == '+') {
5092                                 param->fp_mirror_index_sign = -1;
5093                                 optarg++;
5094                         } else if (optarg[0] == '-') {
5095                                 param->fp_mirror_index_sign = 1;
5096                                 optarg++;
5097                         }
5098
5099                         param->fp_mirror_index = strtoul(optarg, &end, 0);
5100                         if (*end != '\0' || (param->fp_mirror_index == 0 &&
5101                             param->fp_mirror_index_sign == 0 && neg_opt == 0)) {
5102                                 fprintf(stderr,
5103                                         "%s %s: invalid mirror index '%s'\n",
5104                                         progname, argv[0], optarg);
5105                                 return CMD_HELP;
5106                         }
5107                         if (param->fp_mirror_id != 0) {
5108                                 fprintf(stderr,
5109                                         "%s %s: can't specify both mirror index and mirror ID\n",
5110                                         progname, argv[0]);
5111                                 return CMD_HELP;
5112                         }
5113                         param->fp_check_mirror_index = 1;
5114                         param->fp_exclude_mirror_index = !!neg_opt;
5115                         break;
5116                 case LFS_MIRROR_ID_OPT:
5117                         if (optarg[0] == '+') {
5118                                 param->fp_mirror_id_sign = -1;
5119                                 optarg++;
5120                         } else if (optarg[0] == '-') {
5121                                 param->fp_mirror_id_sign = 1;
5122                                 optarg++;
5123                         }
5124
5125                         param->fp_mirror_id = strtoul(optarg, &end, 0);
5126                         if (*end != '\0' || (param->fp_mirror_id == 0 &&
5127                             param->fp_mirror_id_sign == 0 && neg_opt == 0)) {
5128                                 fprintf(stderr,
5129                                         "%s %s: invalid mirror ID '%s'\n",
5130                                         progname, argv[0], optarg);
5131                                 return CMD_HELP;
5132                         }
5133                         if (param->fp_mirror_index != 0) {
5134                                 fprintf(stderr,
5135                                         "%s %s: can't specify both mirror index and mirror ID\n",
5136                                         progname, argv[0]);
5137                                 return CMD_HELP;
5138                         }
5139                         param->fp_check_mirror_id = 1;
5140                         param->fp_exclude_mirror_id = !!neg_opt;
5141                         break;
5142                 case 'd':
5143                         param->fp_max_depth = 0;
5144                         break;
5145                 case 'D':
5146                         param->fp_get_default_lmv = 1;
5147                         break;
5148                 case 'E':
5149                         if (optarg != NULL) {
5150                                 tmp = optarg;
5151                                 if (tmp[0] == '+') {
5152                                         param->fp_comp_end_sign = -1;
5153                                         tmp++;
5154                                 } else if (tmp[0] == '-') {
5155                                         param->fp_comp_end_sign = 1;
5156                                         tmp++;
5157                                 }
5158
5159                                 if (arg_is_eof(tmp)) {
5160                                         param->fp_comp_end = LUSTRE_EOF;
5161                                         param->fp_comp_end_units = 1;
5162                                         rc = 0;
5163                                 } else {
5164                                         rc = llapi_parse_size(tmp,
5165                                                 &param->fp_comp_end,
5166                                                 &param->fp_comp_end_units, 0);
5167                                 }
5168                                 if (rc != 0) {
5169                                         fprintf(stderr, "error: %s bad "
5170                                                 "component end '%s'.\n",
5171                                                 argv[0], tmp);
5172                                         return CMD_HELP;
5173                                 }
5174                                 param->fp_check_comp_end = 1;
5175                         } else {
5176                                 param->fp_verbose |= VERBOSE_COMP_END;
5177                                 param->fp_max_depth = 0;
5178                         }
5179                         break;
5180                 case 'F':
5181                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5182                                 param->fp_verbose |= VERBOSE_DFID;
5183                                 param->fp_max_depth = 0;
5184                         }
5185                         break;
5186                 case 'g':
5187                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5188                                 param->fp_verbose |= VERBOSE_GENERATION;
5189                                 param->fp_max_depth = 0;
5190                         }
5191                         break;
5192                 case 'i':
5193                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5194                                 param->fp_verbose |= VERBOSE_STRIPE_OFFSET;
5195                                 param->fp_max_depth = 0;
5196                         }
5197                         break;
5198                 case 'I':
5199                         if (optarg != NULL) {
5200                                 param->fp_comp_id = strtoul(optarg, &end, 0);
5201                                 if (*end != '\0' || param->fp_comp_id == 0 ||
5202                                     param->fp_comp_id > LCME_ID_MAX) {
5203                                         fprintf(stderr, "error: %s bad "
5204                                                 "component id '%s'\n",
5205                                                 argv[0], optarg);
5206                                         return CMD_HELP;
5207                                 } else {
5208                                         param->fp_check_comp_id = 1;
5209                                 }
5210                         } else {
5211                                 param->fp_max_depth = 0;
5212                                 param->fp_verbose |= VERBOSE_COMP_ID;
5213                         }
5214                         break;
5215                 case 'L':
5216                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5217                                 param->fp_verbose |= VERBOSE_PATTERN;
5218                                 param->fp_max_depth = 0;
5219                         }
5220                         break;
5221 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
5222                 case 'M':
5223                         fprintf(stderr, "warning: '-M' deprecated"
5224                                 ", use '--mdt-index' or '-m' instead\n");
5225 #endif
5226                 case 'm':
5227                         if (!(param->fp_verbose & VERBOSE_DETAIL))
5228                                 param->fp_max_depth = 0;
5229                         param->fp_verbose |= VERBOSE_MDTINDEX;
5230                         break;
5231                 case 'N':
5232                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5233                                 param->fp_verbose |= VERBOSE_MIRROR_COUNT;
5234                                 param->fp_max_depth = 0;
5235                         }
5236                         break;
5237                 case 'O':
5238                         if (param->fp_obd_uuid) {
5239                                 fprintf(stderr,
5240                                         "error: %s: only one obduuid allowed",
5241                                         argv[0]);
5242                                 return CMD_HELP;
5243                         }
5244                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
5245                         break;
5246                 case 'p':
5247                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5248                                 param->fp_verbose |= VERBOSE_POOL;
5249                                 param->fp_max_depth = 0;
5250                         }
5251                         break;
5252                 case 'q':
5253                         param->fp_quiet++;
5254                         break;
5255                 case 'r':
5256                         param->fp_recursive = 1;
5257                         break;
5258                 case 'R':
5259                         param->fp_raw = 1;
5260                         break;
5261                 case 'S':
5262                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5263                                 param->fp_verbose |= VERBOSE_STRIPE_SIZE;
5264                                 param->fp_max_depth = 0;
5265                         }
5266                         break;
5267                 case 'v':
5268                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
5269                         break;
5270                 case 'y':
5271                         param->fp_yaml = 1;
5272                         break;
5273                 case 'z':
5274                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5275                                 param->fp_verbose |= VERBOSE_EXT_SIZE;
5276                                 param->fp_max_depth = 0;
5277                         }
5278                         break;
5279                 default:
5280                         return CMD_HELP;
5281                 }
5282         }
5283
5284         if (pathstart == -1) {
5285                 fprintf(stderr, "error: %s: no filename|pathname\n",
5286                                 argv[0]);
5287                 return CMD_HELP;
5288         } else if (pathend == -1) {
5289                 /* no options */
5290                 pathend = argc;
5291         }
5292
5293         if (pathend > argc)
5294                 return CMD_HELP;
5295
5296         if (param->fp_recursive)
5297                 param->fp_max_depth = -1;
5298         else if (param->fp_verbose & VERBOSE_DETAIL)
5299                 param->fp_max_depth = 1;
5300
5301         if (!param->fp_verbose)
5302                 param->fp_verbose = VERBOSE_DEFAULT;
5303         if (param->fp_quiet)
5304                 param->fp_verbose = VERBOSE_OBJID;
5305
5306         do {
5307                 rc = llapi_getstripe(argv[pathstart], param);
5308         } while (++pathstart < pathend && !rc);
5309
5310         if (rc)
5311                 fprintf(stderr, "error: %s failed for %s.\n",
5312                         argv[0], argv[optind - 1]);
5313         return rc;
5314 }
5315
5316 static int lfs_tgts(int argc, char **argv)
5317 {
5318         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
5319         struct find_param param;
5320         int index = 0, rc=0;
5321
5322         if (argc > 2)
5323                 return CMD_HELP;
5324
5325         if (argc == 2 && !realpath(argv[1], path)) {
5326                 rc = -errno;
5327                 fprintf(stderr, "error: invalid path '%s': %s\n",
5328                         argv[1], strerror(-rc));
5329                 return rc;
5330         }
5331
5332         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
5333                 /* Check if we have a mount point */
5334                 if (mntdir[0] == '\0')
5335                         continue;
5336
5337                 memset(&param, 0, sizeof(param));
5338                 if (!strcmp(argv[0], "mdts"))
5339                         param.fp_get_lmv = 1;
5340
5341                 rc = llapi_ostlist(mntdir, &param);
5342                 if (rc) {
5343                         fprintf(stderr, "error: %s: failed on %s\n",
5344                                 argv[0], mntdir);
5345                 }
5346                 if (path[0] != '\0')
5347                         break;
5348                 memset(mntdir, 0, PATH_MAX);
5349         }
5350
5351         return rc;
5352 }
5353
5354 static int lfs_getstripe(int argc, char **argv)
5355 {
5356         struct find_param param = { 0 };
5357
5358         param.fp_max_depth = 1;
5359         return lfs_getstripe_internal(argc, argv, &param);
5360 }
5361
5362 /* functions */
5363 static int lfs_getdirstripe(int argc, char **argv)
5364 {
5365         struct find_param param = { 0 };
5366         struct option long_opts[] = {
5367         { .val = 'c',   .name = "mdt-count",    .has_arg = no_argument },
5368         { .val = 'D',   .name = "default",      .has_arg = no_argument },
5369         { .val = 'H',   .name = "mdt-hash",     .has_arg = no_argument },
5370         { .val = 'i',   .name = "mdt-index",    .has_arg = no_argument },
5371         { .val = 'm',   .name = "mdt-index",    .has_arg = no_argument },
5372         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
5373         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
5374         { .val = 'T',   .name = "mdt-count",    .has_arg = no_argument },
5375         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
5376         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
5377         { .name = NULL } };
5378         int c, rc;
5379
5380         param.fp_get_lmv = 1;
5381
5382         while ((c = getopt_long(argc, argv,
5383                                 "cDHimO:rtTvy", long_opts, NULL)) != -1)
5384         {
5385                 switch (c) {
5386                 case 'c':
5387                 case 'T':
5388                         param.fp_verbose |= VERBOSE_COUNT;
5389                         break;
5390                 case 'D':
5391                         param.fp_get_default_lmv = 1;
5392                         break;
5393                 case 'i':
5394                 case 'm':
5395                         param.fp_verbose |= VERBOSE_STRIPE_OFFSET;
5396                         break;
5397 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
5398                 case 't':
5399                         fprintf(stderr, "warning: '-t' deprecated, "
5400                                 "use '--mdt-hash' or '-H' instead\n");
5401 #endif
5402                 case 'H':
5403                         param.fp_verbose |= VERBOSE_HASH_TYPE;
5404                         break;
5405                 case 'O':
5406                         if (param.fp_obd_uuid) {
5407                                 fprintf(stderr,
5408                                         "error: %s: only one obduuid allowed",
5409                                         argv[0]);
5410                                 return CMD_HELP;
5411                         }
5412                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
5413                         break;
5414                 case 'r':
5415                         param.fp_recursive = 1;
5416                         break;
5417                 case 'v':
5418                         param.fp_verbose |= VERBOSE_DETAIL;
5419                         break;
5420                 case 'y':
5421                         param.fp_yaml = 1;
5422                         break;
5423                 default:
5424                         fprintf(stderr, "%s %s: unrecognized option '%s'\n",
5425                                 progname, argv[0], argv[optind - 1]);
5426                         return CMD_HELP;
5427                 }
5428         }
5429
5430         if (optind >= argc)
5431                 return CMD_HELP;
5432
5433         if (param.fp_recursive)
5434                 param.fp_max_depth = -1;
5435
5436         if (!param.fp_verbose)
5437                 param.fp_verbose = VERBOSE_DEFAULT;
5438
5439         do {
5440                 rc = llapi_getstripe(argv[optind], &param);
5441         } while (++optind < argc && !rc);
5442
5443         if (rc)
5444                 fprintf(stderr, "error: %s failed for %s.\n",
5445                         argv[0], argv[optind - 1]);
5446         return rc;
5447 }
5448
5449 enum mntdf_flags {
5450         MNTDF_INODES    = 0x0001,
5451         MNTDF_COOKED    = 0x0002,
5452         MNTDF_LAZY      = 0x0004,
5453         MNTDF_VERBOSE   = 0x0008,
5454         MNTDF_SHOW      = 0x0010,
5455 };
5456
5457 #define COOK(value)                                             \
5458 ({                                                              \
5459         int radix = 0;                                          \
5460         while (value > 1024) {                                  \
5461                 value /= 1024;                                  \
5462                 radix++;                                        \
5463         }                                                       \
5464         radix;                                                  \
5465 })
5466 #define UUF     "%-20s"
5467 #define CSF     "%11s"
5468 #define CDF     "%11llu"
5469 #define HDF     "%8.1f%c"
5470 #define RSF     "%4s"
5471 #define RDF     "%3d%%"
5472
5473 static inline int obd_statfs_ratio(const struct obd_statfs *st, bool inodes)
5474 {
5475         double avail, used, ratio = 0;
5476
5477         if (inodes) {
5478                 avail = st->os_ffree;
5479                 used = st->os_files - st->os_ffree;
5480         } else {
5481                 avail = st->os_bavail;
5482                 used = st->os_blocks - st->os_bfree;
5483         }
5484         if (avail + used > 0)
5485                 ratio = used / (used + avail) * 100;
5486
5487         /* Round up to match df(1) usage percentage */
5488         return (ratio - (int)ratio) > 0 ? (int)(ratio + 1) : (int)ratio;
5489 }
5490
5491 /* This is to identify various problem states for "lfs df" if .osn_err = true,
5492  * so only show flags reflecting those states by default. Informational states
5493  * are only shown with "-v" and use lower-case names to distinguish them.
5494  * UNUSED[12] were for "EROFS = 30" until 1.6 but are now available for use.
5495  */
5496 static struct obd_statfs_state_names {
5497         enum obd_statfs_state   osn_state;
5498         const char              osn_name;
5499         bool                    osn_err;
5500 } oss_names[] = {
5501         { .osn_state = OS_STATE_DEGRADED,    .osn_name = 'D', .osn_err = true },
5502         { .osn_state = OS_STATE_READONLY,    .osn_name = 'R', .osn_err = true },
5503         { .osn_state = OS_STATE_NOPRECREATE, .osn_name = 'N', .osn_err = true },
5504         { .osn_state = OS_STATE_UNUSED1,     .osn_name = '?', .osn_err = true },
5505         { .osn_state = OS_STATE_UNUSED2,     .osn_name = '?', .osn_err = true },
5506         { .osn_state = OS_STATE_ENOSPC,      .osn_name = 'S', .osn_err = true },
5507         { .osn_state = OS_STATE_ENOINO,      .osn_name = 'I', .osn_err = true },
5508         { .osn_state = OS_STATE_SUM,         .osn_name = 'a', /* aggregate */ },
5509         { .osn_state = OS_STATE_NONROT,      .osn_name = 'f', /* flash */     },
5510 };
5511
5512 static int showdf(char *mntdir, struct obd_statfs *stat,
5513                   char *uuid, enum mntdf_flags flags,
5514                   char *type, int index, int rc)
5515 {
5516         long long avail, used, total;
5517         int ratio = 0;
5518         char *suffix = "KMGTPEZY";
5519         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
5520         char tbuf[3 * sizeof(__u64)];
5521         char ubuf[3 * sizeof(__u64)];
5522         char abuf[3 * sizeof(__u64)];
5523         char rbuf[3 * sizeof(__u64)];
5524
5525         if (!uuid || !stat)
5526                 return -EINVAL;
5527
5528         switch (rc) {
5529         case 0:
5530                 if (flags & MNTDF_INODES) {
5531                         avail = stat->os_ffree;
5532                         used = stat->os_files - stat->os_ffree;
5533                         total = stat->os_files;
5534                 } else {
5535                         int shift = flags & MNTDF_COOKED ? 0 : 10;
5536
5537                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
5538                         used  = ((stat->os_blocks - stat->os_bfree) *
5539                                  stat->os_bsize) >> shift;
5540                         total = (stat->os_blocks * stat->os_bsize) >> shift;
5541                 }
5542
5543                 ratio = obd_statfs_ratio(stat, flags & MNTDF_INODES);
5544
5545                 if (flags & MNTDF_COOKED) {
5546                         int i;
5547                         double cook_val;
5548
5549                         cook_val = (double)total;
5550                         i = COOK(cook_val);
5551                         if (i > 0)
5552                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
5553                                          suffix[i - 1]);
5554                         else
5555                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
5556
5557                         cook_val = (double)used;
5558                         i = COOK(cook_val);
5559                         if (i > 0)
5560                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
5561                                          suffix[i - 1]);
5562                         else
5563                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
5564
5565                         cook_val = (double)avail;
5566                         i = COOK(cook_val);
5567                         if (i > 0)
5568                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
5569                                          suffix[i - 1]);
5570                         else
5571                                 snprintf(abuf, sizeof(abuf), CDF, avail);
5572                 } else {
5573                         snprintf(tbuf, sizeof(tbuf), CDF, total);
5574                         snprintf(ubuf, sizeof(tbuf), CDF, used);
5575                         snprintf(abuf, sizeof(tbuf), CDF, avail);
5576                 }
5577
5578                 sprintf(rbuf, RDF, ratio);
5579                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
5580                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
5581                 if (type)
5582                         printf("[%s:%d]", type, index);
5583
5584                 if (stat->os_state) {
5585                         uint32_t i;
5586
5587                         printf(" ");
5588                         for (i = 0; i < ARRAY_SIZE(oss_names); i++) {
5589                                 if (oss_names[i].osn_state & stat->os_state &&
5590                                     (oss_names[i].osn_err ||
5591                                      flags & MNTDF_VERBOSE))
5592                                         printf("%c", oss_names[i].osn_name);
5593                         }
5594                 }
5595
5596                 printf("\n");
5597                 break;
5598         case -ENODATA:
5599                 printf(UUF": inactive device\n", uuid);
5600                 break;
5601         default:
5602                 printf(UUF": %s\n", uuid, strerror(-rc));
5603                 break;
5604         }
5605
5606         return 0;
5607 }
5608
5609 struct ll_stat_type {
5610         int   st_op;
5611         char *st_name;
5612 };
5613
5614 #define LL_STATFS_MAX   LOV_MAX_STRIPE_COUNT
5615
5616 struct ll_statfs_data {
5617         int                     sd_index;
5618         struct obd_statfs       sd_st;
5619 };
5620
5621 struct ll_statfs_buf {
5622         int                     sb_count;
5623         struct ll_statfs_data   sb_buf[LL_STATFS_MAX];
5624 };
5625
5626 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags,
5627                  int ops, struct ll_statfs_buf *lsb)
5628 {
5629         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
5630         struct obd_uuid uuid_buf;
5631         char *poolname = NULL;
5632         struct ll_stat_type types[] = {
5633                 { .st_op = LL_STATFS_LMV,       .st_name = "MDT" },
5634                 { .st_op = LL_STATFS_LOV,       .st_name = "OST" },
5635                 { .st_name = NULL } };
5636         struct ll_stat_type *tp;
5637         __u64 ost_files = 0;
5638         __u64 ost_ffree = 0;
5639         __u32 index;
5640         __u32 type;
5641         int fd;
5642         int rc = 0;
5643         int rc2;
5644
5645         if (pool) {
5646                 poolname = strchr(pool, '.');
5647                 if (poolname != NULL) {
5648                         if (strncmp(fsname, pool, strlen(fsname))) {
5649                                 fprintf(stderr, "filesystem name incorrect\n");
5650                                 return -ENODEV;
5651                         }
5652                         poolname++;
5653                 } else
5654                         poolname = pool;
5655         }
5656
5657         fd = open(mntdir, O_RDONLY);
5658         if (fd < 0) {
5659                 rc = -errno;
5660                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
5661                         strerror(errno));
5662                 return rc;
5663         }
5664
5665         if (flags & MNTDF_SHOW) {
5666                 if (flags & MNTDF_INODES)
5667                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
5668                                "UUID", "Inodes", "IUsed", "IFree",
5669                                "IUse%", "Mounted on");
5670                 else
5671                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
5672                                "UUID",
5673                                flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
5674                                "Used", "Available", "Use%", "Mounted on");
5675         }
5676
5677         for (tp = types; tp->st_name != NULL; tp++) {
5678                 bool have_ost = false;
5679
5680                 if (!(tp->st_op & ops))
5681                         continue;
5682
5683                 for (index = 0; ; index++) {
5684                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
5685                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
5686                         type = flags & MNTDF_LAZY ?
5687                                 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
5688                         rc2 = llapi_obd_fstatfs(fd, type, index,
5689                                                &stat_buf, &uuid_buf);
5690                         if (rc2 == -ENODEV)
5691                                 break;
5692                         if (rc2 == -EAGAIN)
5693                                 continue;
5694                         if (rc2 == -ENODATA) { /* Inactive device, OK. */
5695                                 if (!(flags & MNTDF_VERBOSE))
5696                                         continue;
5697                         } else if (rc2 < 0 && rc == 0) {
5698                                 rc = rc2;
5699                         }
5700
5701                         /* If we have OSTs then don't report MDT block counts.
5702                          * For MDT-only filesystems the expectation is that all
5703                          * layouts have a DoM component.  For filesystems with
5704                          * OSTs, files are not necessarily going to store data
5705                          * on MDTs, and MDT space is limited to a fraction of
5706                          * OST space, so don't include it in the summary.
5707                          */
5708                         if (tp->st_op == LL_STATFS_LOV && !have_ost) {
5709                                 have_ost = true;
5710                                 sum.os_blocks = 0;
5711                                 sum.os_bfree = 0;
5712                                 sum.os_bavail = 0;
5713                         }
5714
5715                         if (poolname && tp->st_op == LL_STATFS_LOV &&
5716                             llapi_search_ost(fsname, poolname,
5717                                              obd_uuid2str(&uuid_buf)) != 1)
5718                                 continue;
5719
5720                         /* the llapi_obd_statfs() call may have returned with
5721                          * an error, but if it filled in uuid_buf we will at
5722                          * lease use that to print out a message for that OBD.
5723                          * If we didn't get anything in the uuid_buf, then fill
5724                          * it in so that we can print an error message. */
5725                         if (uuid_buf.uuid[0] == '\0')
5726                                 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
5727                                          "%s%04x", tp->st_name, index);
5728                         if (!rc && lsb) {
5729                                 lsb->sb_buf[lsb->sb_count].sd_index = index;
5730                                 lsb->sb_buf[lsb->sb_count].sd_st = stat_buf;
5731                                 lsb->sb_count++;
5732                         }
5733                         if (flags & MNTDF_SHOW)
5734                                 showdf(mntdir, &stat_buf,
5735                                        obd_uuid2str(&uuid_buf), flags,
5736                                        tp->st_name, index, rc2);
5737
5738                         if (rc2)
5739                                 continue;
5740
5741                         if (tp->st_op == LL_STATFS_LMV) {
5742                                 sum.os_ffree += stat_buf.os_ffree;
5743                                 sum.os_files += stat_buf.os_files;
5744                         } else /* if (tp->st_op == LL_STATFS_LOV) */ {
5745                                 ost_files += stat_buf.os_files;
5746                                 ost_ffree += stat_buf.os_ffree;
5747                         }
5748                         sum.os_blocks += stat_buf.os_blocks *
5749                                          stat_buf.os_bsize;
5750                         sum.os_bfree  += stat_buf.os_bfree *
5751                                          stat_buf.os_bsize;
5752                         sum.os_bavail += stat_buf.os_bavail *
5753                                          stat_buf.os_bsize;
5754                 }
5755         }
5756
5757         close(fd);
5758
5759         /* If we have _some_ OSTs, but don't have as many free objects on the
5760          * OST as inodes on the MDTs, reduce the reported number of inodes
5761          * to compensate, so that the "inodes in use" number is correct.
5762          * This should be kept in sync with ll_statfs_internal().
5763          */
5764         if (ost_files && ost_ffree < sum.os_ffree) {
5765                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
5766                 sum.os_ffree = ost_ffree;
5767         }
5768         if (flags & MNTDF_SHOW) {
5769                 printf("\n");
5770                 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
5771                 printf("\n");
5772         }
5773
5774         return rc;
5775 }
5776
5777 /* functions */
5778 static int lfs_setdirstripe(int argc, char **argv)
5779 {
5780         char *dname;
5781         struct lfs_setstripe_args lsa = { 0 };
5782         struct llapi_stripe_param *param = NULL;
5783         __u32 mdts[LMV_MAX_STRIPE_COUNT] = { 0 };
5784         char *end;
5785         int c;
5786         char *mode_opt = NULL;
5787         bool default_stripe = false;
5788         bool delete = false;
5789         bool foreign_mode = false;
5790         mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
5791         mode_t previous_mode = 0;
5792         char *xattr = NULL;
5793         __u32 type = LU_FOREIGN_TYPE_DAOS, flags = 0;
5794         struct option long_opts[] = {
5795         { .val = 'c',   .name = "count",        .has_arg = required_argument },
5796         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
5797         { .val = 'd',   .name = "delete",       .has_arg = no_argument },
5798         { .val = 'D',   .name = "default",      .has_arg = no_argument },
5799         { .val = 'D',   .name = "default_stripe", .has_arg = no_argument },
5800         { .val = LFS_LAYOUT_FLAGS_OPT,
5801                         .name = "flags",        .has_arg = required_argument },
5802         { .val = LFS_LAYOUT_FOREIGN_OPT,
5803                         .name = "foreign",      .has_arg = optional_argument},
5804         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
5805 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 17, 53, 0)
5806         { .val = 'i',   .name = "mdt-index",    .has_arg = required_argument },
5807         { .val = 'i',   .name = "mdt",          .has_arg = required_argument },
5808 #else
5809 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
5810         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
5811         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
5812 #endif
5813 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
5814         { .val = 'i',   .name = "index",        .has_arg = required_argument },
5815 #endif
5816         { .val = 'o',   .name = "mode",         .has_arg = required_argument },
5817 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
5818         { .val = 't',   .name = "hash-type",    .has_arg = required_argument },
5819 #endif
5820         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
5821 /* setstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
5822         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
5823         { .name = NULL } };
5824         int result = 0;
5825
5826         setstripe_args_init(&lsa);
5827
5828         while ((c = getopt_long(argc, argv, "c:dDi:H:m:o:t:T:x:",
5829                                 long_opts, NULL)) >= 0) {
5830                 switch (c) {
5831                 case 0:
5832                         /* Long options. */
5833                         break;
5834                 case 'c':
5835                 case 'T':
5836                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
5837                         if (*end != '\0') {
5838                                 fprintf(stderr,
5839                                         "%s %s: invalid stripe count '%s'\n",
5840                                         progname, argv[0], optarg);
5841                                 return CMD_HELP;
5842                         }
5843                         break;
5844                 case 'd':
5845                         delete = true;
5846                         default_stripe = true;
5847                         break;
5848                 case 'D':
5849                         default_stripe = true;
5850                         break;
5851                 case LFS_LAYOUT_FOREIGN_OPT:
5852                         if (optarg != NULL) {
5853                                 /* check pure numeric */
5854                                 type = strtoul(optarg, &end, 0);
5855                                 if (*end) {
5856                                         /* check name */
5857                                         type = check_foreign_type_name(optarg);
5858                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
5859                                                 fprintf(stderr,
5860                                                         "%s %s: unknown foreign type '%s'\n",
5861                                                         progname, argv[0],
5862                                                         optarg);
5863                                                 return CMD_HELP;
5864                                         }
5865                                 }
5866                         }
5867                         foreign_mode = true;
5868                         break;
5869                 case LFS_LAYOUT_FLAGS_OPT:
5870                         flags = strtoul(optarg, &end, 16);
5871                         if (*end != '\0') {
5872                                 fprintf(stderr,
5873                                         "%s %s: bad flags '%s'\n",
5874                                         progname, argv[0], optarg);
5875                                 return CMD_HELP;
5876                         }
5877                         break;
5878 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
5879                 case 't':
5880                         fprintf(stderr, "warning: '--hash-type' and '-t' "
5881                               "deprecated, use '--mdt-hash' or '-H' instead\n");
5882 #endif
5883                 case 'H':
5884                         lsa.lsa_pattern = check_hashtype(optarg);
5885                         if (lsa.lsa_pattern == 0) {
5886                                 fprintf(stderr,
5887                                         "%s %s: bad stripe hash type '%s'\n",
5888                                         progname, argv[0], optarg);
5889                                 return CMD_HELP;
5890                         }
5891                         break;
5892                 case 'i':
5893 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 17, 53, 0)
5894                 case 'm':
5895 #endif
5896 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
5897                         if (strcmp(argv[optind - 1], "--index") == 0)
5898                                 fprintf(stderr,
5899                                         "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
5900                                         progname, argv[0]);
5901 #endif
5902                         lsa.lsa_nr_tgts = parse_targets(mdts,
5903                                                 sizeof(mdts) / sizeof(__u32),
5904                                                 lsa.lsa_nr_tgts, optarg, NULL);
5905                         if (lsa.lsa_nr_tgts < 0) {
5906                                 fprintf(stderr,
5907                                         "%s %s: invalid MDT target(s) '%s'\n",
5908                                         progname, argv[0], optarg);
5909                                 return CMD_HELP;
5910                         }
5911
5912                         lsa.lsa_tgts = mdts;
5913                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
5914                                 lsa.lsa_stripe_off = mdts[0];
5915                         break;
5916 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 15, 53, 0)
5917                 case 'm':
5918                         fprintf(stderr, "warning: '-m' is deprecated, "
5919                                 "use '--mode' or '-o' instead\n");
5920 #endif
5921                 case 'o':
5922                         mode_opt = optarg;
5923                         break;
5924                 case 'x':
5925                         xattr = optarg;
5926                         break;
5927                 default:
5928                         fprintf(stderr, "%s %s: unrecognized option '%s'\n",
5929                                 progname, argv[0], argv[optind - 1]);
5930                         return CMD_HELP;
5931                 }
5932         }
5933
5934         if (optind == argc) {
5935                 fprintf(stderr, "%s %s: DIR must be specified\n",
5936                         progname, argv[0]);
5937                 return CMD_HELP;
5938         }
5939
5940         if (xattr && !foreign_mode) {
5941                 /* only print a warning as this is armless and will be
5942                  * ignored
5943                  */
5944                 fprintf(stderr,
5945                         "%s %s: xattr has been specified for non-foreign layout\n",
5946                         progname, argv[0]);
5947         } else if (foreign_mode && !xattr) {
5948                 fprintf(stderr,
5949                         "%s %s: xattr must be provided in foreign mode\n",
5950                         progname, argv[0]);
5951                 return CMD_HELP;
5952         }
5953
5954         if (foreign_mode && (delete || default_stripe || lsa.lsa_nr_tgts ||
5955             lsa.lsa_tgts || setstripe_args_specified(&lsa))) {
5956                 fprintf(stderr,
5957                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
5958                         progname, argv[0]);
5959                 return CMD_HELP;
5960         }
5961
5962         if (!delete && lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT &&
5963             lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT && !foreign_mode) {
5964                 fprintf(stderr,
5965                         "%s %s: stripe offset and count must be specified\n",
5966                         progname, argv[0]);
5967                 return CMD_HELP;
5968         }
5969
5970         if (delete &&
5971             (lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
5972              lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)) {
5973                 fprintf(stderr,
5974                         "%s %s: cannot specify -d with -c or -i options\n",
5975                         progname, argv[0]);
5976                 return CMD_HELP;
5977         }
5978
5979         if (mode_opt != NULL) {
5980                 mode = strtoul(mode_opt, &end, 8);
5981                 if (*end != '\0') {
5982                         fprintf(stderr,
5983                                 "%s %s: bad MODE '%s'\n",
5984                                 progname, argv[0], mode_opt);
5985                         return CMD_HELP;
5986                 }
5987                 previous_mode = umask(0);
5988         }
5989
5990         /* foreign LMV/dir case */
5991         if (foreign_mode) {
5992                 if (argc > optind + 1) {
5993                         fprintf(stderr,
5994                                 "%s %s: cannot specify multiple foreign dirs\n",
5995                                 progname, argv[0]);
5996                         return CMD_HELP;
5997                 }
5998
5999                 dname = argv[optind];
6000                 result = llapi_dir_create_foreign(dname, mode, type, flags,
6001                                                   xattr);
6002                 if (result != 0)
6003                         fprintf(stderr,
6004                                 "%s mkdir: can't create foreign dir '%s': %s\n",
6005                                 progname, dname, strerror(-result));
6006                 return result;
6007         }
6008
6009         /*
6010          * initialize stripe parameters, in case param is converted to specific,
6011          * i.e, 'lfs mkdir -i -1 -c N', always allocate space for lsp_tgts.
6012          */
6013         param = calloc(1, offsetof(typeof(*param),
6014                        lsp_tgts[lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ?
6015                                 lsa.lsa_stripe_count : lsa.lsa_nr_tgts]));
6016         if (param == NULL) {
6017                 fprintf(stderr,
6018                         "%s %s: cannot allocate memory for parameters: %s\n",
6019                         progname, argv[0], strerror(ENOMEM));
6020                 return CMD_HELP;
6021         }
6022
6023         if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
6024                 param->lsp_stripe_count = lsa.lsa_stripe_count;
6025         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
6026                 param->lsp_stripe_offset = -1;
6027         else
6028                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
6029         if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
6030                 param->lsp_stripe_pattern = lsa.lsa_pattern;
6031         else
6032                 param->lsp_stripe_pattern = LMV_HASH_TYPE_UNKNOWN;
6033         param->lsp_pool = lsa.lsa_pool_name;
6034         param->lsp_is_specific = false;
6035         if (lsa.lsa_nr_tgts > 1) {
6036                 if (lsa.lsa_stripe_count > 0 &&
6037                     lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
6038                     lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
6039                         fprintf(stderr,
6040                                 "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
6041                                 argv[0], lsa.lsa_stripe_count,
6042                                 lsa.lsa_nr_tgts);
6043                         free(param);
6044                         return CMD_HELP;
6045                 }
6046
6047                 param->lsp_is_specific = true;
6048                 param->lsp_stripe_count = lsa.lsa_nr_tgts;
6049                 memcpy(param->lsp_tgts, mdts, sizeof(*mdts) * lsa.lsa_nr_tgts);
6050         }
6051
6052         dname = argv[optind];
6053         do {
6054                 if (default_stripe) {
6055                         result = llapi_dir_set_default_lmv(dname, param);
6056                         if (result)
6057                                 fprintf(stderr,
6058                                         "%s setdirstripe: cannot set default stripe on dir '%s': %s\n",
6059                                         progname, dname, strerror(-result));
6060                         continue;
6061                 }
6062
6063                 result = llapi_dir_create(dname, mode, param);
6064                 if (result)
6065                         fprintf(stderr,
6066                                 "%s setdirstripe: cannot create dir '%s': %s\n",
6067                                 progname, dname, strerror(-result));
6068         } while (!result && (dname = argv[++optind]));
6069
6070         if (mode_opt != NULL)
6071                 umask(previous_mode);
6072
6073         free(param);
6074         return result;
6075 }
6076
6077 /* functions */
6078 static int lfs_rmentry(int argc, char **argv)
6079 {
6080         char *dname;
6081         int   index;
6082         int   result = 0;
6083
6084         if (argc <= 1) {
6085                 fprintf(stderr, "error: %s: missing dirname\n",
6086                         argv[0]);
6087                 return CMD_HELP;
6088         }
6089
6090         index = 1;
6091         dname = argv[index];
6092         while (dname != NULL) {
6093                 result = llapi_direntry_remove(dname);
6094                 if (result) {
6095                         fprintf(stderr, "error: %s: remove dir entry '%s' "
6096                                 "failed\n", argv[0], dname);
6097                         break;
6098                 }
6099                 dname = argv[++index];
6100         }
6101         return result;
6102 }
6103
6104 static int lfs_mv(int argc, char **argv)
6105 {
6106         struct lmv_user_md lmu = { LMV_USER_MAGIC };
6107         struct find_param param = {
6108                 .fp_max_depth = -1,
6109                 .fp_mdt_index = -1,
6110         };
6111         char *end;
6112         int c;
6113         int rc = 0;
6114         struct option long_opts[] = {
6115         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
6116         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
6117         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
6118         { .name = NULL } };
6119
6120         while ((c = getopt_long(argc, argv, "m:M:v", long_opts, NULL)) != -1) {
6121                 switch (c) {
6122 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6123                 case 'M':
6124                         fprintf(stderr, "warning: '-M' deprecated"
6125                                 ", use '--mdt-index' or '-m' instead\n");
6126 #endif
6127                 case 'm':
6128                         lmu.lum_stripe_offset = strtoul(optarg, &end, 0);
6129                         if (*end != '\0') {
6130                                 fprintf(stderr, "%s mv: bad MDT index '%s'\n",
6131                                         progname, optarg);
6132                                 return CMD_HELP;
6133                         }
6134                         break;
6135                 case 'v':
6136                         param.fp_verbose = VERBOSE_DETAIL;
6137                         break;
6138                 default:
6139                         fprintf(stderr, "%s mv: unrecognized option '%s'\n",
6140                                 progname, argv[optind - 1]);
6141                         return CMD_HELP;
6142                 }
6143         }
6144
6145         if (lmu.lum_stripe_offset == LMV_OFFSET_DEFAULT) {
6146                 fprintf(stderr, "%s mv: MDT index must be specified\n",
6147                         progname);
6148                 return CMD_HELP;
6149         }
6150
6151         if (optind >= argc) {
6152                 fprintf(stderr, "%s mv: DIR must be specified\n", progname);
6153                 return CMD_HELP;
6154         }
6155
6156         lmu.lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
6157
6158         /* initialize migrate mdt parameters */
6159         param.fp_lmv_md = &lmu;
6160         param.fp_migrate = 1;
6161         rc = llapi_migrate_mdt(argv[optind], &param);
6162         if (rc != 0)
6163                 fprintf(stderr, "%s mv: cannot migrate '%s' to MDT%04x: %s\n",
6164                         progname, argv[optind], lmu.lum_stripe_offset,
6165                         strerror(-rc));
6166         return rc;
6167 }
6168
6169 static int lfs_osts(int argc, char **argv)
6170 {
6171         return lfs_tgts(argc, argv);
6172 }
6173
6174 static int lfs_mdts(int argc, char **argv)
6175 {
6176         return lfs_tgts(argc, argv);
6177 }
6178
6179 static int lfs_df(int argc, char **argv)
6180 {
6181         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
6182         enum mntdf_flags flags = MNTDF_SHOW;
6183         int ops = LL_STATFS_LMV | LL_STATFS_LOV;
6184         int c, rc = 0, index = 0;
6185         char fsname[PATH_MAX] = "", *pool_name = NULL;
6186         struct option long_opts[] = {
6187         { .val = 'h',   .name = "human-readable",
6188                                                 .has_arg = no_argument },
6189         { .val = 'i',   .name = "inodes",       .has_arg = no_argument },
6190         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
6191         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
6192         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
6193         { .name = NULL} };
6194
6195         while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
6196                 switch (c) {
6197                 case 'h':
6198                         flags |= MNTDF_COOKED;
6199                         break;
6200                 case 'i':
6201                         flags |= MNTDF_INODES;
6202                         break;
6203                 case 'l':
6204                         flags |= MNTDF_LAZY;
6205                         break;
6206                 case 'p':
6207                         pool_name = optarg;
6208                         break;
6209                 case 'v':
6210                         flags |= MNTDF_VERBOSE;
6211                         break;
6212                 default:
6213                         return CMD_HELP;
6214                 }
6215         }
6216         if (optind < argc && !realpath(argv[optind], path)) {
6217                 rc = -errno;
6218                 fprintf(stderr, "error: invalid path '%s': %s\n",
6219                         argv[optind], strerror(-rc));
6220                 return rc;
6221         }
6222
6223         while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
6224                 /* Check if we have a mount point */
6225                 if (mntdir[0] == '\0')
6226                         continue;
6227
6228                 rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
6229                 if (rc || path[0] != '\0')
6230                         break;
6231                 fsname[0] = '\0'; /* avoid matching in next loop */
6232                 mntdir[0] = '\0'; /* avoid matching in next loop */
6233         }
6234
6235         return rc;
6236 }
6237
6238 static int print_instance(const char *mntdir, char *buf, size_t buflen,
6239                           bool opt_instance, bool opt_fsname, bool opt_mntdir)
6240 {
6241         int rc = 0;
6242
6243         if (opt_fsname == opt_instance) { /* both true or both false */
6244                 rc = llapi_getname(mntdir, buf, buflen);
6245         } else if (opt_fsname) {
6246                 /* llapi_search_mounts() fills @buf with fsname, but that is not
6247                  * called if explicit paths are specified on the command-line
6248                  */
6249                 if (buf[0] == '\0')
6250                         rc = llapi_get_fsname(mntdir, buf, buflen);
6251         } else /* if (opt_instance) */ {
6252                 rc = llapi_get_instance(mntdir, buf, buflen);
6253         }
6254
6255         if (rc < 0) {
6256                 fprintf(stderr, "cannot get instance for '%s': %s\n",
6257                         mntdir, strerror(-rc));
6258                 return rc;
6259         }
6260
6261         if (opt_mntdir)
6262                 printf("%s %s\n", buf, mntdir);
6263         else
6264                 printf("%s\n", buf);
6265
6266         return 0;
6267 }
6268
6269 static int lfs_getname(int argc, char **argv)
6270 {
6271         struct option long_opts[] = {
6272         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6273         { .val = 'i',   .name = "instance",     .has_arg = no_argument },
6274         { .val = 'n',   .name = "fsname",       .has_arg = no_argument },
6275         { .name = NULL} };
6276         bool opt_instance = false, opt_fsname = false;
6277         char fsname[PATH_MAX] = "";
6278         int rc = 0, rc2, c;
6279
6280         while ((c = getopt_long(argc, argv, "hin", long_opts, NULL)) != -1) {
6281                 switch (c) {
6282                 case 'i':
6283                         opt_instance = true;
6284                         break;
6285                 case 'n':
6286                         opt_fsname = true;
6287                         break;
6288                 case 'h':
6289                 default:
6290                         return CMD_HELP;
6291                 }
6292         }
6293
6294         if (optind == argc) { /* no paths specified, get all paths. */
6295                 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "";
6296                 int index = 0;
6297
6298                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
6299                         rc2 = print_instance(mntdir, fsname, sizeof(fsname),
6300                                              opt_instance, opt_fsname, true);
6301                         if (!rc)
6302                                 rc = rc2;
6303                         path[0] = fsname[0] = mntdir[0] = '\0';
6304                 }
6305         } else { /* paths specified, only attempt to search these. */
6306                 bool opt_mntdir;
6307
6308                 /* if only one path is given, print only requested info */
6309                 opt_mntdir = argc - optind > 1 || (opt_instance == opt_fsname);
6310
6311                 for (; optind < argc; optind++) {
6312                         rc2 = print_instance(argv[optind], fsname,
6313                                              sizeof(fsname), opt_instance,
6314                                              opt_fsname, opt_mntdir);
6315                         if (!rc)
6316                                 rc = rc2;
6317                         fsname[0] = '\0';
6318                 }
6319         }
6320
6321         return rc;
6322 }
6323
6324 static int lfs_check(int argc, char **argv)
6325 {
6326         char mntdir[PATH_MAX] = {'\0'};
6327         int num_types = 1;
6328         char *obd_types[3];
6329         char obd_type1[4];
6330         char obd_type2[4];
6331         char obd_type3[4];
6332         int rc;
6333
6334         if (argc != 2) {
6335                 fprintf(stderr, "%s check: server type must be specified\n",
6336                         progname);
6337                 return CMD_HELP;
6338         }
6339
6340         obd_types[0] = obd_type1;
6341         obd_types[1] = obd_type2;
6342         obd_types[2] = obd_type3;
6343
6344         if (strcmp(argv[1], "osts") == 0) {
6345                 strcpy(obd_types[0], "osc");
6346         } else if (strcmp(argv[1], "mdts") == 0 ||
6347                    strcmp(argv[1], "mds") == 0) {
6348                 strcpy(obd_types[0], "mdc");
6349         } else if (strcmp(argv[1], "mgts") == 0) {
6350                 strcpy(obd_types[0], "mgc");
6351         } else if (strcmp(argv[1], "all") == 0 ||
6352                    strcmp(argv[1], "servers") == 0) {
6353                 num_types = 3;
6354                 strcpy(obd_types[0], "osc");
6355                 strcpy(obd_types[1], "mdc");
6356                 strcpy(obd_types[2], "mgc");
6357         } else {
6358                 fprintf(stderr, "%s check: unrecognized option '%s'\n",
6359                         progname, argv[1]);
6360                 return CMD_HELP;
6361         }
6362
6363         rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
6364         if (rc < 0 || mntdir[0] == '\0') {
6365                 fprintf(stderr,
6366                         "%s check: cannot find mounted Lustre filesystem: %s\n",
6367                         progname, (rc < 0) ? strerror(-rc) : strerror(ENODEV));
6368                 return rc;
6369         }
6370
6371         rc = llapi_target_check(num_types, obd_types, mntdir);
6372         if (rc)
6373                 fprintf(stderr, "%s check: cannot check target '%s': %s\n",
6374                         progname, argv[1], strerror(-rc));
6375
6376         return rc;
6377
6378 }
6379
6380 #ifdef HAVE_SYS_QUOTA_H
6381 #define ARG2INT(nr, str, msg)                                           \
6382 do {                                                                    \
6383         char *endp;                                                     \
6384         nr = strtol(str, &endp, 0);                                     \
6385         if (*endp != '\0') {                                            \
6386                 fprintf(stderr, "%s: bad %s '%s'\n",                    \
6387                         progname, msg, str);                            \
6388                 return CMD_HELP;                                        \
6389         }                                                               \
6390 } while (0)
6391
6392 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
6393
6394 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
6395  * returns the value or ULONG_MAX on integer overflow or incorrect format
6396  * Notes:
6397  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
6398  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
6399  *        3. empty integer value is interpreted as 0
6400  */
6401 static unsigned long str2sec(const char* timestr)
6402 {
6403         const char spec[] = "smhdw";
6404         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
6405         unsigned long val = 0;
6406         char *tail;
6407
6408         if (strpbrk(timestr, spec) == NULL) {
6409                 /* no specifiers inside the time string,
6410                    should treat it as an integer value */
6411                 val = strtoul(timestr, &tail, 10);
6412                 return *tail ? ULONG_MAX : val;
6413         }
6414
6415         /* format string is XXwXXdXXhXXmXXs */
6416         while (*timestr) {
6417                 unsigned long v;
6418                 int ind;
6419                 char* ptr;
6420
6421                 v = strtoul(timestr, &tail, 10);
6422                 if (v == ULONG_MAX || *tail == '\0')
6423                         /* value too large (ULONG_MAX or more)
6424                            or missing specifier */
6425                         goto error;
6426
6427                 ptr = strchr(spec, *tail);
6428                 if (ptr == NULL)
6429                         /* unknown specifier */
6430                         goto error;
6431
6432                 ind = ptr - spec;
6433
6434                 /* check if product will overflow the type */
6435                 if (!(v < ULONG_MAX / mult[ind]))
6436                         goto error;
6437
6438                 ADD_OVERFLOW(val, mult[ind] * v);
6439                 if (val == ULONG_MAX)
6440                         goto error;
6441
6442                 timestr = tail + 1;
6443         }
6444
6445         return val;
6446
6447 error:
6448         return ULONG_MAX;
6449 }
6450
6451 #define ARG2ULL(nr, str, def_units)                                     \
6452 do {                                                                    \
6453         unsigned long long limit, units = def_units;                    \
6454         int rc;                                                         \
6455                                                                         \
6456         rc = llapi_parse_size(str, &limit, &units, 1);                  \
6457         if (rc < 0) {                                                   \
6458                 fprintf(stderr, "%s: invalid limit '%s'\n",             \
6459                         progname, str);                                 \
6460                 return CMD_HELP;                                        \
6461         }                                                               \
6462         nr = limit;                                                     \
6463 } while (0)
6464
6465 static inline int has_times_option(int argc, char **argv)
6466 {
6467         int i;
6468
6469         for (i = 1; i < argc; i++)
6470                 if (!strcmp(argv[i], "-t"))
6471                         return 1;
6472
6473         return 0;
6474 }
6475
6476 int lfs_setquota_times(int argc, char **argv)
6477 {
6478         int c, rc;
6479         struct if_quotactl qctl;
6480         char *mnt, *obd_type = (char *)qctl.obd_type;
6481         struct obd_dqblk *dqb = &qctl.qc_dqblk;
6482         struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
6483         struct option long_opts[] = {
6484         { .val = 'b',   .name = "block-grace",  .has_arg = required_argument },
6485         { .val = 'g',   .name = "group",        .has_arg = no_argument },
6486         { .val = 'i',   .name = "inode-grace",  .has_arg = required_argument },
6487         { .val = 'p',   .name = "projid",       .has_arg = no_argument },
6488         { .val = 't',   .name = "times",        .has_arg = no_argument },
6489         { .val = 'u',   .name = "user",         .has_arg = no_argument },
6490         { .name = NULL } };
6491         int qtype;
6492
6493         memset(&qctl, 0, sizeof(qctl));
6494         qctl.qc_cmd  = LUSTRE_Q_SETINFO;
6495         qctl.qc_type = ALLQUOTA;
6496
6497         while ((c = getopt_long(argc, argv, "b:gi:ptu",
6498                                 long_opts, NULL)) != -1) {
6499                 switch (c) {
6500                 case 'u':
6501                         qtype = USRQUOTA;
6502                         goto quota_type;
6503                 case 'g':
6504                         qtype = GRPQUOTA;
6505                         goto quota_type;
6506                 case 'p':
6507                         qtype = PRJQUOTA;
6508 quota_type:
6509                         if (qctl.qc_type != ALLQUOTA) {
6510                                 fprintf(stderr, "error: -u/g/p can't be used "
6511                                                 "more than once\n");
6512                                 return CMD_HELP;
6513                         }
6514                         qctl.qc_type = qtype;
6515                         break;
6516                 case 'b':
6517                         if (strncmp(optarg, NOTIFY_GRACE,
6518                                     strlen(NOTIFY_GRACE)) == 0) {
6519                                 dqi->dqi_bgrace = NOTIFY_GRACE_TIME;
6520                         } else {
6521                                 dqi->dqi_bgrace = str2sec(optarg);
6522                                 if (dqi->dqi_bgrace >= NOTIFY_GRACE_TIME) {
6523                                         fprintf(stderr, "error: bad "
6524                                                 "block-grace: %s\n", optarg);
6525                                         return CMD_HELP;
6526                                 }
6527                         }
6528                         dqb->dqb_valid |= QIF_BTIME;
6529                         break;
6530                 case 'i':
6531                         if (strncmp(optarg, NOTIFY_GRACE,
6532                                     strlen(NOTIFY_GRACE)) == 0) {
6533                                 dqi->dqi_igrace = NOTIFY_GRACE_TIME;
6534                         } else {
6535                                 dqi->dqi_igrace = str2sec(optarg);
6536                                 if (dqi->dqi_igrace >= NOTIFY_GRACE_TIME) {
6537                                         fprintf(stderr, "error: bad "
6538                                                 "inode-grace: %s\n", optarg);
6539                                         return CMD_HELP;
6540                                 }
6541                         }
6542                         dqb->dqb_valid |= QIF_ITIME;
6543                         break;
6544                 case 't': /* Yes, of course! */
6545                         break;
6546                 /* getopt prints error message for us when opterr != 0 */
6547                 default:
6548                         return CMD_HELP;
6549                 }
6550         }
6551
6552         if (qctl.qc_type == ALLQUOTA) {
6553                 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
6554                 return CMD_HELP;
6555         }
6556
6557         if (optind != argc - 1) {
6558                 fprintf(stderr, "error: unexpected parameters encountered\n");
6559                 return CMD_HELP;
6560         }
6561
6562         mnt = argv[optind];
6563         rc = llapi_quotactl(mnt, &qctl);
6564         if (rc) {
6565                 if (*obd_type)
6566                         fprintf(stderr, "%s %s ", obd_type,
6567                                 obd_uuid2str(&qctl.obd_uuid));
6568                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
6569                 return rc;
6570         }
6571
6572         return 0;
6573 }
6574
6575 #define BSLIMIT (1 << 0)
6576 #define BHLIMIT (1 << 1)
6577 #define ISLIMIT (1 << 2)
6578 #define IHLIMIT (1 << 3)
6579
6580 int lfs_setquota(int argc, char **argv)
6581 {
6582         int c, rc = 0;
6583         struct if_quotactl qctl;
6584         char *mnt, *obd_type = (char *)qctl.obd_type;
6585         struct obd_dqblk *dqb = &qctl.qc_dqblk;
6586         struct option long_opts[] = {
6587         { .val = 'b',   .name = "block-softlimit",
6588                                                 .has_arg = required_argument },
6589         { .val = 'B',   .name = "block-hardlimit",
6590                                                 .has_arg = required_argument },
6591         { .val = 'd',   .name = "default",      .has_arg = no_argument },
6592         { .val = 'g',   .name = "group",        .has_arg = required_argument },
6593         { .val = 'G',   .name = "default-grp",  .has_arg = no_argument },
6594         { .val = 'i',   .name = "inode-softlimit",
6595                                                 .has_arg = required_argument },
6596         { .val = 'I',   .name = "inode-hardlimit",
6597                                                 .has_arg = required_argument },
6598         { .val = 'p',   .name = "projid",       .has_arg = required_argument },
6599         { .val = 'P',   .name = "default-prj",  .has_arg = no_argument },
6600         { .val = 'u',   .name = "user",         .has_arg = required_argument },
6601         { .val = 'U',   .name = "default-usr",  .has_arg = no_argument },
6602         { .name = NULL } };
6603         unsigned limit_mask = 0;
6604         char *endptr;
6605         bool use_default = false;
6606         int qtype;
6607
6608         if (has_times_option(argc, argv))
6609                 return lfs_setquota_times(argc, argv);
6610
6611         memset(&qctl, 0, sizeof(qctl));
6612         qctl.qc_cmd  = LUSTRE_Q_SETQUOTA;
6613         qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
6614                                   * so it can be used as a marker that qc_type
6615                                   * isn't reinitialized from command line */
6616
6617         while ((c = getopt_long(argc, argv, "b:B:dg:Gi:I:p:Pu:U",
6618                 long_opts, NULL)) != -1) {
6619                 switch (c) {
6620                 case 'U':
6621                         qctl.qc_cmd = LUSTRE_Q_SETDEFAULT;
6622                         qtype = USRQUOTA;
6623                         qctl.qc_id = 0;
6624                         goto quota_type_def;
6625                 case 'u':
6626                         qtype = USRQUOTA;
6627                         rc = name2uid(&qctl.qc_id, optarg);
6628                         goto quota_type;
6629                 case 'G':
6630                         qctl.qc_cmd = LUSTRE_Q_SETDEFAULT;
6631                         qtype = GRPQUOTA;
6632                         qctl.qc_id = 0;
6633                         goto quota_type_def;
6634                 case 'g':
6635                         qtype = GRPQUOTA;
6636                         rc = name2gid(&qctl.qc_id, optarg);
6637                         goto quota_type;
6638                 case 'P':
6639                         qctl.qc_cmd = LUSTRE_Q_SETDEFAULT;
6640                         qtype = PRJQUOTA;
6641                         qctl.qc_id = 0;
6642                         goto quota_type_def;
6643                 case 'p':
6644                         qtype = PRJQUOTA;
6645                         rc = name2projid(&qctl.qc_id, optarg);
6646 quota_type:
6647                         if (rc) {
6648                                 qctl.qc_id = strtoul(optarg, &endptr, 10);
6649                                 if (*endptr != '\0') {
6650                                         fprintf(stderr, "%s setquota: invalid"
6651                                                 " id '%s'\n", progname, optarg);
6652                                         return -1;
6653                                 }
6654                         }
6655
6656                         if (qctl.qc_id == 0) {
6657                                 fprintf(stderr, "%s setquota: can't set quota"
6658                                         " for root usr/group/project.\n",
6659                                         progname);
6660                                 return -1;
6661                         }
6662
6663 quota_type_def:
6664                         if (qctl.qc_type != ALLQUOTA) {
6665                                 fprintf(stderr,
6666                                         "%s setquota: only one of -u, -U, -g,"
6667                                         " -G, -p or -P may be specified\n",
6668                                         progname);
6669                                 return CMD_HELP;
6670                         }
6671                         qctl.qc_type = qtype;
6672                         break;
6673                 case 'd':
6674                         qctl.qc_cmd = LUSTRE_Q_SETDEFAULT;
6675                         use_default = true;
6676                         break;
6677                 case 'b':
6678                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
6679                         dqb->dqb_bsoftlimit >>= 10;
6680                         limit_mask |= BSLIMIT;
6681                         if (dqb->dqb_bsoftlimit &&
6682                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
6683                                 fprintf(stderr,
6684                                         "%s setquota: warning: block softlimit '%llu' smaller than minimum qunit size\n"
6685                                         "See '%s help setquota' or Lustre manual for details\n",
6686                                         progname,
6687                                         (unsigned long long)dqb->dqb_bsoftlimit,
6688                                         progname);
6689                         break;
6690                 case 'B':
6691                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
6692                         dqb->dqb_bhardlimit >>= 10;
6693                         limit_mask |= BHLIMIT;
6694                         if (dqb->dqb_bhardlimit &&
6695                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
6696                                 fprintf(stderr,
6697                                         "%s setquota: warning: block hardlimit '%llu' smaller than minimum qunit size\n"
6698                                         "See '%s help setquota' or Lustre manual for details\n",
6699                                         progname,
6700                                         (unsigned long long)dqb->dqb_bhardlimit,
6701                                         progname);
6702                         break;
6703                 case 'i':
6704                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
6705                         limit_mask |= ISLIMIT;
6706                         if (dqb->dqb_isoftlimit &&
6707                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
6708                                 fprintf(stderr,
6709                                         "%s setquota: warning: inode softlimit '%llu' smaller than minimum qunit size\n"
6710                                         "See '%s help setquota' or Lustre manual for details\n",
6711                                         progname,
6712                                         (unsigned long long)dqb->dqb_isoftlimit,
6713                                         progname);
6714                         break;
6715                 case 'I':
6716                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
6717                         limit_mask |= IHLIMIT;
6718                         if (dqb->dqb_ihardlimit &&
6719                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
6720                                 fprintf(stderr,
6721                                         "%s setquota: warning: inode hardlimit '%llu' smaller than minimum qunit size\n"
6722                                         "See '%s help setquota' or Lustre manual for details\n",
6723                                         progname,
6724                                         (unsigned long long)dqb->dqb_ihardlimit,
6725                                         progname);
6726                         break;
6727                 default:
6728                         fprintf(stderr,
6729                                 "%s setquota: unrecognized option '%s'\n",
6730                                 progname, argv[optind - 1]);
6731                         return CMD_HELP;
6732                 }
6733         }
6734
6735         if (qctl.qc_type == ALLQUOTA) {
6736                 fprintf(stderr,
6737                         "%s setquota: either -u or -g must be specified\n",
6738                         progname);
6739                 return CMD_HELP;
6740         }
6741
6742         if (!use_default && limit_mask == 0) {
6743                 fprintf(stderr,
6744                         "%s setquota: at least one limit must be specified\n",
6745                         progname);
6746                 return CMD_HELP;
6747         }
6748
6749         if (use_default && limit_mask != 0) {
6750                 fprintf(stderr,
6751                         "%s setquota: limits should not be specified when"
6752                         " using default quota\n",
6753                         progname);
6754                 return CMD_HELP;
6755         }
6756
6757         if (use_default && qctl.qc_id == 0) {
6758                 fprintf(stderr,
6759                         "%s setquota: can not set default quota for root"
6760                         " user/group/project\n",
6761                         progname);
6762                 return CMD_HELP;
6763         }
6764
6765         if (optind != argc - 1) {
6766                 fprintf(stderr,
6767                         "%s setquota: filesystem not specified or unexpected argument '%s'\n",
6768                         progname, argv[optind]);
6769                 return CMD_HELP;
6770         }
6771
6772         mnt = argv[optind];
6773
6774         if (use_default) {
6775                 dqb->dqb_bhardlimit = 0;
6776                 dqb->dqb_bsoftlimit = 0;
6777                 dqb->dqb_ihardlimit = 0;
6778                 dqb->dqb_isoftlimit = 0;
6779                 dqb->dqb_itime = 0;
6780                 dqb->dqb_btime = 0;
6781                 dqb->dqb_valid |= QIF_LIMITS | QIF_TIMES;
6782         } else if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
6783                    (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
6784                 /* sigh, we can't just set blimits/ilimits */
6785                 struct if_quotactl tmp_qctl = {.qc_cmd  = LUSTRE_Q_GETQUOTA,
6786                                                .qc_type = qctl.qc_type,
6787                                                .qc_id   = qctl.qc_id};
6788
6789                 rc = llapi_quotactl(mnt, &tmp_qctl);
6790                 if (rc < 0)
6791                         return rc;
6792
6793                 if (!(limit_mask & BHLIMIT))
6794                         dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
6795                 if (!(limit_mask & BSLIMIT))
6796                         dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
6797                 if (!(limit_mask & IHLIMIT))
6798                         dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
6799                 if (!(limit_mask & ISLIMIT))
6800                         dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
6801
6802                 /* Keep grace times if we have got no softlimit arguments */
6803                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
6804                         dqb->dqb_valid |= QIF_BTIME;
6805                         dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
6806                 }
6807
6808                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
6809                         dqb->dqb_valid |= QIF_ITIME;
6810                         dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
6811                 }
6812         }
6813
6814         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
6815         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
6816
6817         rc = llapi_quotactl(mnt, &qctl);
6818         if (rc) {
6819                 if (*obd_type)
6820                         fprintf(stderr,
6821                                 "%s setquota: cannot quotactl '%s' '%s': %s",
6822                                 progname, obd_type,
6823                                 obd_uuid2str(&qctl.obd_uuid), strerror(-rc));
6824                 return rc;
6825         }
6826
6827         return 0;
6828 }
6829
6830 /* Converts seconds value into format string
6831  * result is returned in buf
6832  * Notes:
6833  *        1. result is in descenting order: 1w2d3h4m5s
6834  *        2. zero fields are not filled (except for p. 3): 5d1s
6835  *        3. zero seconds value is presented as "0s"
6836  */
6837 static char * __sec2str(time_t seconds, char *buf)
6838 {
6839         const char spec[] = "smhdw";
6840         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
6841         unsigned long c;
6842         char *tail = buf;
6843         int i;
6844
6845         for (i = ARRAY_SIZE(mult) - 1 ; i >= 0; i--) {
6846                 c = seconds / mult[i];
6847
6848                 if (c > 0 || (i == 0 && buf == tail))
6849                         tail += scnprintf(tail, 40-(tail-buf), "%lu%c", c,
6850                                           spec[i]);
6851
6852                 seconds %= mult[i];
6853         }
6854
6855         return tail;
6856 }
6857
6858 static void sec2str(time_t seconds, char *buf, int rc)
6859 {
6860         char *tail = buf;
6861
6862         if (rc)
6863                 *tail++ = '[';
6864
6865         tail = __sec2str(seconds, tail);
6866
6867         if (rc && tail - buf < 39) {
6868                 *tail++ = ']';
6869                 *tail++ = 0;
6870         }
6871 }
6872
6873 static void diff2str(time_t seconds, char *buf, time_t now)
6874 {
6875
6876         buf[0] = 0;
6877         if (!seconds)
6878                 return;
6879         if (seconds <= now) {
6880                 strcpy(buf, "none");
6881                 return;
6882         }
6883         __sec2str(seconds - now, buf);
6884 }
6885
6886 static void print_quota_title(char *name, struct if_quotactl *qctl,
6887                               bool human_readable, bool show_default)
6888 {
6889         if (show_default) {
6890                 printf("Disk default %s quota:\n", qtype_name(qctl->qc_type));
6891                 printf("%15s %8s%8s%8s %8s%8s%8s\n",
6892                        "Filesystem", "bquota", "blimit", "bgrace",
6893                        "iquota", "ilimit", "igrace");
6894         } else {
6895                 printf("Disk quotas for %s %s (%cid %u):\n",
6896                        qtype_name(qctl->qc_type), name,
6897                        *qtype_name(qctl->qc_type), qctl->qc_id);
6898                 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
6899                        "Filesystem", human_readable ? "used" : "kbytes",
6900                        "quota", "limit", "grace",
6901                        "files", "quota", "limit", "grace");
6902         }
6903 }
6904
6905 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
6906 {
6907         if (!h) {
6908                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
6909         } else {
6910                 if (num >> 40)
6911                         snprintf(buf, buflen, "%5.4gP",
6912                                  (double)num / ((__u64)1 << 40));
6913                 else if (num >> 30)
6914                         snprintf(buf, buflen, "%5.4gT",
6915                                  (double)num / (1 << 30));
6916                 else if (num >> 20)
6917                         snprintf(buf, buflen, "%5.4gG",
6918                                  (double)num / (1 << 20));
6919                 else if (num >> 10)
6920                         snprintf(buf, buflen, "%5.4gM",
6921                                  (double)num / (1 << 10));
6922                 else
6923                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
6924         }
6925 }
6926
6927 #define STRBUF_LEN      32
6928 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
6929                         int rc, bool h, bool show_default)
6930 {
6931         time_t now;
6932
6933         time(&now);
6934
6935         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA ||
6936             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) {
6937                 int bover = 0, iover = 0;
6938                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
6939                 char numbuf[3][STRBUF_LEN];
6940                 char timebuf[40];
6941                 char strbuf[STRBUF_LEN];
6942
6943                 if (dqb->dqb_bhardlimit &&
6944                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
6945                         bover = 1;
6946                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
6947                         if (dqb->dqb_btime > now) {
6948                                 bover = 2;
6949                         } else {
6950                                 bover = 3;
6951                         }
6952                 }
6953
6954                 if (dqb->dqb_ihardlimit &&
6955                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
6956                         iover = 1;
6957                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
6958                         if (dqb->dqb_itime > now) {
6959                                 iover = 2;
6960                         } else {
6961                                 iover = 3;
6962                         }
6963                 }
6964
6965
6966                 if (strlen(mnt) > 15)
6967                         printf("%s\n%15s", mnt, "");
6968                 else
6969                         printf("%15s", mnt);
6970
6971                 if (bover)
6972                         diff2str(dqb->dqb_btime, timebuf, now);
6973                 else if (show_default)
6974                         snprintf(timebuf, sizeof(timebuf), "%llu",
6975                                  (unsigned long long)dqb->dqb_btime);
6976
6977                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
6978                            strbuf, sizeof(strbuf), h);
6979                 if (rc == -EREMOTEIO)
6980                         sprintf(numbuf[0], "%s*", strbuf);
6981                 else
6982                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
6983                                 "%s" : "[%s]", strbuf);
6984
6985                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
6986                 if (type == QC_GENERAL)
6987                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
6988                                 "%s" : "[%s]", strbuf);
6989                 else
6990                         sprintf(numbuf[1], "%s", "-");
6991
6992                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
6993                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
6994                         "%s" : "[%s]", strbuf);
6995
6996                 if (show_default)
6997                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
6998                 else
6999                         printf(" %7s%c %6s %7s %7s",
7000                                numbuf[0], bover ? '*' : ' ', numbuf[1],
7001                                numbuf[2], bover > 1 ? timebuf : "-");
7002
7003
7004                 if (iover)
7005                         diff2str(dqb->dqb_itime, timebuf, now);
7006                 else if (show_default)
7007                         snprintf(timebuf, sizeof(timebuf), "%llu",
7008                                  (unsigned long long)dqb->dqb_itime);
7009
7010                 snprintf(numbuf[0], sizeof(numbuf),
7011                          (dqb->dqb_valid & QIF_INODES) ? "%ju" : "[%ju]",
7012                          (uintmax_t)dqb->dqb_curinodes);
7013
7014                 if (type == QC_GENERAL)
7015                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
7016                                 "%ju" : "[%ju]",
7017                                 (uintmax_t)dqb->dqb_isoftlimit);
7018                 else
7019                         sprintf(numbuf[1], "%s", "-");
7020
7021                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
7022                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
7023
7024                 if (show_default)
7025                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
7026                 else if (type != QC_OSTIDX)
7027                         printf(" %7s%c %6s %7s %7s",
7028                                numbuf[0], iover ? '*' : ' ', numbuf[1],
7029                                numbuf[2], iover > 1 ? timebuf : "-");
7030                 else
7031                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
7032                 printf("\n");
7033         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
7034                    qctl->qc_cmd == Q_GETOINFO) {
7035                 char bgtimebuf[40];
7036                 char igtimebuf[40];
7037
7038                 if (qctl->qc_dqinfo.dqi_bgrace == NOTIFY_GRACE_TIME)
7039                         strncpy(bgtimebuf, NOTIFY_GRACE, 40);
7040                 else
7041                         sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
7042                 if (qctl->qc_dqinfo.dqi_igrace == NOTIFY_GRACE_TIME)
7043                         strncpy(igtimebuf, NOTIFY_GRACE, 40);
7044                 else
7045                         sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
7046
7047                 printf("Block grace time: %s; Inode grace time: %s\n",
7048                        bgtimebuf, igtimebuf);
7049         }
7050 }
7051
7052 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
7053                            bool h, __u64 *total)
7054 {
7055         int rc = 0, rc1 = 0, count = 0;
7056         __u32 valid = qctl->qc_valid;
7057
7058         rc = llapi_get_obd_count(mnt, &count, is_mdt);
7059         if (rc) {
7060                 fprintf(stderr, "can not get %s count: %s\n",
7061                         is_mdt ? "mdt": "ost", strerror(-rc));
7062                 return rc;
7063         }
7064
7065         for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
7066                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
7067                 rc = llapi_quotactl(mnt, qctl);
7068                 if (rc) {
7069                         /* It is remote client case. */
7070                         if (rc == -EOPNOTSUPP) {
7071                                 rc = 0;
7072                                 goto out;
7073                         }
7074
7075                         if (!rc1)
7076                                 rc1 = rc;
7077                         fprintf(stderr, "quotactl %s%d failed.\n",
7078                                 is_mdt ? "mdt": "ost", qctl->qc_idx);
7079                         continue;
7080                 }
7081
7082                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
7083                             qctl->qc_valid, 0, h, false);
7084                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
7085                                    qctl->qc_dqblk.dqb_bhardlimit;
7086         }
7087 out:
7088         qctl->qc_valid = valid;
7089         return rc ? : rc1;
7090 }
7091
7092 static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
7093                            int verbose, int quiet, bool human_readable,
7094                            bool show_default)
7095 {
7096         int rc1 = 0, rc2 = 0, rc3 = 0;
7097         char *obd_type = (char *)qctl->obd_type;
7098         char *obd_uuid = (char *)qctl->obd_uuid.uuid;
7099         __u64 total_ialloc = 0, total_balloc = 0;
7100         bool use_default_for_blk = false;
7101         bool use_default_for_file = false;
7102         int inacc;
7103
7104         rc1 = llapi_quotactl(mnt, qctl);
7105         if (rc1 < 0) {
7106                 switch (rc1) {
7107                 case -ESRCH:
7108                         fprintf(stderr, "%s quotas are not enabled.\n",
7109                                 qtype_name(qctl->qc_type));
7110                         goto out;
7111                 case -EPERM:
7112                         fprintf(stderr, "Permission denied.\n");
7113                 case -ENODEV:
7114                 case -ENOENT:
7115                         /* We already got error message. */
7116                         goto out;
7117                 default:
7118                         fprintf(stderr, "Unexpected quotactl error: %s\n",
7119                                 strerror(-rc1));
7120                 }
7121         }
7122
7123         if (!show_default && qctl->qc_id == 0) {
7124                 qctl->qc_dqblk.dqb_bhardlimit = 0;
7125                 qctl->qc_dqblk.dqb_bsoftlimit = 0;
7126                 qctl->qc_dqblk.dqb_ihardlimit = 0;
7127                 qctl->qc_dqblk.dqb_isoftlimit = 0;
7128                 qctl->qc_dqblk.dqb_btime = 0;
7129                 qctl->qc_dqblk.dqb_itime = 0;
7130                 qctl->qc_dqblk.dqb_valid |= QIF_LIMITS | QIF_TIMES;
7131         }
7132
7133         if (qctl->qc_dqblk.dqb_valid & QIF_BTIME &&
7134             LQUOTA_FLAG(qctl->qc_dqblk.dqb_btime) & LQUOTA_FLAG_DEFAULT) {
7135                 use_default_for_blk = true;
7136                 qctl->qc_dqblk.dqb_btime &= LQUOTA_GRACE_MASK;
7137         }
7138
7139         if (qctl->qc_dqblk.dqb_valid & QIF_ITIME &&
7140             LQUOTA_FLAG(qctl->qc_dqblk.dqb_itime) & LQUOTA_FLAG_DEFAULT) {
7141                 use_default_for_file = true;
7142                 qctl->qc_dqblk.dqb_itime &= LQUOTA_GRACE_MASK;
7143         }
7144
7145         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
7146              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) && !quiet)
7147                 print_quota_title(name, qctl, human_readable, show_default);
7148
7149         if (rc1 && *obd_type)
7150                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
7151
7152         if (qctl->qc_valid != QC_GENERAL)
7153                 mnt = "";
7154
7155         inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA) &&
7156                 ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
7157                  (QIF_LIMITS|QIF_USAGE));
7158
7159         print_quota(mnt, qctl, QC_GENERAL, rc1, human_readable, show_default);
7160
7161         if (!show_default && verbose &&
7162             qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO) {
7163                 char strbuf[STRBUF_LEN];
7164
7165                 rc2 = print_obd_quota(mnt, qctl, 1, human_readable,
7166                                       &total_ialloc);
7167                 rc3 = print_obd_quota(mnt, qctl, 0, human_readable,
7168                                       &total_balloc);
7169                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
7170                            human_readable);
7171                 printf("Total allocated inode limit: %ju, total "
7172                        "allocated block limit: %s\n", (uintmax_t)total_ialloc,
7173                        strbuf);
7174         }
7175
7176         if (use_default_for_blk)
7177                 printf("%cid %u is using default block quota setting\n",
7178                        *qtype_name(qctl->qc_type), qctl->qc_id);
7179
7180         if (use_default_for_file)
7181                 printf("%cid %u is using default file quota setting\n",
7182                        *qtype_name(qctl->qc_type), qctl->qc_id);
7183
7184         if (rc1 || rc2 || rc3 || inacc)
7185                 printf("Some errors happened when getting quota info. "
7186                        "Some devices may be not working or deactivated. "
7187                        "The data in \"[]\" is inaccurate.\n");
7188 out:
7189         if (rc1)
7190                 return rc1;
7191         if (rc2)
7192                 return rc2;
7193         if (rc3)
7194                 return rc3;
7195         if (inacc)
7196                 return -EIO;
7197
7198         return 0;
7199 }
7200
7201 static int lfs_project(int argc, char **argv)
7202 {
7203         int ret = 0, err = 0, c, i;
7204         struct project_handle_control phc = { 0 };
7205         enum lfs_project_ops_t op;
7206
7207         phc.newline = true;
7208         phc.assign_projid = false;
7209         /* default action */
7210         op = LFS_PROJECT_LIST;
7211
7212         while ((c = getopt(argc, argv, "p:cCsdkr0")) != -1) {
7213                 switch (c) {
7214                 case 'c':
7215                         if (op != LFS_PROJECT_LIST) {
7216                                 fprintf(stderr,
7217                                         "%s: cannot specify '-c' '-C' '-s' together\n",
7218                                         progname);
7219                                 return CMD_HELP;
7220                         }
7221
7222                         op = LFS_PROJECT_CHECK;
7223                         break;
7224                 case 'C':
7225                         if (op != LFS_PROJECT_LIST) {
7226                                 fprintf(stderr,
7227                                         "%s: cannot specify '-c' '-C' '-s' together\n",
7228                                         progname);
7229                                 return CMD_HELP;
7230                         }
7231
7232                         op = LFS_PROJECT_CLEAR;
7233                         break;
7234                 case 's':
7235                         if (op != LFS_PROJECT_LIST) {
7236                                 fprintf(stderr,
7237                                         "%s: cannot specify '-c' '-C' '-s' together\n",
7238                                         progname);
7239                                 return CMD_HELP;
7240                         }
7241
7242                         phc.set_inherit = true;
7243                         op = LFS_PROJECT_SET;
7244                         break;
7245                 case 'd':
7246                         phc.dironly = true;
7247                         break;
7248                 case 'k':
7249                         phc.keep_projid = true;
7250                         break;
7251                 case 'r':
7252                         phc.recursive = true;
7253                         break;
7254                 case 'p':
7255                         phc.projid = strtoul(optarg, NULL, 0);
7256                         phc.assign_projid = true;
7257
7258                         break;
7259                 case '0':
7260                         phc.newline = false;
7261                         break;
7262                 default:
7263                         fprintf(stderr, "%s: invalid option '%c'\n",
7264                                 progname, optopt);
7265                         return CMD_HELP;
7266                 }
7267         }
7268
7269         if (phc.assign_projid && op == LFS_PROJECT_LIST) {
7270                 op = LFS_PROJECT_SET;
7271                 phc.set_projid = true;
7272         } else if (phc.assign_projid && op == LFS_PROJECT_SET) {
7273                 phc.set_projid = true;
7274         }
7275
7276         switch (op) {
7277         case LFS_PROJECT_CHECK:
7278                 if (phc.keep_projid) {
7279                         fprintf(stderr,
7280                                 "%s: '-k' is useless together with '-c'\n",
7281                                 progname);
7282                         return CMD_HELP;
7283                 }
7284                 break;
7285         case LFS_PROJECT_CLEAR:
7286                 if (!phc.newline) {
7287                         fprintf(stderr,
7288                                 "%s: '-0' is useless together with '-C'\n",
7289                                 progname);
7290                         return CMD_HELP;
7291                 }
7292                 if (phc.assign_projid) {
7293                         fprintf(stderr,
7294                                 "%s: '-p' is useless together with '-C'\n",
7295                                 progname);
7296                         return CMD_HELP;
7297                 }
7298                 break;
7299         case LFS_PROJECT_SET:
7300                 if (!phc.newline) {
7301                         fprintf(stderr,
7302                                 "%s: '-0' is useless together with '-s'\n",
7303                                 progname);
7304                         return CMD_HELP;
7305                 }
7306                 if (phc.keep_projid) {
7307                         fprintf(stderr,
7308                                 "%s: '-k' is useless together with '-s'\n",
7309                                 progname);
7310                         return CMD_HELP;
7311                 }
7312                 break;
7313         default:
7314                 if (!phc.newline) {
7315                         fprintf(stderr,
7316                                 "%s: '-0' is useless for list operations\n",
7317                                 progname);
7318                         return CMD_HELP;
7319                 }
7320                 break;
7321         }
7322
7323         argv += optind;
7324         argc -= optind;
7325         if (argc == 0) {
7326                 fprintf(stderr, "%s: missing file or directory target(s)\n",
7327                         progname);
7328                 return CMD_HELP;
7329         }
7330
7331         for (i = 0; i < argc; i++) {
7332                 switch (op) {
7333                 case LFS_PROJECT_CHECK:
7334                         err = lfs_project_check(argv[i], &phc);
7335                         break;
7336                 case LFS_PROJECT_LIST:
7337                         err = lfs_project_list(argv[i], &phc);
7338                         break;
7339                 case LFS_PROJECT_CLEAR:
7340                         err = lfs_project_clear(argv[i], &phc);
7341                         break;
7342                 case LFS_PROJECT_SET:
7343                         err = lfs_project_set(argv[i], &phc);
7344                         break;
7345                 default:
7346                         break;
7347                 }
7348                 if (err && !ret)
7349                         ret = err;
7350         }
7351
7352         return ret;
7353 }
7354
7355 static int lfs_quota(int argc, char **argv)
7356 {
7357         int c;
7358         char *mnt, *name = NULL;
7359         struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
7360                                     .qc_type = ALLQUOTA };
7361         char *obd_uuid = (char *)qctl.obd_uuid.uuid;
7362         int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
7363         char *endptr;
7364         __u32 valid = QC_GENERAL, idx = 0;
7365         bool human_readable = false;
7366         bool show_default = false;
7367         int qtype;
7368
7369         while ((c = getopt(argc, argv, "gGi:I:o:pPqtuUvh")) != -1) {
7370                 switch (c) {
7371                 case 'U':
7372                         show_default = true;
7373                 case 'u':
7374                         qtype = USRQUOTA;
7375                         goto quota_type;
7376                 case 'G':
7377                         show_default = true;
7378                 case 'g':
7379                         qtype = GRPQUOTA;
7380                         goto quota_type;
7381                 case 'P':
7382                         show_default = true;
7383                 case 'p':
7384                         qtype = PRJQUOTA;
7385 quota_type:
7386                         if (qctl.qc_type != ALLQUOTA) {
7387                                 fprintf(stderr,
7388                                         "%s quota: only one of -u, -g, or -p may be specified\n",
7389                                         progname);
7390                                 return CMD_HELP;
7391                         }
7392                         qctl.qc_type = qtype;
7393                         break;
7394                 case 't':
7395                         qctl.qc_cmd = LUSTRE_Q_GETINFO;
7396                         break;
7397                 case 'o':
7398                         valid = qctl.qc_valid = QC_UUID;
7399                         snprintf(obd_uuid, sizeof(qctl.obd_uuid), "%s", optarg);
7400                         break;
7401                 case 'i':
7402                         valid = qctl.qc_valid = QC_MDTIDX;
7403                         idx = qctl.qc_idx = atoi(optarg);
7404                         if (idx == 0 && *optarg != '0') {
7405                                 fprintf(stderr,
7406                                         "%s quota: invalid MDT index '%s'\n",
7407                                         progname, optarg);
7408                                 return CMD_HELP;
7409                         }
7410                         break;
7411                 case 'I':
7412                         valid = qctl.qc_valid = QC_OSTIDX;
7413                         idx = qctl.qc_idx = atoi(optarg);
7414                         if (idx == 0 && *optarg != '0') {
7415                                 fprintf(stderr,
7416                                         "%s quota: invalid OST index '%s'\n",
7417                                         progname, optarg);
7418                                 return CMD_HELP;
7419                         }
7420                         break;
7421                 case 'v':
7422                         verbose = 1;
7423                         break;
7424                 case 'q':
7425                         quiet = 1;
7426                         break;
7427                 case 'h':
7428                         human_readable = true;
7429                         break;
7430                 default:
7431                         fprintf(stderr, "%s quota: unrecognized option '%s'\n",
7432                                 progname, argv[optind - 1]);
7433                         return CMD_HELP;
7434                 }
7435         }
7436
7437         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
7438         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
7439             optind == argc - 1 && !show_default) {
7440
7441                 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
7442                 qctl.qc_idx = idx;
7443
7444                 for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) {
7445                         qctl.qc_type = qtype;
7446                         qctl.qc_valid = valid;
7447                         if (qtype == USRQUOTA) {
7448                                 qctl.qc_id = geteuid();
7449                                 rc = uid2name(&name, qctl.qc_id);
7450                         } else {
7451                                 qctl.qc_id = getegid();
7452                                 rc = gid2name(&name, qctl.qc_id);
7453                                 memset(&qctl.qc_dqblk, 0,
7454                                        sizeof(qctl.qc_dqblk));
7455                         }
7456                         if (rc)
7457                                 name = "<unknown>";
7458                         mnt = argv[optind];
7459                         rc1 = get_print_quota(mnt, name, &qctl, verbose, quiet,
7460                                               human_readable, show_default);
7461                         if (rc1 && !rc)
7462                                 rc = rc1;
7463                 }
7464                 return rc;
7465         /* lfs quota -u username /path/to/lustre/mount */
7466         } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
7467                 /* options should be followed by u/g-name and mntpoint */
7468                 if ((!show_default && optind + 2 != argc) ||
7469                     (show_default && optind + 1 != argc) ||
7470                     qctl.qc_type == ALLQUOTA) {
7471                         fprintf(stderr,
7472                                 "%s quota: name and mount point must be specified\n",
7473                                 progname);
7474                         return CMD_HELP;
7475                 }
7476
7477                 if (!show_default) {
7478                         name = argv[optind++];
7479                         switch (qctl.qc_type) {
7480                         case USRQUOTA:
7481                                 rc = name2uid(&qctl.qc_id, name);
7482                                 break;
7483                         case GRPQUOTA:
7484                                 rc = name2gid(&qctl.qc_id, name);
7485                                 break;
7486                         case PRJQUOTA:
7487                                 rc = name2projid(&qctl.qc_id, name);
7488                                 break;
7489                         default:
7490                                 rc = -ENOTSUP;
7491                                 break;
7492                         }
7493                 } else {
7494                         qctl.qc_valid = QC_GENERAL;
7495                         qctl.qc_cmd = LUSTRE_Q_GETDEFAULT;
7496                         qctl.qc_id = 0;
7497                 }
7498
7499                 if (rc) {
7500                         qctl.qc_id = strtoul(name, &endptr, 10);
7501                         if (*endptr != '\0') {
7502                                 fprintf(stderr, "%s quota: invalid id '%s'\n",
7503                                         progname, name);
7504                                 return CMD_HELP;
7505                         }
7506                 }
7507         } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
7508                 fprintf(stderr, "%s quota: missing quota info argument(s)\n",
7509                         progname);
7510                 return CMD_HELP;
7511         }
7512
7513         mnt = argv[optind];
7514         rc = get_print_quota(mnt, name, &qctl, verbose, quiet,
7515                              human_readable, show_default);
7516         return rc;
7517 }
7518 #endif /* HAVE_SYS_QUOTA_H! */
7519
7520 static int flushctx_ioctl(char *mp)
7521 {
7522         int fd, rc;
7523
7524         fd = open(mp, O_RDONLY);
7525         if (fd == -1) {
7526                 fprintf(stderr, "flushctx: error open %s: %s\n",
7527                         mp, strerror(errno));
7528                 return -1;
7529         }
7530
7531         rc = ioctl(fd, LL_IOC_FLUSHCTX);
7532         if (rc == -1)
7533                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
7534                         mp, strerror(errno));
7535
7536         close(fd);
7537         return rc;
7538 }
7539
7540 static int lfs_flushctx(int argc, char **argv)
7541 {
7542         int     kdestroy = 0, c;
7543         char    mntdir[PATH_MAX] = {'\0'};
7544         int     index = 0;
7545         int     rc = 0;
7546
7547         while ((c = getopt(argc, argv, "k")) != -1) {
7548                 switch (c) {
7549                 case 'k':
7550                         kdestroy = 1;
7551                         break;
7552                 default:
7553                         fprintf(stderr, "error: %s: option '-%c' "
7554                                         "unrecognized\n", argv[0], c);
7555                         return CMD_HELP;
7556                 }
7557         }
7558
7559         if (kdestroy) {
7560             if ((rc = system("kdestroy > /dev/null")) != 0) {
7561                 rc = WEXITSTATUS(rc);
7562                 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
7563             }
7564         }
7565
7566         if (optind >= argc) {
7567                 /* flush for all mounted lustre fs. */
7568                 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
7569                         /* Check if we have a mount point */
7570                         if (mntdir[0] == '\0')
7571                                 continue;
7572
7573                         if (flushctx_ioctl(mntdir))
7574                                 rc = -1;
7575
7576                         mntdir[0] = '\0'; /* avoid matching in next loop */
7577                 }
7578         } else {
7579                 /* flush fs as specified */
7580                 while (optind < argc) {
7581                         if (flushctx_ioctl(argv[optind++]))
7582                                 rc = -1;
7583                 }
7584         }
7585         return rc;
7586 }
7587
7588 static int lfs_changelog(int argc, char **argv)
7589 {
7590         void *changelog_priv;
7591         struct changelog_rec *rec;
7592         long long startrec = 0, endrec = 0;
7593         char *mdd;
7594         struct option long_opts[] = {
7595                 { .val = 'f', .name = "follow", .has_arg = no_argument },
7596                 { .name = NULL } };
7597         char short_opts[] = "f";
7598         int rc, follow = 0;
7599
7600         while ((rc = getopt_long(argc, argv, short_opts,
7601                 long_opts, NULL)) != -1) {
7602                 switch (rc) {
7603                 case 'f':
7604                         follow++;
7605                         break;
7606                 default:
7607                         fprintf(stderr,
7608                                 "%s changelog: unrecognized option '%s'\n",
7609                                 progname, argv[optind - 1]);
7610                         return CMD_HELP;
7611                 }
7612         }
7613         if (optind >= argc) {
7614                 fprintf(stderr, "%s changelog: mdtname must be specified\n",
7615                         progname);
7616                 return CMD_HELP;
7617         }
7618
7619         mdd = argv[optind++];
7620         if (argc > optind)
7621                 startrec = strtoll(argv[optind++], NULL, 10);
7622         if (argc > optind)
7623                 endrec = strtoll(argv[optind++], NULL, 10);
7624
7625         rc = llapi_changelog_start(&changelog_priv,
7626                                    CHANGELOG_FLAG_BLOCK |
7627                                    CHANGELOG_FLAG_JOBID |
7628                                    CHANGELOG_FLAG_EXTRA_FLAGS |
7629                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
7630                                    mdd, startrec);
7631         if (rc < 0) {
7632                 fprintf(stderr, "%s changelog: cannot start changelog: %s\n",
7633                         progname, strerror(errno = -rc));
7634                 return rc;
7635         }
7636
7637         rc = llapi_changelog_set_xflags(changelog_priv,
7638                                         CHANGELOG_EXTRA_FLAG_UIDGID |
7639                                         CHANGELOG_EXTRA_FLAG_NID |
7640                                         CHANGELOG_EXTRA_FLAG_OMODE |
7641                                         CHANGELOG_EXTRA_FLAG_XATTR);
7642         if (rc < 0) {
7643                 fprintf(stderr,
7644                         "%s changelog: cannot set xflags for changelog: %s\n",
7645                         progname, strerror(errno = -rc));
7646                 return rc;
7647         }
7648
7649         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
7650                 time_t secs;
7651                 struct tm ts;
7652
7653                 if (endrec && rec->cr_index > endrec) {
7654                         llapi_changelog_free(&rec);
7655                         break;
7656                 }
7657                 if (rec->cr_index < startrec) {
7658                         llapi_changelog_free(&rec);
7659                         continue;
7660                 }
7661
7662                 secs = rec->cr_time >> 30;
7663                 gmtime_r(&secs, &ts);
7664                 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
7665                        "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
7666                        changelog_type2str(rec->cr_type),
7667                        ts.tm_hour, ts.tm_min, ts.tm_sec,
7668                        (int)(rec->cr_time & ((1 << 30) - 1)),
7669                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
7670                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
7671
7672                 if (rec->cr_flags & CLF_JOBID) {
7673                         struct changelog_ext_jobid *jid =
7674                                 changelog_rec_jobid(rec);
7675
7676                         if (jid->cr_jobid[0] != '\0')
7677                                 printf(" j=%s", jid->cr_jobid);
7678                 }
7679
7680                 if (rec->cr_flags & CLF_EXTRA_FLAGS) {
7681                         struct changelog_ext_extra_flags *ef =
7682                                 changelog_rec_extra_flags(rec);
7683
7684                         printf(" ef=0x%llx",
7685                                (unsigned long long)ef->cr_extra_flags);
7686
7687                         if (ef->cr_extra_flags & CLFE_UIDGID) {
7688                                 struct changelog_ext_uidgid *uidgid =
7689                                         changelog_rec_uidgid(rec);
7690
7691                                 printf(" u=%llu:%llu",
7692                                        (unsigned long long)uidgid->cr_uid,
7693                                        (unsigned long long)uidgid->cr_gid);
7694                         }
7695                         if (ef->cr_extra_flags & CLFE_NID) {
7696                                 struct changelog_ext_nid *nid =
7697                                         changelog_rec_nid(rec);
7698
7699                                 printf(" nid=%s",
7700                                        libcfs_nid2str(nid->cr_nid));
7701                         }
7702
7703                         if (ef->cr_extra_flags & CLFE_OPEN) {
7704                                 struct changelog_ext_openmode *omd =
7705                                         changelog_rec_openmode(rec);
7706                                 char mode[] = "---";
7707
7708                                 /* exec mode must be exclusive */
7709                                 if (omd->cr_openflags & MDS_FMODE_EXEC) {
7710                                         mode[2] = 'x';
7711                                 } else {
7712                                         if (omd->cr_openflags & MDS_FMODE_READ)
7713                                                 mode[0] = 'r';
7714                                         if (omd->cr_openflags &
7715                                             (MDS_FMODE_WRITE |
7716                                              MDS_OPEN_TRUNC |
7717                                              MDS_OPEN_APPEND))
7718                                                 mode[1] = 'w';
7719                                 }
7720
7721                                 if (strcmp(mode, "---") != 0)
7722                                         printf(" m=%s", mode);
7723
7724                         }
7725
7726                         if (ef->cr_extra_flags & CLFE_XATTR) {
7727                                 struct changelog_ext_xattr *xattr =
7728                                         changelog_rec_xattr(rec);
7729
7730                                 if (xattr->cr_xattr[0] != '\0')
7731                                         printf(" x=%s", xattr->cr_xattr);
7732                         }
7733                 }
7734
7735                 if (rec->cr_namelen)
7736                         printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
7737                                rec->cr_namelen, changelog_rec_name(rec));
7738
7739                 if (rec->cr_flags & CLF_RENAME) {
7740                         struct changelog_ext_rename *rnm =
7741                                 changelog_rec_rename(rec);
7742
7743                         if (!fid_is_zero(&rnm->cr_sfid))
7744                                 printf(" s="DFID" sp="DFID" %.*s",
7745                                        PFID(&rnm->cr_sfid),
7746                                        PFID(&rnm->cr_spfid),
7747                                        (int)changelog_rec_snamelen(rec),
7748                                        changelog_rec_sname(rec));
7749                 }
7750                 printf("\n");
7751
7752                 llapi_changelog_free(&rec);
7753         }
7754
7755         llapi_changelog_fini(&changelog_priv);
7756
7757         if (rc < 0)
7758                 fprintf(stderr, "%s changelog: cannot access changelog: %s\n",
7759                         progname, strerror(errno = -rc));
7760
7761         return (rc == 1 ? 0 : rc);
7762 }
7763
7764 static int lfs_changelog_clear(int argc, char **argv)
7765 {
7766         long long endrec;
7767         int rc;
7768
7769         if (argc != 4)
7770                 return CMD_HELP;
7771
7772         endrec = strtoll(argv[3], NULL, 10);
7773
7774         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
7775
7776         if (rc == -EINVAL)
7777                 fprintf(stderr, "%s: record out of range: %llu\n",
7778                         argv[0], endrec);
7779         else if (rc == -ENOENT)
7780                 fprintf(stderr, "%s: no changelog user: %s\n",
7781                         argv[0], argv[2]);
7782         else if (rc)
7783                 fprintf(stderr, "%s error: %s\n", argv[0],
7784                         strerror(-rc));
7785
7786         if (rc)
7787                 errno = -rc;
7788
7789         return rc;
7790 }
7791
7792 static int lfs_fid2path(int argc, char **argv)
7793 {
7794         struct option long_opts[] = {
7795                 { .val = 'c',   .name = "cur",  .has_arg = no_argument },
7796                 { .val = 'l',   .name = "link", .has_arg = required_argument },
7797                 { .val = 'r',   .name = "rec",  .has_arg = required_argument },
7798                 { .name = NULL } };
7799         char  short_opts[] = "cl:r:";
7800         char *device, *fid, *path;
7801         long long recno = -1;
7802         int linkno = -1;
7803         int lnktmp;
7804         int printcur = 0;
7805         int rc = 0;
7806         char *endptr = NULL;
7807
7808         while ((rc = getopt_long(argc, argv, short_opts,
7809                 long_opts, NULL)) != -1) {
7810                 switch (rc) {
7811                 case 'c':
7812                         printcur++;
7813                         break;
7814                 case 'l':
7815                         linkno = strtol(optarg, &endptr, 10);
7816                         if (*endptr != '\0') {
7817                                 fprintf(stderr,
7818                                         "%s fid2path: invalid linkno '%s'\n",
7819                                         progname, optarg);
7820                                 return CMD_HELP;
7821                         }
7822                         break;
7823                 case 'r':
7824                         recno = strtoll(optarg, &endptr, 10);
7825                         if (*endptr != '\0') {
7826                                 fprintf(stderr,
7827                                         "%s fid2path: invalid recno '%s'\n",
7828                                         progname, optarg);
7829                                 return CMD_HELP;
7830                         }
7831                         break;
7832                 default:
7833                         fprintf(stderr,
7834                                 "%s fid2path: unrecognized option '%s'\n",
7835                                 progname, argv[optind - 1]);
7836                         return CMD_HELP;
7837                 }
7838         }
7839
7840         if (argc < 3) {
7841                 fprintf(stderr,
7842                         "%s fid2path: <fsname|rootpath> and <fid>... must be specified\n",
7843                         progname);
7844                 return CMD_HELP;
7845         }
7846
7847         device = argv[optind++];
7848         path = calloc(1, PATH_MAX);
7849         if (path == NULL) {
7850                 rc = -errno;
7851                 fprintf(stderr,
7852                         "%s fid2path: cannot allocate memory for path: %s\n",
7853                         progname, strerror(-rc));
7854                 return rc;
7855         }
7856
7857         rc = 0;
7858         while (optind < argc) {
7859                 fid = argv[optind++];
7860
7861                 lnktmp = (linkno >= 0) ? linkno : 0;
7862                 while (1) {
7863                         int oldtmp = lnktmp;
7864                         long long rectmp = recno;
7865                         int rc2;
7866                         rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
7867                                              &rectmp, &lnktmp);
7868                         if (rc2 < 0) {
7869                                 fprintf(stderr,
7870                                         "%s fid2path: cannot find '%s': %s\n",
7871                                         progname, fid, strerror(errno = -rc2));
7872                                 if (rc == 0)
7873                                         rc = rc2;
7874                                 break;
7875                         }
7876
7877                         if (printcur)
7878                                 fprintf(stdout, "%lld ", rectmp);
7879                         if (device[0] == '/') {
7880                                 fprintf(stdout, "%s", device);
7881                                 if (device[strlen(device) - 1] != '/')
7882                                         fprintf(stdout, "/");
7883                         } else if (path[0] == '\0') {
7884                                 fprintf(stdout, "/");
7885                         }
7886                         fprintf(stdout, "%s\n", path);
7887
7888                         if (linkno >= 0)
7889                                 /* specified linkno */
7890                                 break;
7891                         if (oldtmp == lnktmp)
7892                                 /* no more links */
7893                                 break;
7894                 }
7895         }
7896
7897         free(path);
7898         return rc;
7899 }
7900
7901 static int lfs_path2fid(int argc, char **argv)
7902 {
7903         struct option long_opts[] = {
7904                 { .val = 'p', .name = "parents", .has_arg = no_argument },
7905                 { .name = NULL } };
7906         char            **path;
7907         const char        short_opts[] = "p";
7908         const char       *sep = "";
7909         struct lu_fid     fid;
7910         int               rc = 0;
7911         bool              show_parents = false;
7912
7913         while ((rc = getopt_long(argc, argv, short_opts,
7914                                  long_opts, NULL)) != -1) {
7915                 switch (rc) {
7916                 case 'p':
7917                         show_parents = true;
7918                         break;
7919                 default:
7920                         fprintf(stderr,
7921                                 "%s path2fid: unrecognized option '%s'\n",
7922                                 progname, argv[optind - 1]);
7923                         return CMD_HELP;
7924                 }
7925         }
7926
7927         if (optind > argc - 1) {
7928                 fprintf(stderr, "%s path2fid: FILE... must be specified\n",
7929                         progname);
7930                 return CMD_HELP;
7931         }
7932         else if (optind < argc - 1)
7933                 sep = ": ";
7934
7935         rc = 0;
7936         for (path = argv + optind; *path != NULL; path++) {
7937                 int err = 0;
7938                 if (!show_parents) {
7939                         err = llapi_path2fid(*path, &fid);
7940                         if (!err)
7941                                 printf("%s%s"DFID"\n",
7942                                        *sep != '\0' ? *path : "", sep,
7943                                        PFID(&fid));
7944                 } else {
7945                         char            name[NAME_MAX + 1];
7946                         unsigned int    linkno = 0;
7947
7948                         while ((err = llapi_path2parent(*path, linkno, &fid,
7949                                                 name, sizeof(name))) == 0) {
7950                                 if (*sep != '\0' && linkno == 0)
7951                                         printf("%s%s", *path, sep);
7952
7953                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
7954                                        PFID(&fid), name);
7955                                 linkno++;
7956                         }
7957
7958                         /* err == -ENODATA is end-of-loop */
7959                         if (linkno > 0 && err == -ENODATA) {
7960                                 printf("\n");
7961                                 err = 0;
7962                         }
7963                 }
7964
7965                 if (err) {
7966                         fprintf(stderr,
7967                                 "%s path2fid: cannot get %sfid for '%s': %s\n",
7968                                 progname, show_parents ? "parent " : "", *path,
7969                                 strerror(-err));
7970                         if (rc == 0) {
7971                                 rc = err;
7972                                 errno = -err;
7973                         }
7974                 }
7975         }
7976
7977         return rc;
7978 }
7979
7980 #define MAX_ERRNO       4095
7981 #define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO)
7982
7983 static int lfs_rmfid_and_show_errors(const char *device, struct fid_array *fa)
7984 {
7985         int rc, rc2 = 0, k;
7986
7987         rc = llapi_rmfid(device, fa);
7988         if (rc) {
7989                 fprintf(stderr, "rmfid(): rc = %d\n", rc);
7990                 return rc;
7991         }
7992
7993         for (k = 0; k < fa->fa_nr; k++) {
7994                 rc = (__s32)fa->fa_fids[k].f_ver;
7995                 if (!IS_ERR_VALUE(rc))
7996                         continue;
7997                 if (!rc2 && rc)
7998                         rc2 = rc;
7999                 if (!rc)
8000                         continue;
8001                 fa->fa_fids[k].f_ver = 0;
8002                 fprintf(stderr, "rmfid("DFID"): rc = %d\n",
8003                         PFID(&fa->fa_fids[k]), rc);
8004         }
8005
8006         return rc2;
8007 }
8008
8009 static int lfs_rmfid(int argc, char **argv)
8010 {
8011         char *fidstr, *device;
8012         int rc = 0, rc2, nr;
8013         struct fid_array *fa;
8014
8015         if (optind > argc - 1) {
8016                 fprintf(stderr, "%s rmfid: missing dirname\n", progname);
8017                 return CMD_HELP;
8018         }
8019
8020         device = argv[optind++];
8021
8022         nr = argc - optind;
8023         fa = malloc(offsetof(struct fid_array, fa_fids[nr + 1]));
8024         if (fa == NULL)
8025                 return -ENOMEM;
8026
8027         fa->fa_nr = 0;
8028         rc = 0;
8029         while (optind < argc) {
8030                 int found;
8031
8032                 fidstr = argv[optind++];
8033                 while (*fidstr == '[')
8034                         fidstr++;
8035                 found = sscanf(fidstr, SFID, RFID(&fa->fa_fids[fa->fa_nr]));
8036                 if (found != 3) {
8037                         fprintf(stderr, "unrecognized FID: %s\n",
8038                                 argv[optind - 1]);
8039                         exit(1);
8040                 }
8041                 fa->fa_nr++;
8042                 if (fa->fa_nr == OBD_MAX_FIDS_IN_ARRAY) {
8043                         /* start another batch */
8044                         rc2 = lfs_rmfid_and_show_errors(device, fa);
8045                         if (rc2 && !rc)
8046                                 rc = rc2;
8047                         fa->fa_nr = 0;
8048                 }
8049         }
8050         if (fa->fa_nr) {
8051                 rc2 = lfs_rmfid_and_show_errors(device, fa);
8052                 if (rc2 && !rc)
8053                         rc = rc2;
8054         }
8055
8056         return rc;
8057 }
8058
8059 static int lfs_data_version(int argc, char **argv)
8060 {
8061         char *path;
8062         __u64 data_version;
8063         int fd;
8064         int rc;
8065         int c;
8066         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
8067
8068         if (argc < 2) {
8069                 fprintf(stderr, "%s data_version: FILE must be specified\n",
8070                         progname);
8071                 return CMD_HELP;
8072         }
8073
8074         while ((c = getopt(argc, argv, "nrw")) != -1) {
8075                 switch (c) {
8076                 case 'n':
8077                         data_version_flags = 0;
8078                         break;
8079                 case 'r':
8080                         data_version_flags |= LL_DV_RD_FLUSH;
8081                         break;
8082                 case 'w':
8083                         data_version_flags |= LL_DV_WR_FLUSH;
8084                         break;
8085                 default:
8086                         fprintf(stderr,
8087                                 "%s data_version: unrecognized option '%s'\n",
8088                                 progname, argv[optind - 1]);
8089                         return CMD_HELP;
8090                 }
8091         }
8092         if (optind == argc) {
8093                 fprintf(stderr, "%s data_version: FILE must be specified\n",
8094                         progname);
8095                 return CMD_HELP;
8096         }
8097
8098         path = argv[optind];
8099         fd = open(path, O_RDONLY);
8100         if (fd < 0) {
8101                 rc = -errno;
8102                 fprintf(stderr, "%s data_version: cannot open file '%s': %s\n",
8103                         progname, path, strerror(-rc));
8104                 return rc;
8105         }
8106
8107         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
8108         if (rc < 0)
8109                 fprintf(stderr,
8110                         "%s data_version: cannot get version for '%s': %s\n",
8111                         progname, path, strerror(-rc));
8112         else
8113                 printf("%ju" "\n", (uintmax_t)data_version);
8114
8115         close(fd);
8116         return rc;
8117 }
8118
8119 static int lfs_hsm_state(int argc, char **argv)
8120 {
8121         int rc;
8122         int i = 1;
8123         char *path;
8124         struct hsm_user_state hus;
8125
8126         if (argc < 2)
8127                 return CMD_HELP;
8128
8129         do {
8130                 path = argv[i];
8131
8132                 rc = llapi_hsm_state_get(path, &hus);
8133                 if (rc) {
8134                         fprintf(stderr, "can't get hsm state for %s: %s\n",
8135                                 path, strerror(errno = -rc));
8136                         return rc;
8137                 }
8138
8139                 /* Display path name and status flags */
8140                 printf("%s: (0x%08x)", path, hus.hus_states);
8141
8142                 if (hus.hus_states & HS_RELEASED)
8143                         printf(" released");
8144                 if (hus.hus_states & HS_EXISTS)
8145                         printf(" exists");
8146                 if (hus.hus_states & HS_DIRTY)
8147                         printf(" dirty");
8148                 if (hus.hus_states & HS_ARCHIVED)
8149                         printf(" archived");
8150                 /* Display user-settable flags */
8151                 if (hus.hus_states & HS_NORELEASE)
8152                         printf(" never_release");
8153                 if (hus.hus_states & HS_NOARCHIVE)
8154                         printf(" never_archive");
8155                 if (hus.hus_states & HS_LOST)
8156                         printf(" lost_from_hsm");
8157
8158                 if (hus.hus_archive_id != 0)
8159                         printf(", archive_id:%d", hus.hus_archive_id);
8160                 printf("\n");
8161
8162         } while (++i < argc);
8163
8164         return 0;
8165 }
8166
8167 #define LFS_HSM_SET   0
8168 #define LFS_HSM_CLEAR 1
8169
8170 /**
8171  * Generic function to set or clear HSM flags.
8172  * Used by hsm_set and hsm_clear.
8173  *
8174  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
8175  */
8176 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
8177 {
8178         struct option long_opts[] = {
8179         { .val = 'A',   .name = "archived",     .has_arg = no_argument },
8180         { .val = 'a',   .name = "noarchive",    .has_arg = no_argument },
8181         { .val = 'd',   .name = "dirty",        .has_arg = no_argument },
8182         { .val = 'e',   .name = "exists",       .has_arg = no_argument },
8183         { .val = 'l',   .name = "lost",         .has_arg = no_argument },
8184         { .val = 'r',   .name = "norelease",    .has_arg = no_argument },
8185         { .val = 'i',   .name = "archive-id",   .has_arg = required_argument },
8186         { .name = NULL } };
8187         char short_opts[] = "lraAdei:";
8188         __u64 mask = 0;
8189         int c, rc;
8190         char *path;
8191         __u32 archive_id = 0;
8192         char *end = NULL;
8193
8194         if (argc < 3)
8195                 return CMD_HELP;
8196
8197         while ((c = getopt_long(argc, argv, short_opts,
8198                                 long_opts, NULL)) != -1) {
8199                 switch (c) {
8200                 case 'l':
8201                         mask |= HS_LOST;
8202                         break;
8203                 case 'a':
8204                         mask |= HS_NOARCHIVE;
8205                         break;
8206                 case 'A':
8207                         mask |= HS_ARCHIVED;
8208                         break;
8209                 case 'r':
8210                         mask |= HS_NORELEASE;
8211                         break;
8212                 case 'd':
8213                         mask |= HS_DIRTY;
8214                         break;
8215                 case 'e':
8216                         mask |= HS_EXISTS;
8217                         break;
8218                 case 'i':
8219                         archive_id = strtol(optarg, &end, 10);
8220                         if (*end != '\0') {
8221                                 fprintf(stderr, "invalid archive_id: '%s'\n",
8222                                         end);
8223                                 return CMD_HELP;
8224                         }
8225                         break;
8226                 case '?':
8227                         return CMD_HELP;
8228                 default:
8229                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
8230                                 argv[0], argv[optind - 1]);
8231                         return CMD_HELP;
8232                 }
8233         }
8234
8235         /* User should have specified a flag */
8236         if (mask == 0)
8237                 return CMD_HELP;
8238
8239         while (optind < argc) {
8240
8241                 path = argv[optind];
8242
8243                 /* If mode == 0, this means we apply the mask. */
8244                 if (mode == LFS_HSM_SET)
8245                         rc = llapi_hsm_state_set(path, mask, 0, archive_id);
8246                 else
8247                         rc = llapi_hsm_state_set(path, 0, mask, 0);
8248
8249                 if (rc != 0) {
8250                         fprintf(stderr, "Can't change hsm flags for %s: %s\n",
8251                                 path, strerror(errno = -rc));
8252                         return rc;
8253                 }
8254                 optind++;
8255         }
8256
8257         return 0;
8258 }
8259
8260 static int lfs_hsm_action(int argc, char **argv)
8261 {
8262         int                              rc;
8263         int                              i = 1;
8264         char                            *path;
8265         struct hsm_current_action        hca;
8266         struct hsm_extent                he;
8267         enum hsm_user_action             hua;
8268         enum hsm_progress_states         hps;
8269
8270         if (argc < 2)
8271                 return CMD_HELP;
8272
8273         do {
8274                 path = argv[i];
8275
8276                 rc = llapi_hsm_current_action(path, &hca);
8277                 if (rc) {
8278                         fprintf(stderr, "can't get hsm action for %s: %s\n",
8279                                 path, strerror(errno = -rc));
8280                         return rc;
8281                 }
8282                 he = hca.hca_location;
8283                 hua = hca.hca_action;
8284                 hps = hca.hca_state;
8285
8286                 printf("%s: %s", path, hsm_user_action2name(hua));
8287
8288                 /* Skip file without action */
8289                 if (hca.hca_action == HUA_NONE) {
8290                         printf("\n");
8291                         continue;
8292                 }
8293
8294                 printf(" %s ", hsm_progress_state2name(hps));
8295
8296                 if ((hps == HPS_RUNNING) &&
8297                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
8298                         printf("(%llu bytes moved)\n",
8299                                (unsigned long long)he.length);
8300                 else if ((he.offset + he.length) == LUSTRE_EOF)
8301                         printf("(from %llu to EOF)\n",
8302                                (unsigned long long)he.offset);
8303                 else
8304                         printf("(from %llu to %llu)\n",
8305                                (unsigned long long)he.offset,
8306                                (unsigned long long)(he.offset + he.length));
8307
8308         } while (++i < argc);
8309
8310         return 0;
8311 }
8312
8313 static int lfs_hsm_set(int argc, char **argv)
8314 {
8315         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
8316 }
8317
8318 static int lfs_hsm_clear(int argc, char **argv)
8319 {
8320         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
8321 }
8322
8323 /**
8324  * Check file state and return its fid, to be used by lfs_hsm_request().
8325  *
8326  * \param[in]     file      Path to file to check
8327  * \param[in,out] fid       Pointer to allocated lu_fid struct.
8328  * \param[in,out] last_dev  Pointer to last device id used.
8329  *
8330  * \return 0 on success.
8331  */
8332 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
8333                                 dev_t *last_dev)
8334 {
8335         struct stat     st;
8336         int             rc;
8337
8338         rc = lstat(file, &st);
8339         if (rc) {
8340                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
8341                 return -errno;
8342         }
8343         /* Checking for regular file as archiving as posix copytool
8344          * rejects archiving files other than regular files
8345          */
8346         if (!S_ISREG(st.st_mode)) {
8347                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
8348                 return CMD_HELP;
8349         }
8350         /* A request should be ... */
8351         if (*last_dev != st.st_dev && *last_dev != 0) {
8352                 fprintf(stderr, "All files should be "
8353                         "on the same filesystem: %s\n", file);
8354                 return -EINVAL;
8355         }
8356         *last_dev = st.st_dev;
8357
8358         rc = llapi_path2fid(file, fid);
8359         if (rc) {
8360                 fprintf(stderr, "Cannot read FID of %s: %s\n",
8361                         file, strerror(-rc));
8362                 return rc;
8363         }
8364         return 0;
8365 }
8366
8367 /* Fill an HSM HUR item with a given file name.
8368  *
8369  * If mntpath is set, then the filename is actually a FID, and no
8370  * lookup on the filesystem will be performed.
8371  *
8372  * \param[in]  hur         the user request to fill
8373  * \param[in]  idx         index of the item inside the HUR to fill
8374  * \param[in]  mntpath     mountpoint of Lustre
8375  * \param[in]  fname       filename (if mtnpath is NULL)
8376  *                         or FID (if mntpath is set)
8377  * \param[in]  last_dev    pointer to last device id used
8378  *
8379  * \retval 0 on success
8380  * \retval CMD_HELP or a negative errno on error
8381  */
8382 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
8383                          const char *mntpath, const char *fname,
8384                          dev_t *last_dev)
8385 {
8386         struct hsm_user_item *hui = &hur->hur_user_item[idx];
8387         int rc;
8388
8389         hui->hui_extent.length = -1;
8390
8391         if (mntpath != NULL) {
8392                 rc = llapi_fid_parse(fname, &hui->hui_fid, NULL);
8393                 if (rc)
8394                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
8395                                 fname);
8396         } else {
8397                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
8398         }
8399
8400         if (rc == 0)
8401                 hur->hur_request.hr_itemcount++;
8402
8403         return rc;
8404 }
8405
8406 static int lfs_hsm_request(int argc, char **argv, int action)
8407 {
8408         struct option long_opts[] = {
8409         { .val = 'a',   .name = "archive",      .has_arg = required_argument },
8410         { .val = 'D',   .name = "data",         .has_arg = required_argument },
8411         { .val = 'l',   .name = "filelist",     .has_arg = required_argument },
8412         { .val = 'm',   .name = "mntpath",      .has_arg = required_argument },
8413         { .name = NULL } };
8414         dev_t                    last_dev = 0;
8415         char                     short_opts[] = "l:D:a:m:";
8416         struct hsm_user_request *hur, *oldhur;
8417         int                      c, i;
8418         size_t                   len;
8419         int                      nbfile;
8420         char                    *line = NULL;
8421         char                    *filelist = NULL;
8422         char                     fullpath[PATH_MAX];
8423         char                    *opaque = NULL;
8424         int                      opaque_len = 0;
8425         int                      archive_id = 0;
8426         FILE                    *fp;
8427         int                      nbfile_alloc = 0;
8428         char                    *some_file = NULL;
8429         char                    *mntpath = NULL;
8430         int                      rc;
8431
8432         if (argc < 2)
8433                 return CMD_HELP;
8434
8435         while ((c = getopt_long(argc, argv, short_opts,
8436                                 long_opts, NULL)) != -1) {
8437                 switch (c) {
8438                 case 'l':
8439                         filelist = optarg;
8440                         break;
8441                 case 'D':
8442                         opaque = optarg;
8443                         break;
8444                 case 'a':
8445                         if (action != HUA_ARCHIVE &&
8446                             action != HUA_REMOVE) {
8447                                 fprintf(stderr,
8448                                         "error: -a is supported only "
8449                                         "when archiving or removing\n");
8450                                 return CMD_HELP;
8451                         }
8452                         archive_id = atoi(optarg);
8453                         break;
8454                 case 'm':
8455                         if (some_file == NULL) {
8456                                 mntpath = optarg;
8457                                 some_file = strdup(optarg);
8458                         }
8459                         break;
8460                 case '?':
8461                         return CMD_HELP;
8462                 default:
8463                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
8464                                 argv[0], argv[optind - 1]);
8465                         return CMD_HELP;
8466                 }
8467         }
8468
8469         /* All remaining args are files, so we have at least nbfile */
8470         nbfile = argc - optind;
8471
8472         if ((nbfile == 0) && (filelist == NULL))
8473                 return CMD_HELP;
8474
8475         if (opaque != NULL)
8476                 opaque_len = strlen(opaque);
8477
8478         /* Alloc the request structure with enough place to store all files
8479          * from command line. */
8480         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
8481         if (hur == NULL) {
8482                 fprintf(stderr, "Cannot create the request: %s\n",
8483                         strerror(errno));
8484                 return errno;
8485         }
8486         nbfile_alloc = nbfile;
8487
8488         hur->hur_request.hr_action = action;
8489         hur->hur_request.hr_archive_id = archive_id;
8490         hur->hur_request.hr_flags = 0;
8491
8492         /* All remaining args are files, add them */
8493         if (nbfile != 0 && some_file == NULL)
8494                 some_file = strdup(argv[optind]);
8495
8496         for (i = 0; i < nbfile; i++) {
8497                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
8498                                    &last_dev);
8499                 if (rc)
8500                         goto out_free;
8501         }
8502
8503         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
8504
8505         /* If a filelist was specified, read the filelist from it. */
8506         if (filelist != NULL) {
8507                 fp = fopen(filelist, "r");
8508                 if (fp == NULL) {
8509                         fprintf(stderr, "Cannot read the file list %s: %s\n",
8510                                 filelist, strerror(errno));
8511                         rc = -errno;
8512                         goto out_free;
8513                 }
8514
8515                 while ((rc = getline(&line, &len, fp)) != -1) {
8516                         /* If allocated buffer was too small, get something
8517                          * larger */
8518                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
8519                                 ssize_t size;
8520
8521                                 nbfile_alloc = nbfile_alloc * 2 + 1;
8522                                 oldhur = hur;
8523                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
8524                                                                    opaque_len);
8525                                 if (hur == NULL) {
8526                                         fprintf(stderr, "hsm: cannot allocate "
8527                                                 "the request: %s\n",
8528                                                 strerror(errno));
8529                                         hur = oldhur;
8530                                         rc = -errno;
8531                                         fclose(fp);
8532                                         goto out_free;
8533                                 }
8534                                 size = hur_len(oldhur);
8535                                 if (size < 0) {
8536                                         fprintf(stderr, "hsm: cannot allocate "
8537                                                 "%u files + %u bytes data\n",
8538                                             oldhur->hur_request.hr_itemcount,
8539                                             oldhur->hur_request.hr_data_len);
8540                                         free(hur);
8541                                         hur = oldhur;
8542                                         rc = -E2BIG;
8543                                         fclose(fp);
8544                                         goto out_free;
8545                                 }
8546                                 memcpy(hur, oldhur, size);
8547                                 free(oldhur);
8548                         }
8549
8550                         /* Chop CR */
8551                         if (line[strlen(line) - 1] == '\n')
8552                                 line[strlen(line) - 1] = '\0';
8553
8554                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
8555                                            mntpath, line, &last_dev);
8556                         if (rc) {
8557                                 fclose(fp);
8558                                 goto out_free;
8559                         }
8560
8561                         if (some_file == NULL) {
8562                                 some_file = line;
8563                                 line = NULL;
8564                         }
8565                 }
8566
8567                 rc = fclose(fp);
8568                 free(line);
8569         }
8570
8571         /* If a --data was used, add it to the request */
8572         hur->hur_request.hr_data_len = opaque_len;
8573         if (opaque != NULL)
8574                 memcpy(hur_data(hur), opaque, opaque_len);
8575
8576         /* Send the HSM request */
8577         if (realpath(some_file, fullpath) == NULL) {
8578                 fprintf(stderr, "Could not find path '%s': %s\n",
8579                         some_file, strerror(errno));
8580         }
8581         rc = llapi_hsm_request(fullpath, hur);
8582         if (rc) {
8583                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
8584                         some_file, strerror(-rc));
8585                 goto out_free;
8586         }
8587
8588 out_free:
8589         free(some_file);
8590         free(hur);
8591         return rc;
8592 }
8593
8594 static int lfs_hsm_archive(int argc, char **argv)
8595 {
8596         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
8597 }
8598
8599 static int lfs_hsm_restore(int argc, char **argv)
8600 {
8601         return lfs_hsm_request(argc, argv, HUA_RESTORE);
8602 }
8603
8604 static int lfs_hsm_release(int argc, char **argv)
8605 {
8606         return lfs_hsm_request(argc, argv, HUA_RELEASE);
8607 }
8608
8609 static int lfs_hsm_remove(int argc, char **argv)
8610 {
8611         return lfs_hsm_request(argc, argv, HUA_REMOVE);
8612 }
8613
8614 static int lfs_hsm_cancel(int argc, char **argv)
8615 {
8616         return lfs_hsm_request(argc, argv, HUA_CANCEL);
8617 }
8618
8619 static int lfs_swap_layouts(int argc, char **argv)
8620 {
8621         if (argc != 3)
8622                 return CMD_HELP;
8623
8624         return llapi_swap_layouts(argv[1], argv[2], 0, 0,
8625                                   SWAP_LAYOUTS_KEEP_MTIME |
8626                                   SWAP_LAYOUTS_KEEP_ATIME);
8627 }
8628
8629 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
8630
8631 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
8632
8633 int lfs_get_mode(const char *string)
8634 {
8635         enum lock_mode_user mode;
8636
8637         for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
8638                 if (lock_mode_names[mode] == NULL)
8639                         continue;
8640                 if (strcmp(string, lock_mode_names[mode]) == 0)
8641                         return mode;
8642         }
8643
8644         return -EINVAL;
8645 }
8646
8647 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
8648 {
8649         enum lu_ladvise_type advice;
8650
8651         for (advice = 0;
8652              advice < ARRAY_SIZE(ladvise_names); advice++) {
8653                 if (ladvise_names[advice] == NULL)
8654                         continue;
8655                 if (strcmp(string, ladvise_names[advice]) == 0)
8656                         return advice;
8657         }
8658
8659         return LU_LADVISE_INVALID;
8660 }
8661
8662 static int lfs_ladvise(int argc, char **argv)
8663 {
8664         struct option long_opts[] = {
8665         { .val = 'a',   .name = "advice",       .has_arg = required_argument },
8666         { .val = 'b',   .name = "background",   .has_arg = no_argument },
8667         { .val = 'e',   .name = "end",          .has_arg = required_argument },
8668         { .val = 'l',   .name = "length",       .has_arg = required_argument },
8669         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
8670         { .val = 's',   .name = "start",        .has_arg = required_argument },
8671         { .val = 'u',   .name = "unset",        .has_arg = no_argument },
8672         { .name = NULL } };
8673         char                     short_opts[] = "a:be:l:m:s:u";
8674         int                      c;
8675         int                      rc = 0;
8676         const char              *path;
8677         int                      fd;
8678         struct llapi_lu_ladvise  advice;
8679         enum lu_ladvise_type     advice_type = LU_LADVISE_INVALID;
8680         unsigned long long       start = 0;
8681         unsigned long long       end = LUSTRE_EOF;
8682         unsigned long long       length = 0;
8683         unsigned long long       size_units;
8684         unsigned long long       flags = 0;
8685         int                      mode = 0;
8686
8687         optind = 0;
8688         while ((c = getopt_long(argc, argv, short_opts,
8689                                 long_opts, NULL)) != -1) {
8690                 switch (c) {
8691                 case 'a':
8692                         advice_type = lfs_get_ladvice(optarg);
8693                         if (advice_type == LU_LADVISE_INVALID) {
8694                                 fprintf(stderr, "%s: invalid advice type "
8695                                         "'%s'\n", argv[0], optarg);
8696                                 fprintf(stderr, "Valid types:");
8697
8698                                 for (advice_type = 0;
8699                                      advice_type < ARRAY_SIZE(ladvise_names);
8700                                      advice_type++) {
8701                                         if (ladvise_names[advice_type] == NULL)
8702                                                 continue;
8703                                         fprintf(stderr, " %s",
8704                                                 ladvise_names[advice_type]);
8705                                 }
8706                                 fprintf(stderr, "\n");
8707
8708                                 return CMD_HELP;
8709                         }
8710                         break;
8711                 case 'b':
8712                         flags |= LF_ASYNC;
8713                         break;
8714                 case 'u':
8715                         flags |= LF_UNSET;
8716                         break;
8717                 case 'e':
8718                         size_units = 1;
8719                         rc = llapi_parse_size(optarg, &end,
8720                                               &size_units, 0);
8721                         if (rc) {
8722                                 fprintf(stderr, "%s: bad end offset '%s'\n",
8723                                         argv[0], optarg);
8724                                 return CMD_HELP;
8725                         }
8726                         break;
8727                 case 's':
8728                         size_units = 1;
8729                         rc = llapi_parse_size(optarg, &start,
8730                                               &size_units, 0);
8731                         if (rc) {
8732                                 fprintf(stderr, "%s: bad start offset "
8733                                         "'%s'\n", argv[0], optarg);
8734                                 return CMD_HELP;
8735                         }
8736                         break;
8737                 case 'l':
8738                         size_units = 1;
8739                         rc = llapi_parse_size(optarg, &length,
8740                                               &size_units, 0);
8741                         if (rc) {
8742                                 fprintf(stderr, "%s: bad length '%s'\n",
8743                                         argv[0], optarg);
8744                                 return CMD_HELP;
8745                         }
8746                         break;
8747                 case 'm':
8748                         mode = lfs_get_mode(optarg);
8749                         if (mode < 0) {
8750                                 fprintf(stderr, "%s: bad mode '%s', valid "
8751                                                  "modes are READ or WRITE\n",
8752                                         argv[0], optarg);
8753                                 return CMD_HELP;
8754                         }
8755                         break;
8756                 case '?':
8757                         return CMD_HELP;
8758                 default:
8759                         fprintf(stderr, "%s: option '%s' unrecognized\n",
8760                                 argv[0], argv[optind - 1]);
8761                         return CMD_HELP;
8762                 }
8763         }
8764
8765         if (advice_type == LU_LADVISE_INVALID) {
8766                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
8767                 fprintf(stderr, "Valid types:");
8768                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
8769                      advice_type++) {
8770                         if (ladvise_names[advice_type] == NULL)
8771                                 continue;
8772                         fprintf(stderr, " %s", ladvise_names[advice_type]);
8773                 }
8774                 fprintf(stderr, "\n");
8775                 return CMD_HELP;
8776         }
8777
8778         if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
8779                 fprintf(stderr, "%s: Lock no expand advice is a per file "
8780                                  "descriptor advice, so when called from lfs, "
8781                                  "it does nothing.\n", argv[0]);
8782                 return CMD_HELP;
8783         }
8784
8785         if (argc <= optind) {
8786                 fprintf(stderr, "%s: please give one or more file names\n",
8787                         argv[0]);
8788                 return CMD_HELP;
8789         }
8790
8791         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
8792                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
8793                         argv[0]);
8794                 return CMD_HELP;
8795         }
8796
8797         if (end == LUSTRE_EOF && length != 0)
8798                 end = start + length;
8799
8800         if (end <= start) {
8801                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
8802                         argv[0], start, end);
8803                 return CMD_HELP;
8804         }
8805
8806         if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
8807                 fprintf(stderr, "%s: mode is only valid with lockahead\n",
8808                         argv[0]);
8809                 return CMD_HELP;
8810         }
8811
8812         if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
8813                 fprintf(stderr, "%s: mode is required with lockahead\n",
8814                         argv[0]);
8815                 return CMD_HELP;
8816         }
8817
8818         while (optind < argc) {
8819                 int rc2;
8820
8821                 path = argv[optind++];
8822
8823                 fd = open(path, O_RDONLY);
8824                 if (fd < 0) {
8825                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
8826                                 argv[0], path, strerror(errno));
8827                         rc2 = -errno;
8828                         goto next;
8829                 }
8830
8831                 advice.lla_start = start;
8832                 advice.lla_end = end;
8833                 advice.lla_advice = advice_type;
8834                 advice.lla_value1 = 0;
8835                 advice.lla_value2 = 0;
8836                 advice.lla_value3 = 0;
8837                 advice.lla_value4 = 0;
8838                 if (advice_type == LU_LADVISE_LOCKAHEAD) {
8839                         advice.lla_lockahead_mode = mode;
8840                         advice.lla_peradvice_flags = flags;
8841                 }
8842
8843                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
8844                 close(fd);
8845                 if (rc2 < 0) {
8846                         fprintf(stderr, "%s: cannot give advice '%s' to file "
8847                                 "'%s': %s\n", argv[0],
8848                                 ladvise_names[advice_type],
8849                                 path, strerror(errno));
8850
8851                         goto next;
8852                 }
8853
8854 next:
8855                 if (rc == 0 && rc2 < 0)
8856                         rc = rc2;
8857         }
8858         return rc;
8859 }
8860
8861 static const char *const heat_names[] = LU_HEAT_NAMES;
8862
8863 static int lfs_heat_get(int argc, char **argv)
8864 {
8865         struct lu_heat *heat;
8866         int rc = 0, rc2;
8867         char *path;
8868         int fd;
8869         int i;
8870
8871         if (argc <= 1)
8872                 return CMD_HELP;
8873
8874         heat = calloc(sizeof(*heat) + sizeof(__u64) * OBD_HEAT_COUNT, 1);
8875         if (!heat) {
8876                 fprintf(stderr, "%s: memory allocation failed\n", argv[0]);
8877                 return -ENOMEM;
8878         }
8879
8880         optind = 1;
8881         while (optind < argc) {
8882                 path = argv[optind++];
8883
8884                 fd = open(path, O_RDONLY);
8885                 if (fd < 0) {
8886                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
8887                                 argv[0], path, strerror(errno));
8888                         rc2 = -errno;
8889                         goto next;
8890                 }
8891
8892                 heat->lh_count = OBD_HEAT_COUNT;
8893                 rc2 = llapi_heat_get(fd, heat);
8894                 close(fd);
8895                 if (rc2 < 0) {
8896                         fprintf(stderr, "%s: cannot get heat of file '%s'"
8897                                 ": %s\n", argv[0], path, strerror(errno));
8898                         goto next;
8899                 }
8900
8901                 printf("flags: %x\n", heat->lh_flags);
8902                 for (i = 0; i < heat->lh_count; i++)
8903                         printf("%s: %llu\n", heat_names[i],
8904                                (unsigned long long)heat->lh_heat[i]);
8905 next:
8906                 if (rc == 0 && rc2 < 0)
8907                         rc = rc2;
8908         }
8909
8910         free(heat);
8911         return rc;
8912 }
8913
8914 static int lfs_heat_set(int argc, char **argv)
8915 {
8916         struct option long_opts[] = {
8917         { .val = 'c',   .name = "clear",        .has_arg = no_argument },
8918         { .val = 'o',   .name = "off",          .has_arg = no_argument },
8919         { .val = 'O',   .name = "on",           .has_arg = no_argument },
8920         { .name = NULL } };
8921         enum lu_heat_flag flags = 0;
8922         int rc = 0, rc2;
8923         char *path;
8924         int fd;
8925         int c;
8926
8927         if (argc <= 1)
8928                 return CMD_HELP;
8929
8930         optind = 0;
8931         while ((c = getopt_long(argc, argv, "coO", long_opts, NULL)) != -1) {
8932                 switch (c) {
8933                 case 'c':
8934                         flags |= LU_HEAT_FLAG_CLEAR;
8935                         break;
8936                 case 'o':
8937                         flags |= LU_HEAT_FLAG_CLEAR;
8938                         flags |= LU_HEAT_FLAG_OFF;
8939                         break;
8940                 case 'O':
8941                         flags &= ~LU_HEAT_FLAG_OFF;
8942                         break;
8943                 case '?':
8944                         return CMD_HELP;
8945                 default:
8946                         fprintf(stderr, "%s: option '%s' unrecognized\n",
8947                                 argv[0], argv[optind - 1]);
8948                         return CMD_HELP;
8949                 }
8950         }
8951
8952         if (argc <= optind) {
8953                 fprintf(stderr, "%s: please give one or more file names\n",
8954                         argv[0]);
8955                 return CMD_HELP;
8956         }
8957
8958         while (optind < argc) {
8959                 path = argv[optind++];
8960
8961                 fd = open(path, O_RDONLY);
8962                 if (fd < 0) {
8963                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
8964                                 argv[0], path, strerror(errno));
8965                         rc2 = -errno;
8966                         goto next;
8967                 }
8968
8969                 rc2 = llapi_heat_set(fd, flags);
8970                 close(fd);
8971                 if (rc2 < 0) {
8972                         fprintf(stderr, "%s: cannot setflags heat of file '%s'"
8973                                 ": %s\n", argv[0], path, strerror(errno));
8974                         goto next;
8975                 }
8976 next:
8977                 if (rc == 0 && rc2 < 0)
8978                         rc = rc2;
8979         }
8980         return rc;
8981 }
8982
8983 /** The input string contains a comma delimited list of component ids and
8984  * ranges, for example "1,2-4,7".
8985  */
8986 static int parse_mirror_ids(__u16 *ids, int size, char *arg)
8987 {
8988         bool end_of_loop = false;
8989         char *ptr = NULL;
8990         int nr = 0;
8991         int rc;
8992
8993         if (arg == NULL)
8994                 return -EINVAL;
8995
8996         while (!end_of_loop) {
8997                 int start_index;
8998                 int end_index;
8999                 int i;
9000                 char *endptr = NULL;
9001
9002                 rc = -EINVAL;
9003                 ptr = strchrnul(arg, ',');
9004                 end_of_loop = *ptr == '\0';
9005                 *ptr = '\0';
9006
9007                 start_index = strtol(arg, &endptr, 0);
9008                 if (endptr == arg) /* no data at all */
9009                         break;
9010                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
9011                         break;
9012                 if (start_index < 0)
9013                         break;
9014
9015                 end_index = start_index;
9016                 if (*endptr == '-') {
9017                         end_index = strtol(endptr + 1, &endptr, 0);
9018                         if (*endptr != '\0')
9019                                 break;
9020                         if (end_index < start_index)
9021                                 break;
9022                 }
9023
9024                 for (i = start_index; i <= end_index && size > 0; i++) {
9025                         int j;
9026
9027                         /* remove duplicate */
9028                         for (j = 0; j < nr; j++) {
9029                                 if (ids[j] == i)
9030                                         break;
9031                         }
9032                         if (j == nr) { /* no duplicate */
9033                                 ids[nr++] = i;
9034                                 --size;
9035                         }
9036                 }
9037
9038                 if (size == 0 && i < end_index)
9039                         break;
9040
9041                 *ptr = ',';
9042                 arg = ++ptr;
9043                 rc = 0;
9044         }
9045         if (!end_of_loop && ptr != NULL)
9046                 *ptr = ',';
9047
9048         return rc < 0 ? rc : nr;
9049 }
9050
9051 /**
9052  * struct verify_mirror_id - Mirror id to be verified.
9053  * @mirror_id:   A specified mirror id.
9054  * @is_valid_id: @mirror_id is valid or not in the mirrored file.
9055  */
9056 struct verify_mirror_id {
9057         __u16 mirror_id;
9058         bool is_valid_id;
9059 };
9060
9061 /**
9062  * compare_mirror_ids() - Compare mirror ids.
9063  * @layout: Mirror component list.
9064  * @cbdata: Callback data in verify_mirror_id structure.
9065  *
9066  * This is a callback function called by llapi_layout_comp_iterate()
9067  * to compare the specified mirror id with the one in the current
9068  * component of @layout. If they are the same, then the specified
9069  * mirror id is valid.
9070  *
9071  * Return: a negative error code on failure or
9072  *         LLAPI_LAYOUT_ITER_CONT: Proceed iteration
9073  *         LLAPI_LAYOUT_ITER_STOP: Stop iteration
9074  */
9075 static inline
9076 int compare_mirror_ids(struct llapi_layout *layout, void *cbdata)
9077 {
9078         struct verify_mirror_id *mirror_id_cbdata =
9079                                  (struct verify_mirror_id *)cbdata;
9080         uint32_t mirror_id;
9081         int rc = 0;
9082
9083         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
9084         if (rc < 0) {
9085                 rc = -errno;
9086                 fprintf(stderr,
9087                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
9088                         progname, strerror(errno));
9089                 return rc;
9090         }
9091
9092         if (mirror_id_cbdata->mirror_id == mirror_id) {
9093                 mirror_id_cbdata->is_valid_id = true;
9094                 return LLAPI_LAYOUT_ITER_STOP;
9095         }
9096
9097         return LLAPI_LAYOUT_ITER_CONT;
9098 }
9099
9100 /**
9101  * verify_mirror_ids() - Verify specified mirror ids.
9102  * @fname:      Mirrored file name.
9103  * @mirror_ids: Specified mirror ids to be verified.
9104  * @ids_nr:     Number of specified mirror ids.
9105  *
9106  * This function verifies that specified @mirror_ids are valid
9107  * in the mirrored file @fname.
9108  *
9109  * Return: 0 on success or a negative error code on failure.
9110  */
9111 static inline
9112 int verify_mirror_ids(const char *fname, __u16 *mirror_ids, int ids_nr)
9113 {
9114         struct llapi_layout *layout = NULL;
9115         struct verify_mirror_id mirror_id_cbdata = { 0 };
9116         struct stat stbuf;
9117         uint32_t flr_state;
9118         int i;
9119         int fd;
9120         int rc = 0;
9121         int rc2 = 0;
9122
9123         if (ids_nr <= 0)
9124                 return -EINVAL;
9125
9126         if (stat(fname, &stbuf) < 0) {
9127                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
9128                         progname, fname, strerror(errno));
9129                 rc = -errno;
9130                 goto error;
9131         }
9132
9133         if (!S_ISREG(stbuf.st_mode)) {
9134                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
9135                         progname, fname);
9136                 rc = -EINVAL;
9137                 goto error;
9138         }
9139
9140         fd = open(fname, O_DIRECT | O_RDONLY);
9141         if (fd < 0) {
9142                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
9143                         progname, fname, strerror(errno));
9144                 rc = -errno;
9145                 goto error;
9146         }
9147
9148         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
9149         if (rc < 0) {
9150                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
9151                         progname, fname, strerror(errno));
9152                 goto close_fd;
9153         }
9154
9155         layout = llapi_layout_get_by_fd(fd, 0);
9156         if (layout == NULL) {
9157                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
9158                         progname, fname, strerror(errno));
9159                 rc = -errno;
9160                 llapi_lease_release(fd);
9161                 goto close_fd;
9162         }
9163
9164         rc = llapi_layout_flags_get(layout, &flr_state);
9165         if (rc < 0) {
9166                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
9167                         progname, fname, strerror(errno));
9168                 rc = -errno;
9169                 goto free_layout;
9170         }
9171
9172         flr_state &= LCM_FL_FLR_MASK;
9173         switch (flr_state) {
9174         case LCM_FL_NONE:
9175                 rc = -EINVAL;
9176                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
9177                         progname, fname, llapi_layout_flags_string(flr_state));
9178                 goto free_layout;
9179         default:
9180                 break;
9181         }
9182
9183         rc2 = 0;
9184         for (i = 0; i < ids_nr; i++) {
9185                 mirror_id_cbdata.mirror_id = mirror_ids[i];
9186                 mirror_id_cbdata.is_valid_id = false;
9187
9188                 rc = llapi_layout_comp_iterate(layout, compare_mirror_ids,
9189                                                &mirror_id_cbdata);
9190                 if (rc < 0) {
9191                         rc = -errno;
9192                         fprintf(stderr,
9193                                 "%s: '%s' failed to verify mirror id: %u.\n",
9194                                 progname, fname, mirror_ids[i]);
9195                         goto free_layout;
9196                 }
9197
9198                 if (!mirror_id_cbdata.is_valid_id) {
9199                         rc2 = -EINVAL;
9200                         fprintf(stderr,
9201                                 "%s: '%s' invalid specified mirror id: %u.\n",
9202                                 progname, fname, mirror_ids[i]);
9203                 }
9204         }
9205         rc = rc2;
9206
9207 free_layout:
9208         llapi_layout_free(layout);
9209         llapi_lease_release(fd);
9210 close_fd:
9211         close(fd);
9212 error:
9213         return rc;
9214 }
9215
9216 static inline
9217 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
9218                            __u16 *mirror_ids, int ids_nr)
9219 {
9220         struct llapi_resync_comp comp_array[1024] = { { 0 } };
9221         struct llapi_layout *layout;
9222         struct stat stbuf;
9223         uint32_t flr_state;
9224         uint64_t start;
9225         uint64_t end;
9226         int comp_size = 0;
9227         int idx;
9228         int fd;
9229         int rc;
9230         int rc2;
9231
9232         if (stat(fname, &stbuf) < 0) {
9233                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
9234                         progname, fname, strerror(errno));
9235                 rc = -errno;
9236                 goto error;
9237         }
9238         if (!S_ISREG(stbuf.st_mode)) {
9239                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
9240                         progname, fname);
9241                 rc = -EINVAL;
9242                 goto error;
9243         }
9244
9245         fd = open(fname, O_DIRECT | O_RDWR);
9246         if (fd < 0) {
9247                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
9248                         progname, fname, strerror(errno));
9249                 rc = -errno;
9250                 goto error;
9251         }
9252
9253         layout = llapi_layout_get_by_fd(fd, 0);
9254         if (layout == NULL) {
9255                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
9256                         progname, fname, strerror(errno));
9257                 rc = -errno;
9258                 goto close_fd;
9259         }
9260
9261         rc = llapi_layout_flags_get(layout, &flr_state);
9262         if (rc) {
9263                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
9264                         progname, fname, strerror(errno));
9265                 rc = -errno;
9266                 goto free_layout;
9267         }
9268
9269         flr_state &= LCM_FL_FLR_MASK;
9270         if (flr_state == LCM_FL_NONE) {
9271                 rc = -EINVAL;
9272                 fprintf(stderr, "%s: '%s' is not a FLR file.\n",
9273                         progname, fname);
9274                 goto free_layout;
9275         }
9276
9277         /* get stale component info */
9278         comp_size = llapi_mirror_find_stale(layout, comp_array,
9279                                             ARRAY_SIZE(comp_array),
9280                                             mirror_ids, ids_nr);
9281         if (comp_size <= 0) {
9282                 rc = comp_size;
9283                 goto free_layout;
9284         }
9285
9286         ioc->lil_mode = LL_LEASE_WRLCK;
9287         ioc->lil_flags = LL_LEASE_RESYNC;
9288         rc = llapi_lease_set(fd, ioc);
9289         if (rc < 0) {
9290                 if (rc == -EALREADY)
9291                         rc = 0;
9292                 else
9293                         fprintf(stderr,
9294                             "%s: '%s' llapi_lease_get_ext resync failed: %s.\n",
9295                                 progname, fname, strerror(-rc));
9296                 goto free_layout;
9297         }
9298
9299         /* get the read range [start, end) */
9300         start = comp_array[0].lrc_start;
9301         end = comp_array[0].lrc_end;
9302         for (idx = 1; idx < comp_size; idx++) {
9303                 if (comp_array[idx].lrc_start < start)
9304                         start = comp_array[idx].lrc_start;
9305                 if (end < comp_array[idx].lrc_end)
9306                         end = comp_array[idx].lrc_end;
9307         }
9308
9309         rc = llapi_lease_check(fd);
9310         if (rc != LL_LEASE_WRLCK) {
9311                 fprintf(stderr, "%s: '%s' lost lease lock.\n",
9312                         progname, fname);
9313                 goto free_layout;
9314         }
9315
9316         rc = llapi_mirror_resync_many(fd, layout, comp_array, comp_size,
9317                                       start, end);
9318         if (rc < 0)
9319                 fprintf(stderr, "%s: '%s' llapi_mirror_resync_many: %s.\n",
9320                         progname, fname, strerror(-rc));
9321
9322         /* need to do the lease unlock even resync fails */
9323         ioc->lil_mode = LL_LEASE_UNLCK;
9324         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
9325         ioc->lil_count = 0;
9326         for (idx = 0; idx < comp_size; idx++) {
9327                 if (comp_array[idx].lrc_synced) {
9328                         ioc->lil_ids[ioc->lil_count] = comp_array[idx].lrc_id;
9329                         ioc->lil_count++;
9330                 }
9331         }
9332
9333         rc2 = llapi_lease_set(fd, ioc);
9334         /**
9335          * llapi_lease_set returns lease mode when it request to unlock
9336          * the lease lock.
9337          */
9338         if (rc2 <= 0) {
9339                 /* rc2 == 0 means lost lease lock */
9340                 if (rc2 == 0 && rc == 0)
9341                         rc = -EBUSY;
9342                 fprintf(stderr, "%s: resync file '%s' failed: %s.\n",
9343                         progname, fname,
9344                         rc2 == 0 ? "lost lease lock" : strerror(-rc2));
9345         }
9346
9347 free_layout:
9348         llapi_layout_free(layout);
9349 close_fd:
9350         close(fd);
9351 error:
9352         return rc;
9353 }
9354
9355 static inline int lfs_mirror_resync(int argc, char **argv)
9356 {
9357         struct ll_ioc_lease *ioc = NULL;
9358         __u16 mirror_ids[128] = { 0 };
9359         int ids_nr = 0;
9360         int c;
9361         int rc = 0;
9362
9363         struct option long_opts[] = {
9364         { .val = 'o',   .name = "only",         .has_arg = required_argument },
9365         { .name = NULL } };
9366
9367         while ((c = getopt_long(argc, argv, "o:", long_opts, NULL)) >= 0) {
9368                 switch (c) {
9369                 case 'o':
9370                         rc = parse_mirror_ids(mirror_ids,
9371                                         sizeof(mirror_ids) / sizeof(__u16),
9372                                         optarg);
9373                         if (rc < 0) {
9374                                 fprintf(stderr,
9375                                         "%s: bad mirror ids '%s'.\n",
9376                                         argv[0], optarg);
9377                                 goto error;
9378                         }
9379                         ids_nr = rc;
9380                         break;
9381                 default:
9382                         fprintf(stderr, "%s: options '%s' unrecognized.\n",
9383                                 argv[0], argv[optind - 1]);
9384                         rc = -EINVAL;
9385                         goto error;
9386                 }
9387         }
9388
9389         if (argc == optind) {
9390                 fprintf(stderr, "%s: no file name given.\n", argv[0]);
9391                 rc = CMD_HELP;
9392                 goto error;
9393         }
9394
9395         if (ids_nr > 0 && argc > optind + 1) {
9396                 fprintf(stderr,
9397                     "%s: option '--only' cannot be used upon multiple files.\n",
9398                         argv[0]);
9399                 rc = CMD_HELP;
9400                 goto error;
9401
9402         }
9403
9404         if (ids_nr > 0) {
9405                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
9406                 if (rc < 0)
9407                         goto error;
9408         }
9409
9410         /* set the lease on the file */
9411         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
9412         if (ioc == NULL) {
9413                 fprintf(stderr, "%s: cannot alloc id array for ioc: %s.\n",
9414                         argv[0], strerror(errno));
9415                 rc = -errno;
9416                 goto error;
9417         }
9418
9419         for (; optind < argc; optind++) {
9420                 rc = lfs_mirror_resync_file(argv[optind], ioc,
9421                                             mirror_ids, ids_nr);
9422                 /* ignore previous file's error, continue with next file */
9423
9424                 /* reset ioc */
9425                 memset(ioc, 0, sizeof(*ioc) + sizeof(__u32) * 4096);
9426         }
9427
9428         free(ioc);
9429 error:
9430         return rc;
9431 }
9432
9433 static inline int verify_mirror_id_by_fd(int fd, __u16 mirror_id)
9434 {
9435         struct llapi_layout *layout;
9436         int rc;
9437
9438         layout = llapi_layout_get_by_fd(fd, 0);
9439         if (layout == NULL) {
9440                 fprintf(stderr, "could not get layout.\n");
9441                 return  -EINVAL;
9442         }
9443
9444         rc = llapi_layout_comp_iterate(layout, find_mirror_id, &mirror_id);
9445         if (rc < 0) {
9446                 fprintf(stderr, "failed to iterate layout\n");
9447                 llapi_layout_free(layout);
9448
9449                 return rc;
9450         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
9451                 fprintf(stderr, "does not find mirror with ID %u\n", mirror_id);
9452                 llapi_layout_free(layout);
9453
9454                 return -EINVAL;
9455         }
9456         llapi_layout_free(layout);
9457
9458         return 0;
9459 }
9460
9461 /**
9462  * Check whether two files are the same file
9463  * \retval      0  same file
9464  * \retval      1  not the same file
9465  * \retval      <0 error code
9466  */
9467 static inline int check_same_file(int fd, const char *f2)
9468 {
9469         struct stat stbuf1;
9470         struct stat stbuf2;
9471
9472         if (fstat(fd, &stbuf1) < 0)
9473                 return -errno;
9474
9475         if (stat(f2, &stbuf2) < 0)
9476                 return 1;
9477
9478         if (stbuf1.st_rdev == stbuf2.st_rdev &&
9479             stbuf1.st_ino == stbuf2.st_ino)
9480                 return 0;
9481
9482         return 1;
9483 }
9484
9485 static inline int lfs_mirror_read(int argc, char **argv)
9486 {
9487         int rc = CMD_HELP;
9488         __u16 mirror_id = 0;
9489         const char *outfile = NULL;
9490         char *fname;
9491         int fd = 0;
9492         int outfd;
9493         int c;
9494         void *buf;
9495         const size_t buflen = 4 << 20;
9496         off_t pos;
9497         struct option long_opts[] = {
9498         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
9499         { .val = 'o',   .name = "outfile",      .has_arg = required_argument },
9500         { .name = NULL } };
9501
9502         while ((c = getopt_long(argc, argv, "N:o:", long_opts, NULL)) >= 0) {
9503                 char *end;
9504
9505                 switch (c) {
9506                 case 'N':
9507                         mirror_id = strtoul(optarg, &end, 0);
9508                         if (*end != '\0' || mirror_id == 0) {
9509                                 fprintf(stderr,
9510                                         "%s %s: invalid mirror ID '%s'\n",
9511                                         progname, argv[0], optarg);
9512                                 return rc;
9513                         }
9514                         break;
9515                 case 'o':
9516                         outfile = optarg;
9517                         break;
9518                 default:
9519                         fprintf(stderr, "%s: option '%s' unrecognized.\n",
9520                                 progname, argv[optind - 1]);
9521                         return -EINVAL;
9522                 }
9523         }
9524
9525         if (argc == optind) {
9526                 fprintf(stderr, "%s %s: no mirrored file provided\n",
9527                         progname, argv[0]);
9528                 return rc;
9529         } else if (argc > optind + 1) {
9530                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
9531                 return rc;
9532         }
9533
9534         if (mirror_id == 0) {
9535                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
9536                         progname, argv[0]);
9537                 return rc;
9538         }
9539
9540         /* open mirror file */
9541         fname = argv[optind];
9542         fd = open(fname, O_DIRECT | O_RDONLY);
9543         if (fd < 0) {
9544                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
9545                         progname, argv[0], fname, strerror(errno));
9546                 return rc;
9547         }
9548
9549         /* verify mirror id */
9550         rc = verify_mirror_id_by_fd(fd, mirror_id);
9551         if (rc) {
9552                 fprintf(stderr,
9553                         "%s %s: cannot find mirror with ID %u in '%s'\n",
9554                         progname, argv[0], mirror_id, fname);
9555                 goto close_fd;
9556         }
9557
9558         /* open output file - O_EXCL ensures output is not the same as input */
9559         if (outfile) {
9560                 outfd = open(outfile, O_EXCL | O_WRONLY | O_CREAT, 0644);
9561                 if (outfd < 0) {
9562                         fprintf(stderr, "%s %s: cannot create file '%s': %s\n",
9563                                 progname, argv[0], outfile, strerror(errno));
9564                         rc = -errno;
9565                         goto close_fd;
9566                 }
9567         } else {
9568                 outfd = STDOUT_FILENO;
9569         }
9570
9571         /* allocate buffer */
9572         rc = posix_memalign(&buf, sysconf(_SC_PAGESIZE), buflen);
9573         if (rc) {
9574                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
9575                                 progname, argv[0], rc);
9576                 goto close_outfd;
9577         }
9578
9579         pos = 0;
9580         while (1) {
9581                 ssize_t bytes_read;
9582                 ssize_t written = 0;
9583
9584                 bytes_read = llapi_mirror_read(fd, mirror_id, buf, buflen, pos);
9585                 if (bytes_read < 0) {
9586                         rc = bytes_read;
9587                         fprintf(stderr,
9588                                 "%s %s: fail to read data from mirror %u: %s\n",
9589                                 progname, argv[0], mirror_id, strerror(-rc));
9590                         goto free_buf;
9591                 }
9592
9593                 /* EOF reached */
9594                 if (bytes_read == 0)
9595                         break;
9596
9597                 while (written < bytes_read) {
9598                         ssize_t written2;
9599
9600                         written2 = write(outfd, buf + written,
9601                                          bytes_read - written);
9602                         if (written2 < 0) {
9603                                 fprintf(stderr,
9604                                         "%s %s: fail to write %s: %s\n",
9605                                         progname, argv[0], outfile ? : "STDOUT",
9606                                         strerror(errno));
9607                                 rc = -errno;
9608                                 goto free_buf;
9609                         }
9610                         written += written2;
9611                 }
9612
9613                 if (written != bytes_read) {
9614                         fprintf(stderr,
9615                 "%s %s: written %ld bytes does not match with %ld read.\n",
9616                                 progname, argv[0], written, bytes_read);
9617                         rc = -EIO;
9618                         goto free_buf;
9619                 }
9620
9621                 pos += bytes_read;
9622         }
9623
9624         fsync(outfd);
9625         rc = 0;
9626
9627 free_buf:
9628         free(buf);
9629 close_outfd:
9630         if (outfile)
9631                 close(outfd);
9632 close_fd:
9633         close(fd);
9634
9635         return rc;
9636 }
9637
9638 static inline int lfs_mirror_write(int argc, char **argv)
9639 {
9640         int rc = CMD_HELP;
9641         __u16 mirror_id = 0;
9642         const char *inputfile = NULL;
9643         char *fname;
9644         int fd = 0;
9645         int inputfd;
9646         int c;
9647         void *buf;
9648         const size_t buflen = 4 << 20;
9649         off_t pos;
9650         size_t page_size = sysconf(_SC_PAGESIZE);
9651         struct ll_ioc_lease_id ioc;
9652
9653         struct option long_opts[] = {
9654         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
9655         { .val = 'i',   .name = "inputfile",    .has_arg = required_argument },
9656         { .name = NULL } };
9657
9658         while ((c = getopt_long(argc, argv, "N:i:", long_opts, NULL)) >= 0) {
9659                 char *end;
9660
9661                 switch (c) {
9662                 case 'N':
9663                         mirror_id = strtoul(optarg, &end, 0);
9664                         if (*end != '\0' || mirror_id == 0) {
9665                                 fprintf(stderr,
9666                                         "%s %s: invalid mirror ID '%s'\n",
9667                                         progname, argv[0], optarg);
9668                                 return rc;
9669                         }
9670                         break;
9671                 case 'i':
9672                         inputfile = optarg;
9673                         break;
9674                 default:
9675                         fprintf(stderr, "%s: option '%s' unrecognized\n",
9676                                 progname, argv[optind - 1]);
9677                         return -EINVAL;
9678                 }
9679         }
9680
9681         if (argc == optind) {
9682                 fprintf(stderr, "%s %s: no mirrored file provided\n",
9683                         progname, argv[0]);
9684                 return rc;
9685         } else if (argc > optind + 1) {
9686                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
9687                 return rc;
9688         }
9689
9690         if (mirror_id == 0) {
9691                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
9692                         progname, argv[0]);
9693                 return rc;
9694         }
9695
9696         /* open mirror file */
9697         fname = argv[optind];
9698         fd = open(fname, O_DIRECT | O_WRONLY);
9699         if (fd < 0) {
9700                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
9701                         progname, argv[0], fname, strerror(errno));
9702                 return rc;
9703         }
9704
9705         /* verify mirror id */
9706         rc = verify_mirror_id_by_fd(fd, mirror_id);
9707         if (rc) {
9708                 fprintf(stderr,
9709                         "%s %s: cannot find mirror with ID %u in '%s'\n",
9710                         progname, argv[0], mirror_id, fname);
9711                 goto close_fd;
9712         }
9713
9714         /* open input file */
9715         if (inputfile) {
9716                 rc = check_same_file(fd, inputfile);
9717                 if (rc == 0) {
9718                         fprintf(stderr,
9719                         "%s %s: input file cannot be the mirrored file\n",
9720                                 progname, argv[0]);
9721                         goto close_fd;
9722                 }
9723                 if (rc < 0)
9724                         goto close_fd;
9725
9726                 inputfd = open(inputfile, O_RDONLY, 0644);
9727                 if (inputfd < 0) {
9728                         fprintf(stderr, "%s %s: cannot open file '%s': %s\n",
9729                                 progname, argv[0], inputfile, strerror(errno));
9730                         rc = -errno;
9731                         goto close_fd;
9732                 }
9733         } else {
9734                 inputfd = STDIN_FILENO;
9735         }
9736
9737         /* allocate buffer */
9738         rc = posix_memalign(&buf, page_size, buflen);
9739         if (rc) {
9740                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
9741                         progname, argv[0], rc);
9742                 goto close_inputfd;
9743         }
9744
9745         /* prepare target mirror components instantiation */
9746         ioc.lil_mode = LL_LEASE_WRLCK;
9747         ioc.lil_flags = LL_LEASE_RESYNC;
9748         ioc.lil_mirror_id = mirror_id;
9749         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
9750         if (rc < 0) {
9751                 fprintf(stderr,
9752                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
9753                         progname, argv[0], fname, strerror(errno));
9754                 goto free_buf;
9755         }
9756
9757         pos = 0;
9758         while (1) {
9759                 ssize_t bytes_read;
9760                 ssize_t written;
9761                 size_t to_write;
9762
9763                 rc = llapi_lease_check(fd);
9764                 if (rc != LL_LEASE_WRLCK) {
9765                         fprintf(stderr, "%s %s: '%s' lost lease lock\n",
9766                                 progname, argv[0], fname);
9767                         goto free_buf;
9768                 }
9769
9770                 bytes_read = read(inputfd, buf, buflen);
9771                 if (bytes_read < 0) {
9772                         rc = bytes_read;
9773                         fprintf(stderr,
9774                                 "%s %s: fail to read data from '%s': %s\n",
9775                                 progname, argv[0], inputfile ? : "STDIN",
9776                                 strerror(errno));
9777                         rc = -errno;
9778                         goto free_buf;
9779                 }
9780
9781                 /* EOF reached */
9782                 if (bytes_read == 0)
9783                         break;
9784
9785                 /* round up to page align to make direct IO happy. */
9786                 to_write = (bytes_read + page_size - 1) & ~(page_size - 1);
9787
9788                 written = llapi_mirror_write(fd, mirror_id, buf, to_write,
9789                                              pos);
9790                 if (written < 0) {
9791                         rc = written;
9792                         fprintf(stderr,
9793                               "%s %s: fail to write to mirror %u: %s\n",
9794                                 progname, argv[0], mirror_id,
9795                                 strerror(-rc));
9796                         goto free_buf;
9797                 }
9798
9799                 pos += bytes_read;
9800         }
9801
9802         if (pos & (page_size - 1)) {
9803                 rc = llapi_mirror_truncate(fd, mirror_id, pos);
9804                 if (rc < 0)
9805                         goto free_buf;
9806         }
9807
9808         ioc.lil_mode = LL_LEASE_UNLCK;
9809         ioc.lil_flags = LL_LEASE_RESYNC_DONE;
9810         ioc.lil_count = 0;
9811         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
9812         if (rc <= 0) {
9813                 if (rc == 0)
9814                         rc = -EBUSY;
9815                 fprintf(stderr,
9816                         "%s %s: release lease lock of '%s' failed: %s\n",
9817                         progname, argv[0], fname, strerror(errno));
9818                 goto free_buf;
9819         }
9820
9821         rc = 0;
9822
9823 free_buf:
9824         free(buf);
9825 close_inputfd:
9826         if (inputfile)
9827                 close(inputfd);
9828 close_fd:
9829         close(fd);
9830
9831         return rc;
9832 }
9833
9834 static inline int get_other_mirror_ids(int fd, __u16 *ids, __u16 exclude_id)
9835 {
9836         struct llapi_layout *layout;
9837         struct collect_ids_data cid = { .cid_ids = ids,
9838                                         .cid_count = 0,
9839                                         .cid_exclude = exclude_id, };
9840         int rc;
9841
9842         layout = llapi_layout_get_by_fd(fd, 0);
9843         if (layout == NULL) {
9844                 fprintf(stderr, "could not get layout\n");
9845                 return -EINVAL;
9846         }
9847
9848         rc = llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
9849         if (rc < 0) {
9850                 fprintf(stderr, "failed to iterate layout\n");
9851                 llapi_layout_free(layout);
9852
9853                 return rc;
9854         }
9855         llapi_layout_free(layout);
9856
9857         return cid.cid_count;
9858 }
9859
9860 static inline int lfs_mirror_copy(int argc, char **argv)
9861 {
9862         int rc = CMD_HELP;
9863         __u16 read_mirror_id = 0;
9864         __u16 ids[128] = { 0 };
9865         int count = 0;
9866         struct llapi_layout *layout = NULL;
9867         struct llapi_resync_comp comp_array[1024] = { { 0 } };
9868         int comp_size = 0;
9869         char *fname;
9870         int fd = 0;
9871         int c;
9872         int i;
9873         ssize_t copied;
9874         struct ll_ioc_lease *ioc = NULL;
9875         struct ll_ioc_lease_id *resync_ioc;
9876
9877         struct option long_opts[] = {
9878         { .val = 'i',   .name = "read-mirror",  .has_arg = required_argument },
9879         { .val = 'o',   .name = "write-mirror", .has_arg = required_argument },
9880         { .name = NULL } };
9881
9882         while ((c = getopt_long(argc, argv, "i:o:", long_opts, NULL)) >= 0) {
9883                 char *end;
9884
9885                 switch (c) {
9886                 case 'i':
9887                         read_mirror_id = strtoul(optarg, &end, 0);
9888                         if (*end != '\0' || read_mirror_id == 0) {
9889                                 fprintf(stderr,
9890                                         "%s %s: invalid read mirror ID '%s'\n",
9891                                         progname, argv[0], optarg);
9892                                 return rc;
9893                         }
9894                         break;
9895                 case 'o':
9896                         if (!strcmp(optarg, "-1")) {
9897                                 /* specify all other mirrors */
9898                                 ids[0] = (__u16)-1;
9899                                 count = 1;
9900                         } else {
9901                                 count = parse_mirror_ids((__u16 *)ids,
9902                                                          ARRAY_SIZE(ids),
9903                                                          optarg);
9904                                 if (count < 0)
9905                                         return rc;
9906                         }
9907                         break;
9908                 default:
9909                         fprintf(stderr, "%s: option '%s' unrecognized\n",
9910                                 progname, argv[optind - 1]);
9911                         return -EINVAL;
9912                 }
9913         }
9914
9915         if (argc == optind) {
9916                 fprintf(stderr, "%s %s: no mirrored file provided\n",
9917                         progname, argv[0]);
9918                 return rc;
9919         } else if (argc > optind + 1) {
9920                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
9921                 return rc;
9922         }
9923
9924         if (read_mirror_id == 0) {
9925                 fprintf(stderr,
9926                         "%s %s: no valid read mirror ID %d is provided\n",
9927                         progname, argv[0], read_mirror_id);
9928                 return rc;
9929         }
9930
9931         if (count == 0) {
9932                 fprintf(stderr,
9933                         "%s %s: no write mirror ID is provided\n",
9934                         progname, argv[0]);
9935                 return rc;
9936         }
9937
9938         for (i = 0; i < count; i++) {
9939                 if (read_mirror_id == ids[i]) {
9940                         fprintf(stderr,
9941                         "%s %s: read and write mirror ID cannot be the same\n",
9942                                 progname, argv[0]);
9943                         return rc;
9944                 }
9945         }
9946
9947         /* open mirror file */
9948         fname = argv[optind];
9949
9950         fd = open(fname, O_DIRECT | O_RDWR);
9951         if (fd < 0) {
9952                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
9953                         progname, argv[0], fname, strerror(errno));
9954                 return rc;
9955         }
9956
9957         /* write to all other mirrors */
9958         if (ids[0] == (__u16)-1) {
9959                 count = get_other_mirror_ids(fd, ids, read_mirror_id);
9960                 if (count <= 0) {
9961                         rc = count;
9962                         fprintf(stderr,
9963                         "%s %s: failed to get other mirror ids in '%s': %d\n",
9964                                 progname, argv[0], fname, rc);
9965                         goto close_fd;
9966                 }
9967         }
9968
9969         /* verify mirror id */
9970         rc = verify_mirror_id_by_fd(fd, read_mirror_id);
9971         if (rc) {
9972                 fprintf(stderr,
9973                         "%s %s: cannot find mirror with ID %u in '%s'\n",
9974                         progname, argv[0], read_mirror_id, fname);
9975                 goto close_fd;
9976         }
9977
9978         for (i = 0; i < count; i++) {
9979                 rc = verify_mirror_id_by_fd(fd, ids[i]);
9980                 if (rc) {
9981                         fprintf(stderr,
9982                         "%s %s: cannot find mirror with ID %u in '%s'\n",
9983                                 progname, argv[0], ids[i], fname);
9984                         goto close_fd;
9985                 }
9986         }
9987
9988         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
9989         if (ioc == NULL) {
9990                 fprintf(stderr,
9991                         "%s %s: cannot alloc comp id array for ioc: %s\n",
9992                         progname, argv[0], strerror(errno));
9993                 rc = -errno;
9994                 goto close_fd;
9995         }
9996
9997         /* get stale component info */
9998         layout = llapi_layout_get_by_fd(fd, 0);
9999         if (layout == NULL) {
10000                 fprintf(stderr, "%s %s: failed to get layout of '%s': %s\n",
10001                         progname, argv[0], fname, strerror(errno));
10002                 rc = -errno;
10003                 goto free_ioc;
10004         }
10005         comp_size = llapi_mirror_find_stale(layout, comp_array,
10006                                             ARRAY_SIZE(comp_array),
10007                                             ids, count);
10008         llapi_layout_free(layout);
10009         if (comp_size < 0) {
10010                 rc = comp_size;
10011                 goto free_ioc;
10012         }
10013
10014         /* prepare target mirror components instantiation */
10015         resync_ioc = (struct ll_ioc_lease_id *)ioc;
10016         resync_ioc->lil_mode = LL_LEASE_WRLCK;
10017         resync_ioc->lil_flags = LL_LEASE_RESYNC;
10018         if (count == 1)
10019                 resync_ioc->lil_mirror_id = ids[0];
10020         else
10021                 resync_ioc->lil_mirror_id = read_mirror_id | MIRROR_ID_NEG;
10022         rc = llapi_lease_set(fd, ioc);
10023         if (rc < 0) {
10024                 fprintf(stderr,
10025                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
10026                         progname, argv[0], fname, strerror(errno));
10027                 goto free_ioc;
10028         }
10029
10030         copied = llapi_mirror_copy_many(fd, read_mirror_id, ids, count);
10031         if (copied < 0) {
10032                 rc = copied;
10033                 fprintf(stderr, "%s %s: copy error: %d\n",
10034                         progname, argv[0], rc);
10035                 goto free_ioc;
10036         }
10037
10038         fprintf(stdout, "mirror copied successfully: ");
10039         for (i = 0; i < copied; i++)
10040                 fprintf(stdout, "%d ", ids[i]);
10041         fprintf(stdout, "\n");
10042
10043         ioc->lil_mode = LL_LEASE_UNLCK;
10044         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
10045         ioc->lil_count = 0;
10046         for (i = 0; i < comp_size; i++) {
10047                 int j;
10048
10049                 for (j = 0; j < copied; j++) {
10050                         if (comp_array[i].lrc_mirror_id != ids[j])
10051                                 continue;
10052
10053                         ioc->lil_ids[ioc->lil_count] = comp_array[i].lrc_id;
10054                         ioc->lil_count++;
10055                 }
10056         }
10057         rc = llapi_lease_set(fd, ioc);
10058         if (rc <= 0) {
10059                 if (rc == 0)
10060                         rc = -EBUSY;
10061                 fprintf(stderr,
10062                         "%s %s: release lease lock of '%s' failed: %s\n",
10063                         progname, argv[0], fname, strerror(errno));
10064                 goto free_ioc;
10065         }
10066
10067         rc = 0;
10068
10069 free_ioc:
10070         free(ioc);
10071 close_fd:
10072         close(fd);
10073
10074         return rc;
10075 }
10076 /**
10077  * struct verify_chunk - Mirror chunk to be verified.
10078  * @chunk:        [start, end) of the chunk.
10079  * @mirror_count: Number of mirror ids in @mirror_id array.
10080  * @mirror_id:    Array of valid mirror ids that cover the chunk.
10081  */
10082 struct verify_chunk {
10083         struct lu_extent chunk;
10084         unsigned int mirror_count;
10085         __u16 mirror_id[LUSTRE_MIRROR_COUNT_MAX];
10086 };
10087
10088 /**
10089  * print_chunks() - Print chunk information.
10090  * @fname:       Mirrored file name.
10091  * @chunks:      Array of chunks.
10092  * @chunk_count: Number of chunks in @chunks array.
10093  *
10094  * This function prints [start, end) of each chunk in @chunks
10095  * for mirrored file @fname, and also prints the valid mirror ids
10096  * that cover the chunk.
10097  *
10098  * Return: void.
10099  */
10100 static inline
10101 void print_chunks(const char *fname, struct verify_chunk *chunks,
10102                   int chunk_count)
10103 {
10104         int i;
10105         int j;
10106
10107         fprintf(stdout, "Chunks to be verified in %s:\n", fname);
10108         for (i = 0; i < chunk_count; i++) {
10109                 fprintf(stdout, DEXT, PEXT(&chunks[i].chunk));
10110
10111                 if (chunks[i].mirror_count == 0)
10112                         fprintf(stdout, "\t[");
10113                 else {
10114                         fprintf(stdout, "\t[%u", chunks[i].mirror_id[0]);
10115                         for (j = 1; j < chunks[i].mirror_count; j++)
10116                                 fprintf(stdout, ", %u", chunks[i].mirror_id[j]);
10117                 }
10118                 fprintf(stdout, "]\t%u\n", chunks[i].mirror_count);
10119         }
10120         fprintf(stdout, "\n");
10121 }
10122
10123 /**
10124  * print_checksums() - Print CRC-32 checksum values.
10125  * @chunk: A chunk and its corresponding valid mirror ids.
10126  * @crc:   CRC-32 checksum values on the chunk for each valid mirror.
10127  *
10128  * This function prints CRC-32 checksum values on @chunk for
10129  * each valid mirror that covers it.
10130  *
10131  * Return: void.
10132  */
10133 static inline
10134 void print_checksums(struct verify_chunk *chunk, unsigned long *crc)
10135 {
10136         int i;
10137
10138         fprintf(stdout,
10139                 "CRC-32 checksum value for chunk "DEXT":\n",
10140                 PEXT(&chunk->chunk));
10141         for (i = 0; i < chunk->mirror_count; i++)
10142                 fprintf(stdout, "Mirror %u:\t%#lx\n",
10143                         chunk->mirror_id[i], crc[i]);
10144         fprintf(stdout, "\n");
10145 }
10146
10147 /**
10148  * filter_mirror_id() - Filter specified mirror ids.
10149  * @chunks:      Array of chunks.
10150  * @chunk_count: Number of chunks in @chunks array.
10151  * @mirror_ids:  Specified mirror ids to be verified.
10152  * @ids_nr:      Number of specified mirror ids.
10153  *
10154  * This function scans valid mirror ids that cover each chunk in @chunks
10155  * and filters specified mirror ids.
10156  *
10157  * Return: void.
10158  */
10159 static inline
10160 void filter_mirror_id(struct verify_chunk *chunks, int chunk_count,
10161                       __u16 *mirror_ids, int ids_nr)
10162 {
10163         int i;
10164         int j;
10165         int k;
10166         __u16 valid_id[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
10167         unsigned int valid_count = 0;
10168
10169         for (i = 0; i < chunk_count; i++) {
10170                 if (chunks[i].mirror_count == 0)
10171                         continue;
10172
10173                 valid_count = 0;
10174                 for (j = 0; j < ids_nr; j++) {
10175                         for (k = 0; k < chunks[i].mirror_count; k++) {
10176                                 if (chunks[i].mirror_id[k] == mirror_ids[j]) {
10177                                         valid_id[valid_count] = mirror_ids[j];
10178                                         valid_count++;
10179                                         break;
10180                                 }
10181                         }
10182                 }
10183
10184                 memcpy(chunks[i].mirror_id, valid_id,
10185                        sizeof(__u16) * valid_count);
10186                 chunks[i].mirror_count = valid_count;
10187         }
10188 }
10189
10190 /**
10191  * lfs_mirror_prepare_chunk() - Find mirror chunks to be verified.
10192  * @layout:      Mirror component list.
10193  * @chunks:      Array of chunks.
10194  * @chunks_size: Array size of @chunks.
10195  *
10196  * This function scans the components in @layout from offset 0 to LUSTRE_EOF
10197  * to find out chunk segments and store them in @chunks array.
10198  *
10199  * The @mirror_id array in each element of @chunks will store the valid
10200  * mirror ids that cover the chunk. If a mirror component covering the
10201  * chunk has LCME_FL_STALE or LCME_FL_OFFLINE flag, then the mirror id
10202  * will not be stored into the @mirror_id array, and the chunk for that
10203  * mirror will not be verified.
10204  *
10205  * The @mirror_count in each element of @chunks will store the number of
10206  * mirror ids in @mirror_id array. If @mirror_count is 0, it indicates the
10207  * chunk is invalid in all of the mirrors. And if @mirror_count is 1, it
10208  * indicates the chunk is valid in only one mirror. In both cases, the
10209  * chunk will not be verified.
10210  *
10211  * Here is an example:
10212  *
10213  *  0      1M     2M     3M     4M           EOF
10214  *  +------+-------------+--------------------+
10215  *  |      |             |      S             |       mirror1
10216  *  +------+------+------+------+-------------+
10217  *  |             |   S  |   S  |             |       mirror2
10218  *  +-------------+------+------+-------------+
10219  *
10220  * prepared @chunks array will contain 5 elements:
10221  * (([0, 1M), [1, 2], 2),
10222  *  ([1M, 2M), [1, 2], 2),
10223  *  ([2M, 3M), [1], 1),
10224  *  ([3M, 4M], [], 0),
10225  *  ([4M, EOF), [2], 1))
10226  *
10227  * Return: the actual array size of @chunks on success
10228  *         or a negative error code on failure.
10229  */
10230 static inline
10231 int lfs_mirror_prepare_chunk(struct llapi_layout *layout,
10232                              struct verify_chunk *chunks,
10233                              size_t chunks_size)
10234 {
10235         uint64_t start;
10236         uint64_t end;
10237         uint32_t mirror_id;
10238         uint32_t flags;
10239         int idx = 0;
10240         int i = 0;
10241         int rc = 0;
10242
10243         memset(chunks, 0, sizeof(*chunks) * chunks_size);
10244
10245         while (1) {
10246                 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
10247                 if (rc < 0) {
10248                         fprintf(stderr,
10249                                 "%s: move to the first layout component: %s.\n",
10250                                 progname, strerror(errno));
10251                         goto error;
10252                 }
10253
10254                 i = 0;
10255                 rc = 0;
10256                 chunks[idx].chunk.e_end = LUSTRE_EOF;
10257                 while (rc == 0) {
10258                         rc = llapi_layout_comp_extent_get(layout, &start, &end);
10259                         if (rc < 0) {
10260                                 fprintf(stderr,
10261                                         "%s: llapi_layout_comp_extent_get failed: %s.\n",
10262                                         progname, strerror(errno));
10263                                 goto error;
10264                         }
10265
10266                         if (start > chunks[idx].chunk.e_start ||
10267                             end <= chunks[idx].chunk.e_start)
10268                                 goto next;
10269
10270                         if (end < chunks[idx].chunk.e_end)
10271                                 chunks[idx].chunk.e_end = end;
10272
10273                         rc = llapi_layout_comp_flags_get(layout, &flags);
10274                         if (rc < 0) {
10275                                 fprintf(stderr,
10276                                         "%s: llapi_layout_comp_flags_get failed: %s.\n",
10277                                         progname, strerror(errno));
10278                                 goto error;
10279                         }
10280
10281                         if (flags & LCME_FL_STALE || flags & LCME_FL_OFFLINE)
10282                                 goto next;
10283
10284                         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
10285                         if (rc < 0) {
10286                                 fprintf(stderr,
10287                                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
10288                                         progname, strerror(errno));
10289                                 goto error;
10290                         }
10291
10292                         chunks[idx].mirror_id[i] = mirror_id;
10293                         i++;
10294                         if (i >= ARRAY_SIZE(chunks[idx].mirror_id)) {
10295                                 fprintf(stderr,
10296                                         "%s: mirror_id array is too small.\n",
10297                                         progname);
10298                                 rc = -EINVAL;
10299                                 goto error;
10300                         }
10301
10302                 next:
10303                         rc = llapi_layout_comp_use(layout,
10304                                                    LLAPI_LAYOUT_COMP_USE_NEXT);
10305                         if (rc < 0) {
10306                                 fprintf(stderr,
10307                                         "%s: move to the next layout component: %s.\n",
10308                                         progname, strerror(errno));
10309                                 goto error;
10310                         }
10311                 } /* loop through all components */
10312
10313                 chunks[idx].mirror_count = i;
10314
10315                 if (chunks[idx].chunk.e_end == LUSTRE_EOF)
10316                         break;
10317
10318                 idx++;
10319                 if (idx >= chunks_size) {
10320                         fprintf(stderr, "%s: chunks array is too small.\n",
10321                                 progname);
10322                         rc = -EINVAL;
10323                         goto error;
10324                 }
10325
10326                 chunks[idx].chunk.e_start = chunks[idx - 1].chunk.e_end;
10327         }
10328
10329 error:
10330         return rc < 0 ? rc : idx + 1;
10331 }
10332
10333 /**
10334  * lfs_mirror_verify_chunk() - Verify a chunk.
10335  * @fd:        File descriptor of the mirrored file.
10336  * @file_size: Size of the mirrored file.
10337  * @chunk:     A chunk and its corresponding valid mirror ids.
10338  * @verbose:   Verbose mode.
10339  *
10340  * This function verifies a @chunk contains exactly the same data
10341  * ammong the mirrors that cover it.
10342  *
10343  * If @verbose is specified, then the function will print where the
10344  * differences are if the data do not match. Otherwise, it will
10345  * just return an error in that case.
10346  *
10347  * Return: 0 on success or a negative error code on failure.
10348  */
10349 static inline
10350 int lfs_mirror_verify_chunk(int fd, size_t file_size,
10351                             struct verify_chunk *chunk, int verbose)
10352 {
10353         const size_t buflen = 4 * 1024 * 1024; /* 4M */
10354         void *buf;
10355         size_t page_size = sysconf(_SC_PAGESIZE);
10356         ssize_t bytes_read;
10357         ssize_t bytes_done;
10358         size_t count;
10359         off_t pos;
10360         unsigned long crc;
10361         unsigned long crc_array[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
10362         int i;
10363         int rc = 0;
10364
10365         if (file_size == 0)
10366                 return 0;
10367
10368         rc = posix_memalign(&buf, page_size, buflen);
10369         if (rc) /* error code is returned directly */
10370                 return -rc;
10371
10372         if (verbose > 1) {
10373                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
10374                         PEXT(&chunk->chunk));
10375                 for (i = 0; i < chunk->mirror_count; i++)
10376                         fprintf(stdout, " %u", chunk->mirror_id[i]);
10377                 fprintf(stdout, "\n");
10378         }
10379
10380         bytes_done = 0;
10381         count = MIN(chunk->chunk.e_end, file_size) - chunk->chunk.e_start;
10382         pos = chunk->chunk.e_start;
10383         while (bytes_done < count) {
10384                 /* compute initial CRC-32 checksum */
10385                 crc = crc32(0L, Z_NULL, 0);
10386                 memset(crc_array, 0, sizeof(crc_array));
10387
10388                 bytes_read = 0;
10389                 for (i = 0; i < chunk->mirror_count; i++) {
10390                         bytes_read = llapi_mirror_read(fd, chunk->mirror_id[i],
10391                                                        buf, buflen, pos);
10392                         if (bytes_read < 0) {
10393                                 rc = bytes_read;
10394                                 fprintf(stderr,
10395                                         "%s: failed to read data from mirror %u: %s.\n",
10396                                         progname, chunk->mirror_id[i],
10397                                         strerror(-rc));
10398                                 goto error;
10399                         }
10400
10401                         /* compute new CRC-32 checksum */
10402                         crc_array[i] = crc32(crc, buf, bytes_read);
10403                 }
10404
10405                 if (verbose)
10406                         print_checksums(chunk, crc_array);
10407
10408                 /* compare CRC-32 checksum values */
10409                 for (i = 1; i < chunk->mirror_count; i++) {
10410                         if (crc_array[i] != crc_array[0]) {
10411                                 rc = -EINVAL;
10412
10413                                 fprintf(stderr,
10414                                         "%s: chunk "DEXT" has different checksum value on mirror %u and mirror %u.\n",
10415                                         progname, PEXT(&chunk->chunk),
10416                                         chunk->mirror_id[0],
10417                                         chunk->mirror_id[i]);
10418                         }
10419                 }
10420
10421                 pos += bytes_read;
10422                 bytes_done += bytes_read;
10423         }
10424
10425         if (verbose > 1 && rc == 0) {
10426                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
10427                         PEXT(&chunk->chunk));
10428                 for (i = 0; i < chunk->mirror_count; i++)
10429                         fprintf(stdout, " %u", chunk->mirror_id[i]);
10430                 fprintf(stdout, " PASS\n\n");
10431         }
10432
10433 error:
10434         free(buf);
10435         return rc;
10436 }
10437
10438 /**
10439  * lfs_mirror_verify_file() - Verify a mirrored file.
10440  * @fname:      Mirrored file name.
10441  * @mirror_ids: Specified mirror ids to be verified.
10442  * @ids_nr:     Number of specified mirror ids.
10443  * @verbose:    Verbose mode.
10444  *
10445  * This function verifies that each SYNC mirror of a mirrored file
10446  * specified by @fname contains exactly the same data.
10447  *
10448  * If @mirror_ids is specified, then the function will verify the
10449  * mirrors specified by @mirror_ids contain exactly the same data.
10450  *
10451  * If @verbose is specified, then the function will print where the
10452  * differences are if the data do not match. Otherwise, it will
10453  * just return an error in that case.
10454  *
10455  * Return: 0 on success or a negative error code on failure.
10456  */
10457 static inline
10458 int lfs_mirror_verify_file(const char *fname, __u16 *mirror_ids, int ids_nr,
10459                            int verbose)
10460 {
10461         struct verify_chunk chunks_array[1024] = { };
10462         struct llapi_layout *layout = NULL;
10463         struct stat stbuf;
10464         uint32_t flr_state;
10465         int fd;
10466         int chunk_count = 0;
10467         int idx = 0;
10468         int rc = 0;
10469         int rc1 = 0;
10470         int rc2 = 0;
10471
10472         if (stat(fname, &stbuf) < 0) {
10473                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
10474                         progname, fname, strerror(errno));
10475                 rc = -errno;
10476                 goto error;
10477         }
10478
10479         if (!S_ISREG(stbuf.st_mode)) {
10480                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
10481                         progname, fname);
10482                 rc = -EINVAL;
10483                 goto error;
10484         }
10485
10486         if (stbuf.st_size == 0) {
10487                 if (verbose)
10488                         fprintf(stdout, "%s: '%s' file size is 0.\n",
10489                                 progname, fname);
10490                 rc = 0;
10491                 goto error;
10492         }
10493
10494         fd = open(fname, O_DIRECT | O_RDONLY);
10495         if (fd < 0) {
10496                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
10497                         progname, fname, strerror(errno));
10498                 rc = -errno;
10499                 goto error;
10500         }
10501
10502         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
10503         if (rc < 0) {
10504                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
10505                         progname, fname, strerror(errno));
10506                 goto close_fd;
10507         }
10508
10509         layout = llapi_layout_get_by_fd(fd, 0);
10510         if (layout == NULL) {
10511                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
10512                         progname, fname, strerror(errno));
10513                 rc = -errno;
10514                 llapi_lease_release(fd);
10515                 goto close_fd;
10516         }
10517
10518         rc = llapi_layout_flags_get(layout, &flr_state);
10519         if (rc < 0) {
10520                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
10521                         progname, fname, strerror(errno));
10522                 rc = -errno;
10523                 goto free_layout;
10524         }
10525
10526         flr_state &= LCM_FL_FLR_MASK;
10527         switch (flr_state) {
10528         case LCM_FL_NONE:
10529                 rc = -EINVAL;
10530                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
10531                         progname, fname, llapi_layout_flags_string(flr_state));
10532                 goto free_layout;
10533         default:
10534                 break;
10535         }
10536
10537         /* find out mirror chunks to be verified */
10538         chunk_count = lfs_mirror_prepare_chunk(layout, chunks_array,
10539                                                ARRAY_SIZE(chunks_array));
10540         if (chunk_count < 0) {
10541                 rc = chunk_count;
10542                 goto free_layout;
10543         }
10544
10545         if (ids_nr > 0)
10546                 /* filter specified mirror ids */
10547                 filter_mirror_id(chunks_array, chunk_count, mirror_ids, ids_nr);
10548
10549         if (verbose > 2)
10550                 print_chunks(fname, chunks_array, chunk_count);
10551
10552         for (idx = 0; idx < chunk_count; idx++) {
10553                 if (chunks_array[idx].chunk.e_start >= stbuf.st_size) {
10554                         if (verbose)
10555                                 fprintf(stdout,
10556                                         "%s: '%s' chunk "DEXT" exceeds file size %#llx: skipped\n",
10557                                         progname, fname,
10558                                         PEXT(&chunks_array[idx].chunk),
10559                                         (unsigned long long)stbuf.st_size);
10560                         break;
10561                 }
10562
10563                 if (chunks_array[idx].mirror_count == 0) {
10564                         fprintf(stderr,
10565                                 "%s: '%s' chunk "DEXT" is invalid in all of the mirrors: ",
10566                                 progname, fname,
10567                                 PEXT(&chunks_array[idx].chunk));
10568                         if (verbose) {
10569                                 fprintf(stderr, "skipped\n");
10570                                 continue;
10571                         }
10572                         rc = -EINVAL;
10573                         fprintf(stderr, "failed\n");
10574                         goto free_layout;
10575                 }
10576
10577                 if (chunks_array[idx].mirror_count == 1) {
10578                         if (verbose)
10579                                 fprintf(stdout,
10580                                         "%s: '%s' chunk "DEXT" is only valid in mirror %u: skipped\n",
10581                                         progname, fname,
10582                                         PEXT(&chunks_array[idx].chunk),
10583                                         chunks_array[idx].mirror_id[0]);
10584                         continue;
10585                 }
10586
10587                 rc = llapi_lease_check(fd);
10588                 if (rc != LL_LEASE_RDLCK) {
10589                         fprintf(stderr, "%s: '%s' lost lease lock.\n",
10590                                 progname, fname);
10591                         goto free_layout;
10592                 }
10593
10594                 /* verify one chunk */
10595                 rc1 = lfs_mirror_verify_chunk(fd, stbuf.st_size,
10596                                               &chunks_array[idx], verbose);
10597                 if (rc1 < 0) {
10598                         rc2 = rc1;
10599                         if (!verbose) {
10600                                 rc = rc1;
10601                                 goto free_layout;
10602                         }
10603                 }
10604         }
10605
10606         if (rc2 < 0)
10607                 rc = rc2;
10608
10609 free_layout:
10610         llapi_layout_free(layout);
10611         llapi_lease_release(fd);
10612 close_fd:
10613         close(fd);
10614 error:
10615         return rc;
10616 }
10617
10618 /**
10619  * lfs_mirror_verify() - Parse and execute lfs mirror verify command.
10620  * @argc: The count of lfs mirror verify command line arguments.
10621  * @argv: Array of strings for lfs mirror verify command line arguments.
10622  *
10623  * This function parses lfs mirror verify command and verifies the
10624  * specified mirrored file(s).
10625  *
10626  * Return: 0 on success or a negative error code on failure.
10627  */
10628 static inline int lfs_mirror_verify(int argc, char **argv)
10629 {
10630         __u16 mirror_ids[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
10631         int ids_nr = 0;
10632         int c;
10633         int verbose = 0;
10634         int rc = 0;
10635         int rc1 = 0;
10636         char cmd[PATH_MAX];
10637
10638         struct option long_opts[] = {
10639         { .val = 'o',   .name = "only",         .has_arg = required_argument },
10640         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
10641         { .name = NULL } };
10642
10643         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
10644         progname = cmd;
10645         while ((c = getopt_long(argc, argv, "o:v", long_opts, NULL)) >= 0) {
10646                 switch (c) {
10647                 case 'o':
10648                         rc = parse_mirror_ids(mirror_ids,
10649                                               ARRAY_SIZE(mirror_ids),
10650                                               optarg);
10651                         if (rc < 0) {
10652                                 fprintf(stderr,
10653                                         "%s: bad mirror ids '%s'.\n",
10654                                         progname, optarg);
10655                                 goto error;
10656                         }
10657                         ids_nr = rc;
10658                         if (ids_nr < 2) {
10659                                 fprintf(stderr,
10660                                         "%s: at least 2 mirror ids needed with '--only' option.\n",
10661                                         progname);
10662                                 rc = CMD_HELP;
10663                                 goto error;
10664                         }
10665                         break;
10666                 case 'v':
10667                         verbose++;
10668                         break;
10669                 default:
10670                         fprintf(stderr, "%s: option '%s' unrecognized.\n",
10671                                 progname, argv[optind - 1]);
10672                         rc = -EINVAL;
10673                         goto error;
10674                 }
10675         }
10676
10677         if (argc == optind) {
10678                 fprintf(stderr, "%s: no file name given.\n", progname);
10679                 rc = CMD_HELP;
10680                 goto error;
10681         }
10682
10683         if (ids_nr > 0 && argc > optind + 1) {
10684                 fprintf(stderr,
10685                         "%s: '--only' cannot be used upon multiple files.\n",
10686                         progname);
10687                 rc = CMD_HELP;
10688                 goto error;
10689
10690         }
10691
10692         if (ids_nr > 0) {
10693                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
10694                 if (rc < 0)
10695                         goto error;
10696         }
10697
10698         rc = 0;
10699         for (; optind < argc; optind++) {
10700                 rc1 = lfs_mirror_verify_file(argv[optind], mirror_ids, ids_nr,
10701                                              verbose);
10702                 if (rc1 < 0)
10703                         rc = rc1;
10704         }
10705 error:
10706         return rc;
10707 }
10708
10709 /**
10710  * lfs_mirror() - Parse and execute lfs mirror commands.
10711  * @argc: The count of lfs mirror command line arguments.
10712  * @argv: Array of strings for lfs mirror command line arguments.
10713  *
10714  * This function parses lfs mirror commands and performs the
10715  * corresponding functions specified in mirror_cmdlist[].
10716  *
10717  * Return: 0 on success or an error code on failure.
10718  */
10719 static int lfs_mirror(int argc, char **argv)
10720 {
10721         char cmd[PATH_MAX];
10722         int rc = 0;
10723
10724         setlinebuf(stdout);
10725
10726         Parser_init("lfs-mirror > ", mirror_cmdlist);
10727
10728         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
10729         progname = cmd;
10730         program_invocation_short_name = cmd;
10731         if (argc > 1)
10732                 rc = Parser_execarg(argc - 1, argv + 1, mirror_cmdlist);
10733         else
10734                 rc = Parser_commands();
10735
10736         return rc < 0 ? -rc : rc;
10737 }
10738
10739 static void lustre_som_swab(struct lustre_som_attrs *attrs)
10740 {
10741 #if __BYTE_ORDER == __BIG_ENDIAN
10742         __swab16s(&attrs->lsa_valid);
10743         __swab64s(&attrs->lsa_size);
10744         __swab64s(&attrs->lsa_blocks);
10745 #endif
10746 }
10747
10748 enum lfs_som_type {
10749         LFS_SOM_SIZE = 0x1,
10750         LFS_SOM_BLOCKS = 0x2,
10751         LFS_SOM_FLAGS = 0x4,
10752         LFS_SOM_ATTR_ALL = LFS_SOM_SIZE | LFS_SOM_BLOCKS |
10753                            LFS_SOM_FLAGS,
10754 };
10755
10756 static int lfs_getsom(int argc, char **argv)
10757 {
10758         const char *path;
10759         struct lustre_som_attrs *attrs;
10760         char buf[sizeof(*attrs) + 64];
10761         enum lfs_som_type type = LFS_SOM_ATTR_ALL;
10762         int rc = 0, c;
10763
10764         while ((c = getopt(argc, argv, "sbf")) != -1) {
10765                 switch (c) {
10766                 case 's':
10767                         type = LFS_SOM_SIZE;
10768                         break;
10769                 case 'b':
10770                         type = LFS_SOM_BLOCKS;
10771                         break;
10772                 case 'f':
10773                         type = LFS_SOM_FLAGS;
10774                         break;
10775                 default:
10776                         fprintf(stderr, "%s: invalid option '%c'\n",
10777                                 progname, optopt);
10778                         return CMD_HELP;
10779                 }
10780         }
10781
10782         argc -= optind;
10783         argv += optind;
10784
10785         if (argc != 1) {
10786                 fprintf(stderr, "%s: %s\n",
10787                         progname, argc == 0 ? "miss file target" :
10788                         "input more than 2 files");
10789                 return CMD_HELP;
10790         }
10791
10792         path = argv[0];
10793         attrs = (void *)buf;
10794         rc = lgetxattr(path, "trusted.som", attrs, sizeof(buf));
10795         if (rc < 0) {
10796                 rc = -errno;
10797                 fprintf(stderr, "%s failed to get som xattr: %s (%d)\n",
10798                         argv[0], strerror(errno), errno);
10799                 return rc;
10800         }
10801
10802         lustre_som_swab(attrs);
10803
10804         switch (type) {
10805         case LFS_SOM_ATTR_ALL:
10806                 printf("file: %s size: %llu blocks: %llu flags: %x\n",
10807                        path, (unsigned long long)attrs->lsa_size,
10808                        (unsigned long long)attrs->lsa_blocks,
10809                        attrs->lsa_valid);
10810                 break;
10811         case LFS_SOM_SIZE:
10812                 printf("%llu\n", (unsigned long long)attrs->lsa_size);
10813                 break;
10814         case LFS_SOM_BLOCKS:
10815                 printf("%llu\n", (unsigned long long)attrs->lsa_blocks);
10816                 break;
10817         case LFS_SOM_FLAGS:
10818                 printf("%x\n", attrs->lsa_valid);
10819                 break;
10820         default:
10821                 fprintf(stderr, "%s: unknown option\n", progname);
10822                 return CMD_HELP;
10823         }
10824
10825         return 0;
10826 }
10827
10828 /**
10829  * lfs_mirror_list_commands() - List lfs mirror commands.
10830  * @argc: The count of command line arguments.
10831  * @argv: Array of strings for command line arguments.
10832  *
10833  * This function lists lfs mirror commands defined in mirror_cmdlist[].
10834  *
10835  * Return: 0 on success.
10836  */
10837 static int lfs_mirror_list_commands(int argc, char **argv)
10838 {
10839         char buffer[81] = "";
10840
10841         Parser_list_commands(mirror_cmdlist, buffer, sizeof(buffer),
10842                              NULL, 0, 4);
10843
10844         return 0;
10845 }
10846
10847 static int lfs_pcc_attach(int argc, char **argv)
10848 {
10849         struct option long_opts[] = {
10850         { .val = 'i',   .name = "id",   .has_arg = required_argument },
10851         { .name = NULL } };
10852         int c;
10853         int rc = 0;
10854         __u32 archive_id = 0;
10855         const char *path;
10856         char *end;
10857         char fullpath[PATH_MAX];
10858         enum lu_pcc_type type = LU_PCC_READWRITE;
10859
10860         optind = 0;
10861         while ((c = getopt_long(argc, argv, "i:",
10862                                 long_opts, NULL)) != -1) {
10863                 switch (c) {
10864                 case 'i':
10865                         archive_id = strtoul(optarg, &end, 0);
10866                         if (*end != '\0' || archive_id == 0) {
10867                                 fprintf(stderr, "error: %s: bad archive ID "
10868                                         "'%s'\n", argv[0], optarg);
10869                                 return CMD_HELP;
10870                         }
10871                         break;
10872                 case '?':
10873                         return CMD_HELP;
10874                 default:
10875                         fprintf(stderr, "%s: option '%s' unrecognized\n",
10876                                 argv[0], argv[optind - 1]);
10877                         return CMD_HELP;
10878                 }
10879         }
10880
10881         if (archive_id == 0) {
10882                 fprintf(stderr, "%s: must specify attach ID\n", argv[0]);
10883                 return CMD_HELP;
10884         }
10885
10886         if (argc <= optind) {
10887                 fprintf(stderr, "%s: must specify one or more file names\n",
10888                         argv[0]);
10889                 return CMD_HELP;
10890         }
10891
10892         while (optind < argc) {
10893                 int rc2;
10894
10895                 path = argv[optind++];
10896                 if (realpath(path, fullpath) == NULL) {
10897                         fprintf(stderr, "%s: could not find path '%s': %s\n",
10898                                 argv[0], path, strerror(errno));
10899                         if (rc == 0)
10900                                 rc = -EINVAL;
10901                         continue;
10902                 }
10903
10904                 rc2 = llapi_pcc_attach(fullpath, archive_id, type);
10905                 if (rc2 < 0) {
10906                         fprintf(stderr, "%s: cannot attach '%s' to PCC "
10907                                 "with archive ID '%u': %s\n", argv[0],
10908                                 path, archive_id, strerror(-rc2));
10909                         if (rc == 0)
10910                                 rc = rc2;
10911                 }
10912         }
10913         return rc;
10914 }
10915
10916 static int lfs_pcc_attach_fid(int argc, char **argv)
10917 {
10918         struct option long_opts[] = {
10919         { .val = 'i',   .name = "id",   .has_arg = required_argument },
10920         { .val = 'm',   .name = "mnt",  .has_arg = required_argument },
10921         { .name = NULL } };
10922         char                     short_opts[] = "i:m:";
10923         int                      c;
10924         int                      rc = 0;
10925         __u32                    archive_id = 0;
10926         char                    *end;
10927         const char              *mntpath = NULL;
10928         const char              *fidstr;
10929         enum lu_pcc_type         type = LU_PCC_READWRITE;
10930
10931         optind = 0;
10932         while ((c = getopt_long(argc, argv, short_opts,
10933                                 long_opts, NULL)) != -1) {
10934                 switch (c) {
10935                 case 'i':
10936                         archive_id = strtoul(optarg, &end, 0);
10937                         if (*end != '\0') {
10938                                 fprintf(stderr, "error: %s: bad archive ID "
10939                                         "'%s'\n", argv[0], optarg);
10940                                 return CMD_HELP;
10941                         }
10942                         break;
10943                 case 'm':
10944                         mntpath = optarg;
10945                         break;
10946                 case '?':
10947                         return CMD_HELP;
10948                 default:
10949                         fprintf(stderr, "%s: option '%s' unrecognized\n",
10950                                 argv[0], argv[optind - 1]);
10951                         return CMD_HELP;
10952                 }
10953         }
10954
10955         if (archive_id == 0) {
10956                 fprintf(stderr, "%s: must specify an archive ID\n", argv[0]);
10957                 return CMD_HELP;
10958         }
10959
10960         if (mntpath == NULL) {
10961                 fprintf(stderr, "%s: must specify Lustre mount point\n",
10962                         argv[0]);
10963                 return CMD_HELP;
10964         }
10965
10966         if (argc <= optind) {
10967                 fprintf(stderr, "%s: must specify one or more fids\n", argv[0]);
10968                 return CMD_HELP;
10969         }
10970
10971         while (optind < argc) {
10972                 int rc2;
10973
10974                 fidstr = argv[optind++];
10975
10976                 rc2 = llapi_pcc_attach_fid_str(mntpath, fidstr,
10977                                                archive_id, type);
10978                 if (rc2 < 0) {
10979                         fprintf(stderr, "%s: cannot attach '%s' on '%s' to PCC "
10980                                 "with archive ID '%u': %s\n", argv[0],
10981                                 fidstr, mntpath, archive_id, strerror(rc2));
10982                 }
10983                 if (rc == 0 && rc2 < 0)
10984                         rc = rc2;
10985         }
10986         return rc;
10987 }
10988
10989 static int lfs_pcc_detach(int argc, char **argv)
10990 {
10991         struct option long_opts[] = {
10992         { .val = 'k',   .name = "keep", .has_arg = no_argument },
10993         { .name = NULL } };
10994         char                     short_opts[] = "k";
10995         int                      c;
10996         int                      rc = 0;
10997         const char              *path;
10998         char                     fullpath[PATH_MAX];
10999         __u32                    detach_opt = PCC_DETACH_OPT_UNCACHE;
11000
11001         optind = 0;
11002         while ((c = getopt_long(argc, argv, short_opts,
11003                                 long_opts, NULL)) != -1) {
11004                 switch (c) {
11005                 case 'k':
11006                         detach_opt = PCC_DETACH_OPT_NONE;
11007                         break;
11008                 case '?':
11009                         return CMD_HELP;
11010                 default:
11011                         fprintf(stderr, "%s: option '%s' unrecognized\n",
11012                                 argv[0], argv[optind - 1]);
11013                         return CMD_HELP;
11014                 }
11015         }
11016
11017         while (optind < argc) {
11018                 int rc2;
11019
11020                 path = argv[optind++];
11021                 if (realpath(path, fullpath) == NULL) {
11022                         fprintf(stderr, "%s: could not find path '%s': %s\n",
11023                                 argv[0], path, strerror(errno));
11024                         if (rc == 0)
11025                                 rc = -EINVAL;
11026                         continue;
11027                 }
11028
11029                 rc2 = llapi_pcc_detach_file(fullpath, detach_opt);
11030                 if (rc2 < 0) {
11031                         rc2 = -errno;
11032                         fprintf(stderr, "%s: cannot detach '%s' from PCC: "
11033                                 "%s\n", argv[0], path, strerror(errno));
11034                         if (rc == 0)
11035                                 rc = rc2;
11036                 }
11037         }
11038         return rc;
11039 }
11040
11041 static int lfs_pcc_detach_fid(int argc, char **argv)
11042 {
11043         struct option long_opts[] = {
11044         { .val = 'k',   .name = "keep", .has_arg = no_argument },
11045         { .name = NULL } };
11046         char             short_opts[] = "k";
11047         int              c;
11048         int              rc = 0;
11049         const char      *fid;
11050         const char      *mntpath;
11051         __u32            detach_opt = PCC_DETACH_OPT_UNCACHE;
11052
11053         optind = 0;
11054         while ((c = getopt_long(argc, argv, short_opts,
11055                                 long_opts, NULL)) != -1) {
11056                 switch (c) {
11057                 case 'k':
11058                         detach_opt = PCC_DETACH_OPT_NONE;
11059                         break;
11060                 case '?':
11061                         return CMD_HELP;
11062                 default:
11063                         fprintf(stderr, "%s: option '%s' unrecognized\n",
11064                                 argv[0], argv[optind - 1]);
11065                         return CMD_HELP;
11066                 }
11067         }
11068
11069         mntpath = argv[optind++];
11070
11071         while (optind < argc) {
11072                 int rc2;
11073
11074                 fid = argv[optind++];
11075
11076                 rc2 = llapi_pcc_detach_fid_str(mntpath, fid, detach_opt);
11077                 if (rc2 < 0) {
11078                         fprintf(stderr, "%s: cannot detach '%s' on '%s' "
11079                                 "from PCC: %s\n", argv[0], fid, mntpath,
11080                                 strerror(-rc2));
11081                         if (rc == 0)
11082                                 rc = rc2;
11083                 }
11084         }
11085         return rc;
11086 }
11087
11088 static int lfs_pcc_state(int argc, char **argv)
11089 {
11090         int                      rc = 0;
11091         const char              *path;
11092         char                     fullpath[PATH_MAX];
11093         struct lu_pcc_state      state;
11094
11095         optind = 1;
11096
11097         if (argc <= 1) {
11098                 fprintf(stderr, "%s: must specify one or more file names\n",
11099                         argv[0]);
11100                 return CMD_HELP;
11101         }
11102
11103         while (optind < argc) {
11104                 int rc2;
11105
11106                 path = argv[optind++];
11107                 if (realpath(path, fullpath) == NULL) {
11108                         fprintf(stderr, "%s: could not find path '%s': %s\n",
11109                                 argv[0], path, strerror(errno));
11110                         if (rc == 0)
11111                                 rc = -EINVAL;
11112                         continue;
11113                 }
11114
11115                 rc2 = llapi_pcc_state_get(fullpath, &state);
11116                 if (rc2 < 0) {
11117                         if (rc == 0)
11118                                 rc = rc2;
11119                         fprintf(stderr, "%s: cannot get PCC state of '%s': "
11120                                 "%s\n", argv[0], path, strerror(-rc2));
11121                         continue;
11122                 }
11123
11124                 printf("file: %s", path);
11125                 printf(", type: %s", pcc_type2string(state.pccs_type));
11126                 if (state.pccs_type == LU_PCC_NONE &&
11127                     state.pccs_open_count == 0) {
11128                         printf("\n");
11129                         continue;
11130                 }
11131
11132                 printf(", PCC file: %s", state.pccs_path);
11133                 printf(", user number: %u", state.pccs_open_count);
11134                 printf(", flags: %x", state.pccs_flags);
11135                 printf("\n");
11136         }
11137         return rc;
11138 }
11139
11140 /**
11141  * lfs_pcc_list_commands() - List lfs pcc commands.
11142  * @argc: The count of command line arguments.
11143  * @argv: Array of strings for command line arguments.
11144  *
11145  * This function lists lfs pcc commands defined in pcc_cmdlist[].
11146  *
11147  * Return: 0 on success.
11148  */
11149 static int lfs_pcc_list_commands(int argc, char **argv)
11150 {
11151         char buffer[81] = "";
11152
11153         Parser_list_commands(pcc_cmdlist, buffer, sizeof(buffer),
11154                              NULL, 0, 4);
11155
11156         return 0;
11157 }
11158
11159 /**
11160  * lfs_pcc() - Parse and execute lfs pcc commands.
11161  * @argc: The count of lfs pcc command line arguments.
11162  * @argv: Array of strings for lfs pcc command line arguments.
11163  *
11164  * This function parses lfs pcc commands and performs the
11165  * corresponding functions specified in pcc_cmdlist[].
11166  *
11167  * Return: 0 on success or an error code on failure.
11168  */
11169 static int lfs_pcc(int argc, char **argv)
11170 {
11171         char cmd[PATH_MAX];
11172         int rc = 0;
11173
11174         setlinebuf(stdout);
11175
11176         Parser_init("lfs-pcc > ", pcc_cmdlist);
11177
11178         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
11179         progname = cmd;
11180         program_invocation_short_name = cmd;
11181         if (argc > 1)
11182                 rc = Parser_execarg(argc - 1, argv + 1, pcc_cmdlist);
11183         else
11184                 rc = Parser_commands();
11185
11186         return rc < 0 ? -rc : rc;
11187 }
11188
11189 static int lfs_list_commands(int argc, char **argv)
11190 {
11191         char buffer[81] = ""; /* 80 printable chars + terminating NUL */
11192
11193         Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
11194
11195         return 0;
11196 }
11197
11198 int main(int argc, char **argv)
11199 {
11200         int rc;
11201
11202         /* Ensure that liblustreapi constructor has run */
11203         if (!llapi_liblustreapi_initialized())
11204                 fprintf(stderr, "liblustreapi was not properly initialized\n");
11205
11206         setlinebuf(stdout);
11207         opterr = 0;
11208
11209         Parser_init("lfs > ", cmdlist);
11210
11211         progname = program_invocation_short_name; /* Used in error messages */
11212         if (argc > 1) {
11213                 llapi_set_command_name(argv[1]);
11214                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
11215                 llapi_clear_command_name();
11216         } else {
11217                 rc = Parser_commands();
11218         }
11219
11220         return rc < 0 ? -rc : rc;
11221 }
11222
11223 #ifdef _LUSTRE_IDL_H_
11224 /* Everything we need here should be included by lustreapi.h. */
11225 # error "lfs should not depend on lustre_idl.h"
11226 #endif /* _LUSTRE_IDL_H_ */