Whamcloud - gitweb
Revert "LU-15969 llite: add support for ->fileattr_get/set"
[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 #ifndef NSEC_PER_SEC
82 # define NSEC_PER_SEC 1000000000UL
83 #endif
84 #define ONE_MB 0x100000
85
86 /* all functions */
87 static int lfs_find(int argc, char **argv);
88 static int lfs_getstripe(int argc, char **argv);
89 static int lfs_getdirstripe(int argc, char **argv);
90 static int lfs_setdirstripe(int argc, char **argv);
91 static int lfs_rmentry(int argc, char **argv);
92 static int lfs_unlink_foreign(int argc, char **argv);
93 static int lfs_osts(int argc, char **argv);
94 static int lfs_mdts(int argc, char **argv);
95 static int lfs_df(int argc, char **argv);
96 static int lfs_getname(int argc, char **argv);
97 static int lfs_check(int argc, char **argv);
98 #ifdef HAVE_SYS_QUOTA_H
99 static int lfs_setquota(int argc, char **argv);
100 static int lfs_quota(int argc, char **argv);
101 static int lfs_project(int argc, char **argv);
102 #endif
103 static int lfs_flushctx(int argc, char **argv);
104 static int lfs_poollist(int argc, char **argv);
105 static int lfs_changelog(int argc, char **argv);
106 static int lfs_changelog_clear(int argc, char **argv);
107 static int lfs_fid2path(int argc, char **argv);
108 static int lfs_path2fid(int argc, char **argv);
109 static int lfs_rmfid(int argc, char **argv);
110 static int lfs_data_version(int argc, char **argv);
111 static int lfs_hsm_state(int argc, char **argv);
112 static int lfs_hsm_set(int argc, char **argv);
113 static int lfs_hsm_clear(int argc, char **argv);
114 static int lfs_hsm_action(int argc, char **argv);
115 static int lfs_hsm_archive(int argc, char **argv);
116 static int lfs_hsm_restore(int argc, char **argv);
117 static int lfs_hsm_release(int argc, char **argv);
118 static int lfs_hsm_remove(int argc, char **argv);
119 static int lfs_hsm_cancel(int argc, char **argv);
120 static int lfs_swap_layouts(int argc, char **argv);
121 static int lfs_mv(int argc, char **argv);
122 static int lfs_ladvise(int argc, char **argv);
123 static int lfs_getsom(int argc, char **argv);
124 static int lfs_heat_get(int argc, char **argv);
125 static int lfs_heat_set(int argc, char **argv);
126 static int lfs_mirror(int argc, char **argv);
127 static int lfs_mirror_list_commands(int argc, char **argv);
128 static int lfs_list_commands(int argc, char **argv);
129 static inline int lfs_mirror_resync(int argc, char **argv);
130 static inline int lfs_mirror_verify(int argc, char **argv);
131 static inline int lfs_mirror_read(int argc, char **argv);
132 static inline int lfs_mirror_write(int argc, char **argv);
133 static inline int lfs_mirror_copy(int argc, char **argv);
134 static int lfs_pcc_attach(int argc, char **argv);
135 static int lfs_pcc_attach_fid(int argc, char **argv);
136 static int lfs_pcc_detach(int argc, char **argv);
137 static int lfs_pcc_detach_fid(int argc, char **argv);
138 static int lfs_pcc_state(int argc, char **argv);
139 static int lfs_pcc(int argc, char **argv);
140 static int lfs_pcc_list_commands(int argc, char **argv);
141
142 enum stats_flag {
143         STATS_ON,
144         STATS_OFF,
145 };
146
147 static int lfs_migrate_to_dom(int fd_src, int fd_dst, char *name,
148                               __u64 migration_flags,
149                               unsigned long long bandwidth_bytes_sec,
150                               enum stats_flag stats_flag,
151                               long stats_interval_sec);
152
153 struct pool_to_id_cbdata {
154         const char *pool;
155         __u32 id;
156 };
157
158 static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata);
159 static int find_mirror_id_by_pool(struct llapi_layout *layout, void *cbdata);
160
161 enum setstripe_origin {
162         SO_SETSTRIPE,
163         SO_MIGRATE,
164         SO_MIGRATE_MDT,
165         SO_MIRROR_CREATE,
166         SO_MIRROR_EXTEND,
167         SO_MIRROR_SPLIT,
168         SO_MIRROR_DELETE,
169 };
170
171 static int lfs_setstripe_internal(int argc, char **argv,
172                                   enum setstripe_origin opc);
173
174 static inline int lfs_setstripe(int argc, char **argv)
175 {
176         return lfs_setstripe_internal(argc, argv, SO_SETSTRIPE);
177 }
178
179 static inline int lfs_setstripe_migrate(int argc, char **argv)
180 {
181         return lfs_setstripe_internal(argc, argv, SO_MIGRATE);
182 }
183
184 static inline int lfs_mirror_create(int argc, char **argv)
185 {
186         return lfs_setstripe_internal(argc, argv, SO_MIRROR_CREATE);
187 }
188
189 static inline int lfs_mirror_extend(int argc, char **argv)
190 {
191         return lfs_setstripe_internal(argc, argv, SO_MIRROR_EXTEND);
192 }
193
194 static inline int lfs_mirror_split(int argc, char **argv)
195 {
196         return lfs_setstripe_internal(argc, argv, SO_MIRROR_SPLIT);
197 }
198
199 static inline int lfs_mirror_delete(int argc, char **argv)
200 {
201         return lfs_setstripe_internal(argc, argv, SO_MIRROR_DELETE);
202 }
203
204 /* Setstripe and migrate share mostly the same parameters */
205 #define SSM_CMD_COMMON(cmd) \
206         "usage: "cmd" [--component-end|-E COMP_END]\n"                  \
207         "                 [--copy=LUSTRE_SRC]\n"                        \
208         "                 [--extension-size|--ext-size|-z SIZE]\n"      \
209         "                 [--help|-h] [--layout|-L PATTERN]\n"          \
210         "                 [--layout|-L PATTERN]\n"                      \
211         "                 [--mirror-count|-N[MIRROR_COUNT]]\n"          \
212         "                 [--ost|-o OST_INDICES]\n"                     \
213         "                 [--overstripe-count|-C STRIPE_COUNT]\n"       \
214         "                 [--pool|-p POOL_NAME]\n"                      \
215         "                 [--stripe-count|-c STRIPE_COUNT]\n"           \
216         "                 [--stripe-index|-i START_OST_IDX]\n"          \
217         "                 [--stripe-size|-S STRIPE_SIZE]\n"             \
218         "                 [--yaml|-y YAML_TEMPLATE_FILE]\n"
219
220 #define MIRROR_EXTEND_USAGE                                             \
221         "                 {--mirror-count|-N[MIRROR_COUNT]}\n"          \
222         "                 [SETSTRIPE_OPTIONS|-f|--file VICTIM_FILE]\n"  \
223         "                 [--no-verify]\n"
224
225 #define SETSTRIPE_USAGE                                                 \
226         SSM_CMD_COMMON("setstripe")                                     \
227         MIRROR_EXTEND_USAGE                                             \
228         "                 DIRECTORY|FILENAME\n"
229
230 #define MIGRATE_USAGE                                                   \
231         SSM_CMD_COMMON("migrate  ")                                     \
232         "                 [--block|-b] [--non-block|-n]\n"              \
233         "                 [--non-direct|-D] [--verbose|-v]\n"           \
234         "                 FILENAME\n"
235
236 #define SETDIRSTRIPE_USAGE                                              \
237         "               [--mdt-count|-c stripe_count>\n"                \
238         "               [--help|-h] [--mdt-hash|-H mdt_hash]\n"         \
239         "               [--mdt-index|-i mdt_index[,mdt_index,...]\n"    \
240         "               [--default|-D] [--mode|-o mode]\n"              \
241         "               [--max-inherit|-X max_inherit]\n"               \
242         "               [--max-inherit-rr max_inherit_rr] <dir>\n"      \
243         "To create dir with a foreign (free format) layout :\n"         \
244         "setdirstripe|mkdir --foreign[=FOREIGN_TYPE] -x|-xattr STRING " \
245         "               [--mode|-o MODE] [--flags HEX] DIRECTORY\n"
246
247 /**
248  * command_t mirror_cmdlist - lfs mirror commands.
249  */
250 command_t mirror_cmdlist[] = {
251         { .pc_name = "create", .pc_func = lfs_mirror_create,
252           .pc_help = "Create a mirrored file.\n"
253                 "usage: lfs mirror create --mirror-count|-N[MIRROR_COUNT]\n"
254                 "           [SETSTRIPE_OPTIONS] ... FILENAME|DIRECTORY ...\n" },
255         { .pc_name = "delete", .pc_func = lfs_mirror_delete,
256           .pc_help = "Delete a mirror from a file.\n"
257         "usage: lfs mirror delete {--mirror-id <mirror_id> |\n"
258         "\t               --component-id|--comp-id|-I COMP_ID |\n"
259         "\t               -p <pool>} MIRRORED_FILE ...\n"
260         },
261         { .pc_name = "extend", .pc_func = lfs_mirror_extend,
262           .pc_help = "Extend a mirrored file.\n"
263                 "usage: lfs mirror extend "
264                 "{--mirror-count|-N[MIRROR_COUNT]} [--no-verify] "
265                 "[SETSTRIPE_OPTIONS|-f VICTIM_FILE] ... FILENAME ...\n" },
266         { .pc_name = "split", .pc_func = lfs_mirror_split,
267           .pc_help = "Split a mirrored file.\n"
268         "usage: lfs mirror split {--mirror-id MIRROR_ID |\n"
269         "\t             --component-id|-I COMP_ID|-p POOL} [--destroy|-d]\n"
270         "\t             [-f NEW_FILE] MIRRORED_FILE ...\n" },
271         { .pc_name = "read", .pc_func = lfs_mirror_read,
272           .pc_help = "Read the content of a specified mirror of a file.\n"
273                 "usage: lfs mirror read {--mirror-id|-N MIRROR_ID}\n"
274                 "\t\t[--outfile|-o <output_file>] <mirrored_file>\n" },
275         { .pc_name = "write", .pc_func = lfs_mirror_write,
276           .pc_help = "Write to a specified mirror of a file.\n"
277                 "usage: lfs mirror write {--mirror-id|-N MIRROR_ID}\n"
278                 "\t\t[--inputfile|-i <input_file>] <mirrored_file>\n" },
279         { .pc_name = "copy", .pc_func = lfs_mirror_copy,
280           .pc_help = "Copy a specified mirror to other mirror(s) of a file.\n"
281                 "usage: lfs mirror copy {--read-mirror|-i MIRROR_ID0}\n"
282                 "\t\t{--write-mirror|-o MIRROR_ID1[,...]} <mirrored_file>\n" },
283         { .pc_name = "resync", .pc_func = lfs_mirror_resync,
284           .pc_help = "Resynchronizes out-of-sync mirrored file(s).\n"
285                 "usage: lfs mirror resync [--only MIRROR_ID[,...]>]\n"
286                 "\t\t<mirrored_file> [<mirrored_file2>...]\n" },
287         { .pc_name = "verify", .pc_func = lfs_mirror_verify,
288           .pc_help = "Verify mirrored file(s).\n"
289                 "usage: lfs mirror verify [--only MIRROR_ID[,...]]\n"
290                 "\t\t[--verbose|-v] <mirrored_file> [<mirrored_file2> ...]\n" },
291         { .pc_name = "--list-commands", .pc_func = lfs_mirror_list_commands,
292           .pc_help = "list commands supported by lfs mirror"},
293         { .pc_name = "help", .pc_func = Parser_help, .pc_help = "help" },
294         { .pc_name = "exit", .pc_func = Parser_quit, .pc_help = "quit" },
295         { .pc_name = "quit", .pc_func = Parser_quit, .pc_help = "quit" },
296         { .pc_help = NULL }
297 };
298
299 /**
300  * command_t pcc_cmdlist - lfs pcc commands.
301  */
302 command_t pcc_cmdlist[] = {
303         { .pc_name = "attach", .pc_func = lfs_pcc_attach,
304           .pc_help = "Attach given files to the Persistent Client Cache.\n"
305                 "usage: lfs pcc attach <--id|-i NUM> <file> ...\n"
306                 "\t-i: archive id for RW-PCC\n" },
307         { .pc_name = "attach_fid", .pc_func = lfs_pcc_attach_fid,
308           .pc_help = "Attach given files into PCC by FID(s).\n"
309                 "usage: lfs pcc attach_id {--id|-i NUM} {--mnt|-m MOUNTPOINT} FID ...\n"
310                 "\t-i: archive id for RW-PCC\n"
311                 "\t-m: Lustre mount point\n" },
312         { .pc_name = "state", .pc_func = lfs_pcc_state,
313           .pc_help = "Display the PCC state for given files.\n"
314                 "usage: lfs pcc state <file> ...\n" },
315         { .pc_name = "detach", .pc_func = lfs_pcc_detach,
316           .pc_help = "Detach given files from the Persistent Client Cache.\n"
317                 "usage: lfs pcc detach <file> ...\n" },
318         { .pc_name = "detach_fid", .pc_func = lfs_pcc_detach_fid,
319           .pc_help = "Detach given files from PCC by FID(s).\n"
320                 "usage: lfs pcc detach_fid <mntpath> <fid>...\n" },
321         { .pc_name = "--list-commands", .pc_func = lfs_pcc_list_commands,
322           .pc_help = "list commands supported by lfs pcc"},
323         { .pc_name = "help", .pc_func = Parser_help, .pc_help = "help" },
324         { .pc_name = "exit", .pc_func = Parser_quit, .pc_help = "quit" },
325         { .pc_name = "quit", .pc_func = Parser_quit, .pc_help = "quit" },
326         { .pc_help = NULL }
327 };
328
329 /* all available commands */
330 command_t cmdlist[] = {
331         {"setstripe", lfs_setstripe, 0,
332          "To create a file with specified striping/composite layout, or\n"
333          "create/replace the default layout on an existing directory:\n"
334          SSM_CMD_COMMON("setstripe")
335          "                 [--mode MODE]\n"
336          "                 <directory|filename>\n"
337          " or\n"
338          "To add component(s) to an existing composite file:\n"
339          SSM_CMD_COMMON("setstripe --component-add")
340          "To totally delete the default striping from an existing directory:\n"
341          "usage: setstripe [--delete|-d] <directory>\n"
342          " or\n"
343          "To create a mirrored file or set s default mirror layout on a directory:\n"
344          "usage: setstripe {--mirror-count|-N}[MIRROR_COUNT] [SETSTRIPE_OPTIONS] <directory|filename>\n"
345          " or\n"
346          "To delete the last component(s) from an existing composite file\n"
347          "(note that this will also delete any data in those components):\n"
348          "usage: setstripe --component-del [--component-id|-I COMP_ID]\n"
349          "                               [--component-flags|-F COMP_FLAGS]\n"
350          "                               <filename>\n"
351          "\tCOMP_ID:     Unique component ID to delete\n"
352          "\tCOMP_FLAGS:  'init' indicating all instantiated components\n"
353          "\t             '^init' indicating all uninstantiated components\n"
354          "\t-I and -F cannot be specified at the same time\n"
355          " or\n"
356          "To set or clear flags on a specific component\n"
357          "(note that this command can only be applied to mirrored files:\n"
358          "usage: setstripe --comp-set {-I COMP_ID|--comp-flags=COMP_FLAGS}\n"
359          "                            <filename>\n"
360          " or\n"
361          "To create a file with a foreign (free format) layout:\n"
362          "usage: setstripe --foreign[=FOREIGN_TYPE]\n"
363          "                 --xattr|-x LAYOUT_STRING [--flags HEX]\n"
364          "                 [--mode MODE] <filename>\n"},
365         {"getstripe", lfs_getstripe, 0,
366          "To list the layout pattern for a given file or files in a\n"
367          "directory or recursively for all files in a directory tree.\n"
368          "usage: getstripe [--ost|-O UUID] [--quiet|-q] [--verbose|-v]\n"
369          "                 [--stripe-count|-c] [--stripe-index|-i] [--fid|-F]\n"
370          "                 [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
371          "                 [--mdt-index|-m] [--recursive|-r] [--raw|-R]\n"
372          "                 [--layout|-L] [--generation|-g] [--yaml|-y]\n"
373          "                 [--help|-h] [--hex-idx]\n"
374          "                 [--component-id|-I[=COMP_ID]]\n"
375          "                 [--component-flags[=COMP_FLAGS]]\n"
376          "                 [--component-count]\n"
377          "                 [--extension-size|--ext-size|-z]\n"
378          "                 [--component-start[=[+-]COMP_START]]\n"
379          "                 [--component-end[=[+-]COMP_END]|-E[[+-]comp_end]]\n"
380          "                 [[!] --mirror-index=[+-]INDEX |\n"
381          "                 [!] --mirror-id=[+-]MIRROR_ID] [--mirror-count|-N]\n"
382          "                 [--no-follow]\n"
383          "                 <directory|filename> ..."},
384         {"setdirstripe", lfs_setdirstripe, 0,
385          "Create striped directory on specified MDT, same as mkdir.\n"
386          "May be restricted to root or group users, depending on settings.\n"
387          "usage: setdirstripe [OPTION] <directory>\n"
388          SETDIRSTRIPE_USAGE},
389         {"getdirstripe", lfs_getdirstripe, 0,
390          "To list the layout pattern info for a given directory\n"
391          "or recursively for all directories in a directory tree.\n"
392          "usage: getdirstripe [--mdt-count|-c] [--mdt-index|-m|-i]\n"
393          "                    [--help|-h] [--hex-idx] [--mdt-hash|-H]\n"
394          "                    [--obd|-O UUID] [--recursive|-r] [--yaml|-y]\n"
395          "                    [--verbose|-v] [--default|-D]\n"
396          "                    [--max-inherit|-X]\n"
397          "                    [--max-inherit-rr] <dir> ..."},
398         {"mkdir", lfs_setdirstripe, 0,
399          "Create striped directory on specified MDT, same as setdirstripe.\n"
400          "usage: mkdir [OPTION] <directory>\n"
401          SETDIRSTRIPE_USAGE},
402         {"rm_entry", lfs_rmentry, 0,
403          "To remove the name entry of the remote directory. Note: This\n"
404          "command will only delete the name entry, i.e. the remote directory\n"
405          "will become inaccessable after this command. This can only be done\n"
406          "by the administrator\n"
407          "usage: rm_entry <dir>\n"},
408         {"rmentry", lfs_rmentry, 0, "remove a dir entry, same as 'rm_entry'\n"},
409         {"unlink_foreign", lfs_unlink_foreign, 0,
410          "To remove the foreign file/dir.\n"
411          "Note: This is for files/dirs prevented to be removed using\n"
412          "unlink/rmdir, but works also for regular ones\n"
413          "usage: unlink_foreign <foreign_dir/file> [<foreign_dir/file> ...]\n"},
414         {"pool_list", lfs_poollist, 0,
415          "List pools or pool OSTs\n"
416          "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
417         {"find", lfs_find, 0,
418          "find files matching given attributes recursively in directory tree.\n"
419          "usage: find <directory|filename> ...\n"
420          "     [[!] --atime|-A [+-]N[smhdwy]] [[!] --btime|-B [+-]N[smhdwy]]\n"
421          "     [[!] --ctime|-C [+-]N[smhdwy]] [[!] --mtime|-M [+-]N[smhdwy]]\n"
422          "     [[!] --blocks|-b N] [[!] --component-count [+-]<comp_cnt>]\n"
423          "     [[!] --component-start [+-]N[kMGTPE]]\n"
424          "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
425          "     [[!] --component-flags {init,stale,prefer,offline,nosync,extension}]\n"
426          "     [[!] --extension-size|--ext-size|-z [+-]N[kMGT]]\n"
427          "     [[!] --foreign[=<foreign_type>]]\n"
428          "     [[!] --gid|-g|--group|-G <gid>|<gname>] [--help|-h]\n"
429          "     [[!] --layout|-L released,raid0,mdt] [--lazy|-l] [[!] --links [+-]n]\n"
430          "     [--maxdepth|-D N] [[!] --mdt-count|-T [+-]<stripes>]\n"
431          "     [[!] --mdt-hash|-H <[^][blm],[^]fnv_1a_64,all_char,crush,...>\n"
432          "     [[!] --mdt-index|--mdt|-m <uuid|index,...>]\n"
433          "     [[!] --mirror-count|-N [+-]<n>]\n"
434          "     [[!] --mirror-state <[^]state>]\n"
435          "     [[!] --name|-n <pattern>] [[!] --newer[XY] <reference>]\n"
436          "     [[!] --ost|-O <uuid|index,...>] [[!] --perm [/-]mode]\n"
437          "     [[!] --pool <pool>] [--print|-P] [--print0|-0] [--printf <format>]\n"
438          "     [[!] --projid <projid>] [[!] --size|-s [+-]N[bkMGTPE]]\n"
439          "     [[!] --stripe-count|-c [+-]<stripes>]\n"
440          "     [[!] --stripe-index|-i <index,...>]\n"
441          "     [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
442          "     [[!] --uid|-u|--user|-U <uid>|<uname>]\n"
443          "\t !: used before an option indicates 'NOT' requested attribute\n"
444          "\t -: used before a value indicates less than requested value\n"
445          "\t +: used before a value indicates more than requested value\n"
446          "\t ^: used before a flag indicates to exclude it\n"},
447         {"check", lfs_check, 0,
448          "Display the status of MGTs, MDTs or OSTs (as specified in the command)\n"
449          "or all the servers (MGTs, MDTs and OSTs) [for specified path only].\n"
450          "usage: check {mgts|osts|mdts|all} [path]"},
451         {"osts", lfs_osts, 0, "list OSTs connected to client "
452          "[for specified path only]\n" "usage: osts [path]"},
453         {"mdts", lfs_mdts, 0, "list MDTs connected to client "
454          "[for specified path only]\n" "usage: mdts [path]"},
455         {"df", lfs_df, 0,
456          "report filesystem disk space usage or inodes usage "
457          "of each MDS and all OSDs or a batch belonging to a specific pool.\n"
458          "Usage: df [--inodes|-i] [--human-readable|-h] [--lazy|-l]\n"
459          "          [--pool|-p <fsname>[.<pool>]] [path]"},
460         {"getname", lfs_getname, 0,
461          "list instances and specified mount points [for specified path only]\n"
462          "Usage: getname [--help|-h] [--instance|-i] [--fsname|-n] [path ...]"},
463 #ifdef HAVE_SYS_QUOTA_H
464         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
465          "usage: setquota [-t][-D] {-u|-U|-g|-G|-p|-P} {-b|-B|-i|-I LIMIT} [--pool POOL] FILESYSTEM\n"
466          "       setquota {-u|-g|-p} --delete FILESYSTEM\n"},
467         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
468          "usage: quota [-q] [-v] [-h] [-o OBD_UUID|-i MDT_IDX|-I OST_IDX]\n"
469          "             [{-u|-g|-p} UNAME|UID|GNAME|GID|PROJID]\n"
470          "             [--pool <OST pool name>] <filesystem>\n"
471          "       quota -t <-u|-g|-p> [--pool <OST pool name>] <filesystem>\n"
472          "       quota [-q] [-v] [h] {-U|-G|-P} [--pool <OST pool name>] <filesystem>"},
473         {"project", lfs_project, 0,
474          "Change or list project attribute for specified file or directory.\n"
475          "usage: project [-d|-r] <file|directory...>\n"
476          "         list project ID and flags on file(s) or directories\n"
477          "       project [-p id] [-s] [-r] <file|directory...>\n"
478          "         set project ID and/or inherit flag for specified file(s) or directories\n"
479          "       project -c [-d|-r [-p id] [-0]] <file|directory...>\n"
480          "         check project ID and flags on file(s) or directories, print outliers\n"
481          "       project -C [-d|-r] [-k] <file|directory...>\n"
482          "         clear the project inherit flag and ID on the file or directory\n"
483         },
484 #endif
485         {"flushctx", lfs_flushctx, 0,
486          "Flush security context for current user.\n"
487          "usage: flushctx [-k] [-r] [mountpoint...]"},
488         {"changelog", lfs_changelog, 0,
489          "Show the metadata changes on an MDT."
490          "\nusage: changelog <mdtname> [startrec [endrec]]"},
491         {"changelog_clear", lfs_changelog_clear, 0,
492          "Indicate that old changelog records up to <endrec> are no longer of "
493          "interest to consumer <id>, allowing the system to free up space.\n"
494          "An <endrec> of 0 means all records.\n"
495          "usage: changelog_clear <mdtname> <id> <endrec>"},
496         {"fid2path", lfs_fid2path, 0,
497          "Resolve the full path(s) for given FID(s). For a specific hardlink "
498          "specify link number <linkno>.\n"
499          "usage: fid2path [--print-fid|-f] [--print-link|-c] [--link|-l <linkno>] "
500          "<fsname|root> <fid>..."},
501         {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
502          "usage: path2fid [--parents] <path> ..."},
503         {"rmfid", lfs_rmfid, 0, "Remove file(s) by FID(s)\n"
504          "usage: rmfid <fsname|rootpath> <fid> ..."},
505         {"data_version", lfs_data_version, 0, "Display file data version for "
506          "a given path.\n" "usage: data_version [-n|-r|-w] <path>"},
507         {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
508          "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
509         {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
510          "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
511          "[--archived] [--lost] [--archive-id NUM] <file> ..."},
512         {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
513          "files.\n"
514          "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
515          "[--archived] [--lost] <file> ..."},
516         {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
517          "given files.\n" "usage: hsm_action <file> ..."},
518         {"hsm_archive", lfs_hsm_archive, 0,
519          "Archive file to external storage.\n"
520          "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
521          "<file> ..."},
522         {"hsm_restore", lfs_hsm_restore, 0,
523          "Restore file from external storage.\n"
524          "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
525         {"hsm_release", lfs_hsm_release, 0,
526          "Release files from Lustre.\n"
527          "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
528         {"hsm_remove", lfs_hsm_remove, 0,
529          "Remove file copy from external storage.\n"
530          "usage: hsm_remove [--filelist FILELIST] [--data DATA] "
531          "[--archive NUM]\n"
532          "                  (FILE [FILE ...] | "
533          "--mntpath MOUNTPATH FID [FID ...])\n"
534          "\n"
535          "Note: To remove an archived copy of a file already deleted from a "
536          "Lustre FS, the\n"
537          "--mntpath option and a list of FIDs must be specified"
538         },
539         {"hsm_cancel", lfs_hsm_cancel, 0,
540          "Cancel requests related to specified files.\n"
541          "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
542         {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
543          "usage: swap_layouts <path1> <path2>"},
544         {"migrate", lfs_setstripe_migrate, 0,
545          "migrate directories and their inodes between MDTs.\n"
546          "usage: migrate [--mdt-count|-c STRIPE_COUNT] [--directory|-d]\n"
547          "               [--mdt-hash|-H HASH_TYPE]\n"
548          "               [--mdt-index|-m START_MDT_INDEX] [--verbose|-v]\n"
549          "               DIRECTORY\n"
550          "\n"
551          "migrate file objects from one OST layout to another\n"
552          "(may be not safe with concurent writes).\n"
553          MIGRATE_USAGE },
554         {"mv", lfs_mv, 0,
555          "To move directories between MDTs. This command is deprecated, "
556          "use \"migrate\" instead.\n"
557          "usage: mv <directory|filename> [--mdt-index|-m MDT_INDEX] "
558          "[--verbose|-v]\n"},
559         {"ladvise", lfs_ladvise, 0,
560          "Provide servers with advice about access patterns for a file.\n"
561          "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
562          "               [--background|-b] [--unset|-u]\n\n"
563          "               {--end|-e END[kMGT]|--length|-l LENGTH[kMGT]}\n"
564          "               {[--mode|-m [READ,WRITE]}\n"
565          "               <file> ...\n"},
566         {"mirror", lfs_mirror, mirror_cmdlist,
567          "lfs commands used to manage files with mirrored components:\n"
568          "lfs mirror create - create a mirrored file or directory\n"
569          "lfs mirror extend - add mirror(s) to an existing file\n"
570          "lfs mirror split  - split a mirror from an existing mirrored file\n"
571          "lfs mirror resync - resynchronize out-of-sync mirrored file(s)\n"
572          "lfs mirror read   - read a mirror content of a mirrored file\n"
573          "lfs mirror write  - write to a mirror of a mirrored file\n"
574          "lfs mirror copy   - copy a mirror to other mirror(s) of a file\n"
575          "lfs mirror verify - verify mirrored file(s)\n"},
576         {"getsom", lfs_getsom, 0, "To list the SOM info for a given file.\n"
577          "usage: getsom [-s] [-b] [-f] <path>\n"
578          "\t-s: Only show the size value of the SOM data for a given file\n"
579          "\t-b: Only show the blocks value of the SOM data for a given file\n"
580          "\t-f: Only show the flags value of the SOM data for a given file\n"},
581         {"heat_get", lfs_heat_get, 0,
582          "To get heat of files.\n"
583          "usage: heat_get <file> ...\n"},
584         {"heat_set", lfs_heat_set, 0,
585          "To set heat flags of files.\n"
586          "usage: heat_set [--clear|-c] [--off|-o] [--on|-O] <file> ...\n"
587          "\t--clear|-c: Clear file heat for given files\n"
588          "\t--off|-o:   Turn off file heat for given files\n"
589          "\t--on|-O:    Turn on file heat for given files\n"},
590         {"pcc", lfs_pcc, pcc_cmdlist,
591          "lfs commands used to interact with PCC features:\n"
592          "lfs pcc attach - attach given files to Persistent Client Cache\n"
593          "lfs pcc attach_fid - attach given files into PCC by FID(s)\n"
594          "lfs pcc state  - display the PCC state for given files\n"
595          "lfs pcc detach - detach given files from Persistent Client Cache\n"
596          "lfs pcc detach_fid - detach given files from PCC by FID(s)\n"},
597         {"help", Parser_help, 0, "help"},
598         {"exit", Parser_quit, 0, "quit"},
599         {"quit", Parser_quit, 0, "quit"},
600         {"--version", Parser_version, 0,
601          "output build version of the utility and exit"},
602         {"--list-commands", lfs_list_commands, 0,
603          "list commands supported by the utility and exit"},
604         { 0, 0, 0, NULL }
605 };
606
607 static int check_hashtype(const char *hashtype)
608 {
609         int type_num = atoi(hashtype);
610         int i;
611
612         /* numeric hash type */
613         if (hashtype && lmv_is_known_hash_type(type_num))
614                 return type_num;
615         /* string hash type */
616         for (i = LMV_HASH_TYPE_ALL_CHARS; i < ARRAY_SIZE(mdt_hash_name); i++)
617                 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
618                         return i;
619
620         return 0;
621 }
622
623 static uint32_t check_foreign_type_name(const char *foreign_type_name)
624 {
625         uint32_t i;
626
627         for (i = 0; i < LU_FOREIGN_TYPE_UNKNOWN; i++) {
628                 if (!lu_foreign_types[i].lft_name)
629                         break;
630                 if (strcmp(foreign_type_name,
631                            lu_foreign_types[i].lft_name) == 0)
632                         return lu_foreign_types[i].lft_type;
633         }
634
635         return LU_FOREIGN_TYPE_UNKNOWN;
636 }
637
638 static const char *error_loc = "syserror";
639
640 static int
641 migrate_open_files(const char *name, __u64 migration_flags,
642                    const struct llapi_stripe_param *param,
643                    struct llapi_layout *layout, int *fd_src_ptr,
644                    int *fd_dst_ptr)
645 {
646         int                      fd_src = -1;
647         int                      fd_dst = -1;
648         int                      rflags;
649         int                      mdt_index;
650         int                      random_value;
651         char                     parent[PATH_MAX];
652         char                     volatile_file[PATH_MAX];
653         char                    *ptr;
654         int                      rc;
655         struct stat              st;
656         struct stat              stv;
657
658         if (!param && !layout) {
659                 error_loc = "layout information";
660                 return -EINVAL;
661         }
662
663         /* search for file directory pathname */
664         if (strlen(name) > sizeof(parent) - 1) {
665                 error_loc = "source file name";
666                 return -ERANGE;
667         }
668
669         strncpy(parent, name, sizeof(parent));
670         ptr = strrchr(parent, '/');
671         if (!ptr) {
672                 if (!getcwd(parent, sizeof(parent))) {
673                         error_loc = "getcwd";
674                         return -errno;
675                 }
676         } else {
677                 if (ptr == parent) /* leading '/' */
678                         ptr = parent + 1;
679                 *ptr = '\0';
680         }
681
682         /* even if the file is only read, WR mode is nedeed to allow
683          * layout swap on fd
684          */
685         /* Allow migrating even without the key on encrypted files */
686         rflags = O_RDWR | O_NOATIME | O_FILE_ENC;
687         if (!(migration_flags & LLAPI_MIGRATION_NONDIRECT))
688                 rflags |= O_DIRECT;
689 source_open:
690         fd_src = open(name, rflags);
691         if (fd_src < 0) {
692                 /* If encrypted file without the key,
693                  * retry mirror extend in O_DIRECT.
694                  */
695                 if (errno == ENOKEY && !(rflags & O_DIRECT) &&
696                     migration_flags & LLAPI_MIGRATION_MIRROR) {
697                         rflags |= O_DIRECT;
698                         goto source_open;
699                 }
700                 rc = -errno;
701                 error_loc = "cannot open source file";
702                 return rc;
703         }
704
705         rc = llapi_file_fget_mdtidx(fd_src, &mdt_index);
706         if (rc < 0) {
707                 error_loc = "cannot get MDT index";
708                 goto out;
709         }
710
711         do {
712                 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW |
713                         /* Allow migrating without the key on encrypted files */
714                         O_FILE_ENC;
715                 mode_t open_mode = S_IRUSR | S_IWUSR;
716
717                 if (rflags & O_DIRECT)
718                         open_flags |= O_DIRECT;
719                 random_value = random();
720                 rc = snprintf(volatile_file, sizeof(volatile_file),
721                               "%s/%s:%.4X:%.4X:fd=%.2d", parent,
722                               LUSTRE_VOLATILE_HDR, mdt_index,
723                               random_value, fd_src);
724                 if (rc >= sizeof(volatile_file)) {
725                         rc = -ENAMETOOLONG;
726                         break;
727                 }
728
729                 /* create, open a volatile file, use caching (ie no directio) */
730                 if (layout) {
731                         /* Returns -1 and sets errno on error: */
732                         fd_dst = llapi_layout_file_open(volatile_file,
733                                                          open_flags, open_mode,
734                                                          layout);
735                         if (fd_dst < 0)
736                                 fd_dst = -errno;
737                 } else {
738                         /* Does the right thing on error: */
739                         fd_dst = llapi_file_open_param(volatile_file,
740                                                         open_flags,
741                                                         open_mode, param);
742                 }
743         } while (fd_dst < 0 && (rc = fd_dst) == -EEXIST);
744
745         if (rc < 0) {
746                 error_loc = "cannot create volatile file";
747                 goto out;
748         }
749
750         /*
751          * In case the MDT does not support creation of volatile files
752          * we should try to unlink it.
753          */
754         (void)unlink(volatile_file);
755
756         /*
757          * Not-owner (root?) special case.
758          * Need to set owner/group of volatile file like original.
759          * This will allow to pass related check during layout_swap.
760          */
761         rc = fstat(fd_src, &st);
762         if (rc != 0) {
763                 rc = -errno;
764                 error_loc = "cannot stat source file";
765                 goto out;
766         }
767
768         rc = fstat(fd_dst, &stv);
769         if (rc != 0) {
770                 rc = -errno;
771                 error_loc = "cannot stat volatile";
772                 goto out;
773         }
774
775         if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
776                 rc = fchown(fd_dst, st.st_uid, st.st_gid);
777                 if (rc != 0) {
778                         rc = -errno;
779                         error_loc = "cannot change ownwership of volatile";
780                         goto out;
781                 }
782         }
783
784 out:
785         if (rc < 0) {
786                 if (fd_src > 0)
787                         close(fd_src);
788                 if (fd_dst > 0)
789                         close(fd_dst);
790         } else {
791                 *fd_src_ptr = fd_src;
792                 *fd_dst_ptr = fd_dst;
793                 error_loc = NULL;
794         }
795         return rc;
796 }
797
798 struct timespec timespec_sub(struct timespec *before, struct timespec *after)
799 {
800         struct timespec ret;
801
802         ret.tv_sec = after->tv_sec - before->tv_sec;
803         if (after->tv_nsec < before->tv_nsec) {
804                 ret.tv_sec--;
805                 ret.tv_nsec = NSEC_PER_SEC + after->tv_nsec - before->tv_nsec;
806         } else {
807                 ret.tv_nsec = after->tv_nsec - before->tv_nsec;
808         }
809
810         return ret;
811 }
812
813 static void stats_log(struct timespec *now, struct timespec *start_time,
814                       enum stats_flag stats_flag,
815                       ssize_t read_bytes, size_t write_bytes,
816                       off_t file_size_bytes)
817 {
818         struct timespec diff = timespec_sub(start_time, now);
819
820         if (stats_flag == STATS_ON && ((diff.tv_sec != 0) ||
821                 (diff.tv_nsec != 0)) && file_size_bytes != 0)
822                 printf("- { seconds: %li, rmbps: %5.2g, wmbps: %5.2g, copied: %lu, size: %lu, pct: %lu%% }\n",
823                         diff.tv_sec,
824                         (double) read_bytes/((ONE_MB * diff.tv_sec) +
825                                 ((ONE_MB * diff.tv_nsec)/NSEC_PER_SEC)),
826                         (double) write_bytes/((ONE_MB * diff.tv_sec) +
827                                 ((ONE_MB * diff.tv_nsec)/NSEC_PER_SEC)),
828                         write_bytes/ONE_MB,
829                         file_size_bytes/ONE_MB,
830                         ((write_bytes*100)/file_size_bytes));
831 }
832
833 static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int),
834                              unsigned long long bandwidth_bytes_sec,
835                              enum stats_flag stats_flag,
836                              long stats_interval_sec, off_t file_size_bytes)
837 {
838         struct llapi_layout *layout;
839         size_t buf_size = 64 * 1024 * 1024;
840         void *buf = NULL;
841         off_t pos = 0;
842         off_t data_end = 0;
843         size_t page_size = sysconf(_SC_PAGESIZE);
844         bool sparse;
845         int rc;
846         size_t write_bytes = 0;
847         ssize_t read_bytes = 0;
848         struct timespec start_time;
849         struct timespec now;
850         struct timespec last_bw_print;
851
852         layout = llapi_layout_get_by_fd(fd_src, 0);
853         if (layout) {
854                 uint64_t stripe_size;
855
856                 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
857                 if (rc == 0) {
858                         /* We like big bufs */
859                         if (stripe_size > buf_size)
860                                 buf_size = stripe_size;
861                         else
862                                 /* Trim to stripe_size multiple */
863                                 buf_size -= buf_size % stripe_size;
864                 }
865
866                 llapi_layout_free(layout);
867         }
868
869         /* Use a page-aligned buffer for direct I/O */
870         rc = posix_memalign(&buf, page_size, buf_size);
871         if (rc != 0)
872                 return -rc;
873
874         sparse = llapi_file_is_sparse(fd_src);
875         if (sparse) {
876                 rc = ftruncate(fd_dst, pos);
877                 if (rc < 0) {
878                         rc = -errno;
879                         return rc;
880                 }
881         }
882
883         clock_gettime(CLOCK_REALTIME, &start_time);
884         now = last_bw_print = start_time;
885
886         while (1) {
887                 off_t data_off;
888                 size_t to_read, to_write;
889                 ssize_t rsize;
890
891                 if (sparse && pos >= data_end) {
892                         size_t data_size;
893
894                         data_off = llapi_data_seek(fd_src, pos, &data_size);
895                         if (data_off < 0) {
896                                 /* Non-fatal, switch to full copy */
897                                 sparse = false;
898                                 continue;
899                         }
900                         /* hole at the end of file, truncate up to it */
901                         if (!data_size) {
902                                 rc = ftruncate(fd_dst, data_off);
903                                 if (rc < 0)
904                                         goto out;
905                         }
906                         pos = data_off & ~(page_size - 1);
907                         data_end = data_off + data_size;
908                         to_read = ((data_end - pos - 1) | (page_size - 1)) + 1;
909                         to_read = MIN(to_read, buf_size);
910                 } else {
911                         to_read = buf_size;
912                 }
913
914                 if (check_file) {
915                         rc = check_file(fd_src);
916                         if (rc < 0)
917                                 goto out;
918                 }
919
920                 rsize = pread(fd_src, buf, to_read, pos);
921                 read_bytes += rsize;
922                 if (rsize < 0) {
923                         rc = -errno;
924                         goto out;
925                 }
926                 /* EOF */
927                 if (rsize == 0)
928                         break;
929
930                 to_write = rsize;
931                 while (to_write > 0) {
932                         unsigned long long write_target;
933                         ssize_t written;
934                         struct timespec diff;
935
936                         written = pwrite(fd_dst, buf, to_write, pos);
937                         if (written < 0) {
938                                 rc = -errno;
939                                 goto out;
940                         }
941                         pos += written;
942                         to_write -= written;
943                         write_bytes += written;
944
945                         if (bandwidth_bytes_sec == 0)
946                                 continue;
947
948                         clock_gettime(CLOCK_REALTIME, &now);
949                         diff = timespec_sub(&start_time, &now);
950                         write_target = ((bandwidth_bytes_sec * diff.tv_sec) +
951                                 ((bandwidth_bytes_sec *
952                                 diff.tv_nsec)/NSEC_PER_SEC));
953
954                         if (write_target < write_bytes) {
955                                 unsigned long long excess;
956                                 struct timespec delay = { 0, 0 };
957
958                                 excess = write_bytes - write_target;
959
960                                 if (excess == 0)
961                                         continue;
962
963                                 delay.tv_sec = excess / bandwidth_bytes_sec;
964                                 delay.tv_nsec = (excess % bandwidth_bytes_sec) *
965                                         NSEC_PER_SEC / bandwidth_bytes_sec;
966
967                                 do {
968                                         rc = clock_nanosleep(CLOCK_REALTIME, 0,
969                                                              &delay, &delay);
970                                 } while (rc < 0 && errno == EINTR);
971
972                                 if (rc < 0) {
973                                         if (stats_flag == STATS_OFF)
974                                                 fprintf(stderr,
975                                                         "error %s: delay for bandwidth control failed: %s\n",
976                                                         progname,
977                                                         strerror(-rc));
978                                         rc = 0;
979                                 }
980                         }
981                 }
982
983                 clock_gettime(CLOCK_REALTIME, &now);
984                 if ((write_bytes != file_size_bytes) &&
985                         (now.tv_sec >= last_bw_print.tv_sec +
986                         stats_interval_sec)) {
987                         stats_log(&now, &start_time, stats_flag,
988                                   read_bytes, write_bytes,
989                                   file_size_bytes);
990                         last_bw_print = now;
991                 }
992
993                 if (rc || rsize < to_read)
994                         break;
995         }
996
997         /* Output at least one log, regardless of stats_interval */
998         clock_gettime(CLOCK_REALTIME, &now);
999         stats_log(&now, &start_time, stats_flag,
1000                   read_bytes, write_bytes,
1001                   file_size_bytes);
1002
1003         rc = fsync(fd_dst);
1004         if (rc < 0)
1005                 rc = -errno;
1006 out:
1007         /* Try to avoid page cache pollution after migration. */
1008         (void)posix_fadvise(fd_src, 0, 0, POSIX_FADV_DONTNEED);
1009         (void)posix_fadvise(fd_dst, 0, 0, POSIX_FADV_DONTNEED);
1010
1011         free(buf);
1012         return rc;
1013 }
1014
1015 static int migrate_set_timestamps(int fd, const struct stat *st)
1016 {
1017         struct timeval tv[2] = {
1018                 {.tv_sec = st->st_atime},
1019                 {.tv_sec = st->st_mtime}
1020         };
1021
1022         return futimes(fd, tv);
1023 }
1024
1025 static int migrate_block(int fd_src, int fd_dst,
1026                          unsigned long long bandwidth_bytes_sec,
1027                          enum stats_flag stats_flag,
1028                          long stats_interval_sec)
1029 {
1030         struct stat st;
1031         __u64   dv1;
1032         int     gid;
1033         int     rc;
1034         int     rc2;
1035
1036         do
1037                 gid = random();
1038         while (gid == 0);
1039
1040
1041         /* The grouplock blocks all concurrent accesses to the file. */
1042         rc = llapi_group_lock(fd_src, gid);
1043         if (rc < 0) {
1044                 error_loc = "cannot get group lock";
1045                 return rc;
1046         }
1047
1048         rc = fstat(fd_src, &st);
1049         if (rc < 0) {
1050                 error_loc = "cannot stat source file";
1051                 rc = -errno;
1052                 goto out_unlock;
1053         }
1054
1055         /*
1056          * LL_DV_RD_FLUSH should not be set, otherwise the servers will try to
1057          * get extent locks on the OST objects. This will conflict with our
1058          * extent group locks.
1059          */
1060         rc = llapi_get_data_version(fd_src, &dv1, 0);
1061         if (rc < 0) {
1062                 error_loc = "cannot get dataversion";
1063                 goto out_unlock;
1064         }
1065
1066         rc = migrate_copy_data(fd_src, fd_dst, NULL, bandwidth_bytes_sec,
1067                                stats_flag, stats_interval_sec,
1068                                st.st_size);
1069         if (rc < 0) {
1070                 error_loc = "data copy failed";
1071                 goto out_unlock;
1072         }
1073
1074         /* Make sure we keep original atime/mtime values */
1075         rc = migrate_set_timestamps(fd_dst, &st);
1076         if (rc < 0) {
1077                 error_loc = "set target file timestamp failed";
1078                 goto out_unlock;
1079         }
1080
1081         /*
1082          * swap layouts
1083          * for a migration we need to check data version on file did
1084          * not change.
1085          *
1086          * Pass in gid=0 since we already own grouplock.
1087          */
1088         rc = llapi_fswap_layouts_grouplock(fd_src, fd_dst, dv1, 0, 0,
1089                                            SWAP_LAYOUTS_CHECK_DV1);
1090         if (rc == -EAGAIN) {
1091                 error_loc = "file changed";
1092                 goto out_unlock;
1093         } else if (rc < 0) {
1094                 error_loc = "cannot swap layout";
1095                 goto out_unlock;
1096         }
1097
1098 out_unlock:
1099         rc2 = llapi_group_unlock(fd_src, gid);
1100         if (rc2 < 0 && rc == 0) {
1101                 error_loc = "unlock group lock";
1102                 rc = rc2;
1103         }
1104
1105         return rc;
1106 }
1107
1108 /**
1109  * Internal helper for migrate_copy_data(). Check lease and report error if
1110  * need be.
1111  *
1112  * \param[in]  fd           File descriptor on which to check the lease.
1113  *
1114  * \retval 0       Migration can keep on going.
1115  * \retval -errno  Error occurred, abort migration.
1116  */
1117 static int check_lease(int fd)
1118 {
1119         int rc;
1120
1121         rc = llapi_lease_check(fd);
1122         if (rc > 0)
1123                 return 0; /* llapi_check_lease returns > 0 on success. */
1124
1125         return -EBUSY;
1126 }
1127
1128 static int migrate_nonblock(int fd_src, int fd_dst,
1129                             unsigned long long bandwidth_bytes_sec,
1130                             enum stats_flag stats_flag,
1131                             long stats_interval_sec)
1132 {
1133         struct stat st;
1134         __u64   dv1;
1135         __u64   dv2;
1136         int     rc;
1137
1138         rc = fstat(fd_src, &st);
1139         if (rc < 0) {
1140                 error_loc = "cannot stat source file";
1141                 return -errno;
1142         }
1143
1144         rc = llapi_get_data_version(fd_src, &dv1, LL_DV_RD_FLUSH);
1145         if (rc < 0) {
1146                 error_loc = "cannot get data version";
1147                 return rc;
1148         }
1149
1150         rc = migrate_copy_data(fd_src, fd_dst, check_lease,
1151                                bandwidth_bytes_sec, stats_flag,
1152                                stats_interval_sec, st.st_size);
1153         if (rc < 0) {
1154                 error_loc = "data copy failed";
1155                 return rc;
1156         }
1157
1158         rc = llapi_get_data_version(fd_src, &dv2, LL_DV_RD_FLUSH);
1159         if (rc != 0) {
1160                 error_loc = "cannot get data version";
1161                 return rc;
1162         }
1163
1164         if (dv1 != dv2) {
1165                 rc = -EAGAIN;
1166                 error_loc = "source file changed";
1167                 return rc;
1168         }
1169
1170         /* Make sure we keep original atime/mtime values */
1171         rc = migrate_set_timestamps(fd_dst, &st);
1172         if (rc < 0) {
1173                 error_loc = "set target file timestamp failed";
1174                 return -errno;
1175         }
1176         return 0;
1177 }
1178
1179 static
1180 int lfs_layout_compid_by_pool(char *fname, const char *pool, int *comp_id)
1181 {
1182         struct pool_to_id_cbdata data = { .pool = pool };
1183         struct llapi_layout *layout = NULL;
1184         int rc;
1185
1186         layout = llapi_layout_get_by_path(fname, 0);
1187         if (!layout) {
1188                 fprintf(stderr,
1189                         "error %s: file '%s' couldn't get layout: rc=%d\n",
1190                         progname, fname, errno);
1191                 rc = -errno;
1192                 goto free_layout;
1193         }
1194         rc = llapi_layout_sanity(layout, false, true);
1195         if (rc < 0) {
1196                 llapi_layout_sanity_perror(errno);
1197                 goto free_layout;
1198         }
1199         rc = llapi_layout_comp_iterate(layout, find_comp_id_by_pool, &data);
1200         if (rc < 0)
1201                 goto free_layout;
1202
1203         *comp_id = data.id;
1204         rc = 0;
1205
1206 free_layout:
1207         if (layout)
1208                 llapi_layout_free(layout);
1209         return rc;
1210 }
1211
1212 static int lfs_component_set(char *fname, int comp_id, const char *pool,
1213                              __u32 flags, __u32 neg_flags)
1214 {
1215         __u32 ids[2];
1216         __u32 flags_array[2];
1217         size_t count = 0;
1218         int rc;
1219
1220         if (!comp_id) {
1221                 if (pool == NULL) {
1222                         fprintf(stderr,
1223                                 "error %s: neither component id nor pool is specified\n",
1224                                 progname);
1225                         return -EINVAL;
1226                 }
1227                 rc = lfs_layout_compid_by_pool(fname, pool, &comp_id);
1228                 if (rc)
1229                         return rc;
1230         }
1231
1232         if (flags) {
1233                 ids[count] = comp_id;
1234                 flags_array[count] = flags;
1235                 ++count;
1236         }
1237
1238         if (neg_flags) {
1239                 if (neg_flags & LCME_FL_STALE) {
1240                         fprintf(stderr,
1241                                 "%s: cannot clear 'stale' flags from component. Please use lfs-mirror-resync(1) instead\n",
1242                                 progname);
1243                         return -EINVAL;
1244                 }
1245
1246                 ids[count] = comp_id;
1247                 flags_array[count] = neg_flags | LCME_FL_NEG;
1248                 ++count;
1249         }
1250
1251         rc = llapi_layout_file_comp_set(fname, ids, flags_array, count);
1252         if (rc) {
1253                 if (errno == EUCLEAN) {
1254                         rc = -errno;
1255                         fprintf(stderr,
1256                                 "%s: cannot set 'stale' flag on component '%#x' of the last non-stale mirror of '%s'\n",
1257                                 progname, comp_id, fname);
1258                 } else {
1259                         fprintf(stderr,
1260                                 "%s: cannot change the flags of component '%#x' of file '%s': %x / ^(%x)\n",
1261                                 progname, comp_id, fname, flags, neg_flags);
1262                 }
1263         }
1264
1265         return rc;
1266 }
1267
1268 static int lfs_component_del(char *fname, __u32 comp_id,
1269                              __u32 flags, __u32 neg_flags)
1270 {
1271         int     rc = 0;
1272
1273         if (flags && neg_flags) {
1274                 fprintf(stderr,
1275                         "%s: cannot specify both positive and negative flags\n",
1276                         progname);
1277                 return -EINVAL;
1278         }
1279
1280         if (!flags && neg_flags)
1281                 flags = neg_flags | LCME_FL_NEG;
1282
1283         if (flags && comp_id) {
1284                 fprintf(stderr,
1285                         "%s: cannot specify component ID and flags at the same time\n",
1286                         progname);
1287                 return -EINVAL;
1288         }
1289
1290         if (!flags && !comp_id) {
1291                 fprintf(stderr,
1292                         "%s: neither flags nor component ID is specified\n",
1293                         progname);
1294                 return -EINVAL;
1295         }
1296
1297         if (flags) {
1298                 if (flags & ~LCME_KNOWN_FLAGS) {
1299                         fprintf(stderr,
1300                                 "%s setstripe: unknown flags %#x\n",
1301                                 progname, flags);
1302                         return -EINVAL;
1303                 }
1304         } else if (comp_id > LCME_ID_MAX) {
1305                 fprintf(stderr, "%s setstripe: invalid component id %u\n",
1306                         progname, comp_id);
1307                 return -EINVAL;
1308         }
1309
1310         rc = llapi_layout_file_comp_del(fname, comp_id, flags);
1311         if (rc)
1312                 fprintf(stderr,
1313                         "%s setstripe: cannot delete component %#x from '%s': %s\n",
1314                         progname, comp_id, fname, strerror(errno));
1315         return rc;
1316 }
1317
1318 static int lfs_component_add(char *fname, struct llapi_layout *layout)
1319 {
1320         int     rc;
1321
1322         if (!layout)
1323                 return -EINVAL;
1324
1325         rc = llapi_layout_file_comp_add(fname, layout);
1326         if (rc)
1327                 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
1328                         fname, strerror(errno));
1329         return rc;
1330 }
1331
1332 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
1333                                 struct llapi_layout *layout)
1334 {
1335         struct stat     st;
1336         int     fd;
1337
1338         if (!layout)
1339                 return -EINVAL;
1340
1341         fd = lstat(fname, &st);
1342         if (fd == 0 && S_ISDIR(st.st_mode))
1343                 open_flags = O_DIRECTORY | O_RDONLY;
1344
1345         fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
1346         if (fd < 0)
1347                 fprintf(stderr, "%s: cannot %s '%s': %s\n", progname,
1348                         S_ISDIR(st.st_mode) ?
1349                                 "set default composite layout for" :
1350                                 "create composite file",
1351                         fname, strerror(errno));
1352         return fd;
1353 }
1354
1355 static int lfs_migrate(char *name, __u64 migration_flags,
1356                         struct llapi_stripe_param *param,
1357                         struct llapi_layout *layout,
1358                         unsigned long long bandwidth_bytes_sec,
1359                         enum stats_flag stats_flag, long stats_interval_sec)
1360 {
1361         struct llapi_layout *existing;
1362         uint64_t dom_new, dom_cur;
1363         int fd_src = -1;
1364         int fd_dst = -1;
1365         int rc;
1366
1367         rc = migrate_open_files(name, migration_flags, param, layout,
1368                                 &fd_src, &fd_dst);
1369         if (rc < 0)
1370                 goto out;
1371
1372         rc = llapi_layout_dom_size(layout, &dom_new);
1373         if (rc) {
1374                 error_loc = "cannot get new layout DoM size";
1375                 goto out;
1376         }
1377         /* special case for migration to DOM layout*/
1378         existing = llapi_layout_get_by_fd(fd_src, 0);
1379         if (!existing) {
1380                 error_loc = "cannot get existing layout";
1381                 goto out;
1382         }
1383
1384         rc = llapi_layout_dom_size(existing, &dom_cur);
1385         if (rc) {
1386                 error_loc = "cannot get current layout DoM size";
1387                 goto out;
1388         }
1389
1390         /*
1391          * if file has DoM layout already then migration is possible to
1392          * the new layout with the same DoM component via swap layout,
1393          * if new layout used bigger DOM size, then mirroring is used
1394          */
1395         if (dom_new > dom_cur) {
1396                 rc = lfs_migrate_to_dom(fd_src, fd_dst, name, migration_flags,
1397                                         bandwidth_bytes_sec, stats_flag,
1398                                         stats_interval_sec);
1399                 if (rc)
1400                         error_loc = "cannot migrate to DOM layout";
1401                 goto out_closed;
1402         }
1403
1404         if (stats_flag == STATS_ON)
1405                 printf("%s:\n", name);
1406
1407         if (!(migration_flags & LLAPI_MIGRATION_NONBLOCK)) {
1408                 /*
1409                  * Blocking mode (forced if servers do not support file lease).
1410                  * It is also the default mode, since we cannot distinguish
1411                  * between a broken lease and a server that does not support
1412                  * atomic swap/close (LU-6785)
1413                  */
1414                 rc = migrate_block(fd_src, fd_dst, bandwidth_bytes_sec,
1415                                    stats_flag, stats_interval_sec);
1416                 goto out;
1417         }
1418
1419         rc = llapi_lease_acquire(fd_src, LL_LEASE_RDLCK);
1420         if (rc < 0) {
1421                 error_loc = "cannot get lease";
1422                 goto out;
1423         }
1424
1425         rc = migrate_nonblock(fd_src, fd_dst, bandwidth_bytes_sec, stats_flag,
1426                               stats_interval_sec);
1427         if (rc < 0) {
1428                 llapi_lease_release(fd_src);
1429                 goto out;
1430         }
1431
1432         /*
1433          * Atomically put lease, swap layouts and close.
1434          * for a migration we need to check data version on file did
1435          * not change.
1436          */
1437         rc = llapi_fswap_layouts(fd_src, fd_dst, 0, 0, SWAP_LAYOUTS_CLOSE);
1438         if (rc < 0) {
1439                 error_loc = "cannot swap layout";
1440                 goto out;
1441         }
1442
1443 out:
1444         if (fd_src >= 0)
1445                 close(fd_src);
1446
1447         if (fd_dst >= 0)
1448                 close(fd_dst);
1449 out_closed:
1450         if (rc < 0)
1451                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1452                         progname, name, error_loc, strerror(-rc));
1453         else if (migration_flags & LLAPI_MIGRATION_VERBOSE)
1454                 printf("%s\n", name);
1455
1456         return rc;
1457 }
1458
1459 static int comp_str2flags(char *string, __u32 *flags, __u32 *neg_flags)
1460 {
1461         char *name;
1462         char *dup_string = NULL;
1463         int rc = 0;
1464
1465         *flags = 0;
1466         *neg_flags = 0;
1467
1468         if (!string || !string[0])
1469                 return -EINVAL;
1470
1471         dup_string = strdup(string);
1472         if (!dup_string) {
1473                 llapi_printf(LLAPI_MSG_ERROR,
1474                              "%s: insufficient memory\n",
1475                              progname);
1476                 return -ENOMEM;
1477         }
1478
1479         for (name = strtok(dup_string, ","); name; name = strtok(NULL, ",")) {
1480                 bool found = false;
1481                 int i;
1482
1483                 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1484                         __u32 comp_flag = comp_flags_table[i].cfn_flag;
1485                         const char *comp_name = comp_flags_table[i].cfn_name;
1486
1487                         if (strcmp(name, comp_name) == 0) {
1488                                 *flags |= comp_flag;
1489                                 found = true;
1490                         } else if (strncmp(name, "^", 1) == 0 &&
1491                                    strcmp(name + 1, comp_name) == 0) {
1492                                 *neg_flags |= comp_flag;
1493                                 found = true;
1494                         }
1495                 }
1496                 if (!found) {
1497                         llapi_printf(LLAPI_MSG_ERROR,
1498                                      "%s: component flag '%s' not supported\n",
1499                                      progname, name);
1500                         rc = -EINVAL;
1501                         goto out_free;
1502                 }
1503         }
1504
1505         if (!*flags && !*neg_flags)
1506                 rc = -EINVAL;
1507
1508         /* don't allow to set and exclude the same flag */
1509         if (*flags & *neg_flags)
1510                 rc = -EINVAL;
1511
1512 out_free:
1513         free(dup_string);
1514         return rc;
1515 }
1516
1517 static int mdthash_input(char *string, __u32 *inflags,
1518                          __u32 *exflags, __u32 *type)
1519 {
1520         char *name;
1521         struct mhf_list {
1522                 char *name;
1523                 __u32 flag;
1524         } mhflist[] = {
1525                 {"migrating", LMV_HASH_FLAG_MIGRATION},
1526                 {"bad_type", LMV_HASH_FLAG_BAD_TYPE},
1527                 {"badtype", LMV_HASH_FLAG_BAD_TYPE},
1528                 {"lost_lmv", LMV_HASH_FLAG_LOST_LMV},
1529                 {"lostlmv", LMV_HASH_FLAG_LOST_LMV},
1530         };
1531
1532         if (string == NULL)
1533                 return -EINVAL;
1534
1535         *inflags = 0;
1536         *exflags = 0;
1537         *type = 0;
1538         for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1539                 bool found = false;
1540                 int i;
1541
1542                 for (i = 0; i < ARRAY_SIZE(mhflist); i++) {
1543                         if (strcmp(name, mhflist[i].name) == 0 ||
1544                             name[0] == mhflist[i].name[0]) {
1545                                 *inflags |= mhflist[i].flag;
1546                                 found = true;
1547                         } else if (name[0] == '^' &&
1548                                    (strcmp(name + 1, mhflist[i].name) == 0 ||
1549                                     name[1] == mhflist[i].name[0])) {
1550                                 *exflags |= mhflist[i].flag;
1551                                 found = true;
1552                         }
1553                 }
1554                 if (!found) {
1555                         i = check_hashtype(name);
1556                         if (i > 0) {
1557                                 *type |= 1 << i;
1558                                 continue;
1559                         }
1560                         llapi_printf(LLAPI_MSG_ERROR,
1561                                      "%s: invalid mdt_hash value '%s'\n",
1562                                      progname, name);
1563                         return -EINVAL;
1564                 }
1565         }
1566
1567         /* don't allow to include and exclude the same flag */
1568         if (*inflags & *exflags) {
1569                 llapi_printf(LLAPI_MSG_ERROR,
1570                              "%s: include and exclude same flag '%s'\n",
1571                              progname, string);
1572                 return -EINVAL;
1573         }
1574
1575         return 0;
1576 }
1577
1578 static int mirror_str2state(char *string, __u16 *state, __u16 *neg_state)
1579 {
1580         if (!string)
1581                 return -EINVAL;
1582
1583         *state = 0;
1584         *neg_state = 0;
1585
1586         if (strncmp(string, "^", 1) == 0) {
1587                 *neg_state = llapi_layout_string_flags(string + 1);
1588                 if (*neg_state != 0)
1589                         return 0;
1590         } else {
1591                 *state = llapi_layout_string_flags(string);
1592                 if (*state != 0)
1593                         return 0;
1594         }
1595
1596         llapi_printf(LLAPI_MSG_ERROR,
1597                      "%s: mirrored file state '%s' not supported\n",
1598                      progname, string);
1599         return -EINVAL;
1600 }
1601
1602 /**
1603  * struct mirror_args - Command-line arguments for mirror(s).
1604  * @m_count:  Number of mirrors to be created with this layout.
1605  * @m_flags:  Mirror level flags, only 'prefer' is supported.
1606  * @m_layout: Mirror layout.
1607  * @m_file:   A victim file. Its layout will be split and used as a mirror.
1608  * @m_next:   Point to the next node of the list.
1609  *
1610  * Command-line arguments for mirror(s) will be parsed and stored in
1611  * a linked list that consists of this structure.
1612  */
1613 struct mirror_args {
1614         __u32                   m_count;
1615         __u32                   m_flags;
1616         struct llapi_layout     *m_layout;
1617         const char              *m_file;
1618         struct mirror_args      *m_next;
1619         bool                    m_inherit;
1620 };
1621
1622 /**
1623  * enum mirror_flags - Flags for extending a mirrored file.
1624  * @MF_NO_VERIFY: Indicates not to verify the mirror(s) from victim file(s)
1625  *             in case the victim file(s) contains the same data as the
1626  *             original mirrored file.
1627  * @MF_DESTROY: Indicates to delete the mirror from the mirrored file.
1628  * @MF_COMP_ID: specified component id instead of mirror id
1629  *
1630  * Flags for extending a mirrored file.
1631  */
1632 enum mirror_flags {
1633         MF_NO_VERIFY    = 0x1,
1634         MF_DESTROY      = 0x2,
1635         MF_COMP_ID      = 0x4,
1636         MF_COMP_POOL    = 0x8,
1637 };
1638
1639 /**
1640  * mirror_create_sanity_check() - Check mirror list.
1641  * @list:  A linked list that stores the mirror arguments.
1642  *
1643  * This function does a sanity check on @list for creating
1644  * a mirrored file.
1645  *
1646  * Return: 0 on success or a negative error code on failure.
1647  */
1648 static int mirror_create_sanity_check(const char *fname,
1649                                       struct mirror_args *list,
1650                                       bool check_fname)
1651 {
1652         int rc = 0;
1653         bool has_m_file = false;
1654         bool has_m_layout = false;
1655
1656         if (!list)
1657                 return -EINVAL;
1658
1659         if (fname && check_fname) {
1660                 struct llapi_layout *layout;
1661
1662                 layout = llapi_layout_get_by_path(fname, 0);
1663                 if (!layout) {
1664                         fprintf(stderr,
1665                                 "error: %s: file '%s' couldn't get layout\n",
1666                                 progname, fname);
1667                         return -ENODATA;
1668                 }
1669
1670                 rc = llapi_layout_sanity(layout, false, true);
1671
1672                 llapi_layout_free(layout);
1673
1674                 if (rc) {
1675                         llapi_layout_sanity_perror(rc);
1676                         return rc;
1677                 }
1678         }
1679
1680         while (list) {
1681                 if (list->m_file) {
1682                         has_m_file = true;
1683                         llapi_layout_free(list->m_layout);
1684
1685                         list->m_layout =
1686                                 llapi_layout_get_by_path(list->m_file, 0);
1687                         if (!list->m_layout) {
1688                                 fprintf(stderr,
1689                                         "error: %s: file '%s' has no layout\n",
1690                                         progname, list->m_file);
1691                                 return -ENODATA;
1692                         }
1693                 } else {
1694                         has_m_layout = true;
1695                         if (!list->m_layout) {
1696                                 fprintf(stderr, "error: %s: no mirror layout\n",
1697                                         progname);
1698                                 return -EINVAL;
1699                         }
1700                 }
1701
1702                 rc = llapi_layout_sanity(list->m_layout, false, true);
1703                 if (rc) {
1704                         llapi_layout_sanity_perror(rc);
1705                         return rc;
1706                 }
1707
1708                 list = list->m_next;
1709         }
1710
1711         if (has_m_file && has_m_layout) {
1712                 fprintf(stderr,
1713                         "error: %s: -f <victim_file> option should not be specified with setstripe options\n",
1714                         progname);
1715                 return -EINVAL;
1716         }
1717
1718         return 0;
1719 }
1720
1721 static int mirror_set_flags(struct llapi_layout *layout, void *cbdata)
1722 {
1723         __u32 mirror_flags = *(__u32 *)cbdata;
1724         uint32_t flags;
1725         int rc;
1726
1727         rc = llapi_layout_comp_flags_get(layout, &flags);
1728         if (rc < 0)
1729                 return rc;
1730
1731         if (!flags) {
1732                 rc = llapi_layout_comp_flags_set(layout, mirror_flags);
1733                 if (rc)
1734                         return rc;
1735         }
1736
1737         return LLAPI_LAYOUT_ITER_CONT;
1738 }
1739
1740 /**
1741  * mirror_create() - Create a mirrored file.
1742  * @fname:        The file to be created.
1743  * @mirror_list:  A linked list that stores the mirror arguments.
1744  *
1745  * This function creates a mirrored file @fname with the mirror(s)
1746  * from @mirror_list.
1747  *
1748  * Return: 0 on success or a negative error code on failure.
1749  */
1750 static int mirror_create(char *fname, struct mirror_args *mirror_list)
1751 {
1752         struct llapi_layout *layout = NULL;
1753         struct mirror_args *cur_mirror = NULL;
1754         uint16_t mirror_count = 0;
1755         int i = 0;
1756         int rc = 0;
1757
1758         rc = mirror_create_sanity_check(fname, mirror_list, false);
1759         if (rc)
1760                 return rc;
1761
1762         cur_mirror = mirror_list;
1763         while (cur_mirror) {
1764                 rc = llapi_layout_comp_iterate(cur_mirror->m_layout,
1765                                                mirror_set_flags,
1766                                                &cur_mirror->m_flags);
1767                 if (rc) {
1768                         rc = -errno;
1769                         fprintf(stderr, "%s: failed to set mirror flags\n",
1770                                 progname);
1771                         goto error;
1772                 }
1773
1774                 for (i = 0; i < cur_mirror->m_count; i++) {
1775                         rc = llapi_layout_merge(&layout, cur_mirror->m_layout);
1776                         if (rc) {
1777                                 rc = -errno;
1778                                 fprintf(stderr,
1779                                         "error: %s: merge layout failed: %s\n",
1780                                         progname, strerror(errno));
1781                                 goto error;
1782                         }
1783                 }
1784                 mirror_count += cur_mirror->m_count;
1785                 cur_mirror = cur_mirror->m_next;
1786         }
1787
1788         if (!layout) {
1789                 fprintf(stderr, "error: %s: layout is NULL\n", progname);
1790                 return -EINVAL;
1791         }
1792
1793         rc = llapi_layout_mirror_count_set(layout, mirror_count);
1794         if (rc) {
1795                 rc = -errno;
1796                 fprintf(stderr, "error: %s: set mirror count failed: %s\n",
1797                         progname, strerror(errno));
1798                 goto error;
1799         }
1800
1801         rc = lfs_component_create(fname, O_CREAT | O_WRONLY, 0666,
1802                                   layout);
1803         if (rc >= 0) {
1804                 close(rc);
1805                 rc = 0;
1806         }
1807
1808 error:
1809         llapi_layout_free(layout);
1810         return rc;
1811 }
1812
1813 /**
1814  * Compare files and check lease on @fd.
1815  *
1816  * \retval bytes number of bytes are the same
1817  */
1818 static ssize_t mirror_file_compare(int fd_src, int fd_dst)
1819 {
1820         const size_t buflen = 4 * 1024 * 1024; /* 4M */
1821         void *buf;
1822         ssize_t bytes_done = 0;
1823         ssize_t bytes_read = 0;
1824
1825         buf = malloc(buflen * 2);
1826         if (!buf)
1827                 return -ENOMEM;
1828
1829         while (1) {
1830                 if (!llapi_lease_check(fd_src)) {
1831                         bytes_done = -EBUSY;
1832                         break;
1833                 }
1834
1835                 bytes_read = read(fd_src, buf, buflen);
1836                 if (bytes_read <= 0)
1837                         break;
1838
1839                 if (bytes_read != read(fd_dst, buf + buflen, buflen))
1840                         break;
1841
1842                 /*
1843                  * XXX: should compute the checksum on each buffer and then
1844                  * compare checksum to avoid cache collision
1845                  */
1846                 if (memcmp(buf, buf + buflen, bytes_read))
1847                         break;
1848
1849                 bytes_done += bytes_read;
1850         }
1851
1852         free(buf);
1853
1854         return bytes_done;
1855 }
1856
1857 static int mirror_extend_file(const char *fname, const char *victim_file,
1858                               enum mirror_flags mirror_flags)
1859 {
1860         int fd = -1;
1861         int fdv = -1;
1862         struct stat stbuf;
1863         struct stat stbuf_v;
1864         struct ll_ioc_lease *data = NULL;
1865         int rc;
1866
1867         fd = open(fname, O_RDWR);
1868         if (fd < 0) {
1869                 error_loc = "open source file";
1870                 rc = -errno;
1871                 goto out;
1872         }
1873
1874         fdv = open(victim_file, O_RDWR);
1875         if (fdv < 0) {
1876                 error_loc = "open target file";
1877                 rc = -errno;
1878                 goto out;
1879         }
1880
1881         if (fstat(fd, &stbuf) || fstat(fdv, &stbuf_v)) {
1882                 error_loc = "stat source or target file";
1883                 rc = -errno;
1884                 goto out;
1885         }
1886
1887         if (stbuf.st_dev != stbuf_v.st_dev) {
1888                 error_loc = "stat source and target file";
1889                 rc = -EXDEV;
1890                 goto out;
1891         }
1892
1893         /* mirrors should be of the same size */
1894         if (stbuf.st_size != stbuf_v.st_size) {
1895                 error_loc = "file sizes don't match";
1896                 rc = -EINVAL;
1897                 goto out;
1898         }
1899
1900         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1901         if (rc < 0) {
1902                 error_loc = "cannot get lease";
1903                 goto out;
1904         }
1905
1906         if (!(mirror_flags & MF_NO_VERIFY)) {
1907                 ssize_t ret;
1908                 /* mirrors should have the same contents */
1909                 ret = mirror_file_compare(fd, fdv);
1910                 if (ret != stbuf.st_size) {
1911                         error_loc = "file busy or contents don't match";
1912                         rc = ret < 0 ? ret : -EINVAL;
1913                         goto out;
1914                 }
1915         }
1916
1917         /* Get rid of caching pages from clients */
1918         rc = llapi_file_flush(fd);
1919         if (rc < 0) {
1920                 error_loc = "cannot get data version";
1921                 goto out;
1922         }
1923
1924         rc = llapi_file_flush(fdv);
1925         if (rc < 0) {
1926                 error_loc = "cannot get data version";
1927                 goto out;
1928         }
1929
1930         rc = migrate_set_timestamps(fd, &stbuf);
1931         if (rc < 0) {
1932                 error_loc = "cannot set source file timestamp";
1933                 goto out;
1934         }
1935
1936         /* Atomically put lease, merge layouts and close. */
1937         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
1938         if (!data) {
1939                 error_loc = "memory allocation";
1940                 goto out;
1941         }
1942         data->lil_mode = LL_LEASE_UNLCK;
1943         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
1944         data->lil_count = 1;
1945         data->lil_ids[0] = fdv;
1946         rc = llapi_lease_set(fd, data);
1947         if (rc < 0) {
1948                 error_loc = "cannot merge layout";
1949                 goto out;
1950         } else if (rc == 0) {
1951                 rc = -EBUSY;
1952                 error_loc = "lost lease lock";
1953                 goto out;
1954         }
1955         rc = 0;
1956
1957 out:
1958         if (data)
1959                 free(data);
1960         if (fd >= 0)
1961                 close(fd);
1962         if (fdv >= 0)
1963                 close(fdv);
1964         if (!rc)
1965                 (void) unlink(victim_file);
1966         if (rc < 0)
1967                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1968                         progname, fname, error_loc, strerror(-rc));
1969         return rc;
1970 }
1971
1972 static int mirror_extend_layout(char *name, struct llapi_layout *m_layout,
1973                                 bool inherit, uint32_t flags,
1974                                 unsigned long long bandwidth_bytes_sec,
1975                                 enum stats_flag stats_flag,
1976                                 long stats_interval_sec)
1977 {
1978         struct llapi_layout *f_layout = NULL;
1979         struct ll_ioc_lease *data = NULL;
1980         struct stat st;
1981         int fd_src = -1;
1982         int fd_dst = -1;
1983         int rc = 0;
1984
1985         if (inherit) {
1986                 f_layout = llapi_layout_get_by_path(name, 0);
1987                 if (!f_layout) {
1988                         rc = -EINVAL;
1989                         fprintf(stderr, "%s: cannot get layout\n", progname);
1990                         goto out;
1991                 }
1992                 rc = llapi_layout_get_last_init_comp(f_layout);
1993                 if (rc) {
1994                         fprintf(stderr, "%s: cannot get the last init comp\n",
1995                                 progname);
1996                         goto out;
1997                 }
1998                 rc = llapi_layout_mirror_inherit(f_layout, m_layout);
1999                 if (rc) {
2000                         fprintf(stderr,
2001                                 "%s: cannot inherit from the last init comp\n",
2002                                 progname);
2003                         goto out;
2004                 }
2005         }
2006
2007         llapi_layout_comp_flags_set(m_layout, flags);
2008         rc = migrate_open_files(name,
2009                              LLAPI_MIGRATION_NONDIRECT | LLAPI_MIGRATION_MIRROR,
2010                              NULL, m_layout, &fd_src, &fd_dst);
2011         if (rc < 0)
2012                 goto out;
2013
2014         rc = llapi_lease_acquire(fd_src, LL_LEASE_RDLCK);
2015         if (rc < 0) {
2016                 error_loc = "cannot get lease";
2017                 goto out;
2018         }
2019
2020         rc = fstat(fd_src, &st);
2021         if (rc < 0) {
2022                 error_loc = "cannot stat source file";
2023                 goto out;
2024         }
2025
2026         if (stats_flag)
2027                 printf("%s:\n", name);
2028
2029         rc = migrate_nonblock(fd_src, fd_dst, bandwidth_bytes_sec, stats_flag,
2030                               stats_interval_sec);
2031         if (rc < 0) {
2032                 llapi_lease_release(fd_src);
2033                 goto out;
2034         }
2035
2036         rc = migrate_set_timestamps(fd_src, &st);
2037         if (rc < 0) {
2038                 error_loc = "cannot set source file timestamp";
2039                 goto out;
2040         }
2041
2042         /* Atomically put lease, merge layouts and close. */
2043         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
2044         if (!data) {
2045                 error_loc = "memory allocation";
2046                 goto out;
2047         }
2048         data->lil_mode = LL_LEASE_UNLCK;
2049         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
2050         data->lil_count = 1;
2051         data->lil_ids[0] = fd_dst;
2052         rc = llapi_lease_set(fd_src, data);
2053         if (rc < 0) {
2054                 error_loc = "cannot merge layout";
2055                 goto out;
2056         } else if (rc == 0) {
2057                 rc = -EBUSY;
2058                 error_loc = "lost lease lock";
2059                 goto out;
2060         }
2061         rc = 0;
2062
2063 out:
2064         if (data)
2065                 free(data);
2066         if (fd_src >= 0)
2067                 close(fd_src);
2068         if (fd_dst >= 0)
2069                 close(fd_dst);
2070         if (rc < 0)
2071                 fprintf(stderr, "error: %s: %s: %s: %s\n",
2072                         progname, name, error_loc, strerror(-rc));
2073         return rc;
2074 }
2075
2076 static int mirror_extend(char *fname, struct mirror_args *mirror_list,
2077                          enum mirror_flags mirror_flags,
2078                          unsigned long long bandwidth_bytes_sec,
2079                          enum stats_flag stats_flag, long stats_interval_sec)
2080 {
2081         int rc = 0;
2082
2083         while (mirror_list) {
2084                 if (mirror_list->m_file) {
2085                         rc = mirror_extend_file(fname, mirror_list->m_file,
2086                                                 mirror_flags);
2087                 } else {
2088                         __u32 mirror_count = mirror_list->m_count;
2089
2090                         while (mirror_count > 0) {
2091                                 rc = mirror_extend_layout(fname,
2092                                                         mirror_list->m_layout,
2093                                                         mirror_list->m_inherit,
2094                                                         mirror_list->m_flags,
2095                                                         bandwidth_bytes_sec,
2096                                                         stats_flag,
2097                                                         stats_interval_sec);
2098                                 if (rc)
2099                                         break;
2100
2101                                 --mirror_count;
2102                         }
2103                 }
2104                 if (rc)
2105                         break;
2106
2107                 mirror_list = mirror_list->m_next;
2108         }
2109
2110         return rc;
2111 }
2112
2113 static int find_mirror_id(struct llapi_layout *layout, void *cbdata)
2114 {
2115         uint32_t id;
2116         int rc;
2117
2118         rc = llapi_layout_mirror_id_get(layout, &id);
2119         if (rc < 0)
2120                 return rc;
2121
2122         if ((__u16)id == *(__u16 *)cbdata)
2123                 return LLAPI_LAYOUT_ITER_STOP;
2124
2125         return LLAPI_LAYOUT_ITER_CONT;
2126 }
2127
2128 static int find_comp_id(struct llapi_layout *layout, void *cbdata)
2129 {
2130         uint32_t id;
2131         int rc;
2132
2133         rc = llapi_layout_comp_id_get(layout, &id);
2134         if (rc < 0)
2135                 return rc;
2136
2137         if (id == *(__u32 *)cbdata)
2138                 return LLAPI_LAYOUT_ITER_STOP;
2139
2140         return LLAPI_LAYOUT_ITER_CONT;
2141 }
2142
2143 static int find_mirror_id_by_pool(struct llapi_layout *layout, void *cbdata)
2144 {
2145         char buf[LOV_MAXPOOLNAME + 1];
2146         struct pool_to_id_cbdata *d = (void *)cbdata;
2147         uint32_t id;
2148         int rc;
2149
2150         rc = llapi_layout_pool_name_get(layout, buf, sizeof(buf));
2151         if (rc < 0)
2152                 return rc;
2153         if (strcmp(d->pool, buf))
2154                 return LLAPI_LAYOUT_ITER_CONT;
2155
2156         rc = llapi_layout_mirror_id_get(layout, &id);
2157         if (rc < 0)
2158                 return rc;
2159         d->id = id;
2160
2161         return LLAPI_LAYOUT_ITER_STOP;
2162 }
2163
2164 static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata)
2165 {
2166         char buf[LOV_MAXPOOLNAME + 1];
2167         struct pool_to_id_cbdata *d = (void *)cbdata;
2168         uint32_t id;
2169         int rc;
2170
2171         rc = llapi_layout_pool_name_get(layout, buf, sizeof(buf));
2172         if (rc < 0)
2173                 return rc;
2174         if (strcmp(d->pool, buf))
2175                 return LLAPI_LAYOUT_ITER_CONT;
2176
2177         rc = llapi_layout_comp_id_get(layout, &id);
2178         if (rc < 0)
2179                 return rc;
2180         d->id = id;
2181
2182         return LLAPI_LAYOUT_ITER_STOP;
2183 }
2184
2185 struct collect_ids_data {
2186         __u16   *cid_ids;
2187         int     cid_count;
2188         __u16   cid_exclude;
2189 };
2190
2191 static int collect_mirror_id(struct llapi_layout *layout, void *cbdata)
2192 {
2193         struct collect_ids_data *cid = cbdata;
2194         uint32_t id;
2195         int rc;
2196
2197         rc = llapi_layout_mirror_id_get(layout, &id);
2198         if (rc < 0)
2199                 return rc;
2200
2201         if ((__u16)id != cid->cid_exclude) {
2202                 int i;
2203
2204                 for (i = 0; i < cid->cid_count; i++) {
2205                         /* already collected the mirror id */
2206                         if (id == cid->cid_ids[i])
2207                                 return LLAPI_LAYOUT_ITER_CONT;
2208                 }
2209                 cid->cid_ids[cid->cid_count] = id;
2210                 cid->cid_count++;
2211         }
2212
2213         return LLAPI_LAYOUT_ITER_CONT;
2214 }
2215
2216 /**
2217  * last_non_stale_mirror() - Check if a mirror is the last non-stale mirror.
2218  * @mirror_id: Mirror id to be checked.
2219  * @layout:    Mirror component list.
2220  *
2221  * This function checks if a mirror with specified @mirror_id is the last
2222  * non-stale mirror of a layout @layout.
2223  *
2224  * Return: true or false.
2225  */
2226 static inline
2227 bool last_non_stale_mirror(__u16 mirror_id, struct llapi_layout *layout)
2228 {
2229         __u16 mirror_ids[128] = { 0 };
2230         struct collect_ids_data cid = { .cid_ids = mirror_ids,
2231                                         .cid_count = 0,
2232                                         .cid_exclude = mirror_id, };
2233         int i;
2234
2235         llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
2236
2237         for (i = 0; i < cid.cid_count; i++) {
2238                 struct llapi_resync_comp comp_array[1024] = { { 0 } };
2239                 int comp_size = 0;
2240
2241                 comp_size = llapi_mirror_find_stale(layout, comp_array,
2242                                                     ARRAY_SIZE(comp_array),
2243                                                     &mirror_ids[i], 1);
2244                 if (comp_size == 0)
2245                         return false;
2246         }
2247
2248         return true;
2249 }
2250
2251 static int mirror_split(const char *fname, __u32 id, const char *pool,
2252                         enum mirror_flags mflags, const char *victim_file)
2253 {
2254         struct llapi_layout *layout;
2255         char parent[PATH_MAX];
2256         char victim[PATH_MAX];
2257         int flags = O_CREAT | O_EXCL | O_LOV_DELAY_CREATE | O_NOFOLLOW;
2258         char *ptr;
2259         struct ll_ioc_lease *data;
2260         uint16_t mirror_count;
2261         __u32 mirror_id;
2262         int mdt_index;
2263         int fd, fdv;
2264         bool purge = true; /* delete mirror by setting fdv=fd */
2265         bool is_encrypted;
2266         int rc;
2267
2268         if (victim_file && (strcmp(fname, victim_file) == 0)) {
2269                 fprintf(stderr,
2270                         "error %s: the source file '%s' and -f file are the same\n",
2271                         progname, fname);
2272                 return -EINVAL;
2273         }
2274
2275         /* check fname contains mirror with mirror_id/comp_id */
2276         layout = llapi_layout_get_by_path(fname, 0);
2277         if (!layout) {
2278                 fprintf(stderr,
2279                         "error %s: file '%s' couldn't get layout\n",
2280                         progname, fname);
2281                 return -EINVAL;
2282         }
2283
2284         rc = llapi_layout_sanity(layout, false, true);
2285         if (rc) {
2286                 llapi_layout_sanity_perror(rc);
2287                 goto free_layout;
2288         }
2289
2290         rc = llapi_layout_mirror_count_get(layout, &mirror_count);
2291         if (rc) {
2292                 fprintf(stderr,
2293                         "error %s: file '%s' couldn't get mirror count\n",
2294                         progname, fname);
2295                 goto free_layout;
2296         }
2297         if (mirror_count < 2) {
2298                 fprintf(stderr,
2299                         "error %s: file '%s' has %d component, cannot split\n",
2300                         progname, fname, mirror_count);
2301                 goto free_layout;
2302         }
2303
2304         if (mflags & MF_COMP_POOL) {
2305                 struct pool_to_id_cbdata data = { .pool = pool };
2306
2307                 rc = llapi_layout_comp_iterate(layout, find_mirror_id_by_pool,
2308                                                &data);
2309                 mirror_id = data.id;
2310         } else if (mflags & MF_COMP_ID) {
2311                 rc = llapi_layout_comp_iterate(layout, find_comp_id, &id);
2312                 mirror_id = mirror_id_of(id);
2313         } else {
2314                 rc = llapi_layout_comp_iterate(layout, find_mirror_id, &id);
2315                 mirror_id = id;
2316         }
2317         if (rc < 0) {
2318                 fprintf(stderr, "error %s: failed to iterate layout of '%s'\n",
2319                         progname, fname);
2320                 goto free_layout;
2321         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
2322                 if (mflags & MF_COMP_POOL) {
2323                         fprintf(stderr,
2324                                 "error %s: file '%s' does not contain mirror with pool '%s'\n",
2325                                 progname, fname, pool);
2326                         goto free_layout;
2327                 } else if (mflags & MF_COMP_ID) {
2328                         fprintf(stderr,
2329                                 "error %s: file '%s' does not contain mirror with comp-id %u\n",
2330                                 progname, fname, id);
2331                         goto free_layout;
2332                 } else {
2333                         fprintf(stderr,
2334                                 "error %s: file '%s' does not contain mirror with id %u\n",
2335                                 progname, fname, id);
2336                         goto free_layout;
2337                 }
2338         }
2339
2340         if (!victim_file && mflags & MF_DESTROY)
2341                 /* Allow mirror split even without the key on encrypted files,
2342                  * and in this case of a 'split -d', open file with O_DIRECT
2343                  * (no IOs will be done).
2344                  */
2345                 fd = open(fname, O_RDWR | O_DIRECT | O_FILE_ENC);
2346         else
2347                 fd = open(fname, O_RDWR);
2348
2349         if (fd < 0) {
2350                 fprintf(stderr,
2351                         "error %s: open file '%s' failed: %s\n",
2352                         progname, fname, strerror(errno));
2353                 goto free_layout;
2354         }
2355
2356         /* get victim file directory pathname */
2357         if (strlen(fname) > sizeof(parent) - 1) {
2358                 fprintf(stderr, "error %s: file name of '%s' too long\n",
2359                         progname, fname);
2360                 rc = -ERANGE;
2361                 goto close_fd;
2362         }
2363         strncpy(parent, fname, sizeof(parent));
2364         ptr = strrchr(parent, '/');
2365         if (!ptr) {
2366                 if (!getcwd(parent, sizeof(parent))) {
2367                         fprintf(stderr, "error %s: getcwd failed: %s\n",
2368                                 progname, strerror(errno));
2369                         rc = -errno;
2370                         goto close_fd;
2371                 }
2372         } else {
2373                 if (ptr == parent)
2374                         ptr = parent + 1;
2375                 *ptr = '\0';
2376         }
2377
2378         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
2379         if (rc < 0) {
2380                 fprintf(stderr, "%s: cannot get MDT index of '%s'\n",
2381                         progname, fname);
2382                 goto close_fd;
2383         }
2384
2385         rc = llapi_file_is_encrypted(fd);
2386         if (rc < 0) {
2387                 fprintf(stderr, "%s: cannot get flags of '%s': %d\n",
2388                         progname, fname, rc);
2389                 goto close_fd;
2390         }
2391         is_encrypted = rc;
2392
2393 again:
2394         if (!victim_file) {
2395                 /* use a temp file to store the splitted layout */
2396                 if (mflags & MF_DESTROY) {
2397                         char file_path[PATH_MAX];
2398                         unsigned int rnumber;
2399                         int open_flags;
2400
2401                         if (last_non_stale_mirror(mirror_id, layout)) {
2402                                 rc = -EUCLEAN;
2403                                 fprintf(stderr,
2404                                         "%s: cannot destroy the last non-stale mirror of file '%s'\n",
2405                                         progname, fname);
2406                                 goto close_fd;
2407                         }
2408
2409                         if (purge) {
2410                                 /* don't use volatile file for mirror destroy */
2411                                 fdv = fd;
2412                         } else {
2413                                 /**
2414                                  * try the old way to delete mirror using
2415                                  * volatile file.
2416                                  */
2417                                 do {
2418                                         rnumber = random();
2419                                         rc = snprintf(file_path,
2420                                                       sizeof(file_path),
2421                                                       "%s/" LUSTRE_VOLATILE_HDR ":%.4X:%.4X:fd=%.2d",
2422                                                       parent, mdt_index,
2423                                                       rnumber, fd);
2424                                         if (rc < 0 ||
2425                                             rc >= sizeof(file_path)) {
2426                                                 fdv = -ENAMETOOLONG;
2427                                                 break;
2428                                         }
2429
2430                                         open_flags = O_RDWR |
2431                                              (O_LOV_DELAY_CREATE & ~O_ACCMODE) |
2432                                              O_CREAT | O_EXCL | O_NOFOLLOW |
2433                                              /* O_DIRECT for mirror split -d */
2434                                              O_DIRECT |
2435                                              /* Allow split without the key */
2436                                              O_FILE_ENC;
2437                                         fdv = open(file_path, open_flags,
2438                                                    S_IRUSR | S_IWUSR);
2439                                         if (fdv < 0)
2440                                                 rc = -errno;
2441                                 } while (fdv < 0 && rc == -EEXIST);
2442                         }
2443                 } else {
2444                         if (is_encrypted) {
2445                                 rc = -1;
2446                                 fprintf(stderr,
2447                                         "error %s: not permitted on encrypted file '%s': %d\n",
2448                                         progname, fname, rc);
2449                                 goto close_fd;
2450                         }
2451
2452                         snprintf(victim, sizeof(victim), "%s.mirror~%u",
2453                                  fname, mirror_id);
2454                         fdv = open(victim, flags, S_IRUSR | S_IWUSR);
2455                 }
2456         } else {
2457                 /* user specified victim file */
2458                 if (is_encrypted) {
2459                         rc = -1;
2460                         fprintf(stderr,
2461                                 "error %s: not permitted on encrypted file '%s': %d\n",
2462                                 progname, fname, rc);
2463                         goto close_fd;
2464                 }
2465                 fdv = open(victim_file, flags, S_IRUSR | S_IWUSR);
2466         }
2467
2468         if (fdv < 0) {
2469                 fprintf(stderr,
2470                         "error %s: create victim file failed: %s\n",
2471                         progname, strerror(errno));
2472                 goto close_fd;
2473         }
2474
2475         /* get lease lock of fname */
2476         rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
2477         if (rc < 0) {
2478                 fprintf(stderr,
2479                         "error %s: cannot get lease of file '%s': %d\n",
2480                         progname, fname, rc);
2481                 goto close_victim;
2482         }
2483
2484         /* Atomatically put lease, split layouts and close. */
2485         data = malloc(offsetof(typeof(*data), lil_ids[2]));
2486         if (!data) {
2487                 rc = -ENOMEM;
2488                 goto close_victim;
2489         }
2490
2491         data->lil_mode = LL_LEASE_UNLCK;
2492         data->lil_flags = LL_LEASE_LAYOUT_SPLIT;
2493         data->lil_count = 2;
2494         data->lil_ids[0] = fdv;
2495         data->lil_ids[1] = mirror_id;
2496         rc = llapi_lease_set(fd, data);
2497         if (rc <= 0) {
2498                 if ((rc == -EINVAL || rc == -EBUSY) && purge) {
2499                         /* could be old MDS which prohibit fd==fdv */
2500                         purge = false;
2501                         goto again;
2502
2503                 }
2504                 if (rc == 0) /* lost lease lock */
2505                         rc = -EBUSY;
2506                 fprintf(stderr,
2507                         "error %s: cannot split '%s': %s\n",
2508                         progname, fname, strerror(-rc));
2509         } else {
2510                 rc = 0;
2511         }
2512         free(data);
2513
2514 close_victim:
2515         if (!purge)
2516                 close(fdv);
2517 close_fd:
2518         close(fd);
2519 free_layout:
2520         llapi_layout_free(layout);
2521         return rc;
2522 }
2523
2524 static inline
2525 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
2526                            __u16 *mirror_ids, int ids_nr);
2527
2528 static int lfs_migrate_to_dom(int fd_src, int fd_dst, char *name,
2529                               __u64 migration_flags,
2530                               unsigned long long bandwidth_bytes_sec,
2531                               enum stats_flag stats_flag,
2532                               long stats_interval_sec)
2533 {
2534         struct ll_ioc_lease *data = NULL;
2535         int rc;
2536
2537         rc = llapi_lease_acquire(fd_src, LL_LEASE_RDLCK);
2538         if (rc < 0) {
2539                 error_loc = "cannot get lease";
2540                 goto out_close;
2541         }
2542
2543         if (stats_flag)
2544                 printf("%s:\n", name);
2545
2546         rc = migrate_nonblock(fd_src, fd_dst, bandwidth_bytes_sec, stats_flag,
2547                               stats_interval_sec);
2548         if (rc < 0)
2549                 goto out_release;
2550
2551         /* Atomically put lease, merge layouts, resync and close. */
2552         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
2553         if (!data) {
2554                 error_loc = "memory allocation";
2555                 goto out_release;
2556         }
2557         data->lil_mode = LL_LEASE_UNLCK;
2558         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
2559         data->lil_count = 1;
2560         data->lil_ids[0] = fd_dst;
2561         rc = llapi_lease_set(fd_src, data);
2562         if (rc < 0) {
2563                 error_loc = "cannot merge layout";
2564                 goto out_close;
2565         } else if (rc == 0) {
2566                 rc = -EBUSY;
2567                 error_loc = "lost lease lock";
2568                 goto out_close;
2569         }
2570         close(fd_src);
2571         close(fd_dst);
2572
2573         rc = lfs_mirror_resync_file(name, data, NULL, 0);
2574         if (rc) {
2575                 error_loc = "cannot resync file";
2576                 goto out;
2577         }
2578
2579         /* delete first mirror now */
2580         rc = mirror_split(name, 1, NULL, MF_DESTROY, NULL);
2581         if (rc < 0)
2582                 error_loc = "cannot delete old layout";
2583         goto out;
2584
2585 out_release:
2586         llapi_lease_release(fd_src);
2587 out_close:
2588         close(fd_src);
2589         close(fd_dst);
2590 out:
2591         if (rc < 0)
2592                 fprintf(stderr, "error: %s: %s: %s: %s\n",
2593                         progname, name, error_loc, strerror(-rc));
2594         else if (migration_flags & LLAPI_MIGRATION_VERBOSE)
2595                 printf("%s\n", name);
2596         if (data)
2597                 free(data);
2598         return rc;
2599 }
2600
2601 /**
2602  * Parse a string containing an target index list into an array of integers.
2603  *
2604  * The input string contains a comma delimited list of individual
2605  * indices and ranges, for example "1,2-4,7". Add the indices into the
2606  * \a tgts array and remove duplicates.
2607  *
2608  * \param[out] tgts             array to store indices in
2609  * \param[in] size              size of \a tgts array
2610  * \param[in] offset            starting index in \a tgts
2611  * \param[in] arg               string containing OST index list
2612  * \param[in/out] overstriping  index list may contain duplicates
2613  *
2614  * \retval positive    number of indices in \a tgts
2615  * \retval -EINVAL     unable to parse \a arg
2616  */
2617 static int parse_targets(__u32 *tgts, int size, int offset, char *arg,
2618                          unsigned long long *pattern)
2619 {
2620         int rc;
2621         int nr = offset;
2622         int slots = size - offset;
2623         char *ptr = NULL;
2624         bool overstriped = false;
2625         bool end_of_loop;
2626
2627         if (!arg)
2628                 return -EINVAL;
2629
2630         end_of_loop = false;
2631         while (!end_of_loop) {
2632                 int start_index = 0;
2633                 int end_index = 0;
2634                 int i;
2635                 char *endptr = NULL;
2636
2637                 rc = -EINVAL;
2638
2639                 ptr = strchrnul(arg, ',');
2640
2641                 end_of_loop = *ptr == '\0';
2642                 *ptr = '\0';
2643
2644                 errno = 0;
2645                 start_index = strtol(arg, &endptr, 0);
2646                 if (endptr == arg) /* no data at all */
2647                         break;
2648                 if (errno != 0 || start_index < -1 ||
2649                     (*endptr != '-' && *endptr != '\0'))
2650                         break;
2651
2652                 end_index = start_index;
2653                 if (*endptr == '-') {
2654                         errno = 0;
2655                         end_index = strtol(endptr + 1, &endptr, 0);
2656                         if (errno != 0 || *endptr != '\0' || end_index < -1)
2657                                 break;
2658                         if (end_index < start_index)
2659                                 break;
2660                 }
2661
2662                 for (i = start_index; i <= end_index && slots > 0; i++) {
2663                         int j;
2664
2665                         /* remove duplicate */
2666                         for (j = 0; j < offset; j++) {
2667                                 if (tgts[j] == i && pattern &&
2668                                     *pattern == LLAPI_LAYOUT_OVERSTRIPING)
2669                                         overstriped = true;
2670                                 else if (tgts[j] == i)
2671                                         return -EINVAL;
2672                         }
2673
2674                         j = offset;
2675
2676                         if (j == offset) { /* check complete */
2677                                 tgts[nr++] = i;
2678                                 --slots;
2679                         }
2680                 }
2681
2682                 if (slots == 0 && i < end_index)
2683                         break;
2684
2685                 *ptr = ',';
2686                 arg = ++ptr;
2687                 offset = nr;
2688                 rc = 0;
2689         }
2690         if (!end_of_loop && ptr)
2691                 *ptr = ',';
2692
2693         if (!overstriped && pattern)
2694                 *pattern = LLAPI_LAYOUT_DEFAULT;
2695
2696         return rc < 0 ? rc : nr;
2697 }
2698
2699 struct lfs_setstripe_args {
2700         unsigned long long       lsa_comp_end;
2701         unsigned long long       lsa_stripe_size;
2702         unsigned long long       lsa_extension_size;
2703         long long                lsa_stripe_count;
2704         long long                lsa_stripe_off;
2705         __u32                    lsa_comp_flags;
2706         __u32                    lsa_comp_neg_flags;
2707         unsigned long long       lsa_pattern;
2708         unsigned int             lsa_mirror_count;
2709         int                      lsa_nr_tgts;
2710         bool                     lsa_first_comp;
2711         bool                     lsa_extension_comp;
2712         __u32                   *lsa_tgts;
2713         char                    *lsa_pool_name;
2714 };
2715
2716 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
2717 {
2718         unsigned int mirror_count = lsa->lsa_mirror_count;
2719         bool first_comp = lsa->lsa_first_comp;
2720
2721         memset(lsa, 0, sizeof(*lsa));
2722
2723         lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
2724         lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
2725         lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2726         lsa->lsa_pattern = LLAPI_LAYOUT_RAID0;
2727         lsa->lsa_pool_name = NULL;
2728
2729         lsa->lsa_mirror_count = mirror_count;
2730         lsa->lsa_first_comp = first_comp;
2731 }
2732
2733 /**
2734  * setstripe_args_init_inherit() - Initialize and inherit stripe options.
2735  * @lsa: Stripe options to be initialized and inherited.
2736  *
2737  * This function initializes stripe options in @lsa and inherit
2738  * stripe_size, stripe_count and OST pool_name options.
2739  *
2740  * Return: void.
2741  */
2742 static inline void setstripe_args_init_inherit(struct lfs_setstripe_args *lsa)
2743 {
2744         unsigned long long stripe_size;
2745         long long stripe_count;
2746         char *pool_name = NULL;
2747
2748         stripe_size = lsa->lsa_stripe_size;
2749         stripe_count = lsa->lsa_stripe_count;
2750         pool_name = lsa->lsa_pool_name;
2751
2752         setstripe_args_init(lsa);
2753
2754         lsa->lsa_stripe_size = stripe_size;
2755         lsa->lsa_stripe_count = stripe_count;
2756         lsa->lsa_pool_name = pool_name;
2757 }
2758
2759 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
2760 {
2761         return (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT ||
2762                 lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ||
2763                 lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
2764                 lsa->lsa_pattern != LLAPI_LAYOUT_RAID0 ||
2765                 lsa->lsa_comp_end != 0);
2766 }
2767
2768 static int lsa_args_stripe_count_check(struct lfs_setstripe_args *lsa)
2769 {
2770         if (lsa->lsa_nr_tgts) {
2771                 if (lsa->lsa_nr_tgts < 0 ||
2772                     lsa->lsa_nr_tgts >= LOV_MAX_STRIPE_COUNT) {
2773                         fprintf(stderr, "Invalid nr_tgts(%d)\n",
2774                                 lsa->lsa_nr_tgts);
2775                         errno = EINVAL;
2776                         return -1;
2777                 }
2778
2779                 if (lsa->lsa_stripe_count > 0 &&
2780                     lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
2781                     lsa->lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
2782                     lsa->lsa_nr_tgts != lsa->lsa_stripe_count) {
2783                         fprintf(stderr, "stripe_count(%lld) != nr_tgts(%d)\n",
2784                                 lsa->lsa_stripe_count,
2785                                 lsa->lsa_nr_tgts);
2786                         errno = EINVAL;
2787                         return -1;
2788                 }
2789         }
2790
2791         return 0;
2792
2793 }
2794
2795 /**
2796  * comp_args_to_layout() - Create or extend a composite layout.
2797  * @composite:       Pointer to the composite layout.
2798  * @lsa:             Stripe options for the new component.
2799  *
2800  * This function creates or extends a composite layout by adding a new
2801  * component with stripe options from @lsa.
2802  *
2803  * When modified, adjust llapi_stripe_param_verify() if needed as well.
2804  *
2805  * Return: 0 on success or an error code on failure.
2806  */
2807 static int comp_args_to_layout(struct llapi_layout **composite,
2808                                struct lfs_setstripe_args *lsa,
2809                                bool set_extent)
2810 {
2811         struct llapi_layout *layout = *composite;
2812         uint64_t prev_end = 0;
2813         uint64_t size;
2814         int i = 0, rc;
2815
2816 new_comp:
2817         if (!layout) {
2818                 layout = llapi_layout_alloc();
2819                 if (!layout) {
2820                         fprintf(stderr, "Alloc llapi_layout failed. %s\n",
2821                                 strerror(errno));
2822                         errno = ENOMEM;
2823                         return -1;
2824                 }
2825                 *composite = layout;
2826                 lsa->lsa_first_comp = true;
2827         } else {
2828                 uint64_t start;
2829
2830                 /*
2831                  * Get current component extent, current component
2832                  * must be the tail component.
2833                  */
2834                 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
2835                 if (rc) {
2836                         fprintf(stderr, "Get comp extent failed. %s\n",
2837                                 strerror(errno));
2838                         return rc;
2839                 }
2840
2841                 if (lsa->lsa_first_comp) {
2842                         prev_end = 0;
2843                         rc = llapi_layout_add_first_comp(layout);
2844                 } else {
2845                         rc = llapi_layout_comp_add(layout);
2846                 }
2847                 if (rc) {
2848                         fprintf(stderr, "Add component failed. %s\n",
2849                                 strerror(errno));
2850                         return rc;
2851                 }
2852         }
2853
2854         rc = llapi_layout_comp_flags_set(layout, lsa->lsa_comp_flags);
2855         if (rc) {
2856                 fprintf(stderr, "Set flags 0x%x failed: %s\n",
2857                         lsa->lsa_comp_flags, strerror(errno));
2858                 return rc;
2859         }
2860
2861         if (set_extent) {
2862                 uint64_t comp_end = lsa->lsa_comp_end;
2863
2864                 /*
2865                  * The extendable component is 0-length, so it can be removed
2866                  * if there is insufficient space to extend it.
2867                  */
2868                 if (lsa->lsa_extension_comp)
2869                         comp_end = prev_end;
2870
2871                 rc = llapi_layout_comp_extent_set(layout, prev_end,
2872                                                   comp_end);
2873                 if (rc) {
2874                         fprintf(stderr, "Set extent [%lu, %lu) failed. %s\n",
2875                                 prev_end, comp_end, strerror(errno));
2876                         return rc;
2877                 }
2878         }
2879         /* reset lsa_first_comp */
2880         lsa->lsa_first_comp = false;
2881
2882         /* Data-on-MDT component setting */
2883         if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
2884                 /* Yaml support */
2885                 if (lsa->lsa_stripe_count == 0)
2886                         lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
2887                 if (lsa->lsa_stripe_size == lsa->lsa_comp_end)
2888                         lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
2889                 if (lsa->lsa_stripe_off == -1 ||
2890                     lsa->lsa_stripe_off == 0)
2891                         lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2892                 /*
2893                  * In case of Data-on-MDT patterns the only extra option
2894                  * applicable is stripe size option.
2895                  */
2896                 if (lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
2897                         fprintf(stderr,
2898                                 "Option 'stripe-count' can't be specified with Data-on-MDT component: %lld\n",
2899                                 lsa->lsa_stripe_count);
2900                         errno = EINVAL;
2901                         return -1;
2902                 }
2903                 if (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT &&
2904                     lsa->lsa_stripe_size != lsa->lsa_comp_end - prev_end) {
2905                         fprintf(stderr,
2906                                 "Option 'stripe-size' can't be specified with Data-on-MDT component: %llu\n",
2907                                 lsa->lsa_stripe_size);
2908                         errno = EINVAL;
2909                         return -1;
2910                 }
2911                 if (lsa->lsa_nr_tgts != 0) {
2912                         fprintf(stderr,
2913                                 "Option 'ost-list' can't be specified with Data-on-MDT component: '%i'\n",
2914                                 lsa->lsa_nr_tgts);
2915                         errno = EINVAL;
2916                         return -1;
2917                 }
2918                 if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
2919                         fprintf(stderr,
2920                                 "Option 'stripe-offset' can't be specified with Data-on-MDT component: %lld\n",
2921                                 lsa->lsa_stripe_off);
2922                         errno = EINVAL;
2923                         return -1;
2924                 }
2925                 if (lsa->lsa_pool_name != 0) {
2926                         fprintf(stderr,
2927                                 "Option 'pool' can't be specified with Data-on-MDT component: '%s'\n",
2928                                 lsa->lsa_pool_name);
2929                         errno = EINVAL;
2930                         return -1;
2931                 }
2932
2933                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
2934                 if (rc) {
2935                         fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
2936                                 lsa->lsa_pattern,
2937                                 strerror(errno));
2938                         return rc;
2939                 }
2940                 /* Data-on-MDT component has always single stripe up to end */
2941                 lsa->lsa_stripe_size = lsa->lsa_comp_end;
2942         } else if (lsa->lsa_pattern == LLAPI_LAYOUT_OVERSTRIPING) {
2943                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
2944                 if (rc) {
2945                         fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
2946                                 lsa->lsa_pattern,
2947                                 strerror(errno));
2948                         return rc;
2949                 }
2950         }
2951
2952         size = lsa->lsa_comp_flags & LCME_FL_EXTENSION ?
2953                 lsa->lsa_extension_size : lsa->lsa_stripe_size;
2954
2955         if (lsa->lsa_comp_flags & LCME_FL_EXTENSION)
2956                 rc = llapi_layout_extension_size_set(layout, size);
2957         else
2958                 rc = llapi_layout_stripe_size_set(layout, size);
2959
2960         if (rc) {
2961                 fprintf(stderr, "Set stripe size %lu failed: %s\n",
2962                         size, strerror(errno));
2963                 return rc;
2964         }
2965
2966         rc = llapi_layout_stripe_count_set(layout, lsa->lsa_stripe_count);
2967         if (rc) {
2968                 fprintf(stderr, "Set stripe count %lld failed: %s\n",
2969                         lsa->lsa_stripe_count, strerror(errno));
2970                 return rc;
2971         }
2972
2973         if (lsa->lsa_pool_name) {
2974                 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
2975                 if (rc) {
2976                         fprintf(stderr, "Set pool name: %s failed. %s\n",
2977                                 lsa->lsa_pool_name, strerror(errno));
2978                         return rc;
2979                 }
2980         } else {
2981                 rc = llapi_layout_pool_name_set(layout, "");
2982                 if (rc) {
2983                         fprintf(stderr, "Clear pool name failed: %s\n",
2984                                 strerror(errno));
2985                         return rc;
2986                 }
2987         }
2988
2989         rc = lsa_args_stripe_count_check(lsa);
2990         if (rc)
2991                 return rc;
2992
2993         if (lsa->lsa_nr_tgts > 0) {
2994                 bool found = false;
2995
2996                 for (i = 0; i < lsa->lsa_nr_tgts; i++) {
2997                         rc = llapi_layout_ost_index_set(layout, i,
2998                                                         lsa->lsa_tgts[i]);
2999                         if (rc)
3000                                 break;
3001
3002                         /* Make sure stripe offset is in OST list. */
3003                         if (lsa->lsa_tgts[i] == lsa->lsa_stripe_off)
3004                                 found = true;
3005                 }
3006                 if (!found) {
3007                         fprintf(stderr, "Invalid stripe offset '%lld', not in the target list",
3008                                 lsa->lsa_stripe_off);
3009                         errno = EINVAL;
3010                         return -1;
3011                 }
3012         } else if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT &&
3013                    lsa->lsa_stripe_off != -1) {
3014                 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
3015         }
3016         if (rc) {
3017                 fprintf(stderr, "Set ost index %d failed. %s\n",
3018                         i, strerror(errno));
3019                 return rc;
3020         }
3021
3022         /* Create the second, virtual component of extension space */
3023         if (lsa->lsa_extension_comp) {
3024                 lsa->lsa_comp_flags |= LCME_FL_EXTENSION;
3025                 lsa->lsa_extension_comp = false;
3026                 goto new_comp;
3027         }
3028
3029         return rc;
3030 }
3031
3032 static int build_component(struct llapi_layout **layout,
3033                            struct lfs_setstripe_args *lsa, bool set_extent)
3034 {
3035         int rc;
3036
3037         rc = comp_args_to_layout(layout, lsa, set_extent);
3038         if (rc)
3039                 return rc;
3040
3041         if (lsa->lsa_mirror_count > 0) {
3042                 rc = llapi_layout_mirror_count_set(*layout,
3043                                                    lsa->lsa_mirror_count);
3044                 if (rc)
3045                         return rc;
3046
3047                 rc = llapi_layout_flags_set(*layout, LCM_FL_RDONLY);
3048                 if (rc)
3049                         return rc;
3050                 lsa->lsa_mirror_count = 0;
3051         }
3052
3053         return rc;
3054 }
3055
3056 static int build_prev_component(struct llapi_layout **layout,
3057                                 struct lfs_setstripe_args *prev,
3058                                 struct lfs_setstripe_args *lsa,
3059                                 bool set_extent)
3060 {
3061         int extension = lsa->lsa_comp_flags & LCME_FL_EXTENSION;
3062         int rc;
3063
3064         if (prev->lsa_stripe_size) {
3065                 if (extension) {
3066                         prev->lsa_comp_end = lsa->lsa_comp_end;
3067                         prev->lsa_extension_size = lsa->lsa_extension_size;
3068                         prev->lsa_extension_comp = true;
3069                 }
3070
3071                 rc = build_component(layout, prev, true);
3072                 if (rc)
3073                         return rc;
3074         }
3075
3076         /*
3077          * Copy lsa to previous lsa;
3078          * if this is an extension component, make the previous invalid;
3079          */
3080         if (extension)
3081                 prev->lsa_stripe_size = 0;
3082         else
3083                 *prev = *lsa;
3084
3085         return 0;
3086 }
3087
3088 #ifndef LCME_TEMPLATE_FLAGS
3089 #define LCME_TEMPLATE_FLAGS     (LCME_FL_PREF_RW | LCME_FL_NOSYNC | \
3090                                  LCME_FL_EXTENSION)
3091 #endif
3092
3093 static int build_layout_from_yaml_node(struct cYAML *node,
3094                                        struct llapi_layout **layout,
3095                                        struct lfs_setstripe_args *lsa,
3096                                        struct lfs_setstripe_args *prevp)
3097 {
3098         struct lfs_setstripe_args prev = { 0 };
3099         __u32 *osts = lsa->lsa_tgts;
3100         char *string;
3101         int rc = 0;
3102
3103         if (!prevp)
3104                 prevp = &prev;
3105
3106         while (node) {
3107                 string = node->cy_string;
3108
3109                 if (node->cy_type == CYAML_TYPE_OBJECT) {
3110                         /* go deep to sub blocks */
3111                         if (string && !strncmp(string, "component", 9) &&
3112                             strncmp(string, "component0", 10) &&
3113                             strncmp(string, "components", 10)) {
3114                                 rc = build_prev_component(layout, prevp, lsa,
3115                                                           true);
3116                                 if (rc)
3117                                         return rc;
3118
3119                                 /* initialize lsa. */
3120                                 setstripe_args_init(lsa);
3121                                 lsa->lsa_first_comp = false;
3122                                 lsa->lsa_tgts = osts;
3123                         }
3124
3125                         rc = build_layout_from_yaml_node(node->cy_child, layout,
3126                                                          lsa, prevp);
3127                         if (rc)
3128                                 return rc;
3129                 } else {
3130                         if (!node->cy_string)
3131                                 return -EINVAL;
3132
3133                         /* skip leading lmm_ if present, to simplify parsing */
3134                         if (strncmp(string, "lmm_", 4) == 0)
3135                                 string += 4;
3136
3137                         if (node->cy_type == CYAML_TYPE_STRING) {
3138                                 if (!strcmp(string, "lcme_extent.e_end")) {
3139                                         if (!strcmp(node->cy_valuestring, "EOF") ||
3140                                             !strcmp(node->cy_valuestring, "eof"))
3141                                                 lsa->lsa_comp_end = LUSTRE_EOF;
3142                                 } else if (!strcmp(string, "pool")) {
3143                                         lsa->lsa_pool_name = node->cy_valuestring;
3144                                 } else if (!strcmp(string, "pattern")) {
3145                                         if (!strcmp(node->cy_valuestring, "mdt"))
3146                                                 lsa->lsa_pattern = LLAPI_LAYOUT_MDT;
3147                                         if (!strcmp(node->cy_valuestring,
3148                                                     "raid0,overstriped"))
3149                                                 lsa->lsa_pattern =
3150                                                         LLAPI_LAYOUT_OVERSTRIPING;
3151                                 } else if (!strcmp(string, "lcme_flags")) {
3152                                         rc = comp_str2flags(node->cy_valuestring,
3153                                                             &lsa->lsa_comp_flags,
3154                                                             &lsa->lsa_comp_neg_flags);
3155                                         if (rc)
3156                                                 return rc;
3157                                         /*
3158                                          * Only template flags have meaning in
3159                                          * the layout for a new file
3160                                          */
3161                                         lsa->lsa_comp_flags &= LCME_TEMPLATE_FLAGS;
3162                                 }
3163                         } else if (node->cy_type == CYAML_TYPE_NUMBER) {
3164                                 if (!strcmp(string, "lcm_mirror_count")) {
3165                                         lsa->lsa_mirror_count = node->cy_valueint;
3166                                 } else if (!strcmp(string, "lcme_extent.e_start")) {
3167                                         if (node->cy_valueint == 0)
3168                                                 lsa->lsa_first_comp = true;
3169                                 } else if (!strcmp(string, "lcme_extent.e_end")) {
3170                                         if (node->cy_valueint == -1)
3171                                                 lsa->lsa_comp_end = LUSTRE_EOF;
3172                                         else
3173                                                 lsa->lsa_comp_end = node->cy_valueint;
3174                                 } else if (!strcmp(string, "stripe_count")) {
3175                                         lsa->lsa_stripe_count = node->cy_valueint;
3176                                 } else if (!strcmp(string, "stripe_size")) {
3177                                         lsa->lsa_stripe_size = node->cy_valueint;
3178                                 } else if (!strcmp(string, "extension_size")) {
3179                                         lsa->lsa_extension_size = node->cy_valueint;
3180                                         lsa->lsa_extension_comp = true;
3181                                 } else if (!strcmp(string, "stripe_offset")) {
3182                                         lsa->lsa_stripe_off = node->cy_valueint;
3183                                 } else if (!strcmp(string, "l_ost_idx")) {
3184                                         osts[lsa->lsa_nr_tgts] = node->cy_valueint;
3185                                         lsa->lsa_nr_tgts++;
3186                                 }
3187                         }
3188                 }
3189                 node = node->cy_next;
3190         }
3191
3192         if (prevp == &prev) {
3193                 rc = build_prev_component(layout, prevp, lsa, true);
3194                 if (rc)
3195                         return rc;
3196
3197                 if (!(lsa->lsa_comp_flags & LCME_FL_EXTENSION))
3198                         rc = build_component(layout, lsa, *layout != NULL);
3199         }
3200
3201         return rc;
3202 }
3203
3204 static int lfs_comp_create_from_yaml(char *template,
3205                                      struct llapi_layout **layout,
3206                                      struct lfs_setstripe_args *lsa,
3207                                      __u32 *osts)
3208 {
3209         struct cYAML *tree = NULL, *err_rc = NULL;
3210         int rc = 0;
3211
3212         tree = cYAML_build_tree(template, NULL, 0, &err_rc, false);
3213         if (!tree) {
3214                 fprintf(stderr, "%s: cannot parse YAML file %s\n",
3215                         progname, template);
3216                 cYAML_build_error(-EINVAL, -1, "yaml", "from comp yaml",
3217                                   "can't parse", &err_rc);
3218                 cYAML_print_tree2file(stderr, err_rc);
3219                 cYAML_free_tree(err_rc);
3220                 rc = -EINVAL;
3221                 goto err;
3222         }
3223
3224         /* initialize lsa for plain file */
3225         setstripe_args_init(lsa);
3226         lsa->lsa_tgts = osts;
3227
3228         rc = build_layout_from_yaml_node(tree, layout, lsa, NULL);
3229         if (rc) {
3230                 fprintf(stderr, "%s: cannot build layout from YAML file %s.\n",
3231                         progname, template);
3232                 goto err;
3233         }
3234         /* clean clean lsa */
3235         setstripe_args_init(lsa);
3236
3237 err:
3238         if (tree)
3239                 cYAML_free_tree(tree);
3240         return rc;
3241 }
3242
3243 /**
3244  * Get the extension size from the next (SEL) component and extend the
3245  * current component on it. The start of the next component is to be
3246  * adjusted as well.
3247  *
3248  * \param[in] layout    the current layout
3249  * \param[in] start     the start of the current component
3250  * \param[in,out] end   the end of the current component
3251  * \param[in] offset    the offset to adjust the end position to instead of
3252  *                      extension size
3253  *
3254  * \retval 0            - extended successfully
3255  * \retval < 0          - error
3256  */
3257 static int layout_extend_comp(struct llapi_layout *layout,
3258                               uint64_t start, uint64_t *end,
3259                               uint64_t offset)
3260 {
3261         uint64_t size, next_start, next_end;
3262         int rc;
3263
3264         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
3265         if (rc < 0) {
3266                 fprintf(stderr,
3267                         "%s setstripe: cannot move component cursor: %s\n",
3268                         progname, strerror(errno));
3269                 return rc;
3270         }
3271
3272         /*
3273          * Even if the @size will not be used below, this will fail if
3274          * this is not a SEL component - a good confirmation we are
3275          * working on right components.
3276          */
3277         rc = llapi_layout_extension_size_get(layout, &size);
3278         if (rc < 0) {
3279                 fprintf(stderr,
3280                         "%s setstripe: cannot get component ext size: %s\n",
3281                         progname, strerror(errno));
3282                 return rc;
3283         }
3284
3285         rc = llapi_layout_comp_extent_get(layout, &next_start, &next_end);
3286         if (rc) {
3287                 fprintf(stderr, "%s setstripe: cannot get extent: %s\n",
3288                         progname, strerror(errno));
3289                 return rc;
3290         }
3291
3292         next_start += offset ?: size;
3293         rc = llapi_layout_comp_extent_set(layout, next_start, next_end);
3294         if (rc) {
3295                 fprintf(stderr, "%s setstripe: cannot set extent: %s\n",
3296                         progname, strerror(errno));
3297                 return rc;
3298         }
3299
3300         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_PREV);
3301         if (rc < 0) {
3302                 fprintf(stderr,
3303                         "%s setstripe: cannot move component cursor: %s\n",
3304                         progname, strerror(errno));
3305                 return rc;
3306         }
3307
3308         *end += offset ?: size;
3309         rc = llapi_layout_comp_extent_set(layout, start, *end);
3310         if (rc) {
3311                 fprintf(stderr, "%s setstripe: cannot set extent: %s\n",
3312                         progname, strerror(errno));
3313                 return rc;
3314         }
3315
3316         return 0;
3317 }
3318
3319 /**
3320  * In 'lfs setstripe --component-add' mode, we need to fetch the extent
3321  * end of the last component in the existing file, and adjust the
3322  * first extent start of the components to be added accordingly.
3323  *
3324  * In the create mode, we need to check if the first component is an extendable
3325  * SEL component and extend its length to the extension size (first component
3326  * of the PFL file is initialised at the create time, cannot be 0-lenght.
3327  */
3328 static int layout_adjust_first_extent(char *fname, struct llapi_layout *layout,
3329                                       bool comp_add)
3330 {
3331         struct llapi_layout *head;
3332         uint64_t start = 0, prev_end = 0;
3333         uint64_t end;
3334         int rc, ret = 0;
3335
3336         if (!layout || !(comp_add || llapi_layout_is_composite(layout)))
3337                 return 0;
3338
3339         errno = 0;
3340         while (comp_add) {
3341                 head = llapi_layout_get_by_path(fname, 0);
3342                 if (!head) {
3343                         fprintf(stderr,
3344                                 "%s setstripe: cannot read layout from '%s': %s\n",
3345                                 progname, fname, strerror(errno));
3346                         return -EINVAL;
3347                 } else if (errno == ENODATA) {
3348                         /*
3349                          * file without LOVEA, this component-add will be turned
3350                          * into a component-create.
3351                          */
3352                         llapi_layout_free(head);
3353                         ret = -ENODATA;
3354
3355                         /*
3356                          * the new layout will be added to an empty one, it
3357                          * still needs to be adjusted below
3358                          */
3359                         comp_add = 0;
3360                         break;
3361                 } else if (!llapi_layout_is_composite(head)) {
3362                         fprintf(stderr,
3363                                 "%s setstripe: '%s' not a composite file\n",
3364                                 progname, fname);
3365                         llapi_layout_free(head);
3366                         return -EINVAL;
3367                 }
3368
3369                 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
3370                 if (rc) {
3371                         fprintf(stderr,
3372                                 "%s setstripe: cannot get prev extent: %s\n",
3373                                 progname, strerror(errno));
3374                         llapi_layout_free(head);
3375                         return rc;
3376                 }
3377
3378                 llapi_layout_free(head);
3379                 break;
3380         }
3381
3382         /* Make sure we use the first component of the layout to be added. */
3383         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
3384         if (rc < 0) {
3385                 fprintf(stderr,
3386                         "%s setstripe: cannot move component cursor: %s\n",
3387                         progname, strerror(errno));
3388                 return rc;
3389         }
3390
3391         rc = llapi_layout_comp_extent_get(layout, &start, &end);
3392         if (rc) {
3393                 fprintf(stderr, "%s setstripe: cannot get extent: %s\n",
3394                         progname, strerror(errno));
3395                 return rc;
3396         }
3397
3398         if (start == 0 && end == 0) {
3399                 rc = layout_extend_comp(layout, start, &end,
3400                                         comp_add ? prev_end : 0);
3401                 if (rc)
3402                         return rc;
3403         }
3404
3405         if (start > prev_end || end < prev_end) {
3406                 fprintf(stderr,
3407                         "%s setstripe: first extent [%lu, %lu) not adjacent with extent end %lu\n",
3408                         progname, start, end, prev_end);
3409                 return -EINVAL;
3410         }
3411
3412         rc = llapi_layout_comp_extent_set(layout, prev_end, end);
3413         if (rc) {
3414                 fprintf(stderr,
3415                         "%s setstripe: cannot set component extent [%lu, %lu): %s\n",
3416                         progname, prev_end, end, strerror(errno));
3417                 return rc;
3418         }
3419
3420         return ret;
3421 }
3422
3423 static int mirror_adjust_first_extents(struct mirror_args *list)
3424 {
3425         int rc = 0;
3426
3427         if (!list)
3428                 return 0;
3429
3430         while (list) {
3431                 rc = layout_adjust_first_extent(NULL, list->m_layout, false);
3432                 if (rc)
3433                         break;
3434                 list = list->m_next;
3435         }
3436
3437         return rc;
3438 }
3439
3440 static inline bool arg_is_eof(char *arg)
3441 {
3442         return !strncmp(arg, "-1", strlen("-1")) ||
3443                !strncmp(arg, "EOF", strlen("EOF")) ||
3444                !strncmp(arg, "eof", strlen("eof"));
3445 }
3446
3447 /**
3448  * lfs_mirror_alloc() - Allocate a mirror argument structure.
3449  *
3450  * Return: Valid mirror_args pointer on success and
3451  *         NULL if memory allocation fails.
3452  */
3453 static struct mirror_args *lfs_mirror_alloc(void)
3454 {
3455         struct mirror_args *mirror = NULL;
3456
3457         while (1) {
3458                 mirror = calloc(1, sizeof(*mirror));
3459                 if (mirror) {
3460                         mirror->m_inherit = false;
3461                         break;
3462                 }
3463
3464                 sleep(1);
3465         }
3466
3467         return mirror;
3468 }
3469
3470 /**
3471  * lfs_mirror_free() - Free memory allocated for a mirror argument
3472  *                     structure.
3473  * @mirror: Previously allocated mirror argument structure by
3474  *          lfs_mirror_alloc().
3475  *
3476  * Free memory allocated for @mirror.
3477  *
3478  * Return: void.
3479  */
3480 static void lfs_mirror_free(struct mirror_args *mirror)
3481 {
3482         if (mirror->m_layout)
3483                 llapi_layout_free(mirror->m_layout);
3484         free(mirror);
3485 }
3486
3487 /**
3488  * lfs_mirror_list_free() - Free memory allocated for a mirror list.
3489  * @mirror_list: Previously allocated mirror list.
3490  *
3491  * Free memory allocated for @mirror_list.
3492  *
3493  * Return: void.
3494  */
3495 static void lfs_mirror_list_free(struct mirror_args *mirror_list)
3496 {
3497         struct mirror_args *next_mirror = NULL;
3498
3499         while (mirror_list) {
3500                 next_mirror = mirror_list->m_next;
3501                 lfs_mirror_free(mirror_list);
3502                 mirror_list = next_mirror;
3503         }
3504 }
3505
3506 enum {
3507         LFS_SETQUOTA_DELETE = (CHAR_MAX + 1),
3508         LFS_POOL_OPT,
3509         LFS_COMP_COUNT_OPT,
3510         LFS_COMP_START_OPT,
3511         LFS_COMP_FLAGS_OPT,
3512         LFS_COMP_DEL_OPT,
3513         LFS_COMP_SET_OPT,
3514         LFS_COMP_ADD_OPT,
3515         LFS_COMP_NO_VERIFY_OPT,
3516         LFS_PROJID_OPT,
3517         LFS_LAYOUT_FLAGS_OPT, /* used for mirror and foreign flags */
3518         LFS_MIRROR_ID_OPT,
3519         LFS_MIRROR_STATE_OPT,
3520         LFS_LAYOUT_COPY,
3521         LFS_MIRROR_INDEX_OPT,
3522         LFS_LAYOUT_FOREIGN_OPT,
3523         LFS_MODE_OPT,
3524         LFS_NEWERXY_OPT,
3525         LFS_INHERIT_RR_OPT,
3526         LFS_FIND_PERM,
3527         LFS_PRINTF_OPT,
3528         LFS_NO_FOLLOW_OPT,
3529         LFS_HEX_IDX_OPT,
3530         LFS_STATS_OPT,
3531         LFS_STATS_INTERVAL_OPT,
3532         LFS_LINKS_OPT
3533 };
3534
3535 #ifndef LCME_USER_MIRROR_FLAGS
3536 /* The mirror flags can be set by users at creation time. */
3537 #define LCME_USER_MIRROR_FLAGS  (LCME_FL_PREF_RW)
3538 #endif
3539
3540 /* functions */
3541 static int lfs_setstripe_internal(int argc, char **argv,
3542                                   enum setstripe_origin opc)
3543 {
3544         struct lfs_setstripe_args        lsa = { 0 };
3545         struct llapi_stripe_param       *param = NULL;
3546         struct find_param                migrate_mdt_param = {
3547                 .fp_max_depth = -1,
3548                 .fp_mdt_index = -1,
3549         };
3550         char                            *fname;
3551         int                              result = 0;
3552         int                              result2 = 0;
3553         char                            *end;
3554         int                              c;
3555         int                              delete = 0;
3556         unsigned long long               size_units = 1;
3557         bool                             migrate_mode = false;
3558         bool                             migrate_mdt_mode = false;
3559         bool                             setstripe_mode = false;
3560         bool                             migration_block = false;
3561         __u64                            migration_flags = 0;
3562         __u32                            tgts[LOV_MAX_STRIPE_COUNT] = { 0 };
3563         int                              comp_del = 0, comp_set = 0;
3564         int                              comp_add = 0;
3565         __u32                            comp_id = 0;
3566         struct llapi_layout             *layout = NULL;
3567         struct llapi_layout             **lpp = &layout;
3568         bool                             mirror_mode = false;
3569         bool                             has_m_file = false;
3570         __u32                            mirror_count = 0;
3571         enum mirror_flags                mirror_flags = 0;
3572         struct mirror_args              *mirror_list = NULL;
3573         struct mirror_args              *new_mirror = NULL;
3574         struct mirror_args              *last_mirror = NULL;
3575         __u16                            mirror_id = 0;
3576         char                             cmd[PATH_MAX];
3577         bool from_yaml = false;
3578         bool from_copy = false;
3579         char *template = NULL;
3580         bool foreign_mode = false;
3581         char *xattr = NULL;
3582         uint32_t type = LU_FOREIGN_TYPE_NONE, flags = 0;
3583         char *mode_opt = NULL;
3584         mode_t previous_umask = 0;
3585         mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
3586         unsigned long long bandwidth_bytes_sec = 0;
3587         unsigned long long bandwidth_unit = ONE_MB;
3588         enum stats_flag stats_flag = STATS_OFF;
3589         long stats_interval_sec = 5;
3590
3591         struct option long_opts[] = {
3592 /* find { .val = '0',   .name = "null",         .has_arg = no_argument }, */
3593 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
3594         /* --block is only valid in migrate mode */
3595         { .val = 'b',   .name = "block",        .has_arg = no_argument },
3596 /* find { .val = 'B',   .name = "btime",        .has_arg = required_argument }*/
3597         { .val = LFS_COMP_ADD_OPT,
3598                         .name = "comp-add",     .has_arg = no_argument },
3599         { .val = LFS_COMP_ADD_OPT,
3600                         .name = "component-add", .has_arg = no_argument },
3601         { .val = LFS_COMP_DEL_OPT,
3602                         .name = "comp-del",     .has_arg = no_argument },
3603         { .val = LFS_COMP_DEL_OPT,
3604                         .name = "component-del", .has_arg = no_argument },
3605         { .val = LFS_COMP_FLAGS_OPT,
3606                         .name = "comp-flags",   .has_arg = required_argument },
3607         { .val = LFS_COMP_FLAGS_OPT,
3608                         .name = "component-flags",
3609                                                 .has_arg = required_argument },
3610         { .val = LFS_COMP_SET_OPT,
3611                         .name = "comp-set",     .has_arg = no_argument },
3612         { .val = LFS_COMP_SET_OPT,
3613                         .name = "component-set",
3614                                                 .has_arg = no_argument},
3615         { .val = LFS_COMP_NO_VERIFY_OPT,
3616                         .name = "no-verify",    .has_arg = no_argument},
3617         { .val = LFS_LAYOUT_FLAGS_OPT,
3618                         .name = "flags",        .has_arg = required_argument},
3619         { .val = LFS_LAYOUT_FOREIGN_OPT,
3620                         .name = "foreign",      .has_arg = optional_argument},
3621         { .val = LFS_MIRROR_ID_OPT,
3622                         .name = "mirror-id",    .has_arg = required_argument},
3623         { .val = LFS_MODE_OPT,
3624                         .name = "mode",         .has_arg = required_argument},
3625         { .val = LFS_LAYOUT_COPY,
3626                         .name = "copy",         .has_arg = required_argument},
3627         { .val = LFS_STATS_OPT,
3628                         .name = "stats",        .has_arg = no_argument},
3629         { .val = LFS_STATS_INTERVAL_OPT,
3630                         .name = "stats-interval",
3631                                                 .has_arg = required_argument},
3632         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument},
3633         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument},
3634         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument},
3635         { .val = 'C',   .name = "overstripe-count",
3636                                                 .has_arg = required_argument},
3637         { .val = 'd',   .name = "delete",       .has_arg = no_argument},
3638         { .val = 'd',   .name = "destroy",      .has_arg = no_argument},
3639         /* used with "lfs migrate -m" */
3640         { .val = 'd',   .name = "directory",    .has_arg = no_argument},
3641         /* --non-direct is only valid in migrate mode */
3642         { .val = 'D',   .name = "non-direct",   .has_arg = no_argument },
3643         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument},
3644         { .val = 'E',   .name = "component-end",
3645                                                 .has_arg = required_argument},
3646         { .val = 'f',   .name = "file",         .has_arg = required_argument },
3647 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
3648 /* find { .val = 'g',   .name = "gid",          .has_arg = no_argument }, */
3649 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
3650         { .val = 'h',   .name = "help",         .has_arg = no_argument },
3651         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument},
3652         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument},
3653         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument},
3654         { .val = 'I',   .name = "comp-id",      .has_arg = required_argument},
3655         { .val = 'I',   .name = "component-id", .has_arg = required_argument},
3656 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
3657         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
3658         { .val = 'm',   .name = "mdt",          .has_arg = required_argument},
3659         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument},
3660         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument},
3661         /* --non-block is only valid in migrate mode */
3662         { .val = 'n',   .name = "non-block",    .has_arg = no_argument },
3663         { .val = 'N',   .name = "mirror-count", .has_arg = optional_argument},
3664         { .val = 'o',   .name = "ost",          .has_arg = required_argument },
3665 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3666         { .val = 'o',   .name = "ost-list",     .has_arg = required_argument },
3667         { .val = 'o',   .name = "ost_list",     .has_arg = required_argument },
3668 #endif
3669         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
3670 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
3671 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
3672 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
3673         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
3674         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
3675 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
3676 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
3677 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
3678 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
3679         /* --verbose is only valid in migrate mode */
3680         { .val = 'v',   .name = "verbose",      .has_arg = no_argument},
3681         { .val = 'W',   .name = "bandwidth",    .has_arg = required_argument },
3682         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
3683 /* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/
3684         { .val = 'y',   .name = "yaml",         .has_arg = required_argument },
3685         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument},
3686         { .val = 'z',   .name = "extension-size", .has_arg = required_argument},
3687         { .name = NULL } };
3688
3689         setstripe_args_init(&lsa);
3690
3691         migrate_mode = (opc == SO_MIGRATE);
3692         mirror_mode = (opc == SO_MIRROR_CREATE || opc == SO_MIRROR_EXTEND);
3693         setstripe_mode = (opc == SO_SETSTRIPE);
3694         if (opc == SO_MIRROR_DELETE) {
3695                 delete = 1;
3696                 mirror_flags = MF_DESTROY;
3697         }
3698
3699         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
3700         progname = cmd;
3701         while ((c = getopt_long(argc, argv,
3702                                 "bc:C:dDE:f:hH:i:I:m:N::no:p:L:s:S:vx:W:y:z:",
3703                                 long_opts, NULL)) >= 0) {
3704                 size_units = 1;
3705                 switch (c) {
3706                 case 0:
3707                         /* Long options. */
3708                         break;
3709                 case LFS_COMP_ADD_OPT:
3710                         comp_add = 1;
3711                         break;
3712                 case LFS_COMP_DEL_OPT:
3713                         comp_del = 1;
3714                         break;
3715                 case LFS_COMP_FLAGS_OPT:
3716                         result = comp_str2flags(optarg, &lsa.lsa_comp_flags,
3717                                                 &lsa.lsa_comp_neg_flags);
3718                         if (result != 0)
3719                                 goto usage_error;
3720                         if (mirror_mode && lsa.lsa_comp_neg_flags) {
3721                                 fprintf(stderr,
3722                                         "%s: inverted flags are not supported\n",
3723                                         progname);
3724                                 goto usage_error;
3725                         }
3726                         break;
3727                 case LFS_COMP_SET_OPT:
3728                         comp_set = 1;
3729                         break;
3730                 case LFS_COMP_NO_VERIFY_OPT:
3731                         mirror_flags |= MF_NO_VERIFY;
3732                         break;
3733                 case LFS_MIRROR_ID_OPT: {
3734                         unsigned long int id;
3735
3736                         errno = 0;
3737                         id = strtoul(optarg, &end, 0);
3738                         if (errno != 0 || *end != '\0' || id == 0 ||
3739                             id > UINT16_MAX) {
3740                                 fprintf(stderr,
3741                                         "%s %s: invalid mirror ID '%s'\n",
3742                                         progname, argv[0], optarg);
3743                                 goto usage_error;
3744                         }
3745
3746                         mirror_id = (__u16)id;
3747                         break;
3748                 }
3749                 case LFS_LAYOUT_FLAGS_OPT: {
3750                         uint32_t neg_flags;
3751
3752                         /* check for numeric flags (foreign and mirror cases) */
3753                         if (setstripe_mode && !mirror_mode && !last_mirror) {
3754                                 errno = 0;
3755                                 flags = strtoul(optarg, &end, 16);
3756                                 if (errno != 0 || *end != '\0' ||
3757                                     flags >= UINT32_MAX) {
3758                                         fprintf(stderr,
3759                                                 "%s %s: invalid hex flags '%s'\n",
3760                                                 progname, argv[0], optarg);
3761                                         return CMD_HELP;
3762                                 }
3763                                 if (!foreign_mode) {
3764                                         fprintf(stderr,
3765                                                 "%s %s: hex flags must be specified with --foreign option\n",
3766                                                 progname, argv[0]);
3767                                         return CMD_HELP;
3768                                 }
3769                                 break;
3770                         }
3771
3772                         if (!mirror_mode || !last_mirror) {
3773                                 fprintf(stderr,
3774                                         "error: %s: --flags must be specified with --mirror-count|-N option\n",
3775                                         progname);
3776                                 goto usage_error;
3777                         }
3778
3779                         result = comp_str2flags(optarg, &last_mirror->m_flags,
3780                                                 &neg_flags);
3781                         if (result != 0)
3782                                 goto usage_error;
3783
3784                         if (neg_flags) {
3785                                 fprintf(stderr,
3786                                         "%s: inverted flags are not supported\n",
3787                                         progname);
3788                                 result = -EINVAL;
3789                                 goto usage_error;
3790                         }
3791                         if (last_mirror->m_flags & ~LCME_USER_MIRROR_FLAGS) {
3792                                 fprintf(stderr,
3793                                         "%s: unsupported mirror flags: %s\n",
3794                                         progname, optarg);
3795                                 result = -EINVAL;
3796                                 goto error;
3797                         }
3798                         break;
3799                 }
3800                 case LFS_LAYOUT_FOREIGN_OPT:
3801                         if (optarg) {
3802                                 /* check pure numeric */
3803                                 type = strtoul(optarg, &end, 0);
3804                                 if (*end) {
3805                                         /* check name */
3806                                         type = check_foreign_type_name(optarg);
3807                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
3808                                                 fprintf(stderr,
3809                                                         "%s %s: unrecognized foreign type '%s'\n",
3810                                                         progname, argv[0],
3811                                                         optarg);
3812                                                 return CMD_HELP;
3813                                         }
3814                                 } else if (type >= UINT32_MAX) {
3815                                         fprintf(stderr,
3816                                                 "%s %s: invalid foreign type '%s'\n",
3817                                                 progname, argv[0], optarg);
3818                                         return CMD_HELP;
3819                                 }
3820                         }
3821                         foreign_mode = true;
3822                         break;
3823                 case LFS_MODE_OPT:
3824                         mode_opt = optarg;
3825                         if (mode_opt) {
3826                                 mode = strtoul(mode_opt, &end, 8);
3827                                 if (*end != '\0') {
3828                                         fprintf(stderr,
3829                                                 "%s %s: bad mode '%s'\n",
3830                                                 progname, argv[0], mode_opt);
3831                                         return CMD_HELP;
3832                                 }
3833                                 previous_umask = umask(0);
3834                         }
3835                         break;
3836                 case LFS_LAYOUT_COPY:
3837                         from_copy = true;
3838                         template = optarg;
3839                         break;
3840                 case LFS_STATS_OPT:
3841                         stats_flag = STATS_ON;
3842                         break;
3843                 case LFS_STATS_INTERVAL_OPT:
3844                         stats_flag = STATS_ON;
3845                         stats_interval_sec = strtol(optarg, &end, 0);
3846                         if (stats_interval_sec == 0)
3847                                 stats_interval_sec = 5;
3848                         break;
3849                 case 'b':
3850                         if (!migrate_mode) {
3851                                 fprintf(stderr,
3852                                         "%s %s: -b|--block valid only for migrate command\n",
3853                                         progname, argv[0]);
3854                                 goto usage_error;
3855                         }
3856                         migration_block = true;
3857                         break;
3858                 case 'C':
3859                         if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) {
3860                                 fprintf(stderr,
3861                                         "%s %s: -C|--overstripe-count incompatible with DoM layout\n",
3862                                         progname, argv[0]);
3863                                 goto usage_error;
3864                         }
3865                         lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
3866                         fallthrough;
3867                 case 'c':
3868                         errno = 0;
3869                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
3870                         if (errno != 0 || *end != '\0'|| optarg == end ||
3871                             lsa.lsa_stripe_count < -1 ||
3872                             lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
3873                                 fprintf(stderr,
3874                                         "%s %s: invalid stripe count '%s'\n",
3875                                         progname, argv[0], optarg);
3876                                 goto usage_error;
3877                         }
3878
3879                         if (lsa.lsa_stripe_count == -1)
3880                                 lsa.lsa_stripe_count = LLAPI_LAYOUT_WIDE;
3881                         break;
3882                 case 'd':
3883                         if (migrate_mode) {
3884                                 migrate_mdt_param.fp_max_depth = 1;
3885                         } else {
3886                                 /* delete the default striping pattern */
3887                                 delete = 1;
3888                                 if (opc == SO_MIRROR_SPLIT) {
3889                                         if (has_m_file) {
3890                                                 fprintf(stderr,
3891                                                       "%s %s: -d cannot used with -f\n",
3892                                                         progname, argv[0]);
3893                                                 goto usage_error;
3894                                         }
3895                                         mirror_flags |= MF_DESTROY;
3896                                 }
3897                         }
3898                         break;
3899                 case 'D':
3900                         if (!migrate_mode) {
3901                                 fprintf(stderr,
3902                                         "%s %s: -D|--non-direct is valid only for migrate command\n",
3903                                         progname, argv[0]);
3904                                 goto usage_error;
3905                         }
3906                         migration_flags |= LLAPI_MIGRATION_NONDIRECT;
3907                         break;
3908                 case 'E':
3909                         if (lsa.lsa_comp_end != 0) {
3910                                 result = comp_args_to_layout(lpp, &lsa, true);
3911                                 if (result) {
3912                                         fprintf(stderr, "%s: invalid layout\n",
3913                                                 progname);
3914                                         goto usage_error;
3915                                 }
3916
3917                                 setstripe_args_init_inherit(&lsa);
3918                         }
3919
3920                         if (arg_is_eof(optarg)) {
3921                                 lsa.lsa_comp_end = LUSTRE_EOF;
3922                         } else {
3923                                 result = llapi_parse_size(optarg,
3924                                                           &lsa.lsa_comp_end,
3925                                                           &size_units, 0);
3926                                 /* assume units of KB if too small */
3927                                 if (lsa.lsa_comp_end < 4096)
3928                                         lsa.lsa_comp_end *= 1024;
3929                                 if (result ||
3930                                     lsa.lsa_comp_end & (LOV_MIN_STRIPE_SIZE - 1)) {
3931                                         fprintf(stderr,
3932                                                 "%s %s: invalid component end '%s'\n",
3933                                                 progname, argv[0], optarg);
3934                                         goto usage_error;
3935                                 }
3936                         }
3937                         break;
3938                 case 'H':
3939                         if (!migrate_mode) {
3940                                 fprintf(stderr,
3941                                         "--mdt-hash is valid only for migrate command\n");
3942                                 return CMD_HELP;
3943                         }
3944
3945                         lsa.lsa_pattern = check_hashtype(optarg);
3946                         if (lsa.lsa_pattern == 0) {
3947                                 fprintf(stderr,
3948                                         "%s %s: bad stripe hash type '%s'\n",
3949                                         progname, argv[0], optarg);
3950                                 return CMD_HELP;
3951                         }
3952                         break;
3953                 case 'i':
3954                         errno = 0;
3955                         lsa.lsa_stripe_off = strtol(optarg, &end, 0);
3956                         if (errno != 0 || *end != '\0' || optarg == end ||
3957                             lsa.lsa_stripe_off < -1 ||
3958                             lsa.lsa_stripe_off > LOV_V1_INSANE_STRIPE_COUNT) {
3959                                 fprintf(stderr,
3960                                         "%s %s: invalid stripe offset '%s'\n",
3961                                         progname, argv[0], optarg);
3962                                 goto usage_error;
3963                         }
3964                         if (lsa.lsa_stripe_off == -1)
3965                                 lsa.lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
3966                         break;
3967                 case 'I':
3968                         comp_id = strtoul(optarg, &end, 0);
3969                         if (*end != '\0' || comp_id == 0 ||
3970                             comp_id > LCME_ID_MAX) {
3971                                 fprintf(stderr,
3972                                         "%s %s: invalid component ID '%s'\n",
3973                                         progname, argv[0], optarg);
3974                                 goto usage_error;
3975                         }
3976                         break;
3977                 case 'f':
3978                         if (opc != SO_MIRROR_EXTEND && opc != SO_MIRROR_SPLIT) {
3979                                 fprintf(stderr,
3980                                         "error: %s: invalid option: %s\n",
3981                                         progname, argv[optopt + 1]);
3982                                 goto usage_error;
3983                         }
3984                         if (opc == SO_MIRROR_EXTEND) {
3985                                 if (!last_mirror) {
3986                                         fprintf(stderr,
3987                                 "error: %s: '-N' must exist in front of '%s'\n",
3988                                                 progname, argv[optopt + 1]);
3989                                         goto usage_error;
3990                                 }
3991                                 last_mirror->m_file = optarg;
3992                                 last_mirror->m_count = 1;
3993                         } else {
3994                                 /* mirror split */
3995                                 if (!mirror_list)
3996                                         mirror_list = lfs_mirror_alloc();
3997                                 mirror_list->m_file = optarg;
3998                         }
3999                         has_m_file = true;
4000                         break;
4001                 case 'L':
4002                         if (strcmp(argv[optind - 1], "mdt") == 0) {
4003                                 /* Can be only the first component */
4004                                 if (layout) {
4005                                         result = -EINVAL;
4006                                         fprintf(stderr,
4007                                                 "error: 'mdt' layout can be only the first one\n");
4008                                         goto error;
4009                                 }
4010                                 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
4011                                         result = -EFBIG;
4012                                         fprintf(stderr,
4013                                                 "error: 'mdt' layout size is too big\n");
4014                                         goto error;
4015                                 }
4016                                 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
4017                                 lsa.lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
4018                         } else if (strcmp(argv[optind - 1], "raid0") != 0) {
4019                                 result = -EINVAL;
4020                                 fprintf(stderr,
4021                                         "error: layout '%s' is unknown, supported layouts are: 'mdt', 'raid0'\n",
4022                                         argv[optind]);
4023                                 goto error;
4024                         }
4025                         break;
4026                 case 'm':
4027                         if (!migrate_mode) {
4028                                 fprintf(stderr,
4029                                         "%s %s: -m|--mdt-index is valid only for migrate command\n",
4030                                         progname, argv[0]);
4031                                 goto usage_error;
4032                         }
4033                         migrate_mdt_mode = true;
4034                         lsa.lsa_nr_tgts = parse_targets(tgts,
4035                                                 sizeof(tgts) / sizeof(__u32),
4036                                                 lsa.lsa_nr_tgts, optarg, NULL);
4037                         if (lsa.lsa_nr_tgts < 0) {
4038                                 fprintf(stderr,
4039                                         "%s: invalid MDT target(s) '%s'\n",
4040                                         progname, optarg);
4041                                 goto usage_error;
4042                         }
4043
4044                         lsa.lsa_tgts = tgts;
4045                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4046                                 lsa.lsa_stripe_off = tgts[0];
4047                         break;
4048                 case 'n':
4049                         if (!migrate_mode) {
4050                                 fprintf(stderr,
4051                                         "%s %s: -n|--non-block valid only for migrate command\n",
4052                                         progname, argv[0]);
4053                                 goto usage_error;
4054                         }
4055                         migration_flags |= LLAPI_MIGRATION_NONBLOCK;
4056                         break;
4057                 case 'N':
4058                         if (opc == SO_SETSTRIPE) {
4059                                 opc = SO_MIRROR_CREATE;
4060                                 mirror_mode = true;
4061                         }
4062                         mirror_count = 1;
4063                         if (optarg) {
4064                                 errno = 0;
4065                                 mirror_count = strtoul(optarg, &end, 0);
4066                                 if (errno != 0 || *end != '\0' ||
4067                                     mirror_count == 0 ||
4068                                     mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
4069                                         fprintf(stderr,
4070                                                 "error: %s: bad mirror count: %s\n",
4071                                                 progname, optarg);
4072                                         result = -EINVAL;
4073                                         goto error;
4074                                 }
4075                         }
4076
4077                         new_mirror = lfs_mirror_alloc();
4078                         new_mirror->m_count = mirror_count;
4079
4080                         if (!mirror_list)
4081                                 mirror_list = new_mirror;
4082
4083                         if (last_mirror) {
4084                                 /* wrap up last mirror */
4085                                 if (!setstripe_args_specified(&lsa))
4086                                         last_mirror->m_inherit = true;
4087                                 if (lsa.lsa_comp_end == 0)
4088                                         lsa.lsa_comp_end = LUSTRE_EOF;
4089
4090                                 result = comp_args_to_layout(lpp, &lsa, true);
4091                                 if (result) {
4092                                         lfs_mirror_free(new_mirror);
4093                                         goto error;
4094                                 }
4095
4096                                 setstripe_args_init_inherit(&lsa);
4097
4098                                 last_mirror->m_next = new_mirror;
4099                         }
4100
4101                         last_mirror = new_mirror;
4102                         lpp = &last_mirror->m_layout;
4103                         break;
4104                 case 'o':
4105 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
4106                         if (strcmp(argv[optind - 1], "--ost-list") == 0)
4107                                 fprintf(stderr,
4108                                         "warning: '--ost-list' is deprecated, use '--ost' instead\n");
4109 #endif
4110                         if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) {
4111                                 fprintf(stderr,
4112                                         "%s %s: -o|--ost incompatible with DoM layout\n",
4113                                         progname, argv[0]);
4114                                 goto usage_error;
4115                         }
4116                         /*
4117                          * -o allows overstriping, and must note it because
4118                          * parse_targets is shared with MDT striping, which
4119                          * does not allow duplicates
4120                          */
4121                         lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
4122                         lsa.lsa_nr_tgts = parse_targets(tgts,
4123                                                 sizeof(tgts) / sizeof(__u32),
4124                                                 lsa.lsa_nr_tgts, optarg,
4125                                                 &lsa.lsa_pattern);
4126                         if (lsa.lsa_nr_tgts < 0) {
4127                                 fprintf(stderr,
4128                                         "%s %s: invalid OST target(s) '%s'\n",
4129                                         progname, argv[0], optarg);
4130                                 goto usage_error;
4131                         }
4132
4133                         lsa.lsa_tgts = tgts;
4134                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4135                                 lsa.lsa_stripe_off = tgts[0];
4136                         break;
4137                 case 'p':
4138                         if (!optarg)
4139                                 goto usage_error;
4140
4141                         if (optarg[0] == '\0' || lov_pool_is_inherited(optarg))
4142                                 lsa.lsa_pool_name = NULL;
4143                         else
4144                                 lsa.lsa_pool_name = optarg;
4145                         break;
4146                 case 'S':
4147                         result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
4148                                                   &size_units, 0);
4149                         /* assume units of KB if too small to be valid */
4150                         if (lsa.lsa_stripe_size < 4096)
4151                                 lsa.lsa_stripe_size *= 1024;
4152                         if (result ||
4153                             lsa.lsa_stripe_size & (LOV_MIN_STRIPE_SIZE - 1)) {
4154                                 fprintf(stderr,
4155                                         "%s %s: invalid stripe size '%s'\n",
4156                                         progname, argv[0], optarg);
4157                                 goto usage_error;
4158                         }
4159                         break;
4160                 case 'v':
4161                         if (!migrate_mode) {
4162                                 fprintf(stderr,
4163                                         "%s %s: -v|--verbose valid only for migrate command\n",
4164                                         progname, argv[0]);
4165                                 goto usage_error;
4166                         }
4167                         migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
4168                         migration_flags = LLAPI_MIGRATION_VERBOSE;
4169                         break;
4170                 case 'x':
4171                         xattr = optarg;
4172                         break;
4173                 case 'W':
4174                         if (!migrate_mode) {
4175                                 fprintf(stderr,
4176                                         "--bandwidth is valid only for migrate and mirror mode\n");
4177                                 goto error;
4178                         }
4179                         if (llapi_parse_size(optarg, &bandwidth_bytes_sec,
4180                                              &bandwidth_unit, 0) < 0) {
4181                                 fprintf(stderr,
4182                                         "error: %s: bad value for bandwidth '%s'\n",
4183                                         argv[0], optarg);
4184                                 goto error;
4185                         }
4186                         break;
4187                 case 'y':
4188                         from_yaml = true;
4189                         template = optarg;
4190                         break;
4191                 case 'z':
4192                         result = llapi_parse_size(optarg,
4193                                                   &lsa.lsa_extension_size,
4194                                                   &size_units, 0);
4195                         if (result) {
4196                                 fprintf(stderr,
4197                                         "%s %s: invalid extension size '%s'\n",
4198                                         progname, argv[0], optarg);
4199                                 goto usage_error;
4200                         }
4201
4202                         lsa.lsa_extension_comp = true;
4203                         break;
4204                 default:
4205                         fprintf(stderr, "%s: unrecognized option '%s'\n",
4206                                 progname, argv[optind - 1]);
4207                 case 'h':
4208                         goto usage_error;
4209                 }
4210         }
4211
4212         fname = argv[optind];
4213
4214         if (optind == argc) {
4215                 fprintf(stderr, "%s %s: FILE must be specified\n",
4216                         progname, argv[0]);
4217                 goto usage_error;
4218         }
4219
4220         /* lfs migrate $filename should keep the file's layout by default */
4221         if (migrate_mode && !layout && !from_yaml &&
4222             !setstripe_args_specified(&lsa) && !lsa.lsa_pool_name)
4223                 from_copy = true;
4224
4225         if (xattr && !foreign_mode) {
4226                 /*
4227                  * only print a warning as this is harmless and will be ignored
4228                  */
4229                 fprintf(stderr,
4230                         "%s %s: xattr has been specified for non-foreign layout\n",
4231                         progname, argv[0]);
4232         } else if (foreign_mode && !xattr) {
4233                 fprintf(stderr,
4234                         "%s %s: xattr must be provided in foreign mode\n",
4235                         progname, argv[0]);
4236                 goto usage_error;
4237         }
4238
4239         if (foreign_mode && (!setstripe_mode || comp_add | comp_del ||
4240             comp_set || comp_id || delete || from_copy ||
4241             setstripe_args_specified(&lsa) || lsa.lsa_nr_tgts ||
4242             lsa.lsa_tgts)) {
4243                 fprintf(stderr,
4244                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
4245                         progname, argv[0]);
4246                 return CMD_HELP;
4247         }
4248
4249         if (mirror_mode && mirror_count == 0) {
4250                 fprintf(stderr,
4251                         "error: %s: --mirror-count|-N option is required\n",
4252                         progname);
4253                 result = -EINVAL;
4254                 goto error;
4255         }
4256
4257         if (mirror_mode) {
4258                 if (!setstripe_args_specified(&lsa))
4259                         last_mirror->m_inherit = true;
4260                 if (lsa.lsa_comp_end == 0)
4261                         lsa.lsa_comp_end = LUSTRE_EOF;
4262         }
4263
4264         if (lsa.lsa_comp_end != 0) {
4265                 result = comp_args_to_layout(lpp, &lsa, true);
4266                 if (result) {
4267                         fprintf(stderr, "error: %s: invalid layout\n",
4268                                 progname);
4269                         result = -EINVAL;
4270                         goto error;
4271                 }
4272         }
4273
4274         if (mirror_flags & MF_NO_VERIFY) {
4275                 if (opc != SO_MIRROR_EXTEND) {
4276                         fprintf(stderr,
4277                                 "error: %s: --no-verify is valid only for lfs mirror extend command\n",
4278                                 progname);
4279                         result = -EINVAL;
4280                         goto error;
4281                 } else if (!has_m_file) {
4282                         fprintf(stderr,
4283                                 "error: %s: --no-verify must be specified with -f <victim_file> option\n",
4284                                 progname);
4285                         result = -EINVAL;
4286                         goto error;
4287                 }
4288         }
4289
4290         if (comp_set && !comp_id && !lsa.lsa_pool_name) {
4291                 fprintf(stderr,
4292                         "%s %s: --component-set doesn't have component-id set\n",
4293                         progname, argv[0]);
4294                 goto usage_error;
4295         }
4296
4297         if ((delete + comp_set + comp_del + comp_add) > 1) {
4298                 fprintf(stderr,
4299                         "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
4300                         progname, argv[0]);
4301                 goto usage_error;
4302         }
4303
4304         if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
4305                        lsa.lsa_comp_flags != 0 || layout != NULL)) {
4306                 fprintf(stderr,
4307                         "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
4308                         progname, argv[0]);
4309                 goto usage_error;
4310         }
4311
4312         if ((comp_set || comp_del) &&
4313             (setstripe_args_specified(&lsa) || layout != NULL)) {
4314                 fprintf(stderr,
4315                         "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
4316                         progname, argv[0]);
4317                 goto usage_error;
4318         }
4319
4320         if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
4321                 fprintf(stderr,
4322                         "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
4323                         progname, argv[0]);
4324                 goto usage_error;
4325         }
4326
4327         if (comp_add || comp_del) {
4328                 struct stat st;
4329
4330                 result = lstat(fname, &st);
4331                 if (result == 0 && S_ISDIR(st.st_mode)) {
4332                         fprintf(stderr,
4333                                 "%s setstripe: cannot use --component-add or --component-del for directory\n",
4334                                 progname);
4335                         goto usage_error;
4336                 }
4337
4338                 if (mirror_mode) {
4339                         fprintf(stderr,
4340                                 "error: %s: can't use --component-add or --component-del for mirror operation\n",
4341                                 progname);
4342                         goto usage_error;
4343                 }
4344         }
4345
4346         if (comp_add) {
4347                 if (!layout) {
4348                         fprintf(stderr,
4349                                 "%s %s: option -E must be specified with --component-add\n",
4350                                 progname, argv[0]);
4351                         goto usage_error;
4352                 }
4353         }
4354
4355         if (from_yaml && from_copy) {
4356                 fprintf(stderr,
4357                         "%s: can't specify --yaml and --copy together\n",
4358                         progname);
4359                 goto error;
4360         }
4361
4362         if ((from_yaml || from_copy) &&
4363             (setstripe_args_specified(&lsa) || layout != NULL)) {
4364                 fprintf(stderr,
4365                         "error: %s: can't specify --yaml or --copy with -c, -S, -i, -o, -p or -E options.\n",
4366                         argv[0]);
4367                 goto error;
4368         }
4369
4370         if ((migration_flags & LLAPI_MIGRATION_NONBLOCK) && migration_block) {
4371                 fprintf(stderr,
4372                         "%s %s: options --non-block and --block are mutually exclusive\n",
4373                         progname, argv[0]);
4374                 goto usage_error;
4375         }
4376
4377         if (!comp_del && !comp_set && opc != SO_MIRROR_SPLIT &&
4378             opc != SO_MIRROR_DELETE && comp_id != 0) {
4379                 fprintf(stderr,
4380                         "%s: option -I can only be used with --component-del or --component-set or lfs mirror split\n",
4381                         progname);
4382                 goto usage_error;
4383         }
4384
4385         if (migrate_mdt_mode) {
4386                 struct lmv_user_md *lmu;
4387
4388                 /* initialize migrate mdt parameters */
4389                 lmu = calloc(1, lmv_user_md_size(lsa.lsa_nr_tgts,
4390                                                  LMV_USER_MAGIC_SPECIFIC));
4391                 if (!lmu) {
4392                         fprintf(stderr,
4393                                 "%s %s: cannot allocate memory for lmv_user_md: %s\n",
4394                                 progname, argv[0], strerror(ENOMEM));
4395                         result = -ENOMEM;
4396                         goto error;
4397                 }
4398                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
4399                         lmu->lum_stripe_count = lsa.lsa_stripe_count;
4400                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT) {
4401                         fprintf(stderr,
4402                                 "%s %s: migrate should specify MDT index\n",
4403                                 progname, argv[0]);
4404                         free(lmu);
4405                         goto usage_error;
4406                 }
4407                 lmu->lum_stripe_offset = lsa.lsa_stripe_off;
4408                 if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
4409                         lmu->lum_hash_type = lsa.lsa_pattern;
4410                 else
4411                         lmu->lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
4412                 if (lsa.lsa_pool_name) {
4413                         strncpy(lmu->lum_pool_name, lsa.lsa_pool_name,
4414                                 sizeof(lmu->lum_pool_name) - 1);
4415                         lmu->lum_pool_name[sizeof(lmu->lum_pool_name) - 1] = 0;
4416                 }
4417                 if (lsa.lsa_nr_tgts > 1) {
4418                         int i;
4419
4420                         if (lsa.lsa_stripe_count > 0 &&
4421                             lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
4422                             lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
4423                                 fprintf(stderr,
4424                                         "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
4425                                         progname, lsa.lsa_stripe_count,
4426                                         lsa.lsa_nr_tgts);
4427                                 free(lmu);
4428                                 goto usage_error;
4429                         }
4430
4431                         lmu->lum_magic = LMV_USER_MAGIC_SPECIFIC;
4432                         lmu->lum_stripe_count = lsa.lsa_nr_tgts;
4433                         for (i = 0; i < lsa.lsa_nr_tgts; i++)
4434                                 lmu->lum_objects[i].lum_mds = lsa.lsa_tgts[i];
4435                 } else {
4436                         lmu->lum_magic = LMV_USER_MAGIC;
4437                 }
4438
4439                 migrate_mdt_param.fp_lmv_md = lmu;
4440                 migrate_mdt_param.fp_migrate = 1;
4441         } else if (!layout) {
4442                 if (lsa_args_stripe_count_check(&lsa))
4443                         goto usage_error;
4444
4445                 /* initialize stripe parameters */
4446                 param = calloc(1, offsetof(typeof(*param),
4447                                lsp_osts[lsa.lsa_nr_tgts]));
4448                 if (!param) {
4449                         fprintf(stderr,
4450                                 "%s %s: cannot allocate memory for parameters: %s\n",
4451                                 progname, argv[0], strerror(ENOMEM));
4452                         result = -ENOMEM;
4453                         goto error;
4454                 }
4455
4456                 if (lsa.lsa_stripe_size != LLAPI_LAYOUT_DEFAULT)
4457                         param->lsp_stripe_size = lsa.lsa_stripe_size;
4458                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
4459                         if (lsa.lsa_stripe_count == LLAPI_LAYOUT_WIDE)
4460                                 param->lsp_stripe_count = -1;
4461                         else
4462                                 param->lsp_stripe_count = lsa.lsa_stripe_count;
4463                 }
4464                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4465                         param->lsp_stripe_offset = -1;
4466                 else
4467                         param->lsp_stripe_offset = lsa.lsa_stripe_off;
4468                 param->lsp_stripe_pattern =
4469                                 llapi_pattern_to_lov(lsa.lsa_pattern);
4470                 if (param->lsp_stripe_pattern == EINVAL) {
4471                         fprintf(stderr, "error: %s: invalid stripe pattern\n",
4472                                 argv[0]);
4473                         free(param);
4474                         goto usage_error;
4475                 }
4476                 param->lsp_pool = lsa.lsa_pool_name;
4477                 param->lsp_is_specific = false;
4478
4479                 if (lsa.lsa_nr_tgts > 0) {
4480                         param->lsp_is_specific = true;
4481                         param->lsp_stripe_count = lsa.lsa_nr_tgts;
4482                         memcpy(param->lsp_osts, tgts,
4483                                sizeof(*tgts) * lsa.lsa_nr_tgts);
4484                 }
4485         }
4486
4487         if (from_yaml) {
4488                 /* generate a layout from a YAML template */
4489                 result = lfs_comp_create_from_yaml(template, &layout,
4490                                                    &lsa, tgts);
4491                 if (result) {
4492                         fprintf(stderr,
4493                                 "error: %s: can't create composite layout from template file %s\n",
4494                                 argv[0], template);
4495                         goto error;
4496                 }
4497         }
4498
4499         if (layout != NULL || mirror_list != NULL) {
4500                 if (mirror_list)
4501                         result = mirror_adjust_first_extents(mirror_list);
4502                 else
4503                         result = layout_adjust_first_extent(fname, layout,
4504                                                             comp_add);
4505                 if (result == -ENODATA)
4506                         comp_add = 0;
4507                 else if (result != 0) {
4508                         fprintf(stderr, "error: %s: invalid layout\n",
4509                                 progname);
4510                         goto error;
4511                 }
4512         }
4513
4514         for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
4515                 if (from_copy) {
4516                         layout = llapi_layout_get_by_path(template ?: fname, 0);
4517                         if (!layout) {
4518                                 fprintf(stderr,
4519                                         "%s: can't create composite layout from file %s: %s\n",
4520                                         progname, template ?: fname,
4521                                         strerror(errno));
4522                                 result = -errno;
4523                                 goto error;
4524                         }
4525                 }
4526
4527                 if (migrate_mdt_mode) {
4528                         result = llapi_migrate_mdt(fname, &migrate_mdt_param);
4529                 } else if (migrate_mode) {
4530                         if (from_copy) {
4531                                 /*
4532                                  * Strip the source layout of specific
4533                                  * OST object/index values.
4534                                  */
4535                                 result = llapi_layout_ost_index_set(layout, 0,
4536                                                 LLAPI_LAYOUT_DEFAULT);
4537                                 if (result) {
4538                                         fprintf(stderr,
4539                                                 "%s: set default ost index failed: %s\n",
4540                                                 progname, strerror(errno));
4541                                         result = -errno;
4542                                         goto error;
4543                                 }
4544                         }
4545
4546                         result = lfs_migrate(fname, migration_flags, param,
4547                                              layout, bandwidth_bytes_sec,
4548                                              stats_flag, stats_interval_sec);
4549                 } else if (comp_set != 0) {
4550                         result = lfs_component_set(fname, comp_id,
4551                                                    lsa.lsa_pool_name,
4552                                                    lsa.lsa_comp_flags,
4553                                                    lsa.lsa_comp_neg_flags);
4554                 } else if (comp_del != 0) {
4555                         result = lfs_component_del(fname, comp_id,
4556                                                    lsa.lsa_comp_flags,
4557                                                    lsa.lsa_comp_neg_flags);
4558                 } else if (comp_add != 0) {
4559                         result = lfs_component_add(fname, layout);
4560                 } else if (opc == SO_MIRROR_CREATE) {
4561                         result = mirror_create(fname, mirror_list);
4562                 } else if (opc == SO_MIRROR_EXTEND) {
4563                         result = mirror_extend(fname, mirror_list,
4564                                                mirror_flags,
4565                                                bandwidth_bytes_sec,
4566                                                stats_flag, stats_interval_sec);
4567                 } else if (opc == SO_MIRROR_SPLIT || opc == SO_MIRROR_DELETE) {
4568                         if (!mirror_id && !comp_id && !lsa.lsa_pool_name) {
4569                                 fprintf(stderr,
4570                                         "%s: no mirror id, component id, or pool name specified to delete from '%s'\n",
4571                                         progname, fname);
4572                                 goto usage_error;
4573                         }
4574                         if (lsa.lsa_pool_name)
4575                                 mirror_flags |= MF_COMP_POOL;
4576                         else if (mirror_id != 0)
4577                                 comp_id = mirror_id;
4578                         else
4579                                 mirror_flags |= MF_COMP_ID;
4580                         if (has_m_file && !strcmp(fname, mirror_list->m_file)) {
4581                                 fprintf(stderr,
4582                                         "%s: the file specified by -f cannot be same as the source file '%s'\n",
4583                                         progname, fname);
4584                                 goto usage_error;
4585                         }
4586                         result = mirror_split(fname, comp_id, lsa.lsa_pool_name,
4587                                               mirror_flags,
4588                                               has_m_file ? mirror_list->m_file :
4589                                               NULL);
4590                 } else if (layout) {
4591                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
4592                                                       mode, layout);
4593                         if (result >= 0) {
4594                                 close(result);
4595                                 result = 0;
4596                         }
4597                 } else if (foreign_mode) {
4598                         result = llapi_file_create_foreign(fname, mode, type,
4599                                                            flags, xattr);
4600                         if (result >= 0) {
4601                                 close(result);
4602                                 result = 0;
4603                         }
4604                 } else {
4605                         result = llapi_file_open_param(fname,
4606                                                        O_CREAT | O_WRONLY,
4607                                                        mode, param);
4608                         if (result >= 0) {
4609                                 close(result);
4610                                 result = 0;
4611                         }
4612                 }
4613                 if (result) {
4614                         /* Save the first error encountered. */
4615                         if (result2 == 0)
4616                                 result2 = result;
4617                         continue;
4618                 }
4619         }
4620
4621         if (mode_opt)
4622                 umask(previous_umask);
4623
4624         free(param);
4625         free(migrate_mdt_param.fp_lmv_md);
4626         llapi_layout_free(layout);
4627         lfs_mirror_list_free(mirror_list);
4628         return result2;
4629 usage_error:
4630         result = CMD_HELP;
4631 error:
4632         llapi_layout_free(layout);
4633         lfs_mirror_list_free(mirror_list);
4634         return result;
4635 }
4636
4637 static int lfs_poollist(int argc, char **argv)
4638 {
4639         if (argc != 2)
4640                 return CMD_HELP;
4641
4642         return llapi_poollist(argv[1]);
4643 }
4644
4645 #define FP_DEFAULT_TIME_MARGIN (24 * 60 * 60)
4646 static int set_time(struct find_param *param, time_t *time, time_t *set,
4647                     char *str)
4648 {
4649         long long t = 0;
4650         int sign = 0;
4651         char *endptr = "AD";
4652         char *timebuf;
4653
4654         if (str[0] == '+')
4655                 sign = 1;
4656         else if (str[0] == '-')
4657                 sign = -1;
4658
4659         if (sign)
4660                 str++;
4661
4662         for (timebuf = str; *endptr && *(endptr + 1); timebuf = endptr + 1) {
4663                 long long val = strtoll(timebuf, &endptr, 0);
4664                 int unit = 1;
4665
4666                 switch (*endptr) {
4667                 case  'y':
4668                         unit *= 52; /* 52 weeks + 1 day below */
4669                         fallthrough;
4670                 case  'w':
4671                         unit *= 7;
4672                         if (param->fp_time_margin == FP_DEFAULT_TIME_MARGIN)
4673                                 param->fp_time_margin *= (1 + unit / 52);
4674                         unit += (*endptr == 'y'); /* +1 day for 365 days/year */
4675                         fallthrough;
4676                 case '\0': /* days are default unit if none used */
4677                         fallthrough;
4678                 case  'd':
4679                         unit *= 24;
4680                         fallthrough;
4681                 case  'h':
4682                         unit *= 60;
4683                         fallthrough;
4684                 case  'm':
4685                         unit *= 60;
4686                         fallthrough;
4687                 case  's':
4688                         break;
4689                         /* don't need to multiply by 1 for seconds */
4690                 default:
4691                         fprintf(stderr,
4692                                 "%s find: bad time string '%s': %s\n",
4693                                 progname, timebuf, strerror(EINVAL));
4694                         return INT_MAX;
4695                 }
4696
4697                 if (param->fp_time_margin == 0 ||
4698                     (*endptr && unit < param->fp_time_margin))
4699                         param->fp_time_margin = unit;
4700
4701                 t += val * unit;
4702         }
4703         if (*time < t) {
4704                 if (sign != 0)
4705                         str--;
4706                 fprintf(stderr, "%s find: bad time '%s': too large\n",
4707                         progname, str);
4708                 return INT_MAX;
4709         }
4710
4711         *set = *time - t;
4712
4713         return sign;
4714 }
4715
4716 static int str2quotaid(__u32 *id, const char *arg)
4717 {
4718         unsigned long int projid_tmp = 0;
4719         char *endptr = NULL;
4720
4721         projid_tmp = strtoul(arg, &endptr, 10);
4722         if (*endptr != '\0')
4723                 return -EINVAL;
4724         /* UINT32_MAX is not allowed - see projid_valid()/INVALID_PROJID */
4725         if (projid_tmp >= UINT32_MAX)
4726                 return -ERANGE;
4727
4728         *id = projid_tmp;
4729         return 0;
4730 }
4731
4732 static int name2uid(unsigned int *id, const char *name)
4733 {
4734         struct passwd *passwd;
4735
4736         passwd = getpwnam(name);
4737         if (!passwd)
4738                 return -ENOENT;
4739         *id = passwd->pw_uid;
4740
4741         return 0;
4742 }
4743
4744 static int name2gid(unsigned int *id, const char *name)
4745 {
4746         struct group *group;
4747
4748         group = getgrnam(name);
4749         if (!group)
4750                 return -ENOENT;
4751         *id = group->gr_gid;
4752
4753         return 0;
4754 }
4755
4756 static inline int name2projid(unsigned int *id, const char *name)
4757 {
4758         return -ENOTSUP;
4759 }
4760
4761 static int uid2name(char **name, unsigned int id)
4762 {
4763         struct passwd *passwd;
4764
4765         passwd = getpwuid(id);
4766         if (!passwd)
4767                 return -ENOENT;
4768         *name = passwd->pw_name;
4769
4770         return 0;
4771 }
4772
4773 static inline int gid2name(char **name, unsigned int id)
4774 {
4775         struct group *group;
4776
4777         group = getgrgid(id);
4778         if (!group)
4779                 return -ENOENT;
4780         *name = group->gr_name;
4781
4782         return 0;
4783 }
4784
4785 static int name2layout(__u32 *layout, char *name)
4786 {
4787         char *ptr, *layout_name;
4788
4789         *layout = 0;
4790         for (ptr = name; ; ptr = NULL) {
4791                 layout_name = strtok(ptr, ",");
4792                 if (!layout_name)
4793                         break;
4794                 if (strcmp(layout_name, "released") == 0)
4795                         *layout |= LOV_PATTERN_F_RELEASED;
4796                 else if (strcmp(layout_name, "raid0") == 0)
4797                         *layout |= LOV_PATTERN_RAID0;
4798                 else if (strcmp(layout_name, "mdt") == 0)
4799                         *layout |= LOV_PATTERN_MDT;
4800                 else if (strcmp(layout_name, "overstriping") == 0)
4801                         *layout |= LOV_PATTERN_OVERSTRIPING;
4802                 else
4803                         return -1;
4804         }
4805         return 0;
4806 }
4807
4808 static int parse_symbolic(const char *input, mode_t *outmode, const char **end)
4809 {
4810         int loop;
4811         int user, group, other;
4812         int who, all;
4813         char c, op;
4814         mode_t perm;
4815         mode_t usermask;
4816         mode_t previous_flags;
4817
4818         user = group = other = 0;
4819         all = 0;
4820         loop = 1;
4821         perm = 0;
4822         previous_flags = 0;
4823         *end = input;
4824         usermask = 0;
4825
4826         while (loop) {
4827                 switch (*input) {
4828                 case 'u':
4829                         user = 1;
4830                         break;
4831                 case 'g':
4832                         group = 1;
4833                         break;
4834                 case 'o':
4835                         other = 1;
4836                         break;
4837                 case 'a':
4838                         user = group = other = 1;
4839                         all = 1;
4840                         break;
4841                 default:
4842                         loop = 0;
4843                 }
4844
4845                 if (loop)
4846                         input++;
4847         }
4848
4849         who = user || group || other;
4850         if (!who) {
4851                 /* get the umask */
4852                 usermask = umask(0022);
4853                 umask(usermask);
4854                 usermask &= 07777;
4855         }
4856
4857         if (*input == '-' || *input == '+' || *input == '=')
4858                 op = *input++;
4859         else
4860                 /* operation is required */
4861                 return -1;
4862
4863         /* get the flags in *outmode */
4864         switch (*input) {
4865         case 'u':
4866                 previous_flags = (*outmode & 0700);
4867                 perm |= user  ? previous_flags : 0;
4868                 perm |= group ? (previous_flags >> 3) : 0;
4869                 perm |= other ? (previous_flags >> 6) : 0;
4870                 input++;
4871                 goto write_perm;
4872         case 'g':
4873                 previous_flags = (*outmode & 0070);
4874                 perm |= user  ? (previous_flags << 3) : 0;
4875                 perm |= group ? previous_flags : 0;
4876                 perm |= other ? (previous_flags >> 3) : 0;
4877                 input++;
4878                 goto write_perm;
4879         case 'o':
4880                 previous_flags = (*outmode & 0007);
4881                 perm |= user  ? (previous_flags << 6) : 0;
4882                 perm |= group ? (previous_flags << 3) : 0;
4883                 perm |= other ? previous_flags : 0;
4884                 input++;
4885                 goto write_perm;
4886         default:
4887                 break;
4888         }
4889
4890         /* this part is optional,
4891          * if empty perm = 0 and *outmode is not modified
4892          */
4893         loop = 1;
4894         while (loop) {
4895                 c = *input;
4896                 switch (c) {
4897                 case 'r':
4898                         perm |= user  ? 0400 : 0;
4899                         perm |= group ? 0040 : 0;
4900                         perm |= other ? 0004 : 0;
4901                         /* set read permission for uog except for umask's
4902                          * permissions
4903                          */
4904                         perm |= who   ? 0 : (0444 & ~usermask);
4905                         break;
4906                 case 'w':
4907                         perm |= user  ? 0200 : 0;
4908                         perm |= group ? 0020 : 0;
4909                         perm |= other ? 0002 : 0;
4910                         /* set write permission for uog except for umask'
4911                          * permissions
4912                          */
4913                         perm |= who   ? 0 : (0222 & ~usermask);
4914                         break;
4915                 case 'x':
4916                         perm |= user  ? 0100 : 0;
4917                         perm |= group ? 0010 : 0;
4918                         perm |= other ? 0001 : 0;
4919                         /* set execute permission for uog except for umask'
4920                          * permissions
4921                          */
4922                         perm |= who   ? 0 : (0111 & ~usermask);
4923                         break;
4924                 case 'X':
4925                         /*
4926                          * Adds execute permission to 'u', 'g' and/or 'g' if
4927                          * specified and either 'u', 'g' or 'o' already has
4928                          * execute permissions.
4929                          */
4930                         if ((*outmode & 0111) != 0) {
4931                                 perm |= user  ? 0100 : 0;
4932                                 perm |= group ? 0010 : 0;
4933                                 perm |= other ? 0001 : 0;
4934                                 perm |= !who  ? 0111 : 0;
4935                         }
4936                         break;
4937                 case 's':
4938                         /* s is ignored if o is given, but it's not an error */
4939                         if (other && !group && !user)
4940                                 break;
4941                         perm |= user  ? S_ISUID : 0;
4942                         perm |= group ? S_ISGID : 0;
4943                         break;
4944                 case 't':
4945                         /* 't' should be used when 'a' is given
4946                          * or who is empty
4947                          */
4948                         perm |= (!who || all) ? S_ISVTX : 0;
4949                         /* using ugo with t is not an error */
4950                         break;
4951                 default:
4952                         loop = 0;
4953                         break;
4954                 }
4955                 if (loop)
4956                         input++;
4957         }
4958
4959 write_perm:
4960         /* uog flags should be only one character long */
4961         if (previous_flags && (*input != '\0' && *input != ','))
4962                 return -1;
4963
4964         switch (op) {
4965         case '-':
4966                 /* remove the flags from outmode */
4967                 *outmode &= ~perm;
4968                 break;
4969         case '+':
4970                 /* add the flags to outmode */
4971                 *outmode |= perm;
4972                 break;
4973         case '=':
4974                 /* set the flags of outmode to perm */
4975                 if (perm != 0)
4976                         *outmode = perm;
4977                 break;
4978         }
4979
4980         *end = input;
4981         return 0;
4982 }
4983
4984 static int str2mode_t(const char *input, mode_t *outmode)
4985 {
4986         int ret;
4987         const char *iter;
4988
4989         ret = 0;
4990
4991         if (*input >= '0' && *input <= '7') {
4992                 /* parse octal representation */
4993                 char *end;
4994
4995                 iter = input;
4996
4997                 /* look for invalid digits in octal representation */
4998                 while (isdigit(*iter))
4999                         if (*iter++ > '7')
5000                                 return -1;
5001
5002                 errno = 0;
5003                 *outmode = strtoul(input, &end, 8);
5004
5005                 if (errno != 0 || *outmode > 07777) {
5006                         *outmode = 0;
5007                         ret = -1;
5008                 }
5009
5010         } else if (*input == '8' || *input == '9') {
5011                 /* error: invalid octal number */
5012                 ret = -1;
5013         } else {
5014                 /* parse coma seperated list of symbolic representation */
5015                 int rc;
5016                 const char *end;
5017
5018                 *outmode = 0;
5019                 rc = 0;
5020                 end = NULL;
5021
5022                 do {
5023                         rc = parse_symbolic(input, outmode, &end);
5024                         if (rc)
5025                                 return -1;
5026
5027                         input = end+1;
5028                 } while (*end == ',');
5029
5030                 if (*end != '\0')
5031                         ret = -1;
5032         }
5033         return ret;
5034 }
5035
5036 static int lfs_find(int argc, char **argv)
5037 {
5038         int c, rc;
5039         int ret = 0;
5040         time_t t;
5041         struct find_param param = {
5042                 .fp_max_depth = -1,
5043                 .fp_quiet = 1,
5044                 .fp_time_margin = FP_DEFAULT_TIME_MARGIN,
5045         };
5046         struct option long_opts[] = {
5047         { .val = 'A',   .name = "atime",        .has_arg = required_argument },
5048         { .val = 'b',   .name = "blocks",       .has_arg = required_argument },
5049         { .val = 'B',   .name = "btime",        .has_arg = required_argument },
5050         { .val = 'B',   .name = "Btime",        .has_arg = required_argument },
5051         { .val = LFS_COMP_COUNT_OPT,
5052                         .name = "comp-count",   .has_arg = required_argument },
5053         { .val = LFS_COMP_COUNT_OPT,
5054                         .name = "component-count",
5055                                                 .has_arg = required_argument },
5056         { .val = LFS_COMP_FLAGS_OPT,
5057                         .name = "comp-flags",   .has_arg = required_argument },
5058         { .val = LFS_COMP_FLAGS_OPT,
5059                         .name = "component-flags",
5060                                                 .has_arg = required_argument },
5061         { .val = LFS_COMP_START_OPT,
5062                         .name = "comp-start",   .has_arg = required_argument },
5063         { .val = LFS_COMP_START_OPT,
5064                         .name = "component-start",
5065                                                 .has_arg = required_argument },
5066         { .val = LFS_MIRROR_STATE_OPT,
5067                         .name = "mirror-state", .has_arg = required_argument },
5068         { .val = LFS_NEWERXY_OPT,
5069                         .name = "newer",        .has_arg = required_argument},
5070         { .val = LFS_NEWERXY_OPT,
5071                         .name = "neweraa",      .has_arg = required_argument},
5072         { .val = LFS_NEWERXY_OPT,
5073                         .name = "neweram",      .has_arg = required_argument},
5074         { .val = LFS_NEWERXY_OPT,
5075                         .name = "newerac",      .has_arg = required_argument},
5076         { .val = LFS_NEWERXY_OPT,
5077                         .name = "newerab",      .has_arg = required_argument},
5078         { .val = LFS_NEWERXY_OPT,
5079                         .name = "newerma",      .has_arg = required_argument},
5080         { .val = LFS_NEWERXY_OPT,
5081                         .name = "newermm",      .has_arg = required_argument},
5082         { .val = LFS_NEWERXY_OPT,
5083                         .name = "newermc",      .has_arg = required_argument},
5084         { .val = LFS_NEWERXY_OPT,
5085                         .name = "newermb",      .has_arg = required_argument},
5086         { .val = LFS_NEWERXY_OPT,
5087                         .name = "newerca",      .has_arg = required_argument},
5088         { .val = LFS_NEWERXY_OPT,
5089                         .name = "newercm",      .has_arg = required_argument},
5090         { .val = LFS_NEWERXY_OPT,
5091                         .name = "newercc",      .has_arg = required_argument},
5092         { .val = LFS_NEWERXY_OPT,
5093                         .name = "newercb",      .has_arg = required_argument},
5094         { .val = LFS_NEWERXY_OPT,
5095                         .name = "newerba",      .has_arg = required_argument},
5096         { .val = LFS_NEWERXY_OPT,
5097                         .name = "newerbm",      .has_arg = required_argument},
5098         { .val = LFS_NEWERXY_OPT,
5099                         .name = "newerbc",      .has_arg = required_argument},
5100         { .val = LFS_NEWERXY_OPT,
5101                         .name = "newerbb",      .has_arg = required_argument},
5102         { .val = LFS_NEWERXY_OPT,
5103                         .name = "newerBa",      .has_arg = required_argument},
5104         { .val = LFS_NEWERXY_OPT,
5105                         .name = "newerBm",      .has_arg = required_argument},
5106         { .val = LFS_NEWERXY_OPT,
5107                         .name = "newerBc",      .has_arg = required_argument},
5108         { .val = LFS_NEWERXY_OPT,
5109                         .name = "newerBB",      .has_arg = required_argument},
5110         { .val = LFS_NEWERXY_OPT,
5111                         .name = "newerat",      .has_arg = required_argument},
5112         { .val = LFS_NEWERXY_OPT,
5113                         .name = "newermt",      .has_arg = required_argument},
5114         { .val = LFS_NEWERXY_OPT,
5115                         .name = "newerct",      .has_arg = required_argument},
5116         { .val = LFS_NEWERXY_OPT,
5117                         .name = "newerbt",      .has_arg = required_argument},
5118         { .val = LFS_NEWERXY_OPT,
5119                         .name = "newerBt",      .has_arg = required_argument},
5120         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument },
5121         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument },
5122         { .val = 'C',   .name = "ctime",        .has_arg = required_argument },
5123 /* getstripe { .val = 'd', .name = "directory", .has_arg = no_argument }, */
5124         { .val = 'D',   .name = "maxdepth",     .has_arg = required_argument },
5125         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument },
5126         { .val = 'E',   .name = "component-end",
5127                                                 .has_arg = required_argument },
5128 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
5129         { .val = LFS_LAYOUT_FOREIGN_OPT,
5130                         .name = "foreign",      .has_arg = optional_argument},
5131         { .val = 'g',   .name = "gid",          .has_arg = required_argument },
5132         { .val = 'G',   .name = "group",        .has_arg = required_argument },
5133         { .val = 'h',   .name = "help",         .has_arg = no_argument },
5134         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
5135         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument },
5136         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument },
5137 /* getstripe { .val = 'I', .name = "comp-id",   .has_arg = required_argument }*/
5138         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
5139         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
5140         { .val = LFS_LINKS_OPT,
5141                         .name = "links",        .has_arg = required_argument },
5142         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
5143         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
5144         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument },
5145         { .val = 'M',   .name = "mtime",        .has_arg = required_argument },
5146         { .val = 'n',   .name = "name",         .has_arg = required_argument },
5147         { .val = 'N',   .name = "mirror-count", .has_arg = required_argument },
5148 /* find { .val = 'o'    .name = "or", .has_arg = no_argument }, like find(1) */
5149         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
5150         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
5151         { .val = LFS_FIND_PERM,
5152                         .name = "perm",         .has_arg = required_argument },
5153         /* no short option for pool yet, can be 'p' after 2.18 */
5154         { .val = LFS_POOL_OPT,
5155                         .name = "pool",         .has_arg = required_argument },
5156         { .val = '0',   .name = "print0",       .has_arg = no_argument },
5157         { .val = 'P',   .name = "print",        .has_arg = no_argument },
5158         { .val = LFS_PRINTF_OPT,
5159                         .name = "printf",       .has_arg = required_argument },
5160         { .val = LFS_PROJID_OPT,
5161                         .name = "projid",       .has_arg = required_argument },
5162 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
5163 /* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
5164 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
5165         { .val = 's',   .name = "size",         .has_arg = required_argument },
5166         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
5167         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
5168         { .val = 't',   .name = "type",         .has_arg = required_argument },
5169         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
5170         { .val = 'u',   .name = "uid",          .has_arg = required_argument },
5171         { .val = 'U',   .name = "user",         .has_arg = required_argument },
5172 /* getstripe { .val = 'v', .name = "verbose",   .has_arg = no_argument }, */
5173 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }, */
5174         { .val = 'z',   .name = "extension-size",
5175                                                 .has_arg = required_argument },
5176         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument },
5177         { .name = NULL } };
5178         int optidx = 0;
5179         int pathstart = -1;
5180         int pathend = -1;
5181         int pathbad = -1;
5182         int neg_opt = 0;
5183         time_t *xtime;
5184         int *xsign;
5185         int isoption;
5186         char *endptr;
5187
5188         time(&t);
5189
5190         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
5191         while ((c = getopt_long_only(argc, argv,
5192                 "-0A:b:B:c:C:D:E:g:G:hH:i:lL:m:M:n:N:O:Ppqrs:S:t:T:u:U:z:",
5193                 long_opts, &optidx)) >= 0) {
5194                 xtime = NULL;
5195                 xsign = NULL;
5196                 if (neg_opt)
5197                         --neg_opt;
5198                 /* '!' is part of option */
5199                 /*
5200                  * when getopt_long_only() finds a string which is not
5201                  * an option nor a known option argument it returns 1
5202                  * in that case if we already have found pathstart and pathend
5203                  * (i.e. we have the list of pathnames),
5204                  * the only supported value is "!"
5205                  */
5206                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
5207                 if (!isoption && pathend != -1) {
5208                         fprintf(stderr,
5209                                 "err: %s: filename|dirname must either precede options or follow options\n",
5210                                 argv[0]);
5211                         ret = CMD_HELP;
5212                         goto err;
5213                 }
5214                 if (!isoption && pathstart == -1)
5215                         pathstart = optind - 1;
5216                 if (isoption && pathstart != -1 && pathend == -1)
5217                         pathend = optind - 2;
5218                 switch (c) {
5219                 case 0:
5220                         /* Long options. */
5221                         break;
5222                 case 1:
5223                         /*
5224                          * unknown; opt is "!" or path component,
5225                          * checking done above.
5226                          */
5227                         if (strcmp(optarg, "!") == 0)
5228                                 neg_opt = 2;
5229                         break;
5230                 case 'A':
5231                         xtime = &param.fp_atime;
5232                         xsign = &param.fp_asign;
5233                         param.fp_exclude_atime = !!neg_opt;
5234                         /* no break, this falls through to 'B' for btime */
5235                         fallthrough;
5236                 case 'B':
5237                         if (c == 'B') {
5238                                 xtime = &param.fp_btime;
5239                                 xsign = &param.fp_bsign;
5240                                 param.fp_exclude_btime = !!neg_opt;
5241                         }
5242                         /* no break, this falls through to 'C' for ctime */
5243                         fallthrough;
5244                 case 'C':
5245                         if (c == 'C') {
5246                                 xtime = &param.fp_ctime;
5247                                 xsign = &param.fp_csign;
5248                                 param.fp_exclude_ctime = !!neg_opt;
5249                         }
5250                         /* no break, this falls through to 'M' for mtime */
5251                         fallthrough;
5252                 case 'M':
5253                         if (c == 'M') {
5254                                 xtime = &param.fp_mtime;
5255                                 xsign = &param.fp_msign;
5256                                 param.fp_exclude_mtime = !!neg_opt;
5257                         }
5258                         rc = set_time(&param, &t, xtime, optarg);
5259                         if (rc == INT_MAX) {
5260                                 ret = -1;
5261                                 goto err;
5262                         }
5263                         if (rc)
5264                                 *xsign = rc;
5265                         break;
5266                 case 'b':
5267                         if (optarg[0] == '+') {
5268                                 param.fp_blocks_sign = -1;
5269                                 optarg++;
5270                         } else if (optarg[0] == '-') {
5271                                 param.fp_blocks_sign =  1;
5272                                 optarg++;
5273                         }
5274
5275                         param.fp_blocks_units = 1024;
5276                         ret = llapi_parse_size(optarg, &param.fp_blocks,
5277                                                &param.fp_blocks_units, 0);
5278                         if (ret) {
5279                                 fprintf(stderr, "error: bad blocks '%s'\n",
5280                                         optarg);
5281                                 goto err;
5282                         }
5283                         param.fp_check_blocks = 1;
5284                         param.fp_exclude_blocks = !!neg_opt;
5285                         break;
5286                 case LFS_COMP_COUNT_OPT:
5287                         if (optarg[0] == '+') {
5288                                 param.fp_comp_count_sign = -1;
5289                                 optarg++;
5290                         } else if (optarg[0] == '-') {
5291                                 param.fp_comp_count_sign =  1;
5292                                 optarg++;
5293                         }
5294
5295                         errno = 0;
5296                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
5297                         if (errno != 0 || *endptr != '\0' ||
5298                             param.fp_comp_count > UINT32_MAX) {
5299                                 fprintf(stderr,
5300                                         "error: bad component count '%s'\n",
5301                                         optarg);
5302                                 goto err;
5303                         }
5304                         param.fp_check_comp_count = 1;
5305                         param.fp_exclude_comp_count = !!neg_opt;
5306                         break;
5307                 case LFS_COMP_FLAGS_OPT:
5308                         rc = comp_str2flags(optarg, &param.fp_comp_flags,
5309                                             &param.fp_comp_neg_flags);
5310                         if (rc) {
5311                                 fprintf(stderr,
5312                                         "error: bad component flags '%s'\n",
5313                                         optarg);
5314                                 goto err;
5315                         }
5316                         param.fp_check_comp_flags = 1;
5317                         if (neg_opt) {
5318                                 __u32 flags = param.fp_comp_neg_flags;
5319
5320                                 param.fp_comp_neg_flags = param.fp_comp_flags;
5321                                 param.fp_comp_flags = flags;
5322                         }
5323                         break;
5324                 case LFS_COMP_START_OPT:
5325                         if (optarg[0] == '+') {
5326                                 param.fp_comp_start_sign = -1;
5327                                 optarg++;
5328                         } else if (optarg[0] == '-') {
5329                                 param.fp_comp_start_sign =  1;
5330                                 optarg++;
5331                         }
5332
5333                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
5334                                               &param.fp_comp_start_units, 0);
5335                         if (rc) {
5336                                 fprintf(stderr,
5337                                         "error: bad component start '%s'\n",
5338                                         optarg);
5339                                 goto err;
5340                         }
5341                         param.fp_check_comp_start = 1;
5342                         param.fp_exclude_comp_start = !!neg_opt;
5343                         break;
5344                 case LFS_MIRROR_STATE_OPT:
5345                         rc = mirror_str2state(optarg, &param.fp_mirror_state,
5346                                               &param.fp_mirror_neg_state);
5347                         if (rc) {
5348                                 fprintf(stderr,
5349                                         "error: bad mirrored file state '%s'\n",
5350                                         optarg);
5351                                 goto err;
5352                         }
5353                         param.fp_check_mirror_state = 1;
5354                         if (neg_opt) {
5355                                 __u16 state = param.fp_mirror_neg_state;
5356
5357                                 param.fp_mirror_neg_state =
5358                                         param.fp_mirror_state;
5359                                 param.fp_mirror_state = state;
5360                         }
5361                         break;
5362                 case 'c':
5363                         if (optarg[0] == '+') {
5364                                 param.fp_stripe_count_sign = -1;
5365                                 optarg++;
5366                         } else if (optarg[0] == '-') {
5367                                 param.fp_stripe_count_sign =  1;
5368                                 optarg++;
5369                         }
5370
5371                         errno = 0;
5372                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
5373                         if (errno != 0 || *endptr != '\0' ||
5374                             param.fp_stripe_count > LOV_MAX_STRIPE_COUNT) {
5375                                 fprintf(stderr,
5376                                         "error: bad stripe_count '%s'\n",
5377                                         optarg);
5378                                 ret = -1;
5379                                 goto err;
5380                         }
5381                         param.fp_check_stripe_count = 1;
5382                         param.fp_exclude_stripe_count = !!neg_opt;
5383                         break;
5384                 case 'D':
5385                         errno = 0;
5386                         param.fp_max_depth = strtol(optarg, 0, 0);
5387                         if (errno != 0 || param.fp_max_depth < 0) {
5388                                 fprintf(stderr,
5389                                         "error: bad maxdepth '%s'\n",
5390                                         optarg);
5391                                 ret = -1;
5392                                 goto err;
5393                         }
5394                         break;
5395                 case 'E':
5396                         if (optarg[0] == '+') {
5397                                 param.fp_comp_end_sign = -1;
5398                                 optarg++;
5399                         } else if (optarg[0] == '-') {
5400                                 param.fp_comp_end_sign =  1;
5401                                 optarg++;
5402                         }
5403
5404                         if (arg_is_eof(optarg)) {
5405                                 param.fp_comp_end = LUSTRE_EOF;
5406                                 param.fp_comp_end_units = 1;
5407                                 rc = 0;
5408                         } else {
5409                                 rc = llapi_parse_size(optarg,
5410                                                 &param.fp_comp_end,
5411                                                 &param.fp_comp_end_units, 0);
5412                                 /* assume units of KB if too small */
5413                                 if (param.fp_comp_end < 4096)
5414                                         param.fp_comp_end *= 1024;
5415                         }
5416                         if (rc) {
5417                                 fprintf(stderr,
5418                                         "error: bad component end '%s'\n",
5419                                         optarg);
5420                                 goto err;
5421                         }
5422                         param.fp_check_comp_end = 1;
5423                         param.fp_exclude_comp_end = !!neg_opt;
5424                         break;
5425                 case LFS_LAYOUT_FOREIGN_OPT: {
5426                         /* all types by default */
5427                         uint32_t type = LU_FOREIGN_TYPE_UNKNOWN;
5428
5429                         if (optarg) {
5430                                 /* check pure numeric */
5431                                 type = strtoul(optarg, &endptr, 0);
5432                                 if (*endptr) {
5433                                         /* check name */
5434                                         type = check_foreign_type_name(optarg);
5435                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
5436                                                 fprintf(stderr,
5437                                                         "%s %s: unknown foreign type '%s'\n",
5438                                                         progname, argv[0],
5439                                                         optarg);
5440                                                 return CMD_HELP;
5441                                         }
5442                                 } else if (type >= UINT32_MAX) {
5443                                         fprintf(stderr,
5444                                                 "%s %s: invalid foreign type '%s'\n",
5445                                                 progname, argv[0], optarg);
5446                                         return CMD_HELP;
5447                                 }
5448                         }
5449                         param.fp_foreign_type = type;
5450                         param.fp_check_foreign = 1;
5451                         param.fp_exclude_foreign = !!neg_opt;
5452                         break;
5453                 }
5454                 case LFS_NEWERXY_OPT: {
5455                         char x = 'm';
5456                         char y = 'm';
5457                         int xidx;
5458                         int negidx;
5459                         time_t *newery;
5460                         time_t ref = time(NULL);
5461
5462                         /* no need to check bad options, they won't get here */
5463                         if (strlen(long_opts[optidx].name) == 7) {
5464                                 x = long_opts[optidx].name[5];
5465                                 y = long_opts[optidx].name[6];
5466                         }
5467
5468                         if (y == 't') {
5469                                 static const char *const fmts[] = {
5470                                         "%Y-%m-%d %H:%M:%S",
5471                                         "%Y-%m-%d %H:%M",
5472                                         "%Y-%m-%d",
5473                                         "%H:%M:%S", /* sometime today */
5474                                         "%H:%M",
5475                                         "@%s",
5476                                         "%s",
5477                                         NULL };
5478                                 struct tm tm;
5479                                 bool found = false;
5480                                 int i;
5481
5482                                 for (i = 0; fmts[i] != NULL; i++) {
5483                                         char *ptr;
5484
5485                                         /* Init for times relative to today */
5486                                         if (strncmp(fmts[i], "%H", 2) == 0) {
5487                                                 localtime_r(&ref, &tm);
5488                                         } else {
5489                                                 memset(&tm, 0, sizeof(tm));
5490                                                 tm.tm_isdst = -1;
5491                                         }
5492                                         ptr = strptime(optarg, fmts[i], &tm);
5493                                         /* Skip spaces */
5494                                         while (ptr && isspace(*ptr))
5495                                                 ptr++;
5496                                         if (ptr == optarg + strlen(optarg)) {
5497                                                 found = true;
5498                                                 break;
5499                                         }
5500                                 }
5501
5502                                 if (!found) {
5503                                         fprintf(stderr,
5504                                                 "%s: invalid time '%s'\n",
5505                                                 progname, optarg);
5506                                         fprintf(stderr,
5507                                                 "supported formats are:\n  ");
5508                                         for (i = 0; fmts[i] != NULL; i++)
5509                                                 fprintf(stderr, "'%s', ",
5510                                                         fmts[i]);
5511                                         fprintf(stderr, "\n");
5512                                         ret = -EINVAL;
5513                                         goto err;
5514                                 }
5515
5516                                 ref = mktime(&tm);
5517                         } else if (y == 'b' || y == 'B') {
5518                                 lstatx_t stx;
5519
5520                                 rc = llapi_get_lum_file(optarg, NULL, &stx,
5521                                                         NULL, 0);
5522                                 if (rc || !(stx.stx_mask & STATX_BTIME)) {
5523                                         if (!(stx.stx_mask & STATX_BTIME))
5524                                                 ret = -EOPNOTSUPP;
5525                                         else
5526                                                 ret = -errno;
5527                                         fprintf(stderr,
5528                                                 "%s: get btime failed '%s': %s\n",
5529                                                 progname, optarg,
5530                                                 strerror(-ret));
5531                                         goto err;
5532                                 }
5533
5534                                 ref = stx.stx_btime.tv_sec;
5535                         } else {
5536                                 struct stat statbuf;
5537
5538                                 if (stat(optarg, &statbuf) < 0) {
5539                                         fprintf(stderr,
5540                                                 "%s: cannot stat file '%s': %s\n",
5541                                                 progname, optarg,
5542                                                 strerror(errno));
5543                                         ret = -errno;
5544                                         goto err;
5545                                 }
5546
5547                                 switch (y) {
5548                                 case 'a':
5549                                         ref = statbuf.st_atime;
5550                                         break;
5551                                 case 'm':
5552                                         ref = statbuf.st_mtime;
5553                                         break;
5554                                 case 'c':
5555                                         ref = statbuf.st_ctime;
5556                                         break;
5557                                 default:
5558                                         fprintf(stderr,
5559                                                 "%s: invalid Y argument: '%c'\n",
5560                                                 progname, x);
5561                                         ret = -EINVAL;
5562                                         goto err;
5563                                 }
5564                         }
5565
5566                         switch (x) {
5567                         case 'a':
5568                                 xidx = NEWERXY_ATIME;
5569                                 break;
5570                         case 'm':
5571                                 xidx = NEWERXY_MTIME;
5572                                 break;
5573                         case 'c':
5574                                 xidx = NEWERXY_CTIME;
5575                                 break;
5576                         case 'b':
5577                         case 'B':
5578                                 xidx = NEWERXY_BTIME;
5579                                 break;
5580                         default:
5581                                 fprintf(stderr,
5582                                         "%s: invalid X argument: '%c'\n",
5583                                         progname, x);
5584                                 ret = -EINVAL;
5585                                 goto err;
5586                         }
5587
5588                         negidx = !!neg_opt;
5589                         newery = &param.fp_newery[xidx][negidx];
5590
5591                         if (*newery == 0) {
5592                                 *newery = ref;
5593                         } else {
5594                                 if (negidx)
5595                                         *newery = *newery > ref ? ref : *newery;
5596                                 else
5597                                         *newery = *newery > ref ? *newery : ref;
5598                         }
5599                         param.fp_newerxy = 1;
5600                         break;
5601                 }
5602                 case 'g':
5603                 case 'G':
5604                         rc = name2gid(&param.fp_gid, optarg);
5605                         if (rc) {
5606                                 if (str2quotaid(&param.fp_gid, optarg)) {
5607                                         fprintf(stderr,
5608                                                 "Group/GID: %s cannot be found.\n",
5609                                                 optarg);
5610                                         ret = -1;
5611                                         goto err;
5612                                 }
5613                         }
5614                         param.fp_exclude_gid = !!neg_opt;
5615                         param.fp_check_gid = 1;
5616                         break;
5617                 case 'H':
5618                         rc = mdthash_input(optarg, &param.fp_hash_inflags,
5619                                            &param.fp_hash_exflags,
5620                                            &param.fp_hash_type);
5621                         if (rc) {
5622                                 ret = -1;
5623                                 goto err;
5624                         }
5625                         if (param.fp_hash_inflags || param.fp_hash_exflags)
5626                                 param.fp_check_hash_flag = 1;
5627                         param.fp_exclude_hash_type = !!neg_opt;
5628                         break;
5629                 case 'l':
5630                         param.fp_lazy = 1;
5631                         break;
5632                 case 'L':
5633                         ret = name2layout(&param.fp_layout, optarg);
5634                         if (ret)
5635                                 goto err;
5636                         param.fp_exclude_layout = !!neg_opt;
5637                         param.fp_check_layout = 1;
5638                         break;
5639                 case LFS_LINKS_OPT:
5640                         if (optarg[0] == '+') {
5641                                 param.fp_nlink_sign = -1;
5642                                 optarg++;
5643                         } else if (optarg[0] == '-') {
5644                                 param.fp_nlink_sign =  1;
5645                                 optarg++;
5646                         }
5647                         errno = 0;
5648                         param.fp_nlink = strtoul(optarg, &endptr, 0);
5649                         if (errno != 0 || *endptr != '\0' || !param.fp_nlink) {
5650                                 fprintf(stderr, "error: bad link count '%s'\n",
5651                                         optarg);
5652                                 ret = -1;
5653                                 goto err;
5654                         }
5655                         param.fp_exclude_nlink = !!neg_opt;
5656                         break;
5657                 case 'u':
5658                 case 'U':
5659                         rc = name2uid(&param.fp_uid, optarg);
5660                         if (rc) {
5661                                 if (str2quotaid(&param.fp_uid, optarg)) {
5662                                         fprintf(stderr,
5663                                                 "User/UID: %s cannot be found.\n",
5664                                                 optarg);
5665                                         ret = -1;
5666                                         goto err;
5667                                 }
5668                         }
5669                         param.fp_exclude_uid = !!neg_opt;
5670                         param.fp_check_uid = 1;
5671                         break;
5672                 case 'n':
5673                         param.fp_pattern = (char *)optarg;
5674                         param.fp_exclude_pattern = !!neg_opt;
5675                         break;
5676                 case 'N':
5677                         if (optarg[0] == '+') {
5678                                 param.fp_mirror_count_sign = -1;
5679                                 optarg++;
5680                         } else if (optarg[0] == '-') {
5681                                 param.fp_mirror_count_sign =  1;
5682                                 optarg++;
5683                         }
5684
5685                         errno = 0;
5686                         param.fp_mirror_count = strtoul(optarg, &endptr, 0);
5687                         if (errno != 0 || *endptr != '\0' ||
5688                             param.fp_mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
5689                                 fprintf(stderr,
5690                                         "error: bad mirror count '%s'\n",
5691                                         optarg);
5692                                 goto err;
5693                         }
5694                         param.fp_check_mirror_count = 1;
5695                         param.fp_exclude_mirror_count = !!neg_opt;
5696                         break;
5697                 case 'm':
5698                 case 'i':
5699                 case 'O': {
5700                         char *buf, *token, *next, *p;
5701                         int len = 1;
5702                         void *tmp;
5703
5704                         buf = strdup(optarg);
5705                         if (!buf) {
5706                                 ret = -ENOMEM;
5707                                 goto err;
5708                         }
5709
5710                         param.fp_exclude_obd = !!neg_opt;
5711
5712                         token = buf;
5713                         while (token && *token) {
5714                                 token = strchr(token, ',');
5715                                 if (token) {
5716                                         len++;
5717                                         token++;
5718                                 }
5719                         }
5720                         if (c == 'm') {
5721                                 param.fp_exclude_mdt = !!neg_opt;
5722                                 param.fp_num_alloc_mdts += len;
5723                                 tmp = realloc(param.fp_mdt_uuid,
5724                                               param.fp_num_alloc_mdts *
5725                                               sizeof(*param.fp_mdt_uuid));
5726                                 if (!tmp) {
5727                                         ret = -ENOMEM;
5728                                         goto err_free;
5729                                 }
5730
5731                                 param.fp_mdt_uuid = tmp;
5732                         } else {
5733                                 param.fp_exclude_obd = !!neg_opt;
5734                                 param.fp_num_alloc_obds += len;
5735                                 tmp = realloc(param.fp_obd_uuid,
5736                                               param.fp_num_alloc_obds *
5737                                               sizeof(*param.fp_obd_uuid));
5738                                 if (!tmp) {
5739                                         ret = -ENOMEM;
5740                                         goto err_free;
5741                                 }
5742
5743                                 param.fp_obd_uuid = tmp;
5744                         }
5745                         for (token = buf; token && *token; token = next) {
5746                                 struct obd_uuid *puuid;
5747
5748                                 if (c == 'm') {
5749                                         puuid =
5750                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
5751                                 } else {
5752                                         puuid =
5753                                         &param.fp_obd_uuid[param.fp_num_obds++];
5754                                 }
5755                                 p = strchr(token, ',');
5756                                 next = 0;
5757                                 if (p) {
5758                                         *p = 0;
5759                                         next = p+1;
5760                                 }
5761
5762                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
5763                                         ret = -E2BIG;
5764                                         goto err_free;
5765                                 }
5766
5767                                 strncpy(puuid->uuid, token,
5768                                         sizeof(puuid->uuid));
5769                         }
5770 err_free:
5771                         if (buf)
5772                                 free(buf);
5773                         break;
5774                 }
5775 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 18, 53, 0)
5776                 case 'p':
5777 #endif
5778                 case LFS_POOL_OPT:
5779                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
5780                                 fprintf(stderr,
5781                                         "Pool name %s is too long (max %d)\n",
5782                                         optarg, LOV_MAXPOOLNAME);
5783                                 ret = -1;
5784                                 goto err;
5785                         }
5786                         /*
5787                          * We do check for empty pool because empty pool
5788                          * is used to find V1 LOV attributes
5789                          */
5790                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
5791                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
5792                         param.fp_exclude_pool = !!neg_opt;
5793                         param.fp_check_pool = 1;
5794                         break;
5795                 case '0':
5796                         param.fp_zero_end = 1;
5797                         break;
5798                 case 'P': /* we always print, this option is a no-op */
5799                         break;
5800                 case LFS_PRINTF_OPT:
5801                         param.fp_format_printf_str = strdup(optarg);
5802                         break;
5803                 case LFS_PROJID_OPT:
5804                         rc = name2projid(&param.fp_projid, optarg);
5805                         if (rc) {
5806                                 if (str2quotaid(&param.fp_projid, optarg)) {
5807                                         fprintf(stderr,
5808                                                 "Invalid project ID: %s\n",
5809                                                 optarg);
5810                                         ret = -1;
5811                                         goto err;
5812                                 }
5813                         }
5814                         param.fp_exclude_projid = !!neg_opt;
5815                         param.fp_check_projid = 1;
5816                         break;
5817                 case 's':
5818                         if (optarg[0] == '+') {
5819                                 param.fp_size_sign = -1;
5820                                 optarg++;
5821                         } else if (optarg[0] == '-') {
5822                                 param.fp_size_sign =  1;
5823                                 optarg++;
5824                         }
5825
5826                         ret = llapi_parse_size(optarg, &param.fp_size,
5827                                                &param.fp_size_units, 0);
5828                         if (ret) {
5829                                 fprintf(stderr, "error: bad file size '%s'\n",
5830                                         optarg);
5831                                 goto err;
5832                         }
5833                         param.fp_check_size = 1;
5834                         param.fp_exclude_size = !!neg_opt;
5835                         break;
5836                 case 'S':
5837                         if (optarg[0] == '+') {
5838                                 param.fp_stripe_size_sign = -1;
5839                                 optarg++;
5840                         } else if (optarg[0] == '-') {
5841                                 param.fp_stripe_size_sign =  1;
5842                                 optarg++;
5843                         }
5844
5845                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
5846                                                &param.fp_stripe_size_units, 0);
5847                         /* assume units of KB if too small to be valid */
5848                         if (param.fp_stripe_size < 4096)
5849                                 param.fp_stripe_size *= 1024;
5850                         if (ret) {
5851                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
5852                                         optarg);
5853                                 goto err;
5854                         }
5855                         param.fp_check_stripe_size = 1;
5856                         param.fp_exclude_stripe_size = !!neg_opt;
5857                         break;
5858                 case 't':
5859                         param.fp_exclude_type = !!neg_opt;
5860                         switch (optarg[0]) {
5861                         case 'b':
5862                                 param.fp_type = S_IFBLK;
5863                                 break;
5864                         case 'c':
5865                                 param.fp_type = S_IFCHR;
5866                                 break;
5867                         case 'd':
5868                                 param.fp_type = S_IFDIR;
5869                                 break;
5870                         case 'f':
5871                                 param.fp_type = S_IFREG;
5872                                 break;
5873                         case 'l':
5874                                 param.fp_type = S_IFLNK;
5875                                 break;
5876                         case 'p':
5877                                 param.fp_type = S_IFIFO;
5878                                 break;
5879                         case 's':
5880                                 param.fp_type = S_IFSOCK;
5881                                 break;
5882                         default:
5883                                 fprintf(stderr, "%s: bad type '%s'\n",
5884                                         progname, optarg);
5885                                 ret = CMD_HELP;
5886                                 goto err;
5887                         }
5888                         break;
5889                 case LFS_FIND_PERM:
5890                         param.fp_exclude_perm = !!neg_opt;
5891                         param.fp_perm_sign = LFS_FIND_PERM_EXACT;
5892                         if (*optarg == '/') {
5893                                 param.fp_perm_sign = LFS_FIND_PERM_ANY;
5894                                 optarg++;
5895                         } else if (*optarg == '-') {
5896                                 param.fp_perm_sign = LFS_FIND_PERM_ALL;
5897                                 optarg++;
5898                         }
5899
5900                         if (str2mode_t(optarg, &param.fp_perm)) {
5901                                 fprintf(stderr, "error: invalid mode '%s'\n",
5902                                         optarg);
5903                                 ret = -1;
5904                                 goto err;
5905                         }
5906                         break;
5907                 case 'T':
5908                         if (optarg[0] == '+') {
5909                                 param.fp_mdt_count_sign = -1;
5910                                 optarg++;
5911                         } else if (optarg[0] == '-') {
5912                                 param.fp_mdt_count_sign =  1;
5913                                 optarg++;
5914                         }
5915
5916                         errno = 0;
5917                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
5918                         if (errno != 0 || *endptr != '\0' ||
5919                             param.fp_mdt_count >= UINT32_MAX) {
5920                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
5921                                         optarg);
5922                                 ret = -1;
5923                                 goto err;
5924                         }
5925                         param.fp_check_mdt_count = 1;
5926                         param.fp_exclude_mdt_count = !!neg_opt;
5927                         break;
5928                 case 'z':
5929                         if (optarg[0] == '+') {
5930                                 param.fp_ext_size_sign = -1;
5931                                 optarg++;
5932                         } else if (optarg[0] == '-') {
5933                                 param.fp_ext_size_sign =  1;
5934                                 optarg++;
5935                         }
5936
5937                         ret = llapi_parse_size(optarg, &param.fp_ext_size,
5938                                                &param.fp_ext_size_units, 0);
5939                         if (ret) {
5940                                 fprintf(stderr, "error: bad ext-size '%s'\n",
5941                                         optarg);
5942                                 goto err;
5943                         }
5944                         param.fp_ext_size /= SEL_UNIT_SIZE;
5945                         param.fp_ext_size_units /= SEL_UNIT_SIZE;
5946                         param.fp_check_ext_size = 1;
5947                         param.fp_exclude_ext_size = !!neg_opt;
5948                         break;
5949                 default:
5950                         fprintf(stderr, "%s: unrecognized option '%s'\n",
5951                                 progname, argv[optind - 1]);
5952                 case 'h':
5953                         ret = CMD_HELP;
5954                         goto err;
5955                 }
5956         }
5957         if (!param.fp_verbose)
5958                 param.fp_verbose = VERBOSE_DEFAULT;
5959
5960         if (pathstart == -1) {
5961                 fprintf(stderr, "error: %s: no filename|pathname\n",
5962                         argv[0]);
5963                 ret = CMD_HELP;
5964                 goto err;
5965         } else if (pathend == -1) {
5966                 /* no options */
5967                 pathend = argc;
5968         }
5969
5970         do {
5971                 rc = llapi_find(argv[pathstart], &param);
5972                 if (rc && !ret) {
5973                         ret = rc;
5974                         pathbad = pathstart;
5975                 }
5976         } while (++pathstart < pathend);
5977
5978         if (ret)
5979                 fprintf(stderr, "%s: failed for '%s': %s\n",
5980                         progname, argv[pathbad], strerror(-rc));
5981
5982 err:
5983         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
5984                 free(param.fp_obd_uuid);
5985
5986         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
5987                 free(param.fp_mdt_uuid);
5988
5989         if (param.fp_format_printf_str)
5990                 free(param.fp_format_printf_str);
5991
5992         return ret;
5993 }
5994
5995 static int lfs_getstripe_internal(int argc, char **argv,
5996                                   struct find_param *param)
5997 {
5998         struct option long_opts[] = {
5999 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
6000 /* find { .val = 'b',   .name = "blocks",       .has_arg = required_argument }*/
6001 /* find { .val = 'B',   .name = "btime",        .has_arg = required_argument }*/
6002 /* find { .val = 'B',   .name = "Btime",        .has_arg = required_argument }*/
6003         { .val = LFS_COMP_COUNT_OPT,
6004                         .name = "comp-count",   .has_arg = no_argument },
6005         { .val = LFS_COMP_COUNT_OPT,
6006                 .name = "component-count",      .has_arg = no_argument },
6007         { .val = LFS_COMP_FLAGS_OPT,
6008                         .name = "comp-flags",   .has_arg = optional_argument },
6009         { .val = LFS_COMP_FLAGS_OPT,
6010                 .name = "component-flags",      .has_arg = optional_argument },
6011         { .val = LFS_COMP_START_OPT,
6012                         .name = "comp-start",   .has_arg = optional_argument },
6013         { .val = LFS_COMP_START_OPT,
6014                 .name = "component-start",      .has_arg = optional_argument },
6015         { .val = 'c',   .name = "stripe-count", .has_arg = no_argument },
6016         { .val = 'c',   .name = "stripe_count", .has_arg = no_argument },
6017 /* find { .val = 'C',   .name = "ctime",        .has_arg = required_argument }*/
6018         { .val = 'd',   .name = "directory",    .has_arg = no_argument },
6019         { .val = 'D',   .name = "default",      .has_arg = no_argument },
6020         { .val = 'E',   .name = "comp-end",     .has_arg = optional_argument },
6021         { .val = 'E',   .name = "component-end", .has_arg = optional_argument },
6022         { .val = 'F',   .name = "fid",          .has_arg = no_argument },
6023         { .val = 'g',   .name = "generation",   .has_arg = no_argument },
6024 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
6025         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6026         { .val = LFS_HEX_IDX_OPT,
6027                         .name = "hex-idx",      .has_arg = no_argument },
6028 /* dirstripe { .val = 'H', .name = "mdt-hash",  .has_arg = required_argument }*/
6029         { .val = 'i',   .name = "stripe-index", .has_arg = no_argument },
6030         { .val = 'i',   .name = "stripe_index", .has_arg = no_argument },
6031         { .val = 'I',   .name = "comp-id",      .has_arg = optional_argument },
6032         { .val = 'I',   .name = "component-id", .has_arg = optional_argument },
6033 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
6034         { .val = 'L',   .name = "layout",       .has_arg = no_argument },
6035         { .val = 'm',   .name = "mdt",          .has_arg = no_argument },
6036         { .val = 'm',   .name = "mdt-index",    .has_arg = no_argument },
6037         { .val = 'm',   .name = "mdt_index",    .has_arg = no_argument },
6038 /* find { .val = 'M',   .name = "mtime",        .has_arg = required_argument }*/
6039 /* find { .val = 'n',   .name = "name",         .has_arg = required_argument }*/
6040         { .val = 'N',   .name = "mirror-count", .has_arg = no_argument },
6041         { .val = LFS_MIRROR_INDEX_OPT,
6042                         .name = "mirror-index", .has_arg = required_argument },
6043         { .val = LFS_MIRROR_ID_OPT,
6044                         .name = "mirror-id",    .has_arg = required_argument },
6045         { .val = LFS_NO_FOLLOW_OPT,
6046                         .name = "no-follow",    .has_arg = no_argument },
6047         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
6048         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
6049         { .val = 'p',   .name = "pool",         .has_arg = no_argument },
6050 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
6051         { .val = 'q',   .name = "quiet",        .has_arg = no_argument },
6052         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
6053         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
6054         { .val = 'S',   .name = "stripe-size",  .has_arg = no_argument },
6055         { .val = 'S',   .name = "stripe_size",  .has_arg = no_argument },
6056 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
6057 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
6058 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
6059 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
6060         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
6061 /* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/
6062 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }*/
6063         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
6064         { .val = 'z',   .name = "extension-size", .has_arg = no_argument },
6065         { .val = 'z',   .name = "ext-size",     .has_arg = no_argument },
6066         { .name = NULL } };
6067         int c, rc = 0;
6068         int neg_opt = 0;
6069         int pathstart = -1, pathend = -1;
6070         int isoption;
6071         char *end, *tmp;
6072
6073         while ((c = getopt_long(argc, argv,
6074                         "-cdDE::FghiI::LmMNoO:pqrRsSvyz",
6075                         long_opts, NULL)) != -1) {
6076                 if (neg_opt)
6077                         --neg_opt;
6078
6079                 /* '!' is part of option */
6080                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
6081                 if (!isoption && pathend != -1) {
6082                         fprintf(stderr,
6083                                 "error: %s: filename|dirname must either precede options or follow options\n",
6084                                 argv[0]);
6085                         return CMD_HELP;
6086                 }
6087                 if (!isoption && pathstart == -1)
6088                         pathstart = optind - 1;
6089                 if (isoption && pathstart != -1 && pathend == -1)
6090                         pathend = optind - 2;
6091
6092                 switch (c) {
6093                 case 1:
6094                         /* unknown: opt is "!" */
6095                         if (strcmp(optarg, "!") == 0)
6096                                 neg_opt = 2;
6097                         break;
6098                 case 'c':
6099                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6100                                 param->fp_verbose |= VERBOSE_COUNT;
6101                                 param->fp_max_depth = 0;
6102                         }
6103                         break;
6104                 case LFS_COMP_COUNT_OPT:
6105                         param->fp_verbose |= VERBOSE_COMP_COUNT;
6106                         param->fp_max_depth = 0;
6107                         break;
6108                 case LFS_COMP_FLAGS_OPT:
6109                         if (optarg) {
6110                                 rc = comp_str2flags(optarg,
6111                                                     &param->fp_comp_flags,
6112                                                     &param->fp_comp_neg_flags);
6113                                 if (rc != 0) {
6114                                         fprintf(stderr,
6115                                                 "error: %s bad component flags '%s'.\n",
6116                                                 argv[0], optarg);
6117                                         return CMD_HELP;
6118                                 }
6119                                 param->fp_check_comp_flags = 1;
6120                         } else {
6121                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
6122                                 param->fp_max_depth = 0;
6123                         }
6124                         break;
6125                 case LFS_COMP_START_OPT:
6126                         if (optarg) {
6127                                 tmp = optarg;
6128                                 if (tmp[0] == '+') {
6129                                         param->fp_comp_start_sign = -1;
6130                                         tmp++;
6131                                 } else if (tmp[0] == '-') {
6132                                         param->fp_comp_start_sign = 1;
6133                                         tmp++;
6134                                 }
6135                                 rc = llapi_parse_size(tmp,
6136                                                 &param->fp_comp_start,
6137                                                 &param->fp_comp_start_units, 0);
6138                                 if (rc != 0) {
6139                                         fprintf(stderr,
6140                                                 "error: %s bad component start '%s'.\n",
6141                                                 argv[0], tmp);
6142                                         return CMD_HELP;
6143                                 }
6144                                 param->fp_check_comp_start = 1;
6145                         } else {
6146                                 param->fp_verbose |= VERBOSE_COMP_START;
6147                                 param->fp_max_depth = 0;
6148                         }
6149                         break;
6150                 case LFS_MIRROR_INDEX_OPT: {
6151                         unsigned long int mirror_index;
6152
6153                         if (optarg[0] == '+') {
6154                                 param->fp_mirror_index_sign = -1;
6155                                 optarg++;
6156                         } else if (optarg[0] == '-') {
6157                                 param->fp_mirror_index_sign = 1;
6158                                 optarg++;
6159                         }
6160
6161                         errno = 0;
6162                         mirror_index = strtoul(optarg, &end, 0);
6163                         if (errno != 0 || *end != '\0' ||
6164                             mirror_index > UINT16_MAX || (mirror_index == 0 &&
6165                             param->fp_mirror_index_sign == 0 && neg_opt == 0)) {
6166                                 fprintf(stderr,
6167                                         "%s %s: invalid mirror index '%s'\n",
6168                                         progname, argv[0], optarg);
6169                                 return CMD_HELP;
6170                         }
6171
6172                         param->fp_mirror_index = (__u16)mirror_index;
6173
6174                         if (param->fp_mirror_id != 0) {
6175                                 fprintf(stderr,
6176                                         "%s %s: can't specify both mirror index and mirror ID\n",
6177                                         progname, argv[0]);
6178                                 return CMD_HELP;
6179                         }
6180                         param->fp_check_mirror_index = 1;
6181                         param->fp_exclude_mirror_index = !!neg_opt;
6182                         break;
6183                 }
6184                 case LFS_MIRROR_ID_OPT: {
6185                         unsigned long int mirror_id;
6186
6187                         if (optarg[0] == '+') {
6188                                 param->fp_mirror_id_sign = -1;
6189                                 optarg++;
6190                         } else if (optarg[0] == '-') {
6191                                 param->fp_mirror_id_sign = 1;
6192                                 optarg++;
6193                         }
6194
6195                         errno = 0;
6196                         mirror_id = strtoul(optarg, &end, 0);
6197                         if (errno != 0 || *end != '\0' ||
6198                             mirror_id > UINT16_MAX || (mirror_id == 0 &&
6199                             param->fp_mirror_id_sign == 0 && neg_opt == 0)) {
6200                                 fprintf(stderr,
6201                                         "%s %s: invalid mirror ID '%s'\n",
6202                                         progname, argv[0], optarg);
6203                                 return CMD_HELP;
6204                         }
6205
6206                         param->fp_mirror_id = (__u16)mirror_id;
6207
6208                         if (param->fp_mirror_index != 0) {
6209                                 fprintf(stderr,
6210                                         "%s %s: can't specify both mirror index and mirror ID\n",
6211                                         progname, argv[0]);
6212                                 return CMD_HELP;
6213                         }
6214                         param->fp_check_mirror_id = 1;
6215                         param->fp_exclude_mirror_id = !!neg_opt;
6216                         break;
6217                 }
6218                 case LFS_NO_FOLLOW_OPT:
6219                         param->fp_no_follow = true;
6220                         break;
6221                 case LFS_HEX_IDX_OPT:
6222                         param->fp_hex_idx = true;
6223                         break;
6224                 case 'd':
6225                         param->fp_max_depth = 0;
6226                         break;
6227                 case 'D':
6228                         param->fp_get_default_lmv = 1;
6229                         break;
6230                 case 'E':
6231                         if (optarg) {
6232                                 tmp = optarg;
6233                                 if (tmp[0] == '+') {
6234                                         param->fp_comp_end_sign = -1;
6235                                         tmp++;
6236                                 } else if (tmp[0] == '-') {
6237                                         param->fp_comp_end_sign = 1;
6238                                         tmp++;
6239                                 }
6240
6241                                 if (arg_is_eof(tmp)) {
6242                                         param->fp_comp_end = LUSTRE_EOF;
6243                                         param->fp_comp_end_units = 1;
6244                                         rc = 0;
6245                                 } else {
6246                                         rc = llapi_parse_size(tmp,
6247                                                 &param->fp_comp_end,
6248                                                 &param->fp_comp_end_units, 0);
6249                                         /* assume units of KB if too small */
6250                                         if (param->fp_comp_end < 4096)
6251                                                 param->fp_comp_end *= 1024;
6252                                 }
6253                                 if (rc != 0) {
6254                                         fprintf(stderr,
6255                                                 "error: %s bad component end '%s'.\n",
6256                                                 argv[0], tmp);
6257                                         return CMD_HELP;
6258                                 }
6259                                 param->fp_check_comp_end = 1;
6260                         } else {
6261                                 param->fp_verbose |= VERBOSE_COMP_END;
6262                                 param->fp_max_depth = 0;
6263                         }
6264                         break;
6265                 case 'F':
6266                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6267                                 param->fp_verbose |= VERBOSE_DFID;
6268                                 param->fp_max_depth = 0;
6269                         }
6270                         break;
6271                 case 'g':
6272                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6273                                 param->fp_verbose |= VERBOSE_GENERATION;
6274                                 param->fp_max_depth = 0;
6275                         }
6276                         break;
6277                 case 'i':
6278                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6279                                 param->fp_verbose |= VERBOSE_STRIPE_OFFSET;
6280                                 param->fp_max_depth = 0;
6281                         }
6282                         break;
6283                 case 'I':
6284                         if (optarg) {
6285                                 param->fp_comp_id = strtoul(optarg, &end, 0);
6286                                 if (*end != '\0' || param->fp_comp_id == 0 ||
6287                                     param->fp_comp_id > LCME_ID_MAX) {
6288                                         fprintf(stderr,
6289                                                 "error: %s bad component id '%s'\n",
6290                                                 argv[0], optarg);
6291                                         return CMD_HELP;
6292                                 }
6293                                 param->fp_check_comp_id = 1;
6294                         } else {
6295                                 param->fp_max_depth = 0;
6296                                 param->fp_verbose |= VERBOSE_COMP_ID;
6297                         }
6298                         break;
6299                 case 'L':
6300                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6301                                 param->fp_verbose |= VERBOSE_PATTERN;
6302                                 param->fp_max_depth = 0;
6303                         }
6304                         break;
6305 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6306                 case 'M':
6307                         fprintf(stderr,
6308                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
6309 #endif
6310                 case 'm':
6311                         if (!(param->fp_verbose & VERBOSE_DETAIL))
6312                                 param->fp_max_depth = 0;
6313                         param->fp_verbose |= VERBOSE_MDTINDEX;
6314                         break;
6315                 case 'N':
6316                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6317                                 param->fp_verbose |= VERBOSE_MIRROR_COUNT;
6318                                 param->fp_max_depth = 0;
6319                         }
6320                         break;
6321                 case 'O':
6322                         if (param->fp_obd_uuid) {
6323                                 fprintf(stderr,
6324                                         "error: %s: only one obduuid allowed",
6325                                         argv[0]);
6326                                 return CMD_HELP;
6327                         }
6328                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
6329                         break;
6330                 case 'p':
6331                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6332                                 param->fp_verbose |= VERBOSE_POOL;
6333                                 param->fp_max_depth = 0;
6334                         }
6335                         break;
6336                 case 'q':
6337                         param->fp_quiet++;
6338                         break;
6339                 case 'r':
6340                         param->fp_recursive = 1;
6341                         break;
6342                 case 'R':
6343                         param->fp_raw = 1;
6344                         break;
6345                 case 'S':
6346                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6347                                 param->fp_verbose |= VERBOSE_STRIPE_SIZE;
6348                                 param->fp_max_depth = 0;
6349                         }
6350                         break;
6351                 case 'v':
6352                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
6353                         break;
6354                 case 'y':
6355                         param->fp_yaml = 1;
6356                         break;
6357                 case 'z':
6358                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6359                                 param->fp_verbose |= VERBOSE_EXT_SIZE;
6360                                 param->fp_max_depth = 0;
6361                         }
6362                         break;
6363                 default:
6364                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6365                                 progname, argv[optind - 1]);
6366                 case 'h':
6367                         return CMD_HELP;
6368                 }
6369         }
6370
6371         if (pathstart == -1) {
6372                 fprintf(stderr, "error: %s: no filename|pathname\n",
6373                                 argv[0]);
6374                 return CMD_HELP;
6375         } else if (pathend == -1) {
6376                 /* no options */
6377                 pathend = argc;
6378         }
6379
6380         if (pathend > argc)
6381                 return CMD_HELP;
6382
6383         if (param->fp_recursive)
6384                 param->fp_max_depth = -1;
6385         else if (param->fp_verbose & VERBOSE_DETAIL)
6386                 param->fp_max_depth = 1;
6387
6388         if (!param->fp_verbose)
6389                 param->fp_verbose = VERBOSE_DEFAULT;
6390         if (param->fp_quiet)
6391                 param->fp_verbose = VERBOSE_OBJID;
6392
6393         do {
6394                 int rc2;
6395
6396                 rc2 = llapi_getstripe(argv[pathstart], param);
6397                 if (rc2) {
6398                         fprintf(stderr, "%s: %s for '%s' failed: %s\n",
6399                                 progname, argv[0], argv[optind - 1],
6400                                 strerror(-rc2));
6401                         if (!rc)
6402                                 rc = rc2;
6403                 }
6404         } while (++pathstart < pathend);
6405
6406         return rc;
6407 }
6408
6409 static int lfs_tgts(int argc, char **argv)
6410 {
6411         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
6412         struct find_param param;
6413         int index = 0, rc = 0;
6414
6415         if (argc > 2)
6416                 return CMD_HELP;
6417
6418         if (argc == 2 && !realpath(argv[1], path)) {
6419                 rc = -errno;
6420                 fprintf(stderr, "error: invalid path '%s': %s\n",
6421                         argv[1], strerror(-rc));
6422                 return rc;
6423         }
6424
6425         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
6426                 /* Check if we have a mount point */
6427                 if (mntdir[0] == '\0')
6428                         continue;
6429
6430                 memset(&param, 0, sizeof(param));
6431                 if (!strcmp(argv[0], "mdts"))
6432                         param.fp_get_lmv = 1;
6433
6434                 rc = llapi_ostlist(mntdir, &param);
6435                 if (rc) {
6436                         fprintf(stderr, "error: %s: failed on %s\n",
6437                                 argv[0], mntdir);
6438                 }
6439                 if (path[0] != '\0')
6440                         break;
6441                 memset(mntdir, 0, PATH_MAX);
6442         }
6443
6444         return rc;
6445 }
6446
6447 static int lfs_getstripe(int argc, char **argv)
6448 {
6449         struct find_param param = { 0 };
6450
6451         param.fp_max_depth = 1;
6452         return lfs_getstripe_internal(argc, argv, &param);
6453 }
6454
6455 /* functions */
6456 static int lfs_getdirstripe(int argc, char **argv)
6457 {
6458         struct find_param param = { 0 };
6459         struct option long_opts[] = {
6460         { .val = 'c',   .name = "mdt-count",     .has_arg = no_argument },
6461         { .val = 'D',   .name = "default",       .has_arg = no_argument },
6462         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6463         { .val = 'H',   .name = "mdt-hash",      .has_arg = no_argument },
6464         { .val = LFS_HEX_IDX_OPT,
6465                         .name = "hex-idx",       .has_arg = no_argument },
6466         { .val = 'i',   .name = "mdt-index",     .has_arg = no_argument },
6467         { .val = 'm',   .name = "mdt-index",     .has_arg = no_argument },
6468         { .val = 'O',   .name = "obd",           .has_arg = required_argument },
6469         { .val = 'r',   .name = "recursive",     .has_arg = no_argument },
6470         { .val = 'T',   .name = "mdt-count",     .has_arg = no_argument },
6471         { .val = 'v',   .name = "verbose",       .has_arg = no_argument },
6472         { .val = 'X',   .name = "max-inherit",   .has_arg = no_argument },
6473         { .val = LFS_INHERIT_RR_OPT,
6474                         .name = "max-inherit-rr", .has_arg = no_argument },
6475         { .val = 'y',   .name = "yaml",          .has_arg = no_argument },
6476         { .name = NULL } };
6477         int c, rc = 0;
6478
6479         param.fp_get_lmv = 1;
6480
6481         while ((c = getopt_long(argc, argv,
6482                                 "cDhHimO:rtTvXy", long_opts, NULL)) != -1) {
6483                 switch (c) {
6484                 case 'c':
6485                 case 'T':
6486                         param.fp_verbose |= VERBOSE_COUNT;
6487                         break;
6488                 case 'D':
6489                         param.fp_get_default_lmv = 1;
6490                         break;
6491 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6492                 case 't':
6493                         fprintf(stderr,
6494                                 "warning: '-t' deprecated, use '--mdt-hash' or '-H' instead\n");
6495                         fallthrough;
6496 #endif
6497                 case 'H':
6498                         param.fp_verbose |= VERBOSE_HASH_TYPE;
6499                         break;
6500                 case LFS_HEX_IDX_OPT:
6501                         param.fp_hex_idx = 1;
6502                         break;
6503                 case 'i':
6504                         fallthrough;
6505                 case 'm':
6506                         param.fp_verbose |= VERBOSE_STRIPE_OFFSET;
6507                         break;
6508                 case 'O':
6509                         if (param.fp_obd_uuid) {
6510                                 fprintf(stderr,
6511                                         "%s: only one obduuid allowed",
6512                                         progname);
6513                                 return CMD_HELP;
6514                         }
6515                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
6516                         break;
6517                 case 'r':
6518                         param.fp_recursive = 1;
6519                         break;
6520                 case 'v':
6521                         param.fp_verbose |= VERBOSE_DEFAULT;
6522                         param.fp_verbose |= VERBOSE_DETAIL;
6523                         break;
6524                 case 'X':
6525                         param.fp_verbose |= VERBOSE_INHERIT;
6526                         break;
6527                 case LFS_INHERIT_RR_OPT:
6528                         param.fp_verbose |= VERBOSE_INHERIT_RR;
6529                         break;
6530                 case 'y':
6531                         param.fp_yaml = 1;
6532                         break;
6533                 default:
6534                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6535                                 progname, argv[optind - 1]);
6536                         fallthrough;
6537                 case 'h':
6538                         return CMD_HELP;
6539                 }
6540         }
6541
6542         if (optind >= argc)
6543                 return CMD_HELP;
6544
6545         if (param.fp_recursive)
6546                 param.fp_max_depth = -1;
6547
6548         if (!param.fp_verbose)
6549                 param.fp_verbose = VERBOSE_DEFAULT;
6550
6551         do {
6552                 int rc2;
6553
6554                 rc2 = llapi_getstripe(argv[optind], &param);
6555                 if (rc2) {
6556                         fprintf(stderr, "%s: %s for '%s' failed: %s\n",
6557                                 progname, argv[0], argv[optind],
6558                                 strerror(-rc2));
6559                         if (!rc)
6560                                 rc = rc2;
6561                 }
6562         } while (++optind < argc);
6563
6564         return rc;
6565 }
6566
6567 enum mntdf_flags {
6568         MNTDF_INODES    = 0x0001,
6569         MNTDF_COOKED    = 0x0002,
6570         MNTDF_LAZY      = 0x0004,
6571         MNTDF_VERBOSE   = 0x0008,
6572         MNTDF_SHOW      = 0x0010,
6573         MNTDF_DECIMAL   = 0x0020,
6574 };
6575
6576 #define COOK(value, base)                                       \
6577 ({                                                              \
6578         int radix = 0;                                          \
6579         while (value > base) {                                  \
6580                 value /= base;                                  \
6581                 radix++;                                        \
6582         }                                                       \
6583         radix;                                                  \
6584 })
6585 #define UUF     "%-20s"
6586 #define CSF     "%11s"
6587 #define CDF     "%11llu"
6588 #define HDF     "%8.1f%c"
6589 #define RSF     "%4s"
6590 #define RDF     "%3d%%"
6591
6592 static inline int obd_statfs_ratio(const struct obd_statfs *st, bool inodes)
6593 {
6594         double avail, used, ratio = 0;
6595
6596         if (inodes) {
6597                 avail = st->os_ffree;
6598                 used = st->os_files - st->os_ffree;
6599         } else {
6600                 avail = st->os_bavail;
6601                 used = st->os_blocks - st->os_bfree;
6602         }
6603         if (avail + used > 0)
6604                 ratio = used / (used + avail) * 100;
6605
6606         /* Round up to match df(1) usage percentage */
6607         return (ratio - (int)ratio) > 0 ? (int)(ratio + 1) : (int)ratio;
6608 }
6609
6610 /*
6611  * This is to identify various problem states for "lfs df" if .osn_err = true,
6612  * so only show flags reflecting those states by default. Informational states
6613  * are only shown with "-v" and use lower-case names to distinguish them.
6614  * UNUSED[12] were for "EROFS = 30" until 1.6 but are now available for use.
6615  */
6616 static struct obd_statfs_state_names {
6617         enum obd_statfs_state   osn_state;
6618         const char              osn_name;
6619         bool                    osn_err;
6620 } oss_names[] = {
6621         { .osn_state = OS_STATFS_DEGRADED,   .osn_name = 'D', .osn_err = true },
6622         { .osn_state = OS_STATFS_READONLY,   .osn_name = 'R', .osn_err = true },
6623         { .osn_state = OS_STATFS_NOPRECREATE,.osn_name = 'N', .osn_err = true },
6624         { .osn_state = OS_STATFS_UNUSED1,    .osn_name = '?', .osn_err = true },
6625         { .osn_state = OS_STATFS_UNUSED2,    .osn_name = '?', .osn_err = true },
6626         { .osn_state = OS_STATFS_ENOSPC,     .osn_name = 'S', .osn_err = true },
6627         { .osn_state = OS_STATFS_ENOINO,     .osn_name = 'I', .osn_err = true },
6628         { .osn_state = OS_STATFS_SUM,        .osn_name = 'a', /* aggregate */ },
6629         { .osn_state = OS_STATFS_NONROT,     .osn_name = 'f', /* flash */     },
6630 };
6631
6632 static int showdf(char *mntdir, struct obd_statfs *stat,
6633                   char *uuid, enum mntdf_flags flags,
6634                   char *type, int index, int rc)
6635 {
6636         long long avail, used, total;
6637         int ratio = 0;
6638         char *suffix = flags & MNTDF_DECIMAL ? "kMGTPEZY" : "KMGTPEZY";
6639         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
6640         char tbuf[3 * sizeof(__u64)];
6641         char ubuf[3 * sizeof(__u64)];
6642         char abuf[3 * sizeof(__u64)];
6643         char rbuf[3 * sizeof(__u64)];
6644
6645         if (!uuid || !stat)
6646                 return -EINVAL;
6647
6648         switch (rc) {
6649         case 0:
6650                 if (flags & MNTDF_INODES) {
6651                         avail = stat->os_ffree;
6652                         used = stat->os_files - stat->os_ffree;
6653                         total = stat->os_files;
6654                 } else {
6655                         int shift = flags & MNTDF_COOKED ? 0 : 10;
6656
6657                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
6658                         used  = ((stat->os_blocks - stat->os_bfree) *
6659                                  stat->os_bsize) >> shift;
6660                         total = (stat->os_blocks * stat->os_bsize) >> shift;
6661                 }
6662
6663                 ratio = obd_statfs_ratio(stat, flags & MNTDF_INODES);
6664
6665                 if (flags & MNTDF_COOKED) {
6666                         int base = flags & MNTDF_DECIMAL ? 1000 : 1024;
6667                         double cook_val;
6668                         int i;
6669
6670                         cook_val = (double)total;
6671                         i = COOK(cook_val, base);
6672                         if (i > 0)
6673                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
6674                                          suffix[i - 1]);
6675                         else
6676                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
6677
6678                         cook_val = (double)used;
6679                         i = COOK(cook_val, base);
6680                         if (i > 0)
6681                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
6682                                          suffix[i - 1]);
6683                         else
6684                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
6685
6686                         cook_val = (double)avail;
6687                         i = COOK(cook_val, base);
6688                         if (i > 0)
6689                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
6690                                          suffix[i - 1]);
6691                         else
6692                                 snprintf(abuf, sizeof(abuf), CDF, avail);
6693                 } else {
6694                         snprintf(tbuf, sizeof(tbuf), CDF, total);
6695                         snprintf(ubuf, sizeof(tbuf), CDF, used);
6696                         snprintf(abuf, sizeof(tbuf), CDF, avail);
6697                 }
6698
6699                 sprintf(rbuf, RDF, ratio);
6700                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
6701                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
6702                 if (type)
6703                         printf("[%s:%d]", type, index);
6704
6705                 if (stat->os_state) {
6706                         uint32_t i;
6707
6708                         printf(" ");
6709                         for (i = 0; i < ARRAY_SIZE(oss_names); i++) {
6710                                 if (oss_names[i].osn_state & stat->os_state &&
6711                                     (oss_names[i].osn_err ||
6712                                      flags & MNTDF_VERBOSE))
6713                                         printf("%c", oss_names[i].osn_name);
6714                         }
6715                 }
6716
6717                 printf("\n");
6718                 break;
6719         case -ENODATA:
6720                 printf(UUF": inactive device\n", uuid);
6721                 break;
6722         default:
6723                 printf(UUF": %s\n", uuid, strerror(-rc));
6724                 break;
6725         }
6726
6727         return 0;
6728 }
6729
6730 struct ll_stat_type {
6731         int   st_op;
6732         char *st_name;
6733 };
6734
6735 #define LL_STATFS_MAX   LOV_MAX_STRIPE_COUNT
6736
6737 struct ll_statfs_data {
6738         int                     sd_index;
6739         struct obd_statfs       sd_st;
6740 };
6741
6742 struct ll_statfs_buf {
6743         int                     sb_count;
6744         struct ll_statfs_data   sb_buf[LL_STATFS_MAX];
6745 };
6746
6747 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags,
6748                  int ops, struct ll_statfs_buf *lsb)
6749 {
6750         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
6751         struct obd_uuid uuid_buf;
6752         char *poolname = NULL;
6753         struct ll_stat_type types[] = {
6754                 { .st_op = LL_STATFS_LMV,       .st_name = "MDT" },
6755                 { .st_op = LL_STATFS_LOV,       .st_name = "OST" },
6756                 { .st_name = NULL } };
6757         struct ll_stat_type *tp;
6758         __u64 ost_files = 0;
6759         __u64 ost_ffree = 0;
6760         __u32 index;
6761         __u32 type;
6762         int fd;
6763         int rc = 0;
6764         int rc2;
6765
6766         if (pool) {
6767                 poolname = strchr(pool, '.');
6768                 if (poolname) {
6769                         if (strncmp(fsname, pool, strlen(fsname))) {
6770                                 fprintf(stderr, "filesystem name incorrect\n");
6771                                 return -ENODEV;
6772                         }
6773                         poolname++;
6774                 } else
6775                         poolname = pool;
6776         }
6777
6778         fd = open(mntdir, O_RDONLY);
6779         if (fd < 0) {
6780                 rc = -errno;
6781                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
6782                         strerror(errno));
6783                 return rc;
6784         }
6785
6786         if (flags & MNTDF_SHOW) {
6787                 if (flags & MNTDF_INODES)
6788                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
6789                                "UUID", "Inodes", "IUsed", "IFree",
6790                                "IUse%", "Mounted on");
6791                 else
6792                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
6793                                "UUID",
6794                                flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
6795                                "Used", "Available", "Use%", "Mounted on");
6796         }
6797
6798         for (tp = types; tp->st_name != NULL; tp++) {
6799                 bool have_ost = false;
6800
6801                 if (!(tp->st_op & ops))
6802                         continue;
6803
6804                 for (index = 0; index < LOV_ALL_STRIPES &&
6805                      (!lsb || lsb->sb_count < LL_STATFS_MAX); index++) {
6806                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
6807                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
6808                         type = flags & MNTDF_LAZY ?
6809                                 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
6810                         rc2 = llapi_obd_fstatfs(fd, type, index,
6811                                                 &stat_buf, &uuid_buf);
6812                         if (rc2 == -ENODEV)
6813                                 break;
6814                         if (rc2 == -EAGAIN)
6815                                 continue;
6816                         if (rc2 == -ENODATA) { /* Inactive device, OK. */
6817                                 if (!(flags & MNTDF_VERBOSE))
6818                                         continue;
6819                         } else if (rc2 < 0 && rc == 0) {
6820                                 rc = rc2;
6821                         }
6822
6823                         /*
6824                          * If we have OSTs then don't report MDT block counts.
6825                          * For MDT-only filesystems the expectation is that all
6826                          * layouts have a DoM component.  For filesystems with
6827                          * OSTs, files are not necessarily going to store data
6828                          * on MDTs, and MDT space is limited to a fraction of
6829                          * OST space, so don't include it in the summary.
6830                          */
6831                         if (tp->st_op == LL_STATFS_LOV && !have_ost) {
6832                                 have_ost = true;
6833                                 sum.os_blocks = 0;
6834                                 sum.os_bfree = 0;
6835                                 sum.os_bavail = 0;
6836                         }
6837
6838                         if (poolname && tp->st_op == LL_STATFS_LOV &&
6839                             llapi_search_ost(fsname, poolname,
6840                                              obd_uuid2str(&uuid_buf)) != 1)
6841                                 continue;
6842
6843                         /*
6844                          * the llapi_obd_fstatfs() call may have returned with
6845                          * an error, but if it filled in uuid_buf we will at
6846                          * lease use that to print out a message for that OBD.
6847                          * If we didn't get anything in the uuid_buf, then fill
6848                          * it in so that we can print an error message.
6849                          */
6850                         if (uuid_buf.uuid[0] == '\0')
6851                                 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
6852                                          "%s%04x", tp->st_name, index);
6853                         if (!rc && lsb) {
6854                                 lsb->sb_buf[lsb->sb_count].sd_index = index;
6855                                 lsb->sb_buf[lsb->sb_count].sd_st = stat_buf;
6856                                 lsb->sb_count++;
6857                         }
6858                         if (flags & MNTDF_SHOW)
6859                                 showdf(mntdir, &stat_buf,
6860                                        obd_uuid2str(&uuid_buf), flags,
6861                                        tp->st_name, index, rc2);
6862
6863                         if (rc2)
6864                                 continue;
6865
6866                         if (tp->st_op == LL_STATFS_LMV) {
6867                                 sum.os_ffree += stat_buf.os_ffree;
6868                                 sum.os_files += stat_buf.os_files;
6869                         } else /* if (tp->st_op == LL_STATFS_LOV) */ {
6870                                 ost_files += stat_buf.os_files;
6871                                 ost_ffree += stat_buf.os_ffree;
6872                         }
6873                         sum.os_blocks += stat_buf.os_blocks *
6874                                          stat_buf.os_bsize;
6875                         sum.os_bfree  += stat_buf.os_bfree *
6876                                          stat_buf.os_bsize;
6877                         sum.os_bavail += stat_buf.os_bavail *
6878                                          stat_buf.os_bsize;
6879                 }
6880         }
6881
6882         close(fd);
6883
6884         /*
6885          * If we have _some_ OSTs, but don't have as many free objects on the
6886          * OST as inodes on the MDTs, reduce the reported number of inodes
6887          * to compensate, so that the "inodes in use" number is correct.
6888          * This should be kept in sync with ll_statfs_internal().
6889          */
6890         if (ost_files && ost_ffree < sum.os_ffree) {
6891                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
6892                 sum.os_ffree = ost_ffree;
6893         }
6894         if (flags & MNTDF_SHOW) {
6895                 printf("\n");
6896                 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
6897                 printf("\n");
6898         }
6899
6900         return rc;
6901 }
6902
6903 enum {
6904         LAYOUT_INHERIT_UNSET    = -2,
6905 };
6906
6907 /* functions */
6908 static int lfs_setdirstripe(int argc, char **argv)
6909 {
6910         char *dname;
6911         struct lfs_setstripe_args lsa = { 0 };
6912         struct llapi_stripe_param *param = NULL;
6913         __u32 mdts[LMV_MAX_STRIPE_COUNT] = { 0 };
6914         char *end;
6915         int c;
6916         char *mode_opt = NULL;
6917         bool default_stripe = false;
6918         bool delete = false;
6919         bool foreign_mode = false;
6920         bool mdt_count_set = false;
6921         mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
6922         mode_t previous_mode = 0;
6923         char *xattr = NULL;
6924         __u32 type = LU_FOREIGN_TYPE_SYMLINK, flags = 0;
6925         int max_inherit = LAYOUT_INHERIT_UNSET;
6926         int max_inherit_rr = LAYOUT_INHERIT_UNSET;
6927         struct option long_opts[] = {
6928         { .val = 'c',   .name = "count",        .has_arg = required_argument },
6929         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
6930         { .val = 'd',   .name = "delete",       .has_arg = no_argument },
6931         { .val = 'D',   .name = "default",      .has_arg = no_argument },
6932         { .val = 'D',   .name = "default_stripe", .has_arg = no_argument },
6933         { .val = LFS_LAYOUT_FLAGS_OPT,
6934                         .name = "flags",        .has_arg = required_argument },
6935         { .val = LFS_LAYOUT_FOREIGN_OPT,
6936                         .name = "foreign",      .has_arg = optional_argument},
6937         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6938         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
6939 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 17, 53, 0)
6940         { .val = 'i',   .name = "mdt-index",    .has_arg = required_argument },
6941         { .val = 'i',   .name = "mdt",          .has_arg = required_argument },
6942 #else
6943 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
6944         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
6945         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
6946 #endif
6947 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6948         { .val = 'i',   .name = "index",        .has_arg = required_argument },
6949 #endif
6950         { .val = 'o',   .name = "mode",         .has_arg = required_argument },
6951 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6952         { .val = 't',   .name = "hash-type",    .has_arg = required_argument },
6953 #endif
6954         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
6955         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
6956         { .val = 'X',   .name = "max-inherit",  .has_arg = required_argument },
6957         { .val = LFS_INHERIT_RR_OPT,
6958                         .name = "max-inherit-rr", .has_arg = required_argument},
6959 /* setstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
6960 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }, */
6961         { .name = NULL } };
6962         int result = 0;
6963
6964         setstripe_args_init(&lsa);
6965
6966         while ((c = getopt_long(argc, argv, "c:dDi:hH:m:o:t:T:x:X:",
6967                                 long_opts, NULL)) >= 0) {
6968                 switch (c) {
6969                 case 0:
6970                         /* Long options. */
6971                         break;
6972                 case 'c':
6973                 case 'T':
6974                         errno = 0;
6975                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
6976                         if (errno != 0 || *end != '\0' ||
6977                             lsa.lsa_stripe_count < -1 ||
6978                             lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
6979                                 fprintf(stderr,
6980                                         "%s: invalid stripe count '%s'\n",
6981                                         progname, optarg);
6982                                 return CMD_HELP;
6983                         }
6984                         mdt_count_set = true;
6985                         break;
6986                 case 'd':
6987                         delete = true;
6988                         default_stripe = true;
6989                         break;
6990                 case 'D':
6991                         default_stripe = true;
6992                         break;
6993                 case LFS_LAYOUT_FOREIGN_OPT:
6994                         if (optarg) {
6995                                 /* check pure numeric */
6996                                 type = strtoul(optarg, &end, 0);
6997                                 if (*end) {
6998                                         /* check name */
6999                                         type = check_foreign_type_name(optarg);
7000                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
7001                                                 fprintf(stderr,
7002                                                         "%s %s: unknown foreign type '%s'\n",
7003                                                         progname, argv[0],
7004                                                         optarg);
7005                                                 return CMD_HELP;
7006                                         }
7007                                 } else if (type >= UINT32_MAX) {
7008                                         fprintf(stderr,
7009                                                 "%s %s: invalid foreign type '%s'\n",
7010                                                 progname, argv[0], optarg);
7011                                         return CMD_HELP;
7012                                 }
7013                         }
7014                         foreign_mode = true;
7015                         break;
7016                 case LFS_LAYOUT_FLAGS_OPT:
7017                         errno = 0;
7018                         flags = strtoul(optarg, &end, 16);
7019                         if (errno != 0 || *end != '\0' ||
7020                             flags >= UINT32_MAX) {
7021                                 fprintf(stderr,
7022                                         "%s %s: invalid hex flags '%s'\n",
7023                                         progname, argv[0], optarg);
7024                                 return CMD_HELP;
7025                         }
7026                         if (!foreign_mode) {
7027                                 fprintf(stderr,
7028                                         "%s %s: hex flags must be specified with --foreign option\n",
7029                                         progname, argv[0]);
7030                                 return CMD_HELP;
7031                         }
7032                         break;
7033 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7034                 case 't':
7035                         fprintf(stderr,
7036                                 "warning: '--hash-type' and '-t' deprecated, use '--mdt-hash' or '-H' instead\n");
7037                         fallthrough;
7038 #endif
7039                 case 'H':
7040                         lsa.lsa_pattern = check_hashtype(optarg);
7041                         if (lsa.lsa_pattern == 0) {
7042                                 fprintf(stderr,
7043                                         "%s %s: bad directory hash type '%s'\n",
7044                                         progname, argv[0], optarg);
7045                                 return CMD_HELP;
7046                         }
7047                         break;
7048                 case 'i':
7049 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 17, 53, 0)
7050                 case 'm':
7051 #endif
7052 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7053                         if (strcmp(argv[optind - 1], "--index") == 0)
7054                                 fprintf(stderr,
7055                                         "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
7056                                         progname, argv[0]);
7057 #endif
7058                         lsa.lsa_nr_tgts = parse_targets(mdts,
7059                                                 sizeof(mdts) / sizeof(__u32),
7060                                                 lsa.lsa_nr_tgts, optarg, NULL);
7061                         if (lsa.lsa_nr_tgts < 0) {
7062                                 fprintf(stderr,
7063                                         "%s %s: invalid MDT target(s) '%s'\n",
7064                                         progname, argv[0], optarg);
7065                                 return CMD_HELP;
7066                         }
7067
7068                         lsa.lsa_tgts = mdts;
7069                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
7070                                 lsa.lsa_stripe_off = mdts[0];
7071                         break;
7072                 case 'o':
7073                         mode_opt = optarg;
7074                         break;
7075                 case 'x':
7076                         xattr = optarg;
7077                         break;
7078                 case 'X':
7079                         errno = 0;
7080                         max_inherit = strtol(optarg, &end, 10);
7081                         if (errno != 0 || *end != '\0' || max_inherit < -2) {
7082                                 fprintf(stderr,
7083                                         "%s %s: invalid max-inherit '%s'\n",
7084                                         progname, argv[0], optarg);
7085                                 return CMD_HELP;
7086                         }
7087                         if (max_inherit == 0) {
7088                                 max_inherit = LMV_INHERIT_NONE;
7089                         } else if (max_inherit == -1) {
7090                                 max_inherit = LMV_INHERIT_UNLIMITED;
7091                         } else if (max_inherit > LMV_INHERIT_MAX) {
7092                                 fprintf(stderr,
7093                                         "%s %s: max-inherit %d exceeds maximum %u\n",
7094                                         progname, argv[0], max_inherit,
7095                                         LMV_INHERIT_MAX);
7096                                 return CMD_HELP;
7097                         }
7098                         break;
7099                 case LFS_INHERIT_RR_OPT:
7100                         if (!default_stripe) {
7101                                 fprintf(stderr,
7102                                         "%s %s: '--max-inherit-rr' must be specified with '-D'\n",
7103                                         progname, argv[0]);
7104                                 return CMD_HELP;
7105                         }
7106                         errno = 0;
7107                         max_inherit_rr = strtol(optarg, &end, 10);
7108                         if (errno != 0 || *end != '\0' || max_inherit_rr < -2) {
7109                                 fprintf(stderr,
7110                                         "%s %s: invalid max-inherit-rr '%s'\n",
7111                                         progname, argv[0], optarg);
7112                                 return CMD_HELP;
7113                         }
7114                         if (max_inherit_rr == 0) {
7115                                 max_inherit_rr = LMV_INHERIT_RR_NONE;
7116                         } else if (max_inherit_rr == -1) {
7117                                 max_inherit_rr = LMV_INHERIT_RR_UNLIMITED;
7118                         } else if (max_inherit_rr > LMV_INHERIT_RR_MAX) {
7119                                 fprintf(stderr,
7120                                         "%s %s: max-inherit-rr %d exceeds maximum %u\n",
7121                                         progname, argv[0], max_inherit_rr,
7122                                         LMV_INHERIT_RR_MAX);
7123                                 return CMD_HELP;
7124                         }
7125                         break;
7126                 default:
7127                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7128                                 progname, argv[optind - 1]);
7129                         fallthrough;
7130                 case 'h':
7131                         return CMD_HELP;
7132                 }
7133         }
7134
7135         if (optind == argc) {
7136                 fprintf(stderr, "%s %s: DIR must be specified\n",
7137                         progname, argv[0]);
7138                 return CMD_HELP;
7139         }
7140
7141         if (xattr && !foreign_mode) {
7142                 /*
7143                  * only print a warning as this is armless and will be
7144                  * ignored
7145                  */
7146                 fprintf(stderr,
7147                         "%s %s: xattr has been specified for non-foreign layout\n",
7148                         progname, argv[0]);
7149         } else if (foreign_mode && !xattr) {
7150                 fprintf(stderr,
7151                         "%s %s: xattr must be provided in foreign mode\n",
7152                         progname, argv[0]);
7153                 return CMD_HELP;
7154         }
7155
7156         if (foreign_mode && (delete || default_stripe || lsa.lsa_nr_tgts ||
7157             lsa.lsa_tgts || setstripe_args_specified(&lsa))) {
7158                 fprintf(stderr,
7159                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
7160                         progname, argv[0]);
7161                 return CMD_HELP;
7162         }
7163
7164         if (!delete && lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT &&
7165             lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT && !foreign_mode) {
7166                 /* if no parameters set, create directory on least-used MDTs */
7167                 lsa.lsa_stripe_off = LMV_OFFSET_DEFAULT;
7168                 lsa.lsa_stripe_count = 1;
7169         }
7170
7171         if (delete &&
7172             (lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
7173              lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)) {
7174                 fprintf(stderr,
7175                         "%s %s: cannot specify -d with -c or -i options\n",
7176                         progname, argv[0]);
7177                 return CMD_HELP;
7178         }
7179
7180         if (mode_opt) {
7181                 mode = strtoul(mode_opt, &end, 8);
7182                 if (*end != '\0') {
7183                         fprintf(stderr,
7184                                 "%s %s: bad MODE '%s'\n",
7185                                 progname, argv[0], mode_opt);
7186                         return CMD_HELP;
7187                 }
7188                 previous_mode = umask(0);
7189         }
7190
7191         /* check max-inherit and warn user in some cases */
7192         if (default_stripe &&
7193             (lsa.lsa_stripe_count < 0 || lsa.lsa_stripe_count > 1)) {
7194                 if (max_inherit == LMV_INHERIT_UNLIMITED)
7195                         fprintf(stderr,
7196                         "%s %s: unrecommended max-inherit=-1 when default stripe-count=%lld\n",
7197                         progname, argv[0], lsa.lsa_stripe_count);
7198                 else if (max_inherit > LMV_INHERIT_DEFAULT_STRIPED + 2 &&
7199                          max_inherit != LMV_INHERIT_NONE)
7200                         fprintf(stderr,
7201                                 "%s %s: unrecommended max-inherit=%d when default stripe-count=%lld\n",
7202                                 progname, argv[0], max_inherit,
7203                                 lsa.lsa_stripe_count);
7204         }
7205
7206         if (default_stripe && lsa.lsa_nr_tgts > 1 && !mdt_count_set) {
7207                 fprintf(stderr,
7208                         "%s %s: trying to create unrecommended default striped directory layout,\n"
7209                         "       '-D -i x,y,z' will stripe every new directory across all MDTs,\n"
7210                         "       add -c with the number of MDTs to do this anyway\n",
7211                         progname, argv[0]);
7212                 return CMD_HELP;
7213         }
7214
7215         if (max_inherit_rr != LAYOUT_INHERIT_UNSET &&
7216             lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT &&
7217             lsa.lsa_stripe_off != LMV_OFFSET_DEFAULT) {
7218                 fprintf(stderr,
7219                         "%s %s: max-inherit-rr needs mdt-index=-1, not %lld\n",
7220                         progname, argv[0], lsa.lsa_stripe_off);
7221                 return CMD_HELP;
7222         }
7223
7224         /* foreign LMV/dir case */
7225         if (foreign_mode) {
7226                 if (argc > optind + 1) {
7227                         fprintf(stderr,
7228                                 "%s %s: cannot specify multiple foreign dirs\n",
7229                                 progname, argv[0]);
7230                         return CMD_HELP;
7231                 }
7232
7233                 dname = argv[optind];
7234                 result = llapi_dir_create_foreign(dname, mode, type, flags,
7235                                                   xattr);
7236                 if (result != 0)
7237                         fprintf(stderr,
7238                                 "%s mkdir: can't create foreign dir '%s': %s\n",
7239                                 progname, dname, strerror(-result));
7240                 return result;
7241         }
7242
7243         /*
7244          * initialize stripe parameters, in case param is converted to specific,
7245          * i.e, 'lfs mkdir -i -1 -c N', always allocate space for lsp_tgts.
7246          */
7247         param = calloc(1, offsetof(typeof(*param),
7248                        lsp_tgts[lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ?
7249                                 lsa.lsa_stripe_count : lsa.lsa_nr_tgts]));
7250         if (!param) {
7251                 fprintf(stderr,
7252                         "%s %s: cannot allocate memory for parameters: %s\n",
7253                         progname, argv[0], strerror(ENOMEM));
7254                 return CMD_HELP;
7255         }
7256
7257         /* if "lfs setdirstripe -D -i -1" is used, assume 1-stripe directory */
7258         if (default_stripe && lsa.lsa_stripe_off == LMV_OFFSET_DEFAULT &&
7259             (lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT ||
7260              lsa.lsa_stripe_count == 0))
7261                 lsa.lsa_stripe_count = 1;
7262         if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
7263                 param->lsp_stripe_count = lsa.lsa_stripe_count;
7264         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
7265                 param->lsp_stripe_offset = LMV_OFFSET_DEFAULT;
7266         else
7267                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
7268         if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
7269                 param->lsp_stripe_pattern = lsa.lsa_pattern;
7270         else
7271                 param->lsp_stripe_pattern = LMV_HASH_TYPE_UNKNOWN;
7272         param->lsp_pool = lsa.lsa_pool_name;
7273         param->lsp_is_specific = false;
7274
7275         if (max_inherit == LAYOUT_INHERIT_UNSET) {
7276                 if (lsa.lsa_stripe_count == 0 || lsa.lsa_stripe_count == 1 ||
7277                     lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT)
7278                         max_inherit = LMV_INHERIT_DEFAULT_PLAIN;
7279                 else
7280                         max_inherit = LMV_INHERIT_DEFAULT_STRIPED;
7281         }
7282         param->lsp_max_inherit = max_inherit;
7283         if (default_stripe) {
7284
7285                 if (max_inherit_rr == LAYOUT_INHERIT_UNSET)
7286                         max_inherit_rr = LMV_INHERIT_RR_DEFAULT;
7287                 param->lsp_max_inherit_rr = max_inherit_rr;
7288         }
7289         if (strcmp(argv[0], "mkdir") == 0)
7290                 param->lsp_is_create = true;
7291         if (lsa.lsa_nr_tgts > 1) {
7292                 if (lsa.lsa_stripe_count > 0 &&
7293                     lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
7294                     lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
7295                         fprintf(stderr,
7296                                 "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
7297                                 argv[0], lsa.lsa_stripe_count,
7298                                 lsa.lsa_nr_tgts);
7299                         free(param);
7300                         return CMD_HELP;
7301                 }
7302
7303                 param->lsp_is_specific = true;
7304                 param->lsp_stripe_count = lsa.lsa_nr_tgts;
7305                 memcpy(param->lsp_tgts, mdts, sizeof(*mdts) * lsa.lsa_nr_tgts);
7306         }
7307
7308         dname = argv[optind];
7309         do {
7310                 if (default_stripe) {
7311                         result = llapi_dir_set_default_lmv(dname, param);
7312                         if (result)
7313                                 fprintf(stderr,
7314                                         "%s setdirstripe: cannot set default stripe on dir '%s': %s\n",
7315                                         progname, dname, strerror(-result));
7316                         continue;
7317                 }
7318
7319                 result = llapi_dir_create(dname, mode, param);
7320                 if (result)
7321                         fprintf(stderr,
7322                                 "%s setdirstripe: cannot create dir '%s': %s\n",
7323                                 progname, dname, strerror(-result));
7324         } while (!result && (dname = argv[++optind]));
7325
7326         if (mode_opt)
7327                 umask(previous_mode);
7328
7329         free(param);
7330         return result;
7331 }
7332
7333 static int lfs_rmentry(int argc, char **argv)
7334 {
7335         char *dname;
7336         int index;
7337         int result = 0;
7338
7339         if (argc <= 1) {
7340                 fprintf(stderr, "error: %s: missing dirname\n",
7341                         argv[0]);
7342                 return CMD_HELP;
7343         }
7344
7345         index = 1;
7346         dname = argv[index];
7347         while (dname) {
7348                 int rc2;
7349
7350                 rc2 = llapi_direntry_remove(dname);
7351                 if (rc2) {
7352                         fprintf(stderr,
7353                                 "%s %s: remove dir entry '%s' failed: %s\n",
7354                                 progname, argv[0], dname, strerror(-rc2));
7355                         if (!result)
7356                                 result = rc2;
7357                 }
7358                 dname = argv[++index];
7359         }
7360         return result;
7361 }
7362
7363 static int lfs_unlink_foreign(int argc, char **argv)
7364 {
7365         char *name;
7366         int   index;
7367         int   result = 0;
7368
7369         if (argc <= 1) {
7370                 fprintf(stderr, "error: %s: missing pathname\n",
7371                         argv[0]);
7372                 return CMD_HELP;
7373         }
7374
7375         index = 1;
7376         name = argv[index];
7377         while (name != NULL) {
7378                 result = llapi_unlink_foreign(name);
7379                 if (result) {
7380                         fprintf(stderr,
7381                                 "error: %s: unlink foreign entry '%s' failed\n",
7382                                 argv[0], name);
7383                         break;
7384                 }
7385                 name = argv[++index];
7386         }
7387         return result;
7388 }
7389
7390 static int lfs_mv(int argc, char **argv)
7391 {
7392         struct lmv_user_md lmu = { LMV_USER_MAGIC };
7393         struct find_param param = {
7394                 .fp_max_depth = -1,
7395                 .fp_mdt_index = -1,
7396         };
7397         char *end;
7398         int c;
7399         int rc = 0;
7400         struct option long_opts[] = {
7401         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
7402         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
7403         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7404         { .name = NULL } };
7405
7406         while ((c = getopt_long(argc, argv, "m:M:v", long_opts, NULL)) != -1) {
7407                 switch (c) {
7408 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7409                 case 'M':
7410                         fprintf(stderr,
7411                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
7412 #endif
7413                 case 'm':
7414                         errno = 0;
7415                         lmu.lum_stripe_offset = strtoul(optarg, &end, 0);
7416                         if (errno != 0 || *end != '\0' ||
7417                             lmu.lum_stripe_offset >= UINT32_MAX) {
7418                                 fprintf(stderr, "%s mv: bad MDT index '%s'\n",
7419                                         progname, optarg);
7420                                 return CMD_HELP;
7421                         }
7422                         break;
7423                 case 'v':
7424                         param.fp_verbose = VERBOSE_DETAIL;
7425                         break;
7426                 default:
7427                         fprintf(stderr, "%s mv: unrecognized option '%s'\n",
7428                                 progname, argv[optind - 1]);
7429                         return CMD_HELP;
7430                 }
7431         }
7432
7433         if (lmu.lum_stripe_offset == LMV_OFFSET_DEFAULT) {
7434                 fprintf(stderr, "%s mv: MDT index must be specified\n",
7435                         progname);
7436                 return CMD_HELP;
7437         }
7438
7439         if (optind >= argc) {
7440                 fprintf(stderr, "%s mv: DIR must be specified\n", progname);
7441                 return CMD_HELP;
7442         }
7443
7444         lmu.lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
7445
7446         /* initialize migrate mdt parameters */
7447         param.fp_lmv_md = &lmu;
7448         param.fp_migrate = 1;
7449         rc = llapi_migrate_mdt(argv[optind], &param);
7450         if (rc != 0)
7451                 fprintf(stderr, "%s mv: cannot migrate '%s' to MDT%04x: %s\n",
7452                         progname, argv[optind], lmu.lum_stripe_offset,
7453                         strerror(-rc));
7454         return rc;
7455 }
7456
7457 static int lfs_osts(int argc, char **argv)
7458 {
7459         return lfs_tgts(argc, argv);
7460 }
7461
7462 static int lfs_mdts(int argc, char **argv)
7463 {
7464         return lfs_tgts(argc, argv);
7465 }
7466
7467 static int lfs_df(int argc, char **argv)
7468 {
7469         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
7470         enum mntdf_flags flags = MNTDF_SHOW;
7471         int ops = LL_STATFS_LMV | LL_STATFS_LOV;
7472         int c, rc = 0, rc1 = 0, index = 0, arg_idx = 0;
7473         char fsname[PATH_MAX] = "", *pool_name = NULL;
7474         struct option long_opts[] = {
7475         { .val = 'h',   .name = "human-readable", .has_arg = no_argument },
7476         { .val = 'H',   .name = "si",           .has_arg = no_argument },
7477         { .val = 'i',   .name = "inodes",       .has_arg = no_argument },
7478         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
7479         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
7480         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7481         { .name = NULL} };
7482
7483         while ((c = getopt_long(argc, argv, "hHilp:v", long_opts, NULL)) != -1) {
7484                 switch (c) {
7485                 case 'h':
7486                         flags = (flags & ~MNTDF_DECIMAL) | MNTDF_COOKED;
7487                         break;
7488                 case 'H':
7489                         flags |= MNTDF_COOKED | MNTDF_DECIMAL;
7490                         break;
7491                 case 'i':
7492                         flags |= MNTDF_INODES;
7493                         break;
7494                 case 'l':
7495                         flags |= MNTDF_LAZY;
7496                         break;
7497                 case 'p':
7498                         pool_name = optarg;
7499                         break;
7500                 case 'v':
7501                         flags |= MNTDF_VERBOSE;
7502                         break;
7503                 default:
7504                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7505                                 progname, argv[optind - 1]);
7506                         return CMD_HELP;
7507                 }
7508         }
7509
7510         /* Handle case where path is not specified */
7511         if (optind == argc) {
7512                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7513                         /* Check if we have a mount point */
7514                         if (mntdir[0] == '\0')
7515                                 continue;
7516
7517                         rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
7518                         if (rc || path[0] != '\0')
7519                                 break;
7520
7521                         fsname[0] = '\0'; /* avoid matching in next loop */
7522                         mntdir[0] = '\0'; /* avoid matching in next loop */
7523                         path[0] = '\0'; /* clean for next loop */
7524                 }
7525                 return rc;
7526         }
7527
7528         /* Loop through all the remaining arguments. These are Lustre FS
7529          * paths.
7530          */
7531         for (arg_idx = optind; arg_idx <= argc - 1; arg_idx++) {
7532                 bool valid = false;
7533
7534                 fsname[0] = '\0'; /* start clean */
7535                 mntdir[0] = '\0'; /* start clean */
7536                 path[0] = '\0';   /* start clean */
7537
7538                 /* path does not exists at all */
7539                 if (!realpath(argv[arg_idx], path)) {
7540                         rc = -errno;
7541                         fprintf(stderr, "error: invalid path '%s': %s\n",
7542                                 argv[arg_idx], strerror(-rc));
7543                         /* save first seen error */
7544                         if (!rc1)
7545                                 rc1 = rc;
7546
7547                         continue;
7548                 }
7549
7550                 /* path exists but may not be a Lustre filesystem */
7551                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7552                         /* Check if we have a mount point */
7553                         if (mntdir[0] == '\0')
7554                                 continue;
7555
7556                         rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
7557                         if (rc || path[0] != '\0') {
7558                                 valid = true;
7559
7560                                 /* save first seen error */
7561                                 if (!rc1)
7562                                         rc1 = rc;
7563                                 break;
7564                         }
7565                 }
7566
7567                 if (!valid) {
7568                         llapi_printf(LLAPI_MSG_ERROR,
7569                                      "%s:%s Not a Lustre filesystem\n",
7570                                      argv[0], argv[arg_idx]);
7571                         /* save first seen error */
7572                         if (!rc1)
7573                                 rc1 = -EOPNOTSUPP;
7574                 }
7575         }
7576
7577         return rc1;
7578 }
7579
7580 static int print_instance(const char *mntdir, char *buf, size_t buflen,
7581                           bool opt_instance, bool opt_fsname, bool opt_mntdir)
7582 {
7583         int rc = 0;
7584
7585         if (opt_fsname == opt_instance) { /* both true or both false */
7586                 rc = llapi_getname(mntdir, buf, buflen);
7587         } else if (opt_fsname) {
7588                 /*
7589                  * llapi_search_mounts() fills @buf with fsname, but that is not
7590                  * called if explicit paths are specified on the command-line
7591                  */
7592                 if (buf[0] == '\0')
7593                         rc = llapi_get_fsname(mntdir, buf, buflen);
7594         } else /* if (opt_instance) */ {
7595                 rc = llapi_get_instance(mntdir, buf, buflen);
7596         }
7597
7598         if (rc < 0) {
7599                 fprintf(stderr, "cannot get instance for '%s': %s\n",
7600                         mntdir, strerror(-rc));
7601                 return rc;
7602         }
7603
7604         if (opt_mntdir)
7605                 printf("%s %s\n", buf, mntdir);
7606         else
7607                 printf("%s\n", buf);
7608
7609         return 0;
7610 }
7611
7612 static int lfs_getname(int argc, char **argv)
7613 {
7614         struct option long_opts[] = {
7615         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7616         { .val = 'i',   .name = "instance",     .has_arg = no_argument },
7617         { .val = 'n',   .name = "fsname",       .has_arg = no_argument },
7618         { .name = NULL} };
7619         bool opt_instance = false, opt_fsname = false;
7620         char fsname[PATH_MAX] = "";
7621         int rc = 0, rc2, c;
7622
7623         while ((c = getopt_long(argc, argv, "hin", long_opts, NULL)) != -1) {
7624                 switch (c) {
7625                 case 'i':
7626                         opt_instance = true;
7627                         break;
7628                 case 'n':
7629                         opt_fsname = true;
7630                         break;
7631                 default:
7632                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7633                                 progname, argv[optind - 1]);
7634                         fallthrough;
7635                 case 'h':
7636                         return CMD_HELP;
7637                 }
7638         }
7639
7640         if (optind == argc) { /* no paths specified, get all paths. */
7641                 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "";
7642                 int index = 0;
7643
7644                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7645                         rc2 = print_instance(mntdir, fsname, sizeof(fsname),
7646                                              opt_instance, opt_fsname, true);
7647                         if (!rc)
7648                                 rc = rc2;
7649                         path[0] = fsname[0] = mntdir[0] = '\0';
7650                 }
7651         } else { /* paths specified, only attempt to search these. */
7652                 bool opt_mntdir;
7653
7654                 /* if only one path is given, print only requested info */
7655                 opt_mntdir = argc - optind > 1 || (opt_instance == opt_fsname);
7656
7657                 for (; optind < argc; optind++) {
7658                         rc2 = print_instance(argv[optind], fsname,
7659                                              sizeof(fsname), opt_instance,
7660                                              opt_fsname, opt_mntdir);
7661                         if (!rc)
7662                                 rc = rc2;
7663                         fsname[0] = '\0';
7664                 }
7665         }
7666
7667         return rc;
7668 }
7669
7670 static int lfs_check(int argc, char **argv)
7671 {
7672         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
7673         int num_types = 1;
7674         char *obd_types[3];
7675         char obd_type1[4];
7676         char obd_type2[4];
7677         char obd_type3[4];
7678         int rc;
7679
7680         if (argc < 2 || argc > 3) {
7681                 fprintf(stderr, "%s check: server type must be specified\n",
7682                         progname);
7683                 return CMD_HELP;
7684         }
7685
7686         obd_types[0] = obd_type1;
7687         obd_types[1] = obd_type2;
7688         obd_types[2] = obd_type3;
7689
7690         if (strcmp(argv[1], "osts") == 0) {
7691                 strcpy(obd_types[0], "osc");
7692         } else if (strcmp(argv[1], "mdts") == 0 ||
7693                    strcmp(argv[1], "mds") == 0) {
7694                 strcpy(obd_types[0], "mdc");
7695         } else if (strcmp(argv[1], "mgts") == 0) {
7696                 strcpy(obd_types[0], "mgc");
7697         } else if (strcmp(argv[1], "all") == 0 ||
7698                    strcmp(argv[1], "servers") == 0) {
7699                 num_types = 3;
7700                 strcpy(obd_types[0], "osc");
7701                 strcpy(obd_types[1], "mdc");
7702                 strcpy(obd_types[2], "mgc");
7703         } else {
7704                 fprintf(stderr, "%s check: unrecognized option '%s'\n",
7705                         progname, argv[1]);
7706                 return CMD_HELP;
7707         }
7708
7709         if (argc >= 3 && !realpath(argv[2], path)) {
7710                 rc = -errno;
7711                 fprintf(stderr, "error: invalid path '%s': %s\n",
7712                         argv[2], strerror(-rc));
7713                 return rc;
7714         }
7715
7716         rc = llapi_search_mounts(path, 0, mntdir, NULL);
7717         if (rc < 0 || mntdir[0] == '\0') {
7718                 fprintf(stderr,
7719                         "%s %s: cannot find mounted Lustre filesystem: %s\n",
7720                         progname, argv[0],
7721                         (rc < 0) ? strerror(-rc) : strerror(ENODEV));
7722                 return rc;
7723         }
7724
7725         rc = llapi_target_check(num_types, obd_types, path);
7726         if (rc)
7727                 fprintf(stderr, "%s %s: cannot check target '%s': %s\n",
7728                         progname, argv[0], argv[1], strerror(-rc));
7729
7730         return rc;
7731 }
7732
7733 #ifdef HAVE_SYS_QUOTA_H
7734 #define ADD_OVERFLOW(a, b) \
7735                      ((((a) + (b)) < (a)) ? \
7736                       ((a) = ULONG_MAX) : ((a) = (a) + (b)))
7737
7738 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
7739  * returns the value or ULONG_MAX on integer overflow or incorrect format
7740  * Notes:
7741  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
7742  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
7743  *        3. empty integer value is interpreted as 0
7744  */
7745 static unsigned long str2sec(const char *timestr)
7746 {
7747         const char spec[] = "smhdw";
7748         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
7749         unsigned long val = 0;
7750         char *tail;
7751
7752         if (strpbrk(timestr, spec) == NULL) {
7753                 /*
7754                  * no specifiers inside the time string,
7755                  * should treat it as an integer value
7756                  */
7757                 val = strtoul(timestr, &tail, 10);
7758                 return *tail ? ULONG_MAX : val;
7759         }
7760
7761         /* format string is XXwXXdXXhXXmXXs */
7762         while (*timestr) {
7763                 unsigned long v;
7764                 int ind;
7765                 char *ptr;
7766
7767                 v = strtoul(timestr, &tail, 10);
7768                 if (v == ULONG_MAX || *tail == '\0')
7769                         /*
7770                          * value too large (ULONG_MAX or more)
7771                          * or missing specifier
7772                          */
7773                         goto error;
7774
7775                 ptr = strchr(spec, *tail);
7776                 if (!ptr)
7777                         /* unknown specifier */
7778                         goto error;
7779
7780                 ind = ptr - spec;
7781
7782                 /* check if product will overflow the type */
7783                 if (!(v < ULONG_MAX / mult[ind]))
7784                         goto error;
7785
7786                 ADD_OVERFLOW(val, mult[ind] * v);
7787                 if (val == ULONG_MAX)
7788                         goto error;
7789
7790                 timestr = tail + 1;
7791         }
7792
7793         return val;
7794
7795 error:
7796         return ULONG_MAX;
7797 }
7798
7799 #define ARG2ULL(nr, str, def_units)                                     \
7800 do {                                                                    \
7801         unsigned long long limit, units = def_units;                    \
7802         int rc;                                                         \
7803                                                                         \
7804         rc = llapi_parse_size(str, &limit, &units, 1);                  \
7805         if (rc < 0) {                                                   \
7806                 fprintf(stderr, "%s: invalid limit '%s'\n",             \
7807                         progname, str);                                 \
7808                 return CMD_HELP;                                        \
7809         }                                                               \
7810         nr = limit;                                                     \
7811 } while (0)
7812
7813 static inline int has_times_option(int argc, char **argv)
7814 {
7815         int i;
7816
7817         for (i = 1; i < argc; i++)
7818                 if (!strcmp(argv[i], "-t"))
7819                         return 1;
7820
7821         return 0;
7822 }
7823
7824 static inline int lfs_verify_poolarg(char *pool)
7825 {
7826         if (strnlen(optarg, LOV_MAXPOOLNAME + 1) > LOV_MAXPOOLNAME) {
7827                 fprintf(stderr,
7828                         "Pool name '%.*s' is longer than %d\n",
7829                         LOV_MAXPOOLNAME, pool, LOV_MAXPOOLNAME);
7830                 return 1;
7831         }
7832         return 0;
7833 }
7834
7835 /* special grace time, only notify the user when its quota is over soft limit
7836  * but doesn't block new writes until the hard limit is reached.
7837  */
7838 #define NOTIFY_GRACE            "notify"
7839 #define NOTIFY_GRACE_TIME       LQUOTA_GRACE_MASK
7840
7841 #ifndef toqb
7842 static inline __u64 lustre_stoqb(size_t space)
7843 {
7844         return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
7845 }
7846 #else
7847 #define lustre_stoqb   toqb
7848 #endif
7849
7850 int lfs_setquota_times(int argc, char **argv, struct if_quotactl *qctl)
7851 {
7852         int c, rc;
7853         char *mnt, *obd_type = (char *)qctl->obd_type;
7854         struct obd_dqblk *dqb = &qctl->qc_dqblk;
7855         struct obd_dqinfo *dqi = &qctl->qc_dqinfo;
7856         struct option long_opts[] = {
7857         { .val = 'b',   .name = "block-grace",  .has_arg = required_argument },
7858         { .val = 'g',   .name = "group",        .has_arg = no_argument },
7859         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7860         { .val = 'i',   .name = "inode-grace",  .has_arg = required_argument },
7861         { .val = 'p',   .name = "projid",       .has_arg = no_argument },
7862         { .val = 't',   .name = "times",        .has_arg = no_argument },
7863         { .val = 'u',   .name = "user",         .has_arg = no_argument },
7864         { .val = LFS_POOL_OPT,
7865                         .name = "pool",         .has_arg = required_argument },
7866         { .name = NULL } };
7867         int qtype;
7868
7869         qctl->qc_cmd  = LUSTRE_Q_SETINFO;
7870         qctl->qc_type = ALLQUOTA;
7871
7872         while ((c = getopt_long(argc, argv, "b:ghi:ptu",
7873                                 long_opts, NULL)) != -1) {
7874                 switch (c) {
7875                 case 'u':
7876                         qtype = USRQUOTA;
7877                         goto quota_type;
7878                 case 'g':
7879                         qtype = GRPQUOTA;
7880                         goto quota_type;
7881                 case 'p':
7882                         qtype = PRJQUOTA;
7883 quota_type:
7884                         if (qctl->qc_type != ALLQUOTA) {
7885                                 fprintf(stderr,
7886                                         "%s: -u/g/p cannot be used more than once\n",
7887                                         progname);
7888                                 return CMD_HELP;
7889                         }
7890                         qctl->qc_type = qtype;
7891                         break;
7892                 case 'b':
7893                         if (strncmp(optarg, NOTIFY_GRACE,
7894                                     strlen(NOTIFY_GRACE)) == 0) {
7895                                 dqi->dqi_bgrace = NOTIFY_GRACE_TIME;
7896                         } else {
7897                                 dqi->dqi_bgrace = str2sec(optarg);
7898                                 if (dqi->dqi_bgrace >= NOTIFY_GRACE_TIME) {
7899                                         fprintf(stderr,
7900                                                 "%s: bad block-grace: %s\n",
7901                                                 progname, optarg);
7902                                         return CMD_HELP;
7903                                 }
7904                         }
7905                         dqb->dqb_valid |= QIF_BTIME;
7906                         break;
7907                 case 'i':
7908                         if (strncmp(optarg, NOTIFY_GRACE,
7909                                     strlen(NOTIFY_GRACE)) == 0) {
7910                                 dqi->dqi_igrace = NOTIFY_GRACE_TIME;
7911                         } else {
7912                                 dqi->dqi_igrace = str2sec(optarg);
7913                                 if (dqi->dqi_igrace >= NOTIFY_GRACE_TIME) {
7914                                         fprintf(stderr,
7915                                                 "%s: bad inode-grace: %s\n",
7916                                                 progname, optarg);
7917                                         return CMD_HELP;
7918                                 }
7919                         }
7920                         dqb->dqb_valid |= QIF_ITIME;
7921                         break;
7922                 case 't': /* Yes, of course! */
7923                         break;
7924                 case LFS_POOL_OPT:
7925                         if (lfs_verify_poolarg(optarg))
7926                                 return -1;
7927                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
7928                         qctl->qc_cmd  = LUSTRE_Q_SETINFOPOOL;
7929                         break;
7930                 /* getopt prints error message for us when opterr != 0 */
7931                 default:
7932                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7933                                 progname, argv[optind - 1]);
7934                         fallthrough;
7935                 case 'h':
7936                         return CMD_HELP;
7937                 }
7938         }
7939
7940         if (qctl->qc_type == ALLQUOTA) {
7941                 fprintf(stderr, "%s: neither -u, -g nor -p specified\n",
7942                         progname);
7943                 return CMD_HELP;
7944         }
7945
7946         if (optind != argc - 1) {
7947                 fprintf(stderr, "%s: unexpected parameter '%s'\n",
7948                         progname, argv[optind + 1]);
7949                 return CMD_HELP;
7950         }
7951
7952         mnt = argv[optind];
7953         rc = llapi_quotactl(mnt, qctl);
7954         if (rc) {
7955                 if (*obd_type)
7956                         fprintf(stderr, "%s %s ", obd_type,
7957                                 obd_uuid2str(&qctl->obd_uuid));
7958                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
7959                 return rc;
7960         }
7961
7962         return 0;
7963 }
7964
7965 static int lfs_reset_quota(char *mnt, struct if_quotactl *qctl)
7966 {
7967         struct if_quotactl tmp_qctl;
7968         int index, md_count, dt_count;
7969         int wait_phase = 0, wait_index = 0, wait_count = 0;
7970         int rc, rc2;
7971
7972         /* reset the quota ID, the existing quota setting will be returned */
7973         rc = llapi_quotactl(mnt, qctl);
7974         if (rc)
7975                 return rc;
7976
7977         /* sanity check */
7978         if ((qctl->qc_dqblk.dqb_valid & QIF_LIMITS) != QIF_LIMITS) {
7979                 fprintf(stderr,
7980                         "the existing quota settings are not returned!\n");
7981                 return -EINVAL;
7982         }
7983
7984         rc = llapi_get_obd_count(mnt, &md_count, 1);
7985         if (rc) {
7986                 fprintf(stderr, "can not get mdt count: %s\n", strerror(-rc));
7987                 return rc;
7988         }
7989
7990         rc = llapi_get_obd_count(mnt, &dt_count, 0);
7991         if (rc) {
7992                 fprintf(stderr, "can not get ost count: %s\n", strerror(-rc));
7993                 return rc;
7994         }
7995
7996         memset(&tmp_qctl, 0, sizeof(tmp_qctl));
7997         tmp_qctl.qc_type = qctl->qc_type;
7998         tmp_qctl.qc_id = qctl->qc_id;
7999         tmp_qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
8000
8001 retry:
8002         if (wait_phase == 0) {
8003                 for (index = wait_index; index < md_count; index++) {
8004                         tmp_qctl.qc_idx = index;
8005                         tmp_qctl.qc_valid = QC_MDTIDX;
8006                         rc = llapi_quotactl(mnt, &tmp_qctl);
8007                         if (rc == -ENODEV || rc == -ENODATA)
8008                                 continue;
8009                         if (rc) {
8010                                 fprintf(stderr, "quotactl mdt%d failed: %s\n",
8011                                         index, strerror(-rc));
8012                                 break;
8013                         }
8014                         /* check whether the md quota grant is reset */
8015                         if (tmp_qctl.qc_dqblk.dqb_valid & QIF_LIMITS &&
8016                             tmp_qctl.qc_dqblk.dqb_ihardlimit != 0)
8017                                 break;
8018                 }
8019
8020                 if (index < md_count) {
8021                         wait_phase = 0;
8022                         wait_index = index;
8023                         goto wait;
8024                 }
8025         } else {
8026                 for (index = wait_index; index < dt_count; index++) {
8027                         tmp_qctl.qc_idx = index;
8028                         tmp_qctl.qc_valid = QC_OSTIDX;
8029                         rc = llapi_quotactl(mnt, &tmp_qctl);
8030                         if (rc == -ENODEV || rc == -ENODATA)
8031                                 continue;
8032                         if (rc) {
8033                                 fprintf(stderr, "quotactl mdt%d failed: %s\n",
8034                                         index, strerror(-rc));
8035                                 break;
8036                         }
8037                         /* check whether the dt quota grant is reset */
8038                         if (tmp_qctl.qc_dqblk.dqb_valid & QIF_LIMITS &&
8039                             tmp_qctl.qc_dqblk.dqb_bhardlimit != 0)
8040                                 break;
8041                 }
8042
8043                 if (index < dt_count) {
8044                         wait_phase = 1;
8045                         wait_index = index;
8046                         goto wait;
8047                 }
8048         }
8049
8050         if (wait_phase == 0) {
8051                 wait_phase = 1;
8052                 goto retry;
8053         }
8054
8055         goto out;
8056
8057 wait:
8058         if (rc || wait_count > 30) {
8059                 fprintf(stderr, "fail to reset the quota ID %d on OBDs\n",
8060                         qctl->qc_id);
8061                 goto out;
8062         }
8063
8064         wait_count++;
8065         sleep(1);
8066         fprintf(stdout, "wait %d seconds for OBDs to reset the quota ID %u\n",
8067                 wait_count, qctl->qc_id);
8068         goto retry;
8069
8070
8071 out:
8072         /* restore the quota setting */
8073         if (qctl->qc_dqblk.dqb_isoftlimit == 0 &&
8074             qctl->qc_dqblk.dqb_ihardlimit == 0 &&
8075             qctl->qc_dqblk.dqb_bsoftlimit == 0 &&
8076             qctl->qc_dqblk.dqb_bhardlimit == 0)
8077                 return rc;
8078
8079         memcpy(&tmp_qctl, qctl, sizeof(tmp_qctl));
8080         tmp_qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
8081         rc2 = llapi_quotactl(mnt, &tmp_qctl);
8082         if (!rc2)
8083                 return rc;
8084
8085         fprintf(stderr,
8086                 "fail to restore the quota setting: %s, please restore it manually by\n  lfs setquota %s %d",
8087                 strerror(-rc2),
8088                 qctl->qc_type == USRQUOTA ? "-u" :
8089                                 (qctl->qc_type == GRPQUOTA ? "-g" : "-p"),
8090                 qctl->qc_id);
8091
8092         if (qctl->qc_dqblk.dqb_isoftlimit != 0)
8093                 fprintf(stderr, " -i %llu",
8094                         (unsigned long long)qctl->qc_dqblk.dqb_isoftlimit);
8095         if (qctl->qc_dqblk.dqb_ihardlimit != 0)
8096                 fprintf(stderr, " -I %llu",
8097                         (unsigned long long)qctl->qc_dqblk.dqb_ihardlimit);
8098         if (qctl->qc_dqblk.dqb_bsoftlimit != 0)
8099                 fprintf(stderr, " -b %llu",
8100                         (unsigned long long)qctl->qc_dqblk.dqb_bsoftlimit);
8101         if (qctl->qc_dqblk.dqb_bhardlimit != 0)
8102                 fprintf(stderr, " -B %llu",
8103                         (unsigned long long)qctl->qc_dqblk.dqb_bhardlimit);
8104
8105         fprintf(stderr, " %s\n", mnt);
8106         if (!rc)
8107                 rc = rc2;
8108
8109         return rc;
8110 }
8111
8112 #define BSLIMIT (1 << 0)
8113 #define BHLIMIT (1 << 1)
8114 #define ISLIMIT (1 << 2)
8115 #define IHLIMIT (1 << 3)
8116
8117 int lfs_setquota(int argc, char **argv)
8118 {
8119         int c, rc = 0;
8120         struct if_quotactl *qctl;
8121         char *mnt, *obd_type;
8122         struct obd_dqblk *dqb;
8123         struct option long_opts[] = {
8124         { .val = 'b',   .name = "block-softlimit",
8125                                                 .has_arg = required_argument },
8126         { .val = 'B',   .name = "block-hardlimit",
8127                                                 .has_arg = required_argument },
8128         { .val = 'd',   .name = "default",      .has_arg = no_argument },
8129         { .val = LFS_SETQUOTA_DELETE,
8130                         .name = "delete",       .has_arg = no_argument },
8131         { .val = 'g',   .name = "group",        .has_arg = required_argument },
8132         { .val = 'G',   .name = "default-grp",  .has_arg = no_argument },
8133         { .val = 'h',   .name = "help",         .has_arg = no_argument },
8134         { .val = 'i',   .name = "inode-softlimit",
8135                                                 .has_arg = required_argument },
8136         { .val = 'I',   .name = "inode-hardlimit",
8137                                                 .has_arg = required_argument },
8138         { .val = 'p',   .name = "projid",       .has_arg = required_argument },
8139         { .val = 'P',   .name = "default-prj",  .has_arg = no_argument },
8140         { .val = 'r',   .name = "reset",        .has_arg = no_argument },
8141         { .val = 'u',   .name = "user",         .has_arg = required_argument },
8142         { .val = 'U',   .name = "default-usr",  .has_arg = no_argument },
8143         { .val = LFS_POOL_OPT,
8144                         .name = "pool",         .has_arg = required_argument },
8145         { .name = NULL } };
8146         unsigned int limit_mask = 0;
8147         bool use_default = false;
8148         int qtype, qctl_len;
8149
8150         qctl_len = sizeof(*qctl) + LOV_MAXPOOLNAME + 1;
8151         qctl = malloc(qctl_len);
8152         if (!qctl)
8153                 return -ENOMEM;
8154
8155         memset(qctl, 0, qctl_len);
8156         obd_type = (char *)qctl->obd_type;
8157         dqb = &qctl->qc_dqblk;
8158
8159         if (has_times_option(argc, argv)) {
8160                 rc = lfs_setquota_times(argc, argv, qctl);
8161                 goto out;
8162         }
8163
8164         qctl->qc_cmd  = LUSTRE_Q_SETQUOTA;
8165         qctl->qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
8166                                    * so it can be used as a marker that qc_type
8167                                    * isn't reinitialized from command line
8168                                    */
8169         while ((c = getopt_long(argc, argv, "b:B:dDg:Ghi:I:p:Pru:U",
8170                 long_opts, NULL)) != -1) {
8171                 switch (c) {
8172                 case 'U':
8173                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8174                         qtype = USRQUOTA;
8175                         qctl->qc_id = 0;
8176                         goto quota_type_def;
8177                 case 'u':
8178                         qtype = USRQUOTA;
8179                         rc = name2uid(&qctl->qc_id, optarg);
8180                         goto quota_type;
8181                 case 'G':
8182                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8183                         qtype = GRPQUOTA;
8184                         qctl->qc_id = 0;
8185                         goto quota_type_def;
8186                 case 'g':
8187                         qtype = GRPQUOTA;
8188                         rc = name2gid(&qctl->qc_id, optarg);
8189                         goto quota_type;
8190                 case 'P':
8191                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8192                         qtype = PRJQUOTA;
8193                         qctl->qc_id = 0;
8194                         goto quota_type_def;
8195                 case 'p':
8196                         qtype = PRJQUOTA;
8197                         rc = name2projid(&qctl->qc_id, optarg);
8198 quota_type:
8199                         if (rc) {
8200                                 if (str2quotaid(&qctl->qc_id, optarg)) {
8201                                         fprintf(stderr,
8202                                                 "%s setquota: invalid id '%s'\n",
8203                                                 progname, optarg);
8204                                         rc = -1;
8205                                         goto out;
8206                                 }
8207                         }
8208
8209                         if (qctl->qc_id == 0) {
8210                                 fprintf(stderr,
8211                                         "%s setquota: can't set quota for root usr/group/project.\n",
8212                                         progname);
8213                                 rc = -1;
8214                                 goto out;
8215                         }
8216
8217 quota_type_def:
8218                         if (qctl->qc_type != ALLQUOTA) {
8219                                 fprintf(stderr,
8220                                         "%s setquota: only one of -u, -U, -g, -G, -p or -P may be specified\n",
8221                                         progname);
8222                                 rc = CMD_HELP;
8223                                 goto out;
8224                         }
8225                         qctl->qc_type = qtype;
8226                         break;
8227 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
8228                 case 'd':
8229                         fprintf(stderr,
8230                                 "%s setquota: '-d' deprecated, use '-D' or '--default'\n",
8231                                 progname);
8232                         fallthrough;
8233 #endif
8234                 case 'D':
8235                         use_default = true;
8236                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8237                         break;
8238                 case LFS_SETQUOTA_DELETE:
8239                         qctl->qc_cmd = LUSTRE_Q_DELETEQID;
8240                         break;
8241                 case 'b':
8242                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
8243                         dqb->dqb_bsoftlimit >>= 10;
8244                         limit_mask |= BSLIMIT;
8245                         if (dqb->dqb_bsoftlimit &&
8246                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
8247                                 fprintf(stderr,
8248                                         "%s setquota: warning: block softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8249                                         progname,
8250                                         (unsigned long long)dqb->dqb_bsoftlimit,
8251                                         progname);
8252                         break;
8253                 case 'B':
8254                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
8255                         dqb->dqb_bhardlimit >>= 10;
8256                         limit_mask |= BHLIMIT;
8257                         if (dqb->dqb_bhardlimit &&
8258                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
8259                                 fprintf(stderr,
8260                                         "%s setquota: warning: block hardlimit '%llu' smaller than minimum qunit size\n"
8261                                         "See '%s help setquota' or Lustre manual for details\n",
8262                                         progname,
8263                                         (unsigned long long)dqb->dqb_bhardlimit,
8264                                         progname);
8265                         break;
8266                 case 'i':
8267                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
8268                         limit_mask |= ISLIMIT;
8269                         if (dqb->dqb_isoftlimit &&
8270                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
8271                                 fprintf(stderr,
8272                                         "%s setquota: warning: inode softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8273                                         progname,
8274                                         (unsigned long long)dqb->dqb_isoftlimit,
8275                                         progname);
8276                         break;
8277                 case 'I':
8278                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
8279                         limit_mask |= IHLIMIT;
8280                         if (dqb->dqb_ihardlimit &&
8281                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
8282                                 fprintf(stderr,
8283                                         "%s setquota: warning: inode hardlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8284                                         progname,
8285                                         (unsigned long long)dqb->dqb_ihardlimit,
8286                                         progname);
8287                         break;
8288                 case LFS_POOL_OPT:
8289                         if (lfs_verify_poolarg(optarg)) {
8290                                 rc = -1;
8291                                 goto out;
8292                         }
8293                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
8294                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_SETDEFAULT ?
8295                                                 LUSTRE_Q_SETDEFAULT_POOL :
8296                                                 LUSTRE_Q_SETQUOTAPOOL;
8297                         break;
8298                 case 'r':
8299                         qctl->qc_cmd = LUSTRE_Q_RESETQID;
8300                         break;
8301                 default:
8302                         fprintf(stderr,
8303                                 "%s setquota: unrecognized option '%s'\n",
8304                                 progname, argv[optind - 1]);
8305                         fallthrough;
8306                 case 'h':
8307                         rc = CMD_HELP;
8308                         goto out;
8309                 }
8310         }
8311
8312         if (qctl->qc_type == ALLQUOTA) {
8313                 fprintf(stderr,
8314                         "%s setquota: either -u or -g must be specified\n",
8315                         progname);
8316                 rc = CMD_HELP;
8317                 goto out;
8318         }
8319
8320         if (!use_default && qctl->qc_cmd != LUSTRE_Q_DELETEQID &&
8321             qctl->qc_cmd != LUSTRE_Q_RESETQID && limit_mask == 0) {
8322                 fprintf(stderr,
8323                         "%s setquota: at least one limit must be specified\n",
8324                         progname);
8325                 rc = CMD_HELP;
8326                 goto out;
8327         }
8328
8329         if ((use_default || qctl->qc_cmd == LUSTRE_Q_DELETEQID ||
8330              qctl->qc_cmd == LUSTRE_Q_RESETQID) && limit_mask != 0) {
8331                 fprintf(stderr,
8332                         "%s setquota: limits should not be specified when using default quota, deleting or resetting quota ID\n",
8333                         progname);
8334                 rc = CMD_HELP;
8335                 goto out;
8336         }
8337
8338         if (use_default && qctl->qc_id == 0) {
8339                 fprintf(stderr,
8340                         "%s setquota: can not set default quota for root user/group/project\n",
8341                         progname);
8342                 rc = CMD_HELP;
8343                 goto out;
8344         }
8345
8346         if ((qctl->qc_cmd == LUSTRE_Q_DELETEQID ||
8347              qctl->qc_cmd == LUSTRE_Q_RESETQID)  && qctl->qc_id == 0) {
8348                 fprintf(stderr,
8349                         "%s setquota: can not delete or reset root user/group/project\n",
8350                         progname);
8351                 rc = CMD_HELP;
8352                 goto out;
8353         }
8354
8355         if (optind != argc - 1) {
8356                 fprintf(stderr,
8357                         "%s setquota: filesystem not specified or unexpected argument '%s'\n",
8358                         progname, argv[optind]);
8359                 rc = CMD_HELP;
8360                 goto out;
8361         }
8362
8363         mnt = argv[optind];
8364
8365         if (use_default) {
8366                 dqb->dqb_bhardlimit = 0;
8367                 dqb->dqb_bsoftlimit = 0;
8368                 dqb->dqb_ihardlimit = 0;
8369                 dqb->dqb_isoftlimit = 0;
8370                 dqb->dqb_itime = 0;
8371                 dqb->dqb_btime = 0;
8372                 dqb->dqb_valid |= QIF_LIMITS | QIF_TIMES;
8373                 /* do not set inode limits for Pool Quotas */
8374                 if (qctl->qc_cmd  == LUSTRE_Q_SETDEFAULT_POOL)
8375                         dqb->dqb_valid ^= QIF_ILIMITS | QIF_ITIME;
8376         } else if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
8377                    (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
8378                 /* sigh, we can't just set blimits/ilimits */
8379                 struct if_quotactl *tmp_qctl;
8380
8381                 tmp_qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1);
8382                 if (!tmp_qctl)
8383                         goto out;
8384
8385                 if (qctl->qc_cmd == LUSTRE_Q_SETQUOTAPOOL) {
8386                         tmp_qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
8387                         strncpy(tmp_qctl->qc_poolname, qctl->qc_poolname,
8388                                 LOV_MAXPOOLNAME);
8389                 } else {
8390                         tmp_qctl->qc_cmd  = LUSTRE_Q_GETQUOTA;
8391                 }
8392                 tmp_qctl->qc_type = qctl->qc_type;
8393                 tmp_qctl->qc_id = qctl->qc_id;
8394
8395                 rc = llapi_quotactl(mnt, tmp_qctl);
8396                 if (rc < 0) {
8397                         free(tmp_qctl);
8398                         goto out;
8399                 }
8400
8401                 if (!(limit_mask & BHLIMIT))
8402                         dqb->dqb_bhardlimit = tmp_qctl->qc_dqblk.dqb_bhardlimit;
8403                 if (!(limit_mask & BSLIMIT))
8404                         dqb->dqb_bsoftlimit = tmp_qctl->qc_dqblk.dqb_bsoftlimit;
8405                 if (!(limit_mask & IHLIMIT))
8406                         dqb->dqb_ihardlimit = tmp_qctl->qc_dqblk.dqb_ihardlimit;
8407                 if (!(limit_mask & ISLIMIT))
8408                         dqb->dqb_isoftlimit = tmp_qctl->qc_dqblk.dqb_isoftlimit;
8409
8410                 /* Keep grace times if we have got no softlimit arguments */
8411                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
8412                         dqb->dqb_valid |= QIF_BTIME;
8413                         dqb->dqb_btime = tmp_qctl->qc_dqblk.dqb_btime;
8414                 }
8415
8416                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
8417                         dqb->dqb_valid |= QIF_ITIME;
8418                         dqb->dqb_itime = tmp_qctl->qc_dqblk.dqb_itime;
8419                 }
8420                 free(tmp_qctl);
8421         }
8422
8423         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
8424         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
8425
8426         if (qctl->qc_cmd == LUSTRE_Q_RESETQID)
8427                 rc = lfs_reset_quota(mnt, qctl);
8428         else
8429                 rc = llapi_quotactl(mnt, qctl);
8430
8431         if (rc) {
8432                 if (*obd_type)
8433                         fprintf(stderr,
8434                                 "%s setquota: cannot quotactl '%s' '%s': %s\n",
8435                                 progname, obd_type,
8436                                 obd_uuid2str(&qctl->obd_uuid), strerror(-rc));
8437                 else
8438                         fprintf(stderr,
8439                                 "%s setquota: quotactl failed: %s\n",
8440                                 progname, strerror(-rc));
8441         }
8442 out:
8443         if (rc)
8444                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
8445
8446         free(qctl);
8447         return rc;
8448 }
8449
8450 /* Converts seconds value into format string
8451  * result is returned in buf
8452  * Notes:
8453  *        1. result is in descenting order: 1w2d3h4m5s
8454  *        2. zero fields are not filled (except for p. 3): 5d1s
8455  *        3. zero seconds value is presented as "0s"
8456  */
8457 static char *__sec2str(time_t seconds, char *buf)
8458 {
8459         const char spec[] = "smhdw";
8460         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
8461         unsigned long c;
8462         char *tail = buf;
8463         int i;
8464
8465         for (i = ARRAY_SIZE(mult) - 1 ; i >= 0; i--) {
8466                 c = seconds / mult[i];
8467
8468                 if (c > 0 || (i == 0 && buf == tail))
8469                         tail += scnprintf(tail, 40-(tail-buf), "%lu%c", c,
8470                                           spec[i]);
8471
8472                 seconds %= mult[i];
8473         }
8474
8475         return tail;
8476 }
8477
8478 static void sec2str(time_t seconds, char *buf, int rc)
8479 {
8480         char *tail = buf;
8481
8482         if (rc)
8483                 *tail++ = '[';
8484
8485         tail = __sec2str(seconds, tail);
8486
8487         if (rc && tail - buf < 39) {
8488                 *tail++ = ']';
8489                 *tail++ = 0;
8490         }
8491 }
8492
8493 static void diff2str(time_t seconds, char *buf, time_t now)
8494 {
8495         buf[0] = 0;
8496         if (!seconds)
8497                 return;
8498         if (seconds <= now) {
8499                 strcpy(buf, "expired");
8500                 return;
8501         }
8502         __sec2str(seconds - now, buf);
8503 }
8504
8505 static void print_quota_title(char *name, struct if_quotactl *qctl,
8506                               bool human_readable, bool show_default)
8507 {
8508         if (show_default) {
8509                 printf("Disk default %s quota:\n", qtype_name(qctl->qc_type));
8510                 printf("%15s %8s%8s%8s %8s%8s%8s\n",
8511                        "Filesystem", "bquota", "blimit", "bgrace",
8512                        "iquota", "ilimit", "igrace");
8513         } else {
8514                 printf("Disk quotas for %s %s (%cid %u):\n",
8515                        qtype_name(qctl->qc_type), name,
8516                        *qtype_name(qctl->qc_type), qctl->qc_id);
8517                 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
8518                        "Filesystem", human_readable ? "used" : "kbytes",
8519                        "quota", "limit", "grace",
8520                        "files", "quota", "limit", "grace");
8521         }
8522 }
8523
8524 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
8525 {
8526         if (!h) {
8527                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
8528         } else {
8529                 if (num >> 40)
8530                         snprintf(buf, buflen, "%5.4gP",
8531                                  (double)num / ((__u64)1 << 40));
8532                 else if (num >> 30)
8533                         snprintf(buf, buflen, "%5.4gT",
8534                                  (double)num / (1 << 30));
8535                 else if (num >> 20)
8536                         snprintf(buf, buflen, "%5.4gG",
8537                                  (double)num / (1 << 20));
8538                 else if (num >> 10)
8539                         snprintf(buf, buflen, "%5.4gM",
8540                                  (double)num / (1 << 10));
8541                 else
8542                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
8543         }
8544 }
8545
8546 #ifdef HAVE_NATIVE_CLIENT
8547 /* In the current Lustre implementation, the grace time is either the time
8548  * or the timestamp to be used after some quota ID exceeds the soft limt,
8549  * 48 bits should be enough, its high 16 bits can be used as quota flags.
8550  */
8551 #define LQUOTA_GRACE_BITS       48
8552 #define LQUOTA_GRACE_MASK       ((1ULL << LQUOTA_GRACE_BITS) - 1)
8553 #define LQUOTA_GRACE_MAX        LQUOTA_GRACE_MASK
8554 #define LQUOTA_GRACE(t)         (t & LQUOTA_GRACE_MASK)
8555 #define LQUOTA_FLAG(t)          (t >> LQUOTA_GRACE_BITS)
8556 #define LQUOTA_GRACE_FLAG(t, f) ((__u64)t | (__u64)f << LQUOTA_GRACE_BITS)
8557 #endif
8558
8559 #define STRBUF_LEN      24
8560 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
8561                         int rc, bool h, bool show_default)
8562 {
8563         time_t now;
8564
8565         time(&now);
8566
8567         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA ||
8568             qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
8569             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT ||
8570             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL) {
8571                 int bover = 0, iover = 0;
8572                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
8573                 char numbuf[3][STRBUF_LEN + 2]; /* 2 for brackets or wildcard */
8574                 char timebuf[40];
8575                 char strbuf[STRBUF_LEN];
8576
8577                 dqb->dqb_btime &= LQUOTA_GRACE_MASK;
8578                 dqb->dqb_itime &= LQUOTA_GRACE_MASK;
8579
8580                 if (dqb->dqb_bhardlimit &&
8581                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
8582                         bover = 1;
8583                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
8584                         if (dqb->dqb_btime > now)
8585                                 bover = 2;
8586                         else
8587                                 bover = 3;
8588                 }
8589
8590                 if (dqb->dqb_ihardlimit &&
8591                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
8592                         iover = 1;
8593                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
8594                         if (dqb->dqb_itime > now)
8595                                 iover = 2;
8596                         else
8597                                 iover = 3;
8598                 }
8599
8600                 if (strlen(mnt) > 15)
8601                         printf("%s\n%15s", mnt, "");
8602                 else
8603                         printf("%15s", mnt);
8604
8605                 if (show_default)
8606                         snprintf(timebuf, sizeof(timebuf), "%llu",
8607                                  (unsigned long long)dqb->dqb_btime);
8608                 else if (bover)
8609                         diff2str(dqb->dqb_btime, timebuf, now);
8610
8611                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
8612                            strbuf, sizeof(strbuf), h);
8613                 if (rc == -EREMOTEIO)
8614                         sprintf(numbuf[0], "%s*", strbuf);
8615                 else
8616                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
8617                                 "%s" : "[%s]", strbuf);
8618
8619                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
8620                 if (type == QC_GENERAL)
8621                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
8622                                 "%s" : "[%s]", strbuf);
8623                 else
8624                         sprintf(numbuf[1], "%s", "-");
8625
8626                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
8627                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
8628                         "%s" : "[%s]", strbuf);
8629
8630                 if (show_default)
8631                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
8632                 else
8633                         printf(" %7s%c %6s %7s %7s",
8634                                numbuf[0], bover ? '*' : ' ', numbuf[1],
8635                                numbuf[2], bover > 1 ? timebuf : "-");
8636
8637                 if (show_default)
8638                         snprintf(timebuf, sizeof(timebuf), "%llu",
8639                                  (unsigned long long)dqb->dqb_itime);
8640                 else if (iover)
8641                         diff2str(dqb->dqb_itime, timebuf, now);
8642
8643                 snprintf(numbuf[0], sizeof(numbuf),
8644                          (dqb->dqb_valid & QIF_INODES) ? "%ju" : "[%ju]",
8645                          (uintmax_t)dqb->dqb_curinodes);
8646
8647                 if (type == QC_GENERAL)
8648                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
8649                                 "%ju" : "[%ju]",
8650                                 (uintmax_t)dqb->dqb_isoftlimit);
8651                 else
8652                         sprintf(numbuf[1], "%s", "-");
8653
8654                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
8655                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
8656
8657                 if (show_default)
8658                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
8659                 else if (type != QC_OSTIDX)
8660                         printf(" %7s%c %6s %7s %7s",
8661                                numbuf[0], iover ? '*' : ' ', numbuf[1],
8662                                numbuf[2], iover > 1 ? timebuf : "-");
8663                 else
8664                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
8665                 printf("\n");
8666         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
8667                    qctl->qc_cmd == LUSTRE_Q_GETINFOPOOL ||
8668                    qctl->qc_cmd == Q_GETOINFO) {
8669                 char bgtimebuf[40];
8670                 char igtimebuf[40];
8671
8672                 if (qctl->qc_dqinfo.dqi_bgrace == NOTIFY_GRACE_TIME)
8673                         strncpy(bgtimebuf, NOTIFY_GRACE, 40);
8674                 else
8675                         sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
8676                 if (qctl->qc_dqinfo.dqi_igrace == NOTIFY_GRACE_TIME)
8677                         strncpy(igtimebuf, NOTIFY_GRACE, 40);
8678                 else
8679                         sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
8680
8681                 printf("Block grace time: %s; Inode grace time: %s\n",
8682                        bgtimebuf, igtimebuf);
8683         }
8684 }
8685
8686 static int tgt_name2index(const char *tgtname, unsigned int *idx)
8687 {
8688         char *dash, *endp;
8689
8690         /* format is "lustre-OST0001" */
8691         dash = memchr(tgtname, '-', LUSTRE_MAXFSNAME + 1);
8692         if (!dash) {
8693                 fprintf(stderr, "wrong tgtname format '%s'\n", tgtname);
8694                 return -EINVAL;
8695         }
8696         dash += 4;
8697
8698         *idx = strtoul(dash, &endp, 16);
8699         if (*idx > 0xffff) {
8700                 fprintf(stderr, "wrong index %s\n", tgtname);
8701                 return -ERANGE;
8702         }
8703
8704         return 0;
8705 }
8706
8707 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
8708                            bool h, __u64 *total)
8709 {
8710         int rc = 0, rc1 = 0, count = 0, i = 0;
8711         char **list = NULL, *buffer = NULL;
8712         __u32 valid = qctl->qc_valid;
8713
8714         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL && is_mdt)
8715                 return 0;
8716
8717         /* Is it correct for the case OST0000, OST0002, OST0003 -
8718          * we will ask OST0001 that is absent and won't ask OST0003? */
8719         rc = llapi_get_obd_count(mnt, &count, is_mdt);
8720         if (rc) {
8721                 fprintf(stderr, "can not get %s count: %s\n",
8722                         is_mdt ? "mdt" : "ost", strerror(-rc));
8723                 return rc;
8724         }
8725
8726         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
8727                 char fname[PATH_MAX];
8728                 char fsname[LUSTRE_MAXFSNAME + 1];
8729                 int bufsize = sizeof(struct obd_uuid) * count;
8730
8731                 rc = llapi_search_fsname(mnt, fsname);
8732                 if (rc) {
8733                         fprintf(stderr, "cannot get fsname for mountpoint %s\n",
8734                                 mnt);
8735                         goto out;
8736                 }
8737                 buffer = malloc(bufsize + sizeof(*list) * count);
8738                 if (!buffer)
8739                         return -ENOMEM;
8740                 list = (char **)(buffer + bufsize);
8741                 snprintf(fname, PATH_MAX, "%s.%s", fsname, qctl->qc_poolname);
8742                 count = llapi_get_poolmembers(fname, list, count,
8743                                               buffer, bufsize);
8744                 if (count <= 0)
8745                         goto out;
8746         }
8747
8748         for (i = 0; i < count; i++) {
8749                 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
8750                         unsigned int index;
8751
8752                         if (tgt_name2index(list[i], &index))
8753                                 continue;
8754                         qctl->qc_idx = index;
8755                 } else {
8756                         qctl->qc_idx = i;
8757                 }
8758
8759                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
8760                 rc = llapi_quotactl(mnt, qctl);
8761                 if (rc) {
8762                         /* It is remote client case. */
8763                         if (rc == -EOPNOTSUPP) {
8764                                 rc = 0;
8765                                 goto out;
8766                         }
8767
8768                         /* no target for this index yet */
8769                         if (rc == -ENODEV) {
8770                                 rc = 0;
8771                                 continue;
8772                         }
8773
8774                         /* inactive target */
8775                         if (rc == -ENODATA) {
8776                                 char name[UUID_MAX+8];
8777
8778                                 snprintf(name, sizeof(name), "%s[inact]",
8779                                         obd_uuid2str(&qctl->obd_uuid));
8780                                 memset(&qctl->qc_dqinfo, 0,
8781                                        sizeof(qctl->qc_dqinfo));
8782                                 memset(&qctl->qc_dqblk, 0,
8783                                        sizeof(qctl->qc_dqblk));
8784                                 print_quota(name, qctl, qctl->qc_valid, 0, h,
8785                                             false);
8786                                 rc = 0;
8787                                 continue;
8788                         }
8789
8790                         if (!rc1)
8791                                 rc1 = rc;
8792                         fprintf(stderr, "quotactl %s%d failed.\n",
8793                                 is_mdt ? "mdt" : "ost", qctl->qc_idx);
8794                         continue;
8795                 }
8796
8797                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
8798                             qctl->qc_valid, 0, h, false);
8799                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
8800                                    qctl->qc_dqblk.dqb_bhardlimit;
8801         }
8802 out:
8803         if (buffer)
8804                 free(buffer);
8805         qctl->qc_valid = valid;
8806         return rc ? : rc1;
8807 }
8808
8809 static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
8810                            int verbose, int quiet, bool human_readable,
8811                            bool show_default)
8812 {
8813         int rc1 = 0, rc2 = 0, rc3 = 0;
8814         char *obd_type = (char *)qctl->obd_type;
8815         char *obd_uuid = (char *)qctl->obd_uuid.uuid;
8816         __u64 total_ialloc = 0, total_balloc = 0;
8817         bool use_default_for_blk = false;
8818         bool use_default_for_file = false;
8819         int inacc;
8820
8821         rc1 = llapi_quotactl(mnt, qctl);
8822         if (rc1 < 0) {
8823                 switch (rc1) {
8824                 case -ESRCH:
8825                         fprintf(stderr, "%s quotas are not enabled.\n",
8826                                 qtype_name(qctl->qc_type));
8827                         goto out;
8828                 case -EPERM:
8829                         fprintf(stderr, "Permission denied.\n");
8830                 case -ENODEV:
8831                 case -ENOENT:
8832                         /* We already got error message. */
8833                         goto out;
8834                 default:
8835                         fprintf(stderr, "Unexpected quotactl error: %s\n",
8836                                 strerror(-rc1));
8837                 }
8838         }
8839
8840         if (!show_default && qctl->qc_id == 0) {
8841                 qctl->qc_dqblk.dqb_bhardlimit = 0;
8842                 qctl->qc_dqblk.dqb_bsoftlimit = 0;
8843                 qctl->qc_dqblk.dqb_ihardlimit = 0;
8844                 qctl->qc_dqblk.dqb_isoftlimit = 0;
8845                 qctl->qc_dqblk.dqb_btime = 0;
8846                 qctl->qc_dqblk.dqb_itime = 0;
8847                 qctl->qc_dqblk.dqb_valid |= QIF_LIMITS | QIF_TIMES;
8848         }
8849
8850         if (qctl->qc_dqblk.dqb_valid & QIF_BTIME &&
8851             LQUOTA_FLAG(qctl->qc_dqblk.dqb_btime) & LQUOTA_FLAG_DEFAULT) {
8852                 use_default_for_blk = true;
8853                 qctl->qc_dqblk.dqb_btime &= LQUOTA_GRACE_MASK;
8854         }
8855
8856         if (qctl->qc_dqblk.dqb_valid & QIF_ITIME &&
8857             LQUOTA_FLAG(qctl->qc_dqblk.dqb_itime) & LQUOTA_FLAG_DEFAULT) {
8858                 use_default_for_file = true;
8859                 qctl->qc_dqblk.dqb_itime &= LQUOTA_GRACE_MASK;
8860         }
8861
8862         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
8863              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
8864              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL ||
8865              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) && !quiet)
8866                 print_quota_title(name, qctl, human_readable, show_default);
8867
8868         if (rc1 && *obd_type)
8869                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
8870
8871         if (qctl->qc_valid != QC_GENERAL)
8872                 mnt = "";
8873
8874         inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
8875                  qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
8876                 ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
8877                  (QIF_LIMITS|QIF_USAGE));
8878
8879         print_quota(mnt, qctl, QC_GENERAL, rc1, human_readable, show_default);
8880
8881         if (!show_default && verbose &&
8882             qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO &&
8883             qctl->qc_cmd != LUSTRE_Q_GETINFOPOOL) {
8884                 char strbuf[STRBUF_LEN];
8885
8886                 rc2 = print_obd_quota(mnt, qctl, 1, human_readable,
8887                                       &total_ialloc);
8888                 rc3 = print_obd_quota(mnt, qctl, 0, human_readable,
8889                                       &total_balloc);
8890                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
8891                            human_readable);
8892                 printf("Total allocated inode limit: %ju, total allocated block limit: %s\n",
8893                        (uintmax_t)total_ialloc, strbuf);
8894         }
8895
8896         if (use_default_for_blk)
8897                 printf("%cid %u is using default block quota setting\n",
8898                        *qtype_name(qctl->qc_type), qctl->qc_id);
8899
8900         if (use_default_for_file)
8901                 printf("%cid %u is using default file quota setting\n",
8902                        *qtype_name(qctl->qc_type), qctl->qc_id);
8903
8904         if (rc1 || rc2 || rc3 || inacc)
8905                 printf("Some errors happened when getting quota info. Some devices may be not working or deactivated. The data in \"[]\" is inaccurate.\n");
8906 out:
8907         if (rc1)
8908                 return rc1;
8909         if (rc2)
8910                 return rc2;
8911         if (rc3)
8912                 return rc3;
8913         if (inacc)
8914                 return -EIO;
8915
8916         return 0;
8917 }
8918
8919 static int lfs_project(int argc, char **argv)
8920 {
8921         int ret = 0, err = 0, c, i;
8922         struct project_handle_control phc = { 0 };
8923         enum lfs_project_ops_t op;
8924
8925         phc.newline = true;
8926         phc.assign_projid = false;
8927         /* default action */
8928         op = LFS_PROJECT_LIST;
8929
8930         while ((c = getopt(argc, argv, "p:cCsdkr0")) != -1) {
8931                 switch (c) {
8932                 case 'c':
8933                         if (op != LFS_PROJECT_LIST) {
8934                                 fprintf(stderr,
8935                                         "%s: cannot specify '-c' '-C' '-s' together\n",
8936                                         progname);
8937                                 return CMD_HELP;
8938                         }
8939
8940                         op = LFS_PROJECT_CHECK;
8941                         break;
8942                 case 'C':
8943                         if (op != LFS_PROJECT_LIST) {
8944                                 fprintf(stderr,
8945                                         "%s: cannot specify '-c' '-C' '-s' together\n",
8946                                         progname);
8947                                 return CMD_HELP;
8948                         }
8949
8950                         op = LFS_PROJECT_CLEAR;
8951                         break;
8952                 case 's':
8953                         if (op != LFS_PROJECT_LIST) {
8954                                 fprintf(stderr,
8955                                         "%s: cannot specify '-c' '-C' '-s' together\n",
8956                                         progname);
8957                                 return CMD_HELP;
8958                         }
8959
8960                         phc.set_inherit = true;
8961                         op = LFS_PROJECT_SET;
8962                         break;
8963                 case 'd':
8964                         phc.dironly = true;
8965                         break;
8966                 case 'k':
8967                         phc.keep_projid = true;
8968                         break;
8969                 case 'r':
8970                         phc.recursive = true;
8971                         break;
8972                 case 'p':
8973                         if (str2quotaid(&phc.projid, optarg)) {
8974                                 fprintf(stderr,
8975                                         "Invalid project ID: %s\n",
8976                                         optarg);
8977                                 return CMD_HELP;
8978                         }
8979
8980                         phc.assign_projid = true;
8981
8982                         break;
8983                 case '0':
8984                         phc.newline = false;
8985                         break;
8986                 default:
8987                         fprintf(stderr, "%s: invalid option '%c'\n",
8988                                 progname, optopt);
8989                         return CMD_HELP;
8990                 }
8991         }
8992
8993         if (phc.assign_projid && op == LFS_PROJECT_LIST) {
8994                 op = LFS_PROJECT_SET;
8995                 phc.set_projid = true;
8996         } else if (phc.assign_projid && op == LFS_PROJECT_SET) {
8997                 phc.set_projid = true;
8998         }
8999
9000         switch (op) {
9001         case LFS_PROJECT_CHECK:
9002                 if (phc.keep_projid) {
9003                         fprintf(stderr,
9004                                 "%s: '-k' is useless together with '-c'\n",
9005                                 progname);
9006                         return CMD_HELP;
9007                 }
9008                 break;
9009         case LFS_PROJECT_CLEAR:
9010                 if (!phc.newline) {
9011                         fprintf(stderr,
9012                                 "%s: '-0' is useless together with '-C'\n",
9013                                 progname);
9014                         return CMD_HELP;
9015                 }
9016                 if (phc.assign_projid) {
9017                         fprintf(stderr,
9018                                 "%s: '-p' is useless together with '-C'\n",
9019                                 progname);
9020                         return CMD_HELP;
9021                 }
9022                 break;
9023         case LFS_PROJECT_SET:
9024                 if (!phc.newline) {
9025                         fprintf(stderr,
9026                                 "%s: '-0' is useless together with '-s'\n",
9027                                 progname);
9028                         return CMD_HELP;
9029                 }
9030                 if (phc.keep_projid) {
9031                         fprintf(stderr,
9032                                 "%s: '-k' is useless together with '-s'\n",
9033                                 progname);
9034                         return CMD_HELP;
9035                 }
9036                 break;
9037         default:
9038                 if (!phc.newline) {
9039                         fprintf(stderr,
9040                                 "%s: '-0' is useless for list operations\n",
9041                                 progname);
9042                         return CMD_HELP;
9043                 }
9044                 break;
9045         }
9046
9047         argv += optind;
9048         argc -= optind;
9049         if (argc == 0) {
9050                 fprintf(stderr, "%s: missing file or directory target(s)\n",
9051                         progname);
9052                 return CMD_HELP;
9053         }
9054
9055         for (i = 0; i < argc; i++) {
9056                 switch (op) {
9057                 case LFS_PROJECT_CHECK:
9058                         err = lfs_project_check(argv[i], &phc);
9059                         break;
9060                 case LFS_PROJECT_LIST:
9061                         err = lfs_project_list(argv[i], &phc);
9062                         break;
9063                 case LFS_PROJECT_CLEAR:
9064                         err = lfs_project_clear(argv[i], &phc);
9065                         break;
9066                 case LFS_PROJECT_SET:
9067                         err = lfs_project_set(argv[i], &phc);
9068                         break;
9069                 default:
9070                         break;
9071                 }
9072                 if (err && !ret)
9073                         ret = err;
9074         }
9075
9076         return ret;
9077 }
9078
9079 static int lfs_quota(int argc, char **argv)
9080 {
9081         int c;
9082         char *mnt, *name = NULL;
9083         struct if_quotactl *qctl;
9084         char *obd_uuid;
9085         int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
9086         __u32 valid = QC_GENERAL, idx = 0;
9087         bool human_readable = false;
9088         bool show_default = false;
9089         int qtype;
9090         bool show_pools = false;
9091         struct option long_opts[] = {
9092         { .val = LFS_POOL_OPT, .name = "pool", .has_arg = optional_argument },
9093         { .name = NULL } };
9094         char **poollist = NULL;
9095         char *buf = NULL;
9096         int poolcount, i;
9097
9098         qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1);
9099         if (!qctl)
9100                 return -ENOMEM;
9101
9102         qctl->qc_cmd = LUSTRE_Q_GETQUOTA;
9103         qctl->qc_type = ALLQUOTA;
9104         obd_uuid = (char *)qctl->obd_uuid.uuid;
9105
9106         while ((c = getopt_long(argc, argv, "gGi:I:o:pPqtuUvh",
9107                 long_opts, NULL)) != -1) {
9108                 switch (c) {
9109                 case 'U':
9110                         show_default = true;
9111                 case 'u':
9112                         qtype = USRQUOTA;
9113                         goto quota_type;
9114                 case 'G':
9115                         show_default = true;
9116                 case 'g':
9117                         qtype = GRPQUOTA;
9118                         goto quota_type;
9119                 case 'P':
9120                         show_default = true;
9121                 case 'p':
9122                         qtype = PRJQUOTA;
9123 quota_type:
9124                         if (qctl->qc_type != ALLQUOTA) {
9125                                 fprintf(stderr,
9126                                         "%s quota: only one of -u, -g, or -p may be specified\n",
9127                                         progname);
9128                                 rc = CMD_HELP;
9129                                 goto out;
9130                         }
9131                         qctl->qc_type = qtype;
9132                         break;
9133                 case 't':
9134                         qctl->qc_cmd = LUSTRE_Q_GETINFO;
9135                         break;
9136                 case 'o':
9137                         valid = qctl->qc_valid = QC_UUID;
9138                         snprintf(obd_uuid, sizeof(*obd_uuid), "%s", optarg);
9139                         break;
9140                 case 'i':
9141                         valid = qctl->qc_valid = QC_MDTIDX;
9142                         idx = qctl->qc_idx = atoi(optarg);
9143                         if (idx == 0 && *optarg != '0') {
9144                                 fprintf(stderr,
9145                                         "%s quota: invalid MDT index '%s'\n",
9146                                         progname, optarg);
9147                                 rc = CMD_HELP;
9148                                 goto out;
9149                         }
9150                         break;
9151                 case 'I':
9152                         valid = qctl->qc_valid = QC_OSTIDX;
9153                         idx = qctl->qc_idx = atoi(optarg);
9154                         if (idx == 0 && *optarg != '0') {
9155                                 fprintf(stderr,
9156                                         "%s quota: invalid OST index '%s'\n",
9157                                         progname, optarg);
9158                                 rc = CMD_HELP;
9159                                 goto out;
9160                         }
9161                         break;
9162                 case 'v':
9163                         verbose = 1;
9164                         break;
9165                 case 'q':
9166                         quiet = 1;
9167                         break;
9168                 case 'h':
9169                         human_readable = true;
9170                         break;
9171                 case LFS_POOL_OPT:
9172                         if ((!optarg) && (argv[optind] != NULL) &&
9173                                 (argv[optind][0] != '-') &&
9174                                 (argv[optind][0] != '/')) {
9175                                 optarg = argv[optind++];
9176                                 if (lfs_verify_poolarg(optarg)) {
9177                                         rc = -EINVAL;
9178                                         goto out;
9179                                 }
9180                                 strncpy(qctl->qc_poolname, optarg,
9181                                         LOV_MAXPOOLNAME);
9182                                 if (qctl->qc_cmd == LUSTRE_Q_GETINFO)
9183                                         qctl->qc_cmd = LUSTRE_Q_GETINFOPOOL;
9184                                 else
9185                                         qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
9186                                 break;
9187                         }
9188
9189                         /* optarg is NULL */
9190                         show_pools = true;
9191                         qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
9192                         break;
9193                 default:
9194                         fprintf(stderr, "%s quota: unrecognized option '%s'\n",
9195                                 progname, argv[optind - 1]);
9196                         rc = CMD_HELP;
9197                         goto out;
9198                 }
9199         }
9200
9201         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
9202         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
9203              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
9204              qctl->qc_type == ALLQUOTA &&
9205              optind == argc - 1 && !show_default) {
9206                 qctl->qc_idx = idx;
9207
9208                 for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) {
9209                         qctl->qc_type = qtype;
9210                         qctl->qc_valid = valid;
9211                         if (qtype == USRQUOTA) {
9212                                 qctl->qc_id = geteuid();
9213                                 rc = uid2name(&name, qctl->qc_id);
9214                         } else {
9215                                 qctl->qc_id = getegid();
9216                                 rc = gid2name(&name, qctl->qc_id);
9217                                 memset(&qctl->qc_dqblk, 0,
9218                                        sizeof(qctl->qc_dqblk));
9219                         }
9220                         if (rc)
9221                                 name = "<unknown>";
9222                         mnt = argv[optind];
9223                         rc1 = get_print_quota(mnt, name, qctl, verbose, quiet,
9224                                               human_readable, show_default);
9225                         if (rc1 && !rc)
9226                                 rc = rc1;
9227                 }
9228                 goto out;
9229         /* lfs quota -u username /path/to/lustre/mount */
9230         } else if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
9231                    qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
9232                 /* options should be followed by u/g-name and mntpoint */
9233                 if ((!show_default && optind + 2 != argc) ||
9234                     (show_default && optind + 1 != argc) ||
9235                     qctl->qc_type == ALLQUOTA) {
9236                         fprintf(stderr,
9237                                 "%s quota: name and mount point must be specified\n",
9238                                 progname);
9239                         rc = CMD_HELP;
9240                         goto out;
9241                 }
9242
9243                 if (!show_default) {
9244                         name = argv[optind++];
9245                         switch (qctl->qc_type) {
9246                         case USRQUOTA:
9247                                 rc = name2uid(&qctl->qc_id, name);
9248                                 break;
9249                         case GRPQUOTA:
9250                                 rc = name2gid(&qctl->qc_id, name);
9251                                 break;
9252                         case PRJQUOTA:
9253                                 rc = name2projid(&qctl->qc_id, name);
9254                                 break;
9255                         default:
9256                                 rc = -ENOTSUP;
9257                                 break;
9258                         }
9259                 } else {
9260                         qctl->qc_valid = QC_GENERAL;
9261                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ?
9262                                         LUSTRE_Q_GETDEFAULT_POOL :
9263                                         LUSTRE_Q_GETDEFAULT;
9264                         qctl->qc_id = 0;
9265                 }
9266
9267                 if (rc) {
9268                         if (str2quotaid(&qctl->qc_id, name)) {
9269                                 fprintf(stderr, "%s quota: invalid id '%s'\n",
9270                                         progname, name);
9271                                 rc = CMD_HELP;
9272                                 goto out;
9273                         }
9274                 }
9275         } else if (optind + 1 != argc || qctl->qc_type == ALLQUOTA) {
9276                 fprintf(stderr, "%s quota: missing quota info argument(s)\n",
9277                         progname);
9278                 rc = CMD_HELP;
9279                 goto out;
9280         }
9281
9282         mnt = argv[optind];
9283         if (show_pools) {
9284                 char *p;
9285
9286                 i = 0;
9287                 rc = llapi_get_poolbuf(mnt, &buf, &poollist, &poolcount);
9288                 if (rc)
9289                         goto out;
9290
9291                 for (i = 0; i < poolcount; i++) {
9292                         p = memchr(poollist[i], '.', MAXNAMLEN);
9293                         if (!p) {
9294                                 fprintf(stderr, "bad string format %.*s\n",
9295                                         MAXNAMLEN, poollist[i]);
9296                                 rc = -EINVAL;
9297                                 goto out;
9298                         }
9299                         p++;
9300                         printf("Quotas for pool: %s\n", p);
9301                         strncpy(qctl->qc_poolname, p, LOV_MAXPOOLNAME);
9302                         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
9303                                              human_readable, show_default);
9304                         if (rc)
9305                                 break;
9306                 }
9307                 goto out;
9308         }
9309
9310         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
9311                              human_readable, show_default);
9312 out:
9313         free(buf);
9314         free(qctl);
9315         return rc;
9316 }
9317 #endif /* HAVE_SYS_QUOTA_H! */
9318
9319 static int flushctx_ioctl(char *mp)
9320 {
9321         int fd, rc;
9322
9323         fd = open(mp, O_RDONLY);
9324         if (fd == -1) {
9325                 fprintf(stderr, "flushctx: error open %s: %s\n",
9326                         mp, strerror(errno));
9327                 return -1;
9328         }
9329
9330         rc = ioctl(fd, LL_IOC_FLUSHCTX);
9331         if (rc == -1)
9332                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
9333                         mp, strerror(errno));
9334
9335         close(fd);
9336         return rc;
9337 }
9338
9339 static int lfs_flushctx(int argc, char **argv)
9340 {
9341         int     kdestroy = 0, reap = 0, c;
9342         char    mntdir[PATH_MAX] = {'\0'};
9343         int     index = 0;
9344         int     rc = 0;
9345
9346         while ((c = getopt(argc, argv, "kr")) != -1) {
9347                 switch (c) {
9348                 case 'k':
9349                         kdestroy = 1;
9350                         break;
9351                 case 'r':
9352                         reap = 1;
9353                         break;
9354                 default:
9355                         fprintf(stderr,
9356                                 "error: %s: option '-%c' unrecognized\n",
9357                                 argv[0], c);
9358                         return CMD_HELP;
9359                 }
9360         }
9361
9362         if (kdestroy) {
9363                 rc = system("kdestroy > /dev/null");
9364                 if (rc) {
9365                         rc = WEXITSTATUS(rc);
9366                         fprintf(stderr,
9367                                 "error destroying tickets: %d, continuing\n",
9368                                 rc);
9369                 }
9370         }
9371
9372         if (optind >= argc) {
9373                 /* flush for all mounted lustre fs. */
9374                 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
9375                         /* Check if we have a mount point */
9376                         if (mntdir[0] == '\0')
9377                                 continue;
9378
9379                         if (flushctx_ioctl(mntdir))
9380                                 rc = -1;
9381
9382                         mntdir[0] = '\0'; /* avoid matching in next loop */
9383                 }
9384         } else {
9385                 /* flush fs as specified */
9386                 while (optind < argc) {
9387                         if (flushctx_ioctl(argv[optind++]))
9388                                 rc = -1;
9389                 }
9390         }
9391
9392         if (reap) {
9393                 rc = system("keyctl reap > /dev/null");
9394                 if (rc != 0) {
9395                         rc = WEXITSTATUS(rc);
9396                         fprintf(stderr, "error reaping keyring: %d\n", rc);
9397                 }
9398         }
9399
9400         return rc;
9401 }
9402
9403 static int lfs_changelog(int argc, char **argv)
9404 {
9405         void *changelog_priv;
9406         struct changelog_rec *rec;
9407         long long startrec = 0, endrec = 0;
9408         char *mdd;
9409         struct option long_opts[] = {
9410                 { .val = 'f', .name = "follow", .has_arg = no_argument },
9411                 { .name = NULL } };
9412         char short_opts[] = "f";
9413         int rc, follow = 0;
9414
9415         while ((rc = getopt_long(argc, argv, short_opts,
9416                 long_opts, NULL)) != -1) {
9417                 switch (rc) {
9418                 case 'f':
9419                         follow++;
9420                         break;
9421                 default:
9422                         fprintf(stderr,
9423                                 "%s changelog: unrecognized option '%s'\n",
9424                                 progname, argv[optind - 1]);
9425                         return CMD_HELP;
9426                 }
9427         }
9428         if (optind >= argc) {
9429                 fprintf(stderr, "%s changelog: mdtname must be specified\n",
9430                         progname);
9431                 return CMD_HELP;
9432         }
9433
9434         mdd = argv[optind++];
9435         if (argc > optind) {
9436                 errno = 0;
9437                 startrec = strtoll(argv[optind++], NULL, 10);
9438                 if (errno != 0 || startrec < 0) {
9439                         fprintf(stderr,
9440                                 "%s changelog: bad startrec\n",
9441                                 progname);
9442                         return CMD_HELP;
9443                 }
9444         }
9445
9446         if (argc > optind) {
9447                 errno = 0;
9448                 endrec = strtoll(argv[optind++], NULL, 10);
9449                 if (errno != 0 || endrec < 0) {
9450                         fprintf(stderr,
9451                                 "%s changelog: bad endrec\n",
9452                                 progname);
9453                         return CMD_HELP;
9454                 }
9455         }
9456
9457         rc = llapi_changelog_start(&changelog_priv,
9458                                    CHANGELOG_FLAG_BLOCK |
9459                                    CHANGELOG_FLAG_JOBID |
9460                                    CHANGELOG_FLAG_EXTRA_FLAGS |
9461                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
9462                                    mdd, startrec);
9463         if (rc < 0) {
9464                 fprintf(stderr, "%s changelog: cannot start changelog: %s\n",
9465                         progname, strerror(errno = -rc));
9466                 return rc;
9467         }
9468
9469         rc = llapi_changelog_set_xflags(changelog_priv,
9470                                         CHANGELOG_EXTRA_FLAG_UIDGID |
9471                                         CHANGELOG_EXTRA_FLAG_NID |
9472                                         CHANGELOG_EXTRA_FLAG_OMODE |
9473                                         CHANGELOG_EXTRA_FLAG_XATTR);
9474         if (rc < 0) {
9475                 fprintf(stderr,
9476                         "%s changelog: cannot set xflags for changelog: %s\n",
9477                         progname, strerror(errno = -rc));
9478                 return rc;
9479         }
9480
9481         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
9482                 time_t secs;
9483                 struct tm ts;
9484
9485                 if (endrec && rec->cr_index > endrec) {
9486                         llapi_changelog_free(&rec);
9487                         break;
9488                 }
9489                 if (rec->cr_index < startrec) {
9490                         llapi_changelog_free(&rec);
9491                         continue;
9492                 }
9493
9494                 secs = rec->cr_time >> 30;
9495                 gmtime_r(&secs, &ts);
9496                 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
9497                        "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
9498                        changelog_type2str(rec->cr_type),
9499                        ts.tm_hour, ts.tm_min, ts.tm_sec,
9500                        (int)(rec->cr_time & ((1 << 30) - 1)),
9501                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
9502                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
9503
9504                 if (rec->cr_flags & CLF_JOBID) {
9505                         struct changelog_ext_jobid *jid =
9506                                 changelog_rec_jobid(rec);
9507
9508                         if (jid->cr_jobid[0] != '\0')
9509                                 printf(" j=%s", jid->cr_jobid);
9510                 }
9511
9512                 if (rec->cr_flags & CLF_EXTRA_FLAGS) {
9513                         struct changelog_ext_extra_flags *ef =
9514                                 changelog_rec_extra_flags(rec);
9515
9516                         printf(" ef=0x%llx",
9517                                (unsigned long long)ef->cr_extra_flags);
9518
9519                         if (ef->cr_extra_flags & CLFE_UIDGID) {
9520                                 struct changelog_ext_uidgid *uidgid =
9521                                         changelog_rec_uidgid(rec);
9522
9523                                 printf(" u=%llu:%llu",
9524                                        (unsigned long long)uidgid->cr_uid,
9525                                        (unsigned long long)uidgid->cr_gid);
9526                         }
9527                         if (ef->cr_extra_flags & CLFE_NID) {
9528                                 struct changelog_ext_nid *nid =
9529                                         changelog_rec_nid(rec);
9530
9531                                 printf(" nid=%s",
9532                                        libcfs_nid2str(nid->cr_nid));
9533                         }
9534
9535                         if (ef->cr_extra_flags & CLFE_OPEN) {
9536                                 struct changelog_ext_openmode *omd =
9537                                         changelog_rec_openmode(rec);
9538                                 char mode[] = "---";
9539
9540                                 /* exec mode must be exclusive */
9541                                 if (omd->cr_openflags & MDS_FMODE_EXEC) {
9542                                         mode[2] = 'x';
9543                                 } else {
9544                                         if (omd->cr_openflags & MDS_FMODE_READ)
9545                                                 mode[0] = 'r';
9546                                         if (omd->cr_openflags &
9547                                             (MDS_FMODE_WRITE |
9548                                              MDS_OPEN_TRUNC |
9549                                              MDS_OPEN_APPEND))
9550                                                 mode[1] = 'w';
9551                                 }
9552
9553                                 if (strcmp(mode, "---") != 0)
9554                                         printf(" m=%s", mode);
9555                         }
9556
9557                         if (ef->cr_extra_flags & CLFE_XATTR) {
9558                                 struct changelog_ext_xattr *xattr =
9559                                         changelog_rec_xattr(rec);
9560
9561                                 if (xattr->cr_xattr[0] != '\0')
9562                                         printf(" x=%s", xattr->cr_xattr);
9563                         }
9564                 }
9565
9566                 if (!fid_is_zero(&rec->cr_pfid))
9567                         printf(" p="DFID, PFID(&rec->cr_pfid));
9568                 if (rec->cr_namelen)
9569                         printf(" %.*s", rec->cr_namelen,
9570                                changelog_rec_name(rec));
9571
9572                 if (rec->cr_flags & CLF_RENAME) {
9573                         struct changelog_ext_rename *rnm =
9574                                 changelog_rec_rename(rec);
9575
9576                         if (!fid_is_zero(&rnm->cr_sfid))
9577                                 printf(" s="DFID" sp="DFID" %.*s",
9578                                        PFID(&rnm->cr_sfid),
9579                                        PFID(&rnm->cr_spfid),
9580                                        (int)changelog_rec_snamelen(rec),
9581                                        changelog_rec_sname(rec));
9582                 }
9583                 printf("\n");
9584
9585                 llapi_changelog_free(&rec);
9586         }
9587
9588         llapi_changelog_fini(&changelog_priv);
9589
9590         if (rc < 0)
9591                 fprintf(stderr, "%s changelog: cannot access changelog: %s\n",
9592                         progname, strerror(errno = -rc));
9593
9594         return (rc == 1 ? 0 : rc);
9595 }
9596
9597 static int lfs_changelog_clear(int argc, char **argv)
9598 {
9599         long long endrec;
9600         int rc;
9601
9602         if (argc != 4)
9603                 return CMD_HELP;
9604
9605         errno = 0;
9606         endrec = strtoll(argv[3], NULL, 10);
9607         if (errno != 0 || endrec < 0) {
9608                 fprintf(stderr,
9609                         "%s: bad endrec '%s'\n",
9610                         argv[0], argv[3]);
9611                 return CMD_HELP;
9612         }
9613
9614         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
9615
9616         if (rc == -EINVAL)
9617                 fprintf(stderr, "%s: record out of range: %llu\n",
9618                         argv[0], endrec);
9619         else if (rc == -ENOENT)
9620                 fprintf(stderr, "%s: no changelog user: %s\n",
9621                         argv[0], argv[2]);
9622         else if (rc)
9623                 fprintf(stderr, "%s error: %s\n", argv[0],
9624                         strerror(-rc));
9625
9626         if (rc)
9627                 errno = -rc;
9628
9629         return rc;
9630 }
9631
9632 static void rstripc(char *str, int c)
9633 {
9634         char *end = str + strlen(str);
9635
9636         for (; str < end && end[-1] == c; --end)
9637                 end[-1] = '\0';
9638 }
9639
9640 static int lfs_fid2path(int argc, char **argv)
9641 {
9642         struct option long_opts[] = {
9643                 { .val = 'c',   .name = "cur",  .has_arg = no_argument },
9644                 { .val = 'c',   .name = "current",      .has_arg = no_argument },
9645                 { .val = 'c',   .name = "print-link",   .has_arg = no_argument },
9646                 { .val = 'f',   .name = "print-fid",    .has_arg = no_argument },
9647                 { .val = 'l',   .name = "link", .has_arg = required_argument },
9648                 { .name = NULL } };
9649         char short_opts[] = "cfl:pr:";
9650         bool print_link = false;
9651         bool print_fid = false;
9652         bool print_mnt_dir;
9653         char mnt_dir[PATH_MAX] = "";
9654         int mnt_fd = -1;
9655         char *path_or_fsname;
9656         long long recno = -1;
9657         int linkno = -1;
9658         char *endptr = NULL;
9659         int rc = 0;
9660         int c;
9661         int i;
9662
9663         while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
9664                 switch (c) {
9665                 case 'c':
9666                         print_link = true;
9667                         break;
9668                 case 'f':
9669                         print_fid = true;
9670                         break;
9671                 case 'l':
9672                         errno = 0;
9673                         linkno = strtol(optarg, &endptr, 10);
9674                         if (errno != 0 || *endptr != '\0' || linkno < 0) {
9675                                 fprintf(stderr,
9676                                         "%s fid2path: invalid linkno '%s'\n",
9677                                         progname, optarg);
9678                                 return CMD_HELP;
9679                         }
9680                         break;
9681                 case 'r':
9682                         /* recno is something to do with changelogs
9683                          * that was never implemented. We just pass it
9684                          * through for the MDT to ignore.
9685                          */
9686                         errno = 0;
9687                         recno = strtoll(optarg, &endptr, 10);
9688                         if (errno != 0 || *endptr != '\0' || recno < 0) {
9689                                 fprintf(stderr,
9690                                         "%s fid2path: invalid recno '%s'\n",
9691                                         progname, optarg);
9692                                 return CMD_HELP;
9693                         }
9694                         break;
9695                 default:
9696                         fprintf(stderr,
9697                                 "%s fid2path: unrecognized option '%s'\n",
9698                                 progname, argv[optind - 1]);
9699                         return CMD_HELP;
9700                 }
9701         }
9702
9703         if (argc - optind < 2) {
9704                 fprintf(stderr,
9705                         "Usage: %s fid2path FSNAME|ROOT FID...\n",
9706                         progname);
9707                 return CMD_HELP;
9708         }
9709
9710         path_or_fsname = argv[optind];
9711
9712         if (*path_or_fsname == '/') {
9713                 print_mnt_dir = true;
9714                 rc = llapi_search_mounts(path_or_fsname, 0, mnt_dir, NULL);
9715         } else {
9716                 print_mnt_dir = false;
9717                 rc = llapi_search_rootpath(mnt_dir, path_or_fsname);
9718         }
9719
9720         if (rc < 0) {
9721                 fprintf(stderr,
9722                         "%s fid2path: cannot resolve mount point for '%s': %s\n",
9723                         progname, path_or_fsname, strerror(-rc));
9724                 goto out;
9725         }
9726
9727         mnt_fd = open(mnt_dir, O_RDONLY | O_DIRECTORY);
9728         if (mnt_fd < 0) {
9729                 fprintf(stderr,
9730                         "%s fid2path: cannot open mount point for '%s': %s\n",
9731                         progname, path_or_fsname, strerror(-rc));
9732                 goto out;
9733         }
9734
9735         /* Strip trailing slashes from mnt_dir. */
9736         rstripc(mnt_dir + 1, '/');
9737
9738         for (i = optind + 1; i < argc; i++) {
9739                 const char *fid_str = argv[i];
9740                 struct lu_fid fid;
9741                 int rc2;
9742
9743                 rc2 = llapi_fid_parse(fid_str, &fid, NULL);
9744                 if (rc2 < 0) {
9745                         fprintf(stderr,
9746                                 "%s fid2path: invalid FID '%s'\n",
9747                                 progname, fid_str);
9748                         if (rc == 0)
9749                                 rc = rc2;
9750
9751                         continue;
9752                 }
9753
9754                 int linktmp = (linkno >= 0) ? linkno : 0;
9755                 while (1) {
9756                         int oldtmp = linktmp;
9757                         long long rectmp = recno;
9758                         char path_buf[PATH_MAX];
9759
9760                         rc2 = llapi_fid2path_at(mnt_fd, &fid,
9761                                 path_buf, sizeof(path_buf), &rectmp, &linktmp);
9762                         if (rc2 < 0) {
9763                                 fprintf(stderr,
9764                                         "%s fid2path: cannot find %s %s: %s\n",
9765                                         progname, path_or_fsname, fid_str,
9766                                         strerror(-rc2));
9767                                 if (rc == 0)
9768                                         rc = rc2;
9769                                 break;
9770                         }
9771
9772                         if (print_fid)
9773                                 printf("%s ", fid_str);
9774
9775                         if (print_link)
9776                                 printf("%d ", linktmp);
9777
9778                         /* You may think this looks wrong or weird (and it is!)
9779                          * but we are actually trying to preserve the old quirky
9780                          * behaviors (enforced by our old quirky tests!) that
9781                          * make lfs so much fun to work on:
9782                          *
9783                          *   lustre 0x200000007:0x1:0x0 => "/"
9784                          *   /mnt/lustre 0x200000007:0x1:0x0 => "/mnt/lustre//"
9785                          *
9786                          * Note that llapi_fid2path() returns "" for the root
9787                          * FID. */
9788
9789                         printf("%s%s%s\n",
9790                                print_mnt_dir ? mnt_dir : "",
9791                                (print_mnt_dir || *path_buf == '\0') ? "/" : "",
9792                                path_buf);
9793
9794                         if (linkno >= 0)
9795                                 /* specified linkno */
9796                                 break;
9797
9798                         if (oldtmp == linktmp)
9799                                 /* no more links */
9800                                 break;
9801                 }
9802         }
9803 out:
9804         if (!(mnt_fd < 0))
9805                 close(mnt_fd);
9806
9807         return rc;
9808 }
9809
9810 static int lfs_path2fid(int argc, char **argv)
9811 {
9812         struct option long_opts[] = {
9813                 { .val = 'p', .name = "parents", .has_arg = no_argument },
9814                 { .name = NULL } };
9815         char            **path;
9816         const char        short_opts[] = "p";
9817         const char       *sep = "";
9818         struct lu_fid     fid;
9819         int               rc = 0;
9820         bool              show_parents = false;
9821
9822         while ((rc = getopt_long(argc, argv, short_opts,
9823                                  long_opts, NULL)) != -1) {
9824                 switch (rc) {
9825                 case 'p':
9826                         show_parents = true;
9827                         break;
9828                 default:
9829                         fprintf(stderr,
9830                                 "%s path2fid: unrecognized option '%s'\n",
9831                                 progname, argv[optind - 1]);
9832                         return CMD_HELP;
9833                 }
9834         }
9835
9836         if (optind > argc - 1) {
9837                 fprintf(stderr, "%s path2fid: FILE... must be specified\n",
9838                         progname);
9839                 return CMD_HELP;
9840         } else if (optind < argc - 1) {
9841                 sep = ": ";
9842         }
9843
9844         rc = 0;
9845         for (path = argv + optind; optind < argc; path++, optind++) {
9846                 int err = 0;
9847
9848                 if (!show_parents) {
9849                         err = llapi_path2fid(*path, &fid);
9850                         if (!err)
9851                                 printf("%s%s"DFID"\n",
9852                                        *sep != '\0' ? *path : "", sep,
9853                                        PFID(&fid));
9854                 } else {
9855                         char            name[NAME_MAX + 1];
9856                         unsigned int    linkno = 0;
9857
9858                         while ((err = llapi_path2parent(*path, linkno, &fid,
9859                                                 name, sizeof(name))) == 0) {
9860                                 if (*sep != '\0' && linkno == 0)
9861                                         printf("%s%s", *path, sep);
9862
9863                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
9864                                        PFID(&fid), name);
9865                                 linkno++;
9866                         }
9867
9868                         /* err == -ENODATA is end-of-loop */
9869                         if (linkno > 0 && err == -ENODATA) {
9870                                 printf("\n");
9871                                 err = 0;
9872                         }
9873                 }
9874
9875                 if (err) {
9876                         fprintf(stderr,
9877                                 "%s path2fid: cannot get %sfid for '%s': %s\n",
9878                                 progname, show_parents ? "parent " : "", *path,
9879                                 strerror(-err));
9880                         if (rc == 0) {
9881                                 rc = err;
9882                                 errno = -err;
9883                         }
9884                 }
9885         }
9886
9887         return rc;
9888 }
9889
9890 #define MAX_ERRNO       4095
9891 #define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO)
9892
9893 static int lfs_rmfid_and_show_errors(int rootfd, struct fid_array *fa)
9894 {
9895         int rc, rc2, k;
9896
9897         rc = llapi_rmfid_at(rootfd, fa);
9898         if (rc < 0) {
9899                 fprintf(stderr, "%s rmfid: cannot remove FIDs: %s\n",
9900                         progname, strerror(-rc));
9901                 return rc;
9902         }
9903
9904         for (k = 0; k < fa->fa_nr; k++) {
9905                 rc2 = (__s32)fa->fa_fids[k].f_ver;
9906                 if (!IS_ERR_VALUE(rc2))
9907                         continue;
9908
9909                 if (rc == 0)
9910                         rc = rc2;
9911
9912                 fa->fa_fids[k].f_ver = 0;
9913                 fprintf(stderr, "%s rmfid: cannot remove "DFID": %s\n",
9914                         progname, PFID(&fa->fa_fids[k]), strerror(-rc2));
9915         }
9916
9917         return rc;
9918 }
9919
9920 static int lfs_rmfid(int argc, char **argv)
9921 {
9922         char *fidstr, *device;
9923         int rc = 0, rc2, rc3 = 0, nr;
9924         struct fid_array *fa;
9925         int rootfd;
9926
9927         /* Interactive mode: Adjust optind */
9928         if (!optind)
9929                 optind++;
9930
9931         device = argv[optind++];
9932
9933         if (optind > argc - 1) {
9934                 fprintf(stderr, "%s rmfid: missing dirname\n", progname);
9935                 return CMD_HELP;
9936         }
9937
9938         nr = argc - optind;
9939
9940         rc = llapi_root_path_open(device, &rootfd);
9941         if (rc < 0) {
9942                 fprintf(stderr,
9943                         "%s rmfid: error opening device/fsname '%s': %s\n",
9944                         progname, device, strerror(-rc));
9945                 return -rc;
9946         }
9947
9948         fa = malloc(offsetof(struct fid_array, fa_fids[nr + 1]));
9949         if (!fa) {
9950                 fprintf(stderr, "%s rmfid: error allocating %zd bytes: %s\n",
9951                         progname, offsetof(struct fid_array, fa_fids[nr + 1]),
9952                         strerror(errno));
9953                 return -ENOMEM;
9954         }
9955
9956         fa->fa_nr = 0;
9957         rc = 0;
9958         while (optind < argc) {
9959                 char *origfidstr;
9960                 int found;
9961
9962                 origfidstr = fidstr = argv[optind++];
9963                 while (*fidstr == '[')
9964                         fidstr++;
9965                 found = sscanf(fidstr, SFID, RFID(&fa->fa_fids[fa->fa_nr]));
9966                 if (found != 3) {
9967                         fprintf(stderr, "lfs rmfid: '%s': Wrong FID format\n",
9968                                 origfidstr);
9969                         if (!rc3)
9970                                 rc3 = -EINVAL; /* Invalid argument */
9971                         continue;
9972                 }
9973                 fa->fa_nr++;
9974                 if (fa->fa_nr == OBD_MAX_FIDS_IN_ARRAY) {
9975                         /* start another batch */
9976                         rc2 = lfs_rmfid_and_show_errors(rootfd, fa);
9977                         if (rc2 && !rc)
9978                                 rc = rc2;
9979                         if (rc3)
9980                                 rc = rc3;
9981                         fa->fa_nr = 0;
9982                 }
9983         }
9984         if (fa->fa_nr) {
9985                 rc2 = lfs_rmfid_and_show_errors(rootfd, fa);
9986                 if (rc2 && !rc)
9987                         rc = rc2;
9988                 if (rc3)
9989                         rc = rc3;
9990         }
9991
9992         if (fa) {
9993                 free(fa);
9994                 fa = NULL;
9995         }
9996
9997         close(rootfd);
9998         return rc;
9999 }
10000
10001 static int lfs_data_version(int argc, char **argv)
10002 {
10003         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
10004         __u64 data_version;
10005         char *path;
10006         int fd;
10007         int rc;
10008         int c;
10009
10010         if (argc < 2) {
10011                 fprintf(stderr, "%s: FILE must be specified\n",
10012                         progname);
10013                 return CMD_HELP;
10014         }
10015
10016         while ((c = getopt(argc, argv, "hnrw")) != -1) {
10017                 switch (c) {
10018                 case 'n':
10019                         data_version_flags = 0;
10020                         break;
10021                 case 'r':
10022                         data_version_flags |= LL_DV_RD_FLUSH;
10023                         break;
10024                 case 'w':
10025                         data_version_flags |= LL_DV_WR_FLUSH;
10026                         break;
10027                 default:
10028                         fprintf(stderr,
10029                                 "%s data_version: unrecognized option '%s'\n",
10030                                 progname, argv[optind - 1]);
10031                         fallthrough;
10032                 case 'h':
10033                         return CMD_HELP;
10034                 }
10035         }
10036         if (optind == argc) {
10037                 fprintf(stderr, "%s data_version: FILE must be specified\n",
10038                         progname);
10039                 return CMD_HELP;
10040         }
10041
10042         path = argv[optind];
10043         fd = open(path, O_RDONLY);
10044         if (fd < 0) {
10045                 rc = -errno;
10046                 fprintf(stderr, "%s data_version: cannot open file '%s': %s\n",
10047                         progname, path, strerror(-rc));
10048                 return rc;
10049         }
10050
10051         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
10052         if (rc < 0)
10053                 fprintf(stderr,
10054                         "%s data_version: cannot get version for '%s': %s\n",
10055                         progname, path, strerror(-rc));
10056         else
10057                 printf("%ju" "\n", (uintmax_t)data_version);
10058
10059         close(fd);
10060         return rc;
10061 }
10062
10063 static int lfs_hsm_state(int argc, char **argv)
10064 {
10065         int rc = 0;
10066         int i = 1;
10067         char *path;
10068         struct hsm_user_state hus;
10069
10070         if (argc < 2)
10071                 return CMD_HELP;
10072
10073         do {
10074                 int rc2;
10075                 path = argv[i];
10076
10077                 rc2 = llapi_hsm_state_get(path, &hus);
10078                 if (rc2) {
10079                         fprintf(stderr,
10080                                 "%s %s: get HSM state for '%s' failed: %s\n",
10081                                 progname, argv[0], path, strerror(-rc2));
10082                         if (!rc)
10083                                 rc = rc2;
10084                         continue;
10085                 }
10086
10087                 /* Display path name and status flags */
10088                 printf("%s: (0x%08x)", path, hus.hus_states);
10089
10090                 if (hus.hus_states & HS_RELEASED)
10091                         printf(" released");
10092                 if (hus.hus_states & HS_EXISTS)
10093                         printf(" exists");
10094                 if (hus.hus_states & HS_DIRTY)
10095                         printf(" dirty");
10096                 if (hus.hus_states & HS_ARCHIVED)
10097                         printf(" archived");
10098                 /* Display user-settable flags */
10099                 if (hus.hus_states & HS_NORELEASE)
10100                         printf(" never_release");
10101                 if (hus.hus_states & HS_NOARCHIVE)
10102                         printf(" never_archive");
10103                 if (hus.hus_states & HS_LOST)
10104                         printf(" lost_from_hsm");
10105
10106                 if (hus.hus_archive_id != 0)
10107                         printf(", archive_id:%d", hus.hus_archive_id);
10108                 printf("\n");
10109
10110         } while (++i < argc);
10111
10112         return rc;
10113 }
10114
10115 #define LFS_HSM_SET   0
10116 #define LFS_HSM_CLEAR 1
10117
10118 /**
10119  * Generic function to set or clear HSM flags.
10120  * Used by hsm_set and hsm_clear.
10121  *
10122  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
10123  */
10124 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
10125 {
10126         struct option long_opts[] = {
10127         { .val = 'A',   .name = "archived",     .has_arg = no_argument },
10128         { .val = 'a',   .name = "noarchive",    .has_arg = no_argument },
10129         { .val = 'd',   .name = "dirty",        .has_arg = no_argument },
10130         { .val = 'e',   .name = "exists",       .has_arg = no_argument },
10131         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10132         { .val = 'i',   .name = "archive-id",   .has_arg = required_argument },
10133         { .val = 'l',   .name = "lost",         .has_arg = no_argument },
10134         { .val = 'r',   .name = "norelease",    .has_arg = no_argument },
10135         { .name = NULL } };
10136         __u64 mask = 0;
10137         int c, rc = 0;
10138         char *path;
10139         __u32 archive_id = 0;
10140         char *end = NULL;
10141
10142         if (argc < 3)
10143                 return CMD_HELP;
10144
10145         while ((c = getopt_long(argc, argv, "aAdehi:lr",
10146                                 long_opts, NULL)) != -1) {
10147                 switch (c) {
10148                 case 'l':
10149                         mask |= HS_LOST;
10150                         break;
10151                 case 'a':
10152                         mask |= HS_NOARCHIVE;
10153                         break;
10154                 case 'A':
10155                         mask |= HS_ARCHIVED;
10156                         break;
10157                 case 'r':
10158                         mask |= HS_NORELEASE;
10159                         break;
10160                 case 'd':
10161                         mask |= HS_DIRTY;
10162                         break;
10163                 case 'e':
10164                         mask |= HS_EXISTS;
10165                         break;
10166                 case 'i':
10167                         errno = 0;
10168                         archive_id = strtol(optarg, &end, 10);
10169                         if (errno != 0 || *end != '\0' || archive_id < 0) {
10170                                 fprintf(stderr,
10171                                         "%s: invalid archive_id: '%s'\n",
10172                                         progname, end);
10173                                 return CMD_HELP;
10174                         }
10175                         break;
10176                 default:
10177                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10178                                 progname, argv[optind - 1]);
10179                         fallthrough;
10180                 case 'h':
10181                         return CMD_HELP;
10182                 }
10183         }
10184
10185         /* User should have specified a flag */
10186         if (mask == 0)
10187                 return CMD_HELP;
10188
10189         while (optind < argc) {
10190                 int rc2;
10191                 path = argv[optind];
10192
10193                 /* If mode == 0, this means we apply the mask. */
10194                 if (mode == LFS_HSM_SET)
10195                         rc2 = llapi_hsm_state_set(path, mask, 0, archive_id);
10196                 else
10197                         rc2 = llapi_hsm_state_set(path, 0, mask, 0);
10198
10199                 if (rc2) {
10200                         fprintf(stderr,
10201                                 "%s %s: change hsm flags for '%s' failed: %s\n",
10202                                 progname, argv[0], path, strerror(-rc2));
10203                         if (!rc)
10204                                 rc = rc2;
10205                 }
10206                 optind++;
10207         }
10208
10209         return rc;
10210 }
10211
10212 static int lfs_hsm_action(int argc, char **argv)
10213 {
10214         struct hsm_current_action hca;
10215         struct hsm_extent he;
10216         enum hsm_user_action hua;
10217         enum hsm_progress_states hps;
10218         int rc = 0;
10219         int i = 1;
10220         char *path;
10221
10222         if (argc < 2)
10223                 return CMD_HELP;
10224
10225         do {
10226                 int rc2;
10227                 path = argv[i];
10228
10229                 rc2 = llapi_hsm_current_action(path, &hca);
10230                 if (rc2) {
10231                         fprintf(stderr,
10232                                 "%s %s: get hsm action for '%s' failed: %s\n",
10233                                 progname, argv[0], path, strerror(-rc2));
10234
10235                         if (!rc)
10236                                 rc = rc2;
10237                         continue;
10238                 }
10239                 he = hca.hca_location;
10240                 hua = hca.hca_action;
10241                 hps = hca.hca_state;
10242
10243                 printf("%s: %s", path, hsm_user_action2name(hua));
10244
10245                 /* Skip file without action */
10246                 if (hca.hca_action == HUA_NONE) {
10247                         printf("\n");
10248                         continue;
10249                 }
10250
10251                 printf(" %s ", hsm_progress_state2name(hps));
10252
10253                 if ((hps == HPS_RUNNING) &&
10254                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
10255                         printf("(%llu bytes moved)\n",
10256                                (unsigned long long)he.length);
10257                 else if ((he.offset + he.length) == LUSTRE_EOF)
10258                         printf("(from %llu to EOF)\n",
10259                                (unsigned long long)he.offset);
10260                 else
10261                         printf("(from %llu to %llu)\n",
10262                                (unsigned long long)he.offset,
10263                                (unsigned long long)(he.offset + he.length));
10264
10265         } while (++i < argc);
10266
10267         return rc;
10268 }
10269
10270 static int lfs_hsm_set(int argc, char **argv)
10271 {
10272         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
10273 }
10274
10275 static int lfs_hsm_clear(int argc, char **argv)
10276 {
10277         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
10278 }
10279
10280 /**
10281  * Check file state and return its fid, to be used by lfs_hsm_request().
10282  *
10283  * \param[in]     file      Path to file to check
10284  * \param[in,out] fid       Pointer to allocated lu_fid struct.
10285  * \param[in,out] last_dev  Pointer to last device id used.
10286  *
10287  * \return 0 on success.
10288  */
10289 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
10290                                 dev_t *last_dev)
10291 {
10292         struct stat     st;
10293         int             rc;
10294
10295         rc = lstat(file, &st);
10296         if (rc) {
10297                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
10298                 return -errno;
10299         }
10300         /*
10301          * Checking for regular file as archiving as posix copytool
10302          * rejects archiving files other than regular files
10303          */
10304         if (!S_ISREG(st.st_mode)) {
10305                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
10306                 return CMD_HELP;
10307         }
10308         /* A request should be ... */
10309         if (*last_dev != st.st_dev && *last_dev != 0) {
10310                 fprintf(stderr,
10311                         "All files should be on the same filesystem: %s\n",
10312                         file);
10313                 return -EINVAL;
10314         }
10315         *last_dev = st.st_dev;
10316
10317         rc = llapi_path2fid(file, fid);
10318         if (rc) {
10319                 fprintf(stderr, "Cannot read FID of %s: %s\n",
10320                         file, strerror(-rc));
10321                 return rc;
10322         }
10323         return 0;
10324 }
10325
10326 /* Fill an HSM HUR item with a given file name.
10327  *
10328  * If mntpath is set, then the filename is actually a FID, and no
10329  * lookup on the filesystem will be performed.
10330  *
10331  * \param[in]  hur         the user request to fill
10332  * \param[in]  idx         index of the item inside the HUR to fill
10333  * \param[in]  mntpath     mountpoint of Lustre
10334  * \param[in]  fname       filename (if mtnpath is NULL)
10335  *                         or FID (if mntpath is set)
10336  * \param[in]  last_dev    pointer to last device id used
10337  *
10338  * \retval 0 on success
10339  * \retval CMD_HELP or a negative errno on error
10340  */
10341 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
10342                          const char *mntpath, const char *fname,
10343                          dev_t *last_dev)
10344 {
10345         struct hsm_user_item *hui = &hur->hur_user_item[idx];
10346         int rc;
10347
10348         hui->hui_extent.length = -1;
10349
10350         if (mntpath) {
10351                 rc = llapi_fid_parse(fname, &hui->hui_fid, NULL);
10352                 if (rc)
10353                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
10354                                 fname);
10355         } else {
10356                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
10357         }
10358
10359         if (rc == 0)
10360                 hur->hur_request.hr_itemcount++;
10361
10362         return rc;
10363 }
10364
10365 static int lfs_hsm_request(int argc, char **argv, int action)
10366 {
10367         struct option long_opts[] = {
10368         { .val = 'a',   .name = "archive",      .has_arg = required_argument },
10369         { .val = 'D',   .name = "data",         .has_arg = required_argument },
10370         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10371         { .val = 'l',   .name = "filelist",     .has_arg = required_argument },
10372         { .val = 'm',   .name = "mntpath",      .has_arg = required_argument },
10373         { .name = NULL } };
10374         dev_t last_dev = 0;
10375         struct hsm_user_request *hur, *oldhur;
10376         int c, i;
10377         size_t len;
10378         int nbfile;
10379         char *line = NULL;
10380         char *filelist = NULL;
10381         char fullpath[PATH_MAX];
10382         char *opaque = NULL;
10383         int opaque_len = 0;
10384         int archive_id = 0;
10385         FILE *fp;
10386         int nbfile_alloc = 0;
10387         char *some_file = NULL;
10388         char *mntpath = NULL;
10389         int rc;
10390
10391         if (argc < 2)
10392                 return CMD_HELP;
10393
10394         while ((c = getopt_long(argc, argv, "a:D:hl:m:",
10395                                 long_opts, NULL)) != -1) {
10396                 switch (c) {
10397                 case 'l':
10398                         filelist = optarg;
10399                         break;
10400                 case 'D':
10401                         opaque = optarg;
10402                         break;
10403                 case 'a':
10404                         if (action != HUA_ARCHIVE &&
10405                             action != HUA_REMOVE) {
10406                                 fprintf(stderr,
10407                                         "error: -a is supported only when archiving or removing\n");
10408                                 return CMD_HELP;
10409                         }
10410                         archive_id = atoi(optarg);
10411                         break;
10412                 case 'm':
10413                         if (!some_file) {
10414                                 mntpath = optarg;
10415                                 some_file = strdup(optarg);
10416                         }
10417                         break;
10418                 default:
10419                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10420                                 progname, argv[optind - 1]);
10421                         fallthrough;
10422                 case 'h':
10423                         return CMD_HELP;
10424                 }
10425         }
10426
10427         /* All remaining args are files, so we have at least nbfile */
10428         nbfile = argc - optind;
10429
10430         if ((nbfile == 0) && (!filelist))
10431                 return CMD_HELP;
10432
10433         if (opaque)
10434                 opaque_len = strlen(opaque);
10435
10436         /*
10437          * Alloc the request structure with enough place to store all files
10438          * from command line.
10439          */
10440         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
10441         if (!hur) {
10442                 fprintf(stderr, "Cannot create the request: %s\n",
10443                         strerror(errno));
10444                 return errno;
10445         }
10446         nbfile_alloc = nbfile;
10447
10448         hur->hur_request.hr_action = action;
10449         hur->hur_request.hr_archive_id = archive_id;
10450         hur->hur_request.hr_flags = 0;
10451
10452         /* All remaining args are files, add them */
10453         if (nbfile != 0 && some_file == NULL)
10454                 some_file = strdup(argv[optind]);
10455
10456         for (i = 0; i < nbfile; i++) {
10457                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
10458                                    &last_dev);
10459                 if (rc)
10460                         goto out_free;
10461         }
10462
10463         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
10464
10465         /* If a filelist was specified, read the filelist from it. */
10466         if (filelist) {
10467                 fp = fopen(filelist, "r");
10468                 if (!fp) {
10469                         fprintf(stderr, "Cannot read the file list %s: %s\n",
10470                                 filelist, strerror(errno));
10471                         rc = -errno;
10472                         goto out_free;
10473                 }
10474
10475                 while ((rc = getline(&line, &len, fp)) != -1) {
10476                         /*
10477                          * If allocated buffer was too small, get something
10478                          * larger
10479                          */
10480                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
10481                                 ssize_t size;
10482
10483                                 nbfile_alloc = nbfile_alloc * 2 + 1;
10484                                 oldhur = hur;
10485                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
10486                                                                    opaque_len);
10487                                 if (!hur) {
10488                                         fprintf(stderr,
10489                                                 "hsm: cannot allocate the request: %s\n",
10490                                                 strerror(errno));
10491                                         hur = oldhur;
10492                                         rc = -errno;
10493                                         fclose(fp);
10494                                         goto out_free;
10495                                 }
10496                                 size = hur_len(oldhur);
10497                                 if (size < 0) {
10498                                         fprintf(stderr,
10499                                                 "hsm: cannot allocate %u files + %u bytes data\n",
10500                                                 oldhur->hur_request.hr_itemcount,
10501                                                 oldhur->hur_request.hr_data_len);
10502                                         free(hur);
10503                                         hur = oldhur;
10504                                         rc = -E2BIG;
10505                                         fclose(fp);
10506                                         goto out_free;
10507                                 }
10508                                 memcpy(hur, oldhur, size);
10509                                 free(oldhur);
10510                         }
10511
10512                         /* Chop CR */
10513                         if (line[strlen(line) - 1] == '\n')
10514                                 line[strlen(line) - 1] = '\0';
10515
10516                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
10517                                            mntpath, line, &last_dev);
10518                         if (rc) {
10519                                 fclose(fp);
10520                                 goto out_free;
10521                         }
10522
10523                         if (!some_file) {
10524                                 some_file = line;
10525                                 line = NULL;
10526                         }
10527                 }
10528
10529                 rc = fclose(fp);
10530                 free(line);
10531         }
10532
10533         /* If a --data was used, add it to the request */
10534         hur->hur_request.hr_data_len = opaque_len;
10535         if (opaque)
10536                 memcpy(hur_data(hur), opaque, opaque_len);
10537
10538         /* Send the HSM request */
10539         if (realpath(some_file, fullpath) == NULL) {
10540                 fprintf(stderr, "Could not find path '%s': %s\n",
10541                         some_file, strerror(errno));
10542         }
10543         rc = llapi_hsm_request(fullpath, hur);
10544         if (rc) {
10545                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
10546                         some_file, strerror(-rc));
10547                 goto out_free;
10548         }
10549
10550 out_free:
10551         free(some_file);
10552         free(hur);
10553         return rc;
10554 }
10555
10556 static int lfs_hsm_archive(int argc, char **argv)
10557 {
10558         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
10559 }
10560
10561 static int lfs_hsm_restore(int argc, char **argv)
10562 {
10563         return lfs_hsm_request(argc, argv, HUA_RESTORE);
10564 }
10565
10566 static int lfs_hsm_release(int argc, char **argv)
10567 {
10568         return lfs_hsm_request(argc, argv, HUA_RELEASE);
10569 }
10570
10571 static int lfs_hsm_remove(int argc, char **argv)
10572 {
10573         return lfs_hsm_request(argc, argv, HUA_REMOVE);
10574 }
10575
10576 static int lfs_hsm_cancel(int argc, char **argv)
10577 {
10578         return lfs_hsm_request(argc, argv, HUA_CANCEL);
10579 }
10580
10581 static int lfs_swap_layouts(int argc, char **argv)
10582 {
10583         if (argc != 3)
10584                 return CMD_HELP;
10585
10586         return llapi_swap_layouts(argv[1], argv[2], 0, 0,
10587                                   SWAP_LAYOUTS_KEEP_MTIME |
10588                                   SWAP_LAYOUTS_KEEP_ATIME);
10589 }
10590
10591 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
10592
10593 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
10594
10595 int lfs_get_mode(const char *string)
10596 {
10597         enum lock_mode_user mode;
10598
10599         for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
10600                 if (lock_mode_names[mode] == NULL)
10601                         continue;
10602                 if (strcasecmp(string, lock_mode_names[mode]) == 0)
10603                         return mode;
10604         }
10605
10606         return -EINVAL;
10607 }
10608
10609 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
10610 {
10611         enum lu_ladvise_type advice;
10612
10613         for (advice = 0;
10614              advice < ARRAY_SIZE(ladvise_names); advice++) {
10615                 if (ladvise_names[advice] == NULL)
10616                         continue;
10617                 if (strcmp(string, ladvise_names[advice]) == 0)
10618                         return advice;
10619         }
10620
10621         return LU_LADVISE_INVALID;
10622 }
10623
10624 static int lfs_ladvise(int argc, char **argv)
10625 {
10626         struct option long_opts[] = {
10627         { .val = 'a',   .name = "advice",       .has_arg = required_argument },
10628         { .val = 'b',   .name = "background",   .has_arg = no_argument },
10629         { .val = 'e',   .name = "end",          .has_arg = required_argument },
10630         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10631         { .val = 'l',   .name = "length",       .has_arg = required_argument },
10632         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
10633         { .val = 's',   .name = "start",        .has_arg = required_argument },
10634         { .val = 'u',   .name = "unset",        .has_arg = no_argument },
10635         { .name = NULL } };
10636         struct llapi_lu_ladvise advice;
10637         enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
10638         unsigned long long start = 0;
10639         unsigned long long end = LUSTRE_EOF;
10640         unsigned long long length = 0;
10641         unsigned long long size_units;
10642         unsigned long long flags = 0;
10643         int c, fd, rc = 0;
10644         const char *path;
10645         int mode = 0;
10646
10647         optind = 0;
10648         while ((c = getopt_long(argc, argv, "a:be:hl:m:s:u",
10649                                 long_opts, NULL)) != -1) {
10650                 switch (c) {
10651                 case 'a':
10652                         advice_type = lfs_get_ladvice(optarg);
10653                         if (advice_type == LU_LADVISE_INVALID) {
10654                                 fprintf(stderr,
10655                                         "%s: invalid advice type '%s'\n",
10656                                         progname, optarg);
10657                                 fprintf(stderr, "Valid types:");
10658
10659                                 for (advice_type = 0;
10660                                      advice_type < ARRAY_SIZE(ladvise_names);
10661                                      advice_type++) {
10662                                         if (ladvise_names[advice_type] == NULL)
10663                                                 continue;
10664                                         fprintf(stderr, " %s",
10665                                                 ladvise_names[advice_type]);
10666                                 }
10667                                 fprintf(stderr, "\n");
10668
10669                                 return CMD_HELP;
10670                         }
10671                         break;
10672                 case 'b':
10673                         flags |= LF_ASYNC;
10674                         break;
10675                 case 'u':
10676                         flags |= LF_UNSET;
10677                         break;
10678                 case 'e':
10679                         size_units = 1;
10680                         rc = llapi_parse_size(optarg, &end,
10681                                               &size_units, 0);
10682                         if (rc) {
10683                                 fprintf(stderr, "%s: bad end offset '%s'\n",
10684                                         argv[0], optarg);
10685                                 return CMD_HELP;
10686                         }
10687                         break;
10688                 case 's':
10689                         size_units = 1;
10690                         rc = llapi_parse_size(optarg, &start,
10691                                               &size_units, 0);
10692                         if (rc) {
10693                                 fprintf(stderr,
10694                                         "%s: bad start offset '%s'\n",
10695                                         argv[0], optarg);
10696                                 return CMD_HELP;
10697                         }
10698                         break;
10699                 case 'l':
10700                         size_units = 1;
10701                         rc = llapi_parse_size(optarg, &length,
10702                                               &size_units, 0);
10703                         if (rc) {
10704                                 fprintf(stderr, "%s: bad length '%s'\n",
10705                                         argv[0], optarg);
10706                                 return CMD_HELP;
10707                         }
10708                         break;
10709                 case 'm':
10710                         mode = lfs_get_mode(optarg);
10711                         if (mode < 0) {
10712                                 fprintf(stderr,
10713                                         "%s: bad mode '%s', valid modes are READ or WRITE\n",
10714                                         argv[0], optarg);
10715                                 return CMD_HELP;
10716                         }
10717                         break;
10718                 default:
10719                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10720                                 progname, argv[optind - 1]);
10721                         fallthrough;
10722                 case 'h':
10723                         return CMD_HELP;
10724                 }
10725         }
10726
10727         if (advice_type == LU_LADVISE_INVALID) {
10728                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
10729                 fprintf(stderr, "Valid types:");
10730                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
10731                      advice_type++) {
10732                         if (ladvise_names[advice_type] == NULL)
10733                                 continue;
10734                         fprintf(stderr, " %s", ladvise_names[advice_type]);
10735                 }
10736                 fprintf(stderr, "\n");
10737                 return CMD_HELP;
10738         }
10739
10740         if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
10741                 fprintf(stderr,
10742                         "%s: Lock no expand advice is a per file descriptor advice, so when called from lfs, it does nothing.\n",
10743                         argv[0]);
10744                 return CMD_HELP;
10745         }
10746
10747         if (argc <= optind) {
10748                 fprintf(stderr, "%s: please give one or more file names\n",
10749                         argv[0]);
10750                 return CMD_HELP;
10751         }
10752
10753         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
10754                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
10755                         argv[0]);
10756                 return CMD_HELP;
10757         }
10758
10759         if (end == LUSTRE_EOF && length != 0)
10760                 end = start + length;
10761
10762         if (end <= start) {
10763                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
10764                         argv[0], start, end);
10765                 return CMD_HELP;
10766         }
10767
10768         if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
10769                 fprintf(stderr, "%s: mode is only valid with lockahead\n",
10770                         argv[0]);
10771                 return CMD_HELP;
10772         }
10773
10774         if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
10775                 fprintf(stderr, "%s: mode is required with lockahead\n",
10776                         argv[0]);
10777                 return CMD_HELP;
10778         }
10779
10780         while (optind < argc) {
10781                 int rc2;
10782
10783                 path = argv[optind++];
10784
10785                 fd = open(path, O_RDONLY);
10786                 if (fd < 0) {
10787                         rc2 = -errno;
10788                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
10789                                 argv[0], path, strerror(-rc2));
10790                         if (!rc)
10791                                 rc = rc2;
10792                         continue;
10793                 }
10794
10795                 advice.lla_start = start;
10796                 advice.lla_end = end;
10797                 advice.lla_advice = advice_type;
10798                 advice.lla_value1 = 0;
10799                 advice.lla_value2 = 0;
10800                 advice.lla_value3 = 0;
10801                 advice.lla_value4 = 0;
10802                 if (advice_type == LU_LADVISE_LOCKAHEAD) {
10803                         advice.lla_lockahead_mode = mode;
10804                         advice.lla_peradvice_flags = flags;
10805                 }
10806
10807                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
10808                 close(fd);
10809                 if (rc2 < 0) {
10810                         fprintf(stderr,
10811                                 "%s: cannot give advice '%s' to file '%s': %s\n",
10812                                 argv[0], ladvise_names[advice_type],
10813                                 path, strerror(errno));
10814
10815                         if (!rc)
10816                                 rc = rc2;
10817                         continue;
10818                 }
10819         }
10820
10821         return rc;
10822 }
10823
10824 static const char *const heat_names[] = LU_HEAT_NAMES;
10825
10826 static int lfs_heat_get(int argc, char **argv)
10827 {
10828         struct lu_heat *heat;
10829         int rc = 0, rc2;
10830         char *path;
10831         int fd;
10832         int i;
10833
10834         if (argc <= 1)
10835                 return CMD_HELP;
10836
10837         heat = calloc(sizeof(*heat) + sizeof(__u64) * OBD_HEAT_COUNT, 1);
10838         if (!heat) {
10839                 fprintf(stderr, "%s: memory allocation failed\n", argv[0]);
10840                 return -ENOMEM;
10841         }
10842
10843         optind = 1;
10844         while (optind < argc) {
10845                 path = argv[optind++];
10846
10847                 fd = open(path, O_RDONLY);
10848                 if (fd < 0) {
10849                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
10850                                 argv[0], path, strerror(errno));
10851                         rc2 = -errno;
10852                         goto next;
10853                 }
10854
10855                 heat->lh_count = OBD_HEAT_COUNT;
10856                 rc2 = llapi_heat_get(fd, heat);
10857                 close(fd);
10858                 if (rc2 < 0) {
10859                         fprintf(stderr,
10860                                 "%s: cannot get heat of file '%s': %s\n",
10861                                 argv[0], path, strerror(errno));
10862                         goto next;
10863                 }
10864
10865                 printf("flags: %x\n", heat->lh_flags);
10866                 for (i = 0; i < heat->lh_count; i++)
10867                         printf("%s: %llu\n", heat_names[i],
10868                                (unsigned long long)heat->lh_heat[i]);
10869 next:
10870                 if (rc == 0 && rc2 < 0)
10871                         rc = rc2;
10872         }
10873
10874         free(heat);
10875         return rc;
10876 }
10877
10878 static int lfs_heat_set(int argc, char **argv)
10879 {
10880         struct option long_opts[] = {
10881         { .val = 'c',   .name = "clear",        .has_arg = no_argument },
10882         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10883         { .val = 'o',   .name = "off",          .has_arg = no_argument },
10884         { .val = 'O',   .name = "on",           .has_arg = no_argument },
10885         { .name = NULL } };
10886         enum lu_heat_flag flags = 0;
10887         int rc = 0, rc2;
10888         char *path;
10889         int fd;
10890         int c;
10891
10892         if (argc <= 1)
10893                 return CMD_HELP;
10894
10895         optind = 0;
10896         while ((c = getopt_long(argc, argv, "choO", long_opts, NULL)) != -1) {
10897                 switch (c) {
10898                 case 'c':
10899                         flags |= LU_HEAT_FLAG_CLEAR;
10900                         break;
10901                 case 'o':
10902                         flags |= LU_HEAT_FLAG_CLEAR;
10903                         flags |= LU_HEAT_FLAG_OFF;
10904                         break;
10905                 case 'O':
10906                         flags &= ~LU_HEAT_FLAG_OFF;
10907                         break;
10908                 default:
10909                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10910                                 progname, argv[optind - 1]);
10911                         fallthrough;
10912                 case 'h':
10913                         return CMD_HELP;
10914                 }
10915         }
10916
10917         if (argc <= optind) {
10918                 fprintf(stderr, "%s: please give one or more file names\n",
10919                         argv[0]);
10920                 return CMD_HELP;
10921         }
10922
10923         while (optind < argc) {
10924                 path = argv[optind++];
10925
10926                 fd = open(path, O_RDONLY);
10927                 if (fd < 0) {
10928                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
10929                                 argv[0], path, strerror(errno));
10930                         rc2 = -errno;
10931                         goto next;
10932                 }
10933
10934                 rc2 = llapi_heat_set(fd, flags);
10935                 close(fd);
10936                 if (rc2 < 0) {
10937                         fprintf(stderr,
10938                                 "%s: cannot setflags heat of file '%s': %s\n",
10939                                 argv[0], path, strerror(errno));
10940                         goto next;
10941                 }
10942 next:
10943                 if (rc == 0 && rc2 < 0)
10944                         rc = rc2;
10945         }
10946         return rc;
10947 }
10948
10949 /**
10950  * The input string contains a comma delimited list of component ids and
10951  * ranges, for example "1,2-4,7".
10952  */
10953 static int parse_mirror_ids(__u16 *ids, int size, char *arg)
10954 {
10955         bool end_of_loop = false;
10956         char *ptr = NULL;
10957         int nr = 0;
10958         int rc;
10959
10960         if (!arg)
10961                 return -EINVAL;
10962
10963         while (!end_of_loop) {
10964                 int start_index;
10965                 int end_index;
10966                 int i;
10967                 char *endptr = NULL;
10968
10969                 rc = -EINVAL;
10970                 ptr = strchrnul(arg, ',');
10971                 end_of_loop = *ptr == '\0';
10972                 *ptr = '\0';
10973
10974                 start_index = strtol(arg, &endptr, 0);
10975                 if (endptr == arg) /* no data at all */
10976                         break;
10977                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
10978                         break;
10979                 if (start_index < 0)
10980                         break;
10981
10982                 end_index = start_index;
10983                 if (*endptr == '-') {
10984                         end_index = strtol(endptr + 1, &endptr, 0);
10985                         if (*endptr != '\0')
10986                                 break;
10987                         if (end_index < start_index)
10988                                 break;
10989                 }
10990
10991                 for (i = start_index; i <= end_index && size > 0; i++) {
10992                         int j;
10993
10994                         /* remove duplicate */
10995                         for (j = 0; j < nr; j++) {
10996                                 if (ids[j] == i)
10997                                         break;
10998                         }
10999                         if (j == nr) { /* no duplicate */
11000                                 ids[nr++] = i;
11001                                 --size;
11002                         }
11003                 }
11004
11005                 if (size == 0 && i < end_index)
11006                         break;
11007
11008                 *ptr = ',';
11009                 arg = ++ptr;
11010                 rc = 0;
11011         }
11012         if (!end_of_loop && ptr)
11013                 *ptr = ',';
11014
11015         return rc < 0 ? rc : nr;
11016 }
11017
11018 /**
11019  * struct verify_mirror_id - Mirror id to be verified.
11020  * @mirror_id:   A specified mirror id.
11021  * @is_valid_id: @mirror_id is valid or not in the mirrored file.
11022  */
11023 struct verify_mirror_id {
11024         __u16 mirror_id;
11025         bool is_valid_id;
11026 };
11027
11028 /**
11029  * compare_mirror_ids() - Compare mirror ids.
11030  * @layout: Mirror component list.
11031  * @cbdata: Callback data in verify_mirror_id structure.
11032  *
11033  * This is a callback function called by llapi_layout_comp_iterate()
11034  * to compare the specified mirror id with the one in the current
11035  * component of @layout. If they are the same, then the specified
11036  * mirror id is valid.
11037  *
11038  * Return: a negative error code on failure or
11039  *         LLAPI_LAYOUT_ITER_CONT: Proceed iteration
11040  *         LLAPI_LAYOUT_ITER_STOP: Stop iteration
11041  */
11042 static inline
11043 int compare_mirror_ids(struct llapi_layout *layout, void *cbdata)
11044 {
11045         struct verify_mirror_id *mirror_id_cbdata =
11046                                  (struct verify_mirror_id *)cbdata;
11047         uint32_t mirror_id;
11048         int rc = 0;
11049
11050         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
11051         if (rc < 0) {
11052                 rc = -errno;
11053                 fprintf(stderr,
11054                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
11055                         progname, strerror(errno));
11056                 return rc;
11057         }
11058
11059         if (mirror_id_cbdata->mirror_id == mirror_id) {
11060                 mirror_id_cbdata->is_valid_id = true;
11061                 return LLAPI_LAYOUT_ITER_STOP;
11062         }
11063
11064         return LLAPI_LAYOUT_ITER_CONT;
11065 }
11066
11067 /**
11068  * verify_mirror_ids() - Verify specified mirror ids.
11069  * @fname:      Mirrored file name.
11070  * @mirror_ids: Specified mirror ids to be verified.
11071  * @ids_nr:     Number of specified mirror ids.
11072  *
11073  * This function verifies that specified @mirror_ids are valid
11074  * in the mirrored file @fname.
11075  *
11076  * Return: 0 on success or a negative error code on failure.
11077  */
11078 static inline
11079 int verify_mirror_ids(const char *fname, __u16 *mirror_ids, int ids_nr)
11080 {
11081         struct llapi_layout *layout = NULL;
11082         struct verify_mirror_id mirror_id_cbdata = { 0 };
11083         struct stat stbuf;
11084         uint32_t flr_state;
11085         int i;
11086         int fd;
11087         int rc = 0;
11088         int rc2 = 0;
11089
11090         if (ids_nr <= 0)
11091                 return -EINVAL;
11092
11093         if (stat(fname, &stbuf) < 0) {
11094                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
11095                         progname, fname, strerror(errno));
11096                 rc = -errno;
11097                 goto error;
11098         }
11099
11100         if (!S_ISREG(stbuf.st_mode)) {
11101                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
11102                         progname, fname);
11103                 rc = -EINVAL;
11104                 goto error;
11105         }
11106
11107         fd = open(fname, O_DIRECT | O_RDONLY);
11108         if (fd < 0) {
11109                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
11110                         progname, fname, strerror(errno));
11111                 rc = -errno;
11112                 goto error;
11113         }
11114
11115         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
11116         if (rc < 0) {
11117                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
11118                         progname, fname, strerror(errno));
11119                 goto close_fd;
11120         }
11121
11122         layout = llapi_layout_get_by_fd(fd, 0);
11123         if (!layout) {
11124                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
11125                         progname, fname, strerror(errno));
11126                 rc = -errno;
11127                 llapi_lease_release(fd);
11128                 goto close_fd;
11129         }
11130
11131         rc = llapi_layout_flags_get(layout, &flr_state);
11132         if (rc < 0) {
11133                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
11134                         progname, fname, strerror(errno));
11135                 rc = -errno;
11136                 goto free_layout;
11137         }
11138
11139         flr_state &= LCM_FL_FLR_MASK;
11140         switch (flr_state) {
11141         case LCM_FL_NONE:
11142                 rc = -EINVAL;
11143                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
11144                         progname, fname, llapi_layout_flags_string(flr_state));
11145                 goto free_layout;
11146         default:
11147                 break;
11148         }
11149
11150         rc2 = 0;
11151         for (i = 0; i < ids_nr; i++) {
11152                 mirror_id_cbdata.mirror_id = mirror_ids[i];
11153                 mirror_id_cbdata.is_valid_id = false;
11154
11155                 rc = llapi_layout_comp_iterate(layout, compare_mirror_ids,
11156                                                &mirror_id_cbdata);
11157                 if (rc < 0) {
11158                         rc = -errno;
11159                         fprintf(stderr,
11160                                 "%s: '%s' failed to verify mirror id: %u.\n",
11161                                 progname, fname, mirror_ids[i]);
11162                         goto free_layout;
11163                 }
11164
11165                 if (!mirror_id_cbdata.is_valid_id) {
11166                         rc2 = -EINVAL;
11167                         fprintf(stderr,
11168                                 "%s: '%s' invalid specified mirror id: %u.\n",
11169                                 progname, fname, mirror_ids[i]);
11170                 }
11171         }
11172         rc = rc2;
11173
11174 free_layout:
11175         llapi_layout_free(layout);
11176         llapi_lease_release(fd);
11177 close_fd:
11178         close(fd);
11179 error:
11180         return rc;
11181 }
11182
11183 static inline
11184 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
11185                            __u16 *mirror_ids, int ids_nr)
11186 {
11187         struct llapi_resync_comp comp_array[1024] = { { 0 } };
11188         struct llapi_layout *layout;
11189         struct stat stbuf;
11190         uint32_t flr_state;
11191         uint64_t start;
11192         uint64_t end;
11193         int comp_size = 0;
11194         int idx;
11195         int fd;
11196         int rc;
11197         int rc2;
11198
11199         if (stat(fname, &stbuf) < 0) {
11200                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
11201                         progname, fname, strerror(errno));
11202                 rc = -errno;
11203                 goto error;
11204         }
11205         if (!S_ISREG(stbuf.st_mode)) {
11206                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
11207                         progname, fname);
11208                 rc = -EINVAL;
11209                 goto error;
11210         }
11211
11212         /* Allow mirror resync even without the key on encrypted files */
11213         fd = open(fname, O_DIRECT | O_RDWR | O_FILE_ENC);
11214         if (fd < 0) {
11215                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
11216                         progname, fname, strerror(errno));
11217                 rc = -errno;
11218                 goto error;
11219         }
11220
11221         layout = llapi_layout_get_by_fd(fd, 0);
11222         if (!layout) {
11223                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
11224                         progname, fname, strerror(errno));
11225                 rc = -errno;
11226                 goto close_fd;
11227         }
11228
11229         rc = llapi_layout_flags_get(layout, &flr_state);
11230         if (rc) {
11231                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
11232                         progname, fname, strerror(errno));
11233                 rc = -errno;
11234                 goto free_layout;
11235         }
11236
11237         flr_state &= LCM_FL_FLR_MASK;
11238         if (flr_state == LCM_FL_NONE) {
11239                 rc = -EINVAL;
11240                 fprintf(stderr, "%s: '%s' is not a FLR file.\n",
11241                         progname, fname);
11242                 goto free_layout;
11243         }
11244
11245         /* get stale component info */
11246         comp_size = llapi_mirror_find_stale(layout, comp_array,
11247                                             ARRAY_SIZE(comp_array),
11248                                             mirror_ids, ids_nr);
11249         if (comp_size <= 0) {
11250                 rc = comp_size;
11251                 goto free_layout;
11252         }
11253
11254         ioc->lil_mode = LL_LEASE_WRLCK;
11255         ioc->lil_flags = LL_LEASE_RESYNC;
11256         rc = llapi_lease_set(fd, ioc);
11257         if (rc < 0) {
11258                 if (rc == -EALREADY)
11259                         rc = 0;
11260                 else
11261                         fprintf(stderr,
11262                             "%s: '%s' llapi_lease_get_ext resync failed: %s.\n",
11263                                 progname, fname, strerror(-rc));
11264                 goto free_layout;
11265         }
11266
11267         /* get the read range [start, end) */
11268         start = comp_array[0].lrc_start;
11269         end = comp_array[0].lrc_end;
11270         for (idx = 1; idx < comp_size; idx++) {
11271                 if (comp_array[idx].lrc_start < start)
11272                         start = comp_array[idx].lrc_start;
11273                 if (end < comp_array[idx].lrc_end)
11274                         end = comp_array[idx].lrc_end;
11275         }
11276
11277         rc = llapi_lease_check(fd);
11278         if (rc != LL_LEASE_WRLCK) {
11279                 fprintf(stderr, "%s: '%s' lost lease lock.\n",
11280                         progname, fname);
11281                 goto free_layout;
11282         }
11283
11284         rc = llapi_mirror_resync_many(fd, layout, comp_array, comp_size,
11285                                       start, end);
11286         if (rc < 0)
11287                 fprintf(stderr, "%s: '%s' llapi_mirror_resync_many: %s.\n",
11288                         progname, fname, strerror(-rc));
11289
11290         rc = migrate_set_timestamps(fd, &stbuf);
11291         if (rc < 0) {
11292                 fprintf(stderr, "%s: '%s' cannot set timestamps: %s\n",
11293                         progname, fname, strerror(-rc));
11294                 goto free_layout;
11295         }
11296
11297         /* need to do the lease unlock even resync fails */
11298         ioc->lil_mode = LL_LEASE_UNLCK;
11299         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
11300         ioc->lil_count = 0;
11301         for (idx = 0; idx < comp_size; idx++) {
11302                 if (comp_array[idx].lrc_synced) {
11303                         ioc->lil_ids[ioc->lil_count] = comp_array[idx].lrc_id;
11304                         ioc->lil_count++;
11305                 }
11306         }
11307
11308         rc2 = llapi_lease_set(fd, ioc);
11309         /**
11310          * llapi_lease_set returns lease mode when it request to unlock
11311          * the lease lock.
11312          */
11313         if (rc2 <= 0) {
11314                 /* rc2 == 0 means lost lease lock */
11315                 if (rc2 == 0 && rc == 0)
11316                         rc = -EBUSY;
11317                 else
11318                         rc = rc2;
11319                 fprintf(stderr, "%s: resync file '%s' failed: %s.\n",
11320                         progname, fname,
11321                         rc2 == 0 ? "lost lease lock" : strerror(-rc2));
11322
11323                 llapi_lease_release(fd);
11324                 goto free_layout;
11325         }
11326
11327 free_layout:
11328         llapi_layout_free(layout);
11329 close_fd:
11330         close(fd);
11331 error:
11332         return rc;
11333 }
11334
11335 static inline int lfs_mirror_resync(int argc, char **argv)
11336 {
11337         struct option long_opts[] = {
11338         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11339         { .val = 'o',   .name = "only",         .has_arg = required_argument },
11340         { .name = NULL } };
11341         struct ll_ioc_lease *ioc = NULL;
11342         __u16 mirror_ids[128] = { 0 };
11343         int ids_nr = 0;
11344         int c;
11345         int rc = 0;
11346
11347         while ((c = getopt_long(argc, argv, "ho:", long_opts, NULL)) >= 0) {
11348                 switch (c) {
11349                 case 'o':
11350                         rc = parse_mirror_ids(mirror_ids,
11351                                         sizeof(mirror_ids) / sizeof(__u16),
11352                                         optarg);
11353                         if (rc < 0) {
11354                                 fprintf(stderr,
11355                                         "%s: bad mirror ids '%s'.\n",
11356                                         argv[0], optarg);
11357                                 goto error;
11358                         }
11359                         ids_nr = rc;
11360                         break;
11361                 default:
11362                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11363                                 progname, argv[optind - 1]);
11364                         fallthrough;
11365                 case 'h':
11366                         rc = CMD_HELP;
11367                         goto error;
11368                 }
11369         }
11370
11371         if (argc == optind) {
11372                 fprintf(stderr, "%s: no file name given.\n", argv[0]);
11373                 rc = CMD_HELP;
11374                 goto error;
11375         }
11376
11377         if (ids_nr > 0 && argc > optind + 1) {
11378                 fprintf(stderr,
11379                     "%s: option '--only' cannot be used upon multiple files.\n",
11380                         argv[0]);
11381                 rc = CMD_HELP;
11382                 goto error;
11383         }
11384
11385         if (ids_nr > 0) {
11386                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
11387                 if (rc < 0)
11388                         goto error;
11389         }
11390
11391         /* set the lease on the file */
11392         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
11393         if (!ioc) {
11394                 fprintf(stderr, "%s: cannot alloc id array for ioc: %s.\n",
11395                         argv[0], strerror(errno));
11396                 rc = -errno;
11397                 goto error;
11398         }
11399
11400         for (; optind < argc; optind++) {
11401                 rc = lfs_mirror_resync_file(argv[optind], ioc,
11402                                             mirror_ids, ids_nr);
11403                 /* ignore previous file's error, continue with next file */
11404
11405                 /* reset ioc */
11406                 memset(ioc, 0, sizeof(*ioc) + sizeof(__u32) * 4096);
11407         }
11408
11409         free(ioc);
11410 error:
11411         return rc;
11412 }
11413
11414 static inline int verify_mirror_id_by_fd(int fd, __u16 mirror_id)
11415 {
11416         struct llapi_layout *layout;
11417         int rc;
11418
11419         layout = llapi_layout_get_by_fd(fd, 0);
11420         if (!layout) {
11421                 fprintf(stderr, "could not get layout.\n");
11422                 return  -EINVAL;
11423         }
11424
11425         rc = llapi_layout_comp_iterate(layout, find_mirror_id, &mirror_id);
11426         if (rc < 0) {
11427                 fprintf(stderr, "failed to iterate layout\n");
11428                 llapi_layout_free(layout);
11429
11430                 return rc;
11431         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
11432                 fprintf(stderr, "does not find mirror with ID %u\n", mirror_id);
11433                 llapi_layout_free(layout);
11434
11435                 return -EINVAL;
11436         }
11437         llapi_layout_free(layout);
11438
11439         return 0;
11440 }
11441
11442 /**
11443  * Check whether two files are the same file
11444  * \retval      0  same file
11445  * \retval      1  not the same file
11446  * \retval      <0 error code
11447  */
11448 static inline int check_same_file(int fd, const char *f2)
11449 {
11450         struct stat stbuf1;
11451         struct stat stbuf2;
11452
11453         if (fstat(fd, &stbuf1) < 0)
11454                 return -errno;
11455
11456         if (stat(f2, &stbuf2) < 0)
11457                 return 1;
11458
11459         if (stbuf1.st_rdev == stbuf2.st_rdev &&
11460             stbuf1.st_ino == stbuf2.st_ino)
11461                 return 0;
11462
11463         return 1;
11464 }
11465
11466 static inline int lfs_mirror_read(int argc, char **argv)
11467 {
11468         int rc = CMD_HELP;
11469         __u16 mirror_id = 0;
11470         const char *outfile = NULL;
11471         char *fname;
11472         int fd = 0;
11473         int outfd;
11474         int c;
11475         void *buf;
11476         const size_t buflen = 4 << 20;
11477         off_t pos;
11478         struct option long_opts[] = {
11479         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11480         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
11481         { .val = 'o',   .name = "outfile",      .has_arg = required_argument },
11482         { .name = NULL } };
11483
11484         while ((c = getopt_long(argc, argv, "hN:o:", long_opts, NULL)) >= 0) {
11485                 char *end;
11486
11487                 switch (c) {
11488                 case 'N': {
11489                         unsigned long int id;
11490
11491                         errno = 0;
11492                         id = strtoul(optarg, &end, 0);
11493                         if (errno != 0 || *end != '\0' || id == 0 ||
11494                             id > UINT16_MAX) {
11495                                 fprintf(stderr,
11496                                         "%s %s: invalid mirror ID '%s'\n",
11497                                         progname, argv[0], optarg);
11498                                 return rc;
11499                         }
11500
11501                         mirror_id = (__u16)id;
11502                         break;
11503                 }
11504                 case 'o':
11505                         outfile = optarg;
11506                         break;
11507                 default:
11508                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11509                                 progname, argv[optind - 1]);
11510                         fallthrough;
11511                 case 'h':
11512                         return CMD_HELP;
11513                 }
11514         }
11515
11516         if (argc == optind) {
11517                 fprintf(stderr, "%s %s: no mirrored file provided\n",
11518                         progname, argv[0]);
11519                 return rc;
11520         } else if (argc > optind + 1) {
11521                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
11522                 return rc;
11523         }
11524
11525         if (mirror_id == 0) {
11526                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
11527                         progname, argv[0]);
11528                 return rc;
11529         }
11530
11531         /* open mirror file */
11532         fname = argv[optind];
11533         fd = open(fname, O_DIRECT | O_RDONLY);
11534         if (fd < 0) {
11535                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
11536                         progname, argv[0], fname, strerror(errno));
11537                 return rc;
11538         }
11539
11540         /* verify mirror id */
11541         rc = verify_mirror_id_by_fd(fd, mirror_id);
11542         if (rc) {
11543                 fprintf(stderr,
11544                         "%s %s: cannot find mirror with ID %u in '%s'\n",
11545                         progname, argv[0], mirror_id, fname);
11546                 goto close_fd;
11547         }
11548
11549         /* open output file - O_EXCL ensures output is not the same as input */
11550         if (outfile) {
11551                 outfd = open(outfile, O_EXCL | O_WRONLY | O_CREAT, 0644);
11552                 if (outfd < 0) {
11553                         fprintf(stderr, "%s %s: cannot create file '%s': %s\n",
11554                                 progname, argv[0], outfile, strerror(errno));
11555                         rc = -errno;
11556                         goto close_fd;
11557                 }
11558         } else {
11559                 outfd = STDOUT_FILENO;
11560         }
11561
11562         /* allocate buffer */
11563         rc = posix_memalign(&buf, sysconf(_SC_PAGESIZE), buflen);
11564         if (rc) {
11565                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
11566                                 progname, argv[0], rc);
11567                 goto close_outfd;
11568         }
11569
11570         pos = 0;
11571         while (1) {
11572                 ssize_t bytes_read;
11573                 ssize_t written = 0;
11574
11575                 bytes_read = llapi_mirror_read(fd, mirror_id, buf, buflen, pos);
11576                 if (bytes_read < 0) {
11577                         rc = bytes_read;
11578                         fprintf(stderr,
11579                                 "%s %s: fail to read data from mirror %u: %s\n",
11580                                 progname, argv[0], mirror_id, strerror(-rc));
11581                         goto free_buf;
11582                 }
11583
11584                 /* EOF reached */
11585                 if (bytes_read == 0)
11586                         break;
11587
11588                 while (written < bytes_read) {
11589                         ssize_t written2;
11590
11591                         written2 = write(outfd, buf + written,
11592                                          bytes_read - written);
11593                         if (written2 < 0) {
11594                                 fprintf(stderr,
11595                                         "%s %s: fail to write %s: %s\n",
11596                                         progname, argv[0], outfile ? : "STDOUT",
11597                                         strerror(errno));
11598                                 rc = -errno;
11599                                 goto free_buf;
11600                         }
11601                         written += written2;
11602                 }
11603
11604                 if (written != bytes_read) {
11605                         fprintf(stderr,
11606                 "%s %s: written %ld bytes does not match with %ld read.\n",
11607                                 progname, argv[0], written, bytes_read);
11608                         rc = -EIO;
11609                         goto free_buf;
11610                 }
11611
11612                 pos += bytes_read;
11613         }
11614
11615         fsync(outfd);
11616         rc = 0;
11617
11618 free_buf:
11619         free(buf);
11620 close_outfd:
11621         if (outfile)
11622                 close(outfd);
11623 close_fd:
11624         close(fd);
11625
11626         return rc;
11627 }
11628
11629 static inline int lfs_mirror_write(int argc, char **argv)
11630 {
11631         int rc = CMD_HELP;
11632         __u16 mirror_id = 0;
11633         const char *inputfile = NULL;
11634         char *fname;
11635         int fd = 0;
11636         int inputfd;
11637         int c;
11638         void *buf;
11639         const size_t buflen = 4 << 20;
11640         off_t pos;
11641         size_t page_size = sysconf(_SC_PAGESIZE);
11642         struct ll_ioc_lease_id ioc;
11643         struct option long_opts[] = {
11644         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11645         { .val = 'i',   .name = "inputfile",    .has_arg = required_argument },
11646         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
11647         { .name = NULL } };
11648
11649         while ((c = getopt_long(argc, argv, "hi:N:", long_opts, NULL)) >= 0) {
11650                 char *end;
11651
11652                 switch (c) {
11653                 case 'N': {
11654                         unsigned long int id;
11655
11656                         errno = 0;
11657                         id = strtoul(optarg, &end, 0);
11658                         if (errno != 0 || *end != '\0' || id == 0 ||
11659                             id > UINT16_MAX) {
11660                                 fprintf(stderr,
11661                                         "%s %s: invalid mirror ID '%s'\n",
11662                                         progname, argv[0], optarg);
11663                                 return rc;
11664                         }
11665
11666                         mirror_id = (__u16)id;
11667                         break;
11668                 }
11669                 case 'i':
11670                         inputfile = optarg;
11671                         break;
11672                 default:
11673                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11674                                 progname, argv[optind - 1]);
11675                         fallthrough;
11676                 case 'h':
11677                         return CMD_HELP;
11678                 }
11679         }
11680
11681         if (argc == optind) {
11682                 fprintf(stderr, "%s %s: no mirrored file provided\n",
11683                         progname, argv[0]);
11684                 return rc;
11685         } else if (argc > optind + 1) {
11686                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
11687                 return rc;
11688         }
11689
11690         if (mirror_id == 0) {
11691                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
11692                         progname, argv[0]);
11693                 return rc;
11694         }
11695
11696         /* open mirror file */
11697         fname = argv[optind];
11698         fd = open(fname, O_DIRECT | O_WRONLY);
11699         if (fd < 0) {
11700                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
11701                         progname, argv[0], fname, strerror(errno));
11702                 return rc;
11703         }
11704
11705         /* verify mirror id */
11706         rc = verify_mirror_id_by_fd(fd, mirror_id);
11707         if (rc) {
11708                 fprintf(stderr,
11709                         "%s %s: cannot find mirror with ID %u in '%s'\n",
11710                         progname, argv[0], mirror_id, fname);
11711                 goto close_fd;
11712         }
11713
11714         /* open input file */
11715         if (inputfile) {
11716                 rc = check_same_file(fd, inputfile);
11717                 if (rc == 0) {
11718                         fprintf(stderr,
11719                         "%s %s: input file cannot be the mirrored file '%s'\n",
11720                                 progname, argv[0], fname);
11721                         goto close_fd;
11722                 }
11723                 if (rc < 0)
11724                         goto close_fd;
11725
11726                 inputfd = open(inputfile, O_RDONLY, 0644);
11727                 if (inputfd < 0) {
11728                         fprintf(stderr, "%s %s: cannot open file '%s': %s\n",
11729                                 progname, argv[0], inputfile, strerror(errno));
11730                         rc = -errno;
11731                         goto close_fd;
11732                 }
11733         } else {
11734                 inputfd = STDIN_FILENO;
11735         }
11736
11737         /* allocate buffer */
11738         rc = posix_memalign(&buf, page_size, buflen);
11739         if (rc) {
11740                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
11741                         progname, argv[0], rc);
11742                 goto close_inputfd;
11743         }
11744
11745         /* prepare target mirror components instantiation */
11746         ioc.lil_mode = LL_LEASE_WRLCK;
11747         ioc.lil_flags = LL_LEASE_RESYNC;
11748         ioc.lil_mirror_id = mirror_id;
11749         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
11750         if (rc < 0) {
11751                 fprintf(stderr,
11752                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
11753                         progname, argv[0], fname, strerror(errno));
11754                 goto free_buf;
11755         }
11756
11757         pos = 0;
11758         while (1) {
11759                 ssize_t bytes_read;
11760                 ssize_t written;
11761                 size_t to_write;
11762
11763                 rc = llapi_lease_check(fd);
11764                 if (rc != LL_LEASE_WRLCK) {
11765                         fprintf(stderr, "%s %s: '%s' lost lease lock\n",
11766                                 progname, argv[0], fname);
11767                         goto free_buf;
11768                 }
11769
11770                 bytes_read = read(inputfd, buf, buflen);
11771                 if (bytes_read < 0) {
11772                         rc = bytes_read;
11773                         fprintf(stderr,
11774                                 "%s %s: fail to read data from '%s': %s\n",
11775                                 progname, argv[0], inputfile ? : "STDIN",
11776                                 strerror(errno));
11777                         rc = -errno;
11778                         goto free_buf;
11779                 }
11780
11781                 /* EOF reached */
11782                 if (bytes_read == 0)
11783                         break;
11784
11785                 /* round up to page align to make direct IO happy. */
11786                 to_write = (bytes_read + page_size - 1) & ~(page_size - 1);
11787
11788                 written = llapi_mirror_write(fd, mirror_id, buf, to_write,
11789                                              pos);
11790                 if (written < 0) {
11791                         rc = written;
11792                         fprintf(stderr,
11793                               "%s %s: fail to write to mirror %u: %s\n",
11794                                 progname, argv[0], mirror_id,
11795                                 strerror(-rc));
11796                         goto free_buf;
11797                 }
11798
11799                 pos += bytes_read;
11800         }
11801
11802         if (pos & (page_size - 1)) {
11803                 rc = llapi_mirror_truncate(fd, mirror_id, pos);
11804                 if (rc < 0)
11805                         goto free_buf;
11806         }
11807
11808         ioc.lil_mode = LL_LEASE_UNLCK;
11809         ioc.lil_flags = LL_LEASE_RESYNC_DONE;
11810         ioc.lil_count = 0;
11811         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
11812         if (rc <= 0) {
11813                 if (rc == 0)
11814                         rc = -EBUSY;
11815                 fprintf(stderr,
11816                         "%s %s: release lease lock of '%s' failed: %s\n",
11817                         progname, argv[0], fname, strerror(-rc));
11818                 goto free_buf;
11819         }
11820
11821         rc = 0;
11822
11823 free_buf:
11824         free(buf);
11825 close_inputfd:
11826         if (inputfile)
11827                 close(inputfd);
11828 close_fd:
11829         close(fd);
11830
11831         return rc;
11832 }
11833
11834 static inline int get_other_mirror_ids(int fd, __u16 *ids, __u16 exclude_id)
11835 {
11836         struct llapi_layout *layout;
11837         struct collect_ids_data cid = { .cid_ids = ids,
11838                                         .cid_count = 0,
11839                                         .cid_exclude = exclude_id, };
11840         int rc;
11841
11842         layout = llapi_layout_get_by_fd(fd, 0);
11843         if (!layout) {
11844                 fprintf(stderr, "could not get layout\n");
11845                 return -EINVAL;
11846         }
11847
11848         rc = llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
11849         if (rc < 0) {
11850                 fprintf(stderr, "failed to iterate layout\n");
11851                 llapi_layout_free(layout);
11852
11853                 return rc;
11854         }
11855         llapi_layout_free(layout);
11856
11857         return cid.cid_count;
11858 }
11859
11860 #ifndef MIRROR_ID_NEG
11861 #define MIRROR_ID_NEG         0x8000
11862 #endif
11863
11864 static inline int lfs_mirror_copy(int argc, char **argv)
11865 {
11866         int rc = CMD_HELP;
11867         __u16 read_mirror_id = 0;
11868         __u16 ids[128] = { 0 };
11869         int count = 0;
11870         struct llapi_layout *layout = NULL;
11871         struct llapi_resync_comp comp_array[1024] = { { 0 } };
11872         int comp_size = 0;
11873         char *fname;
11874         int fd = 0;
11875         int c;
11876         int i;
11877         ssize_t copied;
11878         struct ll_ioc_lease *ioc = NULL;
11879         struct ll_ioc_lease_id *resync_ioc;
11880         struct option long_opts[] = {
11881         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11882         { .val = 'i',   .name = "read-mirror",  .has_arg = required_argument },
11883         { .val = 'o',   .name = "write-mirror", .has_arg = required_argument },
11884         { .name = NULL } };
11885         char cmd[PATH_MAX];
11886
11887         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
11888         progname = cmd;
11889         while ((c = getopt_long(argc, argv, "hi:o:", long_opts, NULL)) >= 0) {
11890                 char *end;
11891
11892                 switch (c) {
11893                 case 'i': {
11894                         unsigned long int id;
11895
11896                         errno = 0;
11897                         id = strtoul(optarg, &end, 0);
11898                         if (errno != 0 || *end != '\0' || id == 0 ||
11899                             id > UINT16_MAX) {
11900                                 fprintf(stderr,
11901                                         "%s: invalid read mirror ID '%s'\n",
11902                                         progname, optarg);
11903                                 return rc;
11904                         }
11905
11906                         read_mirror_id = (__u16)id;
11907                         break;
11908                 }
11909                 case 'o':
11910                         if (!strcmp(optarg, "-1")) {
11911                                 /* specify all other mirrors */
11912                                 ids[0] = (__u16)-1;
11913                                 count = 1;
11914                         } else {
11915                                 count = parse_mirror_ids((__u16 *)ids,
11916                                                          ARRAY_SIZE(ids),
11917                                                          optarg);
11918                                 if (count < 0)
11919                                         return rc;
11920                         }
11921                         break;
11922                 default:
11923                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11924                                 progname, argv[optind - 1]);
11925                         fallthrough;
11926                 case 'h':
11927                         return CMD_HELP;
11928                 }
11929         }
11930
11931         if (argc == optind) {
11932                 fprintf(stderr, "%s %s: no mirrored file provided\n",
11933                         progname, argv[0]);
11934                 return rc;
11935         } else if (argc > optind + 1) {
11936                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
11937                 return rc;
11938         }
11939
11940         if (read_mirror_id == 0) {
11941                 fprintf(stderr,
11942                         "%s %s: no valid read mirror ID %d is provided\n",
11943                         progname, argv[0], read_mirror_id);
11944                 return rc;
11945         }
11946
11947         if (count == 0) {
11948                 fprintf(stderr,
11949                         "%s %s: no write mirror ID is provided\n",
11950                         progname, argv[0]);
11951                 return rc;
11952         }
11953
11954         for (i = 0; i < count; i++) {
11955                 if (read_mirror_id == ids[i]) {
11956                         fprintf(stderr,
11957                         "%s %s: read and write mirror ID cannot be the same\n",
11958                                 progname, argv[0]);
11959                         return rc;
11960                 }
11961         }
11962
11963         /* open mirror file */
11964         fname = argv[optind];
11965
11966         fd = open(fname, O_DIRECT | O_RDWR);
11967         if (fd < 0) {
11968                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
11969                         progname, argv[0], fname, strerror(errno));
11970                 return rc;
11971         }
11972
11973         /* write to all other mirrors */
11974         if (ids[0] == (__u16)-1) {
11975                 count = get_other_mirror_ids(fd, ids, read_mirror_id);
11976                 if (count <= 0) {
11977                         rc = count;
11978                         fprintf(stderr,
11979                         "%s %s: failed to get other mirror ids in '%s': %d\n",
11980                                 progname, argv[0], fname, rc);
11981                         goto close_fd;
11982                 }
11983         }
11984
11985         /* verify mirror id */
11986         rc = verify_mirror_id_by_fd(fd, read_mirror_id);
11987         if (rc) {
11988                 fprintf(stderr,
11989                         "%s %s: cannot find mirror with ID %u in '%s'\n",
11990                         progname, argv[0], read_mirror_id, fname);
11991                 goto close_fd;
11992         }
11993
11994         for (i = 0; i < count; i++) {
11995                 rc = verify_mirror_id_by_fd(fd, ids[i]);
11996                 if (rc) {
11997                         fprintf(stderr,
11998                         "%s %s: cannot find mirror with ID %u in '%s'\n",
11999                                 progname, argv[0], ids[i], fname);
12000                         goto close_fd;
12001                 }
12002         }
12003
12004         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
12005         if (!ioc) {
12006                 fprintf(stderr,
12007                         "%s %s: cannot alloc comp id array for ioc: %s\n",
12008                         progname, argv[0], strerror(errno));
12009                 rc = -errno;
12010                 goto close_fd;
12011         }
12012
12013         /* get stale component info */
12014         layout = llapi_layout_get_by_fd(fd, 0);
12015         if (!layout) {
12016                 fprintf(stderr, "%s %s: failed to get layout of '%s': %s\n",
12017                         progname, argv[0], fname, strerror(errno));
12018                 rc = -errno;
12019                 goto free_ioc;
12020         }
12021         comp_size = llapi_mirror_find_stale(layout, comp_array,
12022                                             ARRAY_SIZE(comp_array),
12023                                             ids, count);
12024         llapi_layout_free(layout);
12025         if (comp_size < 0) {
12026                 rc = comp_size;
12027                 goto free_ioc;
12028         }
12029
12030         /* prepare target mirror components instantiation */
12031         resync_ioc = (struct ll_ioc_lease_id *)ioc;
12032         resync_ioc->lil_mode = LL_LEASE_WRLCK;
12033         resync_ioc->lil_flags = LL_LEASE_RESYNC;
12034         if (count == 1)
12035                 resync_ioc->lil_mirror_id = ids[0];
12036         else
12037                 resync_ioc->lil_mirror_id = read_mirror_id | MIRROR_ID_NEG;
12038         rc = llapi_lease_set(fd, ioc);
12039         if (rc < 0) {
12040                 fprintf(stderr,
12041                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
12042                         progname, argv[0], fname, strerror(errno));
12043                 goto free_ioc;
12044         }
12045
12046         copied = llapi_mirror_copy_many(fd, read_mirror_id, ids, count);
12047         if (copied < 0) {
12048                 rc = copied;
12049                 fprintf(stderr, "%s %s: copy error: %d\n",
12050                         progname, argv[0], rc);
12051                 goto free_ioc;
12052         }
12053
12054         fprintf(stdout, "mirror copied successfully: ");
12055         for (i = 0; i < copied; i++)
12056                 fprintf(stdout, "%d ", ids[i]);
12057         fprintf(stdout, "\n");
12058
12059         ioc->lil_mode = LL_LEASE_UNLCK;
12060         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
12061         ioc->lil_count = 0;
12062         for (i = 0; i < comp_size; i++) {
12063                 int j;
12064
12065                 for (j = 0; j < copied; j++) {
12066                         if (comp_array[i].lrc_mirror_id != ids[j])
12067                                 continue;
12068
12069                         ioc->lil_ids[ioc->lil_count] = comp_array[i].lrc_id;
12070                         ioc->lil_count++;
12071                 }
12072         }
12073         rc = llapi_lease_set(fd, ioc);
12074         if (rc <= 0) {
12075                 if (rc == 0)
12076                         rc = -EBUSY;
12077                 fprintf(stderr,
12078                         "%s %s: release lease lock of '%s' failed: %s\n",
12079                         progname, argv[0], fname, strerror(errno));
12080                 goto free_ioc;
12081         }
12082
12083         rc = 0;
12084
12085 free_ioc:
12086         free(ioc);
12087 close_fd:
12088         close(fd);
12089
12090         return rc;
12091 }
12092
12093 /**
12094  * struct verify_chunk - Mirror chunk to be verified.
12095  * @chunk:        [start, end) of the chunk.
12096  * @mirror_count: Number of mirror ids in @mirror_id array.
12097  * @mirror_id:    Array of valid mirror ids that cover the chunk.
12098  */
12099 struct verify_chunk {
12100         struct lu_extent chunk;
12101         unsigned int mirror_count;
12102         __u16 mirror_id[LUSTRE_MIRROR_COUNT_MAX];
12103 };
12104
12105 /**
12106  * print_chunks() - Print chunk information.
12107  * @fname:       Mirrored file name.
12108  * @chunks:      Array of chunks.
12109  * @chunk_count: Number of chunks in @chunks array.
12110  *
12111  * This function prints [start, end) of each chunk in @chunks
12112  * for mirrored file @fname, and also prints the valid mirror ids
12113  * that cover the chunk.
12114  *
12115  * Return: void.
12116  */
12117 static inline
12118 void print_chunks(const char *fname, struct verify_chunk *chunks,
12119                   int chunk_count)
12120 {
12121         int i;
12122         int j;
12123
12124         fprintf(stdout, "Chunks to be verified in %s:\n", fname);
12125         for (i = 0; i < chunk_count; i++) {
12126                 fprintf(stdout, DEXT, PEXT(&chunks[i].chunk));
12127
12128                 if (chunks[i].mirror_count == 0)
12129                         fprintf(stdout, "\t[");
12130                 else {
12131                         fprintf(stdout, "\t[%u", chunks[i].mirror_id[0]);
12132                         for (j = 1; j < chunks[i].mirror_count; j++)
12133                                 fprintf(stdout, ", %u", chunks[i].mirror_id[j]);
12134                 }
12135                 fprintf(stdout, "]\t%u\n", chunks[i].mirror_count);
12136         }
12137         fprintf(stdout, "\n");
12138 }
12139
12140 /**
12141  * print_checksums() - Print CRC-32 checksum values.
12142  * @chunk: A chunk and its corresponding valid mirror ids.
12143  * @crc:   CRC-32 checksum values on the chunk for each valid mirror.
12144  *
12145  * This function prints CRC-32 checksum values on @chunk for
12146  * each valid mirror that covers it.
12147  *
12148  * Return: void.
12149  */
12150 static inline
12151 void print_checksums(struct verify_chunk *chunk, unsigned long *crc,
12152                      unsigned long long pos, unsigned long long len)
12153 {
12154         int i;
12155
12156         fprintf(stdout,
12157                 "CRC-32 checksum value for chunk "DEXT":\n", pos, pos + len);
12158         for (i = 0; i < chunk->mirror_count; i++)
12159                 fprintf(stdout, "Mirror %u:\t%#lx\n",
12160                         chunk->mirror_id[i], crc[i]);
12161         fprintf(stdout, "\n");
12162 }
12163
12164 /**
12165  * filter_mirror_id() - Filter specified mirror ids.
12166  * @chunks:      Array of chunks.
12167  * @chunk_count: Number of chunks in @chunks array.
12168  * @mirror_ids:  Specified mirror ids to be verified.
12169  * @ids_nr:      Number of specified mirror ids.
12170  *
12171  * This function scans valid mirror ids that cover each chunk in @chunks
12172  * and filters specified mirror ids.
12173  *
12174  * Return: void.
12175  */
12176 static inline
12177 void filter_mirror_id(struct verify_chunk *chunks, int chunk_count,
12178                       __u16 *mirror_ids, int ids_nr)
12179 {
12180         int i;
12181         int j;
12182         int k;
12183         __u16 valid_id[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
12184         unsigned int valid_count = 0;
12185
12186         for (i = 0; i < chunk_count; i++) {
12187                 if (chunks[i].mirror_count == 0)
12188                         continue;
12189
12190                 valid_count = 0;
12191                 for (j = 0; j < ids_nr; j++) {
12192                         for (k = 0; k < chunks[i].mirror_count; k++) {
12193                                 if (chunks[i].mirror_id[k] == mirror_ids[j]) {
12194                                         valid_id[valid_count] = mirror_ids[j];
12195                                         valid_count++;
12196                                         break;
12197                                 }
12198                         }
12199                 }
12200
12201                 memcpy(chunks[i].mirror_id, valid_id,
12202                        sizeof(__u16) * valid_count);
12203                 chunks[i].mirror_count = valid_count;
12204         }
12205 }
12206
12207 /**
12208  * lfs_mirror_prepare_chunk() - Find mirror chunks to be verified.
12209  * @layout:      Mirror component list.
12210  * @chunks:      Array of chunks.
12211  * @chunks_size: Array size of @chunks.
12212  *
12213  * This function scans the components in @layout from offset 0 to LUSTRE_EOF
12214  * to find out chunk segments and store them in @chunks array.
12215  *
12216  * The @mirror_id array in each element of @chunks will store the valid
12217  * mirror ids that cover the chunk. If a mirror component covering the
12218  * chunk has LCME_FL_STALE or LCME_FL_OFFLINE flag, then the mirror id
12219  * will not be stored into the @mirror_id array, and the chunk for that
12220  * mirror will not be verified.
12221  *
12222  * The @mirror_count in each element of @chunks will store the number of
12223  * mirror ids in @mirror_id array. If @mirror_count is 0, it indicates the
12224  * chunk is invalid in all of the mirrors. And if @mirror_count is 1, it
12225  * indicates the chunk is valid in only one mirror. In both cases, the
12226  * chunk will not be verified.
12227  *
12228  * Here is an example:
12229  *
12230  *  0      1M     2M     3M     4M           EOF
12231  *  +------+-------------+--------------------+
12232  *  |      |             |      S             |       mirror1
12233  *  +------+------+------+------+-------------+
12234  *  |             |   S  |   S  |             |       mirror2
12235  *  +-------------+------+------+-------------+
12236  *
12237  * prepared @chunks array will contain 5 elements:
12238  * (([0, 1M), [1, 2], 2),
12239  *  ([1M, 2M), [1, 2], 2),
12240  *  ([2M, 3M), [1], 1),
12241  *  ([3M, 4M], [], 0),
12242  *  ([4M, EOF), [2], 1))
12243  *
12244  * Return: the actual array size of @chunks on success
12245  *         or a negative error code on failure.
12246  */
12247 static inline
12248 int lfs_mirror_prepare_chunk(struct llapi_layout *layout,
12249                              struct verify_chunk *chunks,
12250                              size_t chunks_size)
12251 {
12252         uint64_t start;
12253         uint64_t end;
12254         uint32_t mirror_id;
12255         uint32_t flags;
12256         int idx = 0;
12257         int i = 0;
12258         int rc = 0;
12259
12260         memset(chunks, 0, sizeof(*chunks) * chunks_size);
12261
12262         while (1) {
12263                 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
12264                 if (rc < 0) {
12265                         fprintf(stderr,
12266                                 "%s: move to the first layout component: %s.\n",
12267                                 progname, strerror(errno));
12268                         goto error;
12269                 }
12270
12271                 i = 0;
12272                 rc = 0;
12273                 chunks[idx].chunk.e_end = LUSTRE_EOF;
12274                 while (rc == 0) {
12275                         rc = llapi_layout_comp_extent_get(layout, &start, &end);
12276                         if (rc < 0) {
12277                                 fprintf(stderr,
12278                                         "%s: llapi_layout_comp_extent_get failed: %s.\n",
12279                                         progname, strerror(errno));
12280                                 goto error;
12281                         }
12282
12283                         if (start > chunks[idx].chunk.e_start ||
12284                             end <= chunks[idx].chunk.e_start)
12285                                 goto next;
12286
12287                         if (end < chunks[idx].chunk.e_end)
12288                                 chunks[idx].chunk.e_end = end;
12289
12290                         rc = llapi_layout_comp_flags_get(layout, &flags);
12291                         if (rc < 0) {
12292                                 fprintf(stderr,
12293                                         "%s: llapi_layout_comp_flags_get failed: %s.\n",
12294                                         progname, strerror(errno));
12295                                 goto error;
12296                         }
12297
12298                         if (flags & LCME_FL_STALE || flags & LCME_FL_OFFLINE)
12299                                 goto next;
12300
12301                         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
12302                         if (rc < 0) {
12303                                 fprintf(stderr,
12304                                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
12305                                         progname, strerror(errno));
12306                                 goto error;
12307                         }
12308
12309                         if (i >= ARRAY_SIZE(chunks[idx].mirror_id)) {
12310                                 fprintf(stderr,
12311                                         "%s: mirror_id array is too small.\n",
12312                                         progname);
12313                                 rc = -EINVAL;
12314                                 goto error;
12315                         }
12316                         chunks[idx].mirror_id[i] = mirror_id;
12317                         i++;
12318
12319 next:
12320                         rc = llapi_layout_comp_use(layout,
12321                                                    LLAPI_LAYOUT_COMP_USE_NEXT);
12322                         if (rc < 0) {
12323                                 fprintf(stderr,
12324                                         "%s: move to the next layout component: %s.\n",
12325                                         progname, strerror(errno));
12326                                 goto error;
12327                         }
12328                 } /* loop through all components */
12329
12330                 chunks[idx].mirror_count = i;
12331
12332                 if (chunks[idx].chunk.e_end == LUSTRE_EOF)
12333                         break;
12334
12335                 idx++;
12336                 if (idx >= chunks_size) {
12337                         fprintf(stderr, "%s: chunks array is too small.\n",
12338                                 progname);
12339                         rc = -EINVAL;
12340                         goto error;
12341                 }
12342
12343                 chunks[idx].chunk.e_start = chunks[idx - 1].chunk.e_end;
12344         }
12345
12346 error:
12347         return rc < 0 ? rc : idx + 1;
12348 }
12349
12350 /**
12351  * lfs_mirror_verify_chunk() - Verify a chunk.
12352  * @fd:        File descriptor of the mirrored file.
12353  * @file_size: Size of the mirrored file.
12354  * @chunk:     A chunk and its corresponding valid mirror ids.
12355  * @verbose:   Verbose mode.
12356  *
12357  * This function verifies a @chunk contains exactly the same data
12358  * ammong the mirrors that cover it.
12359  *
12360  * If @verbose is specified, then the function will print where the
12361  * differences are if the data do not match. Otherwise, it will
12362  * just return an error in that case.
12363  *
12364  * Return: 0 on success or a negative error code on failure.
12365  */
12366 static inline
12367 int lfs_mirror_verify_chunk(int fd, size_t file_size,
12368                             struct verify_chunk *chunk, int verbose)
12369 {
12370         const size_t buflen = 4 * 1024 * 1024; /* 4M */
12371         void *buf;
12372         size_t page_size = sysconf(_SC_PAGESIZE);
12373         ssize_t bytes_read;
12374         ssize_t bytes_done;
12375         size_t count;
12376         off_t pos;
12377         unsigned long crc;
12378         unsigned long crc_array[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
12379         int i;
12380         int rc = 0;
12381
12382         if (file_size == 0)
12383                 return 0;
12384
12385         rc = posix_memalign(&buf, page_size, buflen);
12386         if (rc) /* error code is returned directly */
12387                 return -rc;
12388
12389         if (verbose > 1) {
12390                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
12391                         PEXT(&chunk->chunk));
12392                 for (i = 0; i < chunk->mirror_count; i++)
12393                         fprintf(stdout, " %u", chunk->mirror_id[i]);
12394                 fprintf(stdout, "\n");
12395         }
12396
12397         bytes_done = 0;
12398         count = MIN(chunk->chunk.e_end, file_size) - chunk->chunk.e_start;
12399         pos = chunk->chunk.e_start;
12400         while (bytes_done < count) {
12401                 /* compute initial CRC-32 checksum */
12402                 crc = crc32(0L, Z_NULL, 0);
12403                 memset(crc_array, 0, sizeof(crc_array));
12404
12405                 bytes_read = 0;
12406                 for (i = 0; i < chunk->mirror_count; i++) {
12407                         bytes_read = llapi_mirror_read(fd, chunk->mirror_id[i],
12408                                                        buf, buflen, pos);
12409                         if (bytes_read < 0) {
12410                                 rc = bytes_read;
12411                                 fprintf(stderr,
12412                                         "%s: failed to read data from mirror %u: %s.\n",
12413                                         progname, chunk->mirror_id[i],
12414                                         strerror(-rc));
12415                                 goto error;
12416                         }
12417
12418                         /* compute new CRC-32 checksum */
12419                         crc_array[i] = crc32(crc, buf, bytes_read);
12420                 }
12421
12422                 if (verbose)
12423                         print_checksums(chunk, crc_array, pos, buflen);
12424
12425                 /* compare CRC-32 checksum values */
12426                 for (i = 1; i < chunk->mirror_count; i++) {
12427                         if (crc_array[i] != crc_array[0]) {
12428                                 rc = -EINVAL;
12429
12430                                 fprintf(stderr,
12431                                         "%s: chunk "DEXT" has different checksum value on mirror %u and mirror %u.\n",
12432                                         progname, PEXT(&chunk->chunk),
12433                                         chunk->mirror_id[0],
12434                                         chunk->mirror_id[i]);
12435                         }
12436                 }
12437
12438                 pos += bytes_read;
12439                 bytes_done += bytes_read;
12440         }
12441
12442         if (verbose > 1 && rc == 0) {
12443                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
12444                         PEXT(&chunk->chunk));
12445                 for (i = 0; i < chunk->mirror_count; i++)
12446                         fprintf(stdout, " %u", chunk->mirror_id[i]);
12447                 fprintf(stdout, " PASS\n\n");
12448         }
12449
12450 error:
12451         free(buf);
12452         return rc;
12453 }
12454
12455 /**
12456  * lfs_mirror_verify_file() - Verify a mirrored file.
12457  * @fname:      Mirrored file name.
12458  * @mirror_ids: Specified mirror ids to be verified.
12459  * @ids_nr:     Number of specified mirror ids.
12460  * @verbose:    Verbose mode.
12461  *
12462  * This function verifies that each SYNC mirror of a mirrored file
12463  * specified by @fname contains exactly the same data.
12464  *
12465  * If @mirror_ids is specified, then the function will verify the
12466  * mirrors specified by @mirror_ids contain exactly the same data.
12467  *
12468  * If @verbose is specified, then the function will print where the
12469  * differences are if the data do not match. Otherwise, it will
12470  * just return an error in that case.
12471  *
12472  * Return: 0 on success or a negative error code on failure.
12473  */
12474 static inline
12475 int lfs_mirror_verify_file(const char *fname, __u16 *mirror_ids, int ids_nr,
12476                            int verbose)
12477 {
12478         struct verify_chunk chunks_array[1024] = { };
12479         struct llapi_layout *layout = NULL;
12480         struct stat stbuf;
12481         uint32_t flr_state;
12482         int fd;
12483         int chunk_count = 0;
12484         int idx = 0;
12485         int rc = 0;
12486         int rc1 = 0;
12487         int rc2 = 0;
12488
12489         if (stat(fname, &stbuf) < 0) {
12490                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
12491                         progname, fname, strerror(errno));
12492                 rc = -errno;
12493                 goto error;
12494         }
12495
12496         if (!S_ISREG(stbuf.st_mode)) {
12497                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
12498                         progname, fname);
12499                 rc = -EINVAL;
12500                 goto error;
12501         }
12502
12503         if (stbuf.st_size == 0) {
12504                 if (verbose)
12505                         fprintf(stdout, "%s: '%s' file size is 0.\n",
12506                                 progname, fname);
12507                 rc = 0;
12508                 goto error;
12509         }
12510
12511         /* Allow mirror verify even without the key on encrypted files */
12512         fd = open(fname, O_DIRECT | O_RDONLY | O_FILE_ENC);
12513         if (fd < 0) {
12514                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
12515                         progname, fname, strerror(errno));
12516                 rc = -errno;
12517                 goto error;
12518         }
12519
12520         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
12521         if (rc < 0) {
12522                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
12523                         progname, fname, strerror(errno));
12524                 goto close_fd;
12525         }
12526
12527         layout = llapi_layout_get_by_fd(fd, 0);
12528         if (!layout) {
12529                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
12530                         progname, fname, strerror(errno));
12531                 rc = -errno;
12532                 llapi_lease_release(fd);
12533                 goto close_fd;
12534         }
12535
12536         rc = llapi_layout_flags_get(layout, &flr_state);
12537         if (rc < 0) {
12538                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
12539                         progname, fname, strerror(errno));
12540                 rc = -errno;
12541                 goto free_layout;
12542         }
12543
12544         flr_state &= LCM_FL_FLR_MASK;
12545         switch (flr_state) {
12546         case LCM_FL_NONE:
12547                 rc = -EINVAL;
12548                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
12549                         progname, fname, llapi_layout_flags_string(flr_state));
12550                 goto free_layout;
12551         default:
12552                 break;
12553         }
12554
12555         /* find out mirror chunks to be verified */
12556         chunk_count = lfs_mirror_prepare_chunk(layout, chunks_array,
12557                                                ARRAY_SIZE(chunks_array));
12558         if (chunk_count < 0) {
12559                 rc = chunk_count;
12560                 goto free_layout;
12561         }
12562
12563         if (ids_nr > 0)
12564                 /* filter specified mirror ids */
12565                 filter_mirror_id(chunks_array, chunk_count, mirror_ids, ids_nr);
12566
12567         if (verbose > 2)
12568                 print_chunks(fname, chunks_array, chunk_count);
12569
12570         for (idx = 0; idx < chunk_count; idx++) {
12571                 if (chunks_array[idx].chunk.e_start >= stbuf.st_size) {
12572                         if (verbose)
12573                                 fprintf(stdout,
12574                                         "%s: '%s' chunk "DEXT" exceeds file size %#llx: skipped\n",
12575                                         progname, fname,
12576                                         PEXT(&chunks_array[idx].chunk),
12577                                         (unsigned long long)stbuf.st_size);
12578                         break;
12579                 }
12580
12581                 if (chunks_array[idx].mirror_count == 0) {
12582                         fprintf(stderr,
12583                                 "%s: '%s' chunk "DEXT" is invalid in all of the mirrors: ",
12584                                 progname, fname,
12585                                 PEXT(&chunks_array[idx].chunk));
12586                         if (verbose) {
12587                                 fprintf(stderr, "skipped\n");
12588                                 continue;
12589                         }
12590                         rc = -EINVAL;
12591                         fprintf(stderr, "failed\n");
12592                         goto free_layout;
12593                 }
12594
12595                 if (chunks_array[idx].mirror_count == 1) {
12596                         if (verbose)
12597                                 fprintf(stdout,
12598                                         "%s: '%s' chunk "DEXT" is only valid in mirror %u: skipped\n",
12599                                         progname, fname,
12600                                         PEXT(&chunks_array[idx].chunk),
12601                                         chunks_array[idx].mirror_id[0]);
12602                         continue;
12603                 }
12604
12605                 rc = llapi_lease_check(fd);
12606                 if (rc != LL_LEASE_RDLCK) {
12607                         fprintf(stderr, "%s: '%s' lost lease lock.\n",
12608                                 progname, fname);
12609                         goto free_layout;
12610                 }
12611
12612                 /* verify one chunk */
12613                 rc1 = lfs_mirror_verify_chunk(fd, stbuf.st_size,
12614                                               &chunks_array[idx], verbose);
12615                 if (rc1 < 0) {
12616                         rc2 = rc1;
12617                         if (!verbose) {
12618                                 rc = rc1;
12619                                 goto free_layout;
12620                         }
12621                 }
12622         }
12623
12624         if (rc2 < 0)
12625                 rc = rc2;
12626
12627 free_layout:
12628         llapi_layout_free(layout);
12629         llapi_lease_release(fd);
12630 close_fd:
12631         close(fd);
12632 error:
12633         return rc;
12634 }
12635
12636 /**
12637  * lfs_mirror_verify() - Parse and execute lfs mirror verify command.
12638  * @argc: The count of lfs mirror verify command line arguments.
12639  * @argv: Array of strings for lfs mirror verify command line arguments.
12640  *
12641  * This function parses lfs mirror verify command and verifies the
12642  * specified mirrored file(s).
12643  *
12644  * Return: 0 on success or a negative error code on failure.
12645  */
12646 static inline int lfs_mirror_verify(int argc, char **argv)
12647 {
12648         __u16 mirror_ids[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
12649         int ids_nr = 0;
12650         int c;
12651         int verbose = 0;
12652         int rc = 0;
12653         int rc1 = 0;
12654         char cmd[PATH_MAX];
12655
12656         struct option long_opts[] = {
12657         { .val = 'h',   .name = "help",         .has_arg = no_argument },
12658         { .val = 'o',   .name = "only",         .has_arg = required_argument },
12659         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
12660         { .name = NULL } };
12661
12662         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12663         progname = cmd;
12664         while ((c = getopt_long(argc, argv, "ho:v", long_opts, NULL)) >= 0) {
12665                 switch (c) {
12666                 case 'o':
12667                         rc = parse_mirror_ids(mirror_ids,
12668                                               ARRAY_SIZE(mirror_ids),
12669                                               optarg);
12670                         if (rc < 0) {
12671                                 fprintf(stderr,
12672                                         "%s: bad mirror ids '%s'.\n",
12673                                         progname, optarg);
12674                                 goto error;
12675                         }
12676                         ids_nr = rc;
12677                         if (ids_nr < 2) {
12678                                 fprintf(stderr,
12679                                         "%s: at least 2 mirror ids needed with '--only' option.\n",
12680                                         progname);
12681                                 rc = CMD_HELP;
12682                                 goto error;
12683                         }
12684                         break;
12685                 case 'v':
12686                         verbose++;
12687                         break;
12688                 default:
12689                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12690                                 progname, argv[optind - 1]);
12691                         fallthrough;
12692                 case 'h':
12693                         rc = CMD_HELP;
12694                         goto error;
12695                 }
12696         }
12697
12698         if (argc == optind) {
12699                 fprintf(stderr, "%s: no file name given.\n", progname);
12700                 rc = CMD_HELP;
12701                 goto error;
12702         }
12703
12704         if (ids_nr > 0 && argc > optind + 1) {
12705                 fprintf(stderr,
12706                         "%s: '--only' cannot be used upon multiple files.\n",
12707                         progname);
12708                 rc = CMD_HELP;
12709                 goto error;
12710         }
12711
12712         if (ids_nr > 0) {
12713                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
12714                 if (rc < 0)
12715                         goto error;
12716         }
12717
12718         rc = 0;
12719         for (; optind < argc; optind++) {
12720                 rc1 = lfs_mirror_verify_file(argv[optind], mirror_ids, ids_nr,
12721                                              verbose);
12722                 if (rc1 < 0)
12723                         rc = rc1;
12724         }
12725 error:
12726         return rc;
12727 }
12728
12729 /**
12730  * lfs_mirror() - Parse and execute lfs mirror commands.
12731  * @argc: The count of lfs mirror command line arguments.
12732  * @argv: Array of strings for lfs mirror command line arguments.
12733  *
12734  * This function parses lfs mirror commands and performs the
12735  * corresponding functions specified in mirror_cmdlist[].
12736  *
12737  * Return: 0 on success or an error code on failure.
12738  */
12739 static int lfs_mirror(int argc, char **argv)
12740 {
12741         char cmd[PATH_MAX];
12742         int rc = 0;
12743
12744         setlinebuf(stdout);
12745
12746         Parser_init("lfs-mirror > ", mirror_cmdlist);
12747
12748         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12749         progname = cmd;
12750         program_invocation_short_name = cmd;
12751         if (argc > 1)
12752                 rc = Parser_execarg(argc - 1, argv + 1, mirror_cmdlist);
12753         else
12754                 rc = Parser_commands();
12755
12756         return rc < 0 ? -rc : rc;
12757 }
12758
12759 static void lustre_som_swab(struct lustre_som_attrs *attrs)
12760 {
12761 #if __BYTE_ORDER == __BIG_ENDIAN
12762         __swab16s(&attrs->lsa_valid);
12763         __swab64s(&attrs->lsa_size);
12764         __swab64s(&attrs->lsa_blocks);
12765 #endif
12766 }
12767
12768 enum lfs_som_type {
12769         LFS_SOM_SIZE = 0x1,
12770         LFS_SOM_BLOCKS = 0x2,
12771         LFS_SOM_FLAGS = 0x4,
12772         LFS_SOM_ATTR_ALL = LFS_SOM_SIZE | LFS_SOM_BLOCKS |
12773                            LFS_SOM_FLAGS,
12774 };
12775
12776 static int lfs_getsom(int argc, char **argv)
12777 {
12778         const char *path;
12779         struct lustre_som_attrs *attrs;
12780         char buf[sizeof(*attrs) + 64];
12781         enum lfs_som_type type = LFS_SOM_ATTR_ALL;
12782         int rc = 0, c;
12783
12784         while ((c = getopt(argc, argv, "bfhs")) != -1) {
12785                 switch (c) {
12786                 case 'b':
12787                         type = LFS_SOM_BLOCKS;
12788                         break;
12789                 case 'f':
12790                         type = LFS_SOM_FLAGS;
12791                         break;
12792                 case 's':
12793                         type = LFS_SOM_SIZE;
12794                         break;
12795                 default:
12796                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12797                                 progname, argv[optind - 1]);
12798                         fallthrough;
12799                 case 'h':
12800                         return CMD_HELP;
12801                 }
12802         }
12803
12804         argc -= optind;
12805         argv += optind;
12806
12807         if (argc != 1) {
12808                 fprintf(stderr, "%s: %s\n",
12809                         progname, argc == 0 ? "miss file target" :
12810                         "input more than 2 files");
12811                 return CMD_HELP;
12812         }
12813
12814         path = argv[0];
12815         attrs = (void *)buf;
12816         rc = lgetxattr(path, "trusted.som", attrs, sizeof(buf));
12817         if (rc < 0) {
12818                 rc = -errno;
12819                 fprintf(stderr, "%s failed to get som xattr: %s (%d)\n",
12820                         argv[0], strerror(errno), errno);
12821                 return rc;
12822         }
12823
12824         lustre_som_swab(attrs);
12825
12826         switch (type) {
12827         case LFS_SOM_ATTR_ALL:
12828                 printf("file: %s size: %llu blocks: %llu flags: %x\n",
12829                        path, (unsigned long long)attrs->lsa_size,
12830                        (unsigned long long)attrs->lsa_blocks,
12831                        attrs->lsa_valid);
12832                 break;
12833         case LFS_SOM_SIZE:
12834                 printf("%llu\n", (unsigned long long)attrs->lsa_size);
12835                 break;
12836         case LFS_SOM_BLOCKS:
12837                 printf("%llu\n", (unsigned long long)attrs->lsa_blocks);
12838                 break;
12839         case LFS_SOM_FLAGS:
12840                 printf("%x\n", attrs->lsa_valid);
12841                 break;
12842         default:
12843                 fprintf(stderr, "%s: unknown option\n", progname);
12844                 return CMD_HELP;
12845         }
12846
12847         return 0;
12848 }
12849
12850 /**
12851  * lfs_mirror_list_commands() - List lfs mirror commands.
12852  * @argc: The count of command line arguments.
12853  * @argv: Array of strings for command line arguments.
12854  *
12855  * This function lists lfs mirror commands defined in mirror_cmdlist[].
12856  *
12857  * Return: 0 on success.
12858  */
12859 static int lfs_mirror_list_commands(int argc, char **argv)
12860 {
12861         Parser_list_commands(mirror_cmdlist, 80, 4);
12862
12863         return 0;
12864 }
12865
12866 static int lfs_pcc_attach(int argc, char **argv)
12867 {
12868         struct option long_opts[] = {
12869         { .val = 'h',   .name = "help", .has_arg = no_argument },
12870         { .val = 'i',   .name = "id",   .has_arg = required_argument },
12871         { .name = NULL } };
12872         int c;
12873         int rc = 0;
12874         __u32 archive_id = 0;
12875         const char *path;
12876         char *end;
12877         char fullpath[PATH_MAX];
12878         enum lu_pcc_type type = LU_PCC_READWRITE;
12879
12880         optind = 0;
12881         while ((c = getopt_long(argc, argv, "hi:",
12882                                 long_opts, NULL)) != -1) {
12883                 switch (c) {
12884                 case 'i':
12885                         errno = 0;
12886                         archive_id = strtoul(optarg, &end, 0);
12887                         if (errno != 0 || *end != '\0' ||
12888                             archive_id == 0 || archive_id > UINT32_MAX) {
12889                                 fprintf(stderr,
12890                                         "error: %s: bad archive ID '%s'\n",
12891                                         progname, optarg);
12892                                 return CMD_HELP;
12893                         }
12894                         break;
12895                 default:
12896                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12897                                 progname, argv[optind - 1]);
12898                         fallthrough;
12899                 case 'h':
12900                         return CMD_HELP;
12901                 }
12902         }
12903
12904         if (archive_id == 0) {
12905                 fprintf(stderr, "%s: must specify attach ID\n", argv[0]);
12906                 return CMD_HELP;
12907         }
12908
12909         if (argc <= optind) {
12910                 fprintf(stderr, "%s: must specify one or more file names\n",
12911                         argv[0]);
12912                 return CMD_HELP;
12913         }
12914
12915         while (optind < argc) {
12916                 int rc2;
12917
12918                 path = argv[optind++];
12919                 if (!realpath(path, fullpath)) {
12920                         fprintf(stderr, "%s: could not find path '%s': %s\n",
12921                                 argv[0], path, strerror(errno));
12922                         if (rc == 0)
12923                                 rc = -EINVAL;
12924                         continue;
12925                 }
12926
12927                 rc2 = llapi_pcc_attach(fullpath, archive_id, type);
12928                 if (rc2 < 0) {
12929                         fprintf(stderr,
12930                                 "%s: cannot attach '%s' to PCC with archive ID '%u': %s\n",
12931                                 argv[0], path, archive_id, strerror(-rc2));
12932                         if (rc == 0)
12933                                 rc = rc2;
12934                 }
12935         }
12936         return rc;
12937 }
12938
12939 static int lfs_pcc_attach_fid(int argc, char **argv)
12940 {
12941         struct option long_opts[] = {
12942         { .val = 'h',   .name = "help", .has_arg = no_argument },
12943         { .val = 'i',   .name = "id",   .has_arg = required_argument },
12944         { .val = 'm',   .name = "mnt",  .has_arg = required_argument },
12945         { .name = NULL } };
12946         int c;
12947         int rc = 0;
12948         __u32 archive_id = 0;
12949         char *end;
12950         const char *mntpath = NULL;
12951         const char *fidstr;
12952         enum lu_pcc_type type = LU_PCC_READWRITE;
12953
12954         optind = 0;
12955         while ((c = getopt_long(argc, argv, "hi:m:",
12956                                 long_opts, NULL)) != -1) {
12957                 switch (c) {
12958                 case 'i':
12959                         errno = 0;
12960                         archive_id = strtoul(optarg, &end, 0);
12961                         if (errno != 0 || *end != '\0' ||
12962                             archive_id > UINT32_MAX) {
12963                                 fprintf(stderr,
12964                                         "error: %s: bad archive ID '%s'\n",
12965                                         argv[0], optarg);
12966                                 return CMD_HELP;
12967                         }
12968                         break;
12969                 case 'm':
12970                         mntpath = optarg;
12971                         break;
12972                 default:
12973                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12974                                 progname, argv[optind - 1]);
12975                         fallthrough;
12976                 case 'h':
12977                         return CMD_HELP;
12978                 }
12979         }
12980
12981         if (archive_id == 0) {
12982                 fprintf(stderr, "%s: must specify an archive ID\n", argv[0]);
12983                 return CMD_HELP;
12984         }
12985
12986         if (!mntpath) {
12987                 fprintf(stderr, "%s: must specify Lustre mount point\n",
12988                         argv[0]);
12989                 return CMD_HELP;
12990         }
12991
12992         if (argc <= optind) {
12993                 fprintf(stderr, "%s: must specify one or more fids\n", argv[0]);
12994                 return CMD_HELP;
12995         }
12996
12997         while (optind < argc) {
12998                 int rc2;
12999
13000                 fidstr = argv[optind++];
13001
13002                 rc2 = llapi_pcc_attach_fid_str(mntpath, fidstr,
13003                                                archive_id, type);
13004                 if (rc2 < 0) {
13005                         fprintf(stderr,
13006                                 "%s: cannot attach '%s' on '%s' to PCC with archive ID '%u': %s\n",
13007                                 argv[0], fidstr, mntpath, archive_id,
13008                                 strerror(rc2));
13009                 }
13010                 if (rc == 0 && rc2 < 0)
13011                         rc = rc2;
13012         }
13013         return rc;
13014 }
13015
13016 static int lfs_pcc_detach(int argc, char **argv)
13017 {
13018         struct option long_opts[] = {
13019         { .val = 'h',   .name = "help", .has_arg = no_argument },
13020         { .val = 'k',   .name = "keep", .has_arg = no_argument },
13021         { .name = NULL } };
13022         int c;
13023         int rc = 0;
13024         const char *path;
13025         char fullpath[PATH_MAX];
13026         __u32 detach_opt = PCC_DETACH_OPT_UNCACHE;
13027
13028         optind = 0;
13029         while ((c = getopt_long(argc, argv, "hk",
13030                                 long_opts, NULL)) != -1) {
13031                 switch (c) {
13032                 case 'k':
13033                         detach_opt = PCC_DETACH_OPT_NONE;
13034                         break;
13035                 default:
13036                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13037                                 progname, argv[optind - 1]);
13038                         fallthrough;
13039                 case 'h':
13040                         return CMD_HELP;
13041                 }
13042         }
13043
13044         while (optind < argc) {
13045                 int rc2;
13046
13047                 path = argv[optind++];
13048                 if (!realpath(path, fullpath)) {
13049                         fprintf(stderr, "%s: could not find path '%s': %s\n",
13050                                 argv[0], path, strerror(errno));
13051                         if (rc == 0)
13052                                 rc = -EINVAL;
13053                         continue;
13054                 }
13055
13056                 rc2 = llapi_pcc_detach_file(fullpath, detach_opt);
13057                 if (rc2 < 0) {
13058                         rc2 = -errno;
13059                         fprintf(stderr,
13060                                 "%s: cannot detach '%s' from PCC: %s\n",
13061                                 argv[0], path, strerror(errno));
13062                         if (rc == 0)
13063                                 rc = rc2;
13064                 }
13065         }
13066         return rc;
13067 }
13068
13069 static int lfs_pcc_detach_fid(int argc, char **argv)
13070 {
13071         struct option long_opts[] = {
13072         { .val = 'h',   .name = "help", .has_arg = no_argument },
13073         { .val = 'k',   .name = "keep", .has_arg = no_argument },
13074         { .name = NULL } };
13075         int c;
13076         int rc = 0;
13077         const char *fid;
13078         const char *mntpath;
13079         __u32 detach_opt = PCC_DETACH_OPT_UNCACHE;
13080
13081         optind = 0;
13082         while ((c = getopt_long(argc, argv, "hk",
13083                                 long_opts, NULL)) != -1) {
13084                 switch (c) {
13085                 case 'k':
13086                         detach_opt = PCC_DETACH_OPT_NONE;
13087                         break;
13088                 default:
13089                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13090                                 progname, argv[optind - 1]);
13091                         fallthrough;
13092                 case 'h':
13093                         return CMD_HELP;
13094                 }
13095         }
13096
13097         mntpath = argv[optind++];
13098
13099         while (optind < argc) {
13100                 int rc2;
13101
13102                 fid = argv[optind++];
13103
13104                 rc2 = llapi_pcc_detach_fid_str(mntpath, fid, detach_opt);
13105                 if (rc2 < 0) {
13106                         fprintf(stderr,
13107                                 "%s: cannot detach '%s' on '%s' from PCC: %s\n",
13108                                 argv[0], fid, mntpath, strerror(-rc2));
13109                         if (rc == 0)
13110                                 rc = rc2;
13111                 }
13112         }
13113         return rc;
13114 }
13115
13116 static int lfs_pcc_state(int argc, char **argv)
13117 {
13118         int rc = 0;
13119         const char *path;
13120         char fullpath[PATH_MAX];
13121         struct lu_pcc_state state;
13122
13123         optind = 1;
13124
13125         if (argc <= 1) {
13126                 fprintf(stderr, "%s: must specify one or more file names\n",
13127                         progname);
13128                 return CMD_HELP;
13129         }
13130
13131         while (optind < argc) {
13132                 int rc2;
13133
13134                 path = argv[optind++];
13135                 if (!realpath(path, fullpath)) {
13136                         fprintf(stderr, "%s: could not find path '%s': %s\n",
13137                                 argv[0], path, strerror(errno));
13138                         if (rc == 0)
13139                                 rc = -EINVAL;
13140                         continue;
13141                 }
13142
13143                 rc2 = llapi_pcc_state_get(fullpath, &state);
13144                 if (rc2 < 0) {
13145                         if (rc == 0)
13146                                 rc = rc2;
13147                         fprintf(stderr,
13148                                 "%s: cannot get PCC state of '%s': %s\n",
13149                                 argv[0], path, strerror(-rc2));
13150                         continue;
13151                 }
13152
13153                 printf("file: %s", path);
13154                 printf(", type: %s", pcc_type2string(state.pccs_type));
13155                 if (state.pccs_type == LU_PCC_NONE &&
13156                     state.pccs_open_count == 0) {
13157                         printf("\n");
13158                         continue;
13159                 }
13160
13161                 printf(", PCC file: %s", state.pccs_path);
13162                 printf(", user number: %u", state.pccs_open_count);
13163                 printf(", flags: %x", state.pccs_flags);
13164                 printf("\n");
13165         }
13166         return rc;
13167 }
13168
13169 /**
13170  * lfs_pcc_list_commands() - List lfs pcc commands.
13171  * @argc: The count of command line arguments.
13172  * @argv: Array of strings for command line arguments.
13173  *
13174  * This function lists lfs pcc commands defined in pcc_cmdlist[].
13175  *
13176  * Return: 0 on success.
13177  */
13178 static int lfs_pcc_list_commands(int argc, char **argv)
13179 {
13180         Parser_list_commands(pcc_cmdlist, 80, 4);
13181
13182         return 0;
13183 }
13184
13185 /**
13186  * lfs_pcc() - Parse and execute lfs pcc commands.
13187  * @argc: The count of lfs pcc command line arguments.
13188  * @argv: Array of strings for lfs pcc command line arguments.
13189  *
13190  * This function parses lfs pcc commands and performs the
13191  * corresponding functions specified in pcc_cmdlist[].
13192  *
13193  * Return: 0 on success or an error code on failure.
13194  */
13195 static int lfs_pcc(int argc, char **argv)
13196 {
13197         char cmd[PATH_MAX];
13198         int rc = 0;
13199
13200         setlinebuf(stdout);
13201
13202         Parser_init("lfs-pcc > ", pcc_cmdlist);
13203
13204         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
13205         progname = cmd;
13206         program_invocation_short_name = cmd;
13207         if (argc > 1)
13208                 rc = Parser_execarg(argc - 1, argv + 1, pcc_cmdlist);
13209         else
13210                 rc = Parser_commands();
13211
13212         return rc < 0 ? -rc : rc;
13213 }
13214
13215 static int lfs_list_commands(int argc, char **argv)
13216 {
13217         Parser_list_commands(cmdlist, 80, 4);
13218
13219         return 0;
13220 }
13221
13222 int main(int argc, char **argv)
13223 {
13224         int rc;
13225
13226         /* Ensure that liblustreapi constructor has run */
13227         if (!llapi_liblustreapi_initialized())
13228                 fprintf(stderr, "liblustreapi was not properly initialized\n");
13229
13230         setlinebuf(stdout);
13231         opterr = 0;
13232
13233         Parser_init("lfs > ", cmdlist);
13234
13235         progname = program_invocation_short_name; /* Used in error messages */
13236         if (argc > 1) {
13237                 llapi_set_command_name(argv[1]);
13238                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
13239                 llapi_clear_command_name();
13240         } else {
13241                 rc = Parser_commands();
13242         }
13243
13244         Parser_exit(argc, argv);
13245
13246         return rc < 0 ? -rc : rc;
13247 }
13248
13249 #ifdef _LUSTRE_IDL_H_
13250 /* Everything we need here should be included by lustreapi.h. */
13251 # error "lfs should not depend on lustre_idl.h"
13252 #endif /* _LUSTRE_IDL_H_ */