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