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