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