Whamcloud - gitweb
LU-13826 utils: fix compatibility for LL_IOC_MDC_GETINFO
[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                 fprintf(stderr,
6213                         "%s %s: stripe offset and count must be specified\n",
6214                         progname, argv[0]);
6215                 return CMD_HELP;
6216         }
6217
6218         if (delete &&
6219             (lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
6220              lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)) {
6221                 fprintf(stderr,
6222                         "%s %s: cannot specify -d with -c or -i options\n",
6223                         progname, argv[0]);
6224                 return CMD_HELP;
6225         }
6226
6227         if (mode_opt) {
6228                 mode = strtoul(mode_opt, &end, 8);
6229                 if (*end != '\0') {
6230                         fprintf(stderr,
6231                                 "%s %s: bad MODE '%s'\n",
6232                                 progname, argv[0], mode_opt);
6233                         return CMD_HELP;
6234                 }
6235                 previous_mode = umask(0);
6236         }
6237
6238         /* foreign LMV/dir case */
6239         if (foreign_mode) {
6240                 if (argc > optind + 1) {
6241                         fprintf(stderr,
6242                                 "%s %s: cannot specify multiple foreign dirs\n",
6243                                 progname, argv[0]);
6244                         return CMD_HELP;
6245                 }
6246
6247                 dname = argv[optind];
6248                 result = llapi_dir_create_foreign(dname, mode, type, flags,
6249                                                   xattr);
6250                 if (result != 0)
6251                         fprintf(stderr,
6252                                 "%s mkdir: can't create foreign dir '%s': %s\n",
6253                                 progname, dname, strerror(-result));
6254                 return result;
6255         }
6256
6257         /*
6258          * initialize stripe parameters, in case param is converted to specific,
6259          * i.e, 'lfs mkdir -i -1 -c N', always allocate space for lsp_tgts.
6260          */
6261         param = calloc(1, offsetof(typeof(*param),
6262                        lsp_tgts[lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ?
6263                                 lsa.lsa_stripe_count : lsa.lsa_nr_tgts]));
6264         if (!param) {
6265                 fprintf(stderr,
6266                         "%s %s: cannot allocate memory for parameters: %s\n",
6267                         progname, argv[0], strerror(ENOMEM));
6268                 return CMD_HELP;
6269         }
6270
6271         /* if "lfs setdirstripe -D -i -1" is used, assume 1-stripe directory */
6272         if (default_stripe && lsa.lsa_stripe_off == -1 &&
6273             (lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT ||
6274              lsa.lsa_stripe_count == 0))
6275                 lsa.lsa_stripe_count = 1;
6276         if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
6277                 param->lsp_stripe_count = lsa.lsa_stripe_count;
6278         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
6279                 param->lsp_stripe_offset = -1;
6280         else
6281                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
6282         if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
6283                 param->lsp_stripe_pattern = lsa.lsa_pattern;
6284         else
6285                 param->lsp_stripe_pattern = LMV_HASH_TYPE_UNKNOWN;
6286         param->lsp_pool = lsa.lsa_pool_name;
6287         param->lsp_is_specific = false;
6288         if (lsa.lsa_nr_tgts > 1) {
6289                 if (lsa.lsa_stripe_count > 0 &&
6290                     lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
6291                     lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
6292                         fprintf(stderr,
6293                                 "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
6294                                 argv[0], lsa.lsa_stripe_count,
6295                                 lsa.lsa_nr_tgts);
6296                         free(param);
6297                         return CMD_HELP;
6298                 }
6299
6300                 param->lsp_is_specific = true;
6301                 param->lsp_stripe_count = lsa.lsa_nr_tgts;
6302                 memcpy(param->lsp_tgts, mdts, sizeof(*mdts) * lsa.lsa_nr_tgts);
6303         }
6304
6305         dname = argv[optind];
6306         do {
6307                 if (default_stripe) {
6308                         result = llapi_dir_set_default_lmv(dname, param);
6309                         if (result)
6310                                 fprintf(stderr,
6311                                         "%s setdirstripe: cannot set default stripe on dir '%s': %s\n",
6312                                         progname, dname, strerror(-result));
6313                         continue;
6314                 }
6315
6316                 result = llapi_dir_create(dname, mode, param);
6317                 if (result)
6318                         fprintf(stderr,
6319                                 "%s setdirstripe: cannot create dir '%s': %s\n",
6320                                 progname, dname, strerror(-result));
6321         } while (!result && (dname = argv[++optind]));
6322
6323         if (mode_opt)
6324                 umask(previous_mode);
6325
6326         free(param);
6327         return result;
6328 }
6329
6330 /* functions */
6331 static int lfs_rmentry(int argc, char **argv)
6332 {
6333         char *dname;
6334         int   index;
6335         int   result = 0;
6336
6337         if (argc <= 1) {
6338                 fprintf(stderr, "error: %s: missing dirname\n",
6339                         argv[0]);
6340                 return CMD_HELP;
6341         }
6342
6343         index = 1;
6344         dname = argv[index];
6345         while (dname) {
6346                 result = llapi_direntry_remove(dname);
6347                 if (result) {
6348                         fprintf(stderr,
6349                                 "error: %s: remove dir entry '%s' failed\n",
6350                                 argv[0], dname);
6351                         break;
6352                 }
6353                 dname = argv[++index];
6354         }
6355         return result;
6356 }
6357
6358 static int lfs_mv(int argc, char **argv)
6359 {
6360         struct lmv_user_md lmu = { LMV_USER_MAGIC };
6361         struct find_param param = {
6362                 .fp_max_depth = -1,
6363                 .fp_mdt_index = -1,
6364         };
6365         char *end;
6366         int c;
6367         int rc = 0;
6368         struct option long_opts[] = {
6369         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
6370         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
6371         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
6372         { .name = NULL } };
6373
6374         while ((c = getopt_long(argc, argv, "m:M:v", long_opts, NULL)) != -1) {
6375                 switch (c) {
6376 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6377                 case 'M':
6378                         fprintf(stderr,
6379                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
6380 #endif
6381                 case 'm':
6382                         lmu.lum_stripe_offset = strtoul(optarg, &end, 0);
6383                         if (*end != '\0') {
6384                                 fprintf(stderr, "%s mv: bad MDT index '%s'\n",
6385                                         progname, optarg);
6386                                 return CMD_HELP;
6387                         }
6388                         break;
6389                 case 'v':
6390                         param.fp_verbose = VERBOSE_DETAIL;
6391                         break;
6392                 default:
6393                         fprintf(stderr, "%s mv: unrecognized option '%s'\n",
6394                                 progname, argv[optind - 1]);
6395                         return CMD_HELP;
6396                 }
6397         }
6398
6399         if (lmu.lum_stripe_offset == LMV_OFFSET_DEFAULT) {
6400                 fprintf(stderr, "%s mv: MDT index must be specified\n",
6401                         progname);
6402                 return CMD_HELP;
6403         }
6404
6405         if (optind >= argc) {
6406                 fprintf(stderr, "%s mv: DIR must be specified\n", progname);
6407                 return CMD_HELP;
6408         }
6409
6410         lmu.lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
6411
6412         /* initialize migrate mdt parameters */
6413         param.fp_lmv_md = &lmu;
6414         param.fp_migrate = 1;
6415         rc = llapi_migrate_mdt(argv[optind], &param);
6416         if (rc != 0)
6417                 fprintf(stderr, "%s mv: cannot migrate '%s' to MDT%04x: %s\n",
6418                         progname, argv[optind], lmu.lum_stripe_offset,
6419                         strerror(-rc));
6420         return rc;
6421 }
6422
6423 static int lfs_osts(int argc, char **argv)
6424 {
6425         return lfs_tgts(argc, argv);
6426 }
6427
6428 static int lfs_mdts(int argc, char **argv)
6429 {
6430         return lfs_tgts(argc, argv);
6431 }
6432
6433 static int lfs_df(int argc, char **argv)
6434 {
6435         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
6436         enum mntdf_flags flags = MNTDF_SHOW;
6437         int ops = LL_STATFS_LMV | LL_STATFS_LOV;
6438         int c, rc = 0, index = 0;
6439         char fsname[PATH_MAX] = "", *pool_name = NULL;
6440         struct option long_opts[] = {
6441         { .val = 'h',   .name = "human-readable",
6442                                                 .has_arg = no_argument },
6443         { .val = 'i',   .name = "inodes",       .has_arg = no_argument },
6444         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
6445         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
6446         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
6447         { .name = NULL} };
6448
6449         while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
6450                 switch (c) {
6451                 case 'h':
6452                         flags |= MNTDF_COOKED;
6453                         break;
6454                 case 'i':
6455                         flags |= MNTDF_INODES;
6456                         break;
6457                 case 'l':
6458                         flags |= MNTDF_LAZY;
6459                         break;
6460                 case 'p':
6461                         pool_name = optarg;
6462                         break;
6463                 case 'v':
6464                         flags |= MNTDF_VERBOSE;
6465                         break;
6466                 default:
6467                         return CMD_HELP;
6468                 }
6469         }
6470         if (optind < argc && !realpath(argv[optind], path)) {
6471                 rc = -errno;
6472                 fprintf(stderr, "error: invalid path '%s': %s\n",
6473                         argv[optind], strerror(-rc));
6474                 return rc;
6475         }
6476
6477         while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
6478                 /* Check if we have a mount point */
6479                 if (mntdir[0] == '\0')
6480                         continue;
6481
6482                 rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
6483                 if (rc || path[0] != '\0')
6484                         break;
6485                 fsname[0] = '\0'; /* avoid matching in next loop */
6486                 mntdir[0] = '\0'; /* avoid matching in next loop */
6487         }
6488
6489         return rc;
6490 }
6491
6492 static int print_instance(const char *mntdir, char *buf, size_t buflen,
6493                           bool opt_instance, bool opt_fsname, bool opt_mntdir)
6494 {
6495         int rc = 0;
6496
6497         if (opt_fsname == opt_instance) { /* both true or both false */
6498                 rc = llapi_getname(mntdir, buf, buflen);
6499         } else if (opt_fsname) {
6500                 /*
6501                  * llapi_search_mounts() fills @buf with fsname, but that is not
6502                  * called if explicit paths are specified on the command-line
6503                  */
6504                 if (buf[0] == '\0')
6505                         rc = llapi_get_fsname(mntdir, buf, buflen);
6506         } else /* if (opt_instance) */ {
6507                 rc = llapi_get_instance(mntdir, buf, buflen);
6508         }
6509
6510         if (rc < 0) {
6511                 fprintf(stderr, "cannot get instance for '%s': %s\n",
6512                         mntdir, strerror(-rc));
6513                 return rc;
6514         }
6515
6516         if (opt_mntdir)
6517                 printf("%s %s\n", buf, mntdir);
6518         else
6519                 printf("%s\n", buf);
6520
6521         return 0;
6522 }
6523
6524 static int lfs_getname(int argc, char **argv)
6525 {
6526         struct option long_opts[] = {
6527         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6528         { .val = 'i',   .name = "instance",     .has_arg = no_argument },
6529         { .val = 'n',   .name = "fsname",       .has_arg = no_argument },
6530         { .name = NULL} };
6531         bool opt_instance = false, opt_fsname = false;
6532         char fsname[PATH_MAX] = "";
6533         int rc = 0, rc2, c;
6534
6535         while ((c = getopt_long(argc, argv, "hin", long_opts, NULL)) != -1) {
6536                 switch (c) {
6537                 case 'i':
6538                         opt_instance = true;
6539                         break;
6540                 case 'n':
6541                         opt_fsname = true;
6542                         break;
6543                 case 'h':
6544                 default:
6545                         return CMD_HELP;
6546                 }
6547         }
6548
6549         if (optind == argc) { /* no paths specified, get all paths. */
6550                 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "";
6551                 int index = 0;
6552
6553                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
6554                         rc2 = print_instance(mntdir, fsname, sizeof(fsname),
6555                                              opt_instance, opt_fsname, true);
6556                         if (!rc)
6557                                 rc = rc2;
6558                         path[0] = fsname[0] = mntdir[0] = '\0';
6559                 }
6560         } else { /* paths specified, only attempt to search these. */
6561                 bool opt_mntdir;
6562
6563                 /* if only one path is given, print only requested info */
6564                 opt_mntdir = argc - optind > 1 || (opt_instance == opt_fsname);
6565
6566                 for (; optind < argc; optind++) {
6567                         rc2 = print_instance(argv[optind], fsname,
6568                                              sizeof(fsname), opt_instance,
6569                                              opt_fsname, opt_mntdir);
6570                         if (!rc)
6571                                 rc = rc2;
6572                         fsname[0] = '\0';
6573                 }
6574         }
6575
6576         return rc;
6577 }
6578
6579 static int lfs_check(int argc, char **argv)
6580 {
6581         char mntdir[PATH_MAX] = {'\0'};
6582         int num_types = 1;
6583         char *obd_types[3];
6584         char obd_type1[4];
6585         char obd_type2[4];
6586         char obd_type3[4];
6587         int rc;
6588
6589         if (argc != 2) {
6590                 fprintf(stderr, "%s check: server type must be specified\n",
6591                         progname);
6592                 return CMD_HELP;
6593         }
6594
6595         obd_types[0] = obd_type1;
6596         obd_types[1] = obd_type2;
6597         obd_types[2] = obd_type3;
6598
6599         if (strcmp(argv[1], "osts") == 0) {
6600                 strcpy(obd_types[0], "osc");
6601         } else if (strcmp(argv[1], "mdts") == 0 ||
6602                    strcmp(argv[1], "mds") == 0) {
6603                 strcpy(obd_types[0], "mdc");
6604         } else if (strcmp(argv[1], "mgts") == 0) {
6605                 strcpy(obd_types[0], "mgc");
6606         } else if (strcmp(argv[1], "all") == 0 ||
6607                    strcmp(argv[1], "servers") == 0) {
6608                 num_types = 3;
6609                 strcpy(obd_types[0], "osc");
6610                 strcpy(obd_types[1], "mdc");
6611                 strcpy(obd_types[2], "mgc");
6612         } else {
6613                 fprintf(stderr, "%s check: unrecognized option '%s'\n",
6614                         progname, argv[1]);
6615                 return CMD_HELP;
6616         }
6617
6618         rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
6619         if (rc < 0 || mntdir[0] == '\0') {
6620                 fprintf(stderr,
6621                         "%s check: cannot find mounted Lustre filesystem: %s\n",
6622                         progname, (rc < 0) ? strerror(-rc) : strerror(ENODEV));
6623                 return rc;
6624         }
6625
6626         rc = llapi_target_check(num_types, obd_types, mntdir);
6627         if (rc)
6628                 fprintf(stderr, "%s check: cannot check target '%s': %s\n",
6629                         progname, argv[1], strerror(-rc));
6630
6631         return rc;
6632 }
6633
6634 #ifdef HAVE_SYS_QUOTA_H
6635 #define ADD_OVERFLOW(a, b) \
6636                      ((((a) + (b)) < (a)) ? \
6637                       ((a) = ULONG_MAX) : ((a) = (a) + (b)))
6638
6639 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
6640  * returns the value or ULONG_MAX on integer overflow or incorrect format
6641  * Notes:
6642  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
6643  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
6644  *        3. empty integer value is interpreted as 0
6645  */
6646 static unsigned long str2sec(const char *timestr)
6647 {
6648         const char spec[] = "smhdw";
6649         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
6650         unsigned long val = 0;
6651         char *tail;
6652
6653         if (strpbrk(timestr, spec) == NULL) {
6654                 /*
6655                  * no specifiers inside the time string,
6656                  * should treat it as an integer value
6657                  */
6658                 val = strtoul(timestr, &tail, 10);
6659                 return *tail ? ULONG_MAX : val;
6660         }
6661
6662         /* format string is XXwXXdXXhXXmXXs */
6663         while (*timestr) {
6664                 unsigned long v;
6665                 int ind;
6666                 char *ptr;
6667
6668                 v = strtoul(timestr, &tail, 10);
6669                 if (v == ULONG_MAX || *tail == '\0')
6670                         /*
6671                          * value too large (ULONG_MAX or more)
6672                          * or missing specifier
6673                          */
6674                         goto error;
6675
6676                 ptr = strchr(spec, *tail);
6677                 if (!ptr)
6678                         /* unknown specifier */
6679                         goto error;
6680
6681                 ind = ptr - spec;
6682
6683                 /* check if product will overflow the type */
6684                 if (!(v < ULONG_MAX / mult[ind]))
6685                         goto error;
6686
6687                 ADD_OVERFLOW(val, mult[ind] * v);
6688                 if (val == ULONG_MAX)
6689                         goto error;
6690
6691                 timestr = tail + 1;
6692         }
6693
6694         return val;
6695
6696 error:
6697         return ULONG_MAX;
6698 }
6699
6700 #define ARG2ULL(nr, str, def_units)                                     \
6701 do {                                                                    \
6702         unsigned long long limit, units = def_units;                    \
6703         int rc;                                                         \
6704                                                                         \
6705         rc = llapi_parse_size(str, &limit, &units, 1);                  \
6706         if (rc < 0) {                                                   \
6707                 fprintf(stderr, "%s: invalid limit '%s'\n",             \
6708                         progname, str);                                 \
6709                 return CMD_HELP;                                        \
6710         }                                                               \
6711         nr = limit;                                                     \
6712 } while (0)
6713
6714 static inline int has_times_option(int argc, char **argv)
6715 {
6716         int i;
6717
6718         for (i = 1; i < argc; i++)
6719                 if (!strcmp(argv[i], "-t"))
6720                         return 1;
6721
6722         return 0;
6723 }
6724
6725 static inline int lfs_verify_poolarg(char *pool)
6726 {
6727         if (strnlen(optarg, LOV_MAXPOOLNAME + 1) > LOV_MAXPOOLNAME) {
6728                 fprintf(stderr,
6729                         "Pool name '%.*s' is longer than %d\n",
6730                         LOV_MAXPOOLNAME, pool, LOV_MAXPOOLNAME);
6731                 return 1;
6732         }
6733         return 0;
6734 }
6735
6736 int lfs_setquota_times(int argc, char **argv, struct if_quotactl *qctl)
6737 {
6738         int c, rc;
6739         char *mnt, *obd_type = (char *)qctl->obd_type;
6740         struct obd_dqblk *dqb = &qctl->qc_dqblk;
6741         struct obd_dqinfo *dqi = &qctl->qc_dqinfo;
6742         struct option long_opts[] = {
6743         { .val = 'b',   .name = "block-grace",  .has_arg = required_argument },
6744         { .val = 'g',   .name = "group",        .has_arg = no_argument },
6745         { .val = 'i',   .name = "inode-grace",  .has_arg = required_argument },
6746         { .val = 'p',   .name = "projid",       .has_arg = no_argument },
6747         { .val = 't',   .name = "times",        .has_arg = no_argument },
6748         { .val = 'u',   .name = "user",         .has_arg = no_argument },
6749         { .val = LFS_POOL_OPT,
6750                         .name = "pool",         .has_arg = required_argument },
6751         { .name = NULL } };
6752         int qtype;
6753
6754         qctl->qc_cmd  = LUSTRE_Q_SETINFO;
6755         qctl->qc_type = ALLQUOTA;
6756
6757         while ((c = getopt_long(argc, argv, "b:gi:ptu",
6758                                 long_opts, NULL)) != -1) {
6759                 switch (c) {
6760                 case 'u':
6761                         qtype = USRQUOTA;
6762                         goto quota_type;
6763                 case 'g':
6764                         qtype = GRPQUOTA;
6765                         goto quota_type;
6766                 case 'p':
6767                         qtype = PRJQUOTA;
6768 quota_type:
6769                         if (qctl->qc_type != ALLQUOTA) {
6770                                 fprintf(stderr,
6771                                         "error: -u/g/p can't be used more than once\n");
6772                                 return CMD_HELP;
6773                         }
6774                         qctl->qc_type = qtype;
6775                         break;
6776                 case 'b':
6777                         if (strncmp(optarg, NOTIFY_GRACE,
6778                                     strlen(NOTIFY_GRACE)) == 0) {
6779                                 dqi->dqi_bgrace = NOTIFY_GRACE_TIME;
6780                         } else {
6781                                 dqi->dqi_bgrace = str2sec(optarg);
6782                                 if (dqi->dqi_bgrace >= NOTIFY_GRACE_TIME) {
6783                                         fprintf(stderr,
6784                                                 "error: bad block-grace: %s\n",
6785                                                 optarg);
6786                                         return CMD_HELP;
6787                                 }
6788                         }
6789                         dqb->dqb_valid |= QIF_BTIME;
6790                         break;
6791                 case 'i':
6792                         if (strncmp(optarg, NOTIFY_GRACE,
6793                                     strlen(NOTIFY_GRACE)) == 0) {
6794                                 dqi->dqi_igrace = NOTIFY_GRACE_TIME;
6795                         } else {
6796                                 dqi->dqi_igrace = str2sec(optarg);
6797                                 if (dqi->dqi_igrace >= NOTIFY_GRACE_TIME) {
6798                                         fprintf(stderr,
6799                                                 "error: bad inode-grace: %s\n",
6800                                                 optarg);
6801                                         return CMD_HELP;
6802                                 }
6803                         }
6804                         dqb->dqb_valid |= QIF_ITIME;
6805                         break;
6806                 case 't': /* Yes, of course! */
6807                         break;
6808                 case LFS_POOL_OPT:
6809                         if (lfs_verify_poolarg(optarg))
6810                                 return -1;
6811                         fprintf(stdout,
6812                                 "Trying to set grace for pool %s\n", optarg);
6813                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
6814                         qctl->qc_cmd  = LUSTRE_Q_SETINFOPOOL;
6815                         break;
6816                 /* getopt prints error message for us when opterr != 0 */
6817                 default:
6818                         return CMD_HELP;
6819                 }
6820         }
6821
6822         if (qctl->qc_type == ALLQUOTA) {
6823                 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
6824                 return CMD_HELP;
6825         }
6826
6827         if (optind != argc - 1) {
6828                 fprintf(stderr, "error: unexpected parameters encountered\n");
6829                 return CMD_HELP;
6830         }
6831
6832         mnt = argv[optind];
6833         rc = llapi_quotactl(mnt, qctl);
6834         if (rc) {
6835                 if (*obd_type)
6836                         fprintf(stderr, "%s %s ", obd_type,
6837                                 obd_uuid2str(&qctl->obd_uuid));
6838                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
6839                 return rc;
6840         }
6841
6842         return 0;
6843 }
6844
6845 #define BSLIMIT (1 << 0)
6846 #define BHLIMIT (1 << 1)
6847 #define ISLIMIT (1 << 2)
6848 #define IHLIMIT (1 << 3)
6849
6850 int lfs_setquota(int argc, char **argv)
6851 {
6852         int c, rc = 0;
6853         struct if_quotactl *qctl;
6854         char *mnt, *obd_type;
6855         struct obd_dqblk *dqb;
6856         struct option long_opts[] = {
6857         { .val = 'b',   .name = "block-softlimit",
6858                                                 .has_arg = required_argument },
6859         { .val = 'B',   .name = "block-hardlimit",
6860                                                 .has_arg = required_argument },
6861         { .val = 'd',   .name = "default",      .has_arg = no_argument },
6862         { .val = 'g',   .name = "group",        .has_arg = required_argument },
6863         { .val = 'G',   .name = "default-grp",  .has_arg = no_argument },
6864         { .val = 'i',   .name = "inode-softlimit",
6865                                                 .has_arg = required_argument },
6866         { .val = 'I',   .name = "inode-hardlimit",
6867                                                 .has_arg = required_argument },
6868         { .val = 'p',   .name = "projid",       .has_arg = required_argument },
6869         { .val = 'P',   .name = "default-prj",  .has_arg = no_argument },
6870         { .val = 'u',   .name = "user",         .has_arg = required_argument },
6871         { .val = 'U',   .name = "default-usr",  .has_arg = no_argument },
6872         { .val = LFS_POOL_OPT,
6873                         .name = "pool",         .has_arg = required_argument },
6874         { .name = NULL } };
6875         unsigned int limit_mask = 0;
6876         bool use_default = false;
6877         int qtype, qctl_len;
6878
6879         qctl_len = sizeof(*qctl) + LOV_MAXPOOLNAME + 1;
6880         qctl = malloc(qctl_len);
6881         if (!qctl)
6882                 return -ENOMEM;
6883
6884         memset(qctl, 0, qctl_len);
6885         obd_type = (char *)qctl->obd_type;
6886         dqb = &qctl->qc_dqblk;
6887
6888         if (has_times_option(argc, argv)) {
6889                 rc = lfs_setquota_times(argc, argv, qctl);
6890                 goto out;
6891         }
6892
6893         qctl->qc_cmd  = LUSTRE_Q_SETQUOTA;
6894         qctl->qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
6895                                    * so it can be used as a marker that qc_type
6896                                    * isn't reinitialized from command line
6897                                    */
6898
6899         while ((c = getopt_long(argc, argv, "b:B:dg:Gi:I:p:Pu:U",
6900                 long_opts, NULL)) != -1) {
6901                 switch (c) {
6902                 case 'U':
6903                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
6904                         qtype = USRQUOTA;
6905                         qctl->qc_id = 0;
6906                         goto quota_type_def;
6907                 case 'u':
6908                         qtype = USRQUOTA;
6909                         rc = name2uid(&qctl->qc_id, optarg);
6910                         goto quota_type;
6911                 case 'G':
6912                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
6913                         qtype = GRPQUOTA;
6914                         qctl->qc_id = 0;
6915                         goto quota_type_def;
6916                 case 'g':
6917                         qtype = GRPQUOTA;
6918                         rc = name2gid(&qctl->qc_id, optarg);
6919                         goto quota_type;
6920                 case 'P':
6921                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
6922                         qtype = PRJQUOTA;
6923                         qctl->qc_id = 0;
6924                         goto quota_type_def;
6925                 case 'p':
6926                         qtype = PRJQUOTA;
6927                         rc = name2projid(&qctl->qc_id, optarg);
6928 quota_type:
6929                         if (rc) {
6930                                 if (str2quotaid(&qctl->qc_id, optarg)) {
6931                                         fprintf(stderr,
6932                                                 "%s setquota: invalid id '%s'\n",
6933                                                 progname, optarg);
6934                                         rc = -1;
6935                                         goto out;
6936                                 }
6937                         }
6938
6939                         if (qctl->qc_id == 0) {
6940                                 fprintf(stderr,
6941                                         "%s setquota: can't set quota for root usr/group/project.\n",
6942                                         progname);
6943                                 rc = -1;
6944                                 goto out;
6945                         }
6946
6947 quota_type_def:
6948                         if (qctl->qc_type != ALLQUOTA) {
6949                                 fprintf(stderr,
6950                                         "%s setquota: only one of -u, -U, -g, -G, -p or -P may be specified\n",
6951                                         progname);
6952                                 rc = CMD_HELP;
6953                                 goto out;
6954                         }
6955                         qctl->qc_type = qtype;
6956                         break;
6957                 case 'd':
6958                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
6959                         use_default = true;
6960                         break;
6961                 case 'b':
6962                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
6963                         dqb->dqb_bsoftlimit >>= 10;
6964                         limit_mask |= BSLIMIT;
6965                         if (dqb->dqb_bsoftlimit &&
6966                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
6967                                 fprintf(stderr,
6968                                         "%s setquota: warning: block softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
6969                                         progname,
6970                                         (unsigned long long)dqb->dqb_bsoftlimit,
6971                                         progname);
6972                         break;
6973                 case 'B':
6974                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
6975                         dqb->dqb_bhardlimit >>= 10;
6976                         limit_mask |= BHLIMIT;
6977                         if (dqb->dqb_bhardlimit &&
6978                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
6979                                 fprintf(stderr,
6980                                         "%s setquota: warning: block hardlimit '%llu' smaller than minimum qunit size\n"
6981                                         "See '%s help setquota' or Lustre manual for details\n",
6982                                         progname,
6983                                         (unsigned long long)dqb->dqb_bhardlimit,
6984                                         progname);
6985                         break;
6986                 case 'i':
6987                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
6988                         limit_mask |= ISLIMIT;
6989                         if (dqb->dqb_isoftlimit &&
6990                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
6991                                 fprintf(stderr,
6992                                         "%s setquota: warning: inode softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
6993                                         progname,
6994                                         (unsigned long long)dqb->dqb_isoftlimit,
6995                                         progname);
6996                         break;
6997                 case 'I':
6998                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
6999                         limit_mask |= IHLIMIT;
7000                         if (dqb->dqb_ihardlimit &&
7001                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
7002                                 fprintf(stderr,
7003                                         "%s setquota: warning: inode hardlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
7004                                         progname,
7005                                         (unsigned long long)dqb->dqb_ihardlimit,
7006                                         progname);
7007                         break;
7008                 case LFS_POOL_OPT:
7009                         if (lfs_verify_poolarg(optarg)) {
7010                                 rc = -1;
7011                                 goto out;
7012                         }
7013                         fprintf(stdout,
7014                                 "Trying to set quota for pool %s\n", optarg);
7015                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
7016                         qctl->qc_cmd  = LUSTRE_Q_SETQUOTAPOOL;
7017                         break;
7018                 default:
7019                         fprintf(stderr,
7020                                 "%s setquota: unrecognized option '%s'\n",
7021                                 progname, argv[optind - 1]);
7022                         rc = CMD_HELP;
7023                         goto out;
7024                 }
7025         }
7026
7027         if (qctl->qc_type == ALLQUOTA) {
7028                 fprintf(stderr,
7029                         "%s setquota: either -u or -g must be specified\n",
7030                         progname);
7031                 rc = CMD_HELP;
7032                 goto out;
7033         }
7034
7035         if (!use_default && limit_mask == 0) {
7036                 fprintf(stderr,
7037                         "%s setquota: at least one limit must be specified\n",
7038                         progname);
7039                 rc = CMD_HELP;
7040                 goto out;
7041         }
7042
7043         if (use_default && limit_mask != 0) {
7044                 fprintf(stderr,
7045                         "%s setquota: limits should not be specified when using default quota\n",
7046                         progname);
7047                 rc = CMD_HELP;
7048                 goto out;
7049         }
7050
7051         if (use_default && qctl->qc_id == 0) {
7052                 fprintf(stderr,
7053                         "%s setquota: can not set default quota for root user/group/project\n",
7054                         progname);
7055                 rc = CMD_HELP;
7056                 goto out;
7057         }
7058
7059         if (optind != argc - 1) {
7060                 fprintf(stderr,
7061                         "%s setquota: filesystem not specified or unexpected argument '%s'\n",
7062                         progname, argv[optind]);
7063                 rc = CMD_HELP;
7064                 goto out;
7065         }
7066
7067         mnt = argv[optind];
7068
7069         if (use_default) {
7070                 dqb->dqb_bhardlimit = 0;
7071                 dqb->dqb_bsoftlimit = 0;
7072                 dqb->dqb_ihardlimit = 0;
7073                 dqb->dqb_isoftlimit = 0;
7074                 dqb->dqb_itime = 0;
7075                 dqb->dqb_btime = 0;
7076                 dqb->dqb_valid |= QIF_LIMITS | QIF_TIMES;
7077         } else if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
7078                    (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
7079                 /* sigh, we can't just set blimits/ilimits */
7080                 struct if_quotactl tmp_qctl = {.qc_cmd  = LUSTRE_Q_GETQUOTA,
7081                                                .qc_type = qctl->qc_type,
7082                                                .qc_id   = qctl->qc_id};
7083
7084                 rc = llapi_quotactl(mnt, &tmp_qctl);
7085                 if (rc < 0)
7086                         goto out;
7087
7088                 if (!(limit_mask & BHLIMIT))
7089                         dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
7090                 if (!(limit_mask & BSLIMIT))
7091                         dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
7092                 if (!(limit_mask & IHLIMIT))
7093                         dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
7094                 if (!(limit_mask & ISLIMIT))
7095                         dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
7096
7097                 /* Keep grace times if we have got no softlimit arguments */
7098                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
7099                         dqb->dqb_valid |= QIF_BTIME;
7100                         dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
7101                 }
7102
7103                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
7104                         dqb->dqb_valid |= QIF_ITIME;
7105                         dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
7106                 }
7107         }
7108
7109         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
7110         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
7111
7112         rc = llapi_quotactl(mnt, qctl);
7113         if (rc) {
7114                 if (*obd_type)
7115                         fprintf(stderr,
7116                                 "%s setquota: cannot quotactl '%s' '%s': %s",
7117                                 progname, obd_type,
7118                                 obd_uuid2str(&qctl->obd_uuid), strerror(-rc));
7119         }
7120 out:
7121         free(qctl);
7122         return rc;
7123 }
7124
7125 /* Converts seconds value into format string
7126  * result is returned in buf
7127  * Notes:
7128  *        1. result is in descenting order: 1w2d3h4m5s
7129  *        2. zero fields are not filled (except for p. 3): 5d1s
7130  *        3. zero seconds value is presented as "0s"
7131  */
7132 static char *__sec2str(time_t seconds, char *buf)
7133 {
7134         const char spec[] = "smhdw";
7135         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
7136         unsigned long c;
7137         char *tail = buf;
7138         int i;
7139
7140         for (i = ARRAY_SIZE(mult) - 1 ; i >= 0; i--) {
7141                 c = seconds / mult[i];
7142
7143                 if (c > 0 || (i == 0 && buf == tail))
7144                         tail += scnprintf(tail, 40-(tail-buf), "%lu%c", c,
7145                                           spec[i]);
7146
7147                 seconds %= mult[i];
7148         }
7149
7150         return tail;
7151 }
7152
7153 static void sec2str(time_t seconds, char *buf, int rc)
7154 {
7155         char *tail = buf;
7156
7157         if (rc)
7158                 *tail++ = '[';
7159
7160         tail = __sec2str(seconds, tail);
7161
7162         if (rc && tail - buf < 39) {
7163                 *tail++ = ']';
7164                 *tail++ = 0;
7165         }
7166 }
7167
7168 static void diff2str(time_t seconds, char *buf, time_t now)
7169 {
7170         buf[0] = 0;
7171         if (!seconds)
7172                 return;
7173         if (seconds <= now) {
7174                 strcpy(buf, "none");
7175                 return;
7176         }
7177         __sec2str(seconds - now, buf);
7178 }
7179
7180 static void print_quota_title(char *name, struct if_quotactl *qctl,
7181                               bool human_readable, bool show_default)
7182 {
7183         if (show_default) {
7184                 printf("Disk default %s quota:\n", qtype_name(qctl->qc_type));
7185                 printf("%15s %8s%8s%8s %8s%8s%8s\n",
7186                        "Filesystem", "bquota", "blimit", "bgrace",
7187                        "iquota", "ilimit", "igrace");
7188         } else {
7189                 printf("Disk quotas for %s %s (%cid %u):\n",
7190                        qtype_name(qctl->qc_type), name,
7191                        *qtype_name(qctl->qc_type), qctl->qc_id);
7192                 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
7193                        "Filesystem", human_readable ? "used" : "kbytes",
7194                        "quota", "limit", "grace",
7195                        "files", "quota", "limit", "grace");
7196         }
7197 }
7198
7199 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
7200 {
7201         if (!h) {
7202                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
7203         } else {
7204                 if (num >> 40)
7205                         snprintf(buf, buflen, "%5.4gP",
7206                                  (double)num / ((__u64)1 << 40));
7207                 else if (num >> 30)
7208                         snprintf(buf, buflen, "%5.4gT",
7209                                  (double)num / (1 << 30));
7210                 else if (num >> 20)
7211                         snprintf(buf, buflen, "%5.4gG",
7212                                  (double)num / (1 << 20));
7213                 else if (num >> 10)
7214                         snprintf(buf, buflen, "%5.4gM",
7215                                  (double)num / (1 << 10));
7216                 else
7217                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
7218         }
7219 }
7220
7221 #define STRBUF_LEN      32
7222 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
7223                         int rc, bool h, bool show_default)
7224 {
7225         time_t now;
7226
7227         time(&now);
7228
7229         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA ||
7230             qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
7231             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) {
7232                 int bover = 0, iover = 0;
7233                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
7234                 char numbuf[3][STRBUF_LEN];
7235                 char timebuf[40];
7236                 char strbuf[STRBUF_LEN];
7237
7238                 if (dqb->dqb_bhardlimit &&
7239                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
7240                         bover = 1;
7241                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
7242                         if (dqb->dqb_btime > now)
7243                                 bover = 2;
7244                         else
7245                                 bover = 3;
7246                 }
7247
7248                 if (dqb->dqb_ihardlimit &&
7249                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
7250                         iover = 1;
7251                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
7252                         if (dqb->dqb_itime > now)
7253                                 iover = 2;
7254                         else
7255                                 iover = 3;
7256                 }
7257
7258                 if (strlen(mnt) > 15)
7259                         printf("%s\n%15s", mnt, "");
7260                 else
7261                         printf("%15s", mnt);
7262
7263                 if (bover)
7264                         diff2str(dqb->dqb_btime, timebuf, now);
7265                 else if (show_default)
7266                         snprintf(timebuf, sizeof(timebuf), "%llu",
7267                                  (unsigned long long)dqb->dqb_btime);
7268
7269                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
7270                            strbuf, sizeof(strbuf), h);
7271                 if (rc == -EREMOTEIO)
7272                         sprintf(numbuf[0], "%s*", strbuf);
7273                 else
7274                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
7275                                 "%s" : "[%s]", strbuf);
7276
7277                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
7278                 if (type == QC_GENERAL)
7279                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
7280                                 "%s" : "[%s]", strbuf);
7281                 else
7282                         sprintf(numbuf[1], "%s", "-");
7283
7284                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
7285                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
7286                         "%s" : "[%s]", strbuf);
7287
7288                 if (show_default)
7289                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
7290                 else
7291                         printf(" %7s%c %6s %7s %7s",
7292                                numbuf[0], bover ? '*' : ' ', numbuf[1],
7293                                numbuf[2], bover > 1 ? timebuf : "-");
7294
7295                 if (iover)
7296                         diff2str(dqb->dqb_itime, timebuf, now);
7297                 else if (show_default)
7298                         snprintf(timebuf, sizeof(timebuf), "%llu",
7299                                  (unsigned long long)dqb->dqb_itime);
7300
7301                 snprintf(numbuf[0], sizeof(numbuf),
7302                          (dqb->dqb_valid & QIF_INODES) ? "%ju" : "[%ju]",
7303                          (uintmax_t)dqb->dqb_curinodes);
7304
7305                 if (type == QC_GENERAL)
7306                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
7307                                 "%ju" : "[%ju]",
7308                                 (uintmax_t)dqb->dqb_isoftlimit);
7309                 else
7310                         sprintf(numbuf[1], "%s", "-");
7311
7312                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
7313                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
7314
7315                 if (show_default)
7316                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
7317                 else if (type != QC_OSTIDX)
7318                         printf(" %7s%c %6s %7s %7s",
7319                                numbuf[0], iover ? '*' : ' ', numbuf[1],
7320                                numbuf[2], iover > 1 ? timebuf : "-");
7321                 else
7322                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
7323                 printf("\n");
7324         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO || LUSTRE_Q_GETINFOPOOL ||
7325                    qctl->qc_cmd == Q_GETOINFO) {
7326                 char bgtimebuf[40];
7327                 char igtimebuf[40];
7328
7329                 if (qctl->qc_dqinfo.dqi_bgrace == NOTIFY_GRACE_TIME)
7330                         strncpy(bgtimebuf, NOTIFY_GRACE, 40);
7331                 else
7332                         sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
7333                 if (qctl->qc_dqinfo.dqi_igrace == NOTIFY_GRACE_TIME)
7334                         strncpy(igtimebuf, NOTIFY_GRACE, 40);
7335                 else
7336                         sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
7337
7338                 printf("Block grace time: %s; Inode grace time: %s\n",
7339                        bgtimebuf, igtimebuf);
7340         }
7341 }
7342
7343 static int tgt_name2index(const char *tgtname, unsigned int *idx)
7344 {
7345         char *dash, *endp;
7346
7347         /* format is "lustre-OST0001" */
7348         dash = memchr(tgtname, '-', LUSTRE_MAXFSNAME + 1);
7349         if (!dash) {
7350                 fprintf(stderr, "wrong tgtname format '%s'\n", tgtname);
7351                 return -EINVAL;
7352         }
7353         dash += 4;
7354
7355         *idx = strtoul(dash, &endp, 16);
7356         if (*idx > 0xffff) {
7357                 fprintf(stderr, "wrong index %s\n", tgtname);
7358                 return -ERANGE;
7359         }
7360
7361         return 0;
7362 }
7363
7364 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
7365                            bool h, __u64 *total)
7366 {
7367         int rc = 0, rc1 = 0, count = 0, i = 0;
7368         char **list = NULL, *buffer = NULL;
7369         __u32 valid = qctl->qc_valid;
7370
7371         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL && is_mdt)
7372                 return 0;
7373
7374         /* Is it correct for the case OST0000, OST0002, OST0003 -
7375          * we will ask OST0001 that is absent and won't ask OST0003? */
7376         rc = llapi_get_obd_count(mnt, &count, is_mdt);
7377         if (rc) {
7378                 fprintf(stderr, "can not get %s count: %s\n",
7379                         is_mdt ? "mdt" : "ost", strerror(-rc));
7380                 return rc;
7381         }
7382
7383         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
7384                 char fname[PATH_MAX];
7385                 char fsname[LUSTRE_MAXFSNAME + 1];
7386                 int bufsize = sizeof(struct obd_uuid) * count;
7387
7388                 rc = llapi_search_fsname(mnt, fsname);
7389                 if (rc) {
7390                         fprintf(stderr, "cannot get fsname for mountpoint %s\n",
7391                                 mnt);
7392                         goto out;
7393                 }
7394                 buffer = malloc(bufsize + sizeof(*list) * count);
7395                 if (!buffer)
7396                         return -ENOMEM;
7397                 list = (char **)(buffer + bufsize);
7398                 snprintf(fname, PATH_MAX, "%s.%s", fsname, qctl->qc_poolname);
7399                 count = llapi_get_poolmembers(fname, list, count,
7400                                               buffer, bufsize);
7401                 if (count <= 0)
7402                         goto out;
7403         }
7404
7405         for (i = 0; i < count; i++) {
7406                 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
7407                         unsigned int index;
7408
7409                         if (tgt_name2index(list[i], &index))
7410                                 continue;
7411                         qctl->qc_idx = index;
7412                 } else {
7413                         qctl->qc_idx = i;
7414                 }
7415
7416                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
7417                 rc = llapi_quotactl(mnt, qctl);
7418                 if (rc) {
7419                         /* It is remote client case. */
7420                         if (rc == -EOPNOTSUPP) {
7421                                 rc = 0;
7422                                 goto out;
7423                         }
7424
7425                         if (!rc1)
7426                                 rc1 = rc;
7427                         fprintf(stderr, "quotactl %s%d failed.\n",
7428                                 is_mdt ? "mdt" : "ost", qctl->qc_idx);
7429                         continue;
7430                 }
7431
7432                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
7433                             qctl->qc_valid, 0, h, false);
7434                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
7435                                    qctl->qc_dqblk.dqb_bhardlimit;
7436         }
7437 out:
7438         if (buffer)
7439                 free(buffer);
7440         qctl->qc_valid = valid;
7441         return rc ? : rc1;
7442 }
7443
7444 static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
7445                            int verbose, int quiet, bool human_readable,
7446                            bool show_default)
7447 {
7448         int rc1 = 0, rc2 = 0, rc3 = 0;
7449         char *obd_type = (char *)qctl->obd_type;
7450         char *obd_uuid = (char *)qctl->obd_uuid.uuid;
7451         __u64 total_ialloc = 0, total_balloc = 0;
7452         bool use_default_for_blk = false;
7453         bool use_default_for_file = false;
7454         int inacc;
7455
7456         rc1 = llapi_quotactl(mnt, qctl);
7457         if (rc1 < 0) {
7458                 switch (rc1) {
7459                 case -ESRCH:
7460                         fprintf(stderr, "%s quotas are not enabled.\n",
7461                                 qtype_name(qctl->qc_type));
7462                         goto out;
7463                 case -EPERM:
7464                         fprintf(stderr, "Permission denied.\n");
7465                 case -ENODEV:
7466                 case -ENOENT:
7467                         /* We already got error message. */
7468                         goto out;
7469                 default:
7470                         fprintf(stderr, "Unexpected quotactl error: %s\n",
7471                                 strerror(-rc1));
7472                 }
7473         }
7474
7475         if (!show_default && qctl->qc_id == 0) {
7476                 qctl->qc_dqblk.dqb_bhardlimit = 0;
7477                 qctl->qc_dqblk.dqb_bsoftlimit = 0;
7478                 qctl->qc_dqblk.dqb_ihardlimit = 0;
7479                 qctl->qc_dqblk.dqb_isoftlimit = 0;
7480                 qctl->qc_dqblk.dqb_btime = 0;
7481                 qctl->qc_dqblk.dqb_itime = 0;
7482                 qctl->qc_dqblk.dqb_valid |= QIF_LIMITS | QIF_TIMES;
7483         }
7484
7485         if (qctl->qc_dqblk.dqb_valid & QIF_BTIME &&
7486             LQUOTA_FLAG(qctl->qc_dqblk.dqb_btime) & LQUOTA_FLAG_DEFAULT) {
7487                 use_default_for_blk = true;
7488                 qctl->qc_dqblk.dqb_btime &= LQUOTA_GRACE_MASK;
7489         }
7490
7491         if (qctl->qc_dqblk.dqb_valid & QIF_ITIME &&
7492             LQUOTA_FLAG(qctl->qc_dqblk.dqb_itime) & LQUOTA_FLAG_DEFAULT) {
7493                 use_default_for_file = true;
7494                 qctl->qc_dqblk.dqb_itime &= LQUOTA_GRACE_MASK;
7495         }
7496
7497         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
7498              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
7499              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) && !quiet)
7500                 print_quota_title(name, qctl, human_readable, show_default);
7501
7502         if (rc1 && *obd_type)
7503                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
7504
7505         if (qctl->qc_valid != QC_GENERAL)
7506                 mnt = "";
7507
7508         inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
7509                  qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
7510                 ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
7511                  (QIF_LIMITS|QIF_USAGE));
7512
7513         print_quota(mnt, qctl, QC_GENERAL, rc1, human_readable, show_default);
7514
7515         if (!show_default && verbose &&
7516             qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO &&
7517             qctl->qc_cmd != LUSTRE_Q_GETINFOPOOL) {
7518                 char strbuf[STRBUF_LEN];
7519
7520                 rc2 = print_obd_quota(mnt, qctl, 1, human_readable,
7521                                       &total_ialloc);
7522                 rc3 = print_obd_quota(mnt, qctl, 0, human_readable,
7523                                       &total_balloc);
7524                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
7525                            human_readable);
7526                 printf("Total allocated inode limit: %ju, total allocated block limit: %s\n",
7527                        (uintmax_t)total_ialloc, strbuf);
7528         }
7529
7530         if (use_default_for_blk)
7531                 printf("%cid %u is using default block quota setting\n",
7532                        *qtype_name(qctl->qc_type), qctl->qc_id);
7533
7534         if (use_default_for_file)
7535                 printf("%cid %u is using default file quota setting\n",
7536                        *qtype_name(qctl->qc_type), qctl->qc_id);
7537
7538         if (rc1 || rc2 || rc3 || inacc)
7539                 printf("Some errors happened when getting quota info. Some devices may be not working or deactivated. The data in \"[]\" is inaccurate.\n");
7540 out:
7541         if (rc1)
7542                 return rc1;
7543         if (rc2)
7544                 return rc2;
7545         if (rc3)
7546                 return rc3;
7547         if (inacc)
7548                 return -EIO;
7549
7550         return 0;
7551 }
7552
7553 static int lfs_project(int argc, char **argv)
7554 {
7555         int ret = 0, err = 0, c, i;
7556         struct project_handle_control phc = { 0 };
7557         enum lfs_project_ops_t op;
7558
7559         phc.newline = true;
7560         phc.assign_projid = false;
7561         /* default action */
7562         op = LFS_PROJECT_LIST;
7563
7564         while ((c = getopt(argc, argv, "p:cCsdkr0")) != -1) {
7565                 switch (c) {
7566                 case 'c':
7567                         if (op != LFS_PROJECT_LIST) {
7568                                 fprintf(stderr,
7569                                         "%s: cannot specify '-c' '-C' '-s' together\n",
7570                                         progname);
7571                                 return CMD_HELP;
7572                         }
7573
7574                         op = LFS_PROJECT_CHECK;
7575                         break;
7576                 case 'C':
7577                         if (op != LFS_PROJECT_LIST) {
7578                                 fprintf(stderr,
7579                                         "%s: cannot specify '-c' '-C' '-s' together\n",
7580                                         progname);
7581                                 return CMD_HELP;
7582                         }
7583
7584                         op = LFS_PROJECT_CLEAR;
7585                         break;
7586                 case 's':
7587                         if (op != LFS_PROJECT_LIST) {
7588                                 fprintf(stderr,
7589                                         "%s: cannot specify '-c' '-C' '-s' together\n",
7590                                         progname);
7591                                 return CMD_HELP;
7592                         }
7593
7594                         phc.set_inherit = true;
7595                         op = LFS_PROJECT_SET;
7596                         break;
7597                 case 'd':
7598                         phc.dironly = true;
7599                         break;
7600                 case 'k':
7601                         phc.keep_projid = true;
7602                         break;
7603                 case 'r':
7604                         phc.recursive = true;
7605                         break;
7606                 case 'p':
7607                         if (str2quotaid(&phc.projid, optarg)) {
7608                                 fprintf(stderr,
7609                                         "Invalid project ID: %s\n",
7610                                         optarg);
7611                                 return CMD_HELP;
7612                         }
7613
7614                         phc.assign_projid = true;
7615
7616                         break;
7617                 case '0':
7618                         phc.newline = false;
7619                         break;
7620                 default:
7621                         fprintf(stderr, "%s: invalid option '%c'\n",
7622                                 progname, optopt);
7623                         return CMD_HELP;
7624                 }
7625         }
7626
7627         if (phc.assign_projid && op == LFS_PROJECT_LIST) {
7628                 op = LFS_PROJECT_SET;
7629                 phc.set_projid = true;
7630         } else if (phc.assign_projid && op == LFS_PROJECT_SET) {
7631                 phc.set_projid = true;
7632         }
7633
7634         switch (op) {
7635         case LFS_PROJECT_CHECK:
7636                 if (phc.keep_projid) {
7637                         fprintf(stderr,
7638                                 "%s: '-k' is useless together with '-c'\n",
7639                                 progname);
7640                         return CMD_HELP;
7641                 }
7642                 break;
7643         case LFS_PROJECT_CLEAR:
7644                 if (!phc.newline) {
7645                         fprintf(stderr,
7646                                 "%s: '-0' is useless together with '-C'\n",
7647                                 progname);
7648                         return CMD_HELP;
7649                 }
7650                 if (phc.assign_projid) {
7651                         fprintf(stderr,
7652                                 "%s: '-p' is useless together with '-C'\n",
7653                                 progname);
7654                         return CMD_HELP;
7655                 }
7656                 break;
7657         case LFS_PROJECT_SET:
7658                 if (!phc.newline) {
7659                         fprintf(stderr,
7660                                 "%s: '-0' is useless together with '-s'\n",
7661                                 progname);
7662                         return CMD_HELP;
7663                 }
7664                 if (phc.keep_projid) {
7665                         fprintf(stderr,
7666                                 "%s: '-k' is useless together with '-s'\n",
7667                                 progname);
7668                         return CMD_HELP;
7669                 }
7670                 break;
7671         default:
7672                 if (!phc.newline) {
7673                         fprintf(stderr,
7674                                 "%s: '-0' is useless for list operations\n",
7675                                 progname);
7676                         return CMD_HELP;
7677                 }
7678                 break;
7679         }
7680
7681         argv += optind;
7682         argc -= optind;
7683         if (argc == 0) {
7684                 fprintf(stderr, "%s: missing file or directory target(s)\n",
7685                         progname);
7686                 return CMD_HELP;
7687         }
7688
7689         for (i = 0; i < argc; i++) {
7690                 switch (op) {
7691                 case LFS_PROJECT_CHECK:
7692                         err = lfs_project_check(argv[i], &phc);
7693                         break;
7694                 case LFS_PROJECT_LIST:
7695                         err = lfs_project_list(argv[i], &phc);
7696                         break;
7697                 case LFS_PROJECT_CLEAR:
7698                         err = lfs_project_clear(argv[i], &phc);
7699                         break;
7700                 case LFS_PROJECT_SET:
7701                         err = lfs_project_set(argv[i], &phc);
7702                         break;
7703                 default:
7704                         break;
7705                 }
7706                 if (err && !ret)
7707                         ret = err;
7708         }
7709
7710         return ret;
7711 }
7712
7713 static int lfs_quota(int argc, char **argv)
7714 {
7715         int c;
7716         char *mnt, *name = NULL;
7717         struct if_quotactl *qctl;
7718         char *obd_uuid;
7719         int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
7720         __u32 valid = QC_GENERAL, idx = 0;
7721         bool human_readable = false;
7722         bool show_default = false;
7723         int qtype;
7724         struct option long_opts[] = {
7725         { .val = LFS_POOL_OPT, .name = "pool", .has_arg = required_argument },
7726         { .name = NULL } };
7727
7728         qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1);
7729         if (!qctl)
7730                 return -ENOMEM;
7731
7732         qctl->qc_cmd = LUSTRE_Q_GETQUOTA;
7733         qctl->qc_type = ALLQUOTA;
7734         obd_uuid = (char *)qctl->obd_uuid.uuid;
7735
7736         while ((c = getopt_long(argc, argv, "gGi:I:o:pPqtuUvh",
7737                 long_opts, NULL)) != -1) {
7738                 switch (c) {
7739                 case 'U':
7740                         show_default = true;
7741                 case 'u':
7742                         qtype = USRQUOTA;
7743                         goto quota_type;
7744                 case 'G':
7745                         show_default = true;
7746                 case 'g':
7747                         qtype = GRPQUOTA;
7748                         goto quota_type;
7749                 case 'P':
7750                         show_default = true;
7751                 case 'p':
7752                         qtype = PRJQUOTA;
7753 quota_type:
7754                         if (qctl->qc_type != ALLQUOTA) {
7755                                 fprintf(stderr,
7756                                         "%s quota: only one of -u, -g, or -p may be specified\n",
7757                                         progname);
7758                                 rc = CMD_HELP;
7759                                 goto out;
7760                         }
7761                         qctl->qc_type = qtype;
7762                         break;
7763                 case 't':
7764                         qctl->qc_cmd = LUSTRE_Q_GETINFO;
7765                         break;
7766                 case 'o':
7767                         valid = qctl->qc_valid = QC_UUID;
7768                         snprintf(obd_uuid, sizeof(*obd_uuid), "%s", optarg);
7769                         break;
7770                 case 'i':
7771                         valid = qctl->qc_valid = QC_MDTIDX;
7772                         idx = qctl->qc_idx = atoi(optarg);
7773                         if (idx == 0 && *optarg != '0') {
7774                                 fprintf(stderr,
7775                                         "%s quota: invalid MDT index '%s'\n",
7776                                         progname, optarg);
7777                                 rc = CMD_HELP;
7778                                 goto out;
7779                         }
7780                         break;
7781                 case 'I':
7782                         valid = qctl->qc_valid = QC_OSTIDX;
7783                         idx = qctl->qc_idx = atoi(optarg);
7784                         if (idx == 0 && *optarg != '0') {
7785                                 fprintf(stderr,
7786                                         "%s quota: invalid OST index '%s'\n",
7787                                         progname, optarg);
7788                                 rc = CMD_HELP;
7789                                 goto out;
7790                         }
7791                         break;
7792                 case 'v':
7793                         verbose = 1;
7794                         break;
7795                 case 'q':
7796                         quiet = 1;
7797                         break;
7798                 case 'h':
7799                         human_readable = true;
7800                         break;
7801                 case LFS_POOL_OPT:
7802                         if (lfs_verify_poolarg(optarg)) {
7803                                 rc = -1;
7804                                 goto out;
7805                         }
7806                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
7807                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_GETINFO ?
7808                                                 LUSTRE_Q_GETINFOPOOL :
7809                                                 LUSTRE_Q_GETQUOTAPOOL;
7810                         break;
7811                 default:
7812                         fprintf(stderr, "%s quota: unrecognized option '%s'\n",
7813                                 progname, argv[optind - 1]);
7814                         rc = CMD_HELP;
7815                         goto out;
7816                 }
7817         }
7818
7819         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
7820         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
7821              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
7822              qctl->qc_type == ALLQUOTA &&
7823              optind == argc - 1 && !show_default) {
7824                 qctl->qc_idx = idx;
7825
7826                 for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) {
7827                         qctl->qc_type = qtype;
7828                         qctl->qc_valid = valid;
7829                         if (qtype == USRQUOTA) {
7830                                 qctl->qc_id = geteuid();
7831                                 rc = uid2name(&name, qctl->qc_id);
7832                         } else {
7833                                 qctl->qc_id = getegid();
7834                                 rc = gid2name(&name, qctl->qc_id);
7835                                 memset(&qctl->qc_dqblk, 0,
7836                                        sizeof(qctl->qc_dqblk));
7837                         }
7838                         if (rc)
7839                                 name = "<unknown>";
7840                         mnt = argv[optind];
7841                         rc1 = get_print_quota(mnt, name, qctl, verbose, quiet,
7842                                               human_readable, show_default);
7843                         if (rc1 && !rc)
7844                                 rc = rc1;
7845                 }
7846                 goto out;
7847         /* lfs quota -u username /path/to/lustre/mount */
7848         } else if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
7849                    qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
7850                 /* options should be followed by u/g-name and mntpoint */
7851                 if ((!show_default && optind + 2 != argc) ||
7852                     (show_default && optind + 1 != argc) ||
7853                     qctl->qc_type == ALLQUOTA) {
7854                         fprintf(stderr,
7855                                 "%s quota: name and mount point must be specified\n",
7856                                 progname);
7857                         rc = CMD_HELP;
7858                         goto out;
7859                 }
7860
7861                 if (!show_default) {
7862                         name = argv[optind++];
7863                         switch (qctl->qc_type) {
7864                         case USRQUOTA:
7865                                 rc = name2uid(&qctl->qc_id, name);
7866                                 break;
7867                         case GRPQUOTA:
7868                                 rc = name2gid(&qctl->qc_id, name);
7869                                 break;
7870                         case PRJQUOTA:
7871                                 rc = name2projid(&qctl->qc_id, name);
7872                                 break;
7873                         default:
7874                                 rc = -ENOTSUP;
7875                                 break;
7876                         }
7877                 } else {
7878                         qctl->qc_valid = QC_GENERAL;
7879                         qctl->qc_cmd = LUSTRE_Q_GETDEFAULT;
7880                         qctl->qc_id = 0;
7881                 }
7882
7883                 if (rc) {
7884                         if (str2quotaid(&qctl->qc_id, name)) {
7885                                 fprintf(stderr, "%s quota: invalid id '%s'\n",
7886                                         progname, name);
7887                                 rc = CMD_HELP;
7888                                 goto out;
7889                         }
7890                 }
7891         } else if (optind + 1 != argc || qctl->qc_type == ALLQUOTA) {
7892                 fprintf(stderr, "%s quota: missing quota info argument(s)\n",
7893                         progname);
7894                 rc = CMD_HELP;
7895                 goto out;
7896         }
7897
7898         mnt = argv[optind];
7899         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
7900                              human_readable, show_default);
7901 out:
7902         free(qctl);
7903         return rc;
7904 }
7905 #endif /* HAVE_SYS_QUOTA_H! */
7906
7907 static int flushctx_ioctl(char *mp)
7908 {
7909         int fd, rc;
7910
7911         fd = open(mp, O_RDONLY);
7912         if (fd == -1) {
7913                 fprintf(stderr, "flushctx: error open %s: %s\n",
7914                         mp, strerror(errno));
7915                 return -1;
7916         }
7917
7918         rc = ioctl(fd, LL_IOC_FLUSHCTX);
7919         if (rc == -1)
7920                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
7921                         mp, strerror(errno));
7922
7923         close(fd);
7924         return rc;
7925 }
7926
7927 static int lfs_flushctx(int argc, char **argv)
7928 {
7929         int     kdestroy = 0, c;
7930         char    mntdir[PATH_MAX] = {'\0'};
7931         int     index = 0;
7932         int     rc = 0;
7933
7934         while ((c = getopt(argc, argv, "k")) != -1) {
7935                 switch (c) {
7936                 case 'k':
7937                         kdestroy = 1;
7938                         break;
7939                 default:
7940                         fprintf(stderr,
7941                                 "error: %s: option '-%c' unrecognized\n",
7942                                 argv[0], c);
7943                         return CMD_HELP;
7944                 }
7945         }
7946
7947         if (kdestroy) {
7948                 rc = system("kdestroy > /dev/null");
7949                 if (rc) {
7950                         rc = WEXITSTATUS(rc);
7951                         fprintf(stderr,
7952                                 "error destroying tickets: %d, continuing\n",
7953                                 rc);
7954                 }
7955         }
7956
7957         if (optind >= argc) {
7958                 /* flush for all mounted lustre fs. */
7959                 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
7960                         /* Check if we have a mount point */
7961                         if (mntdir[0] == '\0')
7962                                 continue;
7963
7964                         if (flushctx_ioctl(mntdir))
7965                                 rc = -1;
7966
7967                         mntdir[0] = '\0'; /* avoid matching in next loop */
7968                 }
7969         } else {
7970                 /* flush fs as specified */
7971                 while (optind < argc) {
7972                         if (flushctx_ioctl(argv[optind++]))
7973                                 rc = -1;
7974                 }
7975         }
7976         return rc;
7977 }
7978
7979 static int lfs_changelog(int argc, char **argv)
7980 {
7981         void *changelog_priv;
7982         struct changelog_rec *rec;
7983         long long startrec = 0, endrec = 0;
7984         char *mdd;
7985         struct option long_opts[] = {
7986                 { .val = 'f', .name = "follow", .has_arg = no_argument },
7987                 { .name = NULL } };
7988         char short_opts[] = "f";
7989         int rc, follow = 0;
7990
7991         while ((rc = getopt_long(argc, argv, short_opts,
7992                 long_opts, NULL)) != -1) {
7993                 switch (rc) {
7994                 case 'f':
7995                         follow++;
7996                         break;
7997                 default:
7998                         fprintf(stderr,
7999                                 "%s changelog: unrecognized option '%s'\n",
8000                                 progname, argv[optind - 1]);
8001                         return CMD_HELP;
8002                 }
8003         }
8004         if (optind >= argc) {
8005                 fprintf(stderr, "%s changelog: mdtname must be specified\n",
8006                         progname);
8007                 return CMD_HELP;
8008         }
8009
8010         mdd = argv[optind++];
8011         if (argc > optind)
8012                 startrec = strtoll(argv[optind++], NULL, 10);
8013         if (argc > optind)
8014                 endrec = strtoll(argv[optind++], NULL, 10);
8015
8016         rc = llapi_changelog_start(&changelog_priv,
8017                                    CHANGELOG_FLAG_BLOCK |
8018                                    CHANGELOG_FLAG_JOBID |
8019                                    CHANGELOG_FLAG_EXTRA_FLAGS |
8020                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
8021                                    mdd, startrec);
8022         if (rc < 0) {
8023                 fprintf(stderr, "%s changelog: cannot start changelog: %s\n",
8024                         progname, strerror(errno = -rc));
8025                 return rc;
8026         }
8027
8028         rc = llapi_changelog_set_xflags(changelog_priv,
8029                                         CHANGELOG_EXTRA_FLAG_UIDGID |
8030                                         CHANGELOG_EXTRA_FLAG_NID |
8031                                         CHANGELOG_EXTRA_FLAG_OMODE |
8032                                         CHANGELOG_EXTRA_FLAG_XATTR);
8033         if (rc < 0) {
8034                 fprintf(stderr,
8035                         "%s changelog: cannot set xflags for changelog: %s\n",
8036                         progname, strerror(errno = -rc));
8037                 return rc;
8038         }
8039
8040         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
8041                 time_t secs;
8042                 struct tm ts;
8043
8044                 if (endrec && rec->cr_index > endrec) {
8045                         llapi_changelog_free(&rec);
8046                         break;
8047                 }
8048                 if (rec->cr_index < startrec) {
8049                         llapi_changelog_free(&rec);
8050                         continue;
8051                 }
8052
8053                 secs = rec->cr_time >> 30;
8054                 gmtime_r(&secs, &ts);
8055                 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
8056                        "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
8057                        changelog_type2str(rec->cr_type),
8058                        ts.tm_hour, ts.tm_min, ts.tm_sec,
8059                        (int)(rec->cr_time & ((1 << 30) - 1)),
8060                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
8061                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
8062
8063                 if (rec->cr_flags & CLF_JOBID) {
8064                         struct changelog_ext_jobid *jid =
8065                                 changelog_rec_jobid(rec);
8066
8067                         if (jid->cr_jobid[0] != '\0')
8068                                 printf(" j=%s", jid->cr_jobid);
8069                 }
8070
8071                 if (rec->cr_flags & CLF_EXTRA_FLAGS) {
8072                         struct changelog_ext_extra_flags *ef =
8073                                 changelog_rec_extra_flags(rec);
8074
8075                         printf(" ef=0x%llx",
8076                                (unsigned long long)ef->cr_extra_flags);
8077
8078                         if (ef->cr_extra_flags & CLFE_UIDGID) {
8079                                 struct changelog_ext_uidgid *uidgid =
8080                                         changelog_rec_uidgid(rec);
8081
8082                                 printf(" u=%llu:%llu",
8083                                        (unsigned long long)uidgid->cr_uid,
8084                                        (unsigned long long)uidgid->cr_gid);
8085                         }
8086                         if (ef->cr_extra_flags & CLFE_NID) {
8087                                 struct changelog_ext_nid *nid =
8088                                         changelog_rec_nid(rec);
8089
8090                                 printf(" nid=%s",
8091                                        libcfs_nid2str(nid->cr_nid));
8092                         }
8093
8094                         if (ef->cr_extra_flags & CLFE_OPEN) {
8095                                 struct changelog_ext_openmode *omd =
8096                                         changelog_rec_openmode(rec);
8097                                 char mode[] = "---";
8098
8099                                 /* exec mode must be exclusive */
8100                                 if (omd->cr_openflags & MDS_FMODE_EXEC) {
8101                                         mode[2] = 'x';
8102                                 } else {
8103                                         if (omd->cr_openflags & MDS_FMODE_READ)
8104                                                 mode[0] = 'r';
8105                                         if (omd->cr_openflags &
8106                                             (MDS_FMODE_WRITE |
8107                                              MDS_OPEN_TRUNC |
8108                                              MDS_OPEN_APPEND))
8109                                                 mode[1] = 'w';
8110                                 }
8111
8112                                 if (strcmp(mode, "---") != 0)
8113                                         printf(" m=%s", mode);
8114                         }
8115
8116                         if (ef->cr_extra_flags & CLFE_XATTR) {
8117                                 struct changelog_ext_xattr *xattr =
8118                                         changelog_rec_xattr(rec);
8119
8120                                 if (xattr->cr_xattr[0] != '\0')
8121                                         printf(" x=%s", xattr->cr_xattr);
8122                         }
8123                 }
8124
8125                 if (!fid_is_zero(&rec->cr_pfid))
8126                         printf(" p="DFID, PFID(&rec->cr_pfid));
8127                 if (rec->cr_namelen)
8128                         printf(" %.*s", rec->cr_namelen,
8129                                changelog_rec_name(rec));
8130
8131                 if (rec->cr_flags & CLF_RENAME) {
8132                         struct changelog_ext_rename *rnm =
8133                                 changelog_rec_rename(rec);
8134
8135                         if (!fid_is_zero(&rnm->cr_sfid))
8136                                 printf(" s="DFID" sp="DFID" %.*s",
8137                                        PFID(&rnm->cr_sfid),
8138                                        PFID(&rnm->cr_spfid),
8139                                        (int)changelog_rec_snamelen(rec),
8140                                        changelog_rec_sname(rec));
8141                 }
8142                 printf("\n");
8143
8144                 llapi_changelog_free(&rec);
8145         }
8146
8147         llapi_changelog_fini(&changelog_priv);
8148
8149         if (rc < 0)
8150                 fprintf(stderr, "%s changelog: cannot access changelog: %s\n",
8151                         progname, strerror(errno = -rc));
8152
8153         return (rc == 1 ? 0 : rc);
8154 }
8155
8156 static int lfs_changelog_clear(int argc, char **argv)
8157 {
8158         long long endrec;
8159         int rc;
8160
8161         if (argc != 4)
8162                 return CMD_HELP;
8163
8164         endrec = strtoll(argv[3], NULL, 10);
8165
8166         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
8167
8168         if (rc == -EINVAL)
8169                 fprintf(stderr, "%s: record out of range: %llu\n",
8170                         argv[0], endrec);
8171         else if (rc == -ENOENT)
8172                 fprintf(stderr, "%s: no changelog user: %s\n",
8173                         argv[0], argv[2]);
8174         else if (rc)
8175                 fprintf(stderr, "%s error: %s\n", argv[0],
8176                         strerror(-rc));
8177
8178         if (rc)
8179                 errno = -rc;
8180
8181         return rc;
8182 }
8183
8184 static int lfs_fid2path(int argc, char **argv)
8185 {
8186         struct option long_opts[] = {
8187                 { .val = 'c',   .name = "cur",  .has_arg = no_argument },
8188                 { .val = 'l',   .name = "link", .has_arg = required_argument },
8189                 { .val = 'r',   .name = "rec",  .has_arg = required_argument },
8190                 { .name = NULL } };
8191         char short_opts[] = "cl:r:";
8192         char mntdir[PATH_MAX];
8193         char *device, *fid, *path, *rootpath;
8194         long long recno = -1;
8195         int linkno = -1;
8196         int lnktmp;
8197         int printcur = 0;
8198         int rc = 0;
8199         char *endptr = NULL;
8200
8201         while ((rc = getopt_long(argc, argv, short_opts,
8202                 long_opts, NULL)) != -1) {
8203                 switch (rc) {
8204                 case 'c':
8205                         printcur++;
8206                         break;
8207                 case 'l':
8208                         linkno = strtol(optarg, &endptr, 10);
8209                         if (*endptr != '\0') {
8210                                 fprintf(stderr,
8211                                         "%s fid2path: invalid linkno '%s'\n",
8212                                         progname, optarg);
8213                                 return CMD_HELP;
8214                         }
8215                         break;
8216                 case 'r':
8217                         recno = strtoll(optarg, &endptr, 10);
8218                         if (*endptr != '\0') {
8219                                 fprintf(stderr,
8220                                         "%s fid2path: invalid recno '%s'\n",
8221                                         progname, optarg);
8222                                 return CMD_HELP;
8223                         }
8224                         break;
8225                 default:
8226                         fprintf(stderr,
8227                                 "%s fid2path: unrecognized option '%s'\n",
8228                                 progname, argv[optind - 1]);
8229                         return CMD_HELP;
8230                 }
8231         }
8232
8233         if (argc < 3) {
8234                 fprintf(stderr,
8235                         "%s fid2path: <fsname|rootpath> and <fid>... must be specified\n",
8236                         progname);
8237                 return CMD_HELP;
8238         }
8239
8240         device = argv[optind++];
8241         path = calloc(1, PATH_MAX);
8242         if (!path) {
8243                 rc = -errno;
8244                 fprintf(stderr,
8245                         "%s fid2path: cannot allocate memory for path: %s\n",
8246                         progname, strerror(-rc));
8247                 return rc;
8248         }
8249
8250         rc = 0;
8251         /* in case that device is not the mountpoint */
8252         if (device[0] == '/') {
8253                 rc = llapi_search_mounts(device, 0, mntdir, NULL);
8254                 if (rc == 0) {
8255                         rootpath = mntdir;
8256                 } else {
8257                         fprintf(stderr,
8258                                 "%s fid2path: %s has no mountpoint: %s\n",
8259                                 progname, device, strerror(-rc));
8260                         goto out;
8261                 }
8262         }
8263         while (optind < argc) {
8264                 fid = argv[optind++];
8265
8266                 lnktmp = (linkno >= 0) ? linkno : 0;
8267                 while (1) {
8268                         int oldtmp = lnktmp;
8269                         long long rectmp = recno;
8270                         int rc2;
8271
8272                         rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
8273                                              &rectmp, &lnktmp);
8274                         if (rc2 < 0) {
8275                                 fprintf(stderr,
8276                                         "%s fid2path: cannot find %s %s: %s\n",
8277                                         progname, device, fid,
8278                                         strerror(errno = -rc2));
8279                                 if (rc == 0)
8280                                         rc = rc2;
8281                                 break;
8282                         }
8283
8284                         if (printcur)
8285                                 fprintf(stdout, "%lld ", rectmp);
8286                         if (device[0] == '/') {
8287                                 fprintf(stdout, "%s", rootpath);
8288                                 if (rootpath[strlen(rootpath) - 1] != '/')
8289                                         fprintf(stdout, "/");
8290                         } else if (path[0] == '\0') {
8291                                 fprintf(stdout, "/");
8292                         }
8293                         fprintf(stdout, "%s\n", path);
8294
8295                         if (linkno >= 0)
8296                                 /* specified linkno */
8297                                 break;
8298                         if (oldtmp == lnktmp)
8299                                 /* no more links */
8300                                 break;
8301                 }
8302         }
8303 out:
8304         free(path);
8305         return rc;
8306 }
8307
8308 static int lfs_path2fid(int argc, char **argv)
8309 {
8310         struct option long_opts[] = {
8311                 { .val = 'p', .name = "parents", .has_arg = no_argument },
8312                 { .name = NULL } };
8313         char            **path;
8314         const char        short_opts[] = "p";
8315         const char       *sep = "";
8316         struct lu_fid     fid;
8317         int               rc = 0;
8318         bool              show_parents = false;
8319
8320         while ((rc = getopt_long(argc, argv, short_opts,
8321                                  long_opts, NULL)) != -1) {
8322                 switch (rc) {
8323                 case 'p':
8324                         show_parents = true;
8325                         break;
8326                 default:
8327                         fprintf(stderr,
8328                                 "%s path2fid: unrecognized option '%s'\n",
8329                                 progname, argv[optind - 1]);
8330                         return CMD_HELP;
8331                 }
8332         }
8333
8334         if (optind > argc - 1) {
8335                 fprintf(stderr, "%s path2fid: FILE... must be specified\n",
8336                         progname);
8337                 return CMD_HELP;
8338         } else if (optind < argc - 1) {
8339                 sep = ": ";
8340         }
8341
8342         rc = 0;
8343         for (path = argv + optind; *path != NULL; path++) {
8344                 int err = 0;
8345
8346                 if (!show_parents) {
8347                         err = llapi_path2fid(*path, &fid);
8348                         if (!err)
8349                                 printf("%s%s"DFID"\n",
8350                                        *sep != '\0' ? *path : "", sep,
8351                                        PFID(&fid));
8352                 } else {
8353                         char            name[NAME_MAX + 1];
8354                         unsigned int    linkno = 0;
8355
8356                         while ((err = llapi_path2parent(*path, linkno, &fid,
8357                                                 name, sizeof(name))) == 0) {
8358                                 if (*sep != '\0' && linkno == 0)
8359                                         printf("%s%s", *path, sep);
8360
8361                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
8362                                        PFID(&fid), name);
8363                                 linkno++;
8364                         }
8365
8366                         /* err == -ENODATA is end-of-loop */
8367                         if (linkno > 0 && err == -ENODATA) {
8368                                 printf("\n");
8369                                 err = 0;
8370                         }
8371                 }
8372
8373                 if (err) {
8374                         fprintf(stderr,
8375                                 "%s path2fid: cannot get %sfid for '%s': %s\n",
8376                                 progname, show_parents ? "parent " : "", *path,
8377                                 strerror(-err));
8378                         if (rc == 0) {
8379                                 rc = err;
8380                                 errno = -err;
8381                         }
8382                 }
8383         }
8384
8385         return rc;
8386 }
8387
8388 #define MAX_ERRNO       4095
8389 #define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO)
8390
8391 static int lfs_rmfid_and_show_errors(const char *device, struct fid_array *fa)
8392 {
8393         int rc, rc2 = 0, k;
8394
8395         rc = llapi_rmfid(device, fa);
8396         if (rc) {
8397                 fprintf(stderr, "rmfid(): rc = %d\n", rc);
8398                 return rc;
8399         }
8400
8401         for (k = 0; k < fa->fa_nr; k++) {
8402                 rc = (__s32)fa->fa_fids[k].f_ver;
8403                 if (!IS_ERR_VALUE(rc))
8404                         continue;
8405                 if (!rc2 && rc)
8406                         rc2 = rc;
8407                 if (!rc)
8408                         continue;
8409                 fa->fa_fids[k].f_ver = 0;
8410                 fprintf(stderr, "rmfid("DFID"): rc = %d\n",
8411                         PFID(&fa->fa_fids[k]), rc);
8412         }
8413
8414         return rc2;
8415 }
8416
8417 static int lfs_rmfid(int argc, char **argv)
8418 {
8419         char *fidstr, *device;
8420         int rc = 0, rc2, nr;
8421         struct fid_array *fa;
8422
8423         if (optind > argc - 1) {
8424                 fprintf(stderr, "%s rmfid: missing dirname\n", progname);
8425                 return CMD_HELP;
8426         }
8427
8428         device = argv[optind++];
8429
8430         nr = argc - optind;
8431         fa = malloc(offsetof(struct fid_array, fa_fids[nr + 1]));
8432         if (!fa)
8433                 return -ENOMEM;
8434
8435         fa->fa_nr = 0;
8436         rc = 0;
8437         while (optind < argc) {
8438                 int found;
8439
8440                 fidstr = argv[optind++];
8441                 while (*fidstr == '[')
8442                         fidstr++;
8443                 found = sscanf(fidstr, SFID, RFID(&fa->fa_fids[fa->fa_nr]));
8444                 if (found != 3) {
8445                         fprintf(stderr, "unrecognized FID: %s\n",
8446                                 argv[optind - 1]);
8447                         exit(1);
8448                 }
8449                 fa->fa_nr++;
8450                 if (fa->fa_nr == OBD_MAX_FIDS_IN_ARRAY) {
8451                         /* start another batch */
8452                         rc2 = lfs_rmfid_and_show_errors(device, fa);
8453                         if (rc2 && !rc)
8454                                 rc = rc2;
8455                         fa->fa_nr = 0;
8456                 }
8457         }
8458         if (fa->fa_nr) {
8459                 rc2 = lfs_rmfid_and_show_errors(device, fa);
8460                 if (rc2 && !rc)
8461                         rc = rc2;
8462         }
8463
8464         return rc;
8465 }
8466
8467 static int lfs_data_version(int argc, char **argv)
8468 {
8469         char *path;
8470         __u64 data_version;
8471         int fd;
8472         int rc;
8473         int c;
8474         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
8475
8476         if (argc < 2) {
8477                 fprintf(stderr, "%s data_version: FILE must be specified\n",
8478                         progname);
8479                 return CMD_HELP;
8480         }
8481
8482         while ((c = getopt(argc, argv, "nrw")) != -1) {
8483                 switch (c) {
8484                 case 'n':
8485                         data_version_flags = 0;
8486                         break;
8487                 case 'r':
8488                         data_version_flags |= LL_DV_RD_FLUSH;
8489                         break;
8490                 case 'w':
8491                         data_version_flags |= LL_DV_WR_FLUSH;
8492                         break;
8493                 default:
8494                         fprintf(stderr,
8495                                 "%s data_version: unrecognized option '%s'\n",
8496                                 progname, argv[optind - 1]);
8497                         return CMD_HELP;
8498                 }
8499         }
8500         if (optind == argc) {
8501                 fprintf(stderr, "%s data_version: FILE must be specified\n",
8502                         progname);
8503                 return CMD_HELP;
8504         }
8505
8506         path = argv[optind];
8507         fd = open(path, O_RDONLY);
8508         if (fd < 0) {
8509                 rc = -errno;
8510                 fprintf(stderr, "%s data_version: cannot open file '%s': %s\n",
8511                         progname, path, strerror(-rc));
8512                 return rc;
8513         }
8514
8515         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
8516         if (rc < 0)
8517                 fprintf(stderr,
8518                         "%s data_version: cannot get version for '%s': %s\n",
8519                         progname, path, strerror(-rc));
8520         else
8521                 printf("%ju" "\n", (uintmax_t)data_version);
8522
8523         close(fd);
8524         return rc;
8525 }
8526
8527 static int lfs_hsm_state(int argc, char **argv)
8528 {
8529         int rc;
8530         int i = 1;
8531         char *path;
8532         struct hsm_user_state hus;
8533
8534         if (argc < 2)
8535                 return CMD_HELP;
8536
8537         do {
8538                 path = argv[i];
8539
8540                 rc = llapi_hsm_state_get(path, &hus);
8541                 if (rc) {
8542                         fprintf(stderr, "can't get hsm state for %s: %s\n",
8543                                 path, strerror(errno = -rc));
8544                         return rc;
8545                 }
8546
8547                 /* Display path name and status flags */
8548                 printf("%s: (0x%08x)", path, hus.hus_states);
8549
8550                 if (hus.hus_states & HS_RELEASED)
8551                         printf(" released");
8552                 if (hus.hus_states & HS_EXISTS)
8553                         printf(" exists");
8554                 if (hus.hus_states & HS_DIRTY)
8555                         printf(" dirty");
8556                 if (hus.hus_states & HS_ARCHIVED)
8557                         printf(" archived");
8558                 /* Display user-settable flags */
8559                 if (hus.hus_states & HS_NORELEASE)
8560                         printf(" never_release");
8561                 if (hus.hus_states & HS_NOARCHIVE)
8562                         printf(" never_archive");
8563                 if (hus.hus_states & HS_LOST)
8564                         printf(" lost_from_hsm");
8565
8566                 if (hus.hus_archive_id != 0)
8567                         printf(", archive_id:%d", hus.hus_archive_id);
8568                 printf("\n");
8569
8570         } while (++i < argc);
8571
8572         return 0;
8573 }
8574
8575 #define LFS_HSM_SET   0
8576 #define LFS_HSM_CLEAR 1
8577
8578 /**
8579  * Generic function to set or clear HSM flags.
8580  * Used by hsm_set and hsm_clear.
8581  *
8582  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
8583  */
8584 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
8585 {
8586         struct option long_opts[] = {
8587         { .val = 'A',   .name = "archived",     .has_arg = no_argument },
8588         { .val = 'a',   .name = "noarchive",    .has_arg = no_argument },
8589         { .val = 'd',   .name = "dirty",        .has_arg = no_argument },
8590         { .val = 'e',   .name = "exists",       .has_arg = no_argument },
8591         { .val = 'l',   .name = "lost",         .has_arg = no_argument },
8592         { .val = 'r',   .name = "norelease",    .has_arg = no_argument },
8593         { .val = 'i',   .name = "archive-id",   .has_arg = required_argument },
8594         { .name = NULL } };
8595         char short_opts[] = "lraAdei:";
8596         __u64 mask = 0;
8597         int c, rc;
8598         char *path;
8599         __u32 archive_id = 0;
8600         char *end = NULL;
8601
8602         if (argc < 3)
8603                 return CMD_HELP;
8604
8605         while ((c = getopt_long(argc, argv, short_opts,
8606                                 long_opts, NULL)) != -1) {
8607                 switch (c) {
8608                 case 'l':
8609                         mask |= HS_LOST;
8610                         break;
8611                 case 'a':
8612                         mask |= HS_NOARCHIVE;
8613                         break;
8614                 case 'A':
8615                         mask |= HS_ARCHIVED;
8616                         break;
8617                 case 'r':
8618                         mask |= HS_NORELEASE;
8619                         break;
8620                 case 'd':
8621                         mask |= HS_DIRTY;
8622                         break;
8623                 case 'e':
8624                         mask |= HS_EXISTS;
8625                         break;
8626                 case 'i':
8627                         archive_id = strtol(optarg, &end, 10);
8628                         if (*end != '\0') {
8629                                 fprintf(stderr, "invalid archive_id: '%s'\n",
8630                                         end);
8631                                 return CMD_HELP;
8632                         }
8633                         break;
8634                 case '?':
8635                         return CMD_HELP;
8636                 default:
8637                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
8638                                 argv[0], argv[optind - 1]);
8639                         return CMD_HELP;
8640                 }
8641         }
8642
8643         /* User should have specified a flag */
8644         if (mask == 0)
8645                 return CMD_HELP;
8646
8647         while (optind < argc) {
8648                 path = argv[optind];
8649
8650                 /* If mode == 0, this means we apply the mask. */
8651                 if (mode == LFS_HSM_SET)
8652                         rc = llapi_hsm_state_set(path, mask, 0, archive_id);
8653                 else
8654                         rc = llapi_hsm_state_set(path, 0, mask, 0);
8655
8656                 if (rc != 0) {
8657                         fprintf(stderr, "Can't change hsm flags for %s: %s\n",
8658                                 path, strerror(errno = -rc));
8659                         return rc;
8660                 }
8661                 optind++;
8662         }
8663
8664         return 0;
8665 }
8666
8667 static int lfs_hsm_action(int argc, char **argv)
8668 {
8669         int                              rc;
8670         int                              i = 1;
8671         char                            *path;
8672         struct hsm_current_action        hca;
8673         struct hsm_extent                he;
8674         enum hsm_user_action             hua;
8675         enum hsm_progress_states         hps;
8676
8677         if (argc < 2)
8678                 return CMD_HELP;
8679
8680         do {
8681                 path = argv[i];
8682
8683                 rc = llapi_hsm_current_action(path, &hca);
8684                 if (rc) {
8685                         fprintf(stderr, "can't get hsm action for %s: %s\n",
8686                                 path, strerror(errno = -rc));
8687                         return rc;
8688                 }
8689                 he = hca.hca_location;
8690                 hua = hca.hca_action;
8691                 hps = hca.hca_state;
8692
8693                 printf("%s: %s", path, hsm_user_action2name(hua));
8694
8695                 /* Skip file without action */
8696                 if (hca.hca_action == HUA_NONE) {
8697                         printf("\n");
8698                         continue;
8699                 }
8700
8701                 printf(" %s ", hsm_progress_state2name(hps));
8702
8703                 if ((hps == HPS_RUNNING) &&
8704                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
8705                         printf("(%llu bytes moved)\n",
8706                                (unsigned long long)he.length);
8707                 else if ((he.offset + he.length) == LUSTRE_EOF)
8708                         printf("(from %llu to EOF)\n",
8709                                (unsigned long long)he.offset);
8710                 else
8711                         printf("(from %llu to %llu)\n",
8712                                (unsigned long long)he.offset,
8713                                (unsigned long long)(he.offset + he.length));
8714
8715         } while (++i < argc);
8716
8717         return 0;
8718 }
8719
8720 static int lfs_hsm_set(int argc, char **argv)
8721 {
8722         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
8723 }
8724
8725 static int lfs_hsm_clear(int argc, char **argv)
8726 {
8727         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
8728 }
8729
8730 /**
8731  * Check file state and return its fid, to be used by lfs_hsm_request().
8732  *
8733  * \param[in]     file      Path to file to check
8734  * \param[in,out] fid       Pointer to allocated lu_fid struct.
8735  * \param[in,out] last_dev  Pointer to last device id used.
8736  *
8737  * \return 0 on success.
8738  */
8739 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
8740                                 dev_t *last_dev)
8741 {
8742         struct stat     st;
8743         int             rc;
8744
8745         rc = lstat(file, &st);
8746         if (rc) {
8747                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
8748                 return -errno;
8749         }
8750         /*
8751          * Checking for regular file as archiving as posix copytool
8752          * rejects archiving files other than regular files
8753          */
8754         if (!S_ISREG(st.st_mode)) {
8755                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
8756                 return CMD_HELP;
8757         }
8758         /* A request should be ... */
8759         if (*last_dev != st.st_dev && *last_dev != 0) {
8760                 fprintf(stderr,
8761                         "All files should be on the same filesystem: %s\n",
8762                         file);
8763                 return -EINVAL;
8764         }
8765         *last_dev = st.st_dev;
8766
8767         rc = llapi_path2fid(file, fid);
8768         if (rc) {
8769                 fprintf(stderr, "Cannot read FID of %s: %s\n",
8770                         file, strerror(-rc));
8771                 return rc;
8772         }
8773         return 0;
8774 }
8775
8776 /* Fill an HSM HUR item with a given file name.
8777  *
8778  * If mntpath is set, then the filename is actually a FID, and no
8779  * lookup on the filesystem will be performed.
8780  *
8781  * \param[in]  hur         the user request to fill
8782  * \param[in]  idx         index of the item inside the HUR to fill
8783  * \param[in]  mntpath     mountpoint of Lustre
8784  * \param[in]  fname       filename (if mtnpath is NULL)
8785  *                         or FID (if mntpath is set)
8786  * \param[in]  last_dev    pointer to last device id used
8787  *
8788  * \retval 0 on success
8789  * \retval CMD_HELP or a negative errno on error
8790  */
8791 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
8792                          const char *mntpath, const char *fname,
8793                          dev_t *last_dev)
8794 {
8795         struct hsm_user_item *hui = &hur->hur_user_item[idx];
8796         int rc;
8797
8798         hui->hui_extent.length = -1;
8799
8800         if (mntpath) {
8801                 rc = llapi_fid_parse(fname, &hui->hui_fid, NULL);
8802                 if (rc)
8803                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
8804                                 fname);
8805         } else {
8806                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
8807         }
8808
8809         if (rc == 0)
8810                 hur->hur_request.hr_itemcount++;
8811
8812         return rc;
8813 }
8814
8815 static int lfs_hsm_request(int argc, char **argv, int action)
8816 {
8817         struct option long_opts[] = {
8818         { .val = 'a',   .name = "archive",      .has_arg = required_argument },
8819         { .val = 'D',   .name = "data",         .has_arg = required_argument },
8820         { .val = 'l',   .name = "filelist",     .has_arg = required_argument },
8821         { .val = 'm',   .name = "mntpath",      .has_arg = required_argument },
8822         { .name = NULL } };
8823         dev_t last_dev = 0;
8824         char short_opts[] = "l:D:a:m:";
8825         struct hsm_user_request *hur, *oldhur;
8826         int c, i;
8827         size_t len;
8828         int nbfile;
8829         char *line = NULL;
8830         char *filelist = NULL;
8831         char fullpath[PATH_MAX];
8832         char *opaque = NULL;
8833         int opaque_len = 0;
8834         int archive_id = 0;
8835         FILE *fp;
8836         int nbfile_alloc = 0;
8837         char *some_file = NULL;
8838         char *mntpath = NULL;
8839         int rc;
8840
8841         if (argc < 2)
8842                 return CMD_HELP;
8843
8844         while ((c = getopt_long(argc, argv, short_opts,
8845                                 long_opts, NULL)) != -1) {
8846                 switch (c) {
8847                 case 'l':
8848                         filelist = optarg;
8849                         break;
8850                 case 'D':
8851                         opaque = optarg;
8852                         break;
8853                 case 'a':
8854                         if (action != HUA_ARCHIVE &&
8855                             action != HUA_REMOVE) {
8856                                 fprintf(stderr,
8857                                         "error: -a is supported only when archiving or removing\n");
8858                                 return CMD_HELP;
8859                         }
8860                         archive_id = atoi(optarg);
8861                         break;
8862                 case 'm':
8863                         if (!some_file) {
8864                                 mntpath = optarg;
8865                                 some_file = strdup(optarg);
8866                         }
8867                         break;
8868                 case '?':
8869                         return CMD_HELP;
8870                 default:
8871                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
8872                                 argv[0], argv[optind - 1]);
8873                         return CMD_HELP;
8874                 }
8875         }
8876
8877         /* All remaining args are files, so we have at least nbfile */
8878         nbfile = argc - optind;
8879
8880         if ((nbfile == 0) && (!filelist))
8881                 return CMD_HELP;
8882
8883         if (opaque)
8884                 opaque_len = strlen(opaque);
8885
8886         /*
8887          * Alloc the request structure with enough place to store all files
8888          * from command line.
8889          */
8890         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
8891         if (!hur) {
8892                 fprintf(stderr, "Cannot create the request: %s\n",
8893                         strerror(errno));
8894                 return errno;
8895         }
8896         nbfile_alloc = nbfile;
8897
8898         hur->hur_request.hr_action = action;
8899         hur->hur_request.hr_archive_id = archive_id;
8900         hur->hur_request.hr_flags = 0;
8901
8902         /* All remaining args are files, add them */
8903         if (nbfile != 0 && some_file == NULL)
8904                 some_file = strdup(argv[optind]);
8905
8906         for (i = 0; i < nbfile; i++) {
8907                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
8908                                    &last_dev);
8909                 if (rc)
8910                         goto out_free;
8911         }
8912
8913         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
8914
8915         /* If a filelist was specified, read the filelist from it. */
8916         if (filelist) {
8917                 fp = fopen(filelist, "r");
8918                 if (!fp) {
8919                         fprintf(stderr, "Cannot read the file list %s: %s\n",
8920                                 filelist, strerror(errno));
8921                         rc = -errno;
8922                         goto out_free;
8923                 }
8924
8925                 while ((rc = getline(&line, &len, fp)) != -1) {
8926                         /*
8927                          * If allocated buffer was too small, get something
8928                          * larger
8929                          */
8930                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
8931                                 ssize_t size;
8932
8933                                 nbfile_alloc = nbfile_alloc * 2 + 1;
8934                                 oldhur = hur;
8935                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
8936                                                                    opaque_len);
8937                                 if (!hur) {
8938                                         fprintf(stderr,
8939                                                 "hsm: cannot allocate the request: %s\n",
8940                                                 strerror(errno));
8941                                         hur = oldhur;
8942                                         rc = -errno;
8943                                         fclose(fp);
8944                                         goto out_free;
8945                                 }
8946                                 size = hur_len(oldhur);
8947                                 if (size < 0) {
8948                                         fprintf(stderr,
8949                                                 "hsm: cannot allocate %u files + %u bytes data\n",
8950                                                 oldhur->hur_request.hr_itemcount,
8951                                                 oldhur->hur_request.hr_data_len);
8952                                         free(hur);
8953                                         hur = oldhur;
8954                                         rc = -E2BIG;
8955                                         fclose(fp);
8956                                         goto out_free;
8957                                 }
8958                                 memcpy(hur, oldhur, size);
8959                                 free(oldhur);
8960                         }
8961
8962                         /* Chop CR */
8963                         if (line[strlen(line) - 1] == '\n')
8964                                 line[strlen(line) - 1] = '\0';
8965
8966                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
8967                                            mntpath, line, &last_dev);
8968                         if (rc) {
8969                                 fclose(fp);
8970                                 goto out_free;
8971                         }
8972
8973                         if (!some_file) {
8974                                 some_file = line;
8975                                 line = NULL;
8976                         }
8977                 }
8978
8979                 rc = fclose(fp);
8980                 free(line);
8981         }
8982
8983         /* If a --data was used, add it to the request */
8984         hur->hur_request.hr_data_len = opaque_len;
8985         if (opaque)
8986                 memcpy(hur_data(hur), opaque, opaque_len);
8987
8988         /* Send the HSM request */
8989         if (realpath(some_file, fullpath) == NULL) {
8990                 fprintf(stderr, "Could not find path '%s': %s\n",
8991                         some_file, strerror(errno));
8992         }
8993         rc = llapi_hsm_request(fullpath, hur);
8994         if (rc) {
8995                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
8996                         some_file, strerror(-rc));
8997                 goto out_free;
8998         }
8999
9000 out_free:
9001         free(some_file);
9002         free(hur);
9003         return rc;
9004 }
9005
9006 static int lfs_hsm_archive(int argc, char **argv)
9007 {
9008         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
9009 }
9010
9011 static int lfs_hsm_restore(int argc, char **argv)
9012 {
9013         return lfs_hsm_request(argc, argv, HUA_RESTORE);
9014 }
9015
9016 static int lfs_hsm_release(int argc, char **argv)
9017 {
9018         return lfs_hsm_request(argc, argv, HUA_RELEASE);
9019 }
9020
9021 static int lfs_hsm_remove(int argc, char **argv)
9022 {
9023         return lfs_hsm_request(argc, argv, HUA_REMOVE);
9024 }
9025
9026 static int lfs_hsm_cancel(int argc, char **argv)
9027 {
9028         return lfs_hsm_request(argc, argv, HUA_CANCEL);
9029 }
9030
9031 static int lfs_swap_layouts(int argc, char **argv)
9032 {
9033         if (argc != 3)
9034                 return CMD_HELP;
9035
9036         return llapi_swap_layouts(argv[1], argv[2], 0, 0,
9037                                   SWAP_LAYOUTS_KEEP_MTIME |
9038                                   SWAP_LAYOUTS_KEEP_ATIME);
9039 }
9040
9041 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
9042
9043 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
9044
9045 int lfs_get_mode(const char *string)
9046 {
9047         enum lock_mode_user mode;
9048
9049         for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
9050                 if (lock_mode_names[mode] == NULL)
9051                         continue;
9052                 if (strcmp(string, lock_mode_names[mode]) == 0)
9053                         return mode;
9054         }
9055
9056         return -EINVAL;
9057 }
9058
9059 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
9060 {
9061         enum lu_ladvise_type advice;
9062
9063         for (advice = 0;
9064              advice < ARRAY_SIZE(ladvise_names); advice++) {
9065                 if (ladvise_names[advice] == NULL)
9066                         continue;
9067                 if (strcmp(string, ladvise_names[advice]) == 0)
9068                         return advice;
9069         }
9070
9071         return LU_LADVISE_INVALID;
9072 }
9073
9074 static int lfs_ladvise(int argc, char **argv)
9075 {
9076         struct option long_opts[] = {
9077         { .val = 'a',   .name = "advice",       .has_arg = required_argument },
9078         { .val = 'b',   .name = "background",   .has_arg = no_argument },
9079         { .val = 'e',   .name = "end",          .has_arg = required_argument },
9080         { .val = 'l',   .name = "length",       .has_arg = required_argument },
9081         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
9082         { .val = 's',   .name = "start",        .has_arg = required_argument },
9083         { .val = 'u',   .name = "unset",        .has_arg = no_argument },
9084         { .name = NULL } };
9085         char                     short_opts[] = "a:be:l:m:s:u";
9086         int                      c;
9087         int                      rc = 0;
9088         const char              *path;
9089         int                      fd;
9090         struct llapi_lu_ladvise  advice;
9091         enum lu_ladvise_type     advice_type = LU_LADVISE_INVALID;
9092         unsigned long long       start = 0;
9093         unsigned long long       end = LUSTRE_EOF;
9094         unsigned long long       length = 0;
9095         unsigned long long       size_units;
9096         unsigned long long       flags = 0;
9097         int                      mode = 0;
9098
9099         optind = 0;
9100         while ((c = getopt_long(argc, argv, short_opts,
9101                                 long_opts, NULL)) != -1) {
9102                 switch (c) {
9103                 case 'a':
9104                         advice_type = lfs_get_ladvice(optarg);
9105                         if (advice_type == LU_LADVISE_INVALID) {
9106                                 fprintf(stderr,
9107                                         "%s: invalid advice type '%s'\n",
9108                                         argv[0], optarg);
9109                                 fprintf(stderr, "Valid types:");
9110
9111                                 for (advice_type = 0;
9112                                      advice_type < ARRAY_SIZE(ladvise_names);
9113                                      advice_type++) {
9114                                         if (ladvise_names[advice_type] == NULL)
9115                                                 continue;
9116                                         fprintf(stderr, " %s",
9117                                                 ladvise_names[advice_type]);
9118                                 }
9119                                 fprintf(stderr, "\n");
9120
9121                                 return CMD_HELP;
9122                         }
9123                         break;
9124                 case 'b':
9125                         flags |= LF_ASYNC;
9126                         break;
9127                 case 'u':
9128                         flags |= LF_UNSET;
9129                         break;
9130                 case 'e':
9131                         size_units = 1;
9132                         rc = llapi_parse_size(optarg, &end,
9133                                               &size_units, 0);
9134                         if (rc) {
9135                                 fprintf(stderr, "%s: bad end offset '%s'\n",
9136                                         argv[0], optarg);
9137                                 return CMD_HELP;
9138                         }
9139                         break;
9140                 case 's':
9141                         size_units = 1;
9142                         rc = llapi_parse_size(optarg, &start,
9143                                               &size_units, 0);
9144                         if (rc) {
9145                                 fprintf(stderr,
9146                                         "%s: bad start offset '%s'\n",
9147                                         argv[0], optarg);
9148                                 return CMD_HELP;
9149                         }
9150                         break;
9151                 case 'l':
9152                         size_units = 1;
9153                         rc = llapi_parse_size(optarg, &length,
9154                                               &size_units, 0);
9155                         if (rc) {
9156                                 fprintf(stderr, "%s: bad length '%s'\n",
9157                                         argv[0], optarg);
9158                                 return CMD_HELP;
9159                         }
9160                         break;
9161                 case 'm':
9162                         mode = lfs_get_mode(optarg);
9163                         if (mode < 0) {
9164                                 fprintf(stderr,
9165                                         "%s: bad mode '%s', valid modes are READ or WRITE\n",
9166                                         argv[0], optarg);
9167                                 return CMD_HELP;
9168                         }
9169                         break;
9170                 case '?':
9171                         return CMD_HELP;
9172                 default:
9173                         fprintf(stderr, "%s: option '%s' unrecognized\n",
9174                                 argv[0], argv[optind - 1]);
9175                         return CMD_HELP;
9176                 }
9177         }
9178
9179         if (advice_type == LU_LADVISE_INVALID) {
9180                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
9181                 fprintf(stderr, "Valid types:");
9182                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
9183                      advice_type++) {
9184                         if (ladvise_names[advice_type] == NULL)
9185                                 continue;
9186                         fprintf(stderr, " %s", ladvise_names[advice_type]);
9187                 }
9188                 fprintf(stderr, "\n");
9189                 return CMD_HELP;
9190         }
9191
9192         if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
9193                 fprintf(stderr,
9194                         "%s: Lock no expand advice is a per file descriptor advice, so when called from lfs, it does nothing.\n",
9195                         argv[0]);
9196                 return CMD_HELP;
9197         }
9198
9199         if (argc <= optind) {
9200                 fprintf(stderr, "%s: please give one or more file names\n",
9201                         argv[0]);
9202                 return CMD_HELP;
9203         }
9204
9205         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
9206                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
9207                         argv[0]);
9208                 return CMD_HELP;
9209         }
9210
9211         if (end == LUSTRE_EOF && length != 0)
9212                 end = start + length;
9213
9214         if (end <= start) {
9215                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
9216                         argv[0], start, end);
9217                 return CMD_HELP;
9218         }
9219
9220         if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
9221                 fprintf(stderr, "%s: mode is only valid with lockahead\n",
9222                         argv[0]);
9223                 return CMD_HELP;
9224         }
9225
9226         if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
9227                 fprintf(stderr, "%s: mode is required with lockahead\n",
9228                         argv[0]);
9229                 return CMD_HELP;
9230         }
9231
9232         while (optind < argc) {
9233                 int rc2;
9234
9235                 path = argv[optind++];
9236
9237                 fd = open(path, O_RDONLY);
9238                 if (fd < 0) {
9239                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
9240                                 argv[0], path, strerror(errno));
9241                         rc2 = -errno;
9242                         goto next;
9243                 }
9244
9245                 advice.lla_start = start;
9246                 advice.lla_end = end;
9247                 advice.lla_advice = advice_type;
9248                 advice.lla_value1 = 0;
9249                 advice.lla_value2 = 0;
9250                 advice.lla_value3 = 0;
9251                 advice.lla_value4 = 0;
9252                 if (advice_type == LU_LADVISE_LOCKAHEAD) {
9253                         advice.lla_lockahead_mode = mode;
9254                         advice.lla_peradvice_flags = flags;
9255                 }
9256
9257                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
9258                 close(fd);
9259                 if (rc2 < 0) {
9260                         fprintf(stderr,
9261                                 "%s: cannot give advice '%s' to file '%s': %s\n",
9262                                 argv[0], ladvise_names[advice_type],
9263                                 path, strerror(errno));
9264
9265                         goto next;
9266                 }
9267
9268 next:
9269                 if (rc == 0 && rc2 < 0)
9270                         rc = rc2;
9271         }
9272         return rc;
9273 }
9274
9275 static const char *const heat_names[] = LU_HEAT_NAMES;
9276
9277 static int lfs_heat_get(int argc, char **argv)
9278 {
9279         struct lu_heat *heat;
9280         int rc = 0, rc2;
9281         char *path;
9282         int fd;
9283         int i;
9284
9285         if (argc <= 1)
9286                 return CMD_HELP;
9287
9288         heat = calloc(sizeof(*heat) + sizeof(__u64) * OBD_HEAT_COUNT, 1);
9289         if (!heat) {
9290                 fprintf(stderr, "%s: memory allocation failed\n", argv[0]);
9291                 return -ENOMEM;
9292         }
9293
9294         optind = 1;
9295         while (optind < argc) {
9296                 path = argv[optind++];
9297
9298                 fd = open(path, O_RDONLY);
9299                 if (fd < 0) {
9300                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
9301                                 argv[0], path, strerror(errno));
9302                         rc2 = -errno;
9303                         goto next;
9304                 }
9305
9306                 heat->lh_count = OBD_HEAT_COUNT;
9307                 rc2 = llapi_heat_get(fd, heat);
9308                 close(fd);
9309                 if (rc2 < 0) {
9310                         fprintf(stderr,
9311                                 "%s: cannot get heat of file '%s': %s\n",
9312                                 argv[0], path, strerror(errno));
9313                         goto next;
9314                 }
9315
9316                 printf("flags: %x\n", heat->lh_flags);
9317                 for (i = 0; i < heat->lh_count; i++)
9318                         printf("%s: %llu\n", heat_names[i],
9319                                (unsigned long long)heat->lh_heat[i]);
9320 next:
9321                 if (rc == 0 && rc2 < 0)
9322                         rc = rc2;
9323         }
9324
9325         free(heat);
9326         return rc;
9327 }
9328
9329 static int lfs_heat_set(int argc, char **argv)
9330 {
9331         struct option long_opts[] = {
9332         { .val = 'c',   .name = "clear",        .has_arg = no_argument },
9333         { .val = 'o',   .name = "off",          .has_arg = no_argument },
9334         { .val = 'O',   .name = "on",           .has_arg = no_argument },
9335         { .name = NULL } };
9336         enum lu_heat_flag flags = 0;
9337         int rc = 0, rc2;
9338         char *path;
9339         int fd;
9340         int c;
9341
9342         if (argc <= 1)
9343                 return CMD_HELP;
9344
9345         optind = 0;
9346         while ((c = getopt_long(argc, argv, "coO", long_opts, NULL)) != -1) {
9347                 switch (c) {
9348                 case 'c':
9349                         flags |= LU_HEAT_FLAG_CLEAR;
9350                         break;
9351                 case 'o':
9352                         flags |= LU_HEAT_FLAG_CLEAR;
9353                         flags |= LU_HEAT_FLAG_OFF;
9354                         break;
9355                 case 'O':
9356                         flags &= ~LU_HEAT_FLAG_OFF;
9357                         break;
9358                 case '?':
9359                         return CMD_HELP;
9360                 default:
9361                         fprintf(stderr, "%s: option '%s' unrecognized\n",
9362                                 argv[0], argv[optind - 1]);
9363                         return CMD_HELP;
9364                 }
9365         }
9366
9367         if (argc <= optind) {
9368                 fprintf(stderr, "%s: please give one or more file names\n",
9369                         argv[0]);
9370                 return CMD_HELP;
9371         }
9372
9373         while (optind < argc) {
9374                 path = argv[optind++];
9375
9376                 fd = open(path, O_RDONLY);
9377                 if (fd < 0) {
9378                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
9379                                 argv[0], path, strerror(errno));
9380                         rc2 = -errno;
9381                         goto next;
9382                 }
9383
9384                 rc2 = llapi_heat_set(fd, flags);
9385                 close(fd);
9386                 if (rc2 < 0) {
9387                         fprintf(stderr,
9388                                 "%s: cannot setflags heat of file '%s': %s\n",
9389                                 argv[0], path, strerror(errno));
9390                         goto next;
9391                 }
9392 next:
9393                 if (rc == 0 && rc2 < 0)
9394                         rc = rc2;
9395         }
9396         return rc;
9397 }
9398
9399 /**
9400  * The input string contains a comma delimited list of component ids and
9401  * ranges, for example "1,2-4,7".
9402  */
9403 static int parse_mirror_ids(__u16 *ids, int size, char *arg)
9404 {
9405         bool end_of_loop = false;
9406         char *ptr = NULL;
9407         int nr = 0;
9408         int rc;
9409
9410         if (!arg)
9411                 return -EINVAL;
9412
9413         while (!end_of_loop) {
9414                 int start_index;
9415                 int end_index;
9416                 int i;
9417                 char *endptr = NULL;
9418
9419                 rc = -EINVAL;
9420                 ptr = strchrnul(arg, ',');
9421                 end_of_loop = *ptr == '\0';
9422                 *ptr = '\0';
9423
9424                 start_index = strtol(arg, &endptr, 0);
9425                 if (endptr == arg) /* no data at all */
9426                         break;
9427                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
9428                         break;
9429                 if (start_index < 0)
9430                         break;
9431
9432                 end_index = start_index;
9433                 if (*endptr == '-') {
9434                         end_index = strtol(endptr + 1, &endptr, 0);
9435                         if (*endptr != '\0')
9436                                 break;
9437                         if (end_index < start_index)
9438                                 break;
9439                 }
9440
9441                 for (i = start_index; i <= end_index && size > 0; i++) {
9442                         int j;
9443
9444                         /* remove duplicate */
9445                         for (j = 0; j < nr; j++) {
9446                                 if (ids[j] == i)
9447                                         break;
9448                         }
9449                         if (j == nr) { /* no duplicate */
9450                                 ids[nr++] = i;
9451                                 --size;
9452                         }
9453                 }
9454
9455                 if (size == 0 && i < end_index)
9456                         break;
9457
9458                 *ptr = ',';
9459                 arg = ++ptr;
9460                 rc = 0;
9461         }
9462         if (!end_of_loop && ptr)
9463                 *ptr = ',';
9464
9465         return rc < 0 ? rc : nr;
9466 }
9467
9468 /**
9469  * struct verify_mirror_id - Mirror id to be verified.
9470  * @mirror_id:   A specified mirror id.
9471  * @is_valid_id: @mirror_id is valid or not in the mirrored file.
9472  */
9473 struct verify_mirror_id {
9474         __u16 mirror_id;
9475         bool is_valid_id;
9476 };
9477
9478 /**
9479  * compare_mirror_ids() - Compare mirror ids.
9480  * @layout: Mirror component list.
9481  * @cbdata: Callback data in verify_mirror_id structure.
9482  *
9483  * This is a callback function called by llapi_layout_comp_iterate()
9484  * to compare the specified mirror id with the one in the current
9485  * component of @layout. If they are the same, then the specified
9486  * mirror id is valid.
9487  *
9488  * Return: a negative error code on failure or
9489  *         LLAPI_LAYOUT_ITER_CONT: Proceed iteration
9490  *         LLAPI_LAYOUT_ITER_STOP: Stop iteration
9491  */
9492 static inline
9493 int compare_mirror_ids(struct llapi_layout *layout, void *cbdata)
9494 {
9495         struct verify_mirror_id *mirror_id_cbdata =
9496                                  (struct verify_mirror_id *)cbdata;
9497         uint32_t mirror_id;
9498         int rc = 0;
9499
9500         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
9501         if (rc < 0) {
9502                 rc = -errno;
9503                 fprintf(stderr,
9504                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
9505                         progname, strerror(errno));
9506                 return rc;
9507         }
9508
9509         if (mirror_id_cbdata->mirror_id == mirror_id) {
9510                 mirror_id_cbdata->is_valid_id = true;
9511                 return LLAPI_LAYOUT_ITER_STOP;
9512         }
9513
9514         return LLAPI_LAYOUT_ITER_CONT;
9515 }
9516
9517 /**
9518  * verify_mirror_ids() - Verify specified mirror ids.
9519  * @fname:      Mirrored file name.
9520  * @mirror_ids: Specified mirror ids to be verified.
9521  * @ids_nr:     Number of specified mirror ids.
9522  *
9523  * This function verifies that specified @mirror_ids are valid
9524  * in the mirrored file @fname.
9525  *
9526  * Return: 0 on success or a negative error code on failure.
9527  */
9528 static inline
9529 int verify_mirror_ids(const char *fname, __u16 *mirror_ids, int ids_nr)
9530 {
9531         struct llapi_layout *layout = NULL;
9532         struct verify_mirror_id mirror_id_cbdata = { 0 };
9533         struct stat stbuf;
9534         uint32_t flr_state;
9535         int i;
9536         int fd;
9537         int rc = 0;
9538         int rc2 = 0;
9539
9540         if (ids_nr <= 0)
9541                 return -EINVAL;
9542
9543         if (stat(fname, &stbuf) < 0) {
9544                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
9545                         progname, fname, strerror(errno));
9546                 rc = -errno;
9547                 goto error;
9548         }
9549
9550         if (!S_ISREG(stbuf.st_mode)) {
9551                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
9552                         progname, fname);
9553                 rc = -EINVAL;
9554                 goto error;
9555         }
9556
9557         fd = open(fname, O_DIRECT | O_RDONLY);
9558         if (fd < 0) {
9559                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
9560                         progname, fname, strerror(errno));
9561                 rc = -errno;
9562                 goto error;
9563         }
9564
9565         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
9566         if (rc < 0) {
9567                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
9568                         progname, fname, strerror(errno));
9569                 goto close_fd;
9570         }
9571
9572         layout = llapi_layout_get_by_fd(fd, 0);
9573         if (!layout) {
9574                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
9575                         progname, fname, strerror(errno));
9576                 rc = -errno;
9577                 llapi_lease_release(fd);
9578                 goto close_fd;
9579         }
9580
9581         rc = llapi_layout_flags_get(layout, &flr_state);
9582         if (rc < 0) {
9583                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
9584                         progname, fname, strerror(errno));
9585                 rc = -errno;
9586                 goto free_layout;
9587         }
9588
9589         flr_state &= LCM_FL_FLR_MASK;
9590         switch (flr_state) {
9591         case LCM_FL_NONE:
9592                 rc = -EINVAL;
9593                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
9594                         progname, fname, llapi_layout_flags_string(flr_state));
9595                 goto free_layout;
9596         default:
9597                 break;
9598         }
9599
9600         rc2 = 0;
9601         for (i = 0; i < ids_nr; i++) {
9602                 mirror_id_cbdata.mirror_id = mirror_ids[i];
9603                 mirror_id_cbdata.is_valid_id = false;
9604
9605                 rc = llapi_layout_comp_iterate(layout, compare_mirror_ids,
9606                                                &mirror_id_cbdata);
9607                 if (rc < 0) {
9608                         rc = -errno;
9609                         fprintf(stderr,
9610                                 "%s: '%s' failed to verify mirror id: %u.\n",
9611                                 progname, fname, mirror_ids[i]);
9612                         goto free_layout;
9613                 }
9614
9615                 if (!mirror_id_cbdata.is_valid_id) {
9616                         rc2 = -EINVAL;
9617                         fprintf(stderr,
9618                                 "%s: '%s' invalid specified mirror id: %u.\n",
9619                                 progname, fname, mirror_ids[i]);
9620                 }
9621         }
9622         rc = rc2;
9623
9624 free_layout:
9625         llapi_layout_free(layout);
9626         llapi_lease_release(fd);
9627 close_fd:
9628         close(fd);
9629 error:
9630         return rc;
9631 }
9632
9633 static inline
9634 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
9635                            __u16 *mirror_ids, int ids_nr)
9636 {
9637         struct llapi_resync_comp comp_array[1024] = { { 0 } };
9638         struct llapi_layout *layout;
9639         struct stat stbuf;
9640         uint32_t flr_state;
9641         uint64_t start;
9642         uint64_t end;
9643         int comp_size = 0;
9644         int idx;
9645         int fd;
9646         int rc;
9647         int rc2;
9648
9649         if (stat(fname, &stbuf) < 0) {
9650                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
9651                         progname, fname, strerror(errno));
9652                 rc = -errno;
9653                 goto error;
9654         }
9655         if (!S_ISREG(stbuf.st_mode)) {
9656                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
9657                         progname, fname);
9658                 rc = -EINVAL;
9659                 goto error;
9660         }
9661
9662         fd = open(fname, O_DIRECT | O_RDWR);
9663         if (fd < 0) {
9664                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
9665                         progname, fname, strerror(errno));
9666                 rc = -errno;
9667                 goto error;
9668         }
9669
9670         layout = llapi_layout_get_by_fd(fd, 0);
9671         if (!layout) {
9672                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
9673                         progname, fname, strerror(errno));
9674                 rc = -errno;
9675                 goto close_fd;
9676         }
9677
9678         rc = llapi_layout_flags_get(layout, &flr_state);
9679         if (rc) {
9680                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
9681                         progname, fname, strerror(errno));
9682                 rc = -errno;
9683                 goto free_layout;
9684         }
9685
9686         flr_state &= LCM_FL_FLR_MASK;
9687         if (flr_state == LCM_FL_NONE) {
9688                 rc = -EINVAL;
9689                 fprintf(stderr, "%s: '%s' is not a FLR file.\n",
9690                         progname, fname);
9691                 goto free_layout;
9692         }
9693
9694         /* get stale component info */
9695         comp_size = llapi_mirror_find_stale(layout, comp_array,
9696                                             ARRAY_SIZE(comp_array),
9697                                             mirror_ids, ids_nr);
9698         if (comp_size <= 0) {
9699                 rc = comp_size;
9700                 goto free_layout;
9701         }
9702
9703         ioc->lil_mode = LL_LEASE_WRLCK;
9704         ioc->lil_flags = LL_LEASE_RESYNC;
9705         rc = llapi_lease_set(fd, ioc);
9706         if (rc < 0) {
9707                 if (rc == -EALREADY)
9708                         rc = 0;
9709                 else
9710                         fprintf(stderr,
9711                             "%s: '%s' llapi_lease_get_ext resync failed: %s.\n",
9712                                 progname, fname, strerror(-rc));
9713                 goto free_layout;
9714         }
9715
9716         /* get the read range [start, end) */
9717         start = comp_array[0].lrc_start;
9718         end = comp_array[0].lrc_end;
9719         for (idx = 1; idx < comp_size; idx++) {
9720                 if (comp_array[idx].lrc_start < start)
9721                         start = comp_array[idx].lrc_start;
9722                 if (end < comp_array[idx].lrc_end)
9723                         end = comp_array[idx].lrc_end;
9724         }
9725
9726         rc = llapi_lease_check(fd);
9727         if (rc != LL_LEASE_WRLCK) {
9728                 fprintf(stderr, "%s: '%s' lost lease lock.\n",
9729                         progname, fname);
9730                 goto free_layout;
9731         }
9732
9733         rc = llapi_mirror_resync_many(fd, layout, comp_array, comp_size,
9734                                       start, end);
9735         if (rc < 0)
9736                 fprintf(stderr, "%s: '%s' llapi_mirror_resync_many: %s.\n",
9737                         progname, fname, strerror(-rc));
9738
9739         /* need to do the lease unlock even resync fails */
9740         ioc->lil_mode = LL_LEASE_UNLCK;
9741         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
9742         ioc->lil_count = 0;
9743         for (idx = 0; idx < comp_size; idx++) {
9744                 if (comp_array[idx].lrc_synced) {
9745                         ioc->lil_ids[ioc->lil_count] = comp_array[idx].lrc_id;
9746                         ioc->lil_count++;
9747                 }
9748         }
9749
9750         rc2 = llapi_lease_set(fd, ioc);
9751         /**
9752          * llapi_lease_set returns lease mode when it request to unlock
9753          * the lease lock.
9754          */
9755         if (rc2 <= 0) {
9756                 /* rc2 == 0 means lost lease lock */
9757                 if (rc2 == 0 && rc == 0)
9758                         rc = -EBUSY;
9759                 fprintf(stderr, "%s: resync file '%s' failed: %s.\n",
9760                         progname, fname,
9761                         rc2 == 0 ? "lost lease lock" : strerror(-rc2));
9762         }
9763
9764 free_layout:
9765         llapi_layout_free(layout);
9766 close_fd:
9767         close(fd);
9768 error:
9769         return rc;
9770 }
9771
9772 static inline int lfs_mirror_resync(int argc, char **argv)
9773 {
9774         struct ll_ioc_lease *ioc = NULL;
9775         __u16 mirror_ids[128] = { 0 };
9776         int ids_nr = 0;
9777         int c;
9778         int rc = 0;
9779
9780         struct option long_opts[] = {
9781         { .val = 'o',   .name = "only",         .has_arg = required_argument },
9782         { .name = NULL } };
9783
9784         while ((c = getopt_long(argc, argv, "o:", long_opts, NULL)) >= 0) {
9785                 switch (c) {
9786                 case 'o':
9787                         rc = parse_mirror_ids(mirror_ids,
9788                                         sizeof(mirror_ids) / sizeof(__u16),
9789                                         optarg);
9790                         if (rc < 0) {
9791                                 fprintf(stderr,
9792                                         "%s: bad mirror ids '%s'.\n",
9793                                         argv[0], optarg);
9794                                 goto error;
9795                         }
9796                         ids_nr = rc;
9797                         break;
9798                 default:
9799                         fprintf(stderr, "%s: options '%s' unrecognized.\n",
9800                                 argv[0], argv[optind - 1]);
9801                         rc = -EINVAL;
9802                         goto error;
9803                 }
9804         }
9805
9806         if (argc == optind) {
9807                 fprintf(stderr, "%s: no file name given.\n", argv[0]);
9808                 rc = CMD_HELP;
9809                 goto error;
9810         }
9811
9812         if (ids_nr > 0 && argc > optind + 1) {
9813                 fprintf(stderr,
9814                     "%s: option '--only' cannot be used upon multiple files.\n",
9815                         argv[0]);
9816                 rc = CMD_HELP;
9817                 goto error;
9818         }
9819
9820         if (ids_nr > 0) {
9821                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
9822                 if (rc < 0)
9823                         goto error;
9824         }
9825
9826         /* set the lease on the file */
9827         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
9828         if (!ioc) {
9829                 fprintf(stderr, "%s: cannot alloc id array for ioc: %s.\n",
9830                         argv[0], strerror(errno));
9831                 rc = -errno;
9832                 goto error;
9833         }
9834
9835         for (; optind < argc; optind++) {
9836                 rc = lfs_mirror_resync_file(argv[optind], ioc,
9837                                             mirror_ids, ids_nr);
9838                 /* ignore previous file's error, continue with next file */
9839
9840                 /* reset ioc */
9841                 memset(ioc, 0, sizeof(*ioc) + sizeof(__u32) * 4096);
9842         }
9843
9844         free(ioc);
9845 error:
9846         return rc;
9847 }
9848
9849 static inline int verify_mirror_id_by_fd(int fd, __u16 mirror_id)
9850 {
9851         struct llapi_layout *layout;
9852         int rc;
9853
9854         layout = llapi_layout_get_by_fd(fd, 0);
9855         if (!layout) {
9856                 fprintf(stderr, "could not get layout.\n");
9857                 return  -EINVAL;
9858         }
9859
9860         rc = llapi_layout_comp_iterate(layout, find_mirror_id, &mirror_id);
9861         if (rc < 0) {
9862                 fprintf(stderr, "failed to iterate layout\n");
9863                 llapi_layout_free(layout);
9864
9865                 return rc;
9866         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
9867                 fprintf(stderr, "does not find mirror with ID %u\n", mirror_id);
9868                 llapi_layout_free(layout);
9869
9870                 return -EINVAL;
9871         }
9872         llapi_layout_free(layout);
9873
9874         return 0;
9875 }
9876
9877 /**
9878  * Check whether two files are the same file
9879  * \retval      0  same file
9880  * \retval      1  not the same file
9881  * \retval      <0 error code
9882  */
9883 static inline int check_same_file(int fd, const char *f2)
9884 {
9885         struct stat stbuf1;
9886         struct stat stbuf2;
9887
9888         if (fstat(fd, &stbuf1) < 0)
9889                 return -errno;
9890
9891         if (stat(f2, &stbuf2) < 0)
9892                 return 1;
9893
9894         if (stbuf1.st_rdev == stbuf2.st_rdev &&
9895             stbuf1.st_ino == stbuf2.st_ino)
9896                 return 0;
9897
9898         return 1;
9899 }
9900
9901 static inline int lfs_mirror_read(int argc, char **argv)
9902 {
9903         int rc = CMD_HELP;
9904         __u16 mirror_id = 0;
9905         const char *outfile = NULL;
9906         char *fname;
9907         int fd = 0;
9908         int outfd;
9909         int c;
9910         void *buf;
9911         const size_t buflen = 4 << 20;
9912         off_t pos;
9913         struct option long_opts[] = {
9914         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
9915         { .val = 'o',   .name = "outfile",      .has_arg = required_argument },
9916         { .name = NULL } };
9917
9918         while ((c = getopt_long(argc, argv, "N:o:", long_opts, NULL)) >= 0) {
9919                 char *end;
9920
9921                 switch (c) {
9922                 case 'N':
9923                         mirror_id = strtoul(optarg, &end, 0);
9924                         if (*end != '\0' || mirror_id == 0) {
9925                                 fprintf(stderr,
9926                                         "%s %s: invalid mirror ID '%s'\n",
9927                                         progname, argv[0], optarg);
9928                                 return rc;
9929                         }
9930                         break;
9931                 case 'o':
9932                         outfile = optarg;
9933                         break;
9934                 default:
9935                         fprintf(stderr, "%s: option '%s' unrecognized.\n",
9936                                 progname, argv[optind - 1]);
9937                         return -EINVAL;
9938                 }
9939         }
9940
9941         if (argc == optind) {
9942                 fprintf(stderr, "%s %s: no mirrored file provided\n",
9943                         progname, argv[0]);
9944                 return rc;
9945         } else if (argc > optind + 1) {
9946                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
9947                 return rc;
9948         }
9949
9950         if (mirror_id == 0) {
9951                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
9952                         progname, argv[0]);
9953                 return rc;
9954         }
9955
9956         /* open mirror file */
9957         fname = argv[optind];
9958         fd = open(fname, O_DIRECT | O_RDONLY);
9959         if (fd < 0) {
9960                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
9961                         progname, argv[0], fname, strerror(errno));
9962                 return rc;
9963         }
9964
9965         /* verify mirror id */
9966         rc = verify_mirror_id_by_fd(fd, mirror_id);
9967         if (rc) {
9968                 fprintf(stderr,
9969                         "%s %s: cannot find mirror with ID %u in '%s'\n",
9970                         progname, argv[0], mirror_id, fname);
9971                 goto close_fd;
9972         }
9973
9974         /* open output file - O_EXCL ensures output is not the same as input */
9975         if (outfile) {
9976                 outfd = open(outfile, O_EXCL | O_WRONLY | O_CREAT, 0644);
9977                 if (outfd < 0) {
9978                         fprintf(stderr, "%s %s: cannot create file '%s': %s\n",
9979                                 progname, argv[0], outfile, strerror(errno));
9980                         rc = -errno;
9981                         goto close_fd;
9982                 }
9983         } else {
9984                 outfd = STDOUT_FILENO;
9985         }
9986
9987         /* allocate buffer */
9988         rc = posix_memalign(&buf, sysconf(_SC_PAGESIZE), buflen);
9989         if (rc) {
9990                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
9991                                 progname, argv[0], rc);
9992                 goto close_outfd;
9993         }
9994
9995         pos = 0;
9996         while (1) {
9997                 ssize_t bytes_read;
9998                 ssize_t written = 0;
9999
10000                 bytes_read = llapi_mirror_read(fd, mirror_id, buf, buflen, pos);
10001                 if (bytes_read < 0) {
10002                         rc = bytes_read;
10003                         fprintf(stderr,
10004                                 "%s %s: fail to read data from mirror %u: %s\n",
10005                                 progname, argv[0], mirror_id, strerror(-rc));
10006                         goto free_buf;
10007                 }
10008
10009                 /* EOF reached */
10010                 if (bytes_read == 0)
10011                         break;
10012
10013                 while (written < bytes_read) {
10014                         ssize_t written2;
10015
10016                         written2 = write(outfd, buf + written,
10017                                          bytes_read - written);
10018                         if (written2 < 0) {
10019                                 fprintf(stderr,
10020                                         "%s %s: fail to write %s: %s\n",
10021                                         progname, argv[0], outfile ? : "STDOUT",
10022                                         strerror(errno));
10023                                 rc = -errno;
10024                                 goto free_buf;
10025                         }
10026                         written += written2;
10027                 }
10028
10029                 if (written != bytes_read) {
10030                         fprintf(stderr,
10031                 "%s %s: written %ld bytes does not match with %ld read.\n",
10032                                 progname, argv[0], written, bytes_read);
10033                         rc = -EIO;
10034                         goto free_buf;
10035                 }
10036
10037                 pos += bytes_read;
10038         }
10039
10040         fsync(outfd);
10041         rc = 0;
10042
10043 free_buf:
10044         free(buf);
10045 close_outfd:
10046         if (outfile)
10047                 close(outfd);
10048 close_fd:
10049         close(fd);
10050
10051         return rc;
10052 }
10053
10054 static inline int lfs_mirror_write(int argc, char **argv)
10055 {
10056         int rc = CMD_HELP;
10057         __u16 mirror_id = 0;
10058         const char *inputfile = NULL;
10059         char *fname;
10060         int fd = 0;
10061         int inputfd;
10062         int c;
10063         void *buf;
10064         const size_t buflen = 4 << 20;
10065         off_t pos;
10066         size_t page_size = sysconf(_SC_PAGESIZE);
10067         struct ll_ioc_lease_id ioc;
10068
10069         struct option long_opts[] = {
10070         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
10071         { .val = 'i',   .name = "inputfile",    .has_arg = required_argument },
10072         { .name = NULL } };
10073
10074         while ((c = getopt_long(argc, argv, "N:i:", long_opts, NULL)) >= 0) {
10075                 char *end;
10076
10077                 switch (c) {
10078                 case 'N':
10079                         mirror_id = strtoul(optarg, &end, 0);
10080                         if (*end != '\0' || mirror_id == 0) {
10081                                 fprintf(stderr,
10082                                         "%s %s: invalid mirror ID '%s'\n",
10083                                         progname, argv[0], optarg);
10084                                 return rc;
10085                         }
10086                         break;
10087                 case 'i':
10088                         inputfile = optarg;
10089                         break;
10090                 default:
10091                         fprintf(stderr, "%s: option '%s' unrecognized\n",
10092                                 progname, argv[optind - 1]);
10093                         return -EINVAL;
10094                 }
10095         }
10096
10097         if (argc == optind) {
10098                 fprintf(stderr, "%s %s: no mirrored file provided\n",
10099                         progname, argv[0]);
10100                 return rc;
10101         } else if (argc > optind + 1) {
10102                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
10103                 return rc;
10104         }
10105
10106         if (mirror_id == 0) {
10107                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
10108                         progname, argv[0]);
10109                 return rc;
10110         }
10111
10112         /* open mirror file */
10113         fname = argv[optind];
10114         fd = open(fname, O_DIRECT | O_WRONLY);
10115         if (fd < 0) {
10116                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
10117                         progname, argv[0], fname, strerror(errno));
10118                 return rc;
10119         }
10120
10121         /* verify mirror id */
10122         rc = verify_mirror_id_by_fd(fd, mirror_id);
10123         if (rc) {
10124                 fprintf(stderr,
10125                         "%s %s: cannot find mirror with ID %u in '%s'\n",
10126                         progname, argv[0], mirror_id, fname);
10127                 goto close_fd;
10128         }
10129
10130         /* open input file */
10131         if (inputfile) {
10132                 rc = check_same_file(fd, inputfile);
10133                 if (rc == 0) {
10134                         fprintf(stderr,
10135                         "%s %s: input file cannot be the mirrored file\n",
10136                                 progname, argv[0]);
10137                         goto close_fd;
10138                 }
10139                 if (rc < 0)
10140                         goto close_fd;
10141
10142                 inputfd = open(inputfile, O_RDONLY, 0644);
10143                 if (inputfd < 0) {
10144                         fprintf(stderr, "%s %s: cannot open file '%s': %s\n",
10145                                 progname, argv[0], inputfile, strerror(errno));
10146                         rc = -errno;
10147                         goto close_fd;
10148                 }
10149         } else {
10150                 inputfd = STDIN_FILENO;
10151         }
10152
10153         /* allocate buffer */
10154         rc = posix_memalign(&buf, page_size, buflen);
10155         if (rc) {
10156                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
10157                         progname, argv[0], rc);
10158                 goto close_inputfd;
10159         }
10160
10161         /* prepare target mirror components instantiation */
10162         ioc.lil_mode = LL_LEASE_WRLCK;
10163         ioc.lil_flags = LL_LEASE_RESYNC;
10164         ioc.lil_mirror_id = mirror_id;
10165         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
10166         if (rc < 0) {
10167                 fprintf(stderr,
10168                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
10169                         progname, argv[0], fname, strerror(errno));
10170                 goto free_buf;
10171         }
10172
10173         pos = 0;
10174         while (1) {
10175                 ssize_t bytes_read;
10176                 ssize_t written;
10177                 size_t to_write;
10178
10179                 rc = llapi_lease_check(fd);
10180                 if (rc != LL_LEASE_WRLCK) {
10181                         fprintf(stderr, "%s %s: '%s' lost lease lock\n",
10182                                 progname, argv[0], fname);
10183                         goto free_buf;
10184                 }
10185
10186                 bytes_read = read(inputfd, buf, buflen);
10187                 if (bytes_read < 0) {
10188                         rc = bytes_read;
10189                         fprintf(stderr,
10190                                 "%s %s: fail to read data from '%s': %s\n",
10191                                 progname, argv[0], inputfile ? : "STDIN",
10192                                 strerror(errno));
10193                         rc = -errno;
10194                         goto free_buf;
10195                 }
10196
10197                 /* EOF reached */
10198                 if (bytes_read == 0)
10199                         break;
10200
10201                 /* round up to page align to make direct IO happy. */
10202                 to_write = (bytes_read + page_size - 1) & ~(page_size - 1);
10203
10204                 written = llapi_mirror_write(fd, mirror_id, buf, to_write,
10205                                              pos);
10206                 if (written < 0) {
10207                         rc = written;
10208                         fprintf(stderr,
10209                               "%s %s: fail to write to mirror %u: %s\n",
10210                                 progname, argv[0], mirror_id,
10211                                 strerror(-rc));
10212                         goto free_buf;
10213                 }
10214
10215                 pos += bytes_read;
10216         }
10217
10218         if (pos & (page_size - 1)) {
10219                 rc = llapi_mirror_truncate(fd, mirror_id, pos);
10220                 if (rc < 0)
10221                         goto free_buf;
10222         }
10223
10224         ioc.lil_mode = LL_LEASE_UNLCK;
10225         ioc.lil_flags = LL_LEASE_RESYNC_DONE;
10226         ioc.lil_count = 0;
10227         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
10228         if (rc <= 0) {
10229                 if (rc == 0)
10230                         rc = -EBUSY;
10231                 fprintf(stderr,
10232                         "%s %s: release lease lock of '%s' failed: %s\n",
10233                         progname, argv[0], fname, strerror(errno));
10234                 goto free_buf;
10235         }
10236
10237         rc = 0;
10238
10239 free_buf:
10240         free(buf);
10241 close_inputfd:
10242         if (inputfile)
10243                 close(inputfd);
10244 close_fd:
10245         close(fd);
10246
10247         return rc;
10248 }
10249
10250 static inline int get_other_mirror_ids(int fd, __u16 *ids, __u16 exclude_id)
10251 {
10252         struct llapi_layout *layout;
10253         struct collect_ids_data cid = { .cid_ids = ids,
10254                                         .cid_count = 0,
10255                                         .cid_exclude = exclude_id, };
10256         int rc;
10257
10258         layout = llapi_layout_get_by_fd(fd, 0);
10259         if (!layout) {
10260                 fprintf(stderr, "could not get layout\n");
10261                 return -EINVAL;
10262         }
10263
10264         rc = llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
10265         if (rc < 0) {
10266                 fprintf(stderr, "failed to iterate layout\n");
10267                 llapi_layout_free(layout);
10268
10269                 return rc;
10270         }
10271         llapi_layout_free(layout);
10272
10273         return cid.cid_count;
10274 }
10275
10276 static inline int lfs_mirror_copy(int argc, char **argv)
10277 {
10278         int rc = CMD_HELP;
10279         __u16 read_mirror_id = 0;
10280         __u16 ids[128] = { 0 };
10281         int count = 0;
10282         struct llapi_layout *layout = NULL;
10283         struct llapi_resync_comp comp_array[1024] = { { 0 } };
10284         int comp_size = 0;
10285         char *fname;
10286         int fd = 0;
10287         int c;
10288         int i;
10289         ssize_t copied;
10290         struct ll_ioc_lease *ioc = NULL;
10291         struct ll_ioc_lease_id *resync_ioc;
10292
10293         struct option long_opts[] = {
10294         { .val = 'i',   .name = "read-mirror",  .has_arg = required_argument },
10295         { .val = 'o',   .name = "write-mirror", .has_arg = required_argument },
10296         { .name = NULL } };
10297
10298         while ((c = getopt_long(argc, argv, "i:o:", long_opts, NULL)) >= 0) {
10299                 char *end;
10300
10301                 switch (c) {
10302                 case 'i':
10303                         read_mirror_id = strtoul(optarg, &end, 0);
10304                         if (*end != '\0' || read_mirror_id == 0) {
10305                                 fprintf(stderr,
10306                                         "%s %s: invalid read mirror ID '%s'\n",
10307                                         progname, argv[0], optarg);
10308                                 return rc;
10309                         }
10310                         break;
10311                 case 'o':
10312                         if (!strcmp(optarg, "-1")) {
10313                                 /* specify all other mirrors */
10314                                 ids[0] = (__u16)-1;
10315                                 count = 1;
10316                         } else {
10317                                 count = parse_mirror_ids((__u16 *)ids,
10318                                                          ARRAY_SIZE(ids),
10319                                                          optarg);
10320                                 if (count < 0)
10321                                         return rc;
10322                         }
10323                         break;
10324                 default:
10325                         fprintf(stderr, "%s: option '%s' unrecognized\n",
10326                                 progname, argv[optind - 1]);
10327                         return -EINVAL;
10328                 }
10329         }
10330
10331         if (argc == optind) {
10332                 fprintf(stderr, "%s %s: no mirrored file provided\n",
10333                         progname, argv[0]);
10334                 return rc;
10335         } else if (argc > optind + 1) {
10336                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
10337                 return rc;
10338         }
10339
10340         if (read_mirror_id == 0) {
10341                 fprintf(stderr,
10342                         "%s %s: no valid read mirror ID %d is provided\n",
10343                         progname, argv[0], read_mirror_id);
10344                 return rc;
10345         }
10346
10347         if (count == 0) {
10348                 fprintf(stderr,
10349                         "%s %s: no write mirror ID is provided\n",
10350                         progname, argv[0]);
10351                 return rc;
10352         }
10353
10354         for (i = 0; i < count; i++) {
10355                 if (read_mirror_id == ids[i]) {
10356                         fprintf(stderr,
10357                         "%s %s: read and write mirror ID cannot be the same\n",
10358                                 progname, argv[0]);
10359                         return rc;
10360                 }
10361         }
10362
10363         /* open mirror file */
10364         fname = argv[optind];
10365
10366         fd = open(fname, O_DIRECT | O_RDWR);
10367         if (fd < 0) {
10368                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
10369                         progname, argv[0], fname, strerror(errno));
10370                 return rc;
10371         }
10372
10373         /* write to all other mirrors */
10374         if (ids[0] == (__u16)-1) {
10375                 count = get_other_mirror_ids(fd, ids, read_mirror_id);
10376                 if (count <= 0) {
10377                         rc = count;
10378                         fprintf(stderr,
10379                         "%s %s: failed to get other mirror ids in '%s': %d\n",
10380                                 progname, argv[0], fname, rc);
10381                         goto close_fd;
10382                 }
10383         }
10384
10385         /* verify mirror id */
10386         rc = verify_mirror_id_by_fd(fd, read_mirror_id);
10387         if (rc) {
10388                 fprintf(stderr,
10389                         "%s %s: cannot find mirror with ID %u in '%s'\n",
10390                         progname, argv[0], read_mirror_id, fname);
10391                 goto close_fd;
10392         }
10393
10394         for (i = 0; i < count; i++) {
10395                 rc = verify_mirror_id_by_fd(fd, ids[i]);
10396                 if (rc) {
10397                         fprintf(stderr,
10398                         "%s %s: cannot find mirror with ID %u in '%s'\n",
10399                                 progname, argv[0], ids[i], fname);
10400                         goto close_fd;
10401                 }
10402         }
10403
10404         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
10405         if (!ioc) {
10406                 fprintf(stderr,
10407                         "%s %s: cannot alloc comp id array for ioc: %s\n",
10408                         progname, argv[0], strerror(errno));
10409                 rc = -errno;
10410                 goto close_fd;
10411         }
10412
10413         /* get stale component info */
10414         layout = llapi_layout_get_by_fd(fd, 0);
10415         if (!layout) {
10416                 fprintf(stderr, "%s %s: failed to get layout of '%s': %s\n",
10417                         progname, argv[0], fname, strerror(errno));
10418                 rc = -errno;
10419                 goto free_ioc;
10420         }
10421         comp_size = llapi_mirror_find_stale(layout, comp_array,
10422                                             ARRAY_SIZE(comp_array),
10423                                             ids, count);
10424         llapi_layout_free(layout);
10425         if (comp_size < 0) {
10426                 rc = comp_size;
10427                 goto free_ioc;
10428         }
10429
10430         /* prepare target mirror components instantiation */
10431         resync_ioc = (struct ll_ioc_lease_id *)ioc;
10432         resync_ioc->lil_mode = LL_LEASE_WRLCK;
10433         resync_ioc->lil_flags = LL_LEASE_RESYNC;
10434         if (count == 1)
10435                 resync_ioc->lil_mirror_id = ids[0];
10436         else
10437                 resync_ioc->lil_mirror_id = read_mirror_id | MIRROR_ID_NEG;
10438         rc = llapi_lease_set(fd, ioc);
10439         if (rc < 0) {
10440                 fprintf(stderr,
10441                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
10442                         progname, argv[0], fname, strerror(errno));
10443                 goto free_ioc;
10444         }
10445
10446         copied = llapi_mirror_copy_many(fd, read_mirror_id, ids, count);
10447         if (copied < 0) {
10448                 rc = copied;
10449                 fprintf(stderr, "%s %s: copy error: %d\n",
10450                         progname, argv[0], rc);
10451                 goto free_ioc;
10452         }
10453
10454         fprintf(stdout, "mirror copied successfully: ");
10455         for (i = 0; i < copied; i++)
10456                 fprintf(stdout, "%d ", ids[i]);
10457         fprintf(stdout, "\n");
10458
10459         ioc->lil_mode = LL_LEASE_UNLCK;
10460         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
10461         ioc->lil_count = 0;
10462         for (i = 0; i < comp_size; i++) {
10463                 int j;
10464
10465                 for (j = 0; j < copied; j++) {
10466                         if (comp_array[i].lrc_mirror_id != ids[j])
10467                                 continue;
10468
10469                         ioc->lil_ids[ioc->lil_count] = comp_array[i].lrc_id;
10470                         ioc->lil_count++;
10471                 }
10472         }
10473         rc = llapi_lease_set(fd, ioc);
10474         if (rc <= 0) {
10475                 if (rc == 0)
10476                         rc = -EBUSY;
10477                 fprintf(stderr,
10478                         "%s %s: release lease lock of '%s' failed: %s\n",
10479                         progname, argv[0], fname, strerror(errno));
10480                 goto free_ioc;
10481         }
10482
10483         rc = 0;
10484
10485 free_ioc:
10486         free(ioc);
10487 close_fd:
10488         close(fd);
10489
10490         return rc;
10491 }
10492
10493 /**
10494  * struct verify_chunk - Mirror chunk to be verified.
10495  * @chunk:        [start, end) of the chunk.
10496  * @mirror_count: Number of mirror ids in @mirror_id array.
10497  * @mirror_id:    Array of valid mirror ids that cover the chunk.
10498  */
10499 struct verify_chunk {
10500         struct lu_extent chunk;
10501         unsigned int mirror_count;
10502         __u16 mirror_id[LUSTRE_MIRROR_COUNT_MAX];
10503 };
10504
10505 /**
10506  * print_chunks() - Print chunk information.
10507  * @fname:       Mirrored file name.
10508  * @chunks:      Array of chunks.
10509  * @chunk_count: Number of chunks in @chunks array.
10510  *
10511  * This function prints [start, end) of each chunk in @chunks
10512  * for mirrored file @fname, and also prints the valid mirror ids
10513  * that cover the chunk.
10514  *
10515  * Return: void.
10516  */
10517 static inline
10518 void print_chunks(const char *fname, struct verify_chunk *chunks,
10519                   int chunk_count)
10520 {
10521         int i;
10522         int j;
10523
10524         fprintf(stdout, "Chunks to be verified in %s:\n", fname);
10525         for (i = 0; i < chunk_count; i++) {
10526                 fprintf(stdout, DEXT, PEXT(&chunks[i].chunk));
10527
10528                 if (chunks[i].mirror_count == 0)
10529                         fprintf(stdout, "\t[");
10530                 else {
10531                         fprintf(stdout, "\t[%u", chunks[i].mirror_id[0]);
10532                         for (j = 1; j < chunks[i].mirror_count; j++)
10533                                 fprintf(stdout, ", %u", chunks[i].mirror_id[j]);
10534                 }
10535                 fprintf(stdout, "]\t%u\n", chunks[i].mirror_count);
10536         }
10537         fprintf(stdout, "\n");
10538 }
10539
10540 /**
10541  * print_checksums() - Print CRC-32 checksum values.
10542  * @chunk: A chunk and its corresponding valid mirror ids.
10543  * @crc:   CRC-32 checksum values on the chunk for each valid mirror.
10544  *
10545  * This function prints CRC-32 checksum values on @chunk for
10546  * each valid mirror that covers it.
10547  *
10548  * Return: void.
10549  */
10550 static inline
10551 void print_checksums(struct verify_chunk *chunk, unsigned long *crc)
10552 {
10553         int i;
10554
10555         fprintf(stdout,
10556                 "CRC-32 checksum value for chunk "DEXT":\n",
10557                 PEXT(&chunk->chunk));
10558         for (i = 0; i < chunk->mirror_count; i++)
10559                 fprintf(stdout, "Mirror %u:\t%#lx\n",
10560                         chunk->mirror_id[i], crc[i]);
10561         fprintf(stdout, "\n");
10562 }
10563
10564 /**
10565  * filter_mirror_id() - Filter specified mirror ids.
10566  * @chunks:      Array of chunks.
10567  * @chunk_count: Number of chunks in @chunks array.
10568  * @mirror_ids:  Specified mirror ids to be verified.
10569  * @ids_nr:      Number of specified mirror ids.
10570  *
10571  * This function scans valid mirror ids that cover each chunk in @chunks
10572  * and filters specified mirror ids.
10573  *
10574  * Return: void.
10575  */
10576 static inline
10577 void filter_mirror_id(struct verify_chunk *chunks, int chunk_count,
10578                       __u16 *mirror_ids, int ids_nr)
10579 {
10580         int i;
10581         int j;
10582         int k;
10583         __u16 valid_id[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
10584         unsigned int valid_count = 0;
10585
10586         for (i = 0; i < chunk_count; i++) {
10587                 if (chunks[i].mirror_count == 0)
10588                         continue;
10589
10590                 valid_count = 0;
10591                 for (j = 0; j < ids_nr; j++) {
10592                         for (k = 0; k < chunks[i].mirror_count; k++) {
10593                                 if (chunks[i].mirror_id[k] == mirror_ids[j]) {
10594                                         valid_id[valid_count] = mirror_ids[j];
10595                                         valid_count++;
10596                                         break;
10597                                 }
10598                         }
10599                 }
10600
10601                 memcpy(chunks[i].mirror_id, valid_id,
10602                        sizeof(__u16) * valid_count);
10603                 chunks[i].mirror_count = valid_count;
10604         }
10605 }
10606
10607 /**
10608  * lfs_mirror_prepare_chunk() - Find mirror chunks to be verified.
10609  * @layout:      Mirror component list.
10610  * @chunks:      Array of chunks.
10611  * @chunks_size: Array size of @chunks.
10612  *
10613  * This function scans the components in @layout from offset 0 to LUSTRE_EOF
10614  * to find out chunk segments and store them in @chunks array.
10615  *
10616  * The @mirror_id array in each element of @chunks will store the valid
10617  * mirror ids that cover the chunk. If a mirror component covering the
10618  * chunk has LCME_FL_STALE or LCME_FL_OFFLINE flag, then the mirror id
10619  * will not be stored into the @mirror_id array, and the chunk for that
10620  * mirror will not be verified.
10621  *
10622  * The @mirror_count in each element of @chunks will store the number of
10623  * mirror ids in @mirror_id array. If @mirror_count is 0, it indicates the
10624  * chunk is invalid in all of the mirrors. And if @mirror_count is 1, it
10625  * indicates the chunk is valid in only one mirror. In both cases, the
10626  * chunk will not be verified.
10627  *
10628  * Here is an example:
10629  *
10630  *  0      1M     2M     3M     4M           EOF
10631  *  +------+-------------+--------------------+
10632  *  |      |             |      S             |       mirror1
10633  *  +------+------+------+------+-------------+
10634  *  |             |   S  |   S  |             |       mirror2
10635  *  +-------------+------+------+-------------+
10636  *
10637  * prepared @chunks array will contain 5 elements:
10638  * (([0, 1M), [1, 2], 2),
10639  *  ([1M, 2M), [1, 2], 2),
10640  *  ([2M, 3M), [1], 1),
10641  *  ([3M, 4M], [], 0),
10642  *  ([4M, EOF), [2], 1))
10643  *
10644  * Return: the actual array size of @chunks on success
10645  *         or a negative error code on failure.
10646  */
10647 static inline
10648 int lfs_mirror_prepare_chunk(struct llapi_layout *layout,
10649                              struct verify_chunk *chunks,
10650                              size_t chunks_size)
10651 {
10652         uint64_t start;
10653         uint64_t end;
10654         uint32_t mirror_id;
10655         uint32_t flags;
10656         int idx = 0;
10657         int i = 0;
10658         int rc = 0;
10659
10660         memset(chunks, 0, sizeof(*chunks) * chunks_size);
10661
10662         while (1) {
10663                 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
10664                 if (rc < 0) {
10665                         fprintf(stderr,
10666                                 "%s: move to the first layout component: %s.\n",
10667                                 progname, strerror(errno));
10668                         goto error;
10669                 }
10670
10671                 i = 0;
10672                 rc = 0;
10673                 chunks[idx].chunk.e_end = LUSTRE_EOF;
10674                 while (rc == 0) {
10675                         rc = llapi_layout_comp_extent_get(layout, &start, &end);
10676                         if (rc < 0) {
10677                                 fprintf(stderr,
10678                                         "%s: llapi_layout_comp_extent_get failed: %s.\n",
10679                                         progname, strerror(errno));
10680                                 goto error;
10681                         }
10682
10683                         if (start > chunks[idx].chunk.e_start ||
10684                             end <= chunks[idx].chunk.e_start)
10685                                 goto next;
10686
10687                         if (end < chunks[idx].chunk.e_end)
10688                                 chunks[idx].chunk.e_end = end;
10689
10690                         rc = llapi_layout_comp_flags_get(layout, &flags);
10691                         if (rc < 0) {
10692                                 fprintf(stderr,
10693                                         "%s: llapi_layout_comp_flags_get failed: %s.\n",
10694                                         progname, strerror(errno));
10695                                 goto error;
10696                         }
10697
10698                         if (flags & LCME_FL_STALE || flags & LCME_FL_OFFLINE)
10699                                 goto next;
10700
10701                         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
10702                         if (rc < 0) {
10703                                 fprintf(stderr,
10704                                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
10705                                         progname, strerror(errno));
10706                                 goto error;
10707                         }
10708
10709                         chunks[idx].mirror_id[i] = mirror_id;
10710                         i++;
10711                         if (i >= ARRAY_SIZE(chunks[idx].mirror_id)) {
10712                                 fprintf(stderr,
10713                                         "%s: mirror_id array is too small.\n",
10714                                         progname);
10715                                 rc = -EINVAL;
10716                                 goto error;
10717                         }
10718
10719 next:
10720                         rc = llapi_layout_comp_use(layout,
10721                                                    LLAPI_LAYOUT_COMP_USE_NEXT);
10722                         if (rc < 0) {
10723                                 fprintf(stderr,
10724                                         "%s: move to the next layout component: %s.\n",
10725                                         progname, strerror(errno));
10726                                 goto error;
10727                         }
10728                 } /* loop through all components */
10729
10730                 chunks[idx].mirror_count = i;
10731
10732                 if (chunks[idx].chunk.e_end == LUSTRE_EOF)
10733                         break;
10734
10735                 idx++;
10736                 if (idx >= chunks_size) {
10737                         fprintf(stderr, "%s: chunks array is too small.\n",
10738                                 progname);
10739                         rc = -EINVAL;
10740                         goto error;
10741                 }
10742
10743                 chunks[idx].chunk.e_start = chunks[idx - 1].chunk.e_end;
10744         }
10745
10746 error:
10747         return rc < 0 ? rc : idx + 1;
10748 }
10749
10750 /**
10751  * lfs_mirror_verify_chunk() - Verify a chunk.
10752  * @fd:        File descriptor of the mirrored file.
10753  * @file_size: Size of the mirrored file.
10754  * @chunk:     A chunk and its corresponding valid mirror ids.
10755  * @verbose:   Verbose mode.
10756  *
10757  * This function verifies a @chunk contains exactly the same data
10758  * ammong the mirrors that cover it.
10759  *
10760  * If @verbose is specified, then the function will print where the
10761  * differences are if the data do not match. Otherwise, it will
10762  * just return an error in that case.
10763  *
10764  * Return: 0 on success or a negative error code on failure.
10765  */
10766 static inline
10767 int lfs_mirror_verify_chunk(int fd, size_t file_size,
10768                             struct verify_chunk *chunk, int verbose)
10769 {
10770         const size_t buflen = 4 * 1024 * 1024; /* 4M */
10771         void *buf;
10772         size_t page_size = sysconf(_SC_PAGESIZE);
10773         ssize_t bytes_read;
10774         ssize_t bytes_done;
10775         size_t count;
10776         off_t pos;
10777         unsigned long crc;
10778         unsigned long crc_array[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
10779         int i;
10780         int rc = 0;
10781
10782         if (file_size == 0)
10783                 return 0;
10784
10785         rc = posix_memalign(&buf, page_size, buflen);
10786         if (rc) /* error code is returned directly */
10787                 return -rc;
10788
10789         if (verbose > 1) {
10790                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
10791                         PEXT(&chunk->chunk));
10792                 for (i = 0; i < chunk->mirror_count; i++)
10793                         fprintf(stdout, " %u", chunk->mirror_id[i]);
10794                 fprintf(stdout, "\n");
10795         }
10796
10797         bytes_done = 0;
10798         count = MIN(chunk->chunk.e_end, file_size) - chunk->chunk.e_start;
10799         pos = chunk->chunk.e_start;
10800         while (bytes_done < count) {
10801                 /* compute initial CRC-32 checksum */
10802                 crc = crc32(0L, Z_NULL, 0);
10803                 memset(crc_array, 0, sizeof(crc_array));
10804
10805                 bytes_read = 0;
10806                 for (i = 0; i < chunk->mirror_count; i++) {
10807                         bytes_read = llapi_mirror_read(fd, chunk->mirror_id[i],
10808                                                        buf, buflen, pos);
10809                         if (bytes_read < 0) {
10810                                 rc = bytes_read;
10811                                 fprintf(stderr,
10812                                         "%s: failed to read data from mirror %u: %s.\n",
10813                                         progname, chunk->mirror_id[i],
10814                                         strerror(-rc));
10815                                 goto error;
10816                         }
10817
10818                         /* compute new CRC-32 checksum */
10819                         crc_array[i] = crc32(crc, buf, bytes_read);
10820                 }
10821
10822                 if (verbose)
10823                         print_checksums(chunk, crc_array);
10824
10825                 /* compare CRC-32 checksum values */
10826                 for (i = 1; i < chunk->mirror_count; i++) {
10827                         if (crc_array[i] != crc_array[0]) {
10828                                 rc = -EINVAL;
10829
10830                                 fprintf(stderr,
10831                                         "%s: chunk "DEXT" has different checksum value on mirror %u and mirror %u.\n",
10832                                         progname, PEXT(&chunk->chunk),
10833                                         chunk->mirror_id[0],
10834                                         chunk->mirror_id[i]);
10835                         }
10836                 }
10837
10838                 pos += bytes_read;
10839                 bytes_done += bytes_read;
10840         }
10841
10842         if (verbose > 1 && rc == 0) {
10843                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
10844                         PEXT(&chunk->chunk));
10845                 for (i = 0; i < chunk->mirror_count; i++)
10846                         fprintf(stdout, " %u", chunk->mirror_id[i]);
10847                 fprintf(stdout, " PASS\n\n");
10848         }
10849
10850 error:
10851         free(buf);
10852         return rc;
10853 }
10854
10855 /**
10856  * lfs_mirror_verify_file() - Verify a mirrored file.
10857  * @fname:      Mirrored file name.
10858  * @mirror_ids: Specified mirror ids to be verified.
10859  * @ids_nr:     Number of specified mirror ids.
10860  * @verbose:    Verbose mode.
10861  *
10862  * This function verifies that each SYNC mirror of a mirrored file
10863  * specified by @fname contains exactly the same data.
10864  *
10865  * If @mirror_ids is specified, then the function will verify the
10866  * mirrors specified by @mirror_ids contain exactly the same data.
10867  *
10868  * If @verbose is specified, then the function will print where the
10869  * differences are if the data do not match. Otherwise, it will
10870  * just return an error in that case.
10871  *
10872  * Return: 0 on success or a negative error code on failure.
10873  */
10874 static inline
10875 int lfs_mirror_verify_file(const char *fname, __u16 *mirror_ids, int ids_nr,
10876                            int verbose)
10877 {
10878         struct verify_chunk chunks_array[1024] = { };
10879         struct llapi_layout *layout = NULL;
10880         struct stat stbuf;
10881         uint32_t flr_state;
10882         int fd;
10883         int chunk_count = 0;
10884         int idx = 0;
10885         int rc = 0;
10886         int rc1 = 0;
10887         int rc2 = 0;
10888
10889         if (stat(fname, &stbuf) < 0) {
10890                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
10891                         progname, fname, strerror(errno));
10892                 rc = -errno;
10893                 goto error;
10894         }
10895
10896         if (!S_ISREG(stbuf.st_mode)) {
10897                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
10898                         progname, fname);
10899                 rc = -EINVAL;
10900                 goto error;
10901         }
10902
10903         if (stbuf.st_size == 0) {
10904                 if (verbose)
10905                         fprintf(stdout, "%s: '%s' file size is 0.\n",
10906                                 progname, fname);
10907                 rc = 0;
10908                 goto error;
10909         }
10910
10911         fd = open(fname, O_DIRECT | O_RDONLY);
10912         if (fd < 0) {
10913                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
10914                         progname, fname, strerror(errno));
10915                 rc = -errno;
10916                 goto error;
10917         }
10918
10919         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
10920         if (rc < 0) {
10921                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
10922                         progname, fname, strerror(errno));
10923                 goto close_fd;
10924         }
10925
10926         layout = llapi_layout_get_by_fd(fd, 0);
10927         if (!layout) {
10928                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
10929                         progname, fname, strerror(errno));
10930                 rc = -errno;
10931                 llapi_lease_release(fd);
10932                 goto close_fd;
10933         }
10934
10935         rc = llapi_layout_flags_get(layout, &flr_state);
10936         if (rc < 0) {
10937                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
10938                         progname, fname, strerror(errno));
10939                 rc = -errno;
10940                 goto free_layout;
10941         }
10942
10943         flr_state &= LCM_FL_FLR_MASK;
10944         switch (flr_state) {
10945         case LCM_FL_NONE:
10946                 rc = -EINVAL;
10947                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
10948                         progname, fname, llapi_layout_flags_string(flr_state));
10949                 goto free_layout;
10950         default:
10951                 break;
10952         }
10953
10954         /* find out mirror chunks to be verified */
10955         chunk_count = lfs_mirror_prepare_chunk(layout, chunks_array,
10956                                                ARRAY_SIZE(chunks_array));
10957         if (chunk_count < 0) {
10958                 rc = chunk_count;
10959                 goto free_layout;
10960         }
10961
10962         if (ids_nr > 0)
10963                 /* filter specified mirror ids */
10964                 filter_mirror_id(chunks_array, chunk_count, mirror_ids, ids_nr);
10965
10966         if (verbose > 2)
10967                 print_chunks(fname, chunks_array, chunk_count);
10968
10969         for (idx = 0; idx < chunk_count; idx++) {
10970                 if (chunks_array[idx].chunk.e_start >= stbuf.st_size) {
10971                         if (verbose)
10972                                 fprintf(stdout,
10973                                         "%s: '%s' chunk "DEXT" exceeds file size %#llx: skipped\n",
10974                                         progname, fname,
10975                                         PEXT(&chunks_array[idx].chunk),
10976                                         (unsigned long long)stbuf.st_size);
10977                         break;
10978                 }
10979
10980                 if (chunks_array[idx].mirror_count == 0) {
10981                         fprintf(stderr,
10982                                 "%s: '%s' chunk "DEXT" is invalid in all of the mirrors: ",
10983                                 progname, fname,
10984                                 PEXT(&chunks_array[idx].chunk));
10985                         if (verbose) {
10986                                 fprintf(stderr, "skipped\n");
10987                                 continue;
10988                         }
10989                         rc = -EINVAL;
10990                         fprintf(stderr, "failed\n");
10991                         goto free_layout;
10992                 }
10993
10994                 if (chunks_array[idx].mirror_count == 1) {
10995                         if (verbose)
10996                                 fprintf(stdout,
10997                                         "%s: '%s' chunk "DEXT" is only valid in mirror %u: skipped\n",
10998                                         progname, fname,
10999                                         PEXT(&chunks_array[idx].chunk),
11000                                         chunks_array[idx].mirror_id[0]);
11001                         continue;
11002                 }
11003
11004                 rc = llapi_lease_check(fd);
11005                 if (rc != LL_LEASE_RDLCK) {
11006                         fprintf(stderr, "%s: '%s' lost lease lock.\n",
11007                                 progname, fname);
11008                         goto free_layout;
11009                 }
11010
11011                 /* verify one chunk */
11012                 rc1 = lfs_mirror_verify_chunk(fd, stbuf.st_size,
11013                                               &chunks_array[idx], verbose);
11014                 if (rc1 < 0) {
11015                         rc2 = rc1;
11016                         if (!verbose) {
11017                                 rc = rc1;
11018                                 goto free_layout;
11019                         }
11020                 }
11021         }
11022
11023         if (rc2 < 0)
11024                 rc = rc2;
11025
11026 free_layout:
11027         llapi_layout_free(layout);
11028         llapi_lease_release(fd);
11029 close_fd:
11030         close(fd);
11031 error:
11032         return rc;
11033 }
11034
11035 /**
11036  * lfs_mirror_verify() - Parse and execute lfs mirror verify command.
11037  * @argc: The count of lfs mirror verify command line arguments.
11038  * @argv: Array of strings for lfs mirror verify command line arguments.
11039  *
11040  * This function parses lfs mirror verify command and verifies the
11041  * specified mirrored file(s).
11042  *
11043  * Return: 0 on success or a negative error code on failure.
11044  */
11045 static inline int lfs_mirror_verify(int argc, char **argv)
11046 {
11047         __u16 mirror_ids[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
11048         int ids_nr = 0;
11049         int c;
11050         int verbose = 0;
11051         int rc = 0;
11052         int rc1 = 0;
11053         char cmd[PATH_MAX];
11054
11055         struct option long_opts[] = {
11056         { .val = 'o',   .name = "only",         .has_arg = required_argument },
11057         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
11058         { .name = NULL } };
11059
11060         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
11061         progname = cmd;
11062         while ((c = getopt_long(argc, argv, "o:v", long_opts, NULL)) >= 0) {
11063                 switch (c) {
11064                 case 'o':
11065                         rc = parse_mirror_ids(mirror_ids,
11066                                               ARRAY_SIZE(mirror_ids),
11067                                               optarg);
11068                         if (rc < 0) {
11069                                 fprintf(stderr,
11070                                         "%s: bad mirror ids '%s'.\n",
11071                                         progname, optarg);
11072                                 goto error;
11073                         }
11074                         ids_nr = rc;
11075                         if (ids_nr < 2) {
11076                                 fprintf(stderr,
11077                                         "%s: at least 2 mirror ids needed with '--only' option.\n",
11078                                         progname);
11079                                 rc = CMD_HELP;
11080                                 goto error;
11081                         }
11082                         break;
11083                 case 'v':
11084                         verbose++;
11085                         break;
11086                 default:
11087                         fprintf(stderr, "%s: option '%s' unrecognized.\n",
11088                                 progname, argv[optind - 1]);
11089                         rc = -EINVAL;
11090                         goto error;
11091                 }
11092         }
11093
11094         if (argc == optind) {
11095                 fprintf(stderr, "%s: no file name given.\n", progname);
11096                 rc = CMD_HELP;
11097                 goto error;
11098         }
11099
11100         if (ids_nr > 0 && argc > optind + 1) {
11101                 fprintf(stderr,
11102                         "%s: '--only' cannot be used upon multiple files.\n",
11103                         progname);
11104                 rc = CMD_HELP;
11105                 goto error;
11106         }
11107
11108         if (ids_nr > 0) {
11109                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
11110                 if (rc < 0)
11111                         goto error;
11112         }
11113
11114         rc = 0;
11115         for (; optind < argc; optind++) {
11116                 rc1 = lfs_mirror_verify_file(argv[optind], mirror_ids, ids_nr,
11117                                              verbose);
11118                 if (rc1 < 0)
11119                         rc = rc1;
11120         }
11121 error:
11122         return rc;
11123 }
11124
11125 /**
11126  * lfs_mirror() - Parse and execute lfs mirror commands.
11127  * @argc: The count of lfs mirror command line arguments.
11128  * @argv: Array of strings for lfs mirror command line arguments.
11129  *
11130  * This function parses lfs mirror commands and performs the
11131  * corresponding functions specified in mirror_cmdlist[].
11132  *
11133  * Return: 0 on success or an error code on failure.
11134  */
11135 static int lfs_mirror(int argc, char **argv)
11136 {
11137         char cmd[PATH_MAX];
11138         int rc = 0;
11139
11140         setlinebuf(stdout);
11141
11142         Parser_init("lfs-mirror > ", mirror_cmdlist);
11143
11144         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
11145         progname = cmd;
11146         program_invocation_short_name = cmd;
11147         if (argc > 1)
11148                 rc = Parser_execarg(argc - 1, argv + 1, mirror_cmdlist);
11149         else
11150                 rc = Parser_commands();
11151
11152         return rc < 0 ? -rc : rc;
11153 }
11154
11155 static void lustre_som_swab(struct lustre_som_attrs *attrs)
11156 {
11157 #if __BYTE_ORDER == __BIG_ENDIAN
11158         __swab16s(&attrs->lsa_valid);
11159         __swab64s(&attrs->lsa_size);
11160         __swab64s(&attrs->lsa_blocks);
11161 #endif
11162 }
11163
11164 enum lfs_som_type {
11165         LFS_SOM_SIZE = 0x1,
11166         LFS_SOM_BLOCKS = 0x2,
11167         LFS_SOM_FLAGS = 0x4,
11168         LFS_SOM_ATTR_ALL = LFS_SOM_SIZE | LFS_SOM_BLOCKS |
11169                            LFS_SOM_FLAGS,
11170 };
11171
11172 static int lfs_getsom(int argc, char **argv)
11173 {
11174         const char *path;
11175         struct lustre_som_attrs *attrs;
11176         char buf[sizeof(*attrs) + 64];
11177         enum lfs_som_type type = LFS_SOM_ATTR_ALL;
11178         int rc = 0, c;
11179
11180         while ((c = getopt(argc, argv, "sbf")) != -1) {
11181                 switch (c) {
11182                 case 's':
11183                         type = LFS_SOM_SIZE;
11184                         break;
11185                 case 'b':
11186                         type = LFS_SOM_BLOCKS;
11187                         break;
11188                 case 'f':
11189                         type = LFS_SOM_FLAGS;
11190                         break;
11191                 default:
11192                         fprintf(stderr, "%s: invalid option '%c'\n",
11193                                 progname, optopt);
11194                         return CMD_HELP;
11195                 }
11196         }
11197
11198         argc -= optind;
11199         argv += optind;
11200
11201         if (argc != 1) {
11202                 fprintf(stderr, "%s: %s\n",
11203                         progname, argc == 0 ? "miss file target" :
11204                         "input more than 2 files");
11205                 return CMD_HELP;
11206         }
11207
11208         path = argv[0];
11209         attrs = (void *)buf;
11210         rc = lgetxattr(path, "trusted.som", attrs, sizeof(buf));
11211         if (rc < 0) {
11212                 rc = -errno;
11213                 fprintf(stderr, "%s failed to get som xattr: %s (%d)\n",
11214                         argv[0], strerror(errno), errno);
11215                 return rc;
11216         }
11217
11218         lustre_som_swab(attrs);
11219
11220         switch (type) {
11221         case LFS_SOM_ATTR_ALL:
11222                 printf("file: %s size: %llu blocks: %llu flags: %x\n",
11223                        path, (unsigned long long)attrs->lsa_size,
11224                        (unsigned long long)attrs->lsa_blocks,
11225                        attrs->lsa_valid);
11226                 break;
11227         case LFS_SOM_SIZE:
11228                 printf("%llu\n", (unsigned long long)attrs->lsa_size);
11229                 break;
11230         case LFS_SOM_BLOCKS:
11231                 printf("%llu\n", (unsigned long long)attrs->lsa_blocks);
11232                 break;
11233         case LFS_SOM_FLAGS:
11234                 printf("%x\n", attrs->lsa_valid);
11235                 break;
11236         default:
11237                 fprintf(stderr, "%s: unknown option\n", progname);
11238                 return CMD_HELP;
11239         }
11240
11241         return 0;
11242 }
11243
11244 /**
11245  * lfs_mirror_list_commands() - List lfs mirror commands.
11246  * @argc: The count of command line arguments.
11247  * @argv: Array of strings for command line arguments.
11248  *
11249  * This function lists lfs mirror commands defined in mirror_cmdlist[].
11250  *
11251  * Return: 0 on success.
11252  */
11253 static int lfs_mirror_list_commands(int argc, char **argv)
11254 {
11255         char buffer[81] = "";
11256
11257         Parser_list_commands(mirror_cmdlist, buffer, sizeof(buffer),
11258                              NULL, 0, 4);
11259
11260         return 0;
11261 }
11262
11263 static int lfs_pcc_attach(int argc, char **argv)
11264 {
11265         struct option long_opts[] = {
11266         { .val = 'i',   .name = "id",   .has_arg = required_argument },
11267         { .name = NULL } };
11268         int c;
11269         int rc = 0;
11270         __u32 archive_id = 0;
11271         const char *path;
11272         char *end;
11273         char fullpath[PATH_MAX];
11274         enum lu_pcc_type type = LU_PCC_READWRITE;
11275
11276         optind = 0;
11277         while ((c = getopt_long(argc, argv, "i:",
11278                                 long_opts, NULL)) != -1) {
11279                 switch (c) {
11280                 case 'i':
11281                         archive_id = strtoul(optarg, &end, 0);
11282                         if (*end != '\0' || archive_id == 0) {
11283                                 fprintf(stderr,
11284                                         "error: %s: bad archive ID '%s'\n",
11285                                         argv[0], optarg);
11286                                 return CMD_HELP;
11287                         }
11288                         break;
11289                 case '?':
11290                         return CMD_HELP;
11291                 default:
11292                         fprintf(stderr, "%s: option '%s' unrecognized\n",
11293                                 argv[0], argv[optind - 1]);
11294                         return CMD_HELP;
11295                 }
11296         }
11297
11298         if (archive_id == 0) {
11299                 fprintf(stderr, "%s: must specify attach ID\n", argv[0]);
11300                 return CMD_HELP;
11301         }
11302
11303         if (argc <= optind) {
11304                 fprintf(stderr, "%s: must specify one or more file names\n",
11305                         argv[0]);
11306                 return CMD_HELP;
11307         }
11308
11309         while (optind < argc) {
11310                 int rc2;
11311
11312                 path = argv[optind++];
11313                 if (!realpath(path, fullpath)) {
11314                         fprintf(stderr, "%s: could not find path '%s': %s\n",
11315                                 argv[0], path, strerror(errno));
11316                         if (rc == 0)
11317                                 rc = -EINVAL;
11318                         continue;
11319                 }
11320
11321                 rc2 = llapi_pcc_attach(fullpath, archive_id, type);
11322                 if (rc2 < 0) {
11323                         fprintf(stderr,
11324                                 "%s: cannot attach '%s' to PCC with archive ID '%u': %s\n",
11325                                 argv[0], path, archive_id, strerror(-rc2));
11326                         if (rc == 0)
11327                                 rc = rc2;
11328                 }
11329         }
11330         return rc;
11331 }
11332
11333 static int lfs_pcc_attach_fid(int argc, char **argv)
11334 {
11335         struct option long_opts[] = {
11336         { .val = 'i',   .name = "id",   .has_arg = required_argument },
11337         { .val = 'm',   .name = "mnt",  .has_arg = required_argument },
11338         { .name = NULL } };
11339         char                     short_opts[] = "i:m:";
11340         int                      c;
11341         int                      rc = 0;
11342         __u32                    archive_id = 0;
11343         char                    *end;
11344         const char              *mntpath = NULL;
11345         const char              *fidstr;
11346         enum lu_pcc_type         type = LU_PCC_READWRITE;
11347
11348         optind = 0;
11349         while ((c = getopt_long(argc, argv, short_opts,
11350                                 long_opts, NULL)) != -1) {
11351                 switch (c) {
11352                 case 'i':
11353                         archive_id = strtoul(optarg, &end, 0);
11354                         if (*end != '\0') {
11355                                 fprintf(stderr,
11356                                         "error: %s: bad archive ID '%s'\n",
11357                                         argv[0], optarg);
11358                                 return CMD_HELP;
11359                         }
11360                         break;
11361                 case 'm':
11362                         mntpath = optarg;
11363                         break;
11364                 case '?':
11365                         return CMD_HELP;
11366                 default:
11367                         fprintf(stderr, "%s: option '%s' unrecognized\n",
11368                                 argv[0], argv[optind - 1]);
11369                         return CMD_HELP;
11370                 }
11371         }
11372
11373         if (archive_id == 0) {
11374                 fprintf(stderr, "%s: must specify an archive ID\n", argv[0]);
11375                 return CMD_HELP;
11376         }
11377
11378         if (!mntpath) {
11379                 fprintf(stderr, "%s: must specify Lustre mount point\n",
11380                         argv[0]);
11381                 return CMD_HELP;
11382         }
11383
11384         if (argc <= optind) {
11385                 fprintf(stderr, "%s: must specify one or more fids\n", argv[0]);
11386                 return CMD_HELP;
11387         }
11388
11389         while (optind < argc) {
11390                 int rc2;
11391
11392                 fidstr = argv[optind++];
11393
11394                 rc2 = llapi_pcc_attach_fid_str(mntpath, fidstr,
11395                                                archive_id, type);
11396                 if (rc2 < 0) {
11397                         fprintf(stderr,
11398                                 "%s: cannot attach '%s' on '%s' to PCC with archive ID '%u': %s\n",
11399                                 argv[0], fidstr, mntpath, archive_id,
11400                                 strerror(rc2));
11401                 }
11402                 if (rc == 0 && rc2 < 0)
11403                         rc = rc2;
11404         }
11405         return rc;
11406 }
11407
11408 static int lfs_pcc_detach(int argc, char **argv)
11409 {
11410         struct option long_opts[] = {
11411         { .val = 'k',   .name = "keep", .has_arg = no_argument },
11412         { .name = NULL } };
11413         char                     short_opts[] = "k";
11414         int                      c;
11415         int                      rc = 0;
11416         const char              *path;
11417         char                     fullpath[PATH_MAX];
11418         __u32                    detach_opt = PCC_DETACH_OPT_UNCACHE;
11419
11420         optind = 0;
11421         while ((c = getopt_long(argc, argv, short_opts,
11422                                 long_opts, NULL)) != -1) {
11423                 switch (c) {
11424                 case 'k':
11425                         detach_opt = PCC_DETACH_OPT_NONE;
11426                         break;
11427                 case '?':
11428                         return CMD_HELP;
11429                 default:
11430                         fprintf(stderr, "%s: option '%s' unrecognized\n",
11431                                 argv[0], argv[optind - 1]);
11432                         return CMD_HELP;
11433                 }
11434         }
11435
11436         while (optind < argc) {
11437                 int rc2;
11438
11439                 path = argv[optind++];
11440                 if (!realpath(path, fullpath)) {
11441                         fprintf(stderr, "%s: could not find path '%s': %s\n",
11442                                 argv[0], path, strerror(errno));
11443                         if (rc == 0)
11444                                 rc = -EINVAL;
11445                         continue;
11446                 }
11447
11448                 rc2 = llapi_pcc_detach_file(fullpath, detach_opt);
11449                 if (rc2 < 0) {
11450                         rc2 = -errno;
11451                         fprintf(stderr,
11452                                 "%s: cannot detach '%s' from PCC: %s\n",
11453                                 argv[0], path, strerror(errno));
11454                         if (rc == 0)
11455                                 rc = rc2;
11456                 }
11457         }
11458         return rc;
11459 }
11460
11461 static int lfs_pcc_detach_fid(int argc, char **argv)
11462 {
11463         struct option long_opts[] = {
11464         { .val = 'k',   .name = "keep", .has_arg = no_argument },
11465         { .name = NULL } };
11466         char             short_opts[] = "k";
11467         int              c;
11468         int              rc = 0;
11469         const char      *fid;
11470         const char      *mntpath;
11471         __u32            detach_opt = PCC_DETACH_OPT_UNCACHE;
11472
11473         optind = 0;
11474         while ((c = getopt_long(argc, argv, short_opts,
11475                                 long_opts, NULL)) != -1) {
11476                 switch (c) {
11477                 case 'k':
11478                         detach_opt = PCC_DETACH_OPT_NONE;
11479                         break;
11480                 case '?':
11481                         return CMD_HELP;
11482                 default:
11483                         fprintf(stderr, "%s: option '%s' unrecognized\n",
11484                                 argv[0], argv[optind - 1]);
11485                         return CMD_HELP;
11486                 }
11487         }
11488
11489         mntpath = argv[optind++];
11490
11491         while (optind < argc) {
11492                 int rc2;
11493
11494                 fid = argv[optind++];
11495
11496                 rc2 = llapi_pcc_detach_fid_str(mntpath, fid, detach_opt);
11497                 if (rc2 < 0) {
11498                         fprintf(stderr,
11499                                 "%s: cannot detach '%s' on '%s' from PCC: %s\n",
11500                                 argv[0], fid, mntpath, strerror(-rc2));
11501                         if (rc == 0)
11502                                 rc = rc2;
11503                 }
11504         }
11505         return rc;
11506 }
11507
11508 static int lfs_pcc_state(int argc, char **argv)
11509 {
11510         int                      rc = 0;
11511         const char              *path;
11512         char                     fullpath[PATH_MAX];
11513         struct lu_pcc_state      state;
11514
11515         optind = 1;
11516
11517         if (argc <= 1) {
11518                 fprintf(stderr, "%s: must specify one or more file names\n",
11519                         argv[0]);
11520                 return CMD_HELP;
11521         }
11522
11523         while (optind < argc) {
11524                 int rc2;
11525
11526                 path = argv[optind++];
11527                 if (!realpath(path, fullpath)) {
11528                         fprintf(stderr, "%s: could not find path '%s': %s\n",
11529                                 argv[0], path, strerror(errno));
11530                         if (rc == 0)
11531                                 rc = -EINVAL;
11532                         continue;
11533                 }
11534
11535                 rc2 = llapi_pcc_state_get(fullpath, &state);
11536                 if (rc2 < 0) {
11537                         if (rc == 0)
11538                                 rc = rc2;
11539                         fprintf(stderr,
11540                                 "%s: cannot get PCC state of '%s': %s\n",
11541                                 argv[0], path, strerror(-rc2));
11542                         continue;
11543                 }
11544
11545                 printf("file: %s", path);
11546                 printf(", type: %s", pcc_type2string(state.pccs_type));
11547                 if (state.pccs_type == LU_PCC_NONE &&
11548                     state.pccs_open_count == 0) {
11549                         printf("\n");
11550                         continue;
11551                 }
11552
11553                 printf(", PCC file: %s", state.pccs_path);
11554                 printf(", user number: %u", state.pccs_open_count);
11555                 printf(", flags: %x", state.pccs_flags);
11556                 printf("\n");
11557         }
11558         return rc;
11559 }
11560
11561 /**
11562  * lfs_pcc_list_commands() - List lfs pcc commands.
11563  * @argc: The count of command line arguments.
11564  * @argv: Array of strings for command line arguments.
11565  *
11566  * This function lists lfs pcc commands defined in pcc_cmdlist[].
11567  *
11568  * Return: 0 on success.
11569  */
11570 static int lfs_pcc_list_commands(int argc, char **argv)
11571 {
11572         char buffer[81] = "";
11573
11574         Parser_list_commands(pcc_cmdlist, buffer, sizeof(buffer),
11575                              NULL, 0, 4);
11576
11577         return 0;
11578 }
11579
11580 /**
11581  * lfs_pcc() - Parse and execute lfs pcc commands.
11582  * @argc: The count of lfs pcc command line arguments.
11583  * @argv: Array of strings for lfs pcc command line arguments.
11584  *
11585  * This function parses lfs pcc commands and performs the
11586  * corresponding functions specified in pcc_cmdlist[].
11587  *
11588  * Return: 0 on success or an error code on failure.
11589  */
11590 static int lfs_pcc(int argc, char **argv)
11591 {
11592         char cmd[PATH_MAX];
11593         int rc = 0;
11594
11595         setlinebuf(stdout);
11596
11597         Parser_init("lfs-pcc > ", pcc_cmdlist);
11598
11599         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
11600         progname = cmd;
11601         program_invocation_short_name = cmd;
11602         if (argc > 1)
11603                 rc = Parser_execarg(argc - 1, argv + 1, pcc_cmdlist);
11604         else
11605                 rc = Parser_commands();
11606
11607         return rc < 0 ? -rc : rc;
11608 }
11609
11610 static int lfs_list_commands(int argc, char **argv)
11611 {
11612         char buffer[81] = ""; /* 80 printable chars + terminating NUL */
11613
11614         Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
11615
11616         return 0;
11617 }
11618
11619 int main(int argc, char **argv)
11620 {
11621         int rc;
11622
11623         /* Ensure that liblustreapi constructor has run */
11624         if (!llapi_liblustreapi_initialized())
11625                 fprintf(stderr, "liblustreapi was not properly initialized\n");
11626
11627         setlinebuf(stdout);
11628         opterr = 0;
11629
11630         Parser_init("lfs > ", cmdlist);
11631
11632         progname = program_invocation_short_name; /* Used in error messages */
11633         if (argc > 1) {
11634                 llapi_set_command_name(argv[1]);
11635                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
11636                 llapi_clear_command_name();
11637         } else {
11638                 rc = Parser_commands();
11639         }
11640
11641         return rc < 0 ? -rc : rc;
11642 }
11643
11644 #ifdef _LUSTRE_IDL_H_
11645 /* Everything we need here should be included by lustreapi.h. */
11646 # error "lfs should not depend on lustre_idl.h"
11647 #endif /* _LUSTRE_IDL_H_ */