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