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