Whamcloud - gitweb
LU-930 doc: update lfs migrate usage and man page
[fs/lustre-release.git] / lustre / utils / lfs.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  *
31  * lustre/utils/lfs.c
32  *
33  * Author: Peter J. Braam <braam@clusterfs.com>
34  * Author: Phil Schwan <phil@clusterfs.com>
35  * Author: Robert Read <rread@clusterfs.com>
36  */
37
38 /* for O_DIRECTORY */
39 #ifndef _GNU_SOURCE
40 #define _GNU_SOURCE
41 #endif
42
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <inttypes.h>
46 #include <getopt.h>
47 #include <string.h>
48 #include <mntent.h>
49 #include <unistd.h>
50 #include <errno.h>
51 #include <err.h>
52 #include <pwd.h>
53 #include <grp.h>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
56 #include <sys/time.h>
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <sys/param.h>
60 #include <sys/xattr.h>
61 #include <fcntl.h>
62 #include <dirent.h>
63 #include <time.h>
64 #include <ctype.h>
65 #include <zlib.h>
66 #include <libgen.h>
67 #include <asm/byteorder.h>
68 #include "lfs_project.h"
69
70 #include <libcfs/util/string.h>
71 #include <libcfs/util/ioctl.h>
72 #include <libcfs/util/parser.h>
73 #include <libcfs/util/string.h>
74 #include <lustre/lustreapi.h>
75 #include <linux/lustre/lustre_ver.h>
76 #include <linux/lustre/lustre_param.h>
77 #include <linux/lnet/nidstr.h>
78 #include <lnetconfig/cyaml.h>
79 #include "lstddef.h"
80
81 /* all functions */
82 static int lfs_find(int argc, char **argv);
83 static int lfs_getstripe(int argc, char **argv);
84 static int lfs_getdirstripe(int argc, char **argv);
85 static int lfs_setdirstripe(int argc, char **argv);
86 static int lfs_rmentry(int argc, char **argv);
87 static int lfs_unlink_foreign(int argc, char **argv);
88 static int lfs_osts(int argc, char **argv);
89 static int lfs_mdts(int argc, char **argv);
90 static int lfs_df(int argc, char **argv);
91 static int lfs_getname(int argc, char **argv);
92 static int lfs_check(int argc, char **argv);
93 #ifdef HAVE_SYS_QUOTA_H
94 static int lfs_setquota(int argc, char **argv);
95 static int lfs_quota(int argc, char **argv);
96 static int lfs_project(int argc, char **argv);
97 #endif
98 static int lfs_flushctx(int argc, char **argv);
99 static int lfs_poollist(int argc, char **argv);
100 static int lfs_changelog(int argc, char **argv);
101 static int lfs_changelog_clear(int argc, char **argv);
102 static int lfs_fid2path(int argc, char **argv);
103 static int lfs_path2fid(int argc, char **argv);
104 static int lfs_rmfid(int argc, char **argv);
105 static int lfs_data_version(int argc, char **argv);
106 static int lfs_hsm_state(int argc, char **argv);
107 static int lfs_hsm_set(int argc, char **argv);
108 static int lfs_hsm_clear(int argc, char **argv);
109 static int lfs_hsm_action(int argc, char **argv);
110 static int lfs_hsm_archive(int argc, char **argv);
111 static int lfs_hsm_restore(int argc, char **argv);
112 static int lfs_hsm_release(int argc, char **argv);
113 static int lfs_hsm_remove(int argc, char **argv);
114 static int lfs_hsm_cancel(int argc, char **argv);
115 static int lfs_swap_layouts(int argc, char **argv);
116 static int lfs_mv(int argc, char **argv);
117 static int lfs_ladvise(int argc, char **argv);
118 static int lfs_getsom(int argc, char **argv);
119 static int lfs_heat_get(int argc, char **argv);
120 static int lfs_heat_set(int argc, char **argv);
121 static int lfs_mirror(int argc, char **argv);
122 static int lfs_mirror_list_commands(int argc, char **argv);
123 static int lfs_list_commands(int argc, char **argv);
124 static inline int lfs_mirror_resync(int argc, char **argv);
125 static inline int lfs_mirror_verify(int argc, char **argv);
126 static inline int lfs_mirror_read(int argc, char **argv);
127 static inline int lfs_mirror_write(int argc, char **argv);
128 static inline int lfs_mirror_copy(int argc, char **argv);
129 static int lfs_pcc_attach(int argc, char **argv);
130 static int lfs_pcc_attach_fid(int argc, char **argv);
131 static int lfs_pcc_detach(int argc, char **argv);
132 static int lfs_pcc_detach_fid(int argc, char **argv);
133 static int lfs_pcc_state(int argc, char **argv);
134 static int lfs_pcc(int argc, char **argv);
135 static int lfs_pcc_list_commands(int argc, char **argv);
136 static int lfs_migrate_to_dom(int fd, int fdv, char *name,
137                               __u64 migration_flags,
138                               struct llapi_stripe_param *param,
139                               struct llapi_layout *layout);
140
141 struct pool_to_id_cbdata {
142         const char *pool;
143         __u32 id;
144 };
145 static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata);
146 static int find_mirror_id_by_pool(struct llapi_layout *layout, void *cbdata);
147
148 enum setstripe_origin {
149         SO_SETSTRIPE,
150         SO_MIGRATE,
151         SO_MIGRATE_MDT,
152         SO_MIRROR_CREATE,
153         SO_MIRROR_EXTEND,
154         SO_MIRROR_SPLIT,
155         SO_MIRROR_DELETE,
156 };
157
158 static int lfs_setstripe_internal(int argc, char **argv,
159                                   enum setstripe_origin opc);
160
161 static inline int lfs_setstripe(int argc, char **argv)
162 {
163         return lfs_setstripe_internal(argc, argv, SO_SETSTRIPE);
164 }
165
166 static inline int lfs_setstripe_migrate(int argc, char **argv)
167 {
168         return lfs_setstripe_internal(argc, argv, SO_MIGRATE);
169 }
170
171 static inline int lfs_mirror_create(int argc, char **argv)
172 {
173         return lfs_setstripe_internal(argc, argv, SO_MIRROR_CREATE);
174 }
175
176 static inline int lfs_mirror_extend(int argc, char **argv)
177 {
178         return lfs_setstripe_internal(argc, argv, SO_MIRROR_EXTEND);
179 }
180
181 static inline int lfs_mirror_split(int argc, char **argv)
182 {
183         return lfs_setstripe_internal(argc, argv, SO_MIRROR_SPLIT);
184 }
185
186 static inline int lfs_mirror_delete(int argc, char **argv)
187 {
188         return lfs_setstripe_internal(argc, argv, SO_MIRROR_DELETE);
189 }
190
191 /* Setstripe and migrate share mostly the same parameters */
192 #define SSM_CMD_COMMON(cmd) \
193         "usage: "cmd" [--component-end|-E COMP_END]\n"                  \
194         "                 [--copy=LUSTRE_SRC]\n"                        \
195         "                 [--extension-size|--ext-size|-z SIZE]\n"      \
196         "                 [--help|-h] [--layout|-L PATTERN]\n"          \
197         "                 [--layout|-L PATTERN]\n"                      \
198         "                 [--mirror-count|-N[MIRROR_COUNT]]\n"          \
199         "                 [--ost|-o OST_INDICES]\n"                     \
200         "                 [--overstripe-count|-C STRIPE_COUNT]\n"       \
201         "                 [--pool|-p POOL_NAME]\n"                      \
202         "                 [--stripe-count|-c STRIPE_COUNT]\n"           \
203         "                 [--stripe-index|-i START_OST_IDX]\n"          \
204         "                 [--stripe-size|-S STRIPE_SIZE]\n"             \
205         "                 [--yaml|-y YAML_TEMPLATE_FILE]\n"
206
207 #define MIRROR_EXTEND_USAGE                                             \
208         "                 {--mirror-count|-N[MIRROR_COUNT]}\n"          \
209         "                 [SETSTRIPE_OPTIONS|-f|--file VICTIM_FILE]\n"  \
210         "                 [--no-verify]\n"
211
212 #define SETSTRIPE_USAGE                                                 \
213         SSM_CMD_COMMON("setstripe")                                     \
214         MIRROR_EXTEND_USAGE                                             \
215         "                 DIRECTORY|FILENAME\n"
216
217 #define MIGRATE_USAGE                                                   \
218         SSM_CMD_COMMON("migrate  ")                                     \
219         "                 [--block|-b] [--non-block|-n]\n"              \
220         "                 [--non-direct|-D] [--verbose|-v]\n"           \
221         "                 FILENAME\n"
222
223 #define SETDIRSTRIPE_USAGE                                              \
224         "               [--mdt-count|-c stripe_count>\n"                \
225         "               [--help|-h] [--mdt-hash|-H mdt_hash]\n"         \
226         "               [--mdt-index|-i mdt_index[,mdt_index,...]\n"    \
227         "               [--default|-D] [--mode|-o mode]\n"              \
228         "               [--max-inherit|-X max_inherit]\n"               \
229         "               [--max-inherit-rr max_inherit_rr] <dir>\n"      \
230         "To create dir with a foreign (free format) layout :\n"         \
231         "setdirstripe|mkdir --foreign[=FOREIGN_TYPE] -x|-xattr STRING " \
232         "               [--mode|-o MODE] [--flags HEX] DIRECTORY\n"
233
234 /**
235  * command_t mirror_cmdlist - lfs mirror commands.
236  */
237 command_t mirror_cmdlist[] = {
238         { .pc_name = "create", .pc_func = lfs_mirror_create,
239           .pc_help = "Create a mirrored file.\n"
240                 "usage: lfs mirror create --mirror-count|-N[MIRROR_COUNT]\n"
241                 "           [SETSTRIPE_OPTIONS] ... FILENAME|DIRECTORY ...\n" },
242         { .pc_name = "delete", .pc_func = lfs_mirror_delete,
243           .pc_help = "Delete a mirror from a file.\n"
244         "usage: lfs mirror delete {--mirror-id <mirror_id> |\n"
245         "\t               --component-id|--comp-id|-I COMP_ID |\n"
246         "\t               -p <pool>} MIRRORED_FILE ...\n"
247         },
248         { .pc_name = "extend", .pc_func = lfs_mirror_extend,
249           .pc_help = "Extend a mirrored file.\n"
250                 "usage: lfs mirror extend "
251                 "{--mirror-count|-N[MIRROR_COUNT]} [--no-verify] "
252                 "[SETSTRIPE_OPTIONS|-f VICTIM_FILE] ... FILENAME ...\n" },
253         { .pc_name = "split", .pc_func = lfs_mirror_split,
254           .pc_help = "Split a mirrored file.\n"
255         "usage: lfs mirror split {--mirror-id MIRROR_ID |\n"
256         "\t             --component-id|-I COMP_ID|-p POOL} [--destroy|-d]\n"
257         "\t             [-f NEW_FILE] MIRRORED_FILE ...\n" },
258         { .pc_name = "read", .pc_func = lfs_mirror_read,
259           .pc_help = "Read the content of a specified mirror of a file.\n"
260                 "usage: lfs mirror read {--mirror-id|-N MIRROR_ID}\n"
261                 "\t\t[--outfile|-o <output_file>] <mirrored_file>\n" },
262         { .pc_name = "write", .pc_func = lfs_mirror_write,
263           .pc_help = "Write to a specified mirror of a file.\n"
264                 "usage: lfs mirror write {--mirror-id|-N MIRROR_ID}\n"
265                 "\t\t[--inputfile|-i <input_file>] <mirrored_file>\n" },
266         { .pc_name = "copy", .pc_func = lfs_mirror_copy,
267           .pc_help = "Copy a specified mirror to other mirror(s) of a file.\n"
268                 "usage: lfs mirror copy {--read-mirror|-i MIRROR_ID0}\n"
269                 "\t\t{--write-mirror|-o MIRROR_ID1[,...]} <mirrored_file>\n" },
270         { .pc_name = "resync", .pc_func = lfs_mirror_resync,
271           .pc_help = "Resynchronizes out-of-sync mirrored file(s).\n"
272                 "usage: lfs mirror resync [--only MIRROR_ID[,...]>]\n"
273                 "\t\t<mirrored_file> [<mirrored_file2>...]\n" },
274         { .pc_name = "verify", .pc_func = lfs_mirror_verify,
275           .pc_help = "Verify mirrored file(s).\n"
276                 "usage: lfs mirror verify [--only MIRROR_ID[,...]]\n"
277                 "\t\t[--verbose|-v] <mirrored_file> [<mirrored_file2> ...]\n" },
278         { .pc_name = "list-commands", .pc_func = lfs_mirror_list_commands,
279           .pc_help = "list commands supported by lfs mirror"},
280         { .pc_name = "help", .pc_func = Parser_help, .pc_help = "help" },
281         { .pc_name = "exit", .pc_func = Parser_quit, .pc_help = "quit" },
282         { .pc_name = "quit", .pc_func = Parser_quit, .pc_help = "quit" },
283         { .pc_help = NULL }
284 };
285
286 /**
287  * command_t pcc_cmdlist - lfs pcc commands.
288  */
289 command_t pcc_cmdlist[] = {
290         { .pc_name = "attach", .pc_func = lfs_pcc_attach,
291           .pc_help = "Attach given files to the Persistent Client Cache.\n"
292                 "usage: lfs pcc attach <--id|-i NUM> <file> ...\n"
293                 "\t-i: archive id for RW-PCC\n" },
294         { .pc_name = "attach_fid", .pc_func = lfs_pcc_attach_fid,
295           .pc_help = "Attach given files into PCC by FID(s).\n"
296                 "usage: lfs pcc attach_id {--id|-i NUM} {--mnt|-m MOUNTPOINT} FID ...\n"
297                 "\t-i: archive id for RW-PCC\n"
298                 "\t-m: Lustre mount point\n" },
299         { .pc_name = "state", .pc_func = lfs_pcc_state,
300           .pc_help = "Display the PCC state for given files.\n"
301                 "usage: lfs pcc state <file> ...\n" },
302         { .pc_name = "detach", .pc_func = lfs_pcc_detach,
303           .pc_help = "Detach given files from the Persistent Client Cache.\n"
304                 "usage: lfs pcc detach <file> ...\n" },
305         { .pc_name = "detach_fid", .pc_func = lfs_pcc_detach_fid,
306           .pc_help = "Detach given files from PCC by FID(s).\n"
307                 "usage: lfs pcc detach_fid <mntpath> <fid>...\n" },
308         { .pc_name = "list-commands", .pc_func = lfs_pcc_list_commands,
309           .pc_help = "list commands supported by lfs pcc"},
310         { .pc_name = "help", .pc_func = Parser_help, .pc_help = "help" },
311         { .pc_name = "exit", .pc_func = Parser_quit, .pc_help = "quit" },
312         { .pc_name = "quit", .pc_func = Parser_quit, .pc_help = "quit" },
313         { .pc_help = NULL }
314 };
315
316 /* all available commands */
317 command_t cmdlist[] = {
318         {"setstripe", lfs_setstripe, 0,
319          "To create a file with specified striping/composite layout, or\n"
320          "create/replace the default layout on an existing directory:\n"
321          SSM_CMD_COMMON("setstripe")
322          "                 [--mode MODE]\n"
323          "                 <directory|filename>\n"
324          " or\n"
325          "To add component(s) to an existing composite file:\n"
326          SSM_CMD_COMMON("setstripe --component-add")
327          "To totally delete the default striping from an existing directory:\n"
328          "usage: setstripe [--delete|-d] <directory>\n"
329          " or\n"
330          "To create a mirrored file or set s default mirror layout on a directory:\n"
331          "usage: setstripe {--mirror-count|-N}[MIRROR_COUNT] [SETSTRIPE_OPTIONS] <directory|filename>\n"
332          " or\n"
333          "To delete the last component(s) from an existing composite file\n"
334          "(note that this will also delete any data in those components):\n"
335          "usage: setstripe --component-del [--component-id|-I COMP_ID]\n"
336          "                               [--component-flags|-F COMP_FLAGS]\n"
337          "                               <filename>\n"
338          "\tCOMP_ID:     Unique component ID to delete\n"
339          "\tCOMP_FLAGS:  'init' indicating all instantiated components\n"
340          "\t             '^init' indicating all uninstantiated components\n"
341          "\t-I and -F cannot be specified at the same time\n"
342          " or\n"
343          "To set or clear flags on a specific component\n"
344          "(note that this command can only be applied to mirrored files:\n"
345          "usage: setstripe --comp-set {-I COMP_ID|--comp-flags=COMP_FLAGS}\n"
346          "                            <filename>\n"
347          " or\n"
348          "To create a file with a foreign (free format) layout:\n"
349          "usage: setstripe --foreign[=FOREIGN_TYPE]\n"
350          "                 --xattr|-x LAYOUT_STRING [--flags HEX]\n"
351          "                 [--mode MODE] <filename>\n"},
352         {"getstripe", lfs_getstripe, 0,
353          "To list the layout pattern for a given file or files in a\n"
354          "directory or recursively for all files in a directory tree.\n"
355          "usage: getstripe [--ost|-O UUID] [--quiet|-q] [--verbose|-v]\n"
356          "                 [--stripe-count|-c] [--stripe-index|-i] [--fid|-F]\n"
357          "                 [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
358          "                 [--mdt-index|-m] [--recursive|-r] [--raw|-R]\n"
359          "                 [--layout|-L] [--generation|-g] [--yaml|-y]\n"
360          "                 [--help|-h] [--component-id|-I[=COMP_ID]]\n"
361          "                 [--component-flags[=COMP_FLAGS]]\n"
362          "                 [--component-count]\n"
363          "                 [--extension-size|--ext-size|-z]\n"
364          "                 [--component-start[=[+-]COMP_START]]\n"
365          "                 [--component-end[=[+-]COMP_END]|-E[[+-]comp_end]]\n"
366          "                 [[!] --mirror-index=[+-]INDEX |\n"
367          "                 [!] --mirror-id=[+-]MIRROR_ID] [--mirror-count|-N]\n"
368          "                 <directory|filename> ..."},
369         {"setdirstripe", lfs_setdirstripe, 0,
370          "Create striped directory on specified MDT, same as mkdir.\n"
371          "May be restricted to root or group users, depending on settings.\n"
372          "usage: setdirstripe [OPTION] <directory>\n"
373          SETDIRSTRIPE_USAGE},
374         {"getdirstripe", lfs_getdirstripe, 0,
375          "To list the layout pattern info for a given directory\n"
376          "or recursively for all directories in a directory tree.\n"
377          "usage: getdirstripe [--mdt-count|-c] [--mdt-index|-m|-i]\n"
378          "                    [--help|-h] [--mdt-hash|-H] [--obd|-O UUID]\n"
379          "                    [--recursive|-r] [--yaml|-y]\n"
380          "                    [--verbose|-v] [--default|-D]\n"
381          "                    [--max-inherit|-X]\n"
382          "                    [--max-inherit-rr] <dir> ..."},
383         {"mkdir", lfs_setdirstripe, 0,
384          "Create striped directory on specified MDT, same as setdirstripe.\n"
385          "usage: mkdir [OPTION] <directory>\n"
386          SETDIRSTRIPE_USAGE},
387         {"rm_entry", lfs_rmentry, 0,
388          "To remove the name entry of the remote directory. Note: This\n"
389          "command will only delete the name entry, i.e. the remote directory\n"
390          "will become inaccessable after this command. This can only be done\n"
391          "by the administrator\n"
392          "usage: rm_entry <dir>\n"},
393         {"unlink_foreign", lfs_unlink_foreign, 0,
394          "To remove the foreign file/dir.\n"
395          "Note: This is for files/dirs prevented to be removed using\n"
396          "unlink/rmdir, but works also for regular ones\n"
397          "usage: unlink_foreign <foreign_dir/file> [<foreign_dir/file> ...]\n"},
398         {"pool_list", lfs_poollist, 0,
399          "List pools or pool OSTs\n"
400          "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
401         {"find", lfs_find, 0,
402          "find files matching given attributes recursively in directory tree.\n"
403          "usage: find <directory|filename> ...\n"
404          "     [[!] --atime|-A [+-]N[smhdwy]] [[!] --ctime|-C [+-]N[smhdwy]]\n"
405          "     [[!] --mtime|-M [+-]N[smhdwy]]\n"
406          "     [[!] --btime|--Btime|-B [+-]N[smhdwy]] [--help|-h]\n"
407          "     [[!] --newer[XY] <reference>] [[!] --blocks|-b N]\n"
408          "     [--maxdepth|-D N] [[!] --mdt-index|--mdt|-m <uuid|index,...>]\n"
409          "     [[!] --name|-n <pattern>] [[!] --ost|-O <uuid|index,...>]\n"
410          "     [[!] --perm [/-]mode] [[!] --pool <pool>] [--print|-P]\n"
411          "     [--print0|-0] [[!] --projid <projid>]\n"
412          "     [[!] --size|-s [+-]N[bkMGTPE]]\n"
413          "     [[!] --stripe-count|-c [+-]<stripes>]\n"
414          "     [[!] --stripe-index|-i <index,...>]\n"
415          "     [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
416          "     [[!] --extension-size|--ext-size|-z [+-]N[kMGT]]\n"
417          "     [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
418          "     [[!] --uid|-u|--user|-U <uid>|<uname>]\n"
419          "     [[!] --layout|-L released,raid0,mdt]\n"
420          "     [[!] --foreign[=<foreign_type>]]\n"
421          "     [[!] --component-count [+-]<comp_cnt>]\n"
422          "     [[!] --component-start [+-]N[kMGTPE]]\n"
423          "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
424          "     [[!] --component-flags {init,stale,prefer,offline,nosync,extension}]\n"
425          "     [[!] --mirror-count|-N [+-]<n>]\n"
426          "     [[!] --mirror-state <[^]state>]\n"
427          "     [[!] --mdt-count|-T [+-]<stripes>]\n"
428          "     [[!] --mdt-hash|-H <[^][blm],[^]fnv_1a_64,all_char,crush,...>\n"
429          "     [[!] --mdt-index|-m <uuid|index,...>]\n"
430          "\t !: used before an option indicates 'NOT' requested attribute\n"
431          "\t -: used before a value indicates less than requested value\n"
432          "\t +: used before a value indicates more than requested value\n"
433          "\t ^: used before a flag indicates to exclude it\n"},
434         {"check", lfs_check, 0,
435          "Display the status of MGTs, MDTs or OSTs (as specified in the command)\n"
436          "or all the servers (MGTs, MDTs and OSTs).\n"
437          "usage: check {mgts|osts|mdts|all}"},
438         {"osts", lfs_osts, 0, "list OSTs connected to client "
439          "[for specified path only]\n" "usage: osts [path]"},
440         {"mdts", lfs_mdts, 0, "list MDTs connected to client "
441          "[for specified path only]\n" "usage: mdts [path]"},
442         {"df", lfs_df, 0,
443          "report filesystem disk space usage or inodes usage "
444          "of each MDS and all OSDs or a batch belonging to a specific pool.\n"
445          "Usage: df [--inodes|-i] [--human-readable|-h] [--lazy|-l]\n"
446          "          [--pool|-p <fsname>[.<pool>]] [path]"},
447         {"getname", lfs_getname, 0,
448          "list instances and specified mount points [for specified path only]\n"
449          "Usage: getname [--help|-h] [--instance|-i] [--fsname|-n] [path ...]"},
450 #ifdef HAVE_SYS_QUOTA_H
451         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
452          "usage: setquota {-u|-g|-p} UNAME|UID|GNAME|GID|PROJID\n"
453          "                -b BLOCK_SOFTLIMIT -B BLOCK_HARDLIMIT\n"
454          "                -i INODE_SOFTLIMIT -I INODE_HARDLIMIT <filesystem>\n"
455          "       setquota {-u|--user USER|UID|-g|--group GROUP|GID|-p|--projid PROJID}\n"
456          "                [--block-softlimit BLOCK_SOFTLIMIT]\n"
457          "                [--block-hardlimit BLOCK_HARDLIMIT]\n"
458          "                [--inode-softlimit INODE_SOFTLIMIT]\n"
459          "                [--inode-hardlimit INODE_HARDLIMIT] <filesystem>\n"
460          "       setquota [-t] {-h|--help|-u|--user|-g|--group|-p|--projid}\n"
461          "                [--block-grace 'notify'|BLOCK_GRACE]\n"
462          "                [--inode-grace 'notify'|INODE_GRACE] <filesystem>\n"
463          "       setquota {-U|-G|-P}\n"
464          "                -b BLOCK_SOFTLIMIT -B BLOCK_HARDLIMIT\n"
465          "                -i INODE_SOFTLIMIT -I INODE_HARDLIMIT <filesystem>\n"
466          "       setquota {-U|--default-usr|-G|--default-grp|-P|--default-prj}\n"
467          "                [--block-softlimit BLOCK_SOFTLIMIT]\n"
468          "                [--block-hardlimit BLOCK_HARDLIMIT]\n"
469          "                [--inode-softlimit INODE_SOFTLIMIT]\n"
470          "                [--inode-hardlimit INODE_HARDLIMIT] <filesystem>\n"
471          "       setquota {-u|-g|-p} UNAME|UID|GNAME|GID|PROJID\n"
472          "                {-d|--default}\n"
473          "       -b can be used instead of --block-softlimit/--block-grace\n"
474          "       -B can be used instead of --block-hardlimit\n"
475          "       -i can be used instead of --inode-softlimit/--inode-grace\n"
476          "       -I can be used instead of --inode-hardlimit\n"
477          "       -d can be used instead of --default\n\n"
478          "Note: The total quota space will be split into many qunits and\n"
479          "      balanced over all server targets, the minimal qunit size is\n"
480          "      1M bytes for block space and 1K inodes for inode space.\n\n"
481          "      The maximum quota grace time is 2^48 - 1 seconds.\n\n"
482          "      Quota space rebalancing process will stop when this mininum\n"
483          "      value is reached. As a result, quota exceeded can be returned\n"
484          "      while many targets still have 1MB or 1K inodes of spare\n"
485          "      quota space.\n\n"
486          "      When setting the grace time, 'notify' can be used as grace to\n"
487          "      be notified after the quota is over soft limit but prevents\n"
488          "      the soft limit from becoming the hard limit."},
489         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
490          "usage: quota [-q] [-v] [-h] [-o OBD_UUID|-i MDT_IDX|-I OST_IDX]\n"
491          "             [{-u|-g|-p} UNAME|UID|GNAME|GID|PROJID] <filesystem>\n"
492          "       quota [-o OBD_UUID|-i MDT_IDX|-I OST_IDX] -t {-u|-g|-p} <filesystem>\n"
493         "        quota [-q] [-v] [h] {-U|-G|-P} <filesystem>"},
494         {"project", lfs_project, 0,
495          "Change or list project attribute for specified file or directory.\n"
496          "usage: project [-d|-r] <file|directory...>\n"
497          "         list project ID and flags on file(s) or directories\n"
498          "       project [-p id] [-s] [-r] <file|directory...>\n"
499          "         set project ID and/or inherit flag for specified file(s) or directories\n"
500          "       project -c [-d|-r [-p id] [-0]] <file|directory...>\n"
501          "         check project ID and flags on file(s) or directories, print outliers\n"
502          "       project -C [-r] [-k] <file|directory...>\n"
503          "         clear the project inherit flag and ID on the file or directory\n"
504         },
505 #endif
506         {"flushctx", lfs_flushctx, 0,
507          "Flush security context for current user.\n"
508          "usage: flushctx [-k] [-r] [mountpoint...]"},
509         {"changelog", lfs_changelog, 0,
510          "Show the metadata changes on an MDT."
511          "\nusage: changelog <mdtname> [startrec [endrec]]"},
512         {"changelog_clear", lfs_changelog_clear, 0,
513          "Indicate that old changelog records up to <endrec> are no longer of "
514          "interest to consumer <id>, allowing the system to free up space.\n"
515          "An <endrec> of 0 means all records.\n"
516          "usage: changelog_clear <mdtname> <id> <endrec>"},
517         {"fid2path", lfs_fid2path, 0,
518          "Resolve the full path(s) for given FID(s). For a specific hardlink "
519          "specify link number <linkno>.\n"
520          "usage: fid2path [--print-fid|-f] [--print-link|-c] [--link|-l <linkno>] "
521          "<fsname|root> <fid>..."},
522         {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
523          "usage: path2fid [--parents] <path> ..."},
524         {"rmfid", lfs_rmfid, 0, "Remove file(s) by FID(s)\n"
525          "usage: rmfid <fsname|rootpath> <fid> ..."},
526         {"data_version", lfs_data_version, 0, "Display file data version for "
527          "a given path.\n" "usage: data_version [-n|-r|-w] <path>"},
528         {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
529          "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
530         {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
531          "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
532          "[--archived] [--lost] [--archive-id NUM] <file> ..."},
533         {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
534          "files.\n"
535          "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
536          "[--archived] [--lost] <file> ..."},
537         {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
538          "given files.\n" "usage: hsm_action <file> ..."},
539         {"hsm_archive", lfs_hsm_archive, 0,
540          "Archive file to external storage.\n"
541          "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
542          "<file> ..."},
543         {"hsm_restore", lfs_hsm_restore, 0,
544          "Restore file from external storage.\n"
545          "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
546         {"hsm_release", lfs_hsm_release, 0,
547          "Release files from Lustre.\n"
548          "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
549         {"hsm_remove", lfs_hsm_remove, 0,
550          "Remove file copy from external storage.\n"
551          "usage: hsm_remove [--filelist FILELIST] [--data DATA] "
552          "[--archive NUM]\n"
553          "                  (FILE [FILE ...] | "
554          "--mntpath MOUNTPATH FID [FID ...])\n"
555          "\n"
556          "Note: To remove an archived copy of a file already deleted from a "
557          "Lustre FS, the\n"
558          "--mntpath option and a list of FIDs must be specified"
559         },
560         {"hsm_cancel", lfs_hsm_cancel, 0,
561          "Cancel requests related to specified files.\n"
562          "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
563         {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
564          "usage: swap_layouts <path1> <path2>"},
565         {"migrate", lfs_setstripe_migrate, 0,
566          "migrate directories and their inodes between MDTs.\n"
567          "usage: migrate [--mdt-count|-c STRIPE_COUNT]\n"
568          "               [--mdt-hash|-H HASH_TYPE]\n"
569          "               [--mdt-index|-m START_MDT_INDEX] [--verbose|-v]\n"
570          "               DIRECTORY\n"
571          "\n"
572          "migrate file objects from one OST layout to another\n"
573          "(may be not safe with concurent writes).\n"
574          MIGRATE_USAGE },
575         {"mv", lfs_mv, 0,
576          "To move directories between MDTs. This command is deprecated, "
577          "use \"migrate\" instead.\n"
578          "usage: mv <directory|filename> [--mdt-index|-m MDT_INDEX] "
579          "[--verbose|-v]\n"},
580         {"ladvise", lfs_ladvise, 0,
581          "Provide servers with advice about access patterns for a file.\n"
582          "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
583          "               [--background|-b] [--unset|-u]\n\n"
584          "               {--end|-e END[kMGT]|--length|-l LENGTH[kMGT]}\n"
585          "               {[--mode|-m [READ,WRITE]}\n"
586          "               <file> ...\n"},
587         {"mirror", lfs_mirror, mirror_cmdlist,
588          "lfs commands used to manage files with mirrored components:\n"
589          "lfs mirror create - create a mirrored file or directory\n"
590          "lfs mirror extend - add mirror(s) to an existing file\n"
591          "lfs mirror split  - split a mirror from an existing mirrored file\n"
592          "lfs mirror resync - resynchronize out-of-sync mirrored file(s)\n"
593          "lfs mirror read   - read a mirror content of a mirrored file\n"
594          "lfs mirror write  - write to a mirror of a mirrored file\n"
595          "lfs mirror copy   - copy a mirror to other mirror(s) of a file\n"
596          "lfs mirror verify - verify mirrored file(s)\n"},
597         {"getsom", lfs_getsom, 0, "To list the SOM info for a given file.\n"
598          "usage: getsom [-s] [-b] [-f] <path>\n"
599          "\t-s: Only show the size value of the SOM data for a given file\n"
600          "\t-b: Only show the blocks value of the SOM data for a given file\n"
601          "\t-f: Only show the flags value of the SOM data for a given file\n"},
602         {"heat_get", lfs_heat_get, 0,
603          "To get heat of files.\n"
604          "usage: heat_get <file> ...\n"},
605         {"heat_set", lfs_heat_set, 0,
606          "To set heat flags of files.\n"
607          "usage: heat_set [--clear|-c] [--off|-o] [--on|-O] <file> ...\n"
608          "\t--clear|-c: Clear file heat for given files\n"
609          "\t--off|-o:   Turn off file heat for given files\n"
610          "\t--on|-O:    Turn on file heat for given files\n"},
611         {"pcc", lfs_pcc, pcc_cmdlist,
612          "lfs commands used to interact with PCC features:\n"
613          "lfs pcc attach - attach given files to Persistent Client Cache\n"
614          "lfs pcc attach_fid - attach given files into PCC by FID(s)\n"
615          "lfs pcc state  - display the PCC state for given files\n"
616          "lfs pcc detach - detach given files from Persistent Client Cache\n"
617          "lfs pcc detach_fid - detach given files from PCC by FID(s)\n"},
618         {"help", Parser_help, 0, "help"},
619         {"exit", Parser_quit, 0, "quit"},
620         {"quit", Parser_quit, 0, "quit"},
621         {"--version", Parser_version, 0,
622          "output build version of the utility and exit"},
623         {"--list-commands", lfs_list_commands, 0,
624          "list commands supported by the utility and exit"},
625         { 0, 0, 0, NULL }
626 };
627
628 static int check_hashtype(const char *hashtype)
629 {
630         int type_num = atoi(hashtype);
631         int i;
632
633         /* numeric hash type */
634         if (hashtype && strlen(hashtype) == 1 &&
635             (type_num > 0 && type_num < LMV_HASH_TYPE_MAX))
636                 return type_num;
637         /* string hash type */
638         for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
639                 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
640                         return i;
641
642         return 0;
643 }
644
645 static uint32_t check_foreign_type_name(const char *foreign_type_name)
646 {
647         uint32_t i;
648
649         for (i = 0; i < LU_FOREIGN_TYPE_UNKNOWN; i++) {
650                 if (!lu_foreign_types[i].lft_name)
651                         break;
652                 if (strcmp(foreign_type_name,
653                            lu_foreign_types[i].lft_name) == 0)
654                         return lu_foreign_types[i].lft_type;
655         }
656
657         return LU_FOREIGN_TYPE_UNKNOWN;
658 }
659
660 static const char *error_loc = "syserror";
661
662 enum {
663         MIGRATION_NONBLOCK      = 0x0001,
664         MIGRATION_MIRROR        = 0x0002,
665         MIGRATION_NONDIRECT     = 0x0004,
666         MIGRATION_VERBOSE       = 0x0008,
667 };
668
669 static int
670 migrate_open_files(const char *name, __u64 migration_flags,
671                    const struct llapi_stripe_param *param,
672                    struct llapi_layout *layout, int *fd_src, int *fd_tgt)
673 {
674         int                      fd = -1;
675         int                      fdv = -1;
676         int                      rflags;
677         int                      mdt_index;
678         int                      random_value;
679         char                     parent[PATH_MAX];
680         char                     volatile_file[PATH_MAX];
681         char                    *ptr;
682         int                      rc;
683         struct stat              st;
684         struct stat              stv;
685
686         if (!param && !layout) {
687                 error_loc = "layout information";
688                 return -EINVAL;
689         }
690
691         /* search for file directory pathname */
692         if (strlen(name) > sizeof(parent) - 1) {
693                 error_loc = "source file name";
694                 return -ERANGE;
695         }
696
697         strncpy(parent, name, sizeof(parent));
698         ptr = strrchr(parent, '/');
699         if (!ptr) {
700                 if (!getcwd(parent, sizeof(parent))) {
701                         error_loc = "getcwd";
702                         return -errno;
703                 }
704         } else {
705                 if (ptr == parent) /* leading '/' */
706                         ptr = parent + 1;
707                 *ptr = '\0';
708         }
709
710         /* open file, direct io */
711         /* even if the file is only read, WR mode is nedeed to allow
712          * layout swap on fd
713          */
714         rflags = O_RDWR | O_NOATIME;
715         if (!(migration_flags & MIGRATION_NONDIRECT))
716                 rflags |= O_DIRECT;
717         fd = open(name, rflags);
718         if (fd < 0) {
719                 rc = -errno;
720                 error_loc = "cannot open source file";
721                 return rc;
722         }
723
724         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
725         if (rc < 0) {
726                 error_loc = "cannot get MDT index";
727                 goto out;
728         }
729
730         do {
731                 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
732                 mode_t open_mode = S_IRUSR | S_IWUSR;
733
734                 random_value = random();
735                 rc = snprintf(volatile_file, sizeof(volatile_file),
736                               "%s/%s:%.4X:%.4X:fd=%.2d", parent,
737                               LUSTRE_VOLATILE_HDR, mdt_index,
738                               random_value, fd);
739                 if (rc >= sizeof(volatile_file)) {
740                         rc = -ENAMETOOLONG;
741                         break;
742                 }
743
744                 /* create, open a volatile file, use caching (ie no directio) */
745                 if (layout) {
746                         /* Returns -1 and sets errno on error: */
747                         fdv = llapi_layout_file_open(volatile_file, open_flags,
748                                                      open_mode, layout);
749                         if (fdv < 0)
750                                 fdv = -errno;
751                 } else {
752                         /* Does the right thing on error: */
753                         fdv = llapi_file_open_param(volatile_file, open_flags,
754                                                     open_mode, param);
755                 }
756         } while (fdv < 0 && (rc = fdv) == -EEXIST);
757
758         if (rc < 0) {
759                 error_loc = "cannot create volatile file";
760                 goto out;
761         }
762
763         /*
764          * In case the MDT does not support creation of volatile files
765          * we should try to unlink it.
766          */
767         (void)unlink(volatile_file);
768
769         /*
770          * Not-owner (root?) special case.
771          * Need to set owner/group of volatile file like original.
772          * This will allow to pass related check during layout_swap.
773          */
774         rc = fstat(fd, &st);
775         if (rc != 0) {
776                 rc = -errno;
777                 error_loc = "cannot stat source file";
778                 goto out;
779         }
780
781         rc = fstat(fdv, &stv);
782         if (rc != 0) {
783                 rc = -errno;
784                 error_loc = "cannot stat volatile";
785                 goto out;
786         }
787
788         if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
789                 rc = fchown(fdv, st.st_uid, st.st_gid);
790                 if (rc != 0) {
791                         rc = -errno;
792                         error_loc = "cannot change ownwership of volatile";
793                         goto out;
794                 }
795         }
796
797 out:
798         if (rc < 0) {
799                 if (fd > 0)
800                         close(fd);
801                 if (fdv > 0)
802                         close(fdv);
803         } else {
804                 *fd_src = fd;
805                 *fd_tgt = fdv;
806                 error_loc = NULL;
807         }
808         return rc;
809 }
810
811 static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int))
812 {
813         struct llapi_layout *layout;
814         size_t buf_size = 4 * 1024 * 1024;
815         void *buf = NULL;
816         off_t pos = 0;
817         off_t data_end = 0;
818         size_t page_size = sysconf(_SC_PAGESIZE);
819         bool sparse;
820         int rc;
821
822         layout = llapi_layout_get_by_fd(fd_src, 0);
823         if (layout) {
824                 uint64_t stripe_size;
825
826                 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
827                 if (rc == 0)
828                         buf_size = stripe_size;
829
830                 llapi_layout_free(layout);
831         }
832
833         /* Use a page-aligned buffer for direct I/O */
834         rc = posix_memalign(&buf, page_size, buf_size);
835         if (rc != 0)
836                 return -rc;
837
838         sparse = llapi_file_is_sparse(fd_src);
839         if (sparse) {
840                 rc = ftruncate(fd_dst, pos);
841                 if (rc < 0) {
842                         rc = -errno;
843                         return rc;
844                 }
845         }
846
847         while (1) {
848                 off_t data_off;
849                 size_t to_read, to_write;
850                 ssize_t rsize;
851
852                 if (sparse && pos >= data_end) {
853                         size_t data_size;
854
855                         data_off = llapi_data_seek(fd_src, pos, &data_size);
856                         if (data_off < 0) {
857                                 /* Non-fatal, switch to full copy */
858                                 sparse = false;
859                                 continue;
860                         }
861                         /* hole at the end of file, truncate up to it */
862                         if (!data_size) {
863                                 rc = ftruncate(fd_dst, data_off);
864                                 if (rc < 0)
865                                         goto out;
866                         }
867                         pos = data_off & ~(page_size - 1);
868                         data_end = data_off + data_size;
869                         to_read = ((data_end - pos - 1) | (page_size - 1)) + 1;
870                         to_read = MIN(to_read, buf_size);
871                 } else {
872                         to_read = buf_size;
873                 }
874
875                 if (check_file) {
876                         rc = check_file(fd_src);
877                         if (rc < 0)
878                                 goto out;
879                 }
880
881                 rsize = pread(fd_src, buf, to_read, pos);
882                 if (rsize < 0) {
883                         rc = -errno;
884                         goto out;
885                 }
886                 /* EOF */
887                 if (rsize == 0)
888                         break;
889
890                 to_write = rsize;
891                 while (to_write > 0) {
892                         ssize_t written;
893
894                         written = pwrite(fd_dst, buf, to_write, pos);
895                         if (written < 0) {
896                                 rc = -errno;
897                                 goto out;
898                         }
899                         pos += written;
900                         to_write -= written;
901                 }
902                 if (rc || rsize < to_read)
903                         break;
904         }
905
906         rc = fsync(fd_dst);
907         if (rc < 0)
908                 rc = -errno;
909 out:
910         /* Try to avoid page cache pollution after migration. */
911         (void)posix_fadvise(fd_src, 0, 0, POSIX_FADV_DONTNEED);
912         (void)posix_fadvise(fd_dst, 0, 0, POSIX_FADV_DONTNEED);
913
914         free(buf);
915         return rc;
916 }
917
918 static int migrate_set_timestamps(int fd, const struct stat *st)
919 {
920         struct timeval tv[2] = {
921                 {.tv_sec = st->st_atime},
922                 {.tv_sec = st->st_mtime}
923         };
924
925         return futimes(fd, tv);
926 }
927
928 static int migrate_block(int fd, int fdv)
929 {
930         struct stat st;
931         __u64   dv1;
932         int     gid;
933         int     rc;
934         int     rc2;
935
936         rc = fstat(fd, &st);
937         if (rc < 0) {
938                 error_loc = "cannot stat source file";
939                 return -errno;
940         }
941
942         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
943         if (rc < 0) {
944                 error_loc = "cannot get dataversion";
945                 return rc;
946         }
947
948         do
949                 gid = random();
950         while (gid == 0);
951
952         /*
953          * The grouplock blocks all concurrent accesses to the file.
954          * It has to be taken after llapi_get_data_version as it would
955          * block it too.
956          */
957         rc = llapi_group_lock(fd, gid);
958         if (rc < 0) {
959                 error_loc = "cannot get group lock";
960                 return rc;
961         }
962
963         rc = migrate_copy_data(fd, fdv, NULL);
964         if (rc < 0) {
965                 error_loc = "data copy failed";
966                 goto out_unlock;
967         }
968
969         /* Make sure we keep original atime/mtime values */
970         rc = migrate_set_timestamps(fdv, &st);
971         if (rc < 0) {
972                 error_loc = "set target file timestamp failed";
973                 goto out_unlock;
974         }
975
976         /*
977          * swap layouts
978          * for a migration we need to check data version on file did
979          * not change.
980          *
981          * Pass in gid=0 since we already own grouplock.
982          */
983         rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
984                                            SWAP_LAYOUTS_CHECK_DV1);
985         if (rc == -EAGAIN) {
986                 error_loc = "file changed";
987                 goto out_unlock;
988         } else if (rc < 0) {
989                 error_loc = "cannot swap layout";
990                 goto out_unlock;
991         }
992
993 out_unlock:
994         rc2 = llapi_group_unlock(fd, gid);
995         if (rc2 < 0 && rc == 0) {
996                 error_loc = "unlock group lock";
997                 rc = rc2;
998         }
999
1000         return rc;
1001 }
1002
1003 /**
1004  * Internal helper for migrate_copy_data(). Check lease and report error if
1005  * need be.
1006  *
1007  * \param[in]  fd           File descriptor on which to check the lease.
1008  *
1009  * \retval 0       Migration can keep on going.
1010  * \retval -errno  Error occurred, abort migration.
1011  */
1012 static int check_lease(int fd)
1013 {
1014         int rc;
1015
1016         rc = llapi_lease_check(fd);
1017         if (rc > 0)
1018                 return 0; /* llapi_check_lease returns > 0 on success. */
1019
1020         return -EBUSY;
1021 }
1022
1023 static int migrate_nonblock(int fd, int fdv)
1024 {
1025         struct stat st;
1026         __u64   dv1;
1027         __u64   dv2;
1028         int     rc;
1029
1030         rc = fstat(fd, &st);
1031         if (rc < 0) {
1032                 error_loc = "cannot stat source file";
1033                 return -errno;
1034         }
1035
1036         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
1037         if (rc < 0) {
1038                 error_loc = "cannot get data version";
1039                 return rc;
1040         }
1041
1042         rc = migrate_copy_data(fd, fdv, check_lease);
1043         if (rc < 0) {
1044                 error_loc = "data copy failed";
1045                 return rc;
1046         }
1047
1048         rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
1049         if (rc != 0) {
1050                 error_loc = "cannot get data version";
1051                 return rc;
1052         }
1053
1054         if (dv1 != dv2) {
1055                 rc = -EAGAIN;
1056                 error_loc = "source file changed";
1057                 return rc;
1058         }
1059
1060         /* Make sure we keep original atime/mtime values */
1061         rc = migrate_set_timestamps(fdv, &st);
1062         if (rc < 0) {
1063                 error_loc = "set target file timestamp failed";
1064                 return -errno;
1065         }
1066         return 0;
1067 }
1068
1069 static
1070 int lfs_layout_compid_by_pool(char *fname, const char *pool, int *comp_id)
1071 {
1072         struct pool_to_id_cbdata data = { .pool = pool };
1073         struct llapi_layout *layout = NULL;
1074         int rc;
1075
1076         layout = llapi_layout_get_by_path(fname, 0);
1077         if (!layout) {
1078                 fprintf(stderr,
1079                         "error %s: file '%s' couldn't get layout: rc=%d\n",
1080                         progname, fname, errno);
1081                 rc = -errno;
1082                 goto free_layout;
1083         }
1084         rc = llapi_layout_sanity(layout, fname, false, true);
1085         if (rc < 0) {
1086                 llapi_layout_sanity_perror(errno);
1087                 goto free_layout;
1088         }
1089         rc = llapi_layout_comp_iterate(layout, find_comp_id_by_pool, &data);
1090         if (rc < 0)
1091                 goto free_layout;
1092
1093         *comp_id = data.id;
1094         rc = 0;
1095
1096 free_layout:
1097         if (layout)
1098                 llapi_layout_free(layout);
1099         return rc;
1100 }
1101
1102 static int lfs_component_set(char *fname, int comp_id, const char *pool,
1103                              __u32 flags, __u32 neg_flags)
1104 {
1105         __u32 ids[2];
1106         __u32 flags_array[2];
1107         size_t count = 0;
1108         int rc;
1109
1110         if (!comp_id) {
1111                 if (pool == NULL) {
1112                         fprintf(stderr,
1113                                 "error %s: neither component id nor pool is specified\n",
1114                                 progname);
1115                         return -EINVAL;
1116                 }
1117                 rc = lfs_layout_compid_by_pool(fname, pool, &comp_id);
1118                 if (rc)
1119                         return rc;
1120         }
1121
1122         if (flags) {
1123                 ids[count] = comp_id;
1124                 flags_array[count] = flags;
1125                 ++count;
1126         }
1127
1128         if (neg_flags) {
1129                 if (neg_flags & LCME_FL_STALE) {
1130                         fprintf(stderr,
1131                                 "%s: cannot clear 'stale' flags from component. Please use lfs-mirror-resync(1) instead\n",
1132                                 progname);
1133                         return -EINVAL;
1134                 }
1135
1136                 ids[count] = comp_id;
1137                 flags_array[count] = neg_flags | LCME_FL_NEG;
1138                 ++count;
1139         }
1140
1141         rc = llapi_layout_file_comp_set(fname, ids, flags_array, count);
1142         if (rc) {
1143                 if (errno == EUCLEAN) {
1144                         rc = -errno;
1145                         fprintf(stderr,
1146                                 "%s: cannot set 'stale' flag on component '%#x' of the last non-stale mirror of '%s'\n",
1147                                 progname, comp_id, fname);
1148                 } else {
1149                         fprintf(stderr,
1150                                 "%s: cannot change the flags of component '%#x' of file '%s': %x / ^(%x)\n",
1151                                 progname, comp_id, fname, flags, neg_flags);
1152                 }
1153         }
1154
1155         return rc;
1156 }
1157
1158 static int lfs_component_del(char *fname, __u32 comp_id,
1159                              __u32 flags, __u32 neg_flags)
1160 {
1161         int     rc = 0;
1162
1163         if (flags && neg_flags)
1164                 return -EINVAL;
1165
1166         if (!flags && neg_flags)
1167                 flags = neg_flags | LCME_FL_NEG;
1168
1169         if ((flags && comp_id) || (!flags && !comp_id))
1170                 return -EINVAL;
1171
1172         if (flags) {
1173                 if (flags & ~LCME_KNOWN_FLAGS) {
1174                         fprintf(stderr,
1175                                 "%s setstripe: unknown flags %#x\n",
1176                                 progname, flags);
1177                         return -EINVAL;
1178                 }
1179         } else if (comp_id > LCME_ID_MAX) {
1180                 fprintf(stderr, "%s setstripe: invalid component id %u\n",
1181                         progname, comp_id);
1182                 return -EINVAL;
1183         }
1184
1185         rc = llapi_layout_file_comp_del(fname, comp_id, flags);
1186         if (rc)
1187                 fprintf(stderr,
1188                         "%s setstripe: cannot delete component %#x from '%s': %s\n",
1189                         progname, comp_id, fname, strerror(errno));
1190         return rc;
1191 }
1192
1193 static int lfs_component_add(char *fname, struct llapi_layout *layout)
1194 {
1195         int     rc;
1196
1197         if (!layout)
1198                 return -EINVAL;
1199
1200         rc = llapi_layout_file_comp_add(fname, layout);
1201         if (rc)
1202                 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
1203                         fname, strerror(errno));
1204         return rc;
1205 }
1206
1207 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
1208                                 struct llapi_layout *layout)
1209 {
1210         struct stat     st;
1211         int     fd;
1212
1213         if (!layout)
1214                 return -EINVAL;
1215
1216         fd = lstat(fname, &st);
1217         if (fd == 0 && S_ISDIR(st.st_mode))
1218                 open_flags = O_DIRECTORY | O_RDONLY;
1219
1220         fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
1221         if (fd < 0)
1222                 fprintf(stderr, "%s: cannot %s '%s': %s\n", progname,
1223                         S_ISDIR(st.st_mode) ?
1224                                 "set default composite layout for" :
1225                                 "create composite file",
1226                         fname, strerror(errno));
1227         return fd;
1228 }
1229
1230 static int lfs_migrate(char *name, __u64 migration_flags,
1231                        struct llapi_stripe_param *param,
1232                        struct llapi_layout *layout)
1233 {
1234         struct llapi_layout *existing;
1235         uint64_t dom_new, dom_cur;
1236         int fd = -1;
1237         int fdv = -1;
1238         int rc;
1239
1240         rc = migrate_open_files(name, migration_flags, param, layout,
1241                                 &fd, &fdv);
1242         if (rc < 0)
1243                 goto out;
1244
1245         rc = llapi_layout_dom_size(layout, &dom_new);
1246         if (rc) {
1247                 error_loc = "cannot get new layout DoM size";
1248                 goto out;
1249         }
1250         /* special case for migration to DOM layout*/
1251         existing = llapi_layout_get_by_fd(fd, 0);
1252         if (!existing) {
1253                 error_loc = "cannot get existing layout";
1254                 goto out;
1255         }
1256
1257         rc = llapi_layout_dom_size(existing, &dom_cur);
1258         if (rc) {
1259                 error_loc = "cannot get current layout DoM size";
1260                 goto out;
1261         }
1262
1263         /*
1264          * if file has DoM layout already then migration is possible to
1265          * the new layout with the same DoM component via swap layout,
1266          * if new layout used bigger DOM size, then mirroring is used
1267          */
1268         if (dom_new > dom_cur) {
1269                 rc = lfs_migrate_to_dom(fd, fdv, name, migration_flags, param,
1270                                         layout);
1271                 if (rc)
1272                         error_loc = "cannot migrate to DOM layout";
1273                 goto out_closed;
1274         }
1275
1276         if (!(migration_flags & MIGRATION_NONBLOCK)) {
1277                 /*
1278                  * Blocking mode (forced if servers do not support file lease).
1279                  * It is also the default mode, since we cannot distinguish
1280                  * between a broken lease and a server that does not support
1281                  * atomic swap/close (LU-6785)
1282                  */
1283                 rc = migrate_block(fd, fdv);
1284                 goto out;
1285         }
1286
1287         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1288         if (rc < 0) {
1289                 error_loc = "cannot get lease";
1290                 goto out;
1291         }
1292
1293         rc = migrate_nonblock(fd, fdv);
1294         if (rc < 0) {
1295                 llapi_lease_release(fd);
1296                 goto out;
1297         }
1298
1299         /*
1300          * Atomically put lease, swap layouts and close.
1301          * for a migration we need to check data version on file did
1302          * not change.
1303          */
1304         rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
1305         if (rc < 0) {
1306                 error_loc = "cannot swap layout";
1307                 goto out;
1308         }
1309
1310 out:
1311         if (fd >= 0)
1312                 close(fd);
1313
1314         if (fdv >= 0)
1315                 close(fdv);
1316 out_closed:
1317         if (rc < 0)
1318                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1319                         progname, name, error_loc, strerror(-rc));
1320         else if (migration_flags & MIGRATION_VERBOSE)
1321                 printf("%s\n", name);
1322
1323         return rc;
1324 }
1325
1326 static int comp_str2flags(char *string, __u32 *flags, __u32 *neg_flags)
1327 {
1328         char *name;
1329         char *dup_string = NULL;
1330         int rc = 0;
1331
1332         *flags = 0;
1333         *neg_flags = 0;
1334
1335         if (!string || !string[0])
1336                 return -EINVAL;
1337
1338         dup_string = strdup(string);
1339         if (!dup_string) {
1340                 llapi_printf(LLAPI_MSG_ERROR,
1341                              "%s: insufficient memory\n",
1342                              progname);
1343                 return -ENOMEM;
1344         }
1345
1346         for (name = strtok(dup_string, ","); name; name = strtok(NULL, ",")) {
1347                 bool found = false;
1348                 int i;
1349
1350                 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1351                         __u32 comp_flag = comp_flags_table[i].cfn_flag;
1352                         const char *comp_name = comp_flags_table[i].cfn_name;
1353
1354                         if (strcmp(name, comp_name) == 0) {
1355                                 *flags |= comp_flag;
1356                                 found = true;
1357                         } else if (strncmp(name, "^", 1) == 0 &&
1358                                    strcmp(name + 1, comp_name) == 0) {
1359                                 *neg_flags |= comp_flag;
1360                                 found = true;
1361                         }
1362                 }
1363                 if (!found) {
1364                         llapi_printf(LLAPI_MSG_ERROR,
1365                                      "%s: component flag '%s' not supported\n",
1366                                      progname, name);
1367                         rc = -EINVAL;
1368                         goto out_free;
1369                 }
1370         }
1371
1372         if (!*flags && !*neg_flags)
1373                 rc = -EINVAL;
1374
1375         /* don't allow to set and exclude the same flag */
1376         if (*flags & *neg_flags)
1377                 rc = -EINVAL;
1378
1379 out_free:
1380         free(dup_string);
1381         return rc;
1382 }
1383
1384 static int mdthash_input(char *string, __u32 *inflags,
1385                          __u32 *exflags, __u32 *type)
1386 {
1387         char *name;
1388         struct mhf_list {
1389                 char *name;
1390                 __u32 flag;
1391         } mhflist[] = {
1392                 {"migrating", LMV_HASH_FLAG_MIGRATION},
1393                 {"badtype", LMV_HASH_FLAG_BAD_TYPE},
1394                 {"lostlmv", LMV_HASH_FLAG_LOST_LMV},
1395         };
1396
1397         if (string == NULL)
1398                 return -EINVAL;
1399
1400         *inflags = 0;
1401         *exflags = 0;
1402         *type = 0;
1403         for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1404                 bool found = false;
1405                 int i;
1406
1407                 for (i = 0; i < ARRAY_SIZE(mhflist); i++) {
1408                         if (strcmp(name, mhflist[i].name) == 0 ||
1409                             name[0] == mhflist[i].name[0]) {
1410                                 *inflags |= mhflist[i].flag;
1411                                 found = true;
1412                         } else if (name[0] == '^' &&
1413                                    (strcmp(name + 1, mhflist[i].name) == 0 ||
1414                                     name[1] == mhflist[i].name[0])) {
1415                                 *exflags |= mhflist[i].flag;
1416                                 found = true;
1417                         }
1418                 }
1419                 if (!found) {
1420                         i = check_hashtype(name);
1421                         if (i > 0) {
1422                                 *type |= 1 << i;
1423                                 continue;
1424                         }
1425                         llapi_printf(LLAPI_MSG_ERROR,
1426                                      "%s: invalid mdt_hash value '%s'\n",
1427                                      progname, name);
1428                         return -EINVAL;
1429                 }
1430         }
1431
1432         /* don't allow to include and exclude the same flag */
1433         if (*inflags & *exflags) {
1434                 llapi_printf(LLAPI_MSG_ERROR,
1435                              "%s: include and exclude same flag '%s'\n",
1436                              progname, string);
1437                 return -EINVAL;
1438         }
1439
1440         return 0;
1441 }
1442
1443 static int mirror_str2state(char *string, __u16 *state, __u16 *neg_state)
1444 {
1445         if (!string)
1446                 return -EINVAL;
1447
1448         *state = 0;
1449         *neg_state = 0;
1450
1451         if (strncmp(string, "^", 1) == 0) {
1452                 *neg_state = llapi_layout_string_flags(string + 1);
1453                 if (*neg_state != 0)
1454                         return 0;
1455         } else {
1456                 *state = llapi_layout_string_flags(string);
1457                 if (*state != 0)
1458                         return 0;
1459         }
1460
1461         llapi_printf(LLAPI_MSG_ERROR,
1462                      "%s: mirrored file state '%s' not supported\n",
1463                      progname, string);
1464         return -EINVAL;
1465 }
1466
1467 /**
1468  * struct mirror_args - Command-line arguments for mirror(s).
1469  * @m_count:  Number of mirrors to be created with this layout.
1470  * @m_flags:  Mirror level flags, only 'prefer' is supported.
1471  * @m_layout: Mirror layout.
1472  * @m_file:   A victim file. Its layout will be split and used as a mirror.
1473  * @m_next:   Point to the next node of the list.
1474  *
1475  * Command-line arguments for mirror(s) will be parsed and stored in
1476  * a linked list that consists of this structure.
1477  */
1478 struct mirror_args {
1479         __u32                   m_count;
1480         __u32                   m_flags;
1481         struct llapi_layout     *m_layout;
1482         const char              *m_file;
1483         struct mirror_args      *m_next;
1484         bool                    m_inherit;
1485 };
1486
1487 /**
1488  * enum mirror_flags - Flags for extending a mirrored file.
1489  * @MF_NO_VERIFY: Indicates not to verify the mirror(s) from victim file(s)
1490  *             in case the victim file(s) contains the same data as the
1491  *             original mirrored file.
1492  * @MF_DESTROY: Indicates to delete the mirror from the mirrored file.
1493  * @MF_COMP_ID: specified component id instead of mirror id
1494  *
1495  * Flags for extending a mirrored file.
1496  */
1497 enum mirror_flags {
1498         MF_NO_VERIFY    = 0x1,
1499         MF_DESTROY      = 0x2,
1500         MF_COMP_ID      = 0x4,
1501         MF_COMP_POOL    = 0x8,
1502 };
1503
1504 /**
1505  * mirror_create_sanity_check() - Check mirror list.
1506  * @list:  A linked list that stores the mirror arguments.
1507  *
1508  * This function does a sanity check on @list for creating
1509  * a mirrored file.
1510  *
1511  * Return: 0 on success or a negative error code on failure.
1512  */
1513 static int mirror_create_sanity_check(const char *fname,
1514                                       struct mirror_args *list,
1515                                       bool check_fname)
1516 {
1517         int rc = 0;
1518         bool has_m_file = false;
1519         bool has_m_layout = false;
1520
1521         if (!list)
1522                 return -EINVAL;
1523
1524         if (fname && check_fname) {
1525                 struct llapi_layout *layout;
1526
1527                 layout = llapi_layout_get_by_path(fname, 0);
1528                 if (!layout) {
1529                         fprintf(stderr,
1530                                 "error: %s: file '%s' couldn't get layout\n",
1531                                 progname, fname);
1532                         return -ENODATA;
1533                 }
1534
1535                 rc = llapi_layout_sanity(layout, fname, false, true);
1536
1537                 llapi_layout_free(layout);
1538
1539                 if (rc) {
1540                         llapi_layout_sanity_perror(rc);
1541                         return rc;
1542                 }
1543         }
1544
1545         while (list) {
1546                 if (list->m_file) {
1547                         has_m_file = true;
1548                         llapi_layout_free(list->m_layout);
1549
1550                         list->m_layout =
1551                                 llapi_layout_get_by_path(list->m_file, 0);
1552                         if (!list->m_layout) {
1553                                 fprintf(stderr,
1554                                         "error: %s: file '%s' has no layout\n",
1555                                         progname, list->m_file);
1556                                 return -ENODATA;
1557                         }
1558                 } else {
1559                         has_m_layout = true;
1560                         if (!list->m_layout) {
1561                                 fprintf(stderr, "error: %s: no mirror layout\n",
1562                                         progname);
1563                                 return -EINVAL;
1564                         }
1565                 }
1566
1567                 rc = llapi_layout_sanity(list->m_layout, fname, false, true);
1568                 if (rc) {
1569                         llapi_layout_sanity_perror(rc);
1570                         return rc;
1571                 }
1572
1573                 list = list->m_next;
1574         }
1575
1576         if (has_m_file && has_m_layout) {
1577                 fprintf(stderr,
1578                         "error: %s: -f <victim_file> option should not be specified with setstripe options\n",
1579                         progname);
1580                 return -EINVAL;
1581         }
1582
1583         return 0;
1584 }
1585
1586 static int mirror_set_flags(struct llapi_layout *layout, void *cbdata)
1587 {
1588         __u32 mirror_flags = *(__u32 *)cbdata;
1589         uint32_t flags;
1590         int rc;
1591
1592         rc = llapi_layout_comp_flags_get(layout, &flags);
1593         if (rc < 0)
1594                 return rc;
1595
1596         if (!flags) {
1597                 rc = llapi_layout_comp_flags_set(layout, mirror_flags);
1598                 if (rc)
1599                         return rc;
1600         }
1601
1602         return LLAPI_LAYOUT_ITER_CONT;
1603 }
1604
1605 /**
1606  * mirror_create() - Create a mirrored file.
1607  * @fname:        The file to be created.
1608  * @mirror_list:  A linked list that stores the mirror arguments.
1609  *
1610  * This function creates a mirrored file @fname with the mirror(s)
1611  * from @mirror_list.
1612  *
1613  * Return: 0 on success or a negative error code on failure.
1614  */
1615 static int mirror_create(char *fname, struct mirror_args *mirror_list)
1616 {
1617         struct llapi_layout *layout = NULL;
1618         struct mirror_args *cur_mirror = NULL;
1619         uint16_t mirror_count = 0;
1620         int i = 0;
1621         int rc = 0;
1622
1623         rc = mirror_create_sanity_check(fname, mirror_list, false);
1624         if (rc)
1625                 return rc;
1626
1627         cur_mirror = mirror_list;
1628         while (cur_mirror) {
1629                 rc = llapi_layout_comp_iterate(cur_mirror->m_layout,
1630                                                mirror_set_flags,
1631                                                &cur_mirror->m_flags);
1632                 if (rc) {
1633                         rc = -errno;
1634                         fprintf(stderr, "%s: failed to set mirror flags\n",
1635                                 progname);
1636                         goto error;
1637                 }
1638
1639                 for (i = 0; i < cur_mirror->m_count; i++) {
1640                         rc = llapi_layout_merge(&layout, cur_mirror->m_layout);
1641                         if (rc) {
1642                                 rc = -errno;
1643                                 fprintf(stderr,
1644                                         "error: %s: merge layout failed: %s\n",
1645                                         progname, strerror(errno));
1646                                 goto error;
1647                         }
1648                 }
1649                 mirror_count += cur_mirror->m_count;
1650                 cur_mirror = cur_mirror->m_next;
1651         }
1652
1653         if (!layout) {
1654                 fprintf(stderr, "error: %s: layout is NULL\n", progname);
1655                 return -EINVAL;
1656         }
1657
1658         rc = llapi_layout_mirror_count_set(layout, mirror_count);
1659         if (rc) {
1660                 rc = -errno;
1661                 fprintf(stderr, "error: %s: set mirror count failed: %s\n",
1662                         progname, strerror(errno));
1663                 goto error;
1664         }
1665
1666         rc = lfs_component_create(fname, O_CREAT | O_WRONLY, 0666,
1667                                   layout);
1668         if (rc >= 0) {
1669                 close(rc);
1670                 rc = 0;
1671         }
1672
1673 error:
1674         llapi_layout_free(layout);
1675         return rc;
1676 }
1677
1678 /**
1679  * Compare files and check lease on @fd.
1680  *
1681  * \retval bytes number of bytes are the same
1682  */
1683 static ssize_t mirror_file_compare(int fd, int fdv)
1684 {
1685         const size_t buflen = 4 * 1024 * 1024; /* 4M */
1686         void *buf;
1687         ssize_t bytes_done = 0;
1688         ssize_t bytes_read = 0;
1689
1690         buf = malloc(buflen * 2);
1691         if (!buf)
1692                 return -ENOMEM;
1693
1694         while (1) {
1695                 if (!llapi_lease_check(fd)) {
1696                         bytes_done = -EBUSY;
1697                         break;
1698                 }
1699
1700                 bytes_read = read(fd, buf, buflen);
1701                 if (bytes_read <= 0)
1702                         break;
1703
1704                 if (bytes_read != read(fdv, buf + buflen, buflen))
1705                         break;
1706
1707                 /*
1708                  * XXX: should compute the checksum on each buffer and then
1709                  * compare checksum to avoid cache collision
1710                  */
1711                 if (memcmp(buf, buf + buflen, bytes_read))
1712                         break;
1713
1714                 bytes_done += bytes_read;
1715         }
1716
1717         free(buf);
1718
1719         return bytes_done;
1720 }
1721
1722 static int mirror_extend_file(const char *fname, const char *victim_file,
1723                               enum mirror_flags mirror_flags)
1724 {
1725         int fd = -1;
1726         int fdv = -1;
1727         struct stat stbuf;
1728         struct stat stbuf_v;
1729         struct ll_ioc_lease *data = NULL;
1730         int rc;
1731
1732         fd = open(fname, O_RDWR);
1733         if (fd < 0) {
1734                 error_loc = "open source file";
1735                 rc = -errno;
1736                 goto out;
1737         }
1738
1739         fdv = open(victim_file, O_RDWR);
1740         if (fdv < 0) {
1741                 error_loc = "open target file";
1742                 rc = -errno;
1743                 goto out;
1744         }
1745
1746         if (fstat(fd, &stbuf) || fstat(fdv, &stbuf_v)) {
1747                 error_loc = "stat source or target file";
1748                 rc = -errno;
1749                 goto out;
1750         }
1751
1752         if (stbuf.st_dev != stbuf_v.st_dev) {
1753                 error_loc = "stat source and target file";
1754                 rc = -EXDEV;
1755                 goto out;
1756         }
1757
1758         /* mirrors should be of the same size */
1759         if (stbuf.st_size != stbuf_v.st_size) {
1760                 error_loc = "file sizes don't match";
1761                 rc = -EINVAL;
1762                 goto out;
1763         }
1764
1765         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1766         if (rc < 0) {
1767                 error_loc = "cannot get lease";
1768                 goto out;
1769         }
1770
1771         if (!(mirror_flags & MF_NO_VERIFY)) {
1772                 ssize_t ret;
1773                 /* mirrors should have the same contents */
1774                 ret = mirror_file_compare(fd, fdv);
1775                 if (ret != stbuf.st_size) {
1776                         error_loc = "file busy or contents don't match";
1777                         rc = ret < 0 ? ret : -EINVAL;
1778                         goto out;
1779                 }
1780         }
1781
1782         /* Get rid of caching pages from clients */
1783         rc = llapi_file_flush(fd);
1784         if (rc < 0) {
1785                 error_loc = "cannot get data version";
1786                 goto out;
1787         }
1788
1789         rc = llapi_file_flush(fdv);
1790         if (rc < 0) {
1791                 error_loc = "cannot get data version";
1792                 goto out;
1793         }
1794
1795         rc = migrate_set_timestamps(fd, &stbuf);
1796         if (rc < 0) {
1797                 error_loc = "cannot set source file timestamp";
1798                 goto out;
1799         }
1800
1801         /* Atomically put lease, merge layouts and close. */
1802         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
1803         if (!data) {
1804                 error_loc = "memory allocation";
1805                 goto out;
1806         }
1807         data->lil_mode = LL_LEASE_UNLCK;
1808         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
1809         data->lil_count = 1;
1810         data->lil_ids[0] = fdv;
1811         rc = llapi_lease_set(fd, data);
1812         if (rc < 0) {
1813                 error_loc = "cannot merge layout";
1814                 goto out;
1815         } else if (rc == 0) {
1816                 rc = -EBUSY;
1817                 error_loc = "lost lease lock";
1818                 goto out;
1819         }
1820         rc = 0;
1821
1822 out:
1823         if (data)
1824                 free(data);
1825         if (fd >= 0)
1826                 close(fd);
1827         if (fdv >= 0)
1828                 close(fdv);
1829         if (!rc)
1830                 (void) unlink(victim_file);
1831         if (rc < 0)
1832                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1833                         progname, fname, error_loc, strerror(-rc));
1834         return rc;
1835 }
1836
1837 static int mirror_extend_layout(char *name, struct llapi_layout *m_layout,
1838                                 bool inherit, uint32_t flags)
1839 {
1840         struct llapi_layout *f_layout = NULL;
1841         struct ll_ioc_lease *data = NULL;
1842         struct stat st;
1843         int fd = -1;
1844         int fdv = -1;
1845         int rc = 0;
1846
1847         if (inherit) {
1848                 f_layout = llapi_layout_get_by_path(name, 0);
1849                 if (!f_layout) {
1850                         rc = -EINVAL;
1851                         fprintf(stderr, "%s: cannot get layout\n", progname);
1852                         goto out;
1853                 }
1854                 rc = llapi_layout_get_last_init_comp(f_layout);
1855                 if (rc) {
1856                         fprintf(stderr, "%s: cannot get the last init comp\n",
1857                                 progname);
1858                         goto out;
1859                 }
1860                 rc = llapi_layout_mirror_inherit(f_layout, m_layout);
1861                 if (rc) {
1862                         fprintf(stderr,
1863                                 "%s: cannot inherit from the last init comp\n",
1864                                 progname);
1865                         goto out;
1866                 }
1867         }
1868         llapi_layout_comp_flags_set(m_layout, flags);
1869         rc = migrate_open_files(name, MIGRATION_NONDIRECT, NULL, m_layout, &fd,
1870                                 &fdv);
1871         if (rc < 0)
1872                 goto out;
1873
1874         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1875         if (rc < 0) {
1876                 error_loc = "cannot get lease";
1877                 goto out;
1878         }
1879
1880         rc = fstat(fd, &st);
1881         if (rc < 0) {
1882                 error_loc = "cannot stat source file";
1883                 goto out;
1884         }
1885
1886         rc = migrate_nonblock(fd, fdv);
1887         if (rc < 0) {
1888                 llapi_lease_release(fd);
1889                 goto out;
1890         }
1891
1892         rc = migrate_set_timestamps(fd, &st);
1893         if (rc < 0) {
1894                 error_loc = "cannot set source file timestamp";
1895                 goto out;
1896         }
1897
1898         /* Atomically put lease, merge layouts and close. */
1899         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
1900         if (!data) {
1901                 error_loc = "memory allocation";
1902                 goto out;
1903         }
1904         data->lil_mode = LL_LEASE_UNLCK;
1905         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
1906         data->lil_count = 1;
1907         data->lil_ids[0] = fdv;
1908         rc = llapi_lease_set(fd, data);
1909         if (rc < 0) {
1910                 error_loc = "cannot merge layout";
1911                 goto out;
1912         } else if (rc == 0) {
1913                 rc = -EBUSY;
1914                 error_loc = "lost lease lock";
1915                 goto out;
1916         }
1917         rc = 0;
1918
1919 out:
1920         if (data)
1921                 free(data);
1922         if (fd >= 0)
1923                 close(fd);
1924         if (fdv >= 0)
1925                 close(fdv);
1926         if (rc < 0)
1927                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1928                         progname, name, error_loc, strerror(-rc));
1929         return rc;
1930 }
1931
1932 static int mirror_extend(char *fname, struct mirror_args *mirror_list,
1933                          enum mirror_flags mirror_flags)
1934 {
1935         int rc = 0;
1936
1937         while (mirror_list) {
1938                 if (mirror_list->m_file) {
1939                         rc = mirror_extend_file(fname, mirror_list->m_file,
1940                                                 mirror_flags);
1941                 } else {
1942                         __u32 mirror_count = mirror_list->m_count;
1943
1944                         while (mirror_count > 0) {
1945                                 rc = mirror_extend_layout(fname,
1946                                                         mirror_list->m_layout,
1947                                                         mirror_list->m_inherit,
1948                                                         mirror_list->m_flags);
1949                                 if (rc)
1950                                         break;
1951
1952                                 --mirror_count;
1953                         }
1954                 }
1955                 if (rc)
1956                         break;
1957
1958                 mirror_list = mirror_list->m_next;
1959         }
1960
1961         return rc;
1962 }
1963
1964 static int find_mirror_id(struct llapi_layout *layout, void *cbdata)
1965 {
1966         uint32_t id;
1967         int rc;
1968
1969         rc = llapi_layout_mirror_id_get(layout, &id);
1970         if (rc < 0)
1971                 return rc;
1972
1973         if ((__u16)id == *(__u16 *)cbdata)
1974                 return LLAPI_LAYOUT_ITER_STOP;
1975
1976         return LLAPI_LAYOUT_ITER_CONT;
1977 }
1978
1979 static int find_comp_id(struct llapi_layout *layout, void *cbdata)
1980 {
1981         uint32_t id;
1982         int rc;
1983
1984         rc = llapi_layout_comp_id_get(layout, &id);
1985         if (rc < 0)
1986                 return rc;
1987
1988         if (id == *(__u32 *)cbdata)
1989                 return LLAPI_LAYOUT_ITER_STOP;
1990
1991         return LLAPI_LAYOUT_ITER_CONT;
1992 }
1993
1994 static int find_mirror_id_by_pool(struct llapi_layout *layout, void *cbdata)
1995 {
1996         char buf[LOV_MAXPOOLNAME + 1];
1997         struct pool_to_id_cbdata *d = (void *)cbdata;
1998         uint32_t id;
1999         int rc;
2000
2001         rc = llapi_layout_pool_name_get(layout, buf, sizeof(buf));
2002         if (rc < 0)
2003                 return rc;
2004         if (strcmp(d->pool, buf))
2005                 return LLAPI_LAYOUT_ITER_CONT;
2006
2007         rc = llapi_layout_mirror_id_get(layout, &id);
2008         if (rc < 0)
2009                 return rc;
2010         d->id = id;
2011
2012         return LLAPI_LAYOUT_ITER_STOP;
2013 }
2014
2015 static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata)
2016 {
2017         char buf[LOV_MAXPOOLNAME + 1];
2018         struct pool_to_id_cbdata *d = (void *)cbdata;
2019         uint32_t id;
2020         int rc;
2021
2022         rc = llapi_layout_pool_name_get(layout, buf, sizeof(buf));
2023         if (rc < 0)
2024                 return rc;
2025         if (strcmp(d->pool, buf))
2026                 return LLAPI_LAYOUT_ITER_CONT;
2027
2028         rc = llapi_layout_comp_id_get(layout, &id);
2029         if (rc < 0)
2030                 return rc;
2031         d->id = id;
2032
2033         return LLAPI_LAYOUT_ITER_STOP;
2034 }
2035
2036 struct collect_ids_data {
2037         __u16   *cid_ids;
2038         int     cid_count;
2039         __u16   cid_exclude;
2040 };
2041
2042 static int collect_mirror_id(struct llapi_layout *layout, void *cbdata)
2043 {
2044         struct collect_ids_data *cid = cbdata;
2045         uint32_t id;
2046         int rc;
2047
2048         rc = llapi_layout_mirror_id_get(layout, &id);
2049         if (rc < 0)
2050                 return rc;
2051
2052         if ((__u16)id != cid->cid_exclude) {
2053                 int i;
2054
2055                 for (i = 0; i < cid->cid_count; i++) {
2056                         /* already collected the mirror id */
2057                         if (id == cid->cid_ids[i])
2058                                 return LLAPI_LAYOUT_ITER_CONT;
2059                 }
2060                 cid->cid_ids[cid->cid_count] = id;
2061                 cid->cid_count++;
2062         }
2063
2064         return LLAPI_LAYOUT_ITER_CONT;
2065 }
2066
2067 /**
2068  * last_non_stale_mirror() - Check if a mirror is the last non-stale mirror.
2069  * @mirror_id: Mirror id to be checked.
2070  * @layout:    Mirror component list.
2071  *
2072  * This function checks if a mirror with specified @mirror_id is the last
2073  * non-stale mirror of a layout @layout.
2074  *
2075  * Return: true or false.
2076  */
2077 static inline
2078 bool last_non_stale_mirror(__u16 mirror_id, struct llapi_layout *layout)
2079 {
2080         __u16 mirror_ids[128] = { 0 };
2081         struct collect_ids_data cid = { .cid_ids = mirror_ids,
2082                                         .cid_count = 0,
2083                                         .cid_exclude = mirror_id, };
2084         int i;
2085
2086         llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
2087
2088         for (i = 0; i < cid.cid_count; i++) {
2089                 struct llapi_resync_comp comp_array[1024] = { { 0 } };
2090                 int comp_size = 0;
2091
2092                 comp_size = llapi_mirror_find_stale(layout, comp_array,
2093                                                     ARRAY_SIZE(comp_array),
2094                                                     &mirror_ids[i], 1);
2095                 if (comp_size == 0)
2096                         return false;
2097         }
2098
2099         return true;
2100 }
2101
2102 static int mirror_split(const char *fname, __u32 id, const char *pool,
2103                         enum mirror_flags mflags, const char *victim_file)
2104 {
2105         struct llapi_layout *layout;
2106         char parent[PATH_MAX];
2107         char victim[PATH_MAX];
2108         int flags = O_CREAT | O_EXCL | O_LOV_DELAY_CREATE | O_NOFOLLOW;
2109         char *ptr;
2110         struct ll_ioc_lease *data;
2111         uint16_t mirror_count;
2112         __u32 mirror_id;
2113         int mdt_index;
2114         int fd, fdv;
2115         bool purge = true; /* delete mirror by setting fdv=fd */
2116         bool is_encrypted;
2117         int rc;
2118
2119         if (victim_file && (strcmp(fname, victim_file) == 0)) {
2120                 fprintf(stderr,
2121                         "error %s: the source file '%s' and -f file are the same\n",
2122                         progname, fname);
2123                 return -EINVAL;
2124         }
2125
2126         /* check fname contains mirror with mirror_id/comp_id */
2127         layout = llapi_layout_get_by_path(fname, 0);
2128         if (!layout) {
2129                 fprintf(stderr,
2130                         "error %s: file '%s' couldn't get layout\n",
2131                         progname, fname);
2132                 return -EINVAL;
2133         }
2134
2135         rc = llapi_layout_sanity(layout, fname, false, true);
2136         if (rc) {
2137                 llapi_layout_sanity_perror(rc);
2138                 goto free_layout;
2139         }
2140
2141         rc = llapi_layout_mirror_count_get(layout, &mirror_count);
2142         if (rc) {
2143                 fprintf(stderr,
2144                         "error %s: file '%s' couldn't get mirror count\n",
2145                         progname, fname);
2146                 goto free_layout;
2147         }
2148         if (mirror_count < 2) {
2149                 fprintf(stderr,
2150                         "error %s: file '%s' has %d component, cannot split\n",
2151                         progname, fname, mirror_count);
2152                 goto free_layout;
2153         }
2154
2155         if (mflags & MF_COMP_POOL) {
2156                 struct pool_to_id_cbdata data = { .pool = pool };
2157
2158                 rc = llapi_layout_comp_iterate(layout, find_mirror_id_by_pool,
2159                                                &data);
2160                 mirror_id = data.id;
2161         } else if (mflags & MF_COMP_ID) {
2162                 rc = llapi_layout_comp_iterate(layout, find_comp_id, &id);
2163                 mirror_id = mirror_id_of(id);
2164         } else {
2165                 rc = llapi_layout_comp_iterate(layout, find_mirror_id, &id);
2166                 mirror_id = id;
2167         }
2168         if (rc < 0) {
2169                 fprintf(stderr, "error %s: failed to iterate layout of '%s'\n",
2170                         progname, fname);
2171                 goto free_layout;
2172         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
2173                 if (mflags & MF_COMP_POOL) {
2174                         fprintf(stderr,
2175                                 "error %s: file '%s' does not contain mirror with pool '%s'\n",
2176                                 progname, fname, pool);
2177                         goto free_layout;
2178                 } else if (mflags & MF_COMP_ID) {
2179                         fprintf(stderr,
2180                                 "error %s: file '%s' does not contain mirror with comp-id %u\n",
2181                                 progname, fname, id);
2182                         goto free_layout;
2183                 } else {
2184                         fprintf(stderr,
2185                                 "error %s: file '%s' does not contain mirror with id %u\n",
2186                                 progname, fname, id);
2187                         goto free_layout;
2188                 }
2189         }
2190
2191         fd = open(fname, O_RDWR);
2192         if (fd < 0) {
2193                 fprintf(stderr,
2194                         "error %s: open file '%s' failed: %s\n",
2195                         progname, fname, strerror(errno));
2196                 goto free_layout;
2197         }
2198
2199         /* get victim file directory pathname */
2200         if (strlen(fname) > sizeof(parent) - 1) {
2201                 fprintf(stderr, "error %s: file name of '%s' too long\n",
2202                         progname, fname);
2203                 rc = -ERANGE;
2204                 goto close_fd;
2205         }
2206         strncpy(parent, fname, sizeof(parent));
2207         ptr = strrchr(parent, '/');
2208         if (!ptr) {
2209                 if (!getcwd(parent, sizeof(parent))) {
2210                         fprintf(stderr, "error %s: getcwd failed: %s\n",
2211                                 progname, strerror(errno));
2212                         rc = -errno;
2213                         goto close_fd;
2214                 }
2215         } else {
2216                 if (ptr == parent)
2217                         ptr = parent + 1;
2218                 *ptr = '\0';
2219         }
2220
2221         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
2222         if (rc < 0) {
2223                 fprintf(stderr, "%s: cannot get MDT index of '%s'\n",
2224                         progname, fname);
2225                 goto close_fd;
2226         }
2227
2228         rc = llapi_file_is_encrypted(fd);
2229         if (rc < 0) {
2230                 fprintf(stderr, "%s: cannot get flags of '%s': %d\n",
2231                         progname, fname, rc);
2232                 goto close_fd;
2233         }
2234         is_encrypted = rc;
2235
2236 again:
2237         if (!victim_file) {
2238                 /* use a temp file to store the splitted layout */
2239                 if (mflags & MF_DESTROY) {
2240                         char file_path[PATH_MAX];
2241                         unsigned int rnumber;
2242                         int open_flags;
2243
2244                         if (last_non_stale_mirror(mirror_id, layout)) {
2245                                 rc = -EUCLEAN;
2246                                 fprintf(stderr,
2247                                         "%s: cannot destroy the last non-stale mirror of file '%s'\n",
2248                                         progname, fname);
2249                                 goto close_fd;
2250                         }
2251
2252                         if (purge) {
2253                                 /* don't use volatile file for mirror destroy */
2254                                 fdv = fd;
2255                         } else {
2256                                 /**
2257                                  * try the old way to delete mirror using
2258                                  * volatile file.
2259                                  */
2260                                 do {
2261                                         rnumber = random();
2262                                         rc = snprintf(file_path,
2263                                                       sizeof(file_path),
2264                                                       "%s/" LUSTRE_VOLATILE_HDR ":%.4X:%.4X:fd=%.2d",
2265                                                       parent, mdt_index,
2266                                                       rnumber, fd);
2267                                         if (rc < 0 ||
2268                                             rc >= sizeof(file_path)) {
2269                                                 fdv = -ENAMETOOLONG;
2270                                                 break;
2271                                         }
2272
2273                                         open_flags = O_RDWR |
2274                                              (O_LOV_DELAY_CREATE & ~O_ACCMODE) |
2275                                              O_CREAT | O_EXCL | O_NOFOLLOW;
2276                                         fdv = open(file_path, open_flags,
2277                                                    S_IRUSR | S_IWUSR);
2278                                         if (fdv < 0)
2279                                                 rc = -errno;
2280                                 } while (fdv < 0 && rc == -EEXIST);
2281                         }
2282                 } else {
2283                         if (is_encrypted) {
2284                                 rc = -1;
2285                                 fprintf(stderr,
2286                                         "error %s: not permitted on encrypted file '%s': %d\n",
2287                                         progname, fname, rc);
2288                                 goto close_fd;
2289                         }
2290
2291                         snprintf(victim, sizeof(victim), "%s.mirror~%u",
2292                                  fname, mirror_id);
2293                         fdv = open(victim, flags, S_IRUSR | S_IWUSR);
2294                 }
2295         } else {
2296                 /* user specified victim file */
2297                 if (is_encrypted) {
2298                         rc = -1;
2299                         fprintf(stderr,
2300                                 "error %s: not permitted on encrypted file '%s': %d\n",
2301                                 progname, fname, rc);
2302                         goto close_fd;
2303                 }
2304                 fdv = open(victim_file, flags, S_IRUSR | S_IWUSR);
2305         }
2306
2307         if (fdv < 0) {
2308                 fprintf(stderr,
2309                         "error %s: create victim file failed: %s\n",
2310                         progname, strerror(errno));
2311                 goto close_fd;
2312         }
2313
2314         /* get lease lock of fname */
2315         rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
2316         if (rc < 0) {
2317                 fprintf(stderr,
2318                         "error %s: cannot get lease of file '%s': %d\n",
2319                         progname, fname, rc);
2320                 goto close_victim;
2321         }
2322
2323         /* Atomatically put lease, split layouts and close. */
2324         data = malloc(offsetof(typeof(*data), lil_ids[2]));
2325         if (!data) {
2326                 rc = -ENOMEM;
2327                 goto close_victim;
2328         }
2329
2330         data->lil_mode = LL_LEASE_UNLCK;
2331         data->lil_flags = LL_LEASE_LAYOUT_SPLIT;
2332         data->lil_count = 2;
2333         data->lil_ids[0] = fdv;
2334         data->lil_ids[1] = mirror_id;
2335         rc = llapi_lease_set(fd, data);
2336         if (rc <= 0) {
2337                 if (rc == -EINVAL && purge) {
2338                         /* could be old MDS which prohibit fd==fdv */
2339                         purge = false;
2340                         goto again;
2341
2342                 }
2343                 if (rc == 0) /* lost lease lock */
2344                         rc = -EBUSY;
2345                 fprintf(stderr,
2346                         "error %s: cannot split '%s': %s\n",
2347                         progname, fname, strerror(-rc));
2348         } else {
2349                 rc = 0;
2350         }
2351         free(data);
2352
2353 close_victim:
2354         if (!purge)
2355                 close(fdv);
2356 close_fd:
2357         close(fd);
2358 free_layout:
2359         llapi_layout_free(layout);
2360         return rc;
2361 }
2362
2363 static inline
2364 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
2365                            __u16 *mirror_ids, int ids_nr);
2366
2367 static int lfs_migrate_to_dom(int fd, int fdv, char *name,
2368                               __u64 migration_flags,
2369                               struct llapi_stripe_param *param,
2370                               struct llapi_layout *layout)
2371 {
2372         struct ll_ioc_lease *data = NULL;
2373         int rc;
2374
2375         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
2376         if (rc < 0) {
2377                 error_loc = "cannot get lease";
2378                 goto out_close;
2379         }
2380
2381         /* Atomically put lease, merge layouts, resync and close. */
2382         data = calloc(1, offsetof(typeof(*data), lil_ids[1024]));
2383         if (!data) {
2384                 error_loc = "memory allocation";
2385                 goto out_close;
2386         }
2387         data->lil_mode = LL_LEASE_UNLCK;
2388         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
2389         data->lil_count = 1;
2390         data->lil_ids[0] = fdv;
2391         rc = llapi_lease_set(fd, data);
2392         if (rc < 0) {
2393                 error_loc = "cannot merge layout";
2394                 goto out_close;
2395         } else if (rc == 0) {
2396                 rc = -EBUSY;
2397                 error_loc = "lost lease lock";
2398                 goto out_close;
2399         }
2400         close(fd);
2401         close(fdv);
2402
2403         rc = lfs_mirror_resync_file(name, data, NULL, 0);
2404         if (rc) {
2405                 error_loc = "cannot resync file";
2406                 goto out;
2407         }
2408
2409         /* delete first mirror now */
2410         rc = mirror_split(name, 1, NULL, MF_DESTROY, NULL);
2411         if (rc < 0)
2412                 error_loc = "cannot delete old layout";
2413         goto out;
2414
2415 out_close:
2416         close(fd);
2417         close(fdv);
2418 out:
2419         if (rc < 0)
2420                 fprintf(stderr, "error: %s: %s: %s: %s\n",
2421                         progname, name, error_loc, strerror(-rc));
2422         else if (migration_flags & MIGRATION_VERBOSE)
2423                 printf("%s\n", name);
2424         if (data)
2425                 free(data);
2426         return rc;
2427 }
2428
2429 /**
2430  * Parse a string containing an target index list into an array of integers.
2431  *
2432  * The input string contains a comma delimited list of individual
2433  * indices and ranges, for example "1,2-4,7". Add the indices into the
2434  * \a tgts array and remove duplicates.
2435  *
2436  * \param[out] tgts             array to store indices in
2437  * \param[in] size              size of \a tgts array
2438  * \param[in] offset            starting index in \a tgts
2439  * \param[in] arg               string containing OST index list
2440  * \param[in/out] overstriping  index list may contain duplicates
2441  *
2442  * \retval positive    number of indices in \a tgts
2443  * \retval -EINVAL     unable to parse \a arg
2444  */
2445 static int parse_targets(__u32 *tgts, int size, int offset, char *arg,
2446                          unsigned long long *pattern)
2447 {
2448         int rc;
2449         int nr = offset;
2450         int slots = size - offset;
2451         char *ptr = NULL;
2452         bool overstriped = false;
2453         bool end_of_loop;
2454
2455         if (!arg)
2456                 return -EINVAL;
2457
2458         end_of_loop = false;
2459         while (!end_of_loop) {
2460                 int start_index = 0;
2461                 int end_index = 0;
2462                 int i;
2463                 char *endptr = NULL;
2464
2465                 rc = -EINVAL;
2466
2467                 ptr = strchrnul(arg, ',');
2468
2469                 end_of_loop = *ptr == '\0';
2470                 *ptr = '\0';
2471
2472                 errno = 0;
2473                 start_index = strtol(arg, &endptr, 0);
2474                 if (endptr == arg) /* no data at all */
2475                         break;
2476                 if (errno != 0 || start_index < -1 ||
2477                     (*endptr != '-' && *endptr != '\0'))
2478                         break;
2479
2480                 end_index = start_index;
2481                 if (*endptr == '-') {
2482                         errno = 0;
2483                         end_index = strtol(endptr + 1, &endptr, 0);
2484                         if (errno != 0 || *endptr != '\0' || end_index < -1)
2485                                 break;
2486                         if (end_index < start_index)
2487                                 break;
2488                 }
2489
2490                 for (i = start_index; i <= end_index && slots > 0; i++) {
2491                         int j;
2492
2493                         /* remove duplicate */
2494                         for (j = 0; j < offset; j++) {
2495                                 if (tgts[j] == i && pattern &&
2496                                     *pattern == LLAPI_LAYOUT_OVERSTRIPING)
2497                                         overstriped = true;
2498                                 else if (tgts[j] == i)
2499                                         return -EINVAL;
2500                         }
2501
2502                         j = offset;
2503
2504                         if (j == offset) { /* check complete */
2505                                 tgts[nr++] = i;
2506                                 --slots;
2507                         }
2508                 }
2509
2510                 if (slots == 0 && i < end_index)
2511                         break;
2512
2513                 *ptr = ',';
2514                 arg = ++ptr;
2515                 offset = nr;
2516                 rc = 0;
2517         }
2518         if (!end_of_loop && ptr)
2519                 *ptr = ',';
2520
2521         if (!overstriped && pattern)
2522                 *pattern = LLAPI_LAYOUT_DEFAULT;
2523
2524         return rc < 0 ? rc : nr;
2525 }
2526
2527 struct lfs_setstripe_args {
2528         unsigned long long       lsa_comp_end;
2529         unsigned long long       lsa_stripe_size;
2530         unsigned long long       lsa_extension_size;
2531         long long                lsa_stripe_count;
2532         long long                lsa_stripe_off;
2533         __u32                    lsa_comp_flags;
2534         __u32                    lsa_comp_neg_flags;
2535         unsigned long long       lsa_pattern;
2536         unsigned int             lsa_mirror_count;
2537         int                      lsa_nr_tgts;
2538         bool                     lsa_first_comp;
2539         bool                     lsa_extension_comp;
2540         __u32                   *lsa_tgts;
2541         char                    *lsa_pool_name;
2542 };
2543
2544 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
2545 {
2546         unsigned int mirror_count = lsa->lsa_mirror_count;
2547         bool first_comp = lsa->lsa_first_comp;
2548
2549         memset(lsa, 0, sizeof(*lsa));
2550
2551         lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
2552         lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
2553         lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2554         lsa->lsa_pattern = LLAPI_LAYOUT_RAID0;
2555         lsa->lsa_pool_name = NULL;
2556
2557         lsa->lsa_mirror_count = mirror_count;
2558         lsa->lsa_first_comp = first_comp;
2559 }
2560
2561 /**
2562  * setstripe_args_init_inherit() - Initialize and inherit stripe options.
2563  * @lsa: Stripe options to be initialized and inherited.
2564  *
2565  * This function initializes stripe options in @lsa and inherit
2566  * stripe_size, stripe_count and OST pool_name options.
2567  *
2568  * Return: void.
2569  */
2570 static inline void setstripe_args_init_inherit(struct lfs_setstripe_args *lsa)
2571 {
2572         unsigned long long stripe_size;
2573         long long stripe_count;
2574         char *pool_name = NULL;
2575
2576         stripe_size = lsa->lsa_stripe_size;
2577         stripe_count = lsa->lsa_stripe_count;
2578         pool_name = lsa->lsa_pool_name;
2579
2580         setstripe_args_init(lsa);
2581
2582         lsa->lsa_stripe_size = stripe_size;
2583         lsa->lsa_stripe_count = stripe_count;
2584         lsa->lsa_pool_name = pool_name;
2585 }
2586
2587 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
2588 {
2589         return (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT ||
2590                 lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ||
2591                 lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
2592                 lsa->lsa_pattern != LLAPI_LAYOUT_RAID0 ||
2593                 lsa->lsa_comp_end != 0);
2594 }
2595
2596 static int lsa_args_stripe_count_check(struct lfs_setstripe_args *lsa)
2597 {
2598         if (lsa->lsa_nr_tgts) {
2599                 if (lsa->lsa_nr_tgts < 0 ||
2600                     lsa->lsa_nr_tgts >= LOV_MAX_STRIPE_COUNT) {
2601                         fprintf(stderr, "Invalid nr_tgts(%d)\n",
2602                                 lsa->lsa_nr_tgts);
2603                         errno = EINVAL;
2604                         return -1;
2605                 }
2606
2607                 if (lsa->lsa_stripe_count > 0 &&
2608                     lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
2609                     lsa->lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
2610                     lsa->lsa_nr_tgts != lsa->lsa_stripe_count) {
2611                         fprintf(stderr, "stripe_count(%lld) != nr_tgts(%d)\n",
2612                                 lsa->lsa_stripe_count,
2613                                 lsa->lsa_nr_tgts);
2614                         errno = EINVAL;
2615                         return -1;
2616                 }
2617         }
2618
2619         return 0;
2620
2621 }
2622
2623 /**
2624  * comp_args_to_layout() - Create or extend a composite layout.
2625  * @composite:       Pointer to the composite layout.
2626  * @lsa:             Stripe options for the new component.
2627  *
2628  * This function creates or extends a composite layout by adding a new
2629  * component with stripe options from @lsa.
2630  *
2631  * When modified, adjust llapi_stripe_param_verify() if needed as well.
2632  *
2633  * Return: 0 on success or an error code on failure.
2634  */
2635 static int comp_args_to_layout(struct llapi_layout **composite,
2636                                struct lfs_setstripe_args *lsa,
2637                                bool set_extent)
2638 {
2639         struct llapi_layout *layout = *composite;
2640         uint64_t prev_end = 0;
2641         uint64_t size;
2642         int i = 0, rc;
2643
2644 new_comp:
2645         if (!layout) {
2646                 layout = llapi_layout_alloc();
2647                 if (!layout) {
2648                         fprintf(stderr, "Alloc llapi_layout failed. %s\n",
2649                                 strerror(errno));
2650                         errno = ENOMEM;
2651                         return -1;
2652                 }
2653                 *composite = layout;
2654                 lsa->lsa_first_comp = true;
2655         } else {
2656                 uint64_t start;
2657
2658                 /*
2659                  * Get current component extent, current component
2660                  * must be the tail component.
2661                  */
2662                 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
2663                 if (rc) {
2664                         fprintf(stderr, "Get comp extent failed. %s\n",
2665                                 strerror(errno));
2666                         return rc;
2667                 }
2668
2669                 if (lsa->lsa_first_comp) {
2670                         prev_end = 0;
2671                         rc = llapi_layout_add_first_comp(layout);
2672                 } else {
2673                         rc = llapi_layout_comp_add(layout);
2674                 }
2675                 if (rc) {
2676                         fprintf(stderr, "Add component failed. %s\n",
2677                                 strerror(errno));
2678                         return rc;
2679                 }
2680         }
2681
2682         rc = llapi_layout_comp_flags_set(layout, lsa->lsa_comp_flags);
2683         if (rc) {
2684                 fprintf(stderr, "Set flags 0x%x failed: %s\n",
2685                         lsa->lsa_comp_flags, strerror(errno));
2686                 return rc;
2687         }
2688
2689         if (set_extent) {
2690                 uint64_t comp_end = lsa->lsa_comp_end;
2691
2692                 /*
2693                  * The extendable component is 0-length, so it can be removed
2694                  * if there is insufficient space to extend it.
2695                  */
2696                 if (lsa->lsa_extension_comp)
2697                         comp_end = prev_end;
2698
2699                 rc = llapi_layout_comp_extent_set(layout, prev_end,
2700                                                   comp_end);
2701                 if (rc) {
2702                         fprintf(stderr, "Set extent [%lu, %lu) failed. %s\n",
2703                                 prev_end, comp_end, strerror(errno));
2704                         return rc;
2705                 }
2706         }
2707         /* reset lsa_first_comp */
2708         lsa->lsa_first_comp = false;
2709
2710         /* Data-on-MDT component setting */
2711         if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
2712                 /* Yaml support */
2713                 if (lsa->lsa_stripe_count == 0)
2714                         lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
2715                 if (lsa->lsa_stripe_size == lsa->lsa_comp_end)
2716                         lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
2717                 if (lsa->lsa_stripe_off == -1 ||
2718                     lsa->lsa_stripe_off == 0)
2719                         lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2720                 /*
2721                  * In case of Data-on-MDT patterns the only extra option
2722                  * applicable is stripe size option.
2723                  */
2724                 if (lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
2725                         fprintf(stderr,
2726                                 "Option 'stripe-count' can't be specified with Data-on-MDT component: %lld\n",
2727                                 lsa->lsa_stripe_count);
2728                         errno = EINVAL;
2729                         return -1;
2730                 }
2731                 if (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT &&
2732                     lsa->lsa_stripe_size != lsa->lsa_comp_end - prev_end) {
2733                         fprintf(stderr,
2734                                 "Option 'stripe-size' can't be specified with Data-on-MDT component: %llu\n",
2735                                 lsa->lsa_stripe_size);
2736                         errno = EINVAL;
2737                         return -1;
2738                 }
2739                 if (lsa->lsa_nr_tgts != 0) {
2740                         fprintf(stderr,
2741                                 "Option 'ost-list' can't be specified with Data-on-MDT component: '%i'\n",
2742                                 lsa->lsa_nr_tgts);
2743                         errno = EINVAL;
2744                         return -1;
2745                 }
2746                 if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
2747                         fprintf(stderr,
2748                                 "Option 'stripe-offset' can't be specified with Data-on-MDT component: %lld\n",
2749                                 lsa->lsa_stripe_off);
2750                         errno = EINVAL;
2751                         return -1;
2752                 }
2753                 if (lsa->lsa_pool_name != 0) {
2754                         fprintf(stderr,
2755                                 "Option 'pool' can't be specified with Data-on-MDT component: '%s'\n",
2756                                 lsa->lsa_pool_name);
2757                         errno = EINVAL;
2758                         return -1;
2759                 }
2760
2761                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
2762                 if (rc) {
2763                         fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
2764                                 lsa->lsa_pattern,
2765                                 strerror(errno));
2766                         return rc;
2767                 }
2768                 /* Data-on-MDT component has always single stripe up to end */
2769                 lsa->lsa_stripe_size = lsa->lsa_comp_end;
2770         } else if (lsa->lsa_pattern == LLAPI_LAYOUT_OVERSTRIPING) {
2771                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
2772                 if (rc) {
2773                         fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
2774                                 lsa->lsa_pattern,
2775                                 strerror(errno));
2776                         return rc;
2777                 }
2778         }
2779
2780         size = lsa->lsa_comp_flags & LCME_FL_EXTENSION ?
2781                 lsa->lsa_extension_size : lsa->lsa_stripe_size;
2782
2783         if (lsa->lsa_comp_flags & LCME_FL_EXTENSION)
2784                 rc = llapi_layout_extension_size_set(layout, size);
2785         else
2786                 rc = llapi_layout_stripe_size_set(layout, size);
2787
2788         if (rc) {
2789                 fprintf(stderr, "Set stripe size %lu failed: %s\n",
2790                         size, strerror(errno));
2791                 return rc;
2792         }
2793
2794         rc = llapi_layout_stripe_count_set(layout, lsa->lsa_stripe_count);
2795         if (rc) {
2796                 fprintf(stderr, "Set stripe count %lld failed: %s\n",
2797                         lsa->lsa_stripe_count, strerror(errno));
2798                 return rc;
2799         }
2800
2801         if (lsa->lsa_pool_name) {
2802                 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
2803                 if (rc) {
2804                         fprintf(stderr, "Set pool name: %s failed. %s\n",
2805                                 lsa->lsa_pool_name, strerror(errno));
2806                         return rc;
2807                 }
2808         } else {
2809                 rc = llapi_layout_pool_name_set(layout, "");
2810                 if (rc) {
2811                         fprintf(stderr, "Clear pool name failed: %s\n",
2812                                 strerror(errno));
2813                         return rc;
2814                 }
2815         }
2816
2817         rc = lsa_args_stripe_count_check(lsa);
2818         if (rc)
2819                 return rc;
2820
2821         if (lsa->lsa_nr_tgts > 0) {
2822                 bool found = false;
2823
2824                 for (i = 0; i < lsa->lsa_nr_tgts; i++) {
2825                         rc = llapi_layout_ost_index_set(layout, i,
2826                                                         lsa->lsa_tgts[i]);
2827                         if (rc)
2828                                 break;
2829
2830                         /* Make sure stripe offset is in OST list. */
2831                         if (lsa->lsa_tgts[i] == lsa->lsa_stripe_off)
2832                                 found = true;
2833                 }
2834                 if (!found) {
2835                         fprintf(stderr, "Invalid stripe offset '%lld', not in the target list",
2836                                 lsa->lsa_stripe_off);
2837                         errno = EINVAL;
2838                         return -1;
2839                 }
2840         } else if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT &&
2841                    lsa->lsa_stripe_off != -1) {
2842                 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
2843         }
2844         if (rc) {
2845                 fprintf(stderr, "Set ost index %d failed. %s\n",
2846                         i, strerror(errno));
2847                 return rc;
2848         }
2849
2850         /* Create the second, virtual component of extension space */
2851         if (lsa->lsa_extension_comp) {
2852                 lsa->lsa_comp_flags |= LCME_FL_EXTENSION;
2853                 lsa->lsa_extension_comp = false;
2854                 goto new_comp;
2855         }
2856
2857         return rc;
2858 }
2859
2860 static int build_component(struct llapi_layout **layout,
2861                            struct lfs_setstripe_args *lsa, bool set_extent)
2862 {
2863         int rc;
2864
2865         rc = comp_args_to_layout(layout, lsa, set_extent);
2866         if (rc)
2867                 return rc;
2868
2869         if (lsa->lsa_mirror_count > 0) {
2870                 rc = llapi_layout_mirror_count_set(*layout,
2871                                                    lsa->lsa_mirror_count);
2872                 if (rc)
2873                         return rc;
2874
2875                 rc = llapi_layout_flags_set(*layout, LCM_FL_RDONLY);
2876                 if (rc)
2877                         return rc;
2878                 lsa->lsa_mirror_count = 0;
2879         }
2880
2881         return rc;
2882 }
2883
2884 static int build_prev_component(struct llapi_layout **layout,
2885                                 struct lfs_setstripe_args *prev,
2886                                 struct lfs_setstripe_args *lsa,
2887                                 bool set_extent)
2888 {
2889         int extension = lsa->lsa_comp_flags & LCME_FL_EXTENSION;
2890         int rc;
2891
2892         if (prev->lsa_stripe_size) {
2893                 if (extension) {
2894                         prev->lsa_comp_end = lsa->lsa_comp_end;
2895                         prev->lsa_extension_size = lsa->lsa_extension_size;
2896                         prev->lsa_extension_comp = true;
2897                 }
2898
2899                 rc = build_component(layout, prev, true);
2900                 if (rc)
2901                         return rc;
2902         }
2903
2904         /*
2905          * Copy lsa to previous lsa;
2906          * if this is an extension component, make the previous invalid;
2907          */
2908         if (extension)
2909                 prev->lsa_stripe_size = 0;
2910         else
2911                 *prev = *lsa;
2912
2913         return 0;
2914 }
2915
2916 #ifndef LCME_TEMPLATE_FLAGS
2917 #define LCME_TEMPLATE_FLAGS     (LCME_FL_PREF_RW | LCME_FL_NOSYNC | \
2918                                  LCME_FL_EXTENSION)
2919 #endif
2920
2921 static int build_layout_from_yaml_node(struct cYAML *node,
2922                                        struct llapi_layout **layout,
2923                                        struct lfs_setstripe_args *lsa,
2924                                        struct lfs_setstripe_args *prevp)
2925 {
2926         struct lfs_setstripe_args prev = { 0 };
2927         __u32 *osts = lsa->lsa_tgts;
2928         char *string;
2929         int rc = 0;
2930
2931         if (!prevp)
2932                 prevp = &prev;
2933
2934         while (node) {
2935                 string = node->cy_string;
2936
2937                 if (node->cy_type == CYAML_TYPE_OBJECT) {
2938                         /* go deep to sub blocks */
2939                         if (string && !strncmp(string, "component", 9) &&
2940                             strncmp(string, "component0", 10) &&
2941                             strncmp(string, "components", 10)) {
2942                                 rc = build_prev_component(layout, prevp, lsa,
2943                                                           true);
2944                                 if (rc)
2945                                         return rc;
2946
2947                                 /* initialize lsa. */
2948                                 setstripe_args_init(lsa);
2949                                 lsa->lsa_first_comp = false;
2950                                 lsa->lsa_tgts = osts;
2951                         }
2952
2953                         rc = build_layout_from_yaml_node(node->cy_child, layout,
2954                                                          lsa, prevp);
2955                         if (rc)
2956                                 return rc;
2957                 } else {
2958                         if (!node->cy_string)
2959                                 return -EINVAL;
2960
2961                         /* skip leading lmm_ if present, to simplify parsing */
2962                         if (strncmp(string, "lmm_", 4) == 0)
2963                                 string += 4;
2964
2965                         if (node->cy_type == CYAML_TYPE_STRING) {
2966                                 if (!strcmp(string, "lcme_extent.e_end")) {
2967                                         if (!strcmp(node->cy_valuestring, "EOF") ||
2968                                             !strcmp(node->cy_valuestring, "eof"))
2969                                                 lsa->lsa_comp_end = LUSTRE_EOF;
2970                                 } else if (!strcmp(string, "pool")) {
2971                                         lsa->lsa_pool_name = node->cy_valuestring;
2972                                 } else if (!strcmp(string, "pattern")) {
2973                                         if (!strcmp(node->cy_valuestring, "mdt"))
2974                                                 lsa->lsa_pattern = LLAPI_LAYOUT_MDT;
2975                                         if (!strcmp(node->cy_valuestring,
2976                                                     "raid0,overstriped"))
2977                                                 lsa->lsa_pattern =
2978                                                         LLAPI_LAYOUT_OVERSTRIPING;
2979                                 } else if (!strcmp(string, "lcme_flags")) {
2980                                         rc = comp_str2flags(node->cy_valuestring,
2981                                                             &lsa->lsa_comp_flags,
2982                                                             &lsa->lsa_comp_neg_flags);
2983                                         if (rc)
2984                                                 return rc;
2985                                         /*
2986                                          * Only template flags have meaning in
2987                                          * the layout for a new file
2988                                          */
2989                                         lsa->lsa_comp_flags &= LCME_TEMPLATE_FLAGS;
2990                                 }
2991                         } else if (node->cy_type == CYAML_TYPE_NUMBER) {
2992                                 if (!strcmp(string, "lcm_mirror_count")) {
2993                                         lsa->lsa_mirror_count = node->cy_valueint;
2994                                 } else if (!strcmp(string, "lcme_extent.e_start")) {
2995                                         if (node->cy_valueint == 0)
2996                                                 lsa->lsa_first_comp = true;
2997                                 } else if (!strcmp(string, "lcme_extent.e_end")) {
2998                                         if (node->cy_valueint == -1)
2999                                                 lsa->lsa_comp_end = LUSTRE_EOF;
3000                                         else
3001                                                 lsa->lsa_comp_end = node->cy_valueint;
3002                                 } else if (!strcmp(string, "stripe_count")) {
3003                                         lsa->lsa_stripe_count = node->cy_valueint;
3004                                 } else if (!strcmp(string, "stripe_size")) {
3005                                         lsa->lsa_stripe_size = node->cy_valueint;
3006                                 } else if (!strcmp(string, "extension_size")) {
3007                                         lsa->lsa_extension_size = node->cy_valueint;
3008                                         lsa->lsa_extension_comp = true;
3009                                 } else if (!strcmp(string, "stripe_offset")) {
3010                                         lsa->lsa_stripe_off = node->cy_valueint;
3011                                 } else if (!strcmp(string, "l_ost_idx")) {
3012                                         osts[lsa->lsa_nr_tgts] = node->cy_valueint;
3013                                         lsa->lsa_nr_tgts++;
3014                                 }
3015                         }
3016                 }
3017                 node = node->cy_next;
3018         }
3019
3020         if (prevp == &prev) {
3021                 rc = build_prev_component(layout, prevp, lsa, true);
3022                 if (rc)
3023                         return rc;
3024
3025                 if (!(lsa->lsa_comp_flags & LCME_FL_EXTENSION))
3026                         rc = build_component(layout, lsa, *layout != NULL);
3027         }
3028
3029         return rc;
3030 }
3031
3032 static int lfs_comp_create_from_yaml(char *template,
3033                                      struct llapi_layout **layout,
3034                                      struct lfs_setstripe_args *lsa,
3035                                      __u32 *osts)
3036 {
3037         struct cYAML *tree = NULL, *err_rc = NULL;
3038         int rc = 0;
3039
3040         tree = cYAML_build_tree(template, NULL, 0, &err_rc, false);
3041         if (!tree) {
3042                 fprintf(stderr, "%s: cannot parse YAML file %s\n",
3043                         progname, template);
3044                 cYAML_build_error(-EINVAL, -1, "yaml", "from comp yaml",
3045                                   "can't parse", &err_rc);
3046                 cYAML_print_tree2file(stderr, err_rc);
3047                 cYAML_free_tree(err_rc);
3048                 rc = -EINVAL;
3049                 goto err;
3050         }
3051
3052         /* initialize lsa for plain file */
3053         setstripe_args_init(lsa);
3054         lsa->lsa_tgts = osts;
3055
3056         rc = build_layout_from_yaml_node(tree, layout, lsa, NULL);
3057         if (rc) {
3058                 fprintf(stderr, "%s: cannot build layout from YAML file %s.\n",
3059                         progname, template);
3060                 goto err;
3061         }
3062         /* clean clean lsa */
3063         setstripe_args_init(lsa);
3064
3065 err:
3066         if (tree)
3067                 cYAML_free_tree(tree);
3068         return rc;
3069 }
3070
3071 /**
3072  * Get the extension size from the next (SEL) component and extend the
3073  * current component on it. The start of the next component is to be
3074  * adjusted as well.
3075  *
3076  * \param[in] layout    the current layout
3077  * \param[in] start     the start of the current component
3078  * \param[in,out] end   the end of the current component
3079  * \param[in] offset    the offset to adjust the end position to instead of
3080  *                      extension size
3081  *
3082  * \retval 0            - extended successfully
3083  * \retval < 0          - error
3084  */
3085 static int layout_extend_comp(struct llapi_layout *layout,
3086                               uint64_t start, uint64_t *end,
3087                               uint64_t offset)
3088 {
3089         uint64_t size, next_start, next_end;
3090         int rc;
3091
3092         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
3093         if (rc < 0) {
3094                 fprintf(stderr,
3095                         "%s setstripe: cannot move component cursor: %s\n",
3096                         progname, strerror(errno));
3097                 return rc;
3098         }
3099
3100         /*
3101          * Even if the @size will not be used below, this will fail if
3102          * this is not a SEL component - a good confirmation we are
3103          * working on right components.
3104          */
3105         rc = llapi_layout_extension_size_get(layout, &size);
3106         if (rc < 0) {
3107                 fprintf(stderr,
3108                         "%s setstripe: cannot get component ext size: %s\n",
3109                         progname, strerror(errno));
3110                 return rc;
3111         }
3112
3113         rc = llapi_layout_comp_extent_get(layout, &next_start, &next_end);
3114         if (rc) {
3115                 fprintf(stderr, "%s setstripe: cannot get extent: %s\n",
3116                         progname, strerror(errno));
3117                 return rc;
3118         }
3119
3120         next_start += offset ?: size;
3121         rc = llapi_layout_comp_extent_set(layout, next_start, next_end);
3122         if (rc) {
3123                 fprintf(stderr, "%s setstripe: cannot set extent: %s\n",
3124                         progname, strerror(errno));
3125                 return rc;
3126         }
3127
3128         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_PREV);
3129         if (rc < 0) {
3130                 fprintf(stderr,
3131                         "%s setstripe: cannot move component cursor: %s\n",
3132                         progname, strerror(errno));
3133                 return rc;
3134         }
3135
3136         *end += offset ?: size;
3137         rc = llapi_layout_comp_extent_set(layout, start, *end);
3138         if (rc) {
3139                 fprintf(stderr, "%s setstripe: cannot set extent: %s\n",
3140                         progname, strerror(errno));
3141                 return rc;
3142         }
3143
3144         return 0;
3145 }
3146
3147 /**
3148  * In 'lfs setstripe --component-add' mode, we need to fetch the extent
3149  * end of the last component in the existing file, and adjust the
3150  * first extent start of the components to be added accordingly.
3151  *
3152  * In the create mode, we need to check if the first component is an extendable
3153  * SEL component and extend its length to the extension size (first component
3154  * of the PFL file is initialised at the create time, cannot be 0-lenght.
3155  */
3156 static int layout_adjust_first_extent(char *fname, struct llapi_layout *layout,
3157                                       bool comp_add)
3158 {
3159         struct llapi_layout *head;
3160         uint64_t start = 0, prev_end = 0;
3161         uint64_t end;
3162         int rc, ret = 0;
3163
3164         if (!layout || !(comp_add || llapi_layout_is_composite(layout)))
3165                 return 0;
3166
3167         errno = 0;
3168         while (comp_add) {
3169                 head = llapi_layout_get_by_path(fname, 0);
3170                 if (!head) {
3171                         fprintf(stderr,
3172                                 "%s setstripe: cannot read layout from '%s': %s\n",
3173                                 progname, fname, strerror(errno));
3174                         return -EINVAL;
3175                 } else if (errno == ENODATA) {
3176                         /*
3177                          * file without LOVEA, this component-add will be turned
3178                          * into a component-create.
3179                          */
3180                         llapi_layout_free(head);
3181                         ret = -ENODATA;
3182
3183                         /*
3184                          * the new layout will be added to an empty one, it
3185                          * still needs to be adjusted below
3186                          */
3187                         comp_add = 0;
3188                         break;
3189                 } else if (!llapi_layout_is_composite(head)) {
3190                         fprintf(stderr,
3191                                 "%s setstripe: '%s' not a composite file\n",
3192                                 progname, fname);
3193                         llapi_layout_free(head);
3194                         return -EINVAL;
3195                 }
3196
3197                 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
3198                 if (rc) {
3199                         fprintf(stderr,
3200                                 "%s setstripe: cannot get prev extent: %s\n",
3201                                 progname, strerror(errno));
3202                         llapi_layout_free(head);
3203                         return rc;
3204                 }
3205
3206                 llapi_layout_free(head);
3207                 break;
3208         }
3209
3210         /* Make sure we use the first component of the layout to be added. */
3211         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
3212         if (rc < 0) {
3213                 fprintf(stderr,
3214                         "%s setstripe: cannot move component cursor: %s\n",
3215                         progname, strerror(errno));
3216                 return rc;
3217         }
3218
3219         rc = llapi_layout_comp_extent_get(layout, &start, &end);
3220         if (rc) {
3221                 fprintf(stderr, "%s setstripe: cannot get extent: %s\n",
3222                         progname, strerror(errno));
3223                 return rc;
3224         }
3225
3226         if (start == 0 && end == 0) {
3227                 rc = layout_extend_comp(layout, start, &end,
3228                                         comp_add ? prev_end : 0);
3229                 if (rc)
3230                         return rc;
3231         }
3232
3233         if (start > prev_end || end < prev_end) {
3234                 fprintf(stderr,
3235                         "%s setstripe: first extent [%lu, %lu) not adjacent with extent end %lu\n",
3236                         progname, start, end, prev_end);
3237                 return -EINVAL;
3238         }
3239
3240         rc = llapi_layout_comp_extent_set(layout, prev_end, end);
3241         if (rc) {
3242                 fprintf(stderr,
3243                         "%s setstripe: cannot set component extent [%lu, %lu): %s\n",
3244                         progname, prev_end, end, strerror(errno));
3245                 return rc;
3246         }
3247
3248         return ret;
3249 }
3250
3251 static int mirror_adjust_first_extents(struct mirror_args *list)
3252 {
3253         int rc = 0;
3254
3255         if (!list)
3256                 return 0;
3257
3258         while (list) {
3259                 rc = layout_adjust_first_extent(NULL, list->m_layout, false);
3260                 if (rc)
3261                         break;
3262                 list = list->m_next;
3263         }
3264
3265         return rc;
3266 }
3267
3268 static inline bool arg_is_eof(char *arg)
3269 {
3270         return !strncmp(arg, "-1", strlen("-1")) ||
3271                !strncmp(arg, "EOF", strlen("EOF")) ||
3272                !strncmp(arg, "eof", strlen("eof"));
3273 }
3274
3275 /**
3276  * lfs_mirror_alloc() - Allocate a mirror argument structure.
3277  *
3278  * Return: Valid mirror_args pointer on success and
3279  *         NULL if memory allocation fails.
3280  */
3281 static struct mirror_args *lfs_mirror_alloc(void)
3282 {
3283         struct mirror_args *mirror = NULL;
3284
3285         while (1) {
3286                 mirror = calloc(1, sizeof(*mirror));
3287                 if (mirror) {
3288                         mirror->m_inherit = false;
3289                         break;
3290                 }
3291
3292                 sleep(1);
3293         }
3294
3295         return mirror;
3296 }
3297
3298 /**
3299  * lfs_mirror_free() - Free memory allocated for a mirror argument
3300  *                     structure.
3301  * @mirror: Previously allocated mirror argument structure by
3302  *          lfs_mirror_alloc().
3303  *
3304  * Free memory allocated for @mirror.
3305  *
3306  * Return: void.
3307  */
3308 static void lfs_mirror_free(struct mirror_args *mirror)
3309 {
3310         if (mirror->m_layout)
3311                 llapi_layout_free(mirror->m_layout);
3312         free(mirror);
3313 }
3314
3315 /**
3316  * lfs_mirror_list_free() - Free memory allocated for a mirror list.
3317  * @mirror_list: Previously allocated mirror list.
3318  *
3319  * Free memory allocated for @mirror_list.
3320  *
3321  * Return: void.
3322  */
3323 static void lfs_mirror_list_free(struct mirror_args *mirror_list)
3324 {
3325         struct mirror_args *next_mirror = NULL;
3326
3327         while (mirror_list) {
3328                 next_mirror = mirror_list->m_next;
3329                 lfs_mirror_free(mirror_list);
3330                 mirror_list = next_mirror;
3331         }
3332 }
3333
3334 enum {
3335         LFS_POOL_OPT = 3,
3336         LFS_COMP_COUNT_OPT,
3337         LFS_COMP_START_OPT,
3338         LFS_COMP_FLAGS_OPT,
3339         LFS_COMP_DEL_OPT,
3340         LFS_COMP_SET_OPT,
3341         LFS_COMP_ADD_OPT,
3342         LFS_COMP_NO_VERIFY_OPT,
3343         LFS_PROJID_OPT,
3344         LFS_LAYOUT_FLAGS_OPT, /* used for mirror and foreign flags */
3345         LFS_MIRROR_ID_OPT,
3346         LFS_MIRROR_STATE_OPT,
3347         LFS_LAYOUT_COPY,
3348         LFS_MIRROR_INDEX_OPT,
3349         LFS_LAYOUT_FOREIGN_OPT,
3350         LFS_MODE_OPT,
3351         LFS_NEWERXY_OPT,
3352         LFS_INHERIT_RR_OPT,
3353         LFS_FIND_PERM,
3354 };
3355
3356 #ifndef LCME_USER_MIRROR_FLAGS
3357 /* The mirror flags can be set by users at creation time. */
3358 #define LCME_USER_MIRROR_FLAGS  (LCME_FL_PREF_RW)
3359 #endif
3360
3361 /* functions */
3362 static int lfs_setstripe_internal(int argc, char **argv,
3363                                   enum setstripe_origin opc)
3364 {
3365         struct lfs_setstripe_args        lsa = { 0 };
3366         struct llapi_stripe_param       *param = NULL;
3367         struct find_param                migrate_mdt_param = {
3368                 .fp_max_depth = -1,
3369                 .fp_mdt_index = -1,
3370         };
3371         char                            *fname;
3372         int                              result = 0;
3373         int                              result2 = 0;
3374         char                            *end;
3375         int                              c;
3376         int                              delete = 0;
3377         unsigned long long               size_units = 1;
3378         bool                             migrate_mode = false;
3379         bool                             migrate_mdt_mode = false;
3380         bool                             setstripe_mode = false;
3381         bool                             migration_block = false;
3382         __u64                            migration_flags = 0;
3383         __u32                            tgts[LOV_MAX_STRIPE_COUNT] = { 0 };
3384         int                              comp_del = 0, comp_set = 0;
3385         int                              comp_add = 0;
3386         __u32                            comp_id = 0;
3387         struct llapi_layout             *layout = NULL;
3388         struct llapi_layout             **lpp = &layout;
3389         bool                             mirror_mode = false;
3390         bool                             has_m_file = false;
3391         __u32                            mirror_count = 0;
3392         enum mirror_flags                mirror_flags = 0;
3393         struct mirror_args              *mirror_list = NULL;
3394         struct mirror_args              *new_mirror = NULL;
3395         struct mirror_args              *last_mirror = NULL;
3396         __u16                            mirror_id = 0;
3397         char                             cmd[PATH_MAX];
3398         bool from_yaml = false;
3399         bool from_copy = false;
3400         char *template = NULL;
3401         bool foreign_mode = false;
3402         char *xattr = NULL;
3403         uint32_t type = LU_FOREIGN_TYPE_NONE, flags = 0;
3404         char *mode_opt = NULL;
3405         mode_t previous_umask = 0;
3406         mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
3407
3408         struct option long_opts[] = {
3409 /* find { .val = '0',   .name = "null",         .has_arg = no_argument }, */
3410 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
3411         /* --block is only valid in migrate mode */
3412         { .val = 'b',   .name = "block",        .has_arg = no_argument },
3413 /* find { .val = 'B',   .name = "btime",        .has_arg = required_argument }*/
3414         { .val = LFS_COMP_ADD_OPT,
3415                         .name = "comp-add",     .has_arg = no_argument },
3416         { .val = LFS_COMP_ADD_OPT,
3417                         .name = "component-add", .has_arg = no_argument },
3418         { .val = LFS_COMP_DEL_OPT,
3419                         .name = "comp-del",     .has_arg = no_argument },
3420         { .val = LFS_COMP_DEL_OPT,
3421                         .name = "component-del", .has_arg = no_argument },
3422         { .val = LFS_COMP_FLAGS_OPT,
3423                         .name = "comp-flags",   .has_arg = required_argument },
3424         { .val = LFS_COMP_FLAGS_OPT,
3425                         .name = "component-flags",
3426                                                 .has_arg = required_argument },
3427         { .val = LFS_COMP_SET_OPT,
3428                         .name = "comp-set",     .has_arg = no_argument },
3429         { .val = LFS_COMP_SET_OPT,
3430                         .name = "component-set",
3431                                                 .has_arg = no_argument},
3432         { .val = LFS_COMP_NO_VERIFY_OPT,
3433                         .name = "no-verify",    .has_arg = no_argument},
3434         { .val = LFS_LAYOUT_FLAGS_OPT,
3435                         .name = "flags",        .has_arg = required_argument},
3436         { .val = LFS_LAYOUT_FOREIGN_OPT,
3437                         .name = "foreign",      .has_arg = optional_argument},
3438         { .val = LFS_MIRROR_ID_OPT,
3439                         .name = "mirror-id",    .has_arg = required_argument},
3440         { .val = LFS_MODE_OPT,
3441                         .name = "mode",         .has_arg = required_argument},
3442         { .val = LFS_LAYOUT_COPY,
3443                         .name = "copy",         .has_arg = required_argument},
3444         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument},
3445         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument},
3446         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument},
3447         { .val = 'C',   .name = "overstripe-count",
3448                                                 .has_arg = required_argument},
3449         { .val = 'd',   .name = "delete",       .has_arg = no_argument},
3450         { .val = 'd',   .name = "destroy",      .has_arg = no_argument},
3451         /* --non-direct is only valid in migrate mode */
3452         { .val = 'D',   .name = "non-direct",   .has_arg = no_argument },
3453         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument},
3454         { .val = 'E',   .name = "component-end",
3455                                                 .has_arg = required_argument},
3456         { .val = 'f',   .name = "file",         .has_arg = required_argument },
3457 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
3458 /* find { .val = 'g',   .name = "gid",          .has_arg = no_argument }, */
3459 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
3460         { .val = 'h',   .name = "help",         .has_arg = no_argument },
3461         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument},
3462         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument},
3463         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument},
3464         { .val = 'I',   .name = "comp-id",      .has_arg = required_argument},
3465         { .val = 'I',   .name = "component-id", .has_arg = required_argument},
3466 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
3467         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
3468         { .val = 'm',   .name = "mdt",          .has_arg = required_argument},
3469         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument},
3470         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument},
3471         /* --non-block is only valid in migrate mode */
3472         { .val = 'n',   .name = "non-block",    .has_arg = no_argument },
3473         { .val = 'N',   .name = "mirror-count", .has_arg = optional_argument},
3474         { .val = 'o',   .name = "ost",          .has_arg = required_argument },
3475 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3476         { .val = 'o',   .name = "ost-list",     .has_arg = required_argument },
3477         { .val = 'o',   .name = "ost_list",     .has_arg = required_argument },
3478 #endif
3479         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
3480 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
3481 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
3482 /* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
3483 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
3484         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
3485         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
3486 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
3487 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
3488 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
3489 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
3490         /* --verbose is only valid in migrate mode */
3491         { .val = 'v',   .name = "verbose",      .has_arg = no_argument},
3492         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
3493 /* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/
3494         { .val = 'y',   .name = "yaml",         .has_arg = required_argument },
3495         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument},
3496         { .val = 'z',   .name = "extension-size", .has_arg = required_argument},
3497         { .name = NULL } };
3498
3499         setstripe_args_init(&lsa);
3500
3501         migrate_mode = (opc == SO_MIGRATE);
3502         mirror_mode = (opc == SO_MIRROR_CREATE || opc == SO_MIRROR_EXTEND);
3503         setstripe_mode = (opc == SO_SETSTRIPE);
3504         if (opc == SO_MIRROR_DELETE) {
3505                 delete = 1;
3506                 mirror_flags = MF_DESTROY;
3507         }
3508
3509         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
3510         progname = cmd;
3511         while ((c = getopt_long(argc, argv,
3512                                 "bc:C:dDE:f:hH:i:I:m:N::no:p:L:s:S:vx:y:z:",
3513                                 long_opts, NULL)) >= 0) {
3514                 size_units = 1;
3515                 switch (c) {
3516                 case 0:
3517                         /* Long options. */
3518                         break;
3519                 case LFS_COMP_ADD_OPT:
3520                         comp_add = 1;
3521                         break;
3522                 case LFS_COMP_DEL_OPT:
3523                         comp_del = 1;
3524                         break;
3525                 case LFS_COMP_FLAGS_OPT:
3526                         result = comp_str2flags(optarg, &lsa.lsa_comp_flags,
3527                                                 &lsa.lsa_comp_neg_flags);
3528                         if (result != 0)
3529                                 goto usage_error;
3530                         if (mirror_mode && lsa.lsa_comp_neg_flags) {
3531                                 fprintf(stderr,
3532                                         "%s: inverted flags are not supported\n",
3533                                         progname);
3534                                 goto usage_error;
3535                         }
3536                         break;
3537                 case LFS_COMP_SET_OPT:
3538                         comp_set = 1;
3539                         break;
3540                 case LFS_COMP_NO_VERIFY_OPT:
3541                         mirror_flags |= MF_NO_VERIFY;
3542                         break;
3543                 case LFS_MIRROR_ID_OPT: {
3544                         unsigned long int id;
3545
3546                         errno = 0;
3547                         id = strtoul(optarg, &end, 0);
3548                         if (errno != 0 || *end != '\0' || id == 0 ||
3549                             id > UINT16_MAX) {
3550                                 fprintf(stderr,
3551                                         "%s %s: invalid mirror ID '%s'\n",
3552                                         progname, argv[0], optarg);
3553                                 goto usage_error;
3554                         }
3555
3556                         mirror_id = (__u16)id;
3557                         break;
3558                 }
3559                 case LFS_LAYOUT_FLAGS_OPT: {
3560                         uint32_t neg_flags;
3561
3562                         /* check for numeric flags (foreign and mirror cases) */
3563                         if (setstripe_mode && !mirror_mode && !last_mirror) {
3564                                 errno = 0;
3565                                 flags = strtoul(optarg, &end, 16);
3566                                 if (errno != 0 || *end != '\0' ||
3567                                     flags >= UINT32_MAX) {
3568                                         fprintf(stderr,
3569                                                 "%s %s: invalid hex flags '%s'\n",
3570                                                 progname, argv[0], optarg);
3571                                         return CMD_HELP;
3572                                 }
3573                                 if (!foreign_mode) {
3574                                         fprintf(stderr,
3575                                                 "%s %s: hex flags must be specified with --foreign option\n",
3576                                                 progname, argv[0]);
3577                                         return CMD_HELP;
3578                                 }
3579                                 break;
3580                         }
3581
3582                         if (!mirror_mode || !last_mirror) {
3583                                 fprintf(stderr,
3584                                         "error: %s: --flags must be specified with --mirror-count|-N option\n",
3585                                         progname);
3586                                 goto usage_error;
3587                         }
3588
3589                         result = comp_str2flags(optarg, &last_mirror->m_flags,
3590                                                 &neg_flags);
3591                         if (result != 0)
3592                                 goto usage_error;
3593
3594                         if (neg_flags) {
3595                                 fprintf(stderr,
3596                                         "%s: inverted flags are not supported\n",
3597                                         progname);
3598                                 result = -EINVAL;
3599                                 goto usage_error;
3600                         }
3601                         if (last_mirror->m_flags & ~LCME_USER_MIRROR_FLAGS) {
3602                                 fprintf(stderr,
3603                                         "%s: unsupported mirror flags: %s\n",
3604                                         progname, optarg);
3605                                 result = -EINVAL;
3606                                 goto error;
3607                         }
3608                         break;
3609                 }
3610                 case LFS_LAYOUT_FOREIGN_OPT:
3611                         if (optarg) {
3612                                 /* check pure numeric */
3613                                 type = strtoul(optarg, &end, 0);
3614                                 if (*end) {
3615                                         /* check name */
3616                                         type = check_foreign_type_name(optarg);
3617                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
3618                                                 fprintf(stderr,
3619                                                         "%s %s: unrecognized foreign type '%s'\n",
3620                                                         progname, argv[0],
3621                                                         optarg);
3622                                                 return CMD_HELP;
3623                                         }
3624                                 } else if (type >= UINT32_MAX) {
3625                                         fprintf(stderr,
3626                                                 "%s %s: invalid foreign type '%s'\n",
3627                                                 progname, argv[0], optarg);
3628                                         return CMD_HELP;
3629                                 }
3630                         }
3631                         foreign_mode = true;
3632                         break;
3633                 case LFS_MODE_OPT:
3634                         mode_opt = optarg;
3635                         if (mode_opt) {
3636                                 mode = strtoul(mode_opt, &end, 8);
3637                                 if (*end != '\0') {
3638                                         fprintf(stderr,
3639                                                 "%s %s: bad mode '%s'\n",
3640                                                 progname, argv[0], mode_opt);
3641                                         return CMD_HELP;
3642                                 }
3643                                 previous_umask = umask(0);
3644                         }
3645                         break;
3646                 case LFS_LAYOUT_COPY:
3647                         from_copy = true;
3648                         template = optarg;
3649                         break;
3650                 case 'b':
3651                         if (!migrate_mode) {
3652                                 fprintf(stderr,
3653                                         "%s %s: -b|--block valid only for migrate command\n",
3654                                         progname, argv[0]);
3655                                 goto usage_error;
3656                         }
3657                         migration_block = true;
3658                         break;
3659                 case 'C':
3660                         if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) {
3661                                 fprintf(stderr,
3662                                         "%s %s: -C|--overstripe-count incompatible with DoM layout\n",
3663                                         progname, argv[0]);
3664                                 goto usage_error;
3665                         }
3666                         lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
3667                         /* fall through */
3668                 case 'c':
3669                         errno = 0;
3670                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
3671                         if (errno != 0 || *end != '\0'||
3672                             lsa.lsa_stripe_count < -1 ||
3673                             lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
3674                                 fprintf(stderr,
3675                                         "%s %s: invalid stripe count '%s'\n",
3676                                         progname, argv[0], optarg);
3677                                 goto usage_error;
3678                         }
3679
3680                         if (lsa.lsa_stripe_count == -1)
3681                                 lsa.lsa_stripe_count = LLAPI_LAYOUT_WIDE;
3682                         break;
3683                 case 'd':
3684                         /* delete the default striping pattern */
3685                         delete = 1;
3686                         if (opc == SO_MIRROR_SPLIT) {
3687                                 if (has_m_file) {
3688                                         fprintf(stderr,
3689                                               "%s %s: -d cannot used with -f\n",
3690                                                 progname, argv[0]);
3691                                         goto usage_error;
3692                                 }
3693                                 mirror_flags |= MF_DESTROY;
3694                         }
3695                         break;
3696                 case 'D':
3697                         if (!migrate_mode) {
3698                                 fprintf(stderr,
3699                                         "%s %s: -D|--non-direct is valid only for migrate command\n",
3700                                         progname, argv[0]);
3701                                 goto usage_error;
3702                         }
3703                         migration_flags |= MIGRATION_NONDIRECT;
3704                         break;
3705                 case 'E':
3706                         if (lsa.lsa_comp_end != 0) {
3707                                 result = comp_args_to_layout(lpp, &lsa, true);
3708                                 if (result) {
3709                                         fprintf(stderr, "%s: invalid layout\n",
3710                                                 progname);
3711                                         goto usage_error;
3712                                 }
3713
3714                                 setstripe_args_init_inherit(&lsa);
3715                         }
3716
3717                         if (arg_is_eof(optarg)) {
3718                                 lsa.lsa_comp_end = LUSTRE_EOF;
3719                         } else {
3720                                 result = llapi_parse_size(optarg,
3721                                                           &lsa.lsa_comp_end,
3722                                                           &size_units, 0);
3723                                 /* assume units of KB if too small */
3724                                 if (lsa.lsa_comp_end < 4096)
3725                                         lsa.lsa_comp_end *= 1024;
3726                                 if (result ||
3727                                     lsa.lsa_comp_end & (LOV_MIN_STRIPE_SIZE - 1)) {
3728                                         fprintf(stderr,
3729                                                 "%s %s: invalid component end '%s'\n",
3730                                                 progname, argv[0], optarg);
3731                                         goto usage_error;
3732                                 }
3733                         }
3734                         break;
3735                 case 'H':
3736                         if (!migrate_mode) {
3737                                 fprintf(stderr,
3738                                         "--mdt-hash is valid only for migrate command\n");
3739                                 return CMD_HELP;
3740                         }
3741
3742                         lsa.lsa_pattern = check_hashtype(optarg);
3743                         if (lsa.lsa_pattern == 0) {
3744                                 fprintf(stderr,
3745                                         "%s %s: bad stripe hash type '%s'\n",
3746                                         progname, argv[0], optarg);
3747                                 return CMD_HELP;
3748                         }
3749                         break;
3750                 case 'i':
3751                         errno = 0;
3752                         lsa.lsa_stripe_off = strtol(optarg, &end, 0);
3753                         if (errno != 0 || *end != '\0' ||
3754                             lsa.lsa_stripe_off < -1 ||
3755                             lsa.lsa_stripe_off > LOV_V1_INSANE_STRIPE_COUNT) {
3756                                 fprintf(stderr,
3757                                         "%s %s: invalid stripe offset '%s'\n",
3758                                         progname, argv[0], optarg);
3759                                 goto usage_error;
3760                         }
3761                         if (lsa.lsa_stripe_off == -1)
3762                                 lsa.lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
3763                         break;
3764                 case 'I':
3765                         comp_id = strtoul(optarg, &end, 0);
3766                         if (*end != '\0' || comp_id == 0 ||
3767                             comp_id > LCME_ID_MAX) {
3768                                 fprintf(stderr,
3769                                         "%s %s: invalid component ID '%s'\n",
3770                                         progname, argv[0], optarg);
3771                                 goto usage_error;
3772                         }
3773                         break;
3774                 case 'f':
3775                         if (opc != SO_MIRROR_EXTEND && opc != SO_MIRROR_SPLIT) {
3776                                 fprintf(stderr,
3777                                         "error: %s: invalid option: %s\n",
3778                                         progname, argv[optopt + 1]);
3779                                 goto usage_error;
3780                         }
3781                         if (opc == SO_MIRROR_EXTEND) {
3782                                 if (!last_mirror) {
3783                                         fprintf(stderr,
3784                                 "error: %s: '-N' must exist in front of '%s'\n",
3785                                                 progname, argv[optopt + 1]);
3786                                         goto usage_error;
3787                                 }
3788                                 last_mirror->m_file = optarg;
3789                                 last_mirror->m_count = 1;
3790                         } else {
3791                                 /* mirror split */
3792                                 if (!mirror_list)
3793                                         mirror_list = lfs_mirror_alloc();
3794                                 mirror_list->m_file = optarg;
3795                         }
3796                         has_m_file = true;
3797                         break;
3798                 case 'L':
3799                         if (strcmp(argv[optind - 1], "mdt") == 0) {
3800                                 /* Can be only the first component */
3801                                 if (layout) {
3802                                         result = -EINVAL;
3803                                         fprintf(stderr,
3804                                                 "error: 'mdt' layout can be only the first one\n");
3805                                         goto error;
3806                                 }
3807                                 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
3808                                         result = -EFBIG;
3809                                         fprintf(stderr,
3810                                                 "error: 'mdt' layout size is too big\n");
3811                                         goto error;
3812                                 }
3813                                 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
3814                                 lsa.lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
3815                         } else if (strcmp(argv[optind - 1], "raid0") != 0) {
3816                                 result = -EINVAL;
3817                                 fprintf(stderr,
3818                                         "error: layout '%s' is unknown, supported layouts are: 'mdt', 'raid0'\n",
3819                                         argv[optind]);
3820                                 goto error;
3821                         }
3822                         break;
3823                 case 'm':
3824                         if (!migrate_mode) {
3825                                 fprintf(stderr,
3826                                         "%s %s: -m|--mdt-index is valid only for migrate command\n",
3827                                         progname, argv[0]);
3828                                 goto usage_error;
3829                         }
3830                         migrate_mdt_mode = true;
3831                         lsa.lsa_nr_tgts = parse_targets(tgts,
3832                                                 sizeof(tgts) / sizeof(__u32),
3833                                                 lsa.lsa_nr_tgts, optarg, NULL);
3834                         if (lsa.lsa_nr_tgts < 0) {
3835                                 fprintf(stderr,
3836                                         "%s: invalid MDT target(s) '%s'\n",
3837                                         progname, optarg);
3838                                 goto usage_error;
3839                         }
3840
3841                         lsa.lsa_tgts = tgts;
3842                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
3843                                 lsa.lsa_stripe_off = tgts[0];
3844                         break;
3845                 case 'n':
3846                         if (!migrate_mode) {
3847                                 fprintf(stderr,
3848                                         "%s %s: -n|--non-block valid only for migrate command\n",
3849                                         progname, argv[0]);
3850                                 goto usage_error;
3851                         }
3852                         migration_flags |= MIGRATION_NONBLOCK;
3853                         break;
3854                 case 'N':
3855                         if (opc == SO_SETSTRIPE) {
3856                                 opc = SO_MIRROR_CREATE;
3857                                 mirror_mode = true;
3858                         }
3859                         mirror_count = 1;
3860                         if (optarg) {
3861                                 errno = 0;
3862                                 mirror_count = strtoul(optarg, &end, 0);
3863                                 if (errno != 0 || *end != '\0' ||
3864                                     mirror_count == 0 ||
3865                                     mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
3866                                         fprintf(stderr,
3867                                                 "error: %s: bad mirror count: %s\n",
3868                                                 progname, optarg);
3869                                         result = -EINVAL;
3870                                         goto error;
3871                                 }
3872                         }
3873
3874                         new_mirror = lfs_mirror_alloc();
3875                         new_mirror->m_count = mirror_count;
3876
3877                         if (!mirror_list)
3878                                 mirror_list = new_mirror;
3879
3880                         if (last_mirror) {
3881                                 /* wrap up last mirror */
3882                                 if (!setstripe_args_specified(&lsa))
3883                                         last_mirror->m_inherit = true;
3884                                 if (lsa.lsa_comp_end == 0)
3885                                         lsa.lsa_comp_end = LUSTRE_EOF;
3886
3887                                 result = comp_args_to_layout(lpp, &lsa, true);
3888                                 if (result) {
3889                                         lfs_mirror_free(new_mirror);
3890                                         goto error;
3891                                 }
3892
3893                                 setstripe_args_init_inherit(&lsa);
3894
3895                                 last_mirror->m_next = new_mirror;
3896                         }
3897
3898                         last_mirror = new_mirror;
3899                         lpp = &last_mirror->m_layout;
3900                         break;
3901                 case 'o':
3902 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3903                         if (strcmp(argv[optind - 1], "--ost-list") == 0)
3904                                 fprintf(stderr,
3905                                         "warning: '--ost-list' is deprecated, use '--ost' instead\n");
3906 #endif
3907                         if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) {
3908                                 fprintf(stderr,
3909                                         "%s %s: -o|--ost incompatible with DoM layout\n",
3910                                         progname, argv[0]);
3911                                 goto usage_error;
3912                         }
3913                         /*
3914                          * -o allows overstriping, and must note it because
3915                          * parse_targets is shared with MDT striping, which
3916                          * does not allow duplicates
3917                          */
3918                         lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
3919                         lsa.lsa_nr_tgts = parse_targets(tgts,
3920                                                 sizeof(tgts) / sizeof(__u32),
3921                                                 lsa.lsa_nr_tgts, optarg,
3922                                                 &lsa.lsa_pattern);
3923                         if (lsa.lsa_nr_tgts < 0) {
3924                                 fprintf(stderr,
3925                                         "%s %s: invalid OST target(s) '%s'\n",
3926                                         progname, argv[0], optarg);
3927                                 goto usage_error;
3928                         }
3929
3930                         lsa.lsa_tgts = tgts;
3931                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
3932                                 lsa.lsa_stripe_off = tgts[0];
3933                         break;
3934                 case 'p':
3935                         if (!optarg)
3936                                 goto usage_error;
3937                         lsa.lsa_pool_name = optarg;
3938
3939                         if (strlen(lsa.lsa_pool_name) == 0 ||
3940                             strncmp(lsa.lsa_pool_name, "none",
3941                                     LOV_MAXPOOLNAME) == 0)
3942                                 lsa.lsa_pool_name = NULL;
3943                         break;
3944                 case 'S':
3945                         result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
3946                                                   &size_units, 0);
3947                         /* assume units of KB if too small to be valid */
3948                         if (lsa.lsa_stripe_size < 4096)
3949                                 lsa.lsa_stripe_size *= 1024;
3950                         if (result ||
3951                             lsa.lsa_stripe_size & (LOV_MIN_STRIPE_SIZE - 1)) {
3952                                 fprintf(stderr,
3953                                         "%s %s: invalid stripe size '%s'\n",
3954                                         progname, argv[0], optarg);
3955                                 goto usage_error;
3956                         }
3957                         break;
3958                 case 'v':
3959                         if (!migrate_mode) {
3960                                 fprintf(stderr,
3961                                         "%s %s: -v|--verbose valid only for migrate command\n",
3962                                         progname, argv[0]);
3963                                 goto usage_error;
3964                         }
3965                         migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
3966                         migration_flags = MIGRATION_VERBOSE;
3967                         break;
3968                 case 'x':
3969                         xattr = optarg;
3970                         break;
3971                 case 'y':
3972                         from_yaml = true;
3973                         template = optarg;
3974                         break;
3975                 case 'z':
3976                         result = llapi_parse_size(optarg,
3977                                                   &lsa.lsa_extension_size,
3978                                                   &size_units, 0);
3979                         if (result) {
3980                                 fprintf(stderr,
3981                                         "%s %s: invalid extension size '%s'\n",
3982                                         progname, argv[0], optarg);
3983                                 goto usage_error;
3984                         }
3985
3986                         lsa.lsa_extension_comp = true;
3987                         break;
3988                 default:
3989                         fprintf(stderr, "%s: unrecognized option '%s'\n",
3990                                 progname, argv[optind - 1]);
3991                 case 'h':
3992                         goto usage_error;
3993                 }
3994         }
3995
3996         fname = argv[optind];
3997
3998         if (optind == argc) {
3999                 fprintf(stderr, "%s %s: FILE must be specified\n",
4000                         progname, argv[0]);
4001                 goto usage_error;
4002         }
4003
4004         /* lfs migrate $filename should keep the file's layout by default */
4005         if (migrate_mode && !layout && !from_yaml &&
4006             !setstripe_args_specified(&lsa) && !lsa.lsa_pool_name)
4007                 from_copy = true;
4008
4009         if (xattr && !foreign_mode) {
4010                 /*
4011                  * only print a warning as this is harmless and will be ignored
4012                  */
4013                 fprintf(stderr,
4014                         "%s %s: xattr has been specified for non-foreign layout\n",
4015                         progname, argv[0]);
4016         } else if (foreign_mode && !xattr) {
4017                 fprintf(stderr,
4018                         "%s %s: xattr must be provided in foreign mode\n",
4019                         progname, argv[0]);
4020                 goto usage_error;
4021         }
4022
4023         if (foreign_mode && (!setstripe_mode || comp_add | comp_del ||
4024             comp_set || comp_id || delete || from_copy ||
4025             setstripe_args_specified(&lsa) || lsa.lsa_nr_tgts ||
4026             lsa.lsa_tgts)) {
4027                 fprintf(stderr,
4028                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
4029                         progname, argv[0]);
4030                 return CMD_HELP;
4031         }
4032
4033         if (mirror_mode && mirror_count == 0) {
4034                 fprintf(stderr,
4035                         "error: %s: --mirror-count|-N option is required\n",
4036                         progname);
4037                 result = -EINVAL;
4038                 goto error;
4039         }
4040
4041         if (mirror_mode) {
4042                 if (!setstripe_args_specified(&lsa))
4043                         last_mirror->m_inherit = true;
4044                 if (lsa.lsa_comp_end == 0)
4045                         lsa.lsa_comp_end = LUSTRE_EOF;
4046         }
4047
4048         if (lsa.lsa_comp_end != 0) {
4049                 result = comp_args_to_layout(lpp, &lsa, true);
4050                 if (result) {
4051                         fprintf(stderr, "error: %s: invalid layout\n",
4052                                 progname);
4053                         result = -EINVAL;
4054                         goto error;
4055                 }
4056         }
4057
4058         if (mirror_flags & MF_NO_VERIFY) {
4059                 if (opc != SO_MIRROR_EXTEND) {
4060                         fprintf(stderr,
4061                                 "error: %s: --no-verify is valid only for lfs mirror extend command\n",
4062                                 progname);
4063                         result = -EINVAL;
4064                         goto error;
4065                 } else if (!has_m_file) {
4066                         fprintf(stderr,
4067                                 "error: %s: --no-verify must be specified with -f <victim_file> option\n",
4068                                 progname);
4069                         result = -EINVAL;
4070                         goto error;
4071                 }
4072         }
4073
4074         if (comp_set && !comp_id && !lsa.lsa_pool_name) {
4075                 fprintf(stderr,
4076                         "%s %s: --component-set doesn't have component-id set\n",
4077                         progname, argv[0]);
4078                 goto usage_error;
4079         }
4080
4081         if ((delete + comp_set + comp_del + comp_add) > 1) {
4082                 fprintf(stderr,
4083                         "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
4084                         progname, argv[0]);
4085                 goto usage_error;
4086         }
4087
4088         if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
4089                        lsa.lsa_comp_flags != 0 || layout != NULL)) {
4090                 fprintf(stderr,
4091                         "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
4092                         progname, argv[0]);
4093                 goto usage_error;
4094         }
4095
4096         if ((comp_set || comp_del) &&
4097             (setstripe_args_specified(&lsa) || layout != NULL)) {
4098                 fprintf(stderr,
4099                         "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
4100                         progname, argv[0]);
4101                 goto usage_error;
4102         }
4103
4104         if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
4105                 fprintf(stderr,
4106                         "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
4107                         progname, argv[0]);
4108                 goto usage_error;
4109         }
4110
4111         if (comp_add || comp_del) {
4112                 struct stat st;
4113
4114                 result = lstat(fname, &st);
4115                 if (result == 0 && S_ISDIR(st.st_mode)) {
4116                         fprintf(stderr,
4117                                 "%s setstripe: cannot use --component-add or --component-del for directory\n",
4118                                 progname);
4119                         goto usage_error;
4120                 }
4121
4122                 if (mirror_mode) {
4123                         fprintf(stderr,
4124                                 "error: %s: can't use --component-add or --component-del for mirror operation\n",
4125                                 progname);
4126                         goto usage_error;
4127                 }
4128         }
4129
4130         if (comp_add) {
4131                 if (!layout) {
4132                         fprintf(stderr,
4133                                 "%s %s: option -E must be specified with --component-add\n",
4134                                 progname, argv[0]);
4135                         goto usage_error;
4136                 }
4137         }
4138
4139         if (from_yaml && from_copy) {
4140                 fprintf(stderr,
4141                         "%s: can't specify --yaml and --copy together\n",
4142                         progname);
4143                 goto error;
4144         }
4145
4146         if ((from_yaml || from_copy) &&
4147             (setstripe_args_specified(&lsa) || layout != NULL)) {
4148                 fprintf(stderr,
4149                         "error: %s: can't specify --yaml or --copy with -c, -S, -i, -o, -p or -E options.\n",
4150                         argv[0]);
4151                 goto error;
4152         }
4153
4154         if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
4155                 fprintf(stderr,
4156                         "%s %s: options --non-block and --block are mutually exclusive\n",
4157                         progname, argv[0]);
4158                 goto usage_error;
4159         }
4160
4161         if (!comp_del && !comp_set && opc != SO_MIRROR_SPLIT &&
4162             opc != SO_MIRROR_DELETE && comp_id != 0) {
4163                 fprintf(stderr,
4164                         "%s: option -I can only be used with --component-del or --component-set or lfs mirror split\n",
4165                         progname);
4166                 goto usage_error;
4167         }
4168
4169         if (migrate_mdt_mode) {
4170                 struct lmv_user_md *lmu;
4171
4172                 /* initialize migrate mdt parameters */
4173                 lmu = calloc(1, lmv_user_md_size(lsa.lsa_nr_tgts,
4174                                                  LMV_USER_MAGIC_SPECIFIC));
4175                 if (!lmu) {
4176                         fprintf(stderr,
4177                                 "%s %s: cannot allocate memory for lmv_user_md: %s\n",
4178                                 progname, argv[0], strerror(ENOMEM));
4179                         result = -ENOMEM;
4180                         goto error;
4181                 }
4182                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
4183                         lmu->lum_stripe_count = lsa.lsa_stripe_count;
4184                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT) {
4185                         fprintf(stderr,
4186                                 "%s %s: migrate should specify MDT index\n",
4187                                 progname, argv[0]);
4188                         free(lmu);
4189                         goto usage_error;
4190                 }
4191                 lmu->lum_stripe_offset = lsa.lsa_stripe_off;
4192                 if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
4193                         lmu->lum_hash_type = lsa.lsa_pattern;
4194                 else
4195                         lmu->lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
4196                 if (lsa.lsa_pool_name) {
4197                         strncpy(lmu->lum_pool_name, lsa.lsa_pool_name,
4198                                 sizeof(lmu->lum_pool_name) - 1);
4199                         lmu->lum_pool_name[sizeof(lmu->lum_pool_name) - 1] = 0;
4200                 }
4201                 if (lsa.lsa_nr_tgts > 1) {
4202                         int i;
4203
4204                         if (lsa.lsa_stripe_count > 0 &&
4205                             lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
4206                             lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
4207                                 fprintf(stderr,
4208                                         "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
4209                                         progname, lsa.lsa_stripe_count,
4210                                         lsa.lsa_nr_tgts);
4211                                 free(lmu);
4212                                 goto usage_error;
4213                         }
4214
4215                         lmu->lum_magic = LMV_USER_MAGIC_SPECIFIC;
4216                         lmu->lum_stripe_count = lsa.lsa_nr_tgts;
4217                         for (i = 0; i < lsa.lsa_nr_tgts; i++)
4218                                 lmu->lum_objects[i].lum_mds = lsa.lsa_tgts[i];
4219                 } else {
4220                         lmu->lum_magic = LMV_USER_MAGIC;
4221                 }
4222
4223                 migrate_mdt_param.fp_lmv_md = lmu;
4224                 migrate_mdt_param.fp_migrate = 1;
4225         } else if (!layout) {
4226                 if (lsa_args_stripe_count_check(&lsa))
4227                         goto usage_error;
4228
4229                 /* initialize stripe parameters */
4230                 param = calloc(1, offsetof(typeof(*param),
4231                                lsp_osts[lsa.lsa_nr_tgts]));
4232                 if (!param) {
4233                         fprintf(stderr,
4234                                 "%s %s: cannot allocate memory for parameters: %s\n",
4235                                 progname, argv[0], strerror(ENOMEM));
4236                         result = -ENOMEM;
4237                         goto error;
4238                 }
4239
4240                 if (lsa.lsa_stripe_size != LLAPI_LAYOUT_DEFAULT)
4241                         param->lsp_stripe_size = lsa.lsa_stripe_size;
4242                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
4243                         if (lsa.lsa_stripe_count == LLAPI_LAYOUT_WIDE)
4244                                 param->lsp_stripe_count = -1;
4245                         else
4246                                 param->lsp_stripe_count = lsa.lsa_stripe_count;
4247                 }
4248                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4249                         param->lsp_stripe_offset = -1;
4250                 else
4251                         param->lsp_stripe_offset = lsa.lsa_stripe_off;
4252                 param->lsp_stripe_pattern =
4253                                 llapi_pattern_to_lov(lsa.lsa_pattern);
4254                 if (param->lsp_stripe_pattern == EINVAL) {
4255                         fprintf(stderr, "error: %s: invalid stripe pattern\n",
4256                                 argv[0]);
4257                         free(param);
4258                         goto usage_error;
4259                 }
4260                 param->lsp_pool = lsa.lsa_pool_name;
4261                 param->lsp_is_specific = false;
4262
4263                 if (lsa.lsa_nr_tgts > 0) {
4264                         param->lsp_is_specific = true;
4265                         param->lsp_stripe_count = lsa.lsa_nr_tgts;
4266                         memcpy(param->lsp_osts, tgts,
4267                                sizeof(*tgts) * lsa.lsa_nr_tgts);
4268                 }
4269         }
4270
4271         if (from_yaml) {
4272                 /* generate a layout from a YAML template */
4273                 result = lfs_comp_create_from_yaml(template, &layout,
4274                                                    &lsa, tgts);
4275                 if (result) {
4276                         fprintf(stderr,
4277                                 "error: %s: can't create composite layout from template file %s\n",
4278                                 argv[0], template);
4279                         goto error;
4280                 }
4281         }
4282
4283         if (layout != NULL || mirror_list != NULL) {
4284                 if (mirror_list)
4285                         result = mirror_adjust_first_extents(mirror_list);
4286                 else
4287                         result = layout_adjust_first_extent(fname, layout,
4288                                                             comp_add);
4289                 if (result == -ENODATA)
4290                         comp_add = 0;
4291                 else if (result != 0) {
4292                         fprintf(stderr, "error: %s: invalid layout\n",
4293                                 progname);
4294                         goto error;
4295                 }
4296         }
4297
4298         for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
4299                 if (from_copy) {
4300                         layout = llapi_layout_get_by_path(template ?: fname, 0);
4301                         if (!layout) {
4302                                 fprintf(stderr,
4303                                         "%s: can't create composite layout from file %s: %s\n",
4304                                         progname, template ?: fname,
4305                                         strerror(errno));
4306                                 result = -errno;
4307                                 goto error;
4308                         }
4309                 }
4310
4311                 if (migrate_mdt_mode) {
4312                         result = llapi_migrate_mdt(fname, &migrate_mdt_param);
4313                 } else if (migrate_mode) {
4314                         result = lfs_migrate(fname, migration_flags, param,
4315                                              layout);
4316                 } else if (comp_set != 0) {
4317                         result = lfs_component_set(fname, comp_id,
4318                                                    lsa.lsa_pool_name,
4319                                                    lsa.lsa_comp_flags,
4320                                                    lsa.lsa_comp_neg_flags);
4321                 } else if (comp_del != 0) {
4322                         result = lfs_component_del(fname, comp_id,
4323                                                    lsa.lsa_comp_flags,
4324                                                    lsa.lsa_comp_neg_flags);
4325                 } else if (comp_add != 0) {
4326                         result = lfs_component_add(fname, layout);
4327                 } else if (opc == SO_MIRROR_CREATE) {
4328                         result = mirror_create(fname, mirror_list);
4329                 } else if (opc == SO_MIRROR_EXTEND) {
4330                         result = mirror_extend(fname, mirror_list,
4331                                                mirror_flags);
4332                 } else if (opc == SO_MIRROR_SPLIT || opc == SO_MIRROR_DELETE) {
4333                         if (!mirror_id && !comp_id && !lsa.lsa_pool_name) {
4334                                 fprintf(stderr,
4335                                         "%s: no mirror id, component id, or pool name specified to delete from '%s'\n",
4336                                         progname, fname);
4337                                 goto usage_error;
4338                         }
4339                         if (lsa.lsa_pool_name)
4340                                 mirror_flags |= MF_COMP_POOL;
4341                         else if (mirror_id != 0)
4342                                 comp_id = mirror_id;
4343                         else
4344                                 mirror_flags |= MF_COMP_ID;
4345                         if (has_m_file && !strcmp(fname, mirror_list->m_file)) {
4346                                 fprintf(stderr,
4347                                         "%s: the file specified by -f cannot be same as the source file '%s'\n",
4348                                         progname, fname);
4349                                 goto usage_error;
4350                         }
4351                         result = mirror_split(fname, comp_id, lsa.lsa_pool_name,
4352                                               mirror_flags,
4353                                               has_m_file ? mirror_list->m_file :
4354                                               NULL);
4355                 } else if (layout) {
4356                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
4357                                                       mode, layout);
4358                         if (result >= 0) {
4359                                 close(result);
4360                                 result = 0;
4361                         }
4362                 } else if (foreign_mode) {
4363                         result = llapi_file_create_foreign(fname, mode, type,
4364                                                            flags, xattr);
4365                         if (result >= 0) {
4366                                 close(result);
4367                                 result = 0;
4368                         }
4369                 } else {
4370                         result = llapi_file_open_param(fname,
4371                                                        O_CREAT | O_WRONLY,
4372                                                        mode, param);
4373                         if (result >= 0) {
4374                                 close(result);
4375                                 result = 0;
4376                         }
4377                 }
4378                 if (result) {
4379                         /* Save the first error encountered. */
4380                         if (result2 == 0)
4381                                 result2 = result;
4382                         continue;
4383                 }
4384         }
4385
4386         if (mode_opt)
4387                 umask(previous_umask);
4388
4389         free(param);
4390         free(migrate_mdt_param.fp_lmv_md);
4391         llapi_layout_free(layout);
4392         lfs_mirror_list_free(mirror_list);
4393         return result2;
4394 usage_error:
4395         result = CMD_HELP;
4396 error:
4397         llapi_layout_free(layout);
4398         lfs_mirror_list_free(mirror_list);
4399         return result;
4400 }
4401
4402 static int lfs_poollist(int argc, char **argv)
4403 {
4404         if (argc != 2)
4405                 return CMD_HELP;
4406
4407         return llapi_poollist(argv[1]);
4408 }
4409
4410 #define FP_DEFAULT_TIME_MARGIN (24 * 60 * 60)
4411 static time_t set_time(struct find_param *param, time_t *time, time_t *set,
4412                        char *str)
4413 {
4414         long long t = 0;
4415         int sign = 0;
4416         char *endptr = "AD";
4417         char *timebuf;
4418
4419         if (str[0] == '+')
4420                 sign = 1;
4421         else if (str[0] == '-')
4422                 sign = -1;
4423
4424         if (sign)
4425                 str++;
4426
4427         for (timebuf = str; *endptr && *(endptr + 1); timebuf = endptr + 1) {
4428                 long long val = strtoll(timebuf, &endptr, 0);
4429                 int unit = 1;
4430
4431                 switch (*endptr) {
4432                 case  'y':
4433                         unit *= 52; /* 52 weeks + 1 day below */
4434                 case  'w':      /* fallthrough */
4435                         unit *= 7;
4436                         if (param->fp_time_margin == FP_DEFAULT_TIME_MARGIN)
4437                                 param->fp_time_margin *= (1 + unit / 52);
4438                         unit += (*endptr == 'y'); /* +1 day for 365 days/year */
4439                 case '\0': /* days are default unit if none used */
4440                 case  'd':      /* fallthrough */
4441                         unit *= 24;
4442                 case  'h':      /* fallthrough */
4443                         unit *= 60;
4444                 case  'm':      /* fallthrough */
4445                         unit *= 60;
4446                 case  's':      /* fallthrough */
4447                         break;
4448                         /* don't need to multiply by 1 for seconds */
4449                 default:
4450                         fprintf(stderr,
4451                                 "%s find: bad time string '%s': %s\n",
4452                                 progname, timebuf, strerror(EINVAL));
4453                         return LONG_MAX;
4454                 }
4455
4456                 if (param->fp_time_margin == 0 ||
4457                     (*endptr && unit < param->fp_time_margin))
4458                         param->fp_time_margin = unit;
4459
4460                 t += val * unit;
4461         }
4462         if (*time < t) {
4463                 if (sign != 0)
4464                         str--;
4465                 fprintf(stderr, "%s find: bad time '%s': too large\n",
4466                         progname, str);
4467                 return LONG_MAX;
4468         }
4469
4470         *set = *time - t;
4471
4472         return sign;
4473 }
4474
4475 static int str2quotaid(__u32 *id, const char *arg)
4476 {
4477         unsigned long int projid_tmp = 0;
4478         char *endptr = NULL;
4479
4480         projid_tmp = strtoul(arg, &endptr, 10);
4481         if (*endptr != '\0')
4482                 return -EINVAL;
4483         /* UINT32_MAX is not allowed - see projid_valid()/INVALID_PROJID */
4484         if (projid_tmp >= UINT32_MAX)
4485                 return -ERANGE;
4486
4487         *id = projid_tmp;
4488         return 0;
4489 }
4490
4491 static int name2uid(unsigned int *id, const char *name)
4492 {
4493         struct passwd *passwd;
4494
4495         passwd = getpwnam(name);
4496         if (!passwd)
4497                 return -ENOENT;
4498         *id = passwd->pw_uid;
4499
4500         return 0;
4501 }
4502
4503 static int name2gid(unsigned int *id, const char *name)
4504 {
4505         struct group *group;
4506
4507         group = getgrnam(name);
4508         if (!group)
4509                 return -ENOENT;
4510         *id = group->gr_gid;
4511
4512         return 0;
4513 }
4514
4515 static inline int name2projid(unsigned int *id, const char *name)
4516 {
4517         return -ENOTSUP;
4518 }
4519
4520 static int uid2name(char **name, unsigned int id)
4521 {
4522         struct passwd *passwd;
4523
4524         passwd = getpwuid(id);
4525         if (!passwd)
4526                 return -ENOENT;
4527         *name = passwd->pw_name;
4528
4529         return 0;
4530 }
4531
4532 static inline int gid2name(char **name, unsigned int id)
4533 {
4534         struct group *group;
4535
4536         group = getgrgid(id);
4537         if (!group)
4538                 return -ENOENT;
4539         *name = group->gr_name;
4540
4541         return 0;
4542 }
4543
4544 static int name2layout(__u32 *layout, char *name)
4545 {
4546         char *ptr, *layout_name;
4547
4548         *layout = 0;
4549         for (ptr = name; ; ptr = NULL) {
4550                 layout_name = strtok(ptr, ",");
4551                 if (!layout_name)
4552                         break;
4553                 if (strcmp(layout_name, "released") == 0)
4554                         *layout |= LOV_PATTERN_F_RELEASED;
4555                 else if (strcmp(layout_name, "raid0") == 0)
4556                         *layout |= LOV_PATTERN_RAID0;
4557                 else if (strcmp(layout_name, "mdt") == 0)
4558                         *layout |= LOV_PATTERN_MDT;
4559                 else if (strcmp(layout_name, "overstriping") == 0)
4560                         *layout |= LOV_PATTERN_OVERSTRIPING;
4561                 else
4562                         return -1;
4563         }
4564         return 0;
4565 }
4566
4567 static int parse_symbolic(const char *input, mode_t *outmode, const char **end)
4568 {
4569         int loop;
4570         int user, group, other;
4571         int who, all;
4572         char c, op;
4573         mode_t perm;
4574         mode_t usermask;
4575         mode_t previous_flags;
4576
4577         user = group = other = 0;
4578         all = 0;
4579         loop = 1;
4580         perm = 0;
4581         previous_flags = 0;
4582         *end = input;
4583         usermask = 0;
4584
4585         while (loop) {
4586                 switch (*input) {
4587                 case 'u':
4588                         user = 1;
4589                         break;
4590                 case 'g':
4591                         group = 1;
4592                         break;
4593                 case 'o':
4594                         other = 1;
4595                         break;
4596                 case 'a':
4597                         user = group = other = 1;
4598                         all = 1;
4599                         break;
4600                 default:
4601                         loop = 0;
4602                 }
4603
4604                 if (loop)
4605                         input++;
4606         }
4607
4608         who = user || group || other;
4609         if (!who) {
4610                 /* get the umask */
4611                 usermask = umask(0022);
4612                 umask(usermask);
4613                 usermask &= 07777;
4614         }
4615
4616         if (*input == '-' || *input == '+' || *input == '=')
4617                 op = *input++;
4618         else
4619                 /* operation is required */
4620                 return -1;
4621
4622         /* get the flags in *outmode */
4623         switch (*input) {
4624         case 'u':
4625                 previous_flags = (*outmode & 0700);
4626                 perm |= user  ? previous_flags : 0;
4627                 perm |= group ? (previous_flags >> 3) : 0;
4628                 perm |= other ? (previous_flags >> 6) : 0;
4629                 input++;
4630                 goto write_perm;
4631         case 'g':
4632                 previous_flags = (*outmode & 0070);
4633                 perm |= user  ? (previous_flags << 3) : 0;
4634                 perm |= group ? previous_flags : 0;
4635                 perm |= other ? (previous_flags >> 3) : 0;
4636                 input++;
4637                 goto write_perm;
4638         case 'o':
4639                 previous_flags = (*outmode & 0007);
4640                 perm |= user  ? (previous_flags << 6) : 0;
4641                 perm |= group ? (previous_flags << 3) : 0;
4642                 perm |= other ? previous_flags : 0;
4643                 input++;
4644                 goto write_perm;
4645         default:
4646                 break;
4647         }
4648
4649         /* this part is optional,
4650          * if empty perm = 0 and *outmode is not modified
4651          */
4652         loop = 1;
4653         while (loop) {
4654                 c = *input;
4655                 switch (c) {
4656                 case 'r':
4657                         perm |= user  ? 0400 : 0;
4658                         perm |= group ? 0040 : 0;
4659                         perm |= other ? 0004 : 0;
4660                         /* set read permission for uog except for umask's
4661                          * permissions
4662                          */
4663                         perm |= who   ? 0 : (0444 & ~usermask);
4664                         break;
4665                 case 'w':
4666                         perm |= user  ? 0200 : 0;
4667                         perm |= group ? 0020 : 0;
4668                         perm |= other ? 0002 : 0;
4669                         /* set write permission for uog except for umask'
4670                          * permissions
4671                          */
4672                         perm |= who   ? 0 : (0222 & ~usermask);
4673                         break;
4674                 case 'x':
4675                         perm |= user  ? 0100 : 0;
4676                         perm |= group ? 0010 : 0;
4677                         perm |= other ? 0001 : 0;
4678                         /* set execute permission for uog except for umask'
4679                          * permissions
4680                          */
4681                         perm |= who   ? 0 : (0111 & ~usermask);
4682                         break;
4683                 case 'X':
4684                         /*
4685                          * Adds execute permission to 'u', 'g' and/or 'g' if
4686                          * specified and either 'u', 'g' or 'o' already has
4687                          * execute permissions.
4688                          */
4689                         if ((*outmode & 0111) != 0) {
4690                                 perm |= user  ? 0100 : 0;
4691                                 perm |= group ? 0010 : 0;
4692                                 perm |= other ? 0001 : 0;
4693                                 perm |= !who  ? 0111 : 0;
4694                         }
4695                         break;
4696                 case 's':
4697                         /* s is ignored if o is given, but it's not an error */
4698                         if (other && !group && !user)
4699                                 break;
4700                         perm |= user  ? S_ISUID : 0;
4701                         perm |= group ? S_ISGID : 0;
4702                         break;
4703                 case 't':
4704                         /* 't' should be used when 'a' is given
4705                          * or who is empty
4706                          */
4707                         perm |= (!who || all) ? S_ISVTX : 0;
4708                         /* using ugo with t is not an error */
4709                         break;
4710                 default:
4711                         loop = 0;
4712                         break;
4713                 }
4714                 if (loop)
4715                         input++;
4716         }
4717
4718 write_perm:
4719         /* uog flags should be only one character long */
4720         if (previous_flags && (*input != '\0' && *input != ','))
4721                 return -1;
4722
4723         switch (op) {
4724         case '-':
4725                 /* remove the flags from outmode */
4726                 *outmode &= ~perm;
4727                 break;
4728         case '+':
4729                 /* add the flags to outmode */
4730                 *outmode |= perm;
4731                 break;
4732         case '=':
4733                 /* set the flags of outmode to perm */
4734                 if (perm != 0)
4735                         *outmode = perm;
4736                 break;
4737         }
4738
4739         *end = input;
4740         return 0;
4741 }
4742
4743 static int str2mode_t(const char *input, mode_t *outmode)
4744 {
4745         int ret;
4746         const char *iter;
4747
4748         ret = 0;
4749
4750         if (*input >= '0' && *input <= '7') {
4751                 /* parse octal representation */
4752                 char *end;
4753
4754                 iter = input;
4755
4756                 /* look for invalid digits in octal representation */
4757                 while (isdigit(*iter))
4758                         if (*iter++ > '7')
4759                                 return -1;
4760
4761                 errno = 0;
4762                 *outmode = strtoul(input, &end, 8);
4763
4764                 if (errno != 0 || *outmode > 07777) {
4765                         *outmode = 0;
4766                         ret = -1;
4767                 }
4768
4769         } else if (*input == '8' || *input == '9') {
4770                 /* error: invalid octal number */
4771                 ret = -1;
4772         } else {
4773                 /* parse coma seperated list of symbolic representation */
4774                 int rc;
4775                 const char *end;
4776
4777                 *outmode = 0;
4778                 rc = 0;
4779                 end = NULL;
4780
4781                 do {
4782                         rc = parse_symbolic(input, outmode, &end);
4783                         if (rc)
4784                                 return -1;
4785
4786                         input = end+1;
4787                 } while (*end == ',');
4788
4789                 if (*end != '\0')
4790                         ret = -1;
4791         }
4792         return ret;
4793 }
4794
4795 static int lfs_find(int argc, char **argv)
4796 {
4797         int c, rc;
4798         int ret = 0;
4799         time_t t;
4800         struct find_param param = {
4801                 .fp_max_depth = -1,
4802                 .fp_quiet = 1,
4803                 .fp_time_margin = FP_DEFAULT_TIME_MARGIN,
4804         };
4805         struct option long_opts[] = {
4806         { .val = 'A',   .name = "atime",        .has_arg = required_argument },
4807         { .val = 'b',   .name = "blocks",       .has_arg = required_argument },
4808         { .val = 'B',   .name = "btime",        .has_arg = required_argument },
4809         { .val = 'B',   .name = "Btime",        .has_arg = required_argument },
4810         { .val = LFS_COMP_COUNT_OPT,
4811                         .name = "comp-count",   .has_arg = required_argument },
4812         { .val = LFS_COMP_COUNT_OPT,
4813                         .name = "component-count",
4814                                                 .has_arg = required_argument },
4815         { .val = LFS_COMP_FLAGS_OPT,
4816                         .name = "comp-flags",   .has_arg = required_argument },
4817         { .val = LFS_COMP_FLAGS_OPT,
4818                         .name = "component-flags",
4819                                                 .has_arg = required_argument },
4820         { .val = LFS_COMP_START_OPT,
4821                         .name = "comp-start",   .has_arg = required_argument },
4822         { .val = LFS_COMP_START_OPT,
4823                         .name = "component-start",
4824                                                 .has_arg = required_argument },
4825         { .val = LFS_MIRROR_STATE_OPT,
4826                         .name = "mirror-state", .has_arg = required_argument },
4827         { .val = LFS_NEWERXY_OPT,
4828                         .name = "newer",        .has_arg = required_argument},
4829         { .val = LFS_NEWERXY_OPT,
4830                         .name = "neweraa",      .has_arg = required_argument},
4831         { .val = LFS_NEWERXY_OPT,
4832                         .name = "neweram",      .has_arg = required_argument},
4833         { .val = LFS_NEWERXY_OPT,
4834                         .name = "newerac",      .has_arg = required_argument},
4835         { .val = LFS_NEWERXY_OPT,
4836                         .name = "newerab",      .has_arg = required_argument},
4837         { .val = LFS_NEWERXY_OPT,
4838                         .name = "newerma",      .has_arg = required_argument},
4839         { .val = LFS_NEWERXY_OPT,
4840                         .name = "newermm",      .has_arg = required_argument},
4841         { .val = LFS_NEWERXY_OPT,
4842                         .name = "newermc",      .has_arg = required_argument},
4843         { .val = LFS_NEWERXY_OPT,
4844                         .name = "newermb",      .has_arg = required_argument},
4845         { .val = LFS_NEWERXY_OPT,
4846                         .name = "newerca",      .has_arg = required_argument},
4847         { .val = LFS_NEWERXY_OPT,
4848                         .name = "newercm",      .has_arg = required_argument},
4849         { .val = LFS_NEWERXY_OPT,
4850                         .name = "newercc",      .has_arg = required_argument},
4851         { .val = LFS_NEWERXY_OPT,
4852                         .name = "newercb",      .has_arg = required_argument},
4853         { .val = LFS_NEWERXY_OPT,
4854                         .name = "newerba",      .has_arg = required_argument},
4855         { .val = LFS_NEWERXY_OPT,
4856                         .name = "newerbm",      .has_arg = required_argument},
4857         { .val = LFS_NEWERXY_OPT,
4858                         .name = "newerbc",      .has_arg = required_argument},
4859         { .val = LFS_NEWERXY_OPT,
4860                         .name = "newerbb",      .has_arg = required_argument},
4861         { .val = LFS_NEWERXY_OPT,
4862                         .name = "newerBa",      .has_arg = required_argument},
4863         { .val = LFS_NEWERXY_OPT,
4864                         .name = "newerBm",      .has_arg = required_argument},
4865         { .val = LFS_NEWERXY_OPT,
4866                         .name = "newerBc",      .has_arg = required_argument},
4867         { .val = LFS_NEWERXY_OPT,
4868                         .name = "newerBB",      .has_arg = required_argument},
4869         { .val = LFS_NEWERXY_OPT,
4870                         .name = "newerat",      .has_arg = required_argument},
4871         { .val = LFS_NEWERXY_OPT,
4872                         .name = "newermt",      .has_arg = required_argument},
4873         { .val = LFS_NEWERXY_OPT,
4874                         .name = "newerct",      .has_arg = required_argument},
4875         { .val = LFS_NEWERXY_OPT,
4876                         .name = "newerbt",      .has_arg = required_argument},
4877         { .val = LFS_NEWERXY_OPT,
4878                         .name = "newerBt",      .has_arg = required_argument},
4879         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument },
4880         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument },
4881         { .val = 'C',   .name = "ctime",        .has_arg = required_argument },
4882 /* getstripe { .val = 'd', .name = "directory", .has_arg = no_argument }, */
4883         { .val = 'D',   .name = "maxdepth",     .has_arg = required_argument },
4884         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument },
4885         { .val = 'E',   .name = "component-end",
4886                                                 .has_arg = required_argument },
4887 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
4888         { .val = LFS_LAYOUT_FOREIGN_OPT,
4889                         .name = "foreign",      .has_arg = optional_argument},
4890         { .val = 'g',   .name = "gid",          .has_arg = required_argument },
4891         { .val = 'G',   .name = "group",        .has_arg = required_argument },
4892         { .val = 'h',   .name = "help",         .has_arg = no_argument },
4893         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
4894         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument },
4895         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument },
4896 /* getstripe { .val = 'I', .name = "comp-id",   .has_arg = required_argument }*/
4897         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
4898         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
4899         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
4900         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
4901         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument },
4902         { .val = 'M',   .name = "mtime",        .has_arg = required_argument },
4903         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4904         { .val = 'N',   .name = "mirror-count", .has_arg = required_argument },
4905 /* find { .val = 'o'    .name = "or", .has_arg = no_argument }, like find(1) */
4906         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
4907         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
4908         /* no short option for pool yet, can be 'p' after 2.18 */
4909         { .val = LFS_POOL_OPT,
4910                         .name = "pool",         .has_arg = required_argument },
4911         { .val = '0',   .name = "print0",       .has_arg = no_argument },
4912         { .val = 'P',   .name = "print",        .has_arg = no_argument },
4913         { .val = LFS_PROJID_OPT,
4914                         .name = "projid",       .has_arg = required_argument },
4915 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
4916 /* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
4917 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
4918         { .val = 's',   .name = "size",         .has_arg = required_argument },
4919         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
4920         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
4921         { .val = 't',   .name = "type",         .has_arg = required_argument },
4922         { .val = LFS_FIND_PERM,
4923                         .name = "perm",         .has_arg = required_argument },
4924         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
4925         { .val = 'u',   .name = "uid",          .has_arg = required_argument },
4926         { .val = 'U',   .name = "user",         .has_arg = required_argument },
4927         { .val = 'z',   .name = "extension-size",
4928                                                 .has_arg = required_argument },
4929         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument },
4930 /* getstripe { .val = 'v', .name = "verbose",   .has_arg = no_argument }, */
4931 /* getstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
4932         { .name = NULL } };
4933         int optidx = 0;
4934         int pathstart = -1;
4935         int pathend = -1;
4936         int pathbad = -1;
4937         int neg_opt = 0;
4938         time_t *xtime;
4939         int *xsign;
4940         int isoption;
4941         char *endptr;
4942
4943         time(&t);
4944
4945         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
4946         while ((c = getopt_long_only(argc, argv,
4947                 "-0A:b:B:c:C:D:E:g:G:hH:i:L:m:M:n:N:O:Ppqrs:S:t:T:u:U:vz:",
4948                 long_opts, &optidx)) >= 0) {
4949                 xtime = NULL;
4950                 xsign = NULL;
4951                 if (neg_opt)
4952                         --neg_opt;
4953                 /* '!' is part of option */
4954                 /*
4955                  * when getopt_long_only() finds a string which is not
4956                  * an option nor a known option argument it returns 1
4957                  * in that case if we already have found pathstart and pathend
4958                  * (i.e. we have the list of pathnames),
4959                  * the only supported value is "!"
4960                  */
4961                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
4962                 if (!isoption && pathend != -1) {
4963                         fprintf(stderr,
4964                                 "err: %s: filename|dirname must either precede options or follow options\n",
4965                                 argv[0]);
4966                         ret = CMD_HELP;
4967                         goto err;
4968                 }
4969                 if (!isoption && pathstart == -1)
4970                         pathstart = optind - 1;
4971                 if (isoption && pathstart != -1 && pathend == -1)
4972                         pathend = optind - 2;
4973                 switch (c) {
4974                 case 0:
4975                         /* Long options. */
4976                         break;
4977                 case 1:
4978                         /*
4979                          * unknown; opt is "!" or path component,
4980                          * checking done above.
4981                          */
4982                         if (strcmp(optarg, "!") == 0)
4983                                 neg_opt = 2;
4984                         break;
4985                 case 'A':
4986                         xtime = &param.fp_atime;
4987                         xsign = &param.fp_asign;
4988                         param.fp_exclude_atime = !!neg_opt;
4989                         /* no break, this falls through to 'B' for btime */
4990                 case 'B':
4991                         if (c == 'B') {
4992                                 xtime = &param.fp_btime;
4993                                 xsign = &param.fp_bsign;
4994                                 param.fp_exclude_btime = !!neg_opt;
4995                         }
4996                         /* no break, this falls through to 'C' for ctime */
4997                 case 'C':
4998                         if (c == 'C') {
4999                                 xtime = &param.fp_ctime;
5000                                 xsign = &param.fp_csign;
5001                                 param.fp_exclude_ctime = !!neg_opt;
5002                         }
5003                         /* no break, this falls through to 'M' for mtime */
5004                 case 'M':
5005                         if (c == 'M') {
5006                                 xtime = &param.fp_mtime;
5007                                 xsign = &param.fp_msign;
5008                                 param.fp_exclude_mtime = !!neg_opt;
5009                         }
5010                         rc = set_time(&param, &t, xtime, optarg);
5011                         if (rc == LONG_MAX) {
5012                                 ret = -1;
5013                                 goto err;
5014                         }
5015                         if (rc)
5016                                 *xsign = rc;
5017                         break;
5018                 case 'b':
5019                         if (optarg[0] == '+') {
5020                                 param.fp_blocks_sign = -1;
5021                                 optarg++;
5022                         } else if (optarg[0] == '-') {
5023                                 param.fp_blocks_sign =  1;
5024                                 optarg++;
5025                         }
5026
5027                         param.fp_blocks_units = 1024;
5028                         ret = llapi_parse_size(optarg, &param.fp_blocks,
5029                                                &param.fp_blocks_units, 0);
5030                         if (ret) {
5031                                 fprintf(stderr, "error: bad blocks '%s'\n",
5032                                         optarg);
5033                                 goto err;
5034                         }
5035                         param.fp_check_blocks = 1;
5036                         param.fp_exclude_blocks = !!neg_opt;
5037                         break;
5038                 case LFS_COMP_COUNT_OPT:
5039                         if (optarg[0] == '+') {
5040                                 param.fp_comp_count_sign = -1;
5041                                 optarg++;
5042                         } else if (optarg[0] == '-') {
5043                                 param.fp_comp_count_sign =  1;
5044                                 optarg++;
5045                         }
5046
5047                         errno = 0;
5048                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
5049                         if (errno != 0 || *endptr != '\0' ||
5050                             param.fp_comp_count > UINT32_MAX) {
5051                                 fprintf(stderr,
5052                                         "error: bad component count '%s'\n",
5053                                         optarg);
5054                                 goto err;
5055                         }
5056                         param.fp_check_comp_count = 1;
5057                         param.fp_exclude_comp_count = !!neg_opt;
5058                         break;
5059                 case LFS_COMP_FLAGS_OPT:
5060                         rc = comp_str2flags(optarg, &param.fp_comp_flags,
5061                                             &param.fp_comp_neg_flags);
5062                         if (rc) {
5063                                 fprintf(stderr,
5064                                         "error: bad component flags '%s'\n",
5065                                         optarg);
5066                                 goto err;
5067                         }
5068                         param.fp_check_comp_flags = 1;
5069                         if (neg_opt) {
5070                                 __u32 flags = param.fp_comp_neg_flags;
5071
5072                                 param.fp_comp_neg_flags = param.fp_comp_flags;
5073                                 param.fp_comp_flags = flags;
5074                         }
5075                         break;
5076                 case LFS_COMP_START_OPT:
5077                         if (optarg[0] == '+') {
5078                                 param.fp_comp_start_sign = -1;
5079                                 optarg++;
5080                         } else if (optarg[0] == '-') {
5081                                 param.fp_comp_start_sign =  1;
5082                                 optarg++;
5083                         }
5084
5085                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
5086                                               &param.fp_comp_start_units, 0);
5087                         if (rc) {
5088                                 fprintf(stderr,
5089                                         "error: bad component start '%s'\n",
5090                                         optarg);
5091                                 goto err;
5092                         }
5093                         param.fp_check_comp_start = 1;
5094                         param.fp_exclude_comp_start = !!neg_opt;
5095                         break;
5096                 case LFS_MIRROR_STATE_OPT:
5097                         rc = mirror_str2state(optarg, &param.fp_mirror_state,
5098                                               &param.fp_mirror_neg_state);
5099                         if (rc) {
5100                                 fprintf(stderr,
5101                                         "error: bad mirrored file state '%s'\n",
5102                                         optarg);
5103                                 goto err;
5104                         }
5105                         param.fp_check_mirror_state = 1;
5106                         if (neg_opt) {
5107                                 __u16 state = param.fp_mirror_neg_state;
5108
5109                                 param.fp_mirror_neg_state =
5110                                         param.fp_mirror_state;
5111                                 param.fp_mirror_state = state;
5112                         }
5113                         break;
5114                 case 'c':
5115                         if (optarg[0] == '+') {
5116                                 param.fp_stripe_count_sign = -1;
5117                                 optarg++;
5118                         } else if (optarg[0] == '-') {
5119                                 param.fp_stripe_count_sign =  1;
5120                                 optarg++;
5121                         }
5122
5123                         errno = 0;
5124                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
5125                         if (errno != 0 || *endptr != '\0' ||
5126                             param.fp_stripe_count > LOV_MAX_STRIPE_COUNT) {
5127                                 fprintf(stderr,
5128                                         "error: bad stripe_count '%s'\n",
5129                                         optarg);
5130                                 ret = -1;
5131                                 goto err;
5132                         }
5133                         param.fp_check_stripe_count = 1;
5134                         param.fp_exclude_stripe_count = !!neg_opt;
5135                         break;
5136                 case 'D':
5137                         errno = 0;
5138                         param.fp_max_depth = strtol(optarg, 0, 0);
5139                         if (errno != 0 || param.fp_max_depth < 0) {
5140                                 fprintf(stderr,
5141                                         "error: bad maxdepth '%s'\n",
5142                                         optarg);
5143                                 ret = -1;
5144                                 goto err;
5145                         }
5146                         break;
5147                 case 'E':
5148                         if (optarg[0] == '+') {
5149                                 param.fp_comp_end_sign = -1;
5150                                 optarg++;
5151                         } else if (optarg[0] == '-') {
5152                                 param.fp_comp_end_sign =  1;
5153                                 optarg++;
5154                         }
5155
5156                         if (arg_is_eof(optarg)) {
5157                                 param.fp_comp_end = LUSTRE_EOF;
5158                                 param.fp_comp_end_units = 1;
5159                                 rc = 0;
5160                         } else {
5161                                 rc = llapi_parse_size(optarg,
5162                                                 &param.fp_comp_end,
5163                                                 &param.fp_comp_end_units, 0);
5164                                 /* assume units of KB if too small */
5165                                 if (param.fp_comp_end < 4096)
5166                                         param.fp_comp_end *= 1024;
5167                         }
5168                         if (rc) {
5169                                 fprintf(stderr,
5170                                         "error: bad component end '%s'\n",
5171                                         optarg);
5172                                 goto err;
5173                         }
5174                         param.fp_check_comp_end = 1;
5175                         param.fp_exclude_comp_end = !!neg_opt;
5176                         break;
5177                 case LFS_LAYOUT_FOREIGN_OPT: {
5178                         /* all types by default */
5179                         uint32_t type = LU_FOREIGN_TYPE_UNKNOWN;
5180
5181                         if (optarg) {
5182                                 /* check pure numeric */
5183                                 type = strtoul(optarg, &endptr, 0);
5184                                 if (*endptr) {
5185                                         /* check name */
5186                                         type = check_foreign_type_name(optarg);
5187                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
5188                                                 fprintf(stderr,
5189                                                         "%s %s: unknown foreign type '%s'\n",
5190                                                         progname, argv[0],
5191                                                         optarg);
5192                                                 return CMD_HELP;
5193                                         }
5194                                 } else if (type >= UINT32_MAX) {
5195                                         fprintf(stderr,
5196                                                 "%s %s: invalid foreign type '%s'\n",
5197                                                 progname, argv[0], optarg);
5198                                         return CMD_HELP;
5199                                 }
5200                         }
5201                         param.fp_foreign_type = type;
5202                         param.fp_check_foreign = 1;
5203                         param.fp_exclude_foreign = !!neg_opt;
5204                         break;
5205                 }
5206                 case LFS_NEWERXY_OPT: {
5207                         char x = 'm';
5208                         char y = 'm';
5209                         int xidx;
5210                         int negidx;
5211                         time_t *newery;
5212                         time_t ref = time(NULL);
5213
5214                         /* no need to check bad options, they won't get here */
5215                         if (strlen(long_opts[optidx].name) == 7) {
5216                                 x = long_opts[optidx].name[5];
5217                                 y = long_opts[optidx].name[6];
5218                         }
5219
5220                         if (y == 't') {
5221                                 static const char *const fmts[] = {
5222                                         "%Y-%m-%d %H:%M:%S",
5223                                         "%Y-%m-%d %H:%M",
5224                                         "%Y-%m-%d",
5225                                         "%H:%M:%S", /* sometime today */
5226                                         "%H:%M",
5227                                         "@%s",
5228                                         "%s",
5229                                         NULL };
5230                                 struct tm tm;
5231                                 bool found = false;
5232                                 int i;
5233
5234                                 for (i = 0; fmts[i] != NULL; i++) {
5235                                         char *ptr;
5236
5237                                         /* Init for times relative to today */
5238                                         if (strncmp(fmts[i], "%H", 2) == 0)
5239                                                 localtime_r(&ref, &tm);
5240                                         else
5241                                                 memset(&tm, 0, sizeof(tm));
5242                                         ptr = strptime(optarg, fmts[i], &tm);
5243                                         /* Skip spaces */
5244                                         while (ptr && isspace(*ptr))
5245                                                 ptr++;
5246                                         if (ptr == optarg + strlen(optarg)) {
5247                                                 found = true;
5248                                                 break;
5249                                         }
5250                                 }
5251
5252                                 if (!found) {
5253                                         fprintf(stderr,
5254                                                 "%s: invalid time '%s'\n",
5255                                                 progname, optarg);
5256                                         fprintf(stderr,
5257                                                 "supported formats are:\n  ");
5258                                         for (i = 0; fmts[i] != NULL; i++)
5259                                                 fprintf(stderr, "'%s', ",
5260                                                         fmts[i]);
5261                                         fprintf(stderr, "\n");
5262                                         ret = -EINVAL;
5263                                         goto err;
5264                                 }
5265
5266                                 ref = mktime(&tm);
5267                         } else if (y == 'b' || y == 'B') {
5268                                 lstatx_t stx;
5269
5270                                 rc = llapi_get_lum_file(optarg, NULL, &stx,
5271                                                         NULL, 0);
5272                                 if (rc || !(stx.stx_mask & STATX_BTIME)) {
5273                                         if (!(stx.stx_mask & STATX_BTIME))
5274                                                 ret = -EOPNOTSUPP;
5275                                         else
5276                                                 ret = -errno;
5277                                         fprintf(stderr,
5278                                                 "%s: get btime failed '%s': %s\n",
5279                                                 progname, optarg,
5280                                                 strerror(-ret));
5281                                         goto err;
5282                                 }
5283
5284                                 ref = stx.stx_btime.tv_sec;
5285                         } else {
5286                                 struct stat statbuf;
5287
5288                                 if (stat(optarg, &statbuf) < 0) {
5289                                         fprintf(stderr,
5290                                                 "%s: cannot stat file '%s': %s\n",
5291                                                 progname, optarg,
5292                                                 strerror(errno));
5293                                         ret = -errno;
5294                                         goto err;
5295                                 }
5296
5297                                 switch (y) {
5298                                 case 'a':
5299                                         ref = statbuf.st_atime;
5300                                         break;
5301                                 case 'm':
5302                                         ref = statbuf.st_mtime;
5303                                         break;
5304                                 case 'c':
5305                                         ref = statbuf.st_ctime;
5306                                         break;
5307                                 default:
5308                                         fprintf(stderr,
5309                                                 "%s: invalid Y argument: '%c'\n",
5310                                                 progname, x);
5311                                         ret = -EINVAL;
5312                                         goto err;
5313                                 }
5314                         }
5315
5316                         switch (x) {
5317                         case 'a':
5318                                 xidx = NEWERXY_ATIME;
5319                                 break;
5320                         case 'm':
5321                                 xidx = NEWERXY_MTIME;
5322                                 break;
5323                         case 'c':
5324                                 xidx = NEWERXY_CTIME;
5325                                 break;
5326                         case 'b':
5327                         case 'B':
5328                                 xidx = NEWERXY_BTIME;
5329                                 break;
5330                         default:
5331                                 fprintf(stderr,
5332                                         "%s: invalid X argument: '%c'\n",
5333                                         progname, x);
5334                                 ret = -EINVAL;
5335                                 goto err;
5336                         }
5337
5338                         negidx = !!neg_opt;
5339                         newery = &param.fp_newery[xidx][negidx];
5340
5341                         if (*newery == 0) {
5342                                 *newery = ref;
5343                         } else {
5344                                 if (negidx)
5345                                         *newery = *newery > ref ? ref : *newery;
5346                                 else
5347                                         *newery = *newery > ref ? *newery : ref;
5348                         }
5349                         param.fp_newerxy = 1;
5350                         break;
5351                 }
5352                 case 'g':
5353                 case 'G':
5354                         rc = name2gid(&param.fp_gid, optarg);
5355                         if (rc) {
5356                                 if (str2quotaid(&param.fp_gid, optarg)) {
5357                                         fprintf(stderr,
5358                                                 "Group/GID: %s cannot be found.\n",
5359                                                 optarg);
5360                                         ret = -1;
5361                                         goto err;
5362                                 }
5363                         }
5364                         param.fp_exclude_gid = !!neg_opt;
5365                         param.fp_check_gid = 1;
5366                         break;
5367                 case 'H':
5368                         rc = mdthash_input(optarg, &param.fp_hash_inflags,
5369                                            &param.fp_hash_exflags,
5370                                            &param.fp_hash_type);
5371                         if (rc) {
5372                                 ret = -1;
5373                                 goto err;
5374                         }
5375                         if (param.fp_hash_inflags || param.fp_hash_exflags)
5376                                 param.fp_check_hash_flag = 1;
5377                         param.fp_exclude_hash_type = !!neg_opt;
5378                         break;
5379                 case 'l':
5380                         param.fp_lazy = 1;
5381                         break;
5382                 case 'L':
5383                         ret = name2layout(&param.fp_layout, optarg);
5384                         if (ret)
5385                                 goto err;
5386                         param.fp_exclude_layout = !!neg_opt;
5387                         param.fp_check_layout = 1;
5388                         break;
5389                 case 'u':
5390                 case 'U':
5391                         rc = name2uid(&param.fp_uid, optarg);
5392                         if (rc) {
5393                                 if (str2quotaid(&param.fp_uid, optarg)) {
5394                                         fprintf(stderr,
5395                                                 "User/UID: %s cannot be found.\n",
5396                                                 optarg);
5397                                         ret = -1;
5398                                         goto err;
5399                                 }
5400                         }
5401                         param.fp_exclude_uid = !!neg_opt;
5402                         param.fp_check_uid = 1;
5403                         break;
5404                 case 'n':
5405                         param.fp_pattern = (char *)optarg;
5406                         param.fp_exclude_pattern = !!neg_opt;
5407                         break;
5408                 case 'N':
5409                         if (optarg[0] == '+') {
5410                                 param.fp_mirror_count_sign = -1;
5411                                 optarg++;
5412                         } else if (optarg[0] == '-') {
5413                                 param.fp_mirror_count_sign =  1;
5414                                 optarg++;
5415                         }
5416
5417                         errno = 0;
5418                         param.fp_mirror_count = strtoul(optarg, &endptr, 0);
5419                         if (errno != 0 || *endptr != '\0' ||
5420                             param.fp_mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
5421                                 fprintf(stderr,
5422                                         "error: bad mirror count '%s'\n",
5423                                         optarg);
5424                                 goto err;
5425                         }
5426                         param.fp_check_mirror_count = 1;
5427                         param.fp_exclude_mirror_count = !!neg_opt;
5428                         break;
5429                 case 'm':
5430                 case 'i':
5431                 case 'O': {
5432                         char *buf, *token, *next, *p;
5433                         int len = 1;
5434                         void *tmp;
5435
5436                         buf = strdup(optarg);
5437                         if (!buf) {
5438                                 ret = -ENOMEM;
5439                                 goto err;
5440                         }
5441
5442                         param.fp_exclude_obd = !!neg_opt;
5443
5444                         token = buf;
5445                         while (token && *token) {
5446                                 token = strchr(token, ',');
5447                                 if (token) {
5448                                         len++;
5449                                         token++;
5450                                 }
5451                         }
5452                         if (c == 'm') {
5453                                 param.fp_exclude_mdt = !!neg_opt;
5454                                 param.fp_num_alloc_mdts += len;
5455                                 tmp = realloc(param.fp_mdt_uuid,
5456                                               param.fp_num_alloc_mdts *
5457                                               sizeof(*param.fp_mdt_uuid));
5458                                 if (!tmp) {
5459                                         ret = -ENOMEM;
5460                                         goto err_free;
5461                                 }
5462
5463                                 param.fp_mdt_uuid = tmp;
5464                         } else {
5465                                 param.fp_exclude_obd = !!neg_opt;
5466                                 param.fp_num_alloc_obds += len;
5467                                 tmp = realloc(param.fp_obd_uuid,
5468                                               param.fp_num_alloc_obds *
5469                                               sizeof(*param.fp_obd_uuid));
5470                                 if (!tmp) {
5471                                         ret = -ENOMEM;
5472                                         goto err_free;
5473                                 }
5474
5475                                 param.fp_obd_uuid = tmp;
5476                         }
5477                         for (token = buf; token && *token; token = next) {
5478                                 struct obd_uuid *puuid;
5479
5480                                 if (c == 'm') {
5481                                         puuid =
5482                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
5483                                 } else {
5484                                         puuid =
5485                                         &param.fp_obd_uuid[param.fp_num_obds++];
5486                                 }
5487                                 p = strchr(token, ',');
5488                                 next = 0;
5489                                 if (p) {
5490                                         *p = 0;
5491                                         next = p+1;
5492                                 }
5493
5494                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
5495                                         ret = -E2BIG;
5496                                         goto err_free;
5497                                 }
5498
5499                                 strncpy(puuid->uuid, token,
5500                                         sizeof(puuid->uuid));
5501                         }
5502 err_free:
5503                         if (buf)
5504                                 free(buf);
5505                         break;
5506                 }
5507 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 18, 53, 0)
5508                 case 'p':
5509 #endif
5510                 case LFS_POOL_OPT:
5511                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
5512                                 fprintf(stderr,
5513                                         "Pool name %s is too long (max %d)\n",
5514                                         optarg, LOV_MAXPOOLNAME);
5515                                 ret = -1;
5516                                 goto err;
5517                         }
5518                         /*
5519                          * We do check for empty pool because empty pool
5520                          * is used to find V1 LOV attributes
5521                          */
5522                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
5523                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
5524                         param.fp_exclude_pool = !!neg_opt;
5525                         param.fp_check_pool = 1;
5526                         break;
5527 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 14, 53, 0)
5528                 case 'p': /* want this for --pool, to match getstripe/find */
5529                         fprintf(stderr,
5530                                 "warning: -p deprecated, use --print0 or -0\n");
5531 #endif
5532                 case '0':
5533                         param.fp_zero_end = 1;
5534                         break;
5535                 case 'P': /* we always print, this option is a no-op */
5536                         break;
5537                 case LFS_PROJID_OPT:
5538                         rc = name2projid(&param.fp_projid, optarg);
5539                         if (rc) {
5540                                 if (str2quotaid(&param.fp_projid, optarg)) {
5541                                         fprintf(stderr,
5542                                                 "Invalid project ID: %s\n",
5543                                                 optarg);
5544                                         ret = -1;
5545                                         goto err;
5546                                 }
5547                         }
5548                         param.fp_exclude_projid = !!neg_opt;
5549                         param.fp_check_projid = 1;
5550                         break;
5551                 case 's':
5552                         if (optarg[0] == '+') {
5553                                 param.fp_size_sign = -1;
5554                                 optarg++;
5555                         } else if (optarg[0] == '-') {
5556                                 param.fp_size_sign =  1;
5557                                 optarg++;
5558                         }
5559
5560                         ret = llapi_parse_size(optarg, &param.fp_size,
5561                                                &param.fp_size_units, 0);
5562                         if (ret) {
5563                                 fprintf(stderr, "error: bad file size '%s'\n",
5564                                         optarg);
5565                                 goto err;
5566                         }
5567                         param.fp_check_size = 1;
5568                         param.fp_exclude_size = !!neg_opt;
5569                         break;
5570                 case 'S':
5571                         if (optarg[0] == '+') {
5572                                 param.fp_stripe_size_sign = -1;
5573                                 optarg++;
5574                         } else if (optarg[0] == '-') {
5575                                 param.fp_stripe_size_sign =  1;
5576                                 optarg++;
5577                         }
5578
5579                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
5580                                                &param.fp_stripe_size_units, 0);
5581                         /* assume units of KB if too small to be valid */
5582                         if (param.fp_stripe_size < 4096)
5583                                 param.fp_stripe_size *= 1024;
5584                         if (ret) {
5585                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
5586                                         optarg);
5587                                 goto err;
5588                         }
5589                         param.fp_check_stripe_size = 1;
5590                         param.fp_exclude_stripe_size = !!neg_opt;
5591                         break;
5592                 case 't':
5593                         param.fp_exclude_type = !!neg_opt;
5594                         switch (optarg[0]) {
5595                         case 'b':
5596                                 param.fp_type = S_IFBLK;
5597                                 break;
5598                         case 'c':
5599                                 param.fp_type = S_IFCHR;
5600                                 break;
5601                         case 'd':
5602                                 param.fp_type = S_IFDIR;
5603                                 break;
5604                         case 'f':
5605                                 param.fp_type = S_IFREG;
5606                                 break;
5607                         case 'l':
5608                                 param.fp_type = S_IFLNK;
5609                                 break;
5610                         case 'p':
5611                                 param.fp_type = S_IFIFO;
5612                                 break;
5613                         case 's':
5614                                 param.fp_type = S_IFSOCK;
5615                                 break;
5616                         default:
5617                                 fprintf(stderr, "%s: bad type '%s'\n",
5618                                         progname, optarg);
5619                                 ret = CMD_HELP;
5620                                 goto err;
5621                         }
5622                         break;
5623                 case LFS_FIND_PERM:
5624                         param.fp_exclude_perm = !!neg_opt;
5625                         param.fp_perm_sign = LFS_FIND_PERM_EXACT;
5626                         if (*optarg == '/') {
5627                                 param.fp_perm_sign = LFS_FIND_PERM_ANY;
5628                                 optarg++;
5629                         } else if (*optarg == '-') {
5630                                 param.fp_perm_sign = LFS_FIND_PERM_ALL;
5631                                 optarg++;
5632                         }
5633
5634                         if (str2mode_t(optarg, &param.fp_perm)) {
5635                                 fprintf(stderr, "error: invalid mode '%s'\n",
5636                                         optarg);
5637                                 ret = -1;
5638                                 goto err;
5639                         }
5640                         break;
5641                 case 'T':
5642                         if (optarg[0] == '+') {
5643                                 param.fp_mdt_count_sign = -1;
5644                                 optarg++;
5645                         } else if (optarg[0] == '-') {
5646                                 param.fp_mdt_count_sign =  1;
5647                                 optarg++;
5648                         }
5649
5650                         errno = 0;
5651                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
5652                         if (errno != 0 || *endptr != '\0' ||
5653                             param.fp_mdt_count >= UINT32_MAX) {
5654                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
5655                                         optarg);
5656                                 ret = -1;
5657                                 goto err;
5658                         }
5659                         param.fp_check_mdt_count = 1;
5660                         param.fp_exclude_mdt_count = !!neg_opt;
5661                         break;
5662                 case 'z':
5663                         if (optarg[0] == '+') {
5664                                 param.fp_ext_size_sign = -1;
5665                                 optarg++;
5666                         } else if (optarg[0] == '-') {
5667                                 param.fp_ext_size_sign =  1;
5668                                 optarg++;
5669                         }
5670
5671                         ret = llapi_parse_size(optarg, &param.fp_ext_size,
5672                                                &param.fp_ext_size_units, 0);
5673                         if (ret) {
5674                                 fprintf(stderr, "error: bad ext-size '%s'\n",
5675                                         optarg);
5676                                 goto err;
5677                         }
5678                         param.fp_ext_size /= SEL_UNIT_SIZE;
5679                         param.fp_ext_size_units /= SEL_UNIT_SIZE;
5680                         param.fp_check_ext_size = 1;
5681                         param.fp_exclude_ext_size = !!neg_opt;
5682                         break;
5683                 default:
5684                         fprintf(stderr, "%s: unrecognized option '%s'\n",
5685                                 progname, argv[optind - 1]);
5686                 case 'h':
5687                         ret = CMD_HELP;
5688                         goto err;
5689                 }
5690         }
5691
5692         if (pathstart == -1) {
5693                 fprintf(stderr, "error: %s: no filename|pathname\n",
5694                         argv[0]);
5695                 ret = CMD_HELP;
5696                 goto err;
5697         } else if (pathend == -1) {
5698                 /* no options */
5699                 pathend = argc;
5700         }
5701
5702         do {
5703                 rc = llapi_find(argv[pathstart], &param);
5704                 if (rc && !ret) {
5705                         ret = rc;
5706                         pathbad = pathstart;
5707                 }
5708         } while (++pathstart < pathend);
5709
5710         if (ret)
5711                 fprintf(stderr, "%s: failed for '%s': %s\n",
5712                         progname, argv[pathbad], strerror(-rc));
5713
5714 err:
5715         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
5716                 free(param.fp_obd_uuid);
5717
5718         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
5719                 free(param.fp_mdt_uuid);
5720
5721         return ret;
5722 }
5723
5724 static int lfs_getstripe_internal(int argc, char **argv,
5725                                   struct find_param *param)
5726 {
5727         struct option long_opts[] = {
5728 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
5729 /* find { .val = 'b',   .name = "blocks",       .has_arg = required_argument }*/
5730 /* find { .val = 'B',   .name = "btime",        .has_arg = required_argument }*/
5731 /* find { .val = 'B',   .name = "Btime",        .has_arg = required_argument }*/
5732         { .val = LFS_COMP_COUNT_OPT,
5733                         .name = "comp-count",   .has_arg = no_argument },
5734         { .val = LFS_COMP_COUNT_OPT,
5735                 .name = "component-count",      .has_arg = no_argument },
5736         { .val = LFS_COMP_FLAGS_OPT,
5737                         .name = "comp-flags",   .has_arg = optional_argument },
5738         { .val = LFS_COMP_FLAGS_OPT,
5739                 .name = "component-flags",      .has_arg = optional_argument },
5740         { .val = LFS_COMP_START_OPT,
5741                         .name = "comp-start",   .has_arg = optional_argument },
5742         { .val = LFS_COMP_START_OPT,
5743                 .name = "component-start",      .has_arg = optional_argument },
5744         { .val = LFS_MIRROR_INDEX_OPT,
5745                 .name = "mirror-index",         .has_arg = required_argument },
5746         { .val = LFS_MIRROR_ID_OPT,
5747                 .name = "mirror-id",            .has_arg = required_argument },
5748         { .val = 'c',   .name = "stripe-count", .has_arg = no_argument },
5749         { .val = 'c',   .name = "stripe_count", .has_arg = no_argument },
5750 /* find { .val = 'C',   .name = "ctime",        .has_arg = required_argument }*/
5751         { .val = 'd',   .name = "directory",    .has_arg = no_argument },
5752         { .val = 'D',   .name = "default",      .has_arg = no_argument },
5753         { .val = 'E',   .name = "comp-end",     .has_arg = optional_argument },
5754         { .val = 'E',   .name = "component-end", .has_arg = optional_argument },
5755         { .val = 'F',   .name = "fid",          .has_arg = no_argument },
5756         { .val = 'g',   .name = "generation",   .has_arg = no_argument },
5757 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
5758         { .val = 'h',   .name = "help",         .has_arg = no_argument },
5759 /* dirstripe { .val = 'H', .name = "mdt-hash",  .has_arg = required_argument }*/
5760         { .val = 'i',   .name = "stripe-index", .has_arg = no_argument },
5761         { .val = 'i',   .name = "stripe_index", .has_arg = no_argument },
5762         { .val = 'I',   .name = "comp-id",      .has_arg = optional_argument },
5763         { .val = 'I',   .name = "component-id", .has_arg = optional_argument },
5764 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
5765         { .val = 'L',   .name = "layout",       .has_arg = no_argument },
5766         { .val = 'm',   .name = "mdt",          .has_arg = no_argument },
5767         { .val = 'm',   .name = "mdt-index",    .has_arg = no_argument },
5768         { .val = 'm',   .name = "mdt_index",    .has_arg = no_argument },
5769 /* find { .val = 'M',   .name = "mtime",        .has_arg = required_argument }*/
5770 /* find { .val = 'n',   .name = "name",         .has_arg = required_argument }*/
5771         { .val = 'N',   .name = "mirror-count", .has_arg = no_argument },
5772         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
5773         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
5774         { .val = 'p',   .name = "pool",         .has_arg = no_argument },
5775 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
5776         { .val = 'q',   .name = "quiet",        .has_arg = no_argument },
5777         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
5778         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
5779         { .val = 'S',   .name = "stripe-size",  .has_arg = no_argument },
5780         { .val = 'S',   .name = "stripe_size",  .has_arg = no_argument },
5781 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
5782 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
5783 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
5784 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
5785         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
5786 /* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/
5787         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
5788         { .val = 'z',   .name = "extension-size", .has_arg = no_argument },
5789         { .val = 'z',   .name = "ext-size",     .has_arg = no_argument },
5790         { .name = NULL } };
5791         int c, rc;
5792         int neg_opt = 0;
5793         int pathstart = -1, pathend = -1;
5794         int isoption;
5795         char *end, *tmp;
5796
5797         while ((c = getopt_long(argc, argv,
5798                         "-cdDE::FghiI::LmMNoO:pqrRsSvyz",
5799                         long_opts, NULL)) != -1) {
5800                 if (neg_opt)
5801                         --neg_opt;
5802
5803                 /* '!' is part of option */
5804                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
5805                 if (!isoption && pathend != -1) {
5806                         fprintf(stderr,
5807                                 "error: %s: filename|dirname must either precede options or follow options\n",
5808                                 argv[0]);
5809                         return CMD_HELP;
5810                 }
5811                 if (!isoption && pathstart == -1)
5812                         pathstart = optind - 1;
5813                 if (isoption && pathstart != -1 && pathend == -1)
5814                         pathend = optind - 2;
5815
5816                 switch (c) {
5817                 case 1:
5818                         /* unknown: opt is "!" */
5819                         if (strcmp(optarg, "!") == 0)
5820                                 neg_opt = 2;
5821                         break;
5822                 case 'c':
5823                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5824                                 param->fp_verbose |= VERBOSE_COUNT;
5825                                 param->fp_max_depth = 0;
5826                         }
5827                         break;
5828                 case LFS_COMP_COUNT_OPT:
5829                         param->fp_verbose |= VERBOSE_COMP_COUNT;
5830                         param->fp_max_depth = 0;
5831                         break;
5832                 case LFS_COMP_FLAGS_OPT:
5833                         if (optarg) {
5834                                 rc = comp_str2flags(optarg,
5835                                                     &param->fp_comp_flags,
5836                                                     &param->fp_comp_neg_flags);
5837                                 if (rc != 0) {
5838                                         fprintf(stderr,
5839                                                 "error: %s bad component flags '%s'.\n",
5840                                                 argv[0], optarg);
5841                                         return CMD_HELP;
5842                                 }
5843                                 param->fp_check_comp_flags = 1;
5844                         } else {
5845                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
5846                                 param->fp_max_depth = 0;
5847                         }
5848                         break;
5849                 case LFS_COMP_START_OPT:
5850                         if (optarg) {
5851                                 tmp = optarg;
5852                                 if (tmp[0] == '+') {
5853                                         param->fp_comp_start_sign = -1;
5854                                         tmp++;
5855                                 } else if (tmp[0] == '-') {
5856                                         param->fp_comp_start_sign = 1;
5857                                         tmp++;
5858                                 }
5859                                 rc = llapi_parse_size(tmp,
5860                                                 &param->fp_comp_start,
5861                                                 &param->fp_comp_start_units, 0);
5862                                 if (rc != 0) {
5863                                         fprintf(stderr,
5864                                                 "error: %s bad component start '%s'.\n",
5865                                                 argv[0], tmp);
5866                                         return CMD_HELP;
5867                                 }
5868                                 param->fp_check_comp_start = 1;
5869                         } else {
5870                                 param->fp_verbose |= VERBOSE_COMP_START;
5871                                 param->fp_max_depth = 0;
5872                         }
5873                         break;
5874                 case LFS_MIRROR_INDEX_OPT: {
5875                         unsigned long int mirror_index;
5876
5877                         if (optarg[0] == '+') {
5878                                 param->fp_mirror_index_sign = -1;
5879                                 optarg++;
5880                         } else if (optarg[0] == '-') {
5881                                 param->fp_mirror_index_sign = 1;
5882                                 optarg++;
5883                         }
5884
5885                         errno = 0;
5886                         mirror_index = strtoul(optarg, &end, 0);
5887                         if (errno != 0 || *end != '\0' ||
5888                             mirror_index > UINT16_MAX || (mirror_index == 0 &&
5889                             param->fp_mirror_index_sign == 0 && neg_opt == 0)) {
5890                                 fprintf(stderr,
5891                                         "%s %s: invalid mirror index '%s'\n",
5892                                         progname, argv[0], optarg);
5893                                 return CMD_HELP;
5894                         }
5895
5896                         param->fp_mirror_index = (__u16)mirror_index;
5897
5898                         if (param->fp_mirror_id != 0) {
5899                                 fprintf(stderr,
5900                                         "%s %s: can't specify both mirror index and mirror ID\n",
5901                                         progname, argv[0]);
5902                                 return CMD_HELP;
5903                         }
5904                         param->fp_check_mirror_index = 1;
5905                         param->fp_exclude_mirror_index = !!neg_opt;
5906                         break;
5907                 }
5908                 case LFS_MIRROR_ID_OPT: {
5909                         unsigned long int mirror_id;
5910
5911                         if (optarg[0] == '+') {
5912                                 param->fp_mirror_id_sign = -1;
5913                                 optarg++;
5914                         } else if (optarg[0] == '-') {
5915                                 param->fp_mirror_id_sign = 1;
5916                                 optarg++;
5917                         }
5918
5919                         errno = 0;
5920                         mirror_id = strtoul(optarg, &end, 0);
5921                         if (errno != 0 || *end != '\0' ||
5922                             mirror_id > UINT16_MAX || (mirror_id == 0 &&
5923                             param->fp_mirror_id_sign == 0 && neg_opt == 0)) {
5924                                 fprintf(stderr,
5925                                         "%s %s: invalid mirror ID '%s'\n",
5926                                         progname, argv[0], optarg);
5927                                 return CMD_HELP;
5928                         }
5929
5930                         param->fp_mirror_id = (__u16)mirror_id;
5931
5932                         if (param->fp_mirror_index != 0) {
5933                                 fprintf(stderr,
5934                                         "%s %s: can't specify both mirror index and mirror ID\n",
5935                                         progname, argv[0]);
5936                                 return CMD_HELP;
5937                         }
5938                         param->fp_check_mirror_id = 1;
5939                         param->fp_exclude_mirror_id = !!neg_opt;
5940                         break;
5941                 }
5942                 case 'd':
5943                         param->fp_max_depth = 0;
5944                         break;
5945                 case 'D':
5946                         param->fp_get_default_lmv = 1;
5947                         break;
5948                 case 'E':
5949                         if (optarg) {
5950                                 tmp = optarg;
5951                                 if (tmp[0] == '+') {
5952                                         param->fp_comp_end_sign = -1;
5953                                         tmp++;
5954                                 } else if (tmp[0] == '-') {
5955                                         param->fp_comp_end_sign = 1;
5956                                         tmp++;
5957                                 }
5958
5959                                 if (arg_is_eof(tmp)) {
5960                                         param->fp_comp_end = LUSTRE_EOF;
5961                                         param->fp_comp_end_units = 1;
5962                                         rc = 0;
5963                                 } else {
5964                                         rc = llapi_parse_size(tmp,
5965                                                 &param->fp_comp_end,
5966                                                 &param->fp_comp_end_units, 0);
5967                                         /* assume units of KB if too small */
5968                                         if (param->fp_comp_end < 4096)
5969                                                 param->fp_comp_end *= 1024;
5970                                 }
5971                                 if (rc != 0) {
5972                                         fprintf(stderr,
5973                                                 "error: %s bad component end '%s'.\n",
5974                                                 argv[0], tmp);
5975                                         return CMD_HELP;
5976                                 }
5977                                 param->fp_check_comp_end = 1;
5978                         } else {
5979                                 param->fp_verbose |= VERBOSE_COMP_END;
5980                                 param->fp_max_depth = 0;
5981                         }
5982                         break;
5983                 case 'F':
5984                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5985                                 param->fp_verbose |= VERBOSE_DFID;
5986                                 param->fp_max_depth = 0;
5987                         }
5988                         break;
5989                 case 'g':
5990                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5991                                 param->fp_verbose |= VERBOSE_GENERATION;
5992                                 param->fp_max_depth = 0;
5993                         }
5994                         break;
5995                 case 'i':
5996                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5997                                 param->fp_verbose |= VERBOSE_STRIPE_OFFSET;
5998                                 param->fp_max_depth = 0;
5999                         }
6000                         break;
6001                 case 'I':
6002                         if (optarg) {
6003                                 param->fp_comp_id = strtoul(optarg, &end, 0);
6004                                 if (*end != '\0' || param->fp_comp_id == 0 ||
6005                                     param->fp_comp_id > LCME_ID_MAX) {
6006                                         fprintf(stderr,
6007                                                 "error: %s bad component id '%s'\n",
6008                                                 argv[0], optarg);
6009                                         return CMD_HELP;
6010                                 }
6011                                 param->fp_check_comp_id = 1;
6012                         } else {
6013                                 param->fp_max_depth = 0;
6014                                 param->fp_verbose |= VERBOSE_COMP_ID;
6015                         }
6016                         break;
6017                 case 'L':
6018                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6019                                 param->fp_verbose |= VERBOSE_PATTERN;
6020                                 param->fp_max_depth = 0;
6021                         }
6022                         break;
6023 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6024                 case 'M':
6025                         fprintf(stderr,
6026                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
6027 #endif
6028                 case 'm':
6029                         if (!(param->fp_verbose & VERBOSE_DETAIL))
6030                                 param->fp_max_depth = 0;
6031                         param->fp_verbose |= VERBOSE_MDTINDEX;
6032                         break;
6033                 case 'N':
6034                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6035                                 param->fp_verbose |= VERBOSE_MIRROR_COUNT;
6036                                 param->fp_max_depth = 0;
6037                         }
6038                         break;
6039                 case 'O':
6040                         if (param->fp_obd_uuid) {
6041                                 fprintf(stderr,
6042                                         "error: %s: only one obduuid allowed",
6043                                         argv[0]);
6044                                 return CMD_HELP;
6045                         }
6046                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
6047                         break;
6048                 case 'p':
6049                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6050                                 param->fp_verbose |= VERBOSE_POOL;
6051                                 param->fp_max_depth = 0;
6052                         }
6053                         break;
6054                 case 'q':
6055                         param->fp_quiet++;
6056                         break;
6057                 case 'r':
6058                         param->fp_recursive = 1;
6059                         break;
6060                 case 'R':
6061                         param->fp_raw = 1;
6062                         break;
6063                 case 'S':
6064                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6065                                 param->fp_verbose |= VERBOSE_STRIPE_SIZE;
6066                                 param->fp_max_depth = 0;
6067                         }
6068                         break;
6069                 case 'v':
6070                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
6071                         break;
6072                 case 'y':
6073                         param->fp_yaml = 1;
6074                         break;
6075                 case 'z':
6076                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6077                                 param->fp_verbose |= VERBOSE_EXT_SIZE;
6078                                 param->fp_max_depth = 0;
6079                         }
6080                         break;
6081                 default:
6082                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6083                                 progname, argv[optind - 1]);
6084                 case 'h':
6085                         return CMD_HELP;
6086                 }
6087         }
6088
6089         if (pathstart == -1) {
6090                 fprintf(stderr, "error: %s: no filename|pathname\n",
6091                                 argv[0]);
6092                 return CMD_HELP;
6093         } else if (pathend == -1) {
6094                 /* no options */
6095                 pathend = argc;
6096         }
6097
6098         if (pathend > argc)
6099                 return CMD_HELP;
6100
6101         if (param->fp_recursive)
6102                 param->fp_max_depth = -1;
6103         else if (param->fp_verbose & VERBOSE_DETAIL)
6104                 param->fp_max_depth = 1;
6105
6106         if (!param->fp_verbose)
6107                 param->fp_verbose = VERBOSE_DEFAULT;
6108         if (param->fp_quiet)
6109                 param->fp_verbose = VERBOSE_OBJID;
6110
6111         do {
6112                 rc = llapi_getstripe(argv[pathstart], param);
6113         } while (++pathstart < pathend && !rc);
6114
6115         if (rc)
6116                 fprintf(stderr, "error: %s failed for %s.\n",
6117                         argv[0], argv[optind - 1]);
6118         return rc;
6119 }
6120
6121 static int lfs_tgts(int argc, char **argv)
6122 {
6123         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
6124         struct find_param param;
6125         int index = 0, rc = 0;
6126
6127         if (argc > 2)
6128                 return CMD_HELP;
6129
6130         if (argc == 2 && !realpath(argv[1], path)) {
6131                 rc = -errno;
6132                 fprintf(stderr, "error: invalid path '%s': %s\n",
6133                         argv[1], strerror(-rc));
6134                 return rc;
6135         }
6136
6137         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
6138                 /* Check if we have a mount point */
6139                 if (mntdir[0] == '\0')
6140                         continue;
6141
6142                 memset(&param, 0, sizeof(param));
6143                 if (!strcmp(argv[0], "mdts"))
6144                         param.fp_get_lmv = 1;
6145
6146                 rc = llapi_ostlist(mntdir, &param);
6147                 if (rc) {
6148                         fprintf(stderr, "error: %s: failed on %s\n",
6149                                 argv[0], mntdir);
6150                 }
6151                 if (path[0] != '\0')
6152                         break;
6153                 memset(mntdir, 0, PATH_MAX);
6154         }
6155
6156         return rc;
6157 }
6158
6159 static int lfs_getstripe(int argc, char **argv)
6160 {
6161         struct find_param param = { 0 };
6162
6163         param.fp_max_depth = 1;
6164         return lfs_getstripe_internal(argc, argv, &param);
6165 }
6166
6167 /* functions */
6168 static int lfs_getdirstripe(int argc, char **argv)
6169 {
6170         struct find_param param = { 0 };
6171         struct option long_opts[] = {
6172         { .val = 'c',   .name = "mdt-count",     .has_arg = no_argument },
6173         { .val = 'D',   .name = "default",       .has_arg = no_argument },
6174         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6175         { .val = 'H',   .name = "mdt-hash",      .has_arg = no_argument },
6176         { .val = 'i',   .name = "mdt-index",     .has_arg = no_argument },
6177         { .val = 'm',   .name = "mdt-index",     .has_arg = no_argument },
6178         { .val = 'O',   .name = "obd",           .has_arg = required_argument },
6179         { .val = 'r',   .name = "recursive",     .has_arg = no_argument },
6180         { .val = 'T',   .name = "mdt-count",     .has_arg = no_argument },
6181         { .val = 'v',   .name = "verbose",       .has_arg = no_argument },
6182         { .val = 'X',   .name = "max-inherit",   .has_arg = no_argument },
6183         { .val = 'y',   .name = "yaml",          .has_arg = no_argument },
6184         { .val = LFS_INHERIT_RR_OPT,
6185                         .name = "max-inherit-rr", .has_arg = no_argument },
6186         { .name = NULL } };
6187         int c, rc;
6188
6189         param.fp_get_lmv = 1;
6190
6191         while ((c = getopt_long(argc, argv,
6192                                 "cDhHimO:rtTvXy", long_opts, NULL)) != -1) {
6193                 switch (c) {
6194                 case 'c':
6195                 case 'T':
6196                         param.fp_verbose |= VERBOSE_COUNT;
6197                         break;
6198                 case 'D':
6199                         param.fp_get_default_lmv = 1;
6200                         break;
6201 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6202                 case 't':
6203                         fprintf(stderr,
6204                                 "warning: '-t' deprecated, use '--mdt-hash' or '-H' instead\n");
6205                         /* fallthrough */
6206 #endif
6207                 case 'H':
6208                         param.fp_verbose |= VERBOSE_HASH_TYPE;
6209                         break;
6210                 case 'i': /* fallthrough */
6211                 case 'm':
6212                         param.fp_verbose |= VERBOSE_STRIPE_OFFSET;
6213                         break;
6214                 case 'O':
6215                         if (param.fp_obd_uuid) {
6216                                 fprintf(stderr,
6217                                         "%s: only one obduuid allowed",
6218                                         progname);
6219                                 return CMD_HELP;
6220                         }
6221                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
6222                         break;
6223                 case 'r':
6224                         param.fp_recursive = 1;
6225                         break;
6226                 case 'v':
6227                         param.fp_verbose |= VERBOSE_DETAIL;
6228                         break;
6229                 case 'X':
6230                         param.fp_verbose |= VERBOSE_INHERIT;
6231                         break;
6232                 case LFS_INHERIT_RR_OPT:
6233                         param.fp_verbose |= VERBOSE_INHERIT_RR;
6234                         break;
6235                 case 'y':
6236                         param.fp_yaml = 1;
6237                         break;
6238                 default:
6239                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6240                                 progname, argv[optind - 1]);
6241                         /* fallthrough */
6242                 case 'h':
6243                         return CMD_HELP;
6244                 }
6245         }
6246
6247         if (optind >= argc)
6248                 return CMD_HELP;
6249
6250         if (param.fp_recursive)
6251                 param.fp_max_depth = -1;
6252
6253         if (!param.fp_verbose)
6254                 param.fp_verbose = VERBOSE_DEFAULT;
6255
6256         do {
6257                 rc = llapi_getstripe(argv[optind], &param);
6258         } while (++optind < argc && !rc);
6259
6260         if (rc)
6261                 fprintf(stderr, "error: %s failed for %s.\n",
6262                         argv[0], argv[optind - 1]);
6263         return rc;
6264 }
6265
6266 enum mntdf_flags {
6267         MNTDF_INODES    = 0x0001,
6268         MNTDF_COOKED    = 0x0002,
6269         MNTDF_LAZY      = 0x0004,
6270         MNTDF_VERBOSE   = 0x0008,
6271         MNTDF_SHOW      = 0x0010,
6272         MNTDF_DECIMAL   = 0x0020,
6273 };
6274
6275 #define COOK(value, base)                                       \
6276 ({                                                              \
6277         int radix = 0;                                          \
6278         while (value > base) {                                  \
6279                 value /= base;                                  \
6280                 radix++;                                        \
6281         }                                                       \
6282         radix;                                                  \
6283 })
6284 #define UUF     "%-20s"
6285 #define CSF     "%11s"
6286 #define CDF     "%11llu"
6287 #define HDF     "%8.1f%c"
6288 #define RSF     "%4s"
6289 #define RDF     "%3d%%"
6290
6291 static inline int obd_statfs_ratio(const struct obd_statfs *st, bool inodes)
6292 {
6293         double avail, used, ratio = 0;
6294
6295         if (inodes) {
6296                 avail = st->os_ffree;
6297                 used = st->os_files - st->os_ffree;
6298         } else {
6299                 avail = st->os_bavail;
6300                 used = st->os_blocks - st->os_bfree;
6301         }
6302         if (avail + used > 0)
6303                 ratio = used / (used + avail) * 100;
6304
6305         /* Round up to match df(1) usage percentage */
6306         return (ratio - (int)ratio) > 0 ? (int)(ratio + 1) : (int)ratio;
6307 }
6308
6309 /*
6310  * This is to identify various problem states for "lfs df" if .osn_err = true,
6311  * so only show flags reflecting those states by default. Informational states
6312  * are only shown with "-v" and use lower-case names to distinguish them.
6313  * UNUSED[12] were for "EROFS = 30" until 1.6 but are now available for use.
6314  */
6315 static struct obd_statfs_state_names {
6316         enum obd_statfs_state   osn_state;
6317         const char              osn_name;
6318         bool                    osn_err;
6319 } oss_names[] = {
6320         { .osn_state = OS_STATFS_DEGRADED,   .osn_name = 'D', .osn_err = true },
6321         { .osn_state = OS_STATFS_READONLY,   .osn_name = 'R', .osn_err = true },
6322         { .osn_state = OS_STATFS_NOPRECREATE,.osn_name = 'N', .osn_err = true },
6323         { .osn_state = OS_STATFS_UNUSED1,    .osn_name = '?', .osn_err = true },
6324         { .osn_state = OS_STATFS_UNUSED2,    .osn_name = '?', .osn_err = true },
6325         { .osn_state = OS_STATFS_ENOSPC,     .osn_name = 'S', .osn_err = true },
6326         { .osn_state = OS_STATFS_ENOINO,     .osn_name = 'I', .osn_err = true },
6327         { .osn_state = OS_STATFS_SUM,        .osn_name = 'a', /* aggregate */ },
6328         { .osn_state = OS_STATFS_NONROT,     .osn_name = 'f', /* flash */     },
6329 };
6330
6331 static int showdf(char *mntdir, struct obd_statfs *stat,
6332                   char *uuid, enum mntdf_flags flags,
6333                   char *type, int index, int rc)
6334 {
6335         long long avail, used, total;
6336         int ratio = 0;
6337         char *suffix = flags & MNTDF_DECIMAL ? "kMGTPEZY" : "KMGTPEZY";
6338         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
6339         char tbuf[3 * sizeof(__u64)];
6340         char ubuf[3 * sizeof(__u64)];
6341         char abuf[3 * sizeof(__u64)];
6342         char rbuf[3 * sizeof(__u64)];
6343
6344         if (!uuid || !stat)
6345                 return -EINVAL;
6346
6347         switch (rc) {
6348         case 0:
6349                 if (flags & MNTDF_INODES) {
6350                         avail = stat->os_ffree;
6351                         used = stat->os_files - stat->os_ffree;
6352                         total = stat->os_files;
6353                 } else {
6354                         int shift = flags & MNTDF_COOKED ? 0 : 10;
6355
6356                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
6357                         used  = ((stat->os_blocks - stat->os_bfree) *
6358                                  stat->os_bsize) >> shift;
6359                         total = (stat->os_blocks * stat->os_bsize) >> shift;
6360                 }
6361
6362                 ratio = obd_statfs_ratio(stat, flags & MNTDF_INODES);
6363
6364                 if (flags & MNTDF_COOKED) {
6365                         int base = flags & MNTDF_DECIMAL ? 1000 : 1024;
6366                         double cook_val;
6367                         int i;
6368
6369                         cook_val = (double)total;
6370                         i = COOK(cook_val, base);
6371                         if (i > 0)
6372                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
6373                                          suffix[i - 1]);
6374                         else
6375                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
6376
6377                         cook_val = (double)used;
6378                         i = COOK(cook_val, base);
6379                         if (i > 0)
6380                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
6381                                          suffix[i - 1]);
6382                         else
6383                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
6384
6385                         cook_val = (double)avail;
6386                         i = COOK(cook_val, base);
6387                         if (i > 0)
6388                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
6389                                          suffix[i - 1]);
6390                         else
6391                                 snprintf(abuf, sizeof(abuf), CDF, avail);
6392                 } else {
6393                         snprintf(tbuf, sizeof(tbuf), CDF, total);
6394                         snprintf(ubuf, sizeof(tbuf), CDF, used);
6395                         snprintf(abuf, sizeof(tbuf), CDF, avail);
6396                 }
6397
6398                 sprintf(rbuf, RDF, ratio);
6399                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
6400                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
6401                 if (type)
6402                         printf("[%s:%d]", type, index);
6403
6404                 if (stat->os_state) {
6405                         uint32_t i;
6406
6407                         printf(" ");
6408                         for (i = 0; i < ARRAY_SIZE(oss_names); i++) {
6409                                 if (oss_names[i].osn_state & stat->os_state &&
6410                                     (oss_names[i].osn_err ||
6411                                      flags & MNTDF_VERBOSE))
6412                                         printf("%c", oss_names[i].osn_name);
6413                         }
6414                 }
6415
6416                 printf("\n");
6417                 break;
6418         case -ENODATA:
6419                 printf(UUF": inactive device\n", uuid);
6420                 break;
6421         default:
6422                 printf(UUF": %s\n", uuid, strerror(-rc));
6423                 break;
6424         }
6425
6426         return 0;
6427 }
6428
6429 struct ll_stat_type {
6430         int   st_op;
6431         char *st_name;
6432 };
6433
6434 #define LL_STATFS_MAX   LOV_MAX_STRIPE_COUNT
6435
6436 struct ll_statfs_data {
6437         int                     sd_index;
6438         struct obd_statfs       sd_st;
6439 };
6440
6441 struct ll_statfs_buf {
6442         int                     sb_count;
6443         struct ll_statfs_data   sb_buf[LL_STATFS_MAX];
6444 };
6445
6446 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags,
6447                  int ops, struct ll_statfs_buf *lsb)
6448 {
6449         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
6450         struct obd_uuid uuid_buf;
6451         char *poolname = NULL;
6452         struct ll_stat_type types[] = {
6453                 { .st_op = LL_STATFS_LMV,       .st_name = "MDT" },
6454                 { .st_op = LL_STATFS_LOV,       .st_name = "OST" },
6455                 { .st_name = NULL } };
6456         struct ll_stat_type *tp;
6457         __u64 ost_files = 0;
6458         __u64 ost_ffree = 0;
6459         __u32 index;
6460         __u32 type;
6461         int fd;
6462         int rc = 0;
6463         int rc2;
6464
6465         if (pool) {
6466                 poolname = strchr(pool, '.');
6467                 if (poolname) {
6468                         if (strncmp(fsname, pool, strlen(fsname))) {
6469                                 fprintf(stderr, "filesystem name incorrect\n");
6470                                 return -ENODEV;
6471                         }
6472                         poolname++;
6473                 } else
6474                         poolname = pool;
6475         }
6476
6477         fd = open(mntdir, O_RDONLY);
6478         if (fd < 0) {
6479                 rc = -errno;
6480                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
6481                         strerror(errno));
6482                 return rc;
6483         }
6484
6485         if (flags & MNTDF_SHOW) {
6486                 if (flags & MNTDF_INODES)
6487                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
6488                                "UUID", "Inodes", "IUsed", "IFree",
6489                                "IUse%", "Mounted on");
6490                 else
6491                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
6492                                "UUID",
6493                                flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
6494                                "Used", "Available", "Use%", "Mounted on");
6495         }
6496
6497         for (tp = types; tp->st_name != NULL; tp++) {
6498                 bool have_ost = false;
6499
6500                 if (!(tp->st_op & ops))
6501                         continue;
6502
6503                 for (index = 0; ; index++) {
6504                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
6505                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
6506                         type = flags & MNTDF_LAZY ?
6507                                 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
6508                         rc2 = llapi_obd_fstatfs(fd, type, index,
6509                                                &stat_buf, &uuid_buf);
6510                         if (rc2 == -ENODEV)
6511                                 break;
6512                         if (rc2 == -EAGAIN)
6513                                 continue;
6514                         if (rc2 == -ENODATA) { /* Inactive device, OK. */
6515                                 if (!(flags & MNTDF_VERBOSE))
6516                                         continue;
6517                         } else if (rc2 < 0 && rc == 0) {
6518                                 rc = rc2;
6519                         }
6520
6521                         /*
6522                          * If we have OSTs then don't report MDT block counts.
6523                          * For MDT-only filesystems the expectation is that all
6524                          * layouts have a DoM component.  For filesystems with
6525                          * OSTs, files are not necessarily going to store data
6526                          * on MDTs, and MDT space is limited to a fraction of
6527                          * OST space, so don't include it in the summary.
6528                          */
6529                         if (tp->st_op == LL_STATFS_LOV && !have_ost) {
6530                                 have_ost = true;
6531                                 sum.os_blocks = 0;
6532                                 sum.os_bfree = 0;
6533                                 sum.os_bavail = 0;
6534                         }
6535
6536                         if (poolname && tp->st_op == LL_STATFS_LOV &&
6537                             llapi_search_ost(fsname, poolname,
6538                                              obd_uuid2str(&uuid_buf)) != 1)
6539                                 continue;
6540
6541                         /*
6542                          * the llapi_obd_fstatfs() call may have returned with
6543                          * an error, but if it filled in uuid_buf we will at
6544                          * lease use that to print out a message for that OBD.
6545                          * If we didn't get anything in the uuid_buf, then fill
6546                          * it in so that we can print an error message.
6547                          */
6548                         if (uuid_buf.uuid[0] == '\0')
6549                                 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
6550                                          "%s%04x", tp->st_name, index);
6551                         if (!rc && lsb) {
6552                                 lsb->sb_buf[lsb->sb_count].sd_index = index;
6553                                 lsb->sb_buf[lsb->sb_count].sd_st = stat_buf;
6554                                 lsb->sb_count++;
6555                         }
6556                         if (flags & MNTDF_SHOW)
6557                                 showdf(mntdir, &stat_buf,
6558                                        obd_uuid2str(&uuid_buf), flags,
6559                                        tp->st_name, index, rc2);
6560
6561                         if (rc2)
6562                                 continue;
6563
6564                         if (tp->st_op == LL_STATFS_LMV) {
6565                                 sum.os_ffree += stat_buf.os_ffree;
6566                                 sum.os_files += stat_buf.os_files;
6567                         } else /* if (tp->st_op == LL_STATFS_LOV) */ {
6568                                 ost_files += stat_buf.os_files;
6569                                 ost_ffree += stat_buf.os_ffree;
6570                         }
6571                         sum.os_blocks += stat_buf.os_blocks *
6572                                          stat_buf.os_bsize;
6573                         sum.os_bfree  += stat_buf.os_bfree *
6574                                          stat_buf.os_bsize;
6575                         sum.os_bavail += stat_buf.os_bavail *
6576                                          stat_buf.os_bsize;
6577                 }
6578         }
6579
6580         close(fd);
6581
6582         /*
6583          * If we have _some_ OSTs, but don't have as many free objects on the
6584          * OST as inodes on the MDTs, reduce the reported number of inodes
6585          * to compensate, so that the "inodes in use" number is correct.
6586          * This should be kept in sync with ll_statfs_internal().
6587          */
6588         if (ost_files && ost_ffree < sum.os_ffree) {
6589                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
6590                 sum.os_ffree = ost_ffree;
6591         }
6592         if (flags & MNTDF_SHOW) {
6593                 printf("\n");
6594                 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
6595                 printf("\n");
6596         }
6597
6598         return rc;
6599 }
6600
6601 enum {
6602         LAYOUT_INHERIT_UNSET    = -2,
6603 };
6604
6605 /* functions */
6606 static int lfs_setdirstripe(int argc, char **argv)
6607 {
6608         char *dname;
6609         struct lfs_setstripe_args lsa = { 0 };
6610         struct llapi_stripe_param *param = NULL;
6611         __u32 mdts[LMV_MAX_STRIPE_COUNT] = { 0 };
6612         char *end;
6613         int c;
6614         char *mode_opt = NULL;
6615         bool default_stripe = false;
6616         bool delete = false;
6617         bool foreign_mode = false;
6618         mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
6619         mode_t previous_mode = 0;
6620         char *xattr = NULL;
6621         __u32 type = LU_FOREIGN_TYPE_SYMLINK, flags = 0;
6622         int max_inherit = LAYOUT_INHERIT_UNSET;
6623         int max_inherit_rr = LAYOUT_INHERIT_UNSET;
6624         struct option long_opts[] = {
6625         { .val = 'c',   .name = "count",        .has_arg = required_argument },
6626         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
6627         { .val = 'd',   .name = "delete",       .has_arg = no_argument },
6628         { .val = 'D',   .name = "default",      .has_arg = no_argument },
6629         { .val = 'D',   .name = "default_stripe", .has_arg = no_argument },
6630         { .val = LFS_LAYOUT_FLAGS_OPT,
6631                         .name = "flags",        .has_arg = required_argument },
6632         { .val = LFS_LAYOUT_FOREIGN_OPT,
6633                         .name = "foreign",      .has_arg = optional_argument},
6634         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6635         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
6636 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 17, 53, 0)
6637         { .val = 'i',   .name = "mdt-index",    .has_arg = required_argument },
6638         { .val = 'i',   .name = "mdt",          .has_arg = required_argument },
6639 #else
6640 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
6641         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
6642         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
6643 #endif
6644 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6645         { .val = 'i',   .name = "index",        .has_arg = required_argument },
6646 #endif
6647         { .val = 'o',   .name = "mode",         .has_arg = required_argument },
6648 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6649         { .val = 't',   .name = "hash-type",    .has_arg = required_argument },
6650 #endif
6651         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
6652         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
6653         { .val = 'X',   .name = "max-inherit",  .has_arg = required_argument },
6654         { .val = LFS_INHERIT_RR_OPT,
6655                         .name = "max-inherit-rr", .has_arg = required_argument},
6656 /* setstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
6657         { .name = NULL } };
6658         int result = 0;
6659
6660         setstripe_args_init(&lsa);
6661
6662         while ((c = getopt_long(argc, argv, "c:dDi:hH:m:o:t:T:x:X:",
6663                                 long_opts, NULL)) >= 0) {
6664                 switch (c) {
6665                 case 0:
6666                         /* Long options. */
6667                         break;
6668                 case 'c':
6669                 case 'T':
6670                         errno = 0;
6671                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
6672                         if (errno != 0 || *end != '\0' ||
6673                             lsa.lsa_stripe_count < -1 ||
6674                             lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
6675                                 fprintf(stderr,
6676                                         "%s: invalid stripe count '%s'\n",
6677                                         progname, optarg);
6678                                 return CMD_HELP;
6679                         }
6680                         break;
6681                 case 'd':
6682                         delete = true;
6683                         default_stripe = true;
6684                         break;
6685                 case 'D':
6686                         default_stripe = true;
6687                         break;
6688                 case LFS_LAYOUT_FOREIGN_OPT:
6689                         if (optarg) {
6690                                 /* check pure numeric */
6691                                 type = strtoul(optarg, &end, 0);
6692                                 if (*end) {
6693                                         /* check name */
6694                                         type = check_foreign_type_name(optarg);
6695                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
6696                                                 fprintf(stderr,
6697                                                         "%s %s: unknown foreign type '%s'\n",
6698                                                         progname, argv[0],
6699                                                         optarg);
6700                                                 return CMD_HELP;
6701                                         }
6702                                 } else if (type >= UINT32_MAX) {
6703                                         fprintf(stderr,
6704                                                 "%s %s: invalid foreign type '%s'\n",
6705                                                 progname, argv[0], optarg);
6706                                         return CMD_HELP;
6707                                 }
6708                         }
6709                         foreign_mode = true;
6710                         break;
6711                 case LFS_LAYOUT_FLAGS_OPT:
6712                         errno = 0;
6713                         flags = strtoul(optarg, &end, 16);
6714                         if (errno != 0 || *end != '\0' ||
6715                             flags >= UINT32_MAX) {
6716                                 fprintf(stderr,
6717                                         "%s %s: invalid hex flags '%s'\n",
6718                                         progname, argv[0], optarg);
6719                                 return CMD_HELP;
6720                         }
6721                         if (!foreign_mode) {
6722                                 fprintf(stderr,
6723                                         "%s %s: hex flags must be specified with --foreign option\n",
6724                                         progname, argv[0]);
6725                                 return CMD_HELP;
6726                         }
6727                         break;
6728 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6729                 case 't':
6730                         fprintf(stderr,
6731                                 "warning: '--hash-type' and '-t' deprecated, use '--mdt-hash' or '-H' instead\n");
6732                         /* fallthrough */
6733 #endif
6734                 case 'H':
6735                         lsa.lsa_pattern = check_hashtype(optarg);
6736                         if (lsa.lsa_pattern == 0) {
6737                                 fprintf(stderr,
6738                                         "%s %s: bad stripe hash type '%s'\n",
6739                                         progname, argv[0], optarg);
6740                                 return CMD_HELP;
6741                         }
6742                         break;
6743                 case 'i':
6744 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 17, 53, 0)
6745                 case 'm':
6746 #endif
6747 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6748                         if (strcmp(argv[optind - 1], "--index") == 0)
6749                                 fprintf(stderr,
6750                                         "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
6751                                         progname, argv[0]);
6752 #endif
6753                         lsa.lsa_nr_tgts = parse_targets(mdts,
6754                                                 sizeof(mdts) / sizeof(__u32),
6755                                                 lsa.lsa_nr_tgts, optarg, NULL);
6756                         if (lsa.lsa_nr_tgts < 0) {
6757                                 fprintf(stderr,
6758                                         "%s %s: invalid MDT target(s) '%s'\n",
6759                                         progname, argv[0], optarg);
6760                                 return CMD_HELP;
6761                         }
6762
6763                         lsa.lsa_tgts = mdts;
6764                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
6765                                 lsa.lsa_stripe_off = mdts[0];
6766                         break;
6767 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 15, 53, 0)
6768                 case 'm':
6769                         fprintf(stderr,
6770                                 "warning: '-m' is deprecated, use '--mode' or '-o' instead\n");
6771 #endif
6772                 case 'o':
6773                         mode_opt = optarg;
6774                         break;
6775                 case 'x':
6776                         xattr = optarg;
6777                         break;
6778                 case 'X':
6779                         if (!default_stripe) {
6780                                 fprintf(stderr,
6781                                         "%s %s: '--max-inherit' must be specified with '-D'\n",
6782                                         progname, argv[0]);
6783                                 return CMD_HELP;
6784                         }
6785                         errno = 0;
6786                         max_inherit = strtol(optarg, &end, 10);
6787                         if (errno != 0 || *end != '\0' || max_inherit < -2) {
6788                                 fprintf(stderr,
6789                                         "%s %s: invalid max-inherit '%s'\n",
6790                                         progname, argv[0], optarg);
6791                                 return CMD_HELP;
6792                         }
6793                         if (max_inherit == 0) {
6794                                 max_inherit = LMV_INHERIT_NONE;
6795                         } else if (max_inherit == -1) {
6796                                 max_inherit = LMV_INHERIT_UNLIMITED;
6797                         } else if (max_inherit > LMV_INHERIT_MAX) {
6798                                 fprintf(stderr,
6799                                         "%s %s: max-inherit %d exceeds maximum %u\n",
6800                                         progname, argv[0], max_inherit,
6801                                         LMV_INHERIT_MAX);
6802                                 return CMD_HELP;
6803                         }
6804                         break;
6805                 case LFS_INHERIT_RR_OPT:
6806                         if (!default_stripe) {
6807                                 fprintf(stderr,
6808                                         "%s %s: '--max-inherit-rr' must be specified with '-D'\n",
6809                                         progname, argv[0]);
6810                                 return CMD_HELP;
6811                         }
6812                         errno = 0;
6813                         max_inherit_rr = strtol(optarg, &end, 10);
6814                         if (errno != 0 || *end != '\0' || max_inherit_rr < -2) {
6815                                 fprintf(stderr,
6816                                         "%s %s: invalid max-inherit-rr '%s'\n",
6817                                         progname, argv[0], optarg);
6818                                 return CMD_HELP;
6819                         }
6820                         if (max_inherit_rr == 0) {
6821                                 max_inherit_rr = LMV_INHERIT_RR_NONE;
6822                         } else if (max_inherit_rr == -1) {
6823                                 max_inherit_rr = LMV_INHERIT_RR_UNLIMITED;
6824                         } else if (max_inherit_rr > LMV_INHERIT_RR_MAX) {
6825                                 fprintf(stderr,
6826                                         "%s %s: max-inherit-rr %d exceeds maximum %u\n",
6827                                         progname, argv[0], max_inherit_rr,
6828                                         LMV_INHERIT_RR_MAX);
6829                                 return CMD_HELP;
6830                         }
6831                         break;
6832                 default:
6833                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6834                                 progname, argv[optind - 1]);
6835                         /* fallthrough */
6836                 case 'h':
6837                         return CMD_HELP;
6838                 }
6839         }
6840
6841         if (optind == argc) {
6842                 fprintf(stderr, "%s %s: DIR must be specified\n",
6843                         progname, argv[0]);
6844                 return CMD_HELP;
6845         }
6846
6847         if (xattr && !foreign_mode) {
6848                 /*
6849                  * only print a warning as this is armless and will be
6850                  * ignored
6851                  */
6852                 fprintf(stderr,
6853                         "%s %s: xattr has been specified for non-foreign layout\n",
6854                         progname, argv[0]);
6855         } else if (foreign_mode && !xattr) {
6856                 fprintf(stderr,
6857                         "%s %s: xattr must be provided in foreign mode\n",
6858                         progname, argv[0]);
6859                 return CMD_HELP;
6860         }
6861
6862         if (foreign_mode && (delete || default_stripe || lsa.lsa_nr_tgts ||
6863             lsa.lsa_tgts || setstripe_args_specified(&lsa))) {
6864                 fprintf(stderr,
6865                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
6866                         progname, argv[0]);
6867                 return CMD_HELP;
6868         }
6869
6870         if (!delete && lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT &&
6871             lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT && !foreign_mode) {
6872                 /* if no parameters set, create directory on least-used MDTs */
6873                 lsa.lsa_stripe_off = LMV_OFFSET_DEFAULT;
6874                 lsa.lsa_stripe_count = 1;
6875         }
6876
6877         if (delete &&
6878             (lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
6879              lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)) {
6880                 fprintf(stderr,
6881                         "%s %s: cannot specify -d with -c or -i options\n",
6882                         progname, argv[0]);
6883                 return CMD_HELP;
6884         }
6885
6886         if (mode_opt) {
6887                 mode = strtoul(mode_opt, &end, 8);
6888                 if (*end != '\0') {
6889                         fprintf(stderr,
6890                                 "%s %s: bad MODE '%s'\n",
6891                                 progname, argv[0], mode_opt);
6892                         return CMD_HELP;
6893                 }
6894                 previous_mode = umask(0);
6895         }
6896
6897         if (max_inherit_rr != LAYOUT_INHERIT_UNSET &&
6898             lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT &&
6899             lsa.lsa_stripe_off != LMV_OFFSET_DEFAULT) {
6900                 fprintf(stderr,
6901                         "%s %s: max-inherit-rr needs mdt-index=-1, not %lld\n",
6902                         progname, argv[0], lsa.lsa_stripe_off);
6903                 return CMD_HELP;
6904         }
6905
6906         /* foreign LMV/dir case */
6907         if (foreign_mode) {
6908                 if (argc > optind + 1) {
6909                         fprintf(stderr,
6910                                 "%s %s: cannot specify multiple foreign dirs\n",
6911                                 progname, argv[0]);
6912                         return CMD_HELP;
6913                 }
6914
6915                 dname = argv[optind];
6916                 result = llapi_dir_create_foreign(dname, mode, type, flags,
6917                                                   xattr);
6918                 if (result != 0)
6919                         fprintf(stderr,
6920                                 "%s mkdir: can't create foreign dir '%s': %s\n",
6921                                 progname, dname, strerror(-result));
6922                 return result;
6923         }
6924
6925         /*
6926          * initialize stripe parameters, in case param is converted to specific,
6927          * i.e, 'lfs mkdir -i -1 -c N', always allocate space for lsp_tgts.
6928          */
6929         param = calloc(1, offsetof(typeof(*param),
6930                        lsp_tgts[lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ?
6931                                 lsa.lsa_stripe_count : lsa.lsa_nr_tgts]));
6932         if (!param) {
6933                 fprintf(stderr,
6934                         "%s %s: cannot allocate memory for parameters: %s\n",
6935                         progname, argv[0], strerror(ENOMEM));
6936                 return CMD_HELP;
6937         }
6938
6939         /* if "lfs setdirstripe -D -i -1" is used, assume 1-stripe directory */
6940         if (default_stripe && lsa.lsa_stripe_off == LMV_OFFSET_DEFAULT &&
6941             (lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT ||
6942              lsa.lsa_stripe_count == 0))
6943                 lsa.lsa_stripe_count = 1;
6944         if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
6945                 param->lsp_stripe_count = lsa.lsa_stripe_count;
6946         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
6947                 param->lsp_stripe_offset = LMV_OFFSET_DEFAULT;
6948         else
6949                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
6950         if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
6951                 param->lsp_stripe_pattern = lsa.lsa_pattern;
6952         else
6953                 param->lsp_stripe_pattern = LMV_HASH_TYPE_UNKNOWN;
6954         param->lsp_pool = lsa.lsa_pool_name;
6955         param->lsp_is_specific = false;
6956         if (default_stripe) {
6957                 if (max_inherit == LAYOUT_INHERIT_UNSET)
6958                         max_inherit = LMV_INHERIT_DEFAULT;
6959                 if (max_inherit_rr == LAYOUT_INHERIT_UNSET)
6960                         max_inherit_rr = LMV_INHERIT_RR_DEFAULT;
6961                 param->lsp_max_inherit = max_inherit;
6962                 param->lsp_max_inherit_rr = max_inherit_rr;
6963         }
6964         if (strcmp(argv[0], "mkdir") == 0)
6965                 param->lsp_is_create = true;
6966         if (lsa.lsa_nr_tgts > 1) {
6967                 if (lsa.lsa_stripe_count > 0 &&
6968                     lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
6969                     lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
6970                         fprintf(stderr,
6971                                 "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
6972                                 argv[0], lsa.lsa_stripe_count,
6973                                 lsa.lsa_nr_tgts);
6974                         free(param);
6975                         return CMD_HELP;
6976                 }
6977
6978                 param->lsp_is_specific = true;
6979                 param->lsp_stripe_count = lsa.lsa_nr_tgts;
6980                 memcpy(param->lsp_tgts, mdts, sizeof(*mdts) * lsa.lsa_nr_tgts);
6981         }
6982
6983         dname = argv[optind];
6984         do {
6985                 if (default_stripe) {
6986                         result = llapi_dir_set_default_lmv(dname, param);
6987                         if (result)
6988                                 fprintf(stderr,
6989                                         "%s setdirstripe: cannot set default stripe on dir '%s': %s\n",
6990                                         progname, dname, strerror(-result));
6991                         continue;
6992                 }
6993
6994                 result = llapi_dir_create(dname, mode, param);
6995                 if (result)
6996                         fprintf(stderr,
6997                                 "%s setdirstripe: cannot create dir '%s': %s\n",
6998                                 progname, dname, strerror(-result));
6999         } while (!result && (dname = argv[++optind]));
7000
7001         if (mode_opt)
7002                 umask(previous_mode);
7003
7004         free(param);
7005         return result;
7006 }
7007
7008 /* functions */
7009 static int lfs_rmentry(int argc, char **argv)
7010 {
7011         char *dname;
7012         int   index;
7013         int   result = 0;
7014
7015         if (argc <= 1) {
7016                 fprintf(stderr, "error: %s: missing dirname\n",
7017                         argv[0]);
7018                 return CMD_HELP;
7019         }
7020
7021         index = 1;
7022         dname = argv[index];
7023         while (dname) {
7024                 result = llapi_direntry_remove(dname);
7025                 if (result) {
7026                         fprintf(stderr,
7027                                 "error: %s: remove dir entry '%s' failed\n",
7028                                 argv[0], dname);
7029                         break;
7030                 }
7031                 dname = argv[++index];
7032         }
7033         return result;
7034 }
7035
7036 static int lfs_unlink_foreign(int argc, char **argv)
7037 {
7038         char *name;
7039         int   index;
7040         int   result = 0;
7041
7042         if (argc <= 1) {
7043                 fprintf(stderr, "error: %s: missing pathname\n",
7044                         argv[0]);
7045                 return CMD_HELP;
7046         }
7047
7048         index = 1;
7049         name = argv[index];
7050         while (name != NULL) {
7051                 result = llapi_unlink_foreign(name);
7052                 if (result) {
7053                         fprintf(stderr,
7054                                 "error: %s: unlink foreign entry '%s' failed\n",
7055                                 argv[0], name);
7056                         break;
7057                 }
7058                 name = argv[++index];
7059         }
7060         return result;
7061 }
7062
7063 static int lfs_mv(int argc, char **argv)
7064 {
7065         struct lmv_user_md lmu = { LMV_USER_MAGIC };
7066         struct find_param param = {
7067                 .fp_max_depth = -1,
7068                 .fp_mdt_index = -1,
7069         };
7070         char *end;
7071         int c;
7072         int rc = 0;
7073         struct option long_opts[] = {
7074         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
7075         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
7076         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7077         { .name = NULL } };
7078
7079         while ((c = getopt_long(argc, argv, "m:M:v", long_opts, NULL)) != -1) {
7080                 switch (c) {
7081 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7082                 case 'M':
7083                         fprintf(stderr,
7084                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
7085 #endif
7086                 case 'm':
7087                         errno = 0;
7088                         lmu.lum_stripe_offset = strtoul(optarg, &end, 0);
7089                         if (errno != 0 || *end != '\0' ||
7090                             lmu.lum_stripe_offset >= UINT32_MAX) {
7091                                 fprintf(stderr, "%s mv: bad MDT index '%s'\n",
7092                                         progname, optarg);
7093                                 return CMD_HELP;
7094                         }
7095                         break;
7096                 case 'v':
7097                         param.fp_verbose = VERBOSE_DETAIL;
7098                         break;
7099                 default:
7100                         fprintf(stderr, "%s mv: unrecognized option '%s'\n",
7101                                 progname, argv[optind - 1]);
7102                         return CMD_HELP;
7103                 }
7104         }
7105
7106         if (lmu.lum_stripe_offset == LMV_OFFSET_DEFAULT) {
7107                 fprintf(stderr, "%s mv: MDT index must be specified\n",
7108                         progname);
7109                 return CMD_HELP;
7110         }
7111
7112         if (optind >= argc) {
7113                 fprintf(stderr, "%s mv: DIR must be specified\n", progname);
7114                 return CMD_HELP;
7115         }
7116
7117         lmu.lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
7118
7119         /* initialize migrate mdt parameters */
7120         param.fp_lmv_md = &lmu;
7121         param.fp_migrate = 1;
7122         rc = llapi_migrate_mdt(argv[optind], &param);
7123         if (rc != 0)
7124                 fprintf(stderr, "%s mv: cannot migrate '%s' to MDT%04x: %s\n",
7125                         progname, argv[optind], lmu.lum_stripe_offset,
7126                         strerror(-rc));
7127         return rc;
7128 }
7129
7130 static int lfs_osts(int argc, char **argv)
7131 {
7132         return lfs_tgts(argc, argv);
7133 }
7134
7135 static int lfs_mdts(int argc, char **argv)
7136 {
7137         return lfs_tgts(argc, argv);
7138 }
7139
7140 static int lfs_df(int argc, char **argv)
7141 {
7142         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
7143         enum mntdf_flags flags = MNTDF_SHOW;
7144         int ops = LL_STATFS_LMV | LL_STATFS_LOV;
7145         int c, rc = 0, rc1 = 0, index = 0, arg_idx = 0;
7146         char fsname[PATH_MAX] = "", *pool_name = NULL;
7147         struct option long_opts[] = {
7148         { .val = 'h',   .name = "human-readable", .has_arg = no_argument },
7149         { .val = 'H',   .name = "si",           .has_arg = no_argument },
7150         { .val = 'i',   .name = "inodes",       .has_arg = no_argument },
7151         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
7152         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
7153         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7154         { .name = NULL} };
7155
7156         while ((c = getopt_long(argc, argv, "hHilp:v", long_opts, NULL)) != -1) {
7157                 switch (c) {
7158                 case 'h':
7159                         flags = (flags & ~MNTDF_DECIMAL) | MNTDF_COOKED;
7160                         break;
7161                 case 'H':
7162                         flags |= MNTDF_COOKED | MNTDF_DECIMAL;
7163                         break;
7164                 case 'i':
7165                         flags |= MNTDF_INODES;
7166                         break;
7167                 case 'l':
7168                         flags |= MNTDF_LAZY;
7169                         break;
7170                 case 'p':
7171                         pool_name = optarg;
7172                         break;
7173                 case 'v':
7174                         flags |= MNTDF_VERBOSE;
7175                         break;
7176                 default:
7177                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7178                                 progname, argv[optind - 1]);
7179                         return CMD_HELP;
7180                 }
7181         }
7182
7183         /* Handle case where path is not specified */
7184         if (optind == argc) {
7185                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7186                         /* Check if we have a mount point */
7187                         if (mntdir[0] == '\0')
7188                                 continue;
7189
7190                         rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
7191                         if (rc || path[0] != '\0')
7192                                 break;
7193
7194                         fsname[0] = '\0'; /* avoid matching in next loop */
7195                         mntdir[0] = '\0'; /* avoid matching in next loop */
7196                         path[0] = '\0'; /* clean for next loop */
7197                 }
7198                 return rc;
7199         }
7200
7201         /* Loop through all the remaining arguments. These are Lustre FS
7202          * paths.
7203          */
7204         for (arg_idx = optind; arg_idx <= argc - 1; arg_idx++) {
7205                 bool valid = false;
7206
7207                 fsname[0] = '\0'; /* start clean */
7208                 mntdir[0] = '\0'; /* start clean */
7209                 path[0] = '\0';   /* start clean */
7210
7211                 /* path does not exists at all */
7212                 if (!realpath(argv[arg_idx], path)) {
7213                         rc = -errno;
7214                         fprintf(stderr, "error: invalid path '%s': %s\n",
7215                                 argv[arg_idx], strerror(-rc));
7216                         /* save first seen error */
7217                         if (!rc1)
7218                                 rc1 = rc;
7219
7220                         continue;
7221                 }
7222
7223                 /* path exists but may not be a Lustre filesystem */
7224                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7225                         /* Check if we have a mount point */
7226                         if (mntdir[0] == '\0')
7227                                 continue;
7228
7229                         rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
7230                         if (rc || path[0] != '\0') {
7231                                 valid = true;
7232
7233                                 /* save first seen error */
7234                                 if (!rc1)
7235                                         rc1 = rc;
7236                                 break;
7237                         }
7238                 }
7239
7240                 if (!valid) {
7241                         llapi_printf(LLAPI_MSG_ERROR,
7242                                      "%s:%s Not a Lustre filesystem\n",
7243                                      argv[0], argv[arg_idx]);
7244                         /* save first seen error */
7245                         if (!rc1)
7246                                 rc1 = -EOPNOTSUPP;
7247                 }
7248         }
7249
7250         return rc1;
7251 }
7252
7253 static int print_instance(const char *mntdir, char *buf, size_t buflen,
7254                           bool opt_instance, bool opt_fsname, bool opt_mntdir)
7255 {
7256         int rc = 0;
7257
7258         if (opt_fsname == opt_instance) { /* both true or both false */
7259                 rc = llapi_getname(mntdir, buf, buflen);
7260         } else if (opt_fsname) {
7261                 /*
7262                  * llapi_search_mounts() fills @buf with fsname, but that is not
7263                  * called if explicit paths are specified on the command-line
7264                  */
7265                 if (buf[0] == '\0')
7266                         rc = llapi_get_fsname(mntdir, buf, buflen);
7267         } else /* if (opt_instance) */ {
7268                 rc = llapi_get_instance(mntdir, buf, buflen);
7269         }
7270
7271         if (rc < 0) {
7272                 fprintf(stderr, "cannot get instance for '%s': %s\n",
7273                         mntdir, strerror(-rc));
7274                 return rc;
7275         }
7276
7277         if (opt_mntdir)
7278                 printf("%s %s\n", buf, mntdir);
7279         else
7280                 printf("%s\n", buf);
7281
7282         return 0;
7283 }
7284
7285 static int lfs_getname(int argc, char **argv)
7286 {
7287         struct option long_opts[] = {
7288         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7289         { .val = 'i',   .name = "instance",     .has_arg = no_argument },
7290         { .val = 'n',   .name = "fsname",       .has_arg = no_argument },
7291         { .name = NULL} };
7292         bool opt_instance = false, opt_fsname = false;
7293         char fsname[PATH_MAX] = "";
7294         int rc = 0, rc2, c;
7295
7296         while ((c = getopt_long(argc, argv, "hin", long_opts, NULL)) != -1) {
7297                 switch (c) {
7298                 case 'i':
7299                         opt_instance = true;
7300                         break;
7301                 case 'n':
7302                         opt_fsname = true;
7303                         break;
7304                 default:
7305                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7306                                 progname, argv[optind - 1]);
7307                         /* fallthrough */
7308                 case 'h':
7309                         return CMD_HELP;
7310                 }
7311         }
7312
7313         if (optind == argc) { /* no paths specified, get all paths. */
7314                 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "";
7315                 int index = 0;
7316
7317                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7318                         rc2 = print_instance(mntdir, fsname, sizeof(fsname),
7319                                              opt_instance, opt_fsname, true);
7320                         if (!rc)
7321                                 rc = rc2;
7322                         path[0] = fsname[0] = mntdir[0] = '\0';
7323                 }
7324         } else { /* paths specified, only attempt to search these. */
7325                 bool opt_mntdir;
7326
7327                 /* if only one path is given, print only requested info */
7328                 opt_mntdir = argc - optind > 1 || (opt_instance == opt_fsname);
7329
7330                 for (; optind < argc; optind++) {
7331                         rc2 = print_instance(argv[optind], fsname,
7332                                              sizeof(fsname), opt_instance,
7333                                              opt_fsname, opt_mntdir);
7334                         if (!rc)
7335                                 rc = rc2;
7336                         fsname[0] = '\0';
7337                 }
7338         }
7339
7340         return rc;
7341 }
7342
7343 static int lfs_check(int argc, char **argv)
7344 {
7345         char mntdir[PATH_MAX] = {'\0'};
7346         int num_types = 1;
7347         char *obd_types[3];
7348         char obd_type1[4];
7349         char obd_type2[4];
7350         char obd_type3[4];
7351         int rc;
7352
7353         if (argc != 2) {
7354                 fprintf(stderr, "%s check: server type must be specified\n",
7355                         progname);
7356                 return CMD_HELP;
7357         }
7358
7359         obd_types[0] = obd_type1;
7360         obd_types[1] = obd_type2;
7361         obd_types[2] = obd_type3;
7362
7363         if (strcmp(argv[1], "osts") == 0) {
7364                 strcpy(obd_types[0], "osc");
7365         } else if (strcmp(argv[1], "mdts") == 0 ||
7366                    strcmp(argv[1], "mds") == 0) {
7367                 strcpy(obd_types[0], "mdc");
7368         } else if (strcmp(argv[1], "mgts") == 0) {
7369                 strcpy(obd_types[0], "mgc");
7370         } else if (strcmp(argv[1], "all") == 0 ||
7371                    strcmp(argv[1], "servers") == 0) {
7372                 num_types = 3;
7373                 strcpy(obd_types[0], "osc");
7374                 strcpy(obd_types[1], "mdc");
7375                 strcpy(obd_types[2], "mgc");
7376         } else {
7377                 fprintf(stderr, "%s check: unrecognized option '%s'\n",
7378                         progname, argv[1]);
7379                 return CMD_HELP;
7380         }
7381
7382         rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
7383         if (rc < 0 || mntdir[0] == '\0') {
7384                 fprintf(stderr,
7385                         "%s check: cannot find mounted Lustre filesystem: %s\n",
7386                         progname, (rc < 0) ? strerror(-rc) : strerror(ENODEV));
7387                 return rc;
7388         }
7389
7390         rc = llapi_target_check(num_types, obd_types, mntdir);
7391         if (rc)
7392                 fprintf(stderr, "%s check: cannot check target '%s': %s\n",
7393                         progname, argv[1], strerror(-rc));
7394
7395         return rc;
7396 }
7397
7398 #ifdef HAVE_SYS_QUOTA_H
7399 #define ADD_OVERFLOW(a, b) \
7400                      ((((a) + (b)) < (a)) ? \
7401                       ((a) = ULONG_MAX) : ((a) = (a) + (b)))
7402
7403 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
7404  * returns the value or ULONG_MAX on integer overflow or incorrect format
7405  * Notes:
7406  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
7407  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
7408  *        3. empty integer value is interpreted as 0
7409  */
7410 static unsigned long str2sec(const char *timestr)
7411 {
7412         const char spec[] = "smhdw";
7413         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
7414         unsigned long val = 0;
7415         char *tail;
7416
7417         if (strpbrk(timestr, spec) == NULL) {
7418                 /*
7419                  * no specifiers inside the time string,
7420                  * should treat it as an integer value
7421                  */
7422                 val = strtoul(timestr, &tail, 10);
7423                 return *tail ? ULONG_MAX : val;
7424         }
7425
7426         /* format string is XXwXXdXXhXXmXXs */
7427         while (*timestr) {
7428                 unsigned long v;
7429                 int ind;
7430                 char *ptr;
7431
7432                 v = strtoul(timestr, &tail, 10);
7433                 if (v == ULONG_MAX || *tail == '\0')
7434                         /*
7435                          * value too large (ULONG_MAX or more)
7436                          * or missing specifier
7437                          */
7438                         goto error;
7439
7440                 ptr = strchr(spec, *tail);
7441                 if (!ptr)
7442                         /* unknown specifier */
7443                         goto error;
7444
7445                 ind = ptr - spec;
7446
7447                 /* check if product will overflow the type */
7448                 if (!(v < ULONG_MAX / mult[ind]))
7449                         goto error;
7450
7451                 ADD_OVERFLOW(val, mult[ind] * v);
7452                 if (val == ULONG_MAX)
7453                         goto error;
7454
7455                 timestr = tail + 1;
7456         }
7457
7458         return val;
7459
7460 error:
7461         return ULONG_MAX;
7462 }
7463
7464 #define ARG2ULL(nr, str, def_units)                                     \
7465 do {                                                                    \
7466         unsigned long long limit, units = def_units;                    \
7467         int rc;                                                         \
7468                                                                         \
7469         rc = llapi_parse_size(str, &limit, &units, 1);                  \
7470         if (rc < 0) {                                                   \
7471                 fprintf(stderr, "%s: invalid limit '%s'\n",             \
7472                         progname, str);                                 \
7473                 return CMD_HELP;                                        \
7474         }                                                               \
7475         nr = limit;                                                     \
7476 } while (0)
7477
7478 static inline int has_times_option(int argc, char **argv)
7479 {
7480         int i;
7481
7482         for (i = 1; i < argc; i++)
7483                 if (!strcmp(argv[i], "-t"))
7484                         return 1;
7485
7486         return 0;
7487 }
7488
7489 static inline int lfs_verify_poolarg(char *pool)
7490 {
7491         if (strnlen(optarg, LOV_MAXPOOLNAME + 1) > LOV_MAXPOOLNAME) {
7492                 fprintf(stderr,
7493                         "Pool name '%.*s' is longer than %d\n",
7494                         LOV_MAXPOOLNAME, pool, LOV_MAXPOOLNAME);
7495                 return 1;
7496         }
7497         return 0;
7498 }
7499
7500 /* special grace time, only notify the user when its quota is over soft limit
7501  * but doesn't block new writes until the hard limit is reached.
7502  */
7503 #define NOTIFY_GRACE            "notify"
7504 #define NOTIFY_GRACE_TIME       LQUOTA_GRACE_MASK
7505
7506 #ifndef toqb
7507 static inline __u64 lustre_stoqb(size_t space)
7508 {
7509         return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
7510 }
7511 #else
7512 #define lustre_stoqb   toqb
7513 #endif
7514
7515 int lfs_setquota_times(int argc, char **argv, struct if_quotactl *qctl)
7516 {
7517         int c, rc;
7518         char *mnt, *obd_type = (char *)qctl->obd_type;
7519         struct obd_dqblk *dqb = &qctl->qc_dqblk;
7520         struct obd_dqinfo *dqi = &qctl->qc_dqinfo;
7521         struct option long_opts[] = {
7522         { .val = 'b',   .name = "block-grace",  .has_arg = required_argument },
7523         { .val = 'g',   .name = "group",        .has_arg = no_argument },
7524         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7525         { .val = 'i',   .name = "inode-grace",  .has_arg = required_argument },
7526         { .val = 'p',   .name = "projid",       .has_arg = no_argument },
7527         { .val = 't',   .name = "times",        .has_arg = no_argument },
7528         { .val = 'u',   .name = "user",         .has_arg = no_argument },
7529         { .val = LFS_POOL_OPT,
7530                         .name = "pool",         .has_arg = required_argument },
7531         { .name = NULL } };
7532         int qtype;
7533
7534         qctl->qc_cmd  = LUSTRE_Q_SETINFO;
7535         qctl->qc_type = ALLQUOTA;
7536
7537         while ((c = getopt_long(argc, argv, "b:ghi:ptu",
7538                                 long_opts, NULL)) != -1) {
7539                 switch (c) {
7540                 case 'u':
7541                         qtype = USRQUOTA;
7542                         goto quota_type;
7543                 case 'g':
7544                         qtype = GRPQUOTA;
7545                         goto quota_type;
7546                 case 'p':
7547                         qtype = PRJQUOTA;
7548 quota_type:
7549                         if (qctl->qc_type != ALLQUOTA) {
7550                                 fprintf(stderr,
7551                                         "%s: -u/g/p cannot be used more than once\n",
7552                                         progname);
7553                                 return CMD_HELP;
7554                         }
7555                         qctl->qc_type = qtype;
7556                         break;
7557                 case 'b':
7558                         if (strncmp(optarg, NOTIFY_GRACE,
7559                                     strlen(NOTIFY_GRACE)) == 0) {
7560                                 dqi->dqi_bgrace = NOTIFY_GRACE_TIME;
7561                         } else {
7562                                 dqi->dqi_bgrace = str2sec(optarg);
7563                                 if (dqi->dqi_bgrace >= NOTIFY_GRACE_TIME) {
7564                                         fprintf(stderr,
7565                                                 "%s: bad block-grace: %s\n",
7566                                                 progname, optarg);
7567                                         return CMD_HELP;
7568                                 }
7569                         }
7570                         dqb->dqb_valid |= QIF_BTIME;
7571                         break;
7572                 case 'i':
7573                         if (strncmp(optarg, NOTIFY_GRACE,
7574                                     strlen(NOTIFY_GRACE)) == 0) {
7575                                 dqi->dqi_igrace = NOTIFY_GRACE_TIME;
7576                         } else {
7577                                 dqi->dqi_igrace = str2sec(optarg);
7578                                 if (dqi->dqi_igrace >= NOTIFY_GRACE_TIME) {
7579                                         fprintf(stderr,
7580                                                 "%s: bad inode-grace: %s\n",
7581                                                 progname, optarg);
7582                                         return CMD_HELP;
7583                                 }
7584                         }
7585                         dqb->dqb_valid |= QIF_ITIME;
7586                         break;
7587                 case 't': /* Yes, of course! */
7588                         break;
7589                 case LFS_POOL_OPT:
7590                         if (lfs_verify_poolarg(optarg))
7591                                 return -1;
7592                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
7593                         qctl->qc_cmd  = LUSTRE_Q_SETINFOPOOL;
7594                         break;
7595                 /* getopt prints error message for us when opterr != 0 */
7596                 default:
7597                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7598                                 progname, argv[optind - 1]);
7599                         /* fallthrough */
7600                 case 'h':
7601                         return CMD_HELP;
7602                 }
7603         }
7604
7605         if (qctl->qc_type == ALLQUOTA) {
7606                 fprintf(stderr, "%s: neither -u, -g nor -p specified\n",
7607                         progname);
7608                 return CMD_HELP;
7609         }
7610
7611         if (optind != argc - 1) {
7612                 fprintf(stderr, "%s: unexpected parameter '%s'\n",
7613                         progname, argv[optind + 1]);
7614                 return CMD_HELP;
7615         }
7616
7617         mnt = argv[optind];
7618         rc = llapi_quotactl(mnt, qctl);
7619         if (rc) {
7620                 if (*obd_type)
7621                         fprintf(stderr, "%s %s ", obd_type,
7622                                 obd_uuid2str(&qctl->obd_uuid));
7623                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
7624                 return rc;
7625         }
7626
7627         return 0;
7628 }
7629
7630 #define BSLIMIT (1 << 0)
7631 #define BHLIMIT (1 << 1)
7632 #define ISLIMIT (1 << 2)
7633 #define IHLIMIT (1 << 3)
7634
7635 int lfs_setquota(int argc, char **argv)
7636 {
7637         int c, rc = 0;
7638         struct if_quotactl *qctl;
7639         char *mnt, *obd_type;
7640         struct obd_dqblk *dqb;
7641         struct option long_opts[] = {
7642         { .val = 'b',   .name = "block-softlimit",
7643                                                 .has_arg = required_argument },
7644         { .val = 'B',   .name = "block-hardlimit",
7645                                                 .has_arg = required_argument },
7646         { .val = 'd',   .name = "default",      .has_arg = no_argument },
7647         { .val = 'g',   .name = "group",        .has_arg = required_argument },
7648         { .val = 'G',   .name = "default-grp",  .has_arg = no_argument },
7649         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7650         { .val = 'i',   .name = "inode-softlimit",
7651                                                 .has_arg = required_argument },
7652         { .val = 'I',   .name = "inode-hardlimit",
7653                                                 .has_arg = required_argument },
7654         { .val = 'p',   .name = "projid",       .has_arg = required_argument },
7655         { .val = 'P',   .name = "default-prj",  .has_arg = no_argument },
7656         { .val = 'u',   .name = "user",         .has_arg = required_argument },
7657         { .val = 'U',   .name = "default-usr",  .has_arg = no_argument },
7658         { .val = LFS_POOL_OPT,
7659                         .name = "pool",         .has_arg = required_argument },
7660         { .name = NULL } };
7661         unsigned int limit_mask = 0;
7662         bool use_default = false;
7663         int qtype, qctl_len;
7664
7665         qctl_len = sizeof(*qctl) + LOV_MAXPOOLNAME + 1;
7666         qctl = malloc(qctl_len);
7667         if (!qctl)
7668                 return -ENOMEM;
7669
7670         memset(qctl, 0, qctl_len);
7671         obd_type = (char *)qctl->obd_type;
7672         dqb = &qctl->qc_dqblk;
7673
7674         if (has_times_option(argc, argv)) {
7675                 rc = lfs_setquota_times(argc, argv, qctl);
7676                 goto out;
7677         }
7678
7679         qctl->qc_cmd  = LUSTRE_Q_SETQUOTA;
7680         qctl->qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
7681                                    * so it can be used as a marker that qc_type
7682                                    * isn't reinitialized from command line
7683                                    */
7684
7685         while ((c = getopt_long(argc, argv, "b:B:dg:Ghi:I:p:Pu:U",
7686                 long_opts, NULL)) != -1) {
7687                 switch (c) {
7688                 case 'U':
7689                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
7690                         qtype = USRQUOTA;
7691                         qctl->qc_id = 0;
7692                         goto quota_type_def;
7693                 case 'u':
7694                         qtype = USRQUOTA;
7695                         rc = name2uid(&qctl->qc_id, optarg);
7696                         goto quota_type;
7697                 case 'G':
7698                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
7699                         qtype = GRPQUOTA;
7700                         qctl->qc_id = 0;
7701                         goto quota_type_def;
7702                 case 'g':
7703                         qtype = GRPQUOTA;
7704                         rc = name2gid(&qctl->qc_id, optarg);
7705                         goto quota_type;
7706                 case 'P':
7707                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
7708                         qtype = PRJQUOTA;
7709                         qctl->qc_id = 0;
7710                         goto quota_type_def;
7711                 case 'p':
7712                         qtype = PRJQUOTA;
7713                         rc = name2projid(&qctl->qc_id, optarg);
7714 quota_type:
7715                         if (rc) {
7716                                 if (str2quotaid(&qctl->qc_id, optarg)) {
7717                                         fprintf(stderr,
7718                                                 "%s setquota: invalid id '%s'\n",
7719                                                 progname, optarg);
7720                                         rc = -1;
7721                                         goto out;
7722                                 }
7723                         }
7724
7725                         if (qctl->qc_id == 0) {
7726                                 fprintf(stderr,
7727                                         "%s setquota: can't set quota for root usr/group/project.\n",
7728                                         progname);
7729                                 rc = -1;
7730                                 goto out;
7731                         }
7732
7733 quota_type_def:
7734                         if (qctl->qc_type != ALLQUOTA) {
7735                                 fprintf(stderr,
7736                                         "%s setquota: only one of -u, -U, -g, -G, -p or -P may be specified\n",
7737                                         progname);
7738                                 rc = CMD_HELP;
7739                                 goto out;
7740                         }
7741                         qctl->qc_type = qtype;
7742                         break;
7743                 case 'd':
7744                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
7745                         use_default = true;
7746                         break;
7747                 case 'b':
7748                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
7749                         dqb->dqb_bsoftlimit >>= 10;
7750                         limit_mask |= BSLIMIT;
7751                         if (dqb->dqb_bsoftlimit &&
7752                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
7753                                 fprintf(stderr,
7754                                         "%s setquota: warning: block softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
7755                                         progname,
7756                                         (unsigned long long)dqb->dqb_bsoftlimit,
7757                                         progname);
7758                         break;
7759                 case 'B':
7760                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
7761                         dqb->dqb_bhardlimit >>= 10;
7762                         limit_mask |= BHLIMIT;
7763                         if (dqb->dqb_bhardlimit &&
7764                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
7765                                 fprintf(stderr,
7766                                         "%s setquota: warning: block hardlimit '%llu' smaller than minimum qunit size\n"
7767                                         "See '%s help setquota' or Lustre manual for details\n",
7768                                         progname,
7769                                         (unsigned long long)dqb->dqb_bhardlimit,
7770                                         progname);
7771                         break;
7772                 case 'i':
7773                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
7774                         limit_mask |= ISLIMIT;
7775                         if (dqb->dqb_isoftlimit &&
7776                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
7777                                 fprintf(stderr,
7778                                         "%s setquota: warning: inode softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
7779                                         progname,
7780                                         (unsigned long long)dqb->dqb_isoftlimit,
7781                                         progname);
7782                         break;
7783                 case 'I':
7784                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
7785                         limit_mask |= IHLIMIT;
7786                         if (dqb->dqb_ihardlimit &&
7787                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
7788                                 fprintf(stderr,
7789                                         "%s setquota: warning: inode hardlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
7790                                         progname,
7791                                         (unsigned long long)dqb->dqb_ihardlimit,
7792                                         progname);
7793                         break;
7794                 case LFS_POOL_OPT:
7795                         if (lfs_verify_poolarg(optarg)) {
7796                                 rc = -1;
7797                                 goto out;
7798                         }
7799                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
7800                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_SETDEFAULT ?
7801                                                 LUSTRE_Q_SETDEFAULT_POOL :
7802                                                 LUSTRE_Q_SETQUOTAPOOL;
7803                         break;
7804                 default:
7805                         fprintf(stderr,
7806                                 "%s setquota: unrecognized option '%s'\n",
7807                                 progname, argv[optind - 1]);
7808                         /* fallthrough */
7809                 case 'h':
7810                         rc = CMD_HELP;
7811                         goto out;
7812                 }
7813         }
7814
7815         if (qctl->qc_type == ALLQUOTA) {
7816                 fprintf(stderr,
7817                         "%s setquota: either -u or -g must be specified\n",
7818                         progname);
7819                 rc = CMD_HELP;
7820                 goto out;
7821         }
7822
7823         if (!use_default && limit_mask == 0) {
7824                 fprintf(stderr,
7825                         "%s setquota: at least one limit must be specified\n",
7826                         progname);
7827                 rc = CMD_HELP;
7828                 goto out;
7829         }
7830
7831         if (use_default && limit_mask != 0) {
7832                 fprintf(stderr,
7833                         "%s setquota: limits should not be specified when using default quota\n",
7834                         progname);
7835                 rc = CMD_HELP;
7836                 goto out;
7837         }
7838
7839         if (use_default && qctl->qc_id == 0) {
7840                 fprintf(stderr,
7841                         "%s setquota: can not set default quota for root user/group/project\n",
7842                         progname);
7843                 rc = CMD_HELP;
7844                 goto out;
7845         }
7846
7847         if (optind != argc - 1) {
7848                 fprintf(stderr,
7849                         "%s setquota: filesystem not specified or unexpected argument '%s'\n",
7850                         progname, argv[optind]);
7851                 rc = CMD_HELP;
7852                 goto out;
7853         }
7854
7855         mnt = argv[optind];
7856
7857         if (use_default) {
7858                 dqb->dqb_bhardlimit = 0;
7859                 dqb->dqb_bsoftlimit = 0;
7860                 dqb->dqb_ihardlimit = 0;
7861                 dqb->dqb_isoftlimit = 0;
7862                 dqb->dqb_itime = 0;
7863                 dqb->dqb_btime = 0;
7864                 dqb->dqb_valid |= QIF_LIMITS | QIF_TIMES;
7865                 /* do not set inode limits for Pool Quotas */
7866                 if (qctl->qc_cmd  == LUSTRE_Q_SETDEFAULT_POOL)
7867                         dqb->dqb_valid ^= QIF_ILIMITS | QIF_ITIME;
7868         } else if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
7869                    (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
7870                 /* sigh, we can't just set blimits/ilimits */
7871                 struct if_quotactl tmp_qctl = {.qc_cmd  = LUSTRE_Q_GETQUOTA,
7872                                                .qc_type = qctl->qc_type,
7873                                                .qc_id   = qctl->qc_id};
7874
7875                 rc = llapi_quotactl(mnt, &tmp_qctl);
7876                 if (rc < 0)
7877                         goto out;
7878
7879                 if (!(limit_mask & BHLIMIT))
7880                         dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
7881                 if (!(limit_mask & BSLIMIT))
7882                         dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
7883                 if (!(limit_mask & IHLIMIT))
7884                         dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
7885                 if (!(limit_mask & ISLIMIT))
7886                         dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
7887
7888                 /* Keep grace times if we have got no softlimit arguments */
7889                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
7890                         dqb->dqb_valid |= QIF_BTIME;
7891                         dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
7892                 }
7893
7894                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
7895                         dqb->dqb_valid |= QIF_ITIME;
7896                         dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
7897                 }
7898         }
7899
7900         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
7901         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
7902
7903         rc = llapi_quotactl(mnt, qctl);
7904         if (rc) {
7905                 if (*obd_type)
7906                         fprintf(stderr,
7907                                 "%s setquota: cannot quotactl '%s' '%s': %s\n",
7908                                 progname, obd_type,
7909                                 obd_uuid2str(&qctl->obd_uuid), strerror(-rc));
7910                 else
7911                         fprintf(stderr,
7912                                 "%s setquota: quotactl failed: %s\n",
7913                                 progname, strerror(-rc));
7914         }
7915 out:
7916         if (rc)
7917                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
7918
7919         free(qctl);
7920         return rc;
7921 }
7922
7923 /* Converts seconds value into format string
7924  * result is returned in buf
7925  * Notes:
7926  *        1. result is in descenting order: 1w2d3h4m5s
7927  *        2. zero fields are not filled (except for p. 3): 5d1s
7928  *        3. zero seconds value is presented as "0s"
7929  */
7930 static char *__sec2str(time_t seconds, char *buf)
7931 {
7932         const char spec[] = "smhdw";
7933         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
7934         unsigned long c;
7935         char *tail = buf;
7936         int i;
7937
7938         for (i = ARRAY_SIZE(mult) - 1 ; i >= 0; i--) {
7939                 c = seconds / mult[i];
7940
7941                 if (c > 0 || (i == 0 && buf == tail))
7942                         tail += scnprintf(tail, 40-(tail-buf), "%lu%c", c,
7943                                           spec[i]);
7944
7945                 seconds %= mult[i];
7946         }
7947
7948         return tail;
7949 }
7950
7951 static void sec2str(time_t seconds, char *buf, int rc)
7952 {
7953         char *tail = buf;
7954
7955         if (rc)
7956                 *tail++ = '[';
7957
7958         tail = __sec2str(seconds, tail);
7959
7960         if (rc && tail - buf < 39) {
7961                 *tail++ = ']';
7962                 *tail++ = 0;
7963         }
7964 }
7965
7966 static void diff2str(time_t seconds, char *buf, time_t now)
7967 {
7968         buf[0] = 0;
7969         if (!seconds)
7970                 return;
7971         if (seconds <= now) {
7972                 strcpy(buf, "none");
7973                 return;
7974         }
7975         __sec2str(seconds - now, buf);
7976 }
7977
7978 static void print_quota_title(char *name, struct if_quotactl *qctl,
7979                               bool human_readable, bool show_default)
7980 {
7981         if (show_default) {
7982                 printf("Disk default %s quota:\n", qtype_name(qctl->qc_type));
7983                 printf("%15s %8s%8s%8s %8s%8s%8s\n",
7984                        "Filesystem", "bquota", "blimit", "bgrace",
7985                        "iquota", "ilimit", "igrace");
7986         } else {
7987                 printf("Disk quotas for %s %s (%cid %u):\n",
7988                        qtype_name(qctl->qc_type), name,
7989                        *qtype_name(qctl->qc_type), qctl->qc_id);
7990                 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
7991                        "Filesystem", human_readable ? "used" : "kbytes",
7992                        "quota", "limit", "grace",
7993                        "files", "quota", "limit", "grace");
7994         }
7995 }
7996
7997 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
7998 {
7999         if (!h) {
8000                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
8001         } else {
8002                 if (num >> 40)
8003                         snprintf(buf, buflen, "%5.4gP",
8004                                  (double)num / ((__u64)1 << 40));
8005                 else if (num >> 30)
8006                         snprintf(buf, buflen, "%5.4gT",
8007                                  (double)num / (1 << 30));
8008                 else if (num >> 20)
8009                         snprintf(buf, buflen, "%5.4gG",
8010                                  (double)num / (1 << 20));
8011                 else if (num >> 10)
8012                         snprintf(buf, buflen, "%5.4gM",
8013                                  (double)num / (1 << 10));
8014                 else
8015                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
8016         }
8017 }
8018
8019 #ifdef HAVE_NATIVE_CLIENT
8020 /* In the current Lustre implementation, the grace time is either the time
8021  * or the timestamp to be used after some quota ID exceeds the soft limt,
8022  * 48 bits should be enough, its high 16 bits can be used as quota flags.
8023  */
8024 #define LQUOTA_GRACE_BITS       48
8025 #define LQUOTA_GRACE_MASK       ((1ULL << LQUOTA_GRACE_BITS) - 1)
8026 #define LQUOTA_GRACE_MAX        LQUOTA_GRACE_MASK
8027 #define LQUOTA_GRACE(t)         (t & LQUOTA_GRACE_MASK)
8028 #define LQUOTA_FLAG(t)          (t >> LQUOTA_GRACE_BITS)
8029 #define LQUOTA_GRACE_FLAG(t, f) ((__u64)t | (__u64)f << LQUOTA_GRACE_BITS)
8030 #endif
8031
8032 #define STRBUF_LEN      24
8033 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
8034                         int rc, bool h, bool show_default)
8035 {
8036         time_t now;
8037
8038         time(&now);
8039
8040         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA ||
8041             qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
8042             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT ||
8043             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL) {
8044                 int bover = 0, iover = 0;
8045                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
8046                 char numbuf[3][STRBUF_LEN + 2]; /* 2 for brackets or wildcard */
8047                 char timebuf[40];
8048                 char strbuf[STRBUF_LEN];
8049
8050                 if (dqb->dqb_bhardlimit &&
8051                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
8052                         bover = 1;
8053                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
8054                         if (dqb->dqb_btime > now)
8055                                 bover = 2;
8056                         else
8057                                 bover = 3;
8058                 }
8059
8060                 if (dqb->dqb_ihardlimit &&
8061                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
8062                         iover = 1;
8063                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
8064                         if (dqb->dqb_itime > now)
8065                                 iover = 2;
8066                         else
8067                                 iover = 3;
8068                 }
8069
8070                 if (strlen(mnt) > 15)
8071                         printf("%s\n%15s", mnt, "");
8072                 else
8073                         printf("%15s", mnt);
8074
8075                 if (bover)
8076                         diff2str(dqb->dqb_btime, timebuf, now);
8077                 else if (show_default)
8078                         snprintf(timebuf, sizeof(timebuf), "%llu",
8079                                  (unsigned long long)dqb->dqb_btime);
8080
8081                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
8082                            strbuf, sizeof(strbuf), h);
8083                 if (rc == -EREMOTEIO)
8084                         sprintf(numbuf[0], "%s*", strbuf);
8085                 else
8086                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
8087                                 "%s" : "[%s]", strbuf);
8088
8089                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
8090                 if (type == QC_GENERAL)
8091                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
8092                                 "%s" : "[%s]", strbuf);
8093                 else
8094                         sprintf(numbuf[1], "%s", "-");
8095
8096                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
8097                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
8098                         "%s" : "[%s]", strbuf);
8099
8100                 if (show_default)
8101                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
8102                 else
8103                         printf(" %7s%c %6s %7s %7s",
8104                                numbuf[0], bover ? '*' : ' ', numbuf[1],
8105                                numbuf[2], bover > 1 ? timebuf : "-");
8106
8107                 if (iover)
8108                         diff2str(dqb->dqb_itime, timebuf, now);
8109                 else if (show_default)
8110                         snprintf(timebuf, sizeof(timebuf), "%llu",
8111                                  (unsigned long long)dqb->dqb_itime);
8112
8113                 snprintf(numbuf[0], sizeof(numbuf),
8114                          (dqb->dqb_valid & QIF_INODES) ? "%ju" : "[%ju]",
8115                          (uintmax_t)dqb->dqb_curinodes);
8116
8117                 if (type == QC_GENERAL)
8118                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
8119                                 "%ju" : "[%ju]",
8120                                 (uintmax_t)dqb->dqb_isoftlimit);
8121                 else
8122                         sprintf(numbuf[1], "%s", "-");
8123
8124                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
8125                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
8126
8127                 if (show_default)
8128                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
8129                 else if (type != QC_OSTIDX)
8130                         printf(" %7s%c %6s %7s %7s",
8131                                numbuf[0], iover ? '*' : ' ', numbuf[1],
8132                                numbuf[2], iover > 1 ? timebuf : "-");
8133                 else
8134                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
8135                 printf("\n");
8136         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO || LUSTRE_Q_GETINFOPOOL ||
8137                    qctl->qc_cmd == Q_GETOINFO) {
8138                 char bgtimebuf[40];
8139                 char igtimebuf[40];
8140
8141                 if (qctl->qc_dqinfo.dqi_bgrace == NOTIFY_GRACE_TIME)
8142                         strncpy(bgtimebuf, NOTIFY_GRACE, 40);
8143                 else
8144                         sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
8145                 if (qctl->qc_dqinfo.dqi_igrace == NOTIFY_GRACE_TIME)
8146                         strncpy(igtimebuf, NOTIFY_GRACE, 40);
8147                 else
8148                         sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
8149
8150                 printf("Block grace time: %s; Inode grace time: %s\n",
8151                        bgtimebuf, igtimebuf);
8152         }
8153 }
8154
8155 static int tgt_name2index(const char *tgtname, unsigned int *idx)
8156 {
8157         char *dash, *endp;
8158
8159         /* format is "lustre-OST0001" */
8160         dash = memchr(tgtname, '-', LUSTRE_MAXFSNAME + 1);
8161         if (!dash) {
8162                 fprintf(stderr, "wrong tgtname format '%s'\n", tgtname);
8163                 return -EINVAL;
8164         }
8165         dash += 4;
8166
8167         *idx = strtoul(dash, &endp, 16);
8168         if (*idx > 0xffff) {
8169                 fprintf(stderr, "wrong index %s\n", tgtname);
8170                 return -ERANGE;
8171         }
8172
8173         return 0;
8174 }
8175
8176 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
8177                            bool h, __u64 *total)
8178 {
8179         int rc = 0, rc1 = 0, count = 0, i = 0;
8180         char **list = NULL, *buffer = NULL;
8181         __u32 valid = qctl->qc_valid;
8182
8183         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL && is_mdt)
8184                 return 0;
8185
8186         /* Is it correct for the case OST0000, OST0002, OST0003 -
8187          * we will ask OST0001 that is absent and won't ask OST0003? */
8188         rc = llapi_get_obd_count(mnt, &count, is_mdt);
8189         if (rc) {
8190                 fprintf(stderr, "can not get %s count: %s\n",
8191                         is_mdt ? "mdt" : "ost", strerror(-rc));
8192                 return rc;
8193         }
8194
8195         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
8196                 char fname[PATH_MAX];
8197                 char fsname[LUSTRE_MAXFSNAME + 1];
8198                 int bufsize = sizeof(struct obd_uuid) * count;
8199
8200                 rc = llapi_search_fsname(mnt, fsname);
8201                 if (rc) {
8202                         fprintf(stderr, "cannot get fsname for mountpoint %s\n",
8203                                 mnt);
8204                         goto out;
8205                 }
8206                 buffer = malloc(bufsize + sizeof(*list) * count);
8207                 if (!buffer)
8208                         return -ENOMEM;
8209                 list = (char **)(buffer + bufsize);
8210                 snprintf(fname, PATH_MAX, "%s.%s", fsname, qctl->qc_poolname);
8211                 count = llapi_get_poolmembers(fname, list, count,
8212                                               buffer, bufsize);
8213                 if (count <= 0)
8214                         goto out;
8215         }
8216
8217         for (i = 0; i < count; i++) {
8218                 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
8219                         unsigned int index;
8220
8221                         if (tgt_name2index(list[i], &index))
8222                                 continue;
8223                         qctl->qc_idx = index;
8224                 } else {
8225                         qctl->qc_idx = i;
8226                 }
8227
8228                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
8229                 rc = llapi_quotactl(mnt, qctl);
8230                 if (rc) {
8231                         /* It is remote client case. */
8232                         if (rc == -EOPNOTSUPP) {
8233                                 rc = 0;
8234                                 goto out;
8235                         }
8236
8237                         if (!rc1)
8238                                 rc1 = rc;
8239                         fprintf(stderr, "quotactl %s%d failed.\n",
8240                                 is_mdt ? "mdt" : "ost", qctl->qc_idx);
8241                         continue;
8242                 }
8243
8244                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
8245                             qctl->qc_valid, 0, h, false);
8246                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
8247                                    qctl->qc_dqblk.dqb_bhardlimit;
8248         }
8249 out:
8250         if (buffer)
8251                 free(buffer);
8252         qctl->qc_valid = valid;
8253         return rc ? : rc1;
8254 }
8255
8256 static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
8257                            int verbose, int quiet, bool human_readable,
8258                            bool show_default)
8259 {
8260         int rc1 = 0, rc2 = 0, rc3 = 0;
8261         char *obd_type = (char *)qctl->obd_type;
8262         char *obd_uuid = (char *)qctl->obd_uuid.uuid;
8263         __u64 total_ialloc = 0, total_balloc = 0;
8264         bool use_default_for_blk = false;
8265         bool use_default_for_file = false;
8266         int inacc;
8267
8268         rc1 = llapi_quotactl(mnt, qctl);
8269         if (rc1 < 0) {
8270                 switch (rc1) {
8271                 case -ESRCH:
8272                         fprintf(stderr, "%s quotas are not enabled.\n",
8273                                 qtype_name(qctl->qc_type));
8274                         goto out;
8275                 case -EPERM:
8276                         fprintf(stderr, "Permission denied.\n");
8277                 case -ENODEV:
8278                 case -ENOENT:
8279                         /* We already got error message. */
8280                         goto out;
8281                 default:
8282                         fprintf(stderr, "Unexpected quotactl error: %s\n",
8283                                 strerror(-rc1));
8284                 }
8285         }
8286
8287         if (!show_default && qctl->qc_id == 0) {
8288                 qctl->qc_dqblk.dqb_bhardlimit = 0;
8289                 qctl->qc_dqblk.dqb_bsoftlimit = 0;
8290                 qctl->qc_dqblk.dqb_ihardlimit = 0;
8291                 qctl->qc_dqblk.dqb_isoftlimit = 0;
8292                 qctl->qc_dqblk.dqb_btime = 0;
8293                 qctl->qc_dqblk.dqb_itime = 0;
8294                 qctl->qc_dqblk.dqb_valid |= QIF_LIMITS | QIF_TIMES;
8295         }
8296
8297         if (qctl->qc_dqblk.dqb_valid & QIF_BTIME &&
8298             LQUOTA_FLAG(qctl->qc_dqblk.dqb_btime) & LQUOTA_FLAG_DEFAULT) {
8299                 use_default_for_blk = true;
8300                 qctl->qc_dqblk.dqb_btime &= LQUOTA_GRACE_MASK;
8301         }
8302
8303         if (qctl->qc_dqblk.dqb_valid & QIF_ITIME &&
8304             LQUOTA_FLAG(qctl->qc_dqblk.dqb_itime) & LQUOTA_FLAG_DEFAULT) {
8305                 use_default_for_file = true;
8306                 qctl->qc_dqblk.dqb_itime &= LQUOTA_GRACE_MASK;
8307         }
8308
8309         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
8310              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
8311              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL ||
8312              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) && !quiet)
8313                 print_quota_title(name, qctl, human_readable, show_default);
8314
8315         if (rc1 && *obd_type)
8316                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
8317
8318         if (qctl->qc_valid != QC_GENERAL)
8319                 mnt = "";
8320
8321         inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
8322                  qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
8323                 ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
8324                  (QIF_LIMITS|QIF_USAGE));
8325
8326         print_quota(mnt, qctl, QC_GENERAL, rc1, human_readable, show_default);
8327
8328         if (!show_default && verbose &&
8329             qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO &&
8330             qctl->qc_cmd != LUSTRE_Q_GETINFOPOOL) {
8331                 char strbuf[STRBUF_LEN];
8332
8333                 rc2 = print_obd_quota(mnt, qctl, 1, human_readable,
8334                                       &total_ialloc);
8335                 rc3 = print_obd_quota(mnt, qctl, 0, human_readable,
8336                                       &total_balloc);
8337                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
8338                            human_readable);
8339                 printf("Total allocated inode limit: %ju, total allocated block limit: %s\n",
8340                        (uintmax_t)total_ialloc, strbuf);
8341         }
8342
8343         if (use_default_for_blk)
8344                 printf("%cid %u is using default block quota setting\n",
8345                        *qtype_name(qctl->qc_type), qctl->qc_id);
8346
8347         if (use_default_for_file)
8348                 printf("%cid %u is using default file quota setting\n",
8349                        *qtype_name(qctl->qc_type), qctl->qc_id);
8350
8351         if (rc1 || rc2 || rc3 || inacc)
8352                 printf("Some errors happened when getting quota info. Some devices may be not working or deactivated. The data in \"[]\" is inaccurate.\n");
8353 out:
8354         if (rc1)
8355                 return rc1;
8356         if (rc2)
8357                 return rc2;
8358         if (rc3)
8359                 return rc3;
8360         if (inacc)
8361                 return -EIO;
8362
8363         return 0;
8364 }
8365
8366 static int lfs_project(int argc, char **argv)
8367 {
8368         int ret = 0, err = 0, c, i;
8369         struct project_handle_control phc = { 0 };
8370         enum lfs_project_ops_t op;
8371
8372         phc.newline = true;
8373         phc.assign_projid = false;
8374         /* default action */
8375         op = LFS_PROJECT_LIST;
8376
8377         while ((c = getopt(argc, argv, "p:cCsdkr0")) != -1) {
8378                 switch (c) {
8379                 case 'c':
8380                         if (op != LFS_PROJECT_LIST) {
8381                                 fprintf(stderr,
8382                                         "%s: cannot specify '-c' '-C' '-s' together\n",
8383                                         progname);
8384                                 return CMD_HELP;
8385                         }
8386
8387                         op = LFS_PROJECT_CHECK;
8388                         break;
8389                 case 'C':
8390                         if (op != LFS_PROJECT_LIST) {
8391                                 fprintf(stderr,
8392                                         "%s: cannot specify '-c' '-C' '-s' together\n",
8393                                         progname);
8394                                 return CMD_HELP;
8395                         }
8396
8397                         op = LFS_PROJECT_CLEAR;
8398                         break;
8399                 case 's':
8400                         if (op != LFS_PROJECT_LIST) {
8401                                 fprintf(stderr,
8402                                         "%s: cannot specify '-c' '-C' '-s' together\n",
8403                                         progname);
8404                                 return CMD_HELP;
8405                         }
8406
8407                         phc.set_inherit = true;
8408                         op = LFS_PROJECT_SET;
8409                         break;
8410                 case 'd':
8411                         phc.dironly = true;
8412                         break;
8413                 case 'k':
8414                         phc.keep_projid = true;
8415                         break;
8416                 case 'r':
8417                         phc.recursive = true;
8418                         break;
8419                 case 'p':
8420                         if (str2quotaid(&phc.projid, optarg)) {
8421                                 fprintf(stderr,
8422                                         "Invalid project ID: %s\n",
8423                                         optarg);
8424                                 return CMD_HELP;
8425                         }
8426
8427                         phc.assign_projid = true;
8428
8429                         break;
8430                 case '0':
8431                         phc.newline = false;
8432                         break;
8433                 default:
8434                         fprintf(stderr, "%s: invalid option '%c'\n",
8435                                 progname, optopt);
8436                         return CMD_HELP;
8437                 }
8438         }
8439
8440         if (phc.assign_projid && op == LFS_PROJECT_LIST) {
8441                 op = LFS_PROJECT_SET;
8442                 phc.set_projid = true;
8443         } else if (phc.assign_projid && op == LFS_PROJECT_SET) {
8444                 phc.set_projid = true;
8445         }
8446
8447         switch (op) {
8448         case LFS_PROJECT_CHECK:
8449                 if (phc.keep_projid) {
8450                         fprintf(stderr,
8451                                 "%s: '-k' is useless together with '-c'\n",
8452                                 progname);
8453                         return CMD_HELP;
8454                 }
8455                 break;
8456         case LFS_PROJECT_CLEAR:
8457                 if (!phc.newline) {
8458                         fprintf(stderr,
8459                                 "%s: '-0' is useless together with '-C'\n",
8460                                 progname);
8461                         return CMD_HELP;
8462                 }
8463                 if (phc.assign_projid) {
8464                         fprintf(stderr,
8465                                 "%s: '-p' is useless together with '-C'\n",
8466                                 progname);
8467                         return CMD_HELP;
8468                 }
8469                 break;
8470         case LFS_PROJECT_SET:
8471                 if (!phc.newline) {
8472                         fprintf(stderr,
8473                                 "%s: '-0' is useless together with '-s'\n",
8474                                 progname);
8475                         return CMD_HELP;
8476                 }
8477                 if (phc.keep_projid) {
8478                         fprintf(stderr,
8479                                 "%s: '-k' is useless together with '-s'\n",
8480                                 progname);
8481                         return CMD_HELP;
8482                 }
8483                 break;
8484         default:
8485                 if (!phc.newline) {
8486                         fprintf(stderr,
8487                                 "%s: '-0' is useless for list operations\n",
8488                                 progname);
8489                         return CMD_HELP;
8490                 }
8491                 break;
8492         }
8493
8494         argv += optind;
8495         argc -= optind;
8496         if (argc == 0) {
8497                 fprintf(stderr, "%s: missing file or directory target(s)\n",
8498                         progname);
8499                 return CMD_HELP;
8500         }
8501
8502         for (i = 0; i < argc; i++) {
8503                 switch (op) {
8504                 case LFS_PROJECT_CHECK:
8505                         err = lfs_project_check(argv[i], &phc);
8506                         break;
8507                 case LFS_PROJECT_LIST:
8508                         err = lfs_project_list(argv[i], &phc);
8509                         break;
8510                 case LFS_PROJECT_CLEAR:
8511                         err = lfs_project_clear(argv[i], &phc);
8512                         break;
8513                 case LFS_PROJECT_SET:
8514                         err = lfs_project_set(argv[i], &phc);
8515                         break;
8516                 default:
8517                         break;
8518                 }
8519                 if (err && !ret)
8520                         ret = err;
8521         }
8522
8523         return ret;
8524 }
8525
8526 static int lfs_quota(int argc, char **argv)
8527 {
8528         int c;
8529         char *mnt, *name = NULL;
8530         struct if_quotactl *qctl;
8531         char *obd_uuid;
8532         int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
8533         __u32 valid = QC_GENERAL, idx = 0;
8534         bool human_readable = false;
8535         bool show_default = false;
8536         int qtype;
8537         bool show_pools = false;
8538         struct option long_opts[] = {
8539         { .val = LFS_POOL_OPT, .name = "pool", .has_arg = optional_argument },
8540         { .name = NULL } };
8541         char **poollist = NULL;
8542         char *buf = NULL;
8543         int poolcount, i;
8544
8545         qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1);
8546         if (!qctl)
8547                 return -ENOMEM;
8548
8549         qctl->qc_cmd = LUSTRE_Q_GETQUOTA;
8550         qctl->qc_type = ALLQUOTA;
8551         obd_uuid = (char *)qctl->obd_uuid.uuid;
8552
8553         while ((c = getopt_long(argc, argv, "gGi:I:o:pPqtuUvh",
8554                 long_opts, NULL)) != -1) {
8555                 switch (c) {
8556                 case 'U':
8557                         show_default = true;
8558                 case 'u':
8559                         qtype = USRQUOTA;
8560                         goto quota_type;
8561                 case 'G':
8562                         show_default = true;
8563                 case 'g':
8564                         qtype = GRPQUOTA;
8565                         goto quota_type;
8566                 case 'P':
8567                         show_default = true;
8568                 case 'p':
8569                         qtype = PRJQUOTA;
8570 quota_type:
8571                         if (qctl->qc_type != ALLQUOTA) {
8572                                 fprintf(stderr,
8573                                         "%s quota: only one of -u, -g, or -p may be specified\n",
8574                                         progname);
8575                                 rc = CMD_HELP;
8576                                 goto out;
8577                         }
8578                         qctl->qc_type = qtype;
8579                         break;
8580                 case 't':
8581                         qctl->qc_cmd = LUSTRE_Q_GETINFO;
8582                         break;
8583                 case 'o':
8584                         valid = qctl->qc_valid = QC_UUID;
8585                         snprintf(obd_uuid, sizeof(*obd_uuid), "%s", optarg);
8586                         break;
8587                 case 'i':
8588                         valid = qctl->qc_valid = QC_MDTIDX;
8589                         idx = qctl->qc_idx = atoi(optarg);
8590                         if (idx == 0 && *optarg != '0') {
8591                                 fprintf(stderr,
8592                                         "%s quota: invalid MDT index '%s'\n",
8593                                         progname, optarg);
8594                                 rc = CMD_HELP;
8595                                 goto out;
8596                         }
8597                         break;
8598                 case 'I':
8599                         valid = qctl->qc_valid = QC_OSTIDX;
8600                         idx = qctl->qc_idx = atoi(optarg);
8601                         if (idx == 0 && *optarg != '0') {
8602                                 fprintf(stderr,
8603                                         "%s quota: invalid OST index '%s'\n",
8604                                         progname, optarg);
8605                                 rc = CMD_HELP;
8606                                 goto out;
8607                         }
8608                         break;
8609                 case 'v':
8610                         verbose = 1;
8611                         break;
8612                 case 'q':
8613                         quiet = 1;
8614                         break;
8615                 case 'h':
8616                         human_readable = true;
8617                         break;
8618                 case LFS_POOL_OPT:
8619                         if ((!optarg) && (argv[optind] != NULL) &&
8620                                 (argv[optind][0] != '-') &&
8621                                 (argv[optind][0] != '/')) {
8622                                 optarg = argv[optind++];
8623                                 if (lfs_verify_poolarg(optarg)) {
8624                                         rc = -EINVAL;
8625                                         goto out;
8626                                 }
8627                                 strncpy(qctl->qc_poolname, optarg,
8628                                         LOV_MAXPOOLNAME);
8629                                 if (qctl->qc_cmd == LUSTRE_Q_GETINFO)
8630                                         qctl->qc_cmd = LUSTRE_Q_GETINFOPOOL;
8631                                 else
8632                                         qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
8633                                 break;
8634                         }
8635
8636                         /* optarg is NULL */
8637                         show_pools = true;
8638                         qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
8639                         break;
8640                 default:
8641                         fprintf(stderr, "%s quota: unrecognized option '%s'\n",
8642                                 progname, argv[optind - 1]);
8643                         rc = CMD_HELP;
8644                         goto out;
8645                 }
8646         }
8647
8648         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
8649         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
8650              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
8651              qctl->qc_type == ALLQUOTA &&
8652              optind == argc - 1 && !show_default) {
8653                 qctl->qc_idx = idx;
8654
8655                 for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) {
8656                         qctl->qc_type = qtype;
8657                         qctl->qc_valid = valid;
8658                         if (qtype == USRQUOTA) {
8659                                 qctl->qc_id = geteuid();
8660                                 rc = uid2name(&name, qctl->qc_id);
8661                         } else {
8662                                 qctl->qc_id = getegid();
8663                                 rc = gid2name(&name, qctl->qc_id);
8664                                 memset(&qctl->qc_dqblk, 0,
8665                                        sizeof(qctl->qc_dqblk));
8666                         }
8667                         if (rc)
8668                                 name = "<unknown>";
8669                         mnt = argv[optind];
8670                         rc1 = get_print_quota(mnt, name, qctl, verbose, quiet,
8671                                               human_readable, show_default);
8672                         if (rc1 && !rc)
8673                                 rc = rc1;
8674                 }
8675                 goto out;
8676         /* lfs quota -u username /path/to/lustre/mount */
8677         } else if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
8678                    qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
8679                 /* options should be followed by u/g-name and mntpoint */
8680                 if ((!show_default && optind + 2 != argc) ||
8681                     (show_default && optind + 1 != argc) ||
8682                     qctl->qc_type == ALLQUOTA) {
8683                         fprintf(stderr,
8684                                 "%s quota: name and mount point must be specified\n",
8685                                 progname);
8686                         rc = CMD_HELP;
8687                         goto out;
8688                 }
8689
8690                 if (!show_default) {
8691                         name = argv[optind++];
8692                         switch (qctl->qc_type) {
8693                         case USRQUOTA:
8694                                 rc = name2uid(&qctl->qc_id, name);
8695                                 break;
8696                         case GRPQUOTA:
8697                                 rc = name2gid(&qctl->qc_id, name);
8698                                 break;
8699                         case PRJQUOTA:
8700                                 rc = name2projid(&qctl->qc_id, name);
8701                                 break;
8702                         default:
8703                                 rc = -ENOTSUP;
8704                                 break;
8705                         }
8706                 } else {
8707                         qctl->qc_valid = QC_GENERAL;
8708                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ?
8709                                         LUSTRE_Q_GETDEFAULT_POOL :
8710                                         LUSTRE_Q_GETDEFAULT;
8711                         qctl->qc_id = 0;
8712                 }
8713
8714                 if (rc) {
8715                         if (str2quotaid(&qctl->qc_id, name)) {
8716                                 fprintf(stderr, "%s quota: invalid id '%s'\n",
8717                                         progname, name);
8718                                 rc = CMD_HELP;
8719                                 goto out;
8720                         }
8721                 }
8722         } else if (optind + 1 != argc || qctl->qc_type == ALLQUOTA) {
8723                 fprintf(stderr, "%s quota: missing quota info argument(s)\n",
8724                         progname);
8725                 rc = CMD_HELP;
8726                 goto out;
8727         }
8728
8729         mnt = argv[optind];
8730         if (show_pools) {
8731                 char *p;
8732
8733                 i = 0;
8734                 rc = llapi_get_poolbuf(mnt, &buf, &poollist, &poolcount);
8735                 if (rc)
8736                         goto out;
8737
8738                 for (i = 0; i < poolcount; i++) {
8739                         p = memchr(poollist[i], '.', MAXNAMLEN);
8740                         if (!p) {
8741                                 fprintf(stderr, "bad string format %.*s\n",
8742                                         MAXNAMLEN, poollist[i]);
8743                                 rc = -EINVAL;
8744                                 goto out;
8745                         }
8746                         p++;
8747                         printf("Quotas for pool: %s\n", p);
8748                         strncpy(qctl->qc_poolname, p, LOV_MAXPOOLNAME);
8749                         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
8750                                              human_readable, show_default);
8751                         if (rc)
8752                                 break;
8753                 }
8754                 goto out;
8755         }
8756
8757         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
8758                              human_readable, show_default);
8759 out:
8760         free(buf);
8761         free(qctl);
8762         return rc;
8763 }
8764 #endif /* HAVE_SYS_QUOTA_H! */
8765
8766 static int flushctx_ioctl(char *mp)
8767 {
8768         int fd, rc;
8769
8770         fd = open(mp, O_RDONLY);
8771         if (fd == -1) {
8772                 fprintf(stderr, "flushctx: error open %s: %s\n",
8773                         mp, strerror(errno));
8774                 return -1;
8775         }
8776
8777         rc = ioctl(fd, LL_IOC_FLUSHCTX);
8778         if (rc == -1)
8779                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
8780                         mp, strerror(errno));
8781
8782         close(fd);
8783         return rc;
8784 }
8785
8786 static int lfs_flushctx(int argc, char **argv)
8787 {
8788         int     kdestroy = 0, reap = 0, c;
8789         char    mntdir[PATH_MAX] = {'\0'};
8790         int     index = 0;
8791         int     rc = 0;
8792
8793         while ((c = getopt(argc, argv, "kr")) != -1) {
8794                 switch (c) {
8795                 case 'k':
8796                         kdestroy = 1;
8797                         break;
8798                 case 'r':
8799                         reap = 1;
8800                         break;
8801                 default:
8802                         fprintf(stderr,
8803                                 "error: %s: option '-%c' unrecognized\n",
8804                                 argv[0], c);
8805                         return CMD_HELP;
8806                 }
8807         }
8808
8809         if (kdestroy) {
8810                 rc = system("kdestroy > /dev/null");
8811                 if (rc) {
8812                         rc = WEXITSTATUS(rc);
8813                         fprintf(stderr,
8814                                 "error destroying tickets: %d, continuing\n",
8815                                 rc);
8816                 }
8817         }
8818
8819         if (optind >= argc) {
8820                 /* flush for all mounted lustre fs. */
8821                 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
8822                         /* Check if we have a mount point */
8823                         if (mntdir[0] == '\0')
8824                                 continue;
8825
8826                         if (flushctx_ioctl(mntdir))
8827                                 rc = -1;
8828
8829                         mntdir[0] = '\0'; /* avoid matching in next loop */
8830                 }
8831         } else {
8832                 /* flush fs as specified */
8833                 while (optind < argc) {
8834                         if (flushctx_ioctl(argv[optind++]))
8835                                 rc = -1;
8836                 }
8837         }
8838
8839         if (reap) {
8840                 rc = system("keyctl reap > /dev/null");
8841                 if (rc != 0) {
8842                         rc = WEXITSTATUS(rc);
8843                         fprintf(stderr, "error reaping keyring: %d\n", rc);
8844                 }
8845         }
8846
8847         return rc;
8848 }
8849
8850 static int lfs_changelog(int argc, char **argv)
8851 {
8852         void *changelog_priv;
8853         struct changelog_rec *rec;
8854         long long startrec = 0, endrec = 0;
8855         char *mdd;
8856         struct option long_opts[] = {
8857                 { .val = 'f', .name = "follow", .has_arg = no_argument },
8858                 { .name = NULL } };
8859         char short_opts[] = "f";
8860         int rc, follow = 0;
8861
8862         while ((rc = getopt_long(argc, argv, short_opts,
8863                 long_opts, NULL)) != -1) {
8864                 switch (rc) {
8865                 case 'f':
8866                         follow++;
8867                         break;
8868                 default:
8869                         fprintf(stderr,
8870                                 "%s changelog: unrecognized option '%s'\n",
8871                                 progname, argv[optind - 1]);
8872                         return CMD_HELP;
8873                 }
8874         }
8875         if (optind >= argc) {
8876                 fprintf(stderr, "%s changelog: mdtname must be specified\n",
8877                         progname);
8878                 return CMD_HELP;
8879         }
8880
8881         mdd = argv[optind++];
8882         if (argc > optind) {
8883                 errno = 0;
8884                 startrec = strtoll(argv[optind++], NULL, 10);
8885                 if (errno != 0 || startrec < 0) {
8886                         fprintf(stderr,
8887                                 "%s changelog: bad startrec\n",
8888                                 progname);
8889                         return CMD_HELP;
8890                 }
8891         }
8892
8893         if (argc > optind) {
8894                 errno = 0;
8895                 endrec = strtoll(argv[optind++], NULL, 10);
8896                 if (errno != 0 || endrec < 0) {
8897                         fprintf(stderr,
8898                                 "%s changelog: bad endrec\n",
8899                                 progname);
8900                         return CMD_HELP;
8901                 }
8902         }
8903
8904         rc = llapi_changelog_start(&changelog_priv,
8905                                    CHANGELOG_FLAG_BLOCK |
8906                                    CHANGELOG_FLAG_JOBID |
8907                                    CHANGELOG_FLAG_EXTRA_FLAGS |
8908                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
8909                                    mdd, startrec);
8910         if (rc < 0) {
8911                 fprintf(stderr, "%s changelog: cannot start changelog: %s\n",
8912                         progname, strerror(errno = -rc));
8913                 return rc;
8914         }
8915
8916         rc = llapi_changelog_set_xflags(changelog_priv,
8917                                         CHANGELOG_EXTRA_FLAG_UIDGID |
8918                                         CHANGELOG_EXTRA_FLAG_NID |
8919                                         CHANGELOG_EXTRA_FLAG_OMODE |
8920                                         CHANGELOG_EXTRA_FLAG_XATTR);
8921         if (rc < 0) {
8922                 fprintf(stderr,
8923                         "%s changelog: cannot set xflags for changelog: %s\n",
8924                         progname, strerror(errno = -rc));
8925                 return rc;
8926         }
8927
8928         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
8929                 time_t secs;
8930                 struct tm ts;
8931
8932                 if (endrec && rec->cr_index > endrec) {
8933                         llapi_changelog_free(&rec);
8934                         break;
8935                 }
8936                 if (rec->cr_index < startrec) {
8937                         llapi_changelog_free(&rec);
8938                         continue;
8939                 }
8940
8941                 secs = rec->cr_time >> 30;
8942                 gmtime_r(&secs, &ts);
8943                 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
8944                        "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
8945                        changelog_type2str(rec->cr_type),
8946                        ts.tm_hour, ts.tm_min, ts.tm_sec,
8947                        (int)(rec->cr_time & ((1 << 30) - 1)),
8948                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
8949                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
8950
8951                 if (rec->cr_flags & CLF_JOBID) {
8952                         struct changelog_ext_jobid *jid =
8953                                 changelog_rec_jobid(rec);
8954
8955                         if (jid->cr_jobid[0] != '\0')
8956                                 printf(" j=%s", jid->cr_jobid);
8957                 }
8958
8959                 if (rec->cr_flags & CLF_EXTRA_FLAGS) {
8960                         struct changelog_ext_extra_flags *ef =
8961                                 changelog_rec_extra_flags(rec);
8962
8963                         printf(" ef=0x%llx",
8964                                (unsigned long long)ef->cr_extra_flags);
8965
8966                         if (ef->cr_extra_flags & CLFE_UIDGID) {
8967                                 struct changelog_ext_uidgid *uidgid =
8968                                         changelog_rec_uidgid(rec);
8969
8970                                 printf(" u=%llu:%llu",
8971                                        (unsigned long long)uidgid->cr_uid,
8972                                        (unsigned long long)uidgid->cr_gid);
8973                         }
8974                         if (ef->cr_extra_flags & CLFE_NID) {
8975                                 struct changelog_ext_nid *nid =
8976                                         changelog_rec_nid(rec);
8977
8978                                 printf(" nid=%s",
8979                                        libcfs_nid2str(nid->cr_nid));
8980                         }
8981
8982                         if (ef->cr_extra_flags & CLFE_OPEN) {
8983                                 struct changelog_ext_openmode *omd =
8984                                         changelog_rec_openmode(rec);
8985                                 char mode[] = "---";
8986
8987                                 /* exec mode must be exclusive */
8988                                 if (omd->cr_openflags & MDS_FMODE_EXEC) {
8989                                         mode[2] = 'x';
8990                                 } else {
8991                                         if (omd->cr_openflags & MDS_FMODE_READ)
8992                                                 mode[0] = 'r';
8993                                         if (omd->cr_openflags &
8994                                             (MDS_FMODE_WRITE |
8995                                              MDS_OPEN_TRUNC |
8996                                              MDS_OPEN_APPEND))
8997                                                 mode[1] = 'w';
8998                                 }
8999
9000                                 if (strcmp(mode, "---") != 0)
9001                                         printf(" m=%s", mode);
9002                         }
9003
9004                         if (ef->cr_extra_flags & CLFE_XATTR) {
9005                                 struct changelog_ext_xattr *xattr =
9006                                         changelog_rec_xattr(rec);
9007
9008                                 if (xattr->cr_xattr[0] != '\0')
9009                                         printf(" x=%s", xattr->cr_xattr);
9010                         }
9011                 }
9012
9013                 if (!fid_is_zero(&rec->cr_pfid))
9014                         printf(" p="DFID, PFID(&rec->cr_pfid));
9015                 if (rec->cr_namelen)
9016                         printf(" %.*s", rec->cr_namelen,
9017                                changelog_rec_name(rec));
9018
9019                 if (rec->cr_flags & CLF_RENAME) {
9020                         struct changelog_ext_rename *rnm =
9021                                 changelog_rec_rename(rec);
9022
9023                         if (!fid_is_zero(&rnm->cr_sfid))
9024                                 printf(" s="DFID" sp="DFID" %.*s",
9025                                        PFID(&rnm->cr_sfid),
9026                                        PFID(&rnm->cr_spfid),
9027                                        (int)changelog_rec_snamelen(rec),
9028                                        changelog_rec_sname(rec));
9029                 }
9030                 printf("\n");
9031
9032                 llapi_changelog_free(&rec);
9033         }
9034
9035         llapi_changelog_fini(&changelog_priv);
9036
9037         if (rc < 0)
9038                 fprintf(stderr, "%s changelog: cannot access changelog: %s\n",
9039                         progname, strerror(errno = -rc));
9040
9041         return (rc == 1 ? 0 : rc);
9042 }
9043
9044 static int lfs_changelog_clear(int argc, char **argv)
9045 {
9046         long long endrec;
9047         int rc;
9048
9049         if (argc != 4)
9050                 return CMD_HELP;
9051
9052         errno = 0;
9053         endrec = strtoll(argv[3], NULL, 10);
9054         if (errno != 0 || endrec < 0) {
9055                 fprintf(stderr,
9056                         "%s: bad endrec '%s'\n",
9057                         argv[0], argv[3]);
9058                 return CMD_HELP;
9059         }
9060
9061         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
9062
9063         if (rc == -EINVAL)
9064                 fprintf(stderr, "%s: record out of range: %llu\n",
9065                         argv[0], endrec);
9066         else if (rc == -ENOENT)
9067                 fprintf(stderr, "%s: no changelog user: %s\n",
9068                         argv[0], argv[2]);
9069         else if (rc)
9070                 fprintf(stderr, "%s error: %s\n", argv[0],
9071                         strerror(-rc));
9072
9073         if (rc)
9074                 errno = -rc;
9075
9076         return rc;
9077 }
9078
9079 static void rstripc(char *str, int c)
9080 {
9081         char *end = str + strlen(str);
9082
9083         for (; str < end && end[-1] == c; --end)
9084                 end[-1] = '\0';
9085 }
9086
9087 static int lfs_fid2path(int argc, char **argv)
9088 {
9089         struct option long_opts[] = {
9090                 { .val = 'c',   .name = "cur",  .has_arg = no_argument },
9091                 { .val = 'c',   .name = "current",      .has_arg = no_argument },
9092                 { .val = 'c',   .name = "print-link",   .has_arg = no_argument },
9093                 { .val = 'f',   .name = "print-fid",    .has_arg = no_argument },
9094                 { .val = 'l',   .name = "link", .has_arg = required_argument },
9095                 { .name = NULL } };
9096         char short_opts[] = "cfl:pr:";
9097         bool print_link = false;
9098         bool print_fid = false;
9099         bool print_mnt_dir;
9100         char mnt_dir[PATH_MAX] = "";
9101         int mnt_fd = -1;
9102         char *path_or_fsname;
9103         long long recno = -1;
9104         int linkno = -1;
9105         char *endptr = NULL;
9106         int rc = 0;
9107         int c;
9108         int i;
9109
9110         while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
9111                 switch (c) {
9112                 case 'c':
9113                         print_link = true;
9114                         break;
9115                 case 'f':
9116                         print_fid = true;
9117                         break;
9118                 case 'l':
9119                         errno = 0;
9120                         linkno = strtol(optarg, &endptr, 10);
9121                         if (errno != 0 || *endptr != '\0' || linkno < 0) {
9122                                 fprintf(stderr,
9123                                         "%s fid2path: invalid linkno '%s'\n",
9124                                         progname, optarg);
9125                                 return CMD_HELP;
9126                         }
9127                         break;
9128                 case 'r':
9129                         /* recno is something to do with changelogs
9130                          * that was never implemented. We just pass it
9131                          * through for the MDT to ignore.
9132                          */
9133                         errno = 0;
9134                         recno = strtoll(optarg, &endptr, 10);
9135                         if (errno != 0 || *endptr != '\0' || recno < 0) {
9136                                 fprintf(stderr,
9137                                         "%s fid2path: invalid recno '%s'\n",
9138                                         progname, optarg);
9139                                 return CMD_HELP;
9140                         }
9141                         break;
9142                 default:
9143                         fprintf(stderr,
9144                                 "%s fid2path: unrecognized option '%s'\n",
9145                                 progname, argv[optind - 1]);
9146                         return CMD_HELP;
9147                 }
9148         }
9149
9150         if (argc - optind < 2) {
9151                 fprintf(stderr,
9152                         "Usage: %s fid2path FSNAME|ROOT FID...\n",
9153                         progname);
9154                 return CMD_HELP;
9155         }
9156
9157         path_or_fsname = argv[optind];
9158
9159         if (*path_or_fsname == '/') {
9160                 print_mnt_dir = true;
9161                 rc = llapi_search_mounts(path_or_fsname, 0, mnt_dir, NULL);
9162         } else {
9163                 print_mnt_dir = false;
9164                 rc = llapi_search_rootpath(mnt_dir, path_or_fsname);
9165         }
9166
9167         if (rc < 0) {
9168                 fprintf(stderr,
9169                         "%s fid2path: cannot resolve mount point for '%s': %s\n",
9170                         progname, path_or_fsname, strerror(-rc));
9171                 goto out;
9172         }
9173
9174         mnt_fd = open(mnt_dir, O_RDONLY | O_DIRECTORY);
9175         if (mnt_fd < 0) {
9176                 fprintf(stderr,
9177                         "%s fid2path: cannot open mount point for '%s': %s\n",
9178                         progname, path_or_fsname, strerror(-rc));
9179                 goto out;
9180         }
9181
9182         /* Strip trailing slashes from mnt_dir. */
9183         rstripc(mnt_dir + 1, '/');
9184
9185         for (i = optind + 1; i < argc; i++) {
9186                 const char *fid_str = argv[i];
9187                 struct lu_fid fid;
9188                 int rc2;
9189
9190                 rc2 = llapi_fid_parse(fid_str, &fid, NULL);
9191                 if (rc2 < 0) {
9192                         fprintf(stderr,
9193                                 "%s fid2path: invalid FID '%s'\n",
9194                                 progname, fid_str);
9195                         if (rc == 0)
9196                                 rc = rc2;
9197
9198                         continue;
9199                 }
9200
9201                 int linktmp = (linkno >= 0) ? linkno : 0;
9202                 while (1) {
9203                         int oldtmp = linktmp;
9204                         long long rectmp = recno;
9205                         char path_buf[PATH_MAX];
9206
9207                         rc2 = llapi_fid2path_at(mnt_fd, &fid,
9208                                 path_buf, sizeof(path_buf), &rectmp, &linktmp);
9209                         if (rc2 < 0) {
9210                                 fprintf(stderr,
9211                                         "%s fid2path: cannot find %s %s: %s\n",
9212                                         progname, path_or_fsname, fid_str,
9213                                         strerror(-rc2));
9214                                 if (rc == 0)
9215                                         rc = rc2;
9216                                 break;
9217                         }
9218
9219                         if (print_fid)
9220                                 printf("%s ", fid_str);
9221
9222                         if (print_link)
9223                                 printf("%d ", linktmp);
9224
9225                         /* You may think this looks wrong or weird (and it is!)
9226                          * but we are actually trying to preserve the old quirky
9227                          * behaviors (enforced by our old quirky tests!) that
9228                          * make lfs so much fun to work on:
9229                          *
9230                          *   lustre 0x200000007:0x1:0x0 => "/"
9231                          *   /mnt/lustre 0x200000007:0x1:0x0 => "/mnt/lustre//"
9232                          *
9233                          * Note that llapi_fid2path() returns "" for the root
9234                          * FID. */
9235
9236                         printf("%s%s%s\n",
9237                                print_mnt_dir ? mnt_dir : "",
9238                                (print_mnt_dir || *path_buf == '\0') ? "/" : "",
9239                                path_buf);
9240
9241                         if (linkno >= 0)
9242                                 /* specified linkno */
9243                                 break;
9244
9245                         if (oldtmp == linktmp)
9246                                 /* no more links */
9247                                 break;
9248                 }
9249         }
9250 out:
9251         if (!(mnt_fd < 0))
9252                 close(mnt_fd);
9253
9254         return rc;
9255 }
9256
9257 static int lfs_path2fid(int argc, char **argv)
9258 {
9259         struct option long_opts[] = {
9260                 { .val = 'p', .name = "parents", .has_arg = no_argument },
9261                 { .name = NULL } };
9262         char            **path;
9263         const char        short_opts[] = "p";
9264         const char       *sep = "";
9265         struct lu_fid     fid;
9266         int               rc = 0;
9267         bool              show_parents = false;
9268
9269         while ((rc = getopt_long(argc, argv, short_opts,
9270                                  long_opts, NULL)) != -1) {
9271                 switch (rc) {
9272                 case 'p':
9273                         show_parents = true;
9274                         break;
9275                 default:
9276                         fprintf(stderr,
9277                                 "%s path2fid: unrecognized option '%s'\n",
9278                                 progname, argv[optind - 1]);
9279                         return CMD_HELP;
9280                 }
9281         }
9282
9283         if (optind > argc - 1) {
9284                 fprintf(stderr, "%s path2fid: FILE... must be specified\n",
9285                         progname);
9286                 return CMD_HELP;
9287         } else if (optind < argc - 1) {
9288                 sep = ": ";
9289         }
9290
9291         rc = 0;
9292         for (path = argv + optind; *path != NULL; path++) {
9293                 int err = 0;
9294
9295                 if (!show_parents) {
9296                         err = llapi_path2fid(*path, &fid);
9297                         if (!err)
9298                                 printf("%s%s"DFID"\n",
9299                                        *sep != '\0' ? *path : "", sep,
9300                                        PFID(&fid));
9301                 } else {
9302                         char            name[NAME_MAX + 1];
9303                         unsigned int    linkno = 0;
9304
9305                         while ((err = llapi_path2parent(*path, linkno, &fid,
9306                                                 name, sizeof(name))) == 0) {
9307                                 if (*sep != '\0' && linkno == 0)
9308                                         printf("%s%s", *path, sep);
9309
9310                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
9311                                        PFID(&fid), name);
9312                                 linkno++;
9313                         }
9314
9315                         /* err == -ENODATA is end-of-loop */
9316                         if (linkno > 0 && err == -ENODATA) {
9317                                 printf("\n");
9318                                 err = 0;
9319                         }
9320                 }
9321
9322                 if (err) {
9323                         fprintf(stderr,
9324                                 "%s path2fid: cannot get %sfid for '%s': %s\n",
9325                                 progname, show_parents ? "parent " : "", *path,
9326                                 strerror(-err));
9327                         if (rc == 0) {
9328                                 rc = err;
9329                                 errno = -err;
9330                         }
9331                 }
9332         }
9333
9334         return rc;
9335 }
9336
9337 #define MAX_ERRNO       4095
9338 #define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO)
9339
9340 static int lfs_rmfid_and_show_errors(const char *device, struct fid_array *fa)
9341 {
9342         int rc, rc2, k;
9343
9344         rc = llapi_rmfid(device, fa);
9345         if (rc < 0) {
9346                 fprintf(stderr, "%s rmfid: cannot remove FIDs: %s\n",
9347                         progname, strerror(-rc));
9348                 return rc;
9349         }
9350
9351         for (k = 0; k < fa->fa_nr; k++) {
9352                 rc2 = (__s32)fa->fa_fids[k].f_ver;
9353                 if (!IS_ERR_VALUE(rc2))
9354                         continue;
9355
9356                 if (rc == 0)
9357                         rc = rc2;
9358
9359                 fa->fa_fids[k].f_ver = 0;
9360                 fprintf(stderr, "%s rmfid: cannot remove "DFID": %s\n",
9361                         progname, PFID(&fa->fa_fids[k]), strerror(-rc2));
9362         }
9363
9364         return rc;
9365 }
9366
9367 static int lfs_rmfid(int argc, char **argv)
9368 {
9369         char *fidstr, *device;
9370         int rc = 0, rc2, nr;
9371         struct fid_array *fa;
9372
9373         if (optind > argc - 1) {
9374                 fprintf(stderr, "%s rmfid: missing dirname\n", progname);
9375                 return CMD_HELP;
9376         }
9377
9378         device = argv[optind++];
9379
9380         nr = argc - optind;
9381         fa = malloc(offsetof(struct fid_array, fa_fids[nr + 1]));
9382         if (!fa)
9383                 return -ENOMEM;
9384
9385         fa->fa_nr = 0;
9386         rc = 0;
9387         while (optind < argc) {
9388                 int found;
9389
9390                 fidstr = argv[optind++];
9391                 while (*fidstr == '[')
9392                         fidstr++;
9393                 found = sscanf(fidstr, SFID, RFID(&fa->fa_fids[fa->fa_nr]));
9394                 if (found != 3) {
9395                         fprintf(stderr, "unrecognized FID: %s\n",
9396                                 argv[optind - 1]);
9397                         exit(1);
9398                 }
9399                 fa->fa_nr++;
9400                 if (fa->fa_nr == OBD_MAX_FIDS_IN_ARRAY) {
9401                         /* start another batch */
9402                         rc2 = lfs_rmfid_and_show_errors(device, fa);
9403                         if (rc2 && !rc)
9404                                 rc = rc2;
9405                         fa->fa_nr = 0;
9406                 }
9407         }
9408         if (fa->fa_nr) {
9409                 rc2 = lfs_rmfid_and_show_errors(device, fa);
9410                 if (rc2 && !rc)
9411                         rc = rc2;
9412         }
9413
9414         return rc;
9415 }
9416
9417 static int lfs_data_version(int argc, char **argv)
9418 {
9419         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
9420         __u64 data_version;
9421         char *path;
9422         int fd;
9423         int rc;
9424         int c;
9425
9426         if (argc < 2) {
9427                 fprintf(stderr, "%s: FILE must be specified\n",
9428                         progname);
9429                 return CMD_HELP;
9430         }
9431
9432         while ((c = getopt(argc, argv, "hnrw")) != -1) {
9433                 switch (c) {
9434                 case 'n':
9435                         data_version_flags = 0;
9436                         break;
9437                 case 'r':
9438                         data_version_flags |= LL_DV_RD_FLUSH;
9439                         break;
9440                 case 'w':
9441                         data_version_flags |= LL_DV_WR_FLUSH;
9442                         break;
9443                 default:
9444                         fprintf(stderr,
9445                                 "%s data_version: unrecognized option '%s'\n",
9446                                 progname, argv[optind - 1]);
9447                         /* fallthrough */
9448                 case 'h':
9449                         return CMD_HELP;
9450                 }
9451         }
9452         if (optind == argc) {
9453                 fprintf(stderr, "%s data_version: FILE must be specified\n",
9454                         progname);
9455                 return CMD_HELP;
9456         }
9457
9458         path = argv[optind];
9459         fd = open(path, O_RDONLY);
9460         if (fd < 0) {
9461                 rc = -errno;
9462                 fprintf(stderr, "%s data_version: cannot open file '%s': %s\n",
9463                         progname, path, strerror(-rc));
9464                 return rc;
9465         }
9466
9467         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
9468         if (rc < 0)
9469                 fprintf(stderr,
9470                         "%s data_version: cannot get version for '%s': %s\n",
9471                         progname, path, strerror(-rc));
9472         else
9473                 printf("%ju" "\n", (uintmax_t)data_version);
9474
9475         close(fd);
9476         return rc;
9477 }
9478
9479 static int lfs_hsm_state(int argc, char **argv)
9480 {
9481         int rc;
9482         int i = 1;
9483         char *path;
9484         struct hsm_user_state hus;
9485
9486         if (argc < 2)
9487                 return CMD_HELP;
9488
9489         do {
9490                 path = argv[i];
9491
9492                 rc = llapi_hsm_state_get(path, &hus);
9493                 if (rc) {
9494                         fprintf(stderr, "can't get hsm state for %s: %s\n",
9495                                 path, strerror(errno = -rc));
9496                         return rc;
9497                 }
9498
9499                 /* Display path name and status flags */
9500                 printf("%s: (0x%08x)", path, hus.hus_states);
9501
9502                 if (hus.hus_states & HS_RELEASED)
9503                         printf(" released");
9504                 if (hus.hus_states & HS_EXISTS)
9505                         printf(" exists");
9506                 if (hus.hus_states & HS_DIRTY)
9507                         printf(" dirty");
9508                 if (hus.hus_states & HS_ARCHIVED)
9509                         printf(" archived");
9510                 /* Display user-settable flags */
9511                 if (hus.hus_states & HS_NORELEASE)
9512                         printf(" never_release");
9513                 if (hus.hus_states & HS_NOARCHIVE)
9514                         printf(" never_archive");
9515                 if (hus.hus_states & HS_LOST)
9516                         printf(" lost_from_hsm");
9517
9518                 if (hus.hus_archive_id != 0)
9519                         printf(", archive_id:%d", hus.hus_archive_id);
9520                 printf("\n");
9521
9522         } while (++i < argc);
9523
9524         return 0;
9525 }
9526
9527 #define LFS_HSM_SET   0
9528 #define LFS_HSM_CLEAR 1
9529
9530 /**
9531  * Generic function to set or clear HSM flags.
9532  * Used by hsm_set and hsm_clear.
9533  *
9534  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
9535  */
9536 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
9537 {
9538         struct option long_opts[] = {
9539         { .val = 'A',   .name = "archived",     .has_arg = no_argument },
9540         { .val = 'a',   .name = "noarchive",    .has_arg = no_argument },
9541         { .val = 'd',   .name = "dirty",        .has_arg = no_argument },
9542         { .val = 'e',   .name = "exists",       .has_arg = no_argument },
9543         { .val = 'h',   .name = "help",         .has_arg = no_argument },
9544         { .val = 'i',   .name = "archive-id",   .has_arg = required_argument },
9545         { .val = 'l',   .name = "lost",         .has_arg = no_argument },
9546         { .val = 'r',   .name = "norelease",    .has_arg = no_argument },
9547         { .name = NULL } };
9548         __u64 mask = 0;
9549         int c, rc;
9550         char *path;
9551         __u32 archive_id = 0;
9552         char *end = NULL;
9553
9554         if (argc < 3)
9555                 return CMD_HELP;
9556
9557         while ((c = getopt_long(argc, argv, "aAdehi:lr",
9558                                 long_opts, NULL)) != -1) {
9559                 switch (c) {
9560                 case 'l':
9561                         mask |= HS_LOST;
9562                         break;
9563                 case 'a':
9564                         mask |= HS_NOARCHIVE;
9565                         break;
9566                 case 'A':
9567                         mask |= HS_ARCHIVED;
9568                         break;
9569                 case 'r':
9570                         mask |= HS_NORELEASE;
9571                         break;
9572                 case 'd':
9573                         mask |= HS_DIRTY;
9574                         break;
9575                 case 'e':
9576                         mask |= HS_EXISTS;
9577                         break;
9578                 case 'i':
9579                         errno = 0;
9580                         archive_id = strtol(optarg, &end, 10);
9581                         if (errno != 0 || *end != '\0' || archive_id < 0) {
9582                                 fprintf(stderr,
9583                                         "%s: invalid archive_id: '%s'\n",
9584                                         progname, end);
9585                                 return CMD_HELP;
9586                         }
9587                         break;
9588                 default:
9589                         fprintf(stderr, "%s: unrecognized option '%s'\n",
9590                                 progname, argv[optind - 1]);
9591                         /* fallthrough */
9592                 case 'h':
9593                         return CMD_HELP;
9594                 }
9595         }
9596
9597         /* User should have specified a flag */
9598         if (mask == 0)
9599                 return CMD_HELP;
9600
9601         while (optind < argc) {
9602                 path = argv[optind];
9603
9604                 /* If mode == 0, this means we apply the mask. */
9605                 if (mode == LFS_HSM_SET)
9606                         rc = llapi_hsm_state_set(path, mask, 0, archive_id);
9607                 else
9608                         rc = llapi_hsm_state_set(path, 0, mask, 0);
9609
9610                 if (rc != 0) {
9611                         fprintf(stderr, "Can't change hsm flags for %s: %s\n",
9612                                 path, strerror(errno = -rc));
9613                         return rc;
9614                 }
9615                 optind++;
9616         }
9617
9618         return 0;
9619 }
9620
9621 static int lfs_hsm_action(int argc, char **argv)
9622 {
9623         int                              rc;
9624         int                              i = 1;
9625         char                            *path;
9626         struct hsm_current_action        hca;
9627         struct hsm_extent                he;
9628         enum hsm_user_action             hua;
9629         enum hsm_progress_states         hps;
9630
9631         if (argc < 2)
9632                 return CMD_HELP;
9633
9634         do {
9635                 path = argv[i];
9636
9637                 rc = llapi_hsm_current_action(path, &hca);
9638                 if (rc) {
9639                         fprintf(stderr, "can't get hsm action for %s: %s\n",
9640                                 path, strerror(errno = -rc));
9641                         return rc;
9642                 }
9643                 he = hca.hca_location;
9644                 hua = hca.hca_action;
9645                 hps = hca.hca_state;
9646
9647                 printf("%s: %s", path, hsm_user_action2name(hua));
9648
9649                 /* Skip file without action */
9650                 if (hca.hca_action == HUA_NONE) {
9651                         printf("\n");
9652                         continue;
9653                 }
9654
9655                 printf(" %s ", hsm_progress_state2name(hps));
9656
9657                 if ((hps == HPS_RUNNING) &&
9658                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
9659                         printf("(%llu bytes moved)\n",
9660                                (unsigned long long)he.length);
9661                 else if ((he.offset + he.length) == LUSTRE_EOF)
9662                         printf("(from %llu to EOF)\n",
9663                                (unsigned long long)he.offset);
9664                 else
9665                         printf("(from %llu to %llu)\n",
9666                                (unsigned long long)he.offset,
9667                                (unsigned long long)(he.offset + he.length));
9668
9669         } while (++i < argc);
9670
9671         return 0;
9672 }
9673
9674 static int lfs_hsm_set(int argc, char **argv)
9675 {
9676         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
9677 }
9678
9679 static int lfs_hsm_clear(int argc, char **argv)
9680 {
9681         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
9682 }
9683
9684 /**
9685  * Check file state and return its fid, to be used by lfs_hsm_request().
9686  *
9687  * \param[in]     file      Path to file to check
9688  * \param[in,out] fid       Pointer to allocated lu_fid struct.
9689  * \param[in,out] last_dev  Pointer to last device id used.
9690  *
9691  * \return 0 on success.
9692  */
9693 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
9694                                 dev_t *last_dev)
9695 {
9696         struct stat     st;
9697         int             rc;
9698
9699         rc = lstat(file, &st);
9700         if (rc) {
9701                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
9702                 return -errno;
9703         }
9704         /*
9705          * Checking for regular file as archiving as posix copytool
9706          * rejects archiving files other than regular files
9707          */
9708         if (!S_ISREG(st.st_mode)) {
9709                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
9710                 return CMD_HELP;
9711         }
9712         /* A request should be ... */
9713         if (*last_dev != st.st_dev && *last_dev != 0) {
9714                 fprintf(stderr,
9715                         "All files should be on the same filesystem: %s\n",
9716                         file);
9717                 return -EINVAL;
9718         }
9719         *last_dev = st.st_dev;
9720
9721         rc = llapi_path2fid(file, fid);
9722         if (rc) {
9723                 fprintf(stderr, "Cannot read FID of %s: %s\n",
9724                         file, strerror(-rc));
9725                 return rc;
9726         }
9727         return 0;
9728 }
9729
9730 /* Fill an HSM HUR item with a given file name.
9731  *
9732  * If mntpath is set, then the filename is actually a FID, and no
9733  * lookup on the filesystem will be performed.
9734  *
9735  * \param[in]  hur         the user request to fill
9736  * \param[in]  idx         index of the item inside the HUR to fill
9737  * \param[in]  mntpath     mountpoint of Lustre
9738  * \param[in]  fname       filename (if mtnpath is NULL)
9739  *                         or FID (if mntpath is set)
9740  * \param[in]  last_dev    pointer to last device id used
9741  *
9742  * \retval 0 on success
9743  * \retval CMD_HELP or a negative errno on error
9744  */
9745 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
9746                          const char *mntpath, const char *fname,
9747                          dev_t *last_dev)
9748 {
9749         struct hsm_user_item *hui = &hur->hur_user_item[idx];
9750         int rc;
9751
9752         hui->hui_extent.length = -1;
9753
9754         if (mntpath) {
9755                 rc = llapi_fid_parse(fname, &hui->hui_fid, NULL);
9756                 if (rc)
9757                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
9758                                 fname);
9759         } else {
9760                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
9761         }
9762
9763         if (rc == 0)
9764                 hur->hur_request.hr_itemcount++;
9765
9766         return rc;
9767 }
9768
9769 static int lfs_hsm_request(int argc, char **argv, int action)
9770 {
9771         struct option long_opts[] = {
9772         { .val = 'a',   .name = "archive",      .has_arg = required_argument },
9773         { .val = 'D',   .name = "data",         .has_arg = required_argument },
9774         { .val = 'h',   .name = "help",         .has_arg = no_argument },
9775         { .val = 'l',   .name = "filelist",     .has_arg = required_argument },
9776         { .val = 'm',   .name = "mntpath",      .has_arg = required_argument },
9777         { .name = NULL } };
9778         dev_t last_dev = 0;
9779         struct hsm_user_request *hur, *oldhur;
9780         int c, i;
9781         size_t len;
9782         int nbfile;
9783         char *line = NULL;
9784         char *filelist = NULL;
9785         char fullpath[PATH_MAX];
9786         char *opaque = NULL;
9787         int opaque_len = 0;
9788         int archive_id = 0;
9789         FILE *fp;
9790         int nbfile_alloc = 0;
9791         char *some_file = NULL;
9792         char *mntpath = NULL;
9793         int rc;
9794
9795         if (argc < 2)
9796                 return CMD_HELP;
9797
9798         while ((c = getopt_long(argc, argv, "a:D:hl:m:",
9799                                 long_opts, NULL)) != -1) {
9800                 switch (c) {
9801                 case 'l':
9802                         filelist = optarg;
9803                         break;
9804                 case 'D':
9805                         opaque = optarg;
9806                         break;
9807                 case 'a':
9808                         if (action != HUA_ARCHIVE &&
9809                             action != HUA_REMOVE) {
9810                                 fprintf(stderr,
9811                                         "error: -a is supported only when archiving or removing\n");
9812                                 return CMD_HELP;
9813                         }
9814                         archive_id = atoi(optarg);
9815                         break;
9816                 case 'm':
9817                         if (!some_file) {
9818                                 mntpath = optarg;
9819                                 some_file = strdup(optarg);
9820                         }
9821                         break;
9822                 default:
9823                         fprintf(stderr, "%s: unrecognized option '%s'\n",
9824                                 progname, argv[optind - 1]);
9825                         /* fallthrough */
9826                 case 'h':
9827                         return CMD_HELP;
9828                 }
9829         }
9830
9831         /* All remaining args are files, so we have at least nbfile */
9832         nbfile = argc - optind;
9833
9834         if ((nbfile == 0) && (!filelist))
9835                 return CMD_HELP;
9836
9837         if (opaque)
9838                 opaque_len = strlen(opaque);
9839
9840         /*
9841          * Alloc the request structure with enough place to store all files
9842          * from command line.
9843          */
9844         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
9845         if (!hur) {
9846                 fprintf(stderr, "Cannot create the request: %s\n",
9847                         strerror(errno));
9848                 return errno;
9849         }
9850         nbfile_alloc = nbfile;
9851
9852         hur->hur_request.hr_action = action;
9853         hur->hur_request.hr_archive_id = archive_id;
9854         hur->hur_request.hr_flags = 0;
9855
9856         /* All remaining args are files, add them */
9857         if (nbfile != 0 && some_file == NULL)
9858                 some_file = strdup(argv[optind]);
9859
9860         for (i = 0; i < nbfile; i++) {
9861                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
9862                                    &last_dev);
9863                 if (rc)
9864                         goto out_free;
9865         }
9866
9867         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
9868
9869         /* If a filelist was specified, read the filelist from it. */
9870         if (filelist) {
9871                 fp = fopen(filelist, "r");
9872                 if (!fp) {
9873                         fprintf(stderr, "Cannot read the file list %s: %s\n",
9874                                 filelist, strerror(errno));
9875                         rc = -errno;
9876                         goto out_free;
9877                 }
9878
9879                 while ((rc = getline(&line, &len, fp)) != -1) {
9880                         /*
9881                          * If allocated buffer was too small, get something
9882                          * larger
9883                          */
9884                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
9885                                 ssize_t size;
9886
9887                                 nbfile_alloc = nbfile_alloc * 2 + 1;
9888                                 oldhur = hur;
9889                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
9890                                                                    opaque_len);
9891                                 if (!hur) {
9892                                         fprintf(stderr,
9893                                                 "hsm: cannot allocate the request: %s\n",
9894                                                 strerror(errno));
9895                                         hur = oldhur;
9896                                         rc = -errno;
9897                                         fclose(fp);
9898                                         goto out_free;
9899                                 }
9900                                 size = hur_len(oldhur);
9901                                 if (size < 0) {
9902                                         fprintf(stderr,
9903                                                 "hsm: cannot allocate %u files + %u bytes data\n",
9904                                                 oldhur->hur_request.hr_itemcount,
9905                                                 oldhur->hur_request.hr_data_len);
9906                                         free(hur);
9907                                         hur = oldhur;
9908                                         rc = -E2BIG;
9909                                         fclose(fp);
9910                                         goto out_free;
9911                                 }
9912                                 memcpy(hur, oldhur, size);
9913                                 free(oldhur);
9914                         }
9915
9916                         /* Chop CR */
9917                         if (line[strlen(line) - 1] == '\n')
9918                                 line[strlen(line) - 1] = '\0';
9919
9920                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
9921                                            mntpath, line, &last_dev);
9922                         if (rc) {
9923                                 fclose(fp);
9924                                 goto out_free;
9925                         }
9926
9927                         if (!some_file) {
9928                                 some_file = line;
9929                                 line = NULL;
9930                         }
9931                 }
9932
9933                 rc = fclose(fp);
9934                 free(line);
9935         }
9936
9937         /* If a --data was used, add it to the request */
9938         hur->hur_request.hr_data_len = opaque_len;
9939         if (opaque)
9940                 memcpy(hur_data(hur), opaque, opaque_len);
9941
9942         /* Send the HSM request */
9943         if (realpath(some_file, fullpath) == NULL) {
9944                 fprintf(stderr, "Could not find path '%s': %s\n",
9945                         some_file, strerror(errno));
9946         }
9947         rc = llapi_hsm_request(fullpath, hur);
9948         if (rc) {
9949                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
9950                         some_file, strerror(-rc));
9951                 goto out_free;
9952         }
9953
9954 out_free:
9955         free(some_file);
9956         free(hur);
9957         return rc;
9958 }
9959
9960 static int lfs_hsm_archive(int argc, char **argv)
9961 {
9962         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
9963 }
9964
9965 static int lfs_hsm_restore(int argc, char **argv)
9966 {
9967         return lfs_hsm_request(argc, argv, HUA_RESTORE);
9968 }
9969
9970 static int lfs_hsm_release(int argc, char **argv)
9971 {
9972         return lfs_hsm_request(argc, argv, HUA_RELEASE);
9973 }
9974
9975 static int lfs_hsm_remove(int argc, char **argv)
9976 {
9977         return lfs_hsm_request(argc, argv, HUA_REMOVE);
9978 }
9979
9980 static int lfs_hsm_cancel(int argc, char **argv)
9981 {
9982         return lfs_hsm_request(argc, argv, HUA_CANCEL);
9983 }
9984
9985 static int lfs_swap_layouts(int argc, char **argv)
9986 {
9987         if (argc != 3)
9988                 return CMD_HELP;
9989
9990         return llapi_swap_layouts(argv[1], argv[2], 0, 0,
9991                                   SWAP_LAYOUTS_KEEP_MTIME |
9992                                   SWAP_LAYOUTS_KEEP_ATIME);
9993 }
9994
9995 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
9996
9997 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
9998
9999 int lfs_get_mode(const char *string)
10000 {
10001         enum lock_mode_user mode;
10002
10003         for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
10004                 if (lock_mode_names[mode] == NULL)
10005                         continue;
10006                 if (strcasecmp(string, lock_mode_names[mode]) == 0)
10007                         return mode;
10008         }
10009
10010         return -EINVAL;
10011 }
10012
10013 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
10014 {
10015         enum lu_ladvise_type advice;
10016
10017         for (advice = 0;
10018              advice < ARRAY_SIZE(ladvise_names); advice++) {
10019                 if (ladvise_names[advice] == NULL)
10020                         continue;
10021                 if (strcmp(string, ladvise_names[advice]) == 0)
10022                         return advice;
10023         }
10024
10025         return LU_LADVISE_INVALID;
10026 }
10027
10028 static int lfs_ladvise(int argc, char **argv)
10029 {
10030         struct option long_opts[] = {
10031         { .val = 'a',   .name = "advice",       .has_arg = required_argument },
10032         { .val = 'b',   .name = "background",   .has_arg = no_argument },
10033         { .val = 'e',   .name = "end",          .has_arg = required_argument },
10034         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10035         { .val = 'l',   .name = "length",       .has_arg = required_argument },
10036         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
10037         { .val = 's',   .name = "start",        .has_arg = required_argument },
10038         { .val = 'u',   .name = "unset",        .has_arg = no_argument },
10039         { .name = NULL } };
10040         struct llapi_lu_ladvise advice;
10041         enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
10042         unsigned long long start = 0;
10043         unsigned long long end = LUSTRE_EOF;
10044         unsigned long long length = 0;
10045         unsigned long long size_units;
10046         unsigned long long flags = 0;
10047         int c, fd, rc = 0;
10048         const char *path;
10049         int mode = 0;
10050
10051         optind = 0;
10052         while ((c = getopt_long(argc, argv, "a:be:hl:m:s:u",
10053                                 long_opts, NULL)) != -1) {
10054                 switch (c) {
10055                 case 'a':
10056                         advice_type = lfs_get_ladvice(optarg);
10057                         if (advice_type == LU_LADVISE_INVALID) {
10058                                 fprintf(stderr,
10059                                         "%s: invalid advice type '%s'\n",
10060                                         progname, optarg);
10061                                 fprintf(stderr, "Valid types:");
10062
10063                                 for (advice_type = 0;
10064                                      advice_type < ARRAY_SIZE(ladvise_names);
10065                                      advice_type++) {
10066                                         if (ladvise_names[advice_type] == NULL)
10067                                                 continue;
10068                                         fprintf(stderr, " %s",
10069                                                 ladvise_names[advice_type]);
10070                                 }
10071                                 fprintf(stderr, "\n");
10072
10073                                 return CMD_HELP;
10074                         }
10075                         break;
10076                 case 'b':
10077                         flags |= LF_ASYNC;
10078                         break;
10079                 case 'u':
10080                         flags |= LF_UNSET;
10081                         break;
10082                 case 'e':
10083                         size_units = 1;
10084                         rc = llapi_parse_size(optarg, &end,
10085                                               &size_units, 0);
10086                         if (rc) {
10087                                 fprintf(stderr, "%s: bad end offset '%s'\n",
10088                                         argv[0], optarg);
10089                                 return CMD_HELP;
10090                         }
10091                         break;
10092                 case 's':
10093                         size_units = 1;
10094                         rc = llapi_parse_size(optarg, &start,
10095                                               &size_units, 0);
10096                         if (rc) {
10097                                 fprintf(stderr,
10098                                         "%s: bad start offset '%s'\n",
10099                                         argv[0], optarg);
10100                                 return CMD_HELP;
10101                         }
10102                         break;
10103                 case 'l':
10104                         size_units = 1;
10105                         rc = llapi_parse_size(optarg, &length,
10106                                               &size_units, 0);
10107                         if (rc) {
10108                                 fprintf(stderr, "%s: bad length '%s'\n",
10109                                         argv[0], optarg);
10110                                 return CMD_HELP;
10111                         }
10112                         break;
10113                 case 'm':
10114                         mode = lfs_get_mode(optarg);
10115                         if (mode < 0) {
10116                                 fprintf(stderr,
10117                                         "%s: bad mode '%s', valid modes are READ or WRITE\n",
10118                                         argv[0], optarg);
10119                                 return CMD_HELP;
10120                         }
10121                         break;
10122                 default:
10123                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10124                                 progname, argv[optind - 1]);
10125                         /* fallthrough */
10126                 case 'h':
10127                         return CMD_HELP;
10128                 }
10129         }
10130
10131         if (advice_type == LU_LADVISE_INVALID) {
10132                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
10133                 fprintf(stderr, "Valid types:");
10134                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
10135                      advice_type++) {
10136                         if (ladvise_names[advice_type] == NULL)
10137                                 continue;
10138                         fprintf(stderr, " %s", ladvise_names[advice_type]);
10139                 }
10140                 fprintf(stderr, "\n");
10141                 return CMD_HELP;
10142         }
10143
10144         if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
10145                 fprintf(stderr,
10146                         "%s: Lock no expand advice is a per file descriptor advice, so when called from lfs, it does nothing.\n",
10147                         argv[0]);
10148                 return CMD_HELP;
10149         }
10150
10151         if (argc <= optind) {
10152                 fprintf(stderr, "%s: please give one or more file names\n",
10153                         argv[0]);
10154                 return CMD_HELP;
10155         }
10156
10157         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
10158                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
10159                         argv[0]);
10160                 return CMD_HELP;
10161         }
10162
10163         if (end == LUSTRE_EOF && length != 0)
10164                 end = start + length;
10165
10166         if (end <= start) {
10167                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
10168                         argv[0], start, end);
10169                 return CMD_HELP;
10170         }
10171
10172         if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
10173                 fprintf(stderr, "%s: mode is only valid with lockahead\n",
10174                         argv[0]);
10175                 return CMD_HELP;
10176         }
10177
10178         if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
10179                 fprintf(stderr, "%s: mode is required with lockahead\n",
10180                         argv[0]);
10181                 return CMD_HELP;
10182         }
10183
10184         while (optind < argc) {
10185                 int rc2;
10186
10187                 path = argv[optind++];
10188
10189                 fd = open(path, O_RDONLY);
10190                 if (fd < 0) {
10191                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
10192                                 argv[0], path, strerror(errno));
10193                         rc2 = -errno;
10194                         goto next;
10195                 }
10196
10197                 advice.lla_start = start;
10198                 advice.lla_end = end;
10199                 advice.lla_advice = advice_type;
10200                 advice.lla_value1 = 0;
10201                 advice.lla_value2 = 0;
10202                 advice.lla_value3 = 0;
10203                 advice.lla_value4 = 0;
10204                 if (advice_type == LU_LADVISE_LOCKAHEAD) {
10205                         advice.lla_lockahead_mode = mode;
10206                         advice.lla_peradvice_flags = flags;
10207                 }
10208
10209                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
10210                 close(fd);
10211                 if (rc2 < 0) {
10212                         fprintf(stderr,
10213                                 "%s: cannot give advice '%s' to file '%s': %s\n",
10214                                 argv[0], ladvise_names[advice_type],
10215                                 path, strerror(errno));
10216
10217                         goto next;
10218                 }
10219
10220 next:
10221                 if (rc == 0 && rc2 < 0)
10222                         rc = rc2;
10223         }
10224         return rc;
10225 }
10226
10227 static const char *const heat_names[] = LU_HEAT_NAMES;
10228
10229 static int lfs_heat_get(int argc, char **argv)
10230 {
10231         struct lu_heat *heat;
10232         int rc = 0, rc2;
10233         char *path;
10234         int fd;
10235         int i;
10236
10237         if (argc <= 1)
10238                 return CMD_HELP;
10239
10240         heat = calloc(sizeof(*heat) + sizeof(__u64) * OBD_HEAT_COUNT, 1);
10241         if (!heat) {
10242                 fprintf(stderr, "%s: memory allocation failed\n", argv[0]);
10243                 return -ENOMEM;
10244         }
10245
10246         optind = 1;
10247         while (optind < argc) {
10248                 path = argv[optind++];
10249
10250                 fd = open(path, O_RDONLY);
10251                 if (fd < 0) {
10252                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
10253                                 argv[0], path, strerror(errno));
10254                         rc2 = -errno;
10255                         goto next;
10256                 }
10257
10258                 heat->lh_count = OBD_HEAT_COUNT;
10259                 rc2 = llapi_heat_get(fd, heat);
10260                 close(fd);
10261                 if (rc2 < 0) {
10262                         fprintf(stderr,
10263                                 "%s: cannot get heat of file '%s': %s\n",
10264                                 argv[0], path, strerror(errno));
10265                         goto next;
10266                 }
10267
10268                 printf("flags: %x\n", heat->lh_flags);
10269                 for (i = 0; i < heat->lh_count; i++)
10270                         printf("%s: %llu\n", heat_names[i],
10271                                (unsigned long long)heat->lh_heat[i]);
10272 next:
10273                 if (rc == 0 && rc2 < 0)
10274                         rc = rc2;
10275         }
10276
10277         free(heat);
10278         return rc;
10279 }
10280
10281 static int lfs_heat_set(int argc, char **argv)
10282 {
10283         struct option long_opts[] = {
10284         { .val = 'c',   .name = "clear",        .has_arg = no_argument },
10285         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10286         { .val = 'o',   .name = "off",          .has_arg = no_argument },
10287         { .val = 'O',   .name = "on",           .has_arg = no_argument },
10288         { .name = NULL } };
10289         enum lu_heat_flag flags = 0;
10290         int rc = 0, rc2;
10291         char *path;
10292         int fd;
10293         int c;
10294
10295         if (argc <= 1)
10296                 return CMD_HELP;
10297
10298         optind = 0;
10299         while ((c = getopt_long(argc, argv, "choO", long_opts, NULL)) != -1) {
10300                 switch (c) {
10301                 case 'c':
10302                         flags |= LU_HEAT_FLAG_CLEAR;
10303                         break;
10304                 case 'o':
10305                         flags |= LU_HEAT_FLAG_CLEAR;
10306                         flags |= LU_HEAT_FLAG_OFF;
10307                         break;
10308                 case 'O':
10309                         flags &= ~LU_HEAT_FLAG_OFF;
10310                         break;
10311                 default:
10312                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10313                                 progname, argv[optind - 1]);
10314                         /* fallthrough */
10315                 case 'h':
10316                         return CMD_HELP;
10317                 }
10318         }
10319
10320         if (argc <= optind) {
10321                 fprintf(stderr, "%s: please give one or more file names\n",
10322                         argv[0]);
10323                 return CMD_HELP;
10324         }
10325
10326         while (optind < argc) {
10327                 path = argv[optind++];
10328
10329                 fd = open(path, O_RDONLY);
10330                 if (fd < 0) {
10331                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
10332                                 argv[0], path, strerror(errno));
10333                         rc2 = -errno;
10334                         goto next;
10335                 }
10336
10337                 rc2 = llapi_heat_set(fd, flags);
10338                 close(fd);
10339                 if (rc2 < 0) {
10340                         fprintf(stderr,
10341                                 "%s: cannot setflags heat of file '%s': %s\n",
10342                                 argv[0], path, strerror(errno));
10343                         goto next;
10344                 }
10345 next:
10346                 if (rc == 0 && rc2 < 0)
10347                         rc = rc2;
10348         }
10349         return rc;
10350 }
10351
10352 /**
10353  * The input string contains a comma delimited list of component ids and
10354  * ranges, for example "1,2-4,7".
10355  */
10356 static int parse_mirror_ids(__u16 *ids, int size, char *arg)
10357 {
10358         bool end_of_loop = false;
10359         char *ptr = NULL;
10360         int nr = 0;
10361         int rc;
10362
10363         if (!arg)
10364                 return -EINVAL;
10365
10366         while (!end_of_loop) {
10367                 int start_index;
10368                 int end_index;
10369                 int i;
10370                 char *endptr = NULL;
10371
10372                 rc = -EINVAL;
10373                 ptr = strchrnul(arg, ',');
10374                 end_of_loop = *ptr == '\0';
10375                 *ptr = '\0';
10376
10377                 start_index = strtol(arg, &endptr, 0);
10378                 if (endptr == arg) /* no data at all */
10379                         break;
10380                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
10381                         break;
10382                 if (start_index < 0)
10383                         break;
10384
10385                 end_index = start_index;
10386                 if (*endptr == '-') {
10387                         end_index = strtol(endptr + 1, &endptr, 0);
10388                         if (*endptr != '\0')
10389                                 break;
10390                         if (end_index < start_index)
10391                                 break;
10392                 }
10393
10394                 for (i = start_index; i <= end_index && size > 0; i++) {
10395                         int j;
10396
10397                         /* remove duplicate */
10398                         for (j = 0; j < nr; j++) {
10399                                 if (ids[j] == i)
10400                                         break;
10401                         }
10402                         if (j == nr) { /* no duplicate */
10403                                 ids[nr++] = i;
10404                                 --size;
10405                         }
10406                 }
10407
10408                 if (size == 0 && i < end_index)
10409                         break;
10410
10411                 *ptr = ',';
10412                 arg = ++ptr;
10413                 rc = 0;
10414         }
10415         if (!end_of_loop && ptr)
10416                 *ptr = ',';
10417
10418         return rc < 0 ? rc : nr;
10419 }
10420
10421 /**
10422  * struct verify_mirror_id - Mirror id to be verified.
10423  * @mirror_id:   A specified mirror id.
10424  * @is_valid_id: @mirror_id is valid or not in the mirrored file.
10425  */
10426 struct verify_mirror_id {
10427         __u16 mirror_id;
10428         bool is_valid_id;
10429 };
10430
10431 /**
10432  * compare_mirror_ids() - Compare mirror ids.
10433  * @layout: Mirror component list.
10434  * @cbdata: Callback data in verify_mirror_id structure.
10435  *
10436  * This is a callback function called by llapi_layout_comp_iterate()
10437  * to compare the specified mirror id with the one in the current
10438  * component of @layout. If they are the same, then the specified
10439  * mirror id is valid.
10440  *
10441  * Return: a negative error code on failure or
10442  *         LLAPI_LAYOUT_ITER_CONT: Proceed iteration
10443  *         LLAPI_LAYOUT_ITER_STOP: Stop iteration
10444  */
10445 static inline
10446 int compare_mirror_ids(struct llapi_layout *layout, void *cbdata)
10447 {
10448         struct verify_mirror_id *mirror_id_cbdata =
10449                                  (struct verify_mirror_id *)cbdata;
10450         uint32_t mirror_id;
10451         int rc = 0;
10452
10453         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
10454         if (rc < 0) {
10455                 rc = -errno;
10456                 fprintf(stderr,
10457                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
10458                         progname, strerror(errno));
10459                 return rc;
10460         }
10461
10462         if (mirror_id_cbdata->mirror_id == mirror_id) {
10463                 mirror_id_cbdata->is_valid_id = true;
10464                 return LLAPI_LAYOUT_ITER_STOP;
10465         }
10466
10467         return LLAPI_LAYOUT_ITER_CONT;
10468 }
10469
10470 /**
10471  * verify_mirror_ids() - Verify specified mirror ids.
10472  * @fname:      Mirrored file name.
10473  * @mirror_ids: Specified mirror ids to be verified.
10474  * @ids_nr:     Number of specified mirror ids.
10475  *
10476  * This function verifies that specified @mirror_ids are valid
10477  * in the mirrored file @fname.
10478  *
10479  * Return: 0 on success or a negative error code on failure.
10480  */
10481 static inline
10482 int verify_mirror_ids(const char *fname, __u16 *mirror_ids, int ids_nr)
10483 {
10484         struct llapi_layout *layout = NULL;
10485         struct verify_mirror_id mirror_id_cbdata = { 0 };
10486         struct stat stbuf;
10487         uint32_t flr_state;
10488         int i;
10489         int fd;
10490         int rc = 0;
10491         int rc2 = 0;
10492
10493         if (ids_nr <= 0)
10494                 return -EINVAL;
10495
10496         if (stat(fname, &stbuf) < 0) {
10497                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
10498                         progname, fname, strerror(errno));
10499                 rc = -errno;
10500                 goto error;
10501         }
10502
10503         if (!S_ISREG(stbuf.st_mode)) {
10504                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
10505                         progname, fname);
10506                 rc = -EINVAL;
10507                 goto error;
10508         }
10509
10510         fd = open(fname, O_DIRECT | O_RDONLY);
10511         if (fd < 0) {
10512                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
10513                         progname, fname, strerror(errno));
10514                 rc = -errno;
10515                 goto error;
10516         }
10517
10518         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
10519         if (rc < 0) {
10520                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
10521                         progname, fname, strerror(errno));
10522                 goto close_fd;
10523         }
10524
10525         layout = llapi_layout_get_by_fd(fd, 0);
10526         if (!layout) {
10527                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
10528                         progname, fname, strerror(errno));
10529                 rc = -errno;
10530                 llapi_lease_release(fd);
10531                 goto close_fd;
10532         }
10533
10534         rc = llapi_layout_flags_get(layout, &flr_state);
10535         if (rc < 0) {
10536                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
10537                         progname, fname, strerror(errno));
10538                 rc = -errno;
10539                 goto free_layout;
10540         }
10541
10542         flr_state &= LCM_FL_FLR_MASK;
10543         switch (flr_state) {
10544         case LCM_FL_NONE:
10545                 rc = -EINVAL;
10546                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
10547                         progname, fname, llapi_layout_flags_string(flr_state));
10548                 goto free_layout;
10549         default:
10550                 break;
10551         }
10552
10553         rc2 = 0;
10554         for (i = 0; i < ids_nr; i++) {
10555                 mirror_id_cbdata.mirror_id = mirror_ids[i];
10556                 mirror_id_cbdata.is_valid_id = false;
10557
10558                 rc = llapi_layout_comp_iterate(layout, compare_mirror_ids,
10559                                                &mirror_id_cbdata);
10560                 if (rc < 0) {
10561                         rc = -errno;
10562                         fprintf(stderr,
10563                                 "%s: '%s' failed to verify mirror id: %u.\n",
10564                                 progname, fname, mirror_ids[i]);
10565                         goto free_layout;
10566                 }
10567
10568                 if (!mirror_id_cbdata.is_valid_id) {
10569                         rc2 = -EINVAL;
10570                         fprintf(stderr,
10571                                 "%s: '%s' invalid specified mirror id: %u.\n",
10572                                 progname, fname, mirror_ids[i]);
10573                 }
10574         }
10575         rc = rc2;
10576
10577 free_layout:
10578         llapi_layout_free(layout);
10579         llapi_lease_release(fd);
10580 close_fd:
10581         close(fd);
10582 error:
10583         return rc;
10584 }
10585
10586 static inline
10587 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
10588                            __u16 *mirror_ids, int ids_nr)
10589 {
10590         struct llapi_resync_comp comp_array[1024] = { { 0 } };
10591         struct llapi_layout *layout;
10592         struct stat stbuf;
10593         uint32_t flr_state;
10594         uint64_t start;
10595         uint64_t end;
10596         int comp_size = 0;
10597         int idx;
10598         int fd;
10599         int rc;
10600         int rc2;
10601
10602         if (stat(fname, &stbuf) < 0) {
10603                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
10604                         progname, fname, strerror(errno));
10605                 rc = -errno;
10606                 goto error;
10607         }
10608         if (!S_ISREG(stbuf.st_mode)) {
10609                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
10610                         progname, fname);
10611                 rc = -EINVAL;
10612                 goto error;
10613         }
10614
10615         fd = open(fname, O_DIRECT | O_RDWR);
10616         if (fd < 0) {
10617                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
10618                         progname, fname, strerror(errno));
10619                 rc = -errno;
10620                 goto error;
10621         }
10622
10623         layout = llapi_layout_get_by_fd(fd, 0);
10624         if (!layout) {
10625                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
10626                         progname, fname, strerror(errno));
10627                 rc = -errno;
10628                 goto close_fd;
10629         }
10630
10631         rc = llapi_layout_flags_get(layout, &flr_state);
10632         if (rc) {
10633                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
10634                         progname, fname, strerror(errno));
10635                 rc = -errno;
10636                 goto free_layout;
10637         }
10638
10639         flr_state &= LCM_FL_FLR_MASK;
10640         if (flr_state == LCM_FL_NONE) {
10641                 rc = -EINVAL;
10642                 fprintf(stderr, "%s: '%s' is not a FLR file.\n",
10643                         progname, fname);
10644                 goto free_layout;
10645         }
10646
10647         /* get stale component info */
10648         comp_size = llapi_mirror_find_stale(layout, comp_array,
10649                                             ARRAY_SIZE(comp_array),
10650                                             mirror_ids, ids_nr);
10651         if (comp_size <= 0) {
10652                 rc = comp_size;
10653                 goto free_layout;
10654         }
10655
10656         ioc->lil_mode = LL_LEASE_WRLCK;
10657         ioc->lil_flags = LL_LEASE_RESYNC;
10658         rc = llapi_lease_set(fd, ioc);
10659         if (rc < 0) {
10660                 if (rc == -EALREADY)
10661                         rc = 0;
10662                 else
10663                         fprintf(stderr,
10664                             "%s: '%s' llapi_lease_get_ext resync failed: %s.\n",
10665                                 progname, fname, strerror(-rc));
10666                 goto free_layout;
10667         }
10668
10669         /* get the read range [start, end) */
10670         start = comp_array[0].lrc_start;
10671         end = comp_array[0].lrc_end;
10672         for (idx = 1; idx < comp_size; idx++) {
10673                 if (comp_array[idx].lrc_start < start)
10674                         start = comp_array[idx].lrc_start;
10675                 if (end < comp_array[idx].lrc_end)
10676                         end = comp_array[idx].lrc_end;
10677         }
10678
10679         rc = llapi_lease_check(fd);
10680         if (rc != LL_LEASE_WRLCK) {
10681                 fprintf(stderr, "%s: '%s' lost lease lock.\n",
10682                         progname, fname);
10683                 goto free_layout;
10684         }
10685
10686         rc = llapi_mirror_resync_many(fd, layout, comp_array, comp_size,
10687                                       start, end);
10688         if (rc < 0)
10689                 fprintf(stderr, "%s: '%s' llapi_mirror_resync_many: %s.\n",
10690                         progname, fname, strerror(-rc));
10691
10692         rc = migrate_set_timestamps(fd, &stbuf);
10693         if (rc < 0) {
10694                 fprintf(stderr, "%s: '%s' cannot set timestamps: %s\n",
10695                         progname, fname, strerror(-rc));
10696                 goto free_layout;
10697         }
10698
10699         /* need to do the lease unlock even resync fails */
10700         ioc->lil_mode = LL_LEASE_UNLCK;
10701         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
10702         ioc->lil_count = 0;
10703         for (idx = 0; idx < comp_size; idx++) {
10704                 if (comp_array[idx].lrc_synced) {
10705                         ioc->lil_ids[ioc->lil_count] = comp_array[idx].lrc_id;
10706                         ioc->lil_count++;
10707                 }
10708         }
10709
10710         rc2 = llapi_lease_set(fd, ioc);
10711         /**
10712          * llapi_lease_set returns lease mode when it request to unlock
10713          * the lease lock.
10714          */
10715         if (rc2 <= 0) {
10716                 /* rc2 == 0 means lost lease lock */
10717                 if (rc2 == 0 && rc == 0)
10718                         rc = -EBUSY;
10719                 else
10720                         rc = rc2;
10721                 fprintf(stderr, "%s: resync file '%s' failed: %s.\n",
10722                         progname, fname,
10723                         rc2 == 0 ? "lost lease lock" : strerror(-rc2));
10724
10725                 llapi_lease_release(fd);
10726                 goto free_layout;
10727         }
10728
10729 free_layout:
10730         llapi_layout_free(layout);
10731 close_fd:
10732         close(fd);
10733 error:
10734         return rc;
10735 }
10736
10737 static inline int lfs_mirror_resync(int argc, char **argv)
10738 {
10739         struct option long_opts[] = {
10740         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10741         { .val = 'o',   .name = "only",         .has_arg = required_argument },
10742         { .name = NULL } };
10743         struct ll_ioc_lease *ioc = NULL;
10744         __u16 mirror_ids[128] = { 0 };
10745         int ids_nr = 0;
10746         int c;
10747         int rc = 0;
10748
10749         while ((c = getopt_long(argc, argv, "ho:", long_opts, NULL)) >= 0) {
10750                 switch (c) {
10751                 case 'o':
10752                         rc = parse_mirror_ids(mirror_ids,
10753                                         sizeof(mirror_ids) / sizeof(__u16),
10754                                         optarg);
10755                         if (rc < 0) {
10756                                 fprintf(stderr,
10757                                         "%s: bad mirror ids '%s'.\n",
10758                                         argv[0], optarg);
10759                                 goto error;
10760                         }
10761                         ids_nr = rc;
10762                         break;
10763                 default:
10764                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10765                                 progname, argv[optind - 1]);
10766                         /* fallthrough */
10767                 case 'h':
10768                         rc = CMD_HELP;
10769                         goto error;
10770                 }
10771         }
10772
10773         if (argc == optind) {
10774                 fprintf(stderr, "%s: no file name given.\n", argv[0]);
10775                 rc = CMD_HELP;
10776                 goto error;
10777         }
10778
10779         if (ids_nr > 0 && argc > optind + 1) {
10780                 fprintf(stderr,
10781                     "%s: option '--only' cannot be used upon multiple files.\n",
10782                         argv[0]);
10783                 rc = CMD_HELP;
10784                 goto error;
10785         }
10786
10787         if (ids_nr > 0) {
10788                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
10789                 if (rc < 0)
10790                         goto error;
10791         }
10792
10793         /* set the lease on the file */
10794         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
10795         if (!ioc) {
10796                 fprintf(stderr, "%s: cannot alloc id array for ioc: %s.\n",
10797                         argv[0], strerror(errno));
10798                 rc = -errno;
10799                 goto error;
10800         }
10801
10802         for (; optind < argc; optind++) {
10803                 rc = lfs_mirror_resync_file(argv[optind], ioc,
10804                                             mirror_ids, ids_nr);
10805                 /* ignore previous file's error, continue with next file */
10806
10807                 /* reset ioc */
10808                 memset(ioc, 0, sizeof(*ioc) + sizeof(__u32) * 4096);
10809         }
10810
10811         free(ioc);
10812 error:
10813         return rc;
10814 }
10815
10816 static inline int verify_mirror_id_by_fd(int fd, __u16 mirror_id)
10817 {
10818         struct llapi_layout *layout;
10819         int rc;
10820
10821         layout = llapi_layout_get_by_fd(fd, 0);
10822         if (!layout) {
10823                 fprintf(stderr, "could not get layout.\n");
10824                 return  -EINVAL;
10825         }
10826
10827         rc = llapi_layout_comp_iterate(layout, find_mirror_id, &mirror_id);
10828         if (rc < 0) {
10829                 fprintf(stderr, "failed to iterate layout\n");
10830                 llapi_layout_free(layout);
10831
10832                 return rc;
10833         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
10834                 fprintf(stderr, "does not find mirror with ID %u\n", mirror_id);
10835                 llapi_layout_free(layout);
10836
10837                 return -EINVAL;
10838         }
10839         llapi_layout_free(layout);
10840
10841         return 0;
10842 }
10843
10844 /**
10845  * Check whether two files are the same file
10846  * \retval      0  same file
10847  * \retval      1  not the same file
10848  * \retval      <0 error code
10849  */
10850 static inline int check_same_file(int fd, const char *f2)
10851 {
10852         struct stat stbuf1;
10853         struct stat stbuf2;
10854
10855         if (fstat(fd, &stbuf1) < 0)
10856                 return -errno;
10857
10858         if (stat(f2, &stbuf2) < 0)
10859                 return 1;
10860
10861         if (stbuf1.st_rdev == stbuf2.st_rdev &&
10862             stbuf1.st_ino == stbuf2.st_ino)
10863                 return 0;
10864
10865         return 1;
10866 }
10867
10868 static inline int lfs_mirror_read(int argc, char **argv)
10869 {
10870         int rc = CMD_HELP;
10871         __u16 mirror_id = 0;
10872         const char *outfile = NULL;
10873         char *fname;
10874         int fd = 0;
10875         int outfd;
10876         int c;
10877         void *buf;
10878         const size_t buflen = 4 << 20;
10879         off_t pos;
10880         struct option long_opts[] = {
10881         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10882         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
10883         { .val = 'o',   .name = "outfile",      .has_arg = required_argument },
10884         { .name = NULL } };
10885
10886         while ((c = getopt_long(argc, argv, "hN:o:", long_opts, NULL)) >= 0) {
10887                 char *end;
10888
10889                 switch (c) {
10890                 case 'N': {
10891                         unsigned long int id;
10892
10893                         errno = 0;
10894                         id = strtoul(optarg, &end, 0);
10895                         if (errno != 0 || *end != '\0' || id == 0 ||
10896                             id > UINT16_MAX) {
10897                                 fprintf(stderr,
10898                                         "%s %s: invalid mirror ID '%s'\n",
10899                                         progname, argv[0], optarg);
10900                                 return rc;
10901                         }
10902
10903                         mirror_id = (__u16)id;
10904                         break;
10905                 }
10906                 case 'o':
10907                         outfile = optarg;
10908                         break;
10909                 default:
10910                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10911                                 progname, argv[optind - 1]);
10912                         /* fallthrough */
10913                 case 'h':
10914                         return CMD_HELP;
10915                 }
10916         }
10917
10918         if (argc == optind) {
10919                 fprintf(stderr, "%s %s: no mirrored file provided\n",
10920                         progname, argv[0]);
10921                 return rc;
10922         } else if (argc > optind + 1) {
10923                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
10924                 return rc;
10925         }
10926
10927         if (mirror_id == 0) {
10928                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
10929                         progname, argv[0]);
10930                 return rc;
10931         }
10932
10933         /* open mirror file */
10934         fname = argv[optind];
10935         fd = open(fname, O_DIRECT | O_RDONLY);
10936         if (fd < 0) {
10937                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
10938                         progname, argv[0], fname, strerror(errno));
10939                 return rc;
10940         }
10941
10942         /* verify mirror id */
10943         rc = verify_mirror_id_by_fd(fd, mirror_id);
10944         if (rc) {
10945                 fprintf(stderr,
10946                         "%s %s: cannot find mirror with ID %u in '%s'\n",
10947                         progname, argv[0], mirror_id, fname);
10948                 goto close_fd;
10949         }
10950
10951         /* open output file - O_EXCL ensures output is not the same as input */
10952         if (outfile) {
10953                 outfd = open(outfile, O_EXCL | O_WRONLY | O_CREAT, 0644);
10954                 if (outfd < 0) {
10955                         fprintf(stderr, "%s %s: cannot create file '%s': %s\n",
10956                                 progname, argv[0], outfile, strerror(errno));
10957                         rc = -errno;
10958                         goto close_fd;
10959                 }
10960         } else {
10961                 outfd = STDOUT_FILENO;
10962         }
10963
10964         /* allocate buffer */
10965         rc = posix_memalign(&buf, sysconf(_SC_PAGESIZE), buflen);
10966         if (rc) {
10967                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
10968                                 progname, argv[0], rc);
10969                 goto close_outfd;
10970         }
10971
10972         pos = 0;
10973         while (1) {
10974                 ssize_t bytes_read;
10975                 ssize_t written = 0;
10976
10977                 bytes_read = llapi_mirror_read(fd, mirror_id, buf, buflen, pos);
10978                 if (bytes_read < 0) {
10979                         rc = bytes_read;
10980                         fprintf(stderr,
10981                                 "%s %s: fail to read data from mirror %u: %s\n",
10982                                 progname, argv[0], mirror_id, strerror(-rc));
10983                         goto free_buf;
10984                 }
10985
10986                 /* EOF reached */
10987                 if (bytes_read == 0)
10988                         break;
10989
10990                 while (written < bytes_read) {
10991                         ssize_t written2;
10992
10993                         written2 = write(outfd, buf + written,
10994                                          bytes_read - written);
10995                         if (written2 < 0) {
10996                                 fprintf(stderr,
10997                                         "%s %s: fail to write %s: %s\n",
10998                                         progname, argv[0], outfile ? : "STDOUT",
10999                                         strerror(errno));
11000                                 rc = -errno;
11001                                 goto free_buf;
11002                         }
11003                         written += written2;
11004                 }
11005
11006                 if (written != bytes_read) {
11007                         fprintf(stderr,
11008                 "%s %s: written %ld bytes does not match with %ld read.\n",
11009                                 progname, argv[0], written, bytes_read);
11010                         rc = -EIO;
11011                         goto free_buf;
11012                 }
11013
11014                 pos += bytes_read;
11015         }
11016
11017         fsync(outfd);
11018         rc = 0;
11019
11020 free_buf:
11021         free(buf);
11022 close_outfd:
11023         if (outfile)
11024                 close(outfd);
11025 close_fd:
11026         close(fd);
11027
11028         return rc;
11029 }
11030
11031 static inline int lfs_mirror_write(int argc, char **argv)
11032 {
11033         int rc = CMD_HELP;
11034         __u16 mirror_id = 0;
11035         const char *inputfile = NULL;
11036         char *fname;
11037         int fd = 0;
11038         int inputfd;
11039         int c;
11040         void *buf;
11041         const size_t buflen = 4 << 20;
11042         off_t pos;
11043         size_t page_size = sysconf(_SC_PAGESIZE);
11044         struct ll_ioc_lease_id ioc;
11045         struct option long_opts[] = {
11046         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11047         { .val = 'i',   .name = "inputfile",    .has_arg = required_argument },
11048         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
11049         { .name = NULL } };
11050
11051         while ((c = getopt_long(argc, argv, "hi:N:", long_opts, NULL)) >= 0) {
11052                 char *end;
11053
11054                 switch (c) {
11055                 case 'N': {
11056                         unsigned long int id;
11057
11058                         errno = 0;
11059                         id = strtoul(optarg, &end, 0);
11060                         if (errno != 0 || *end != '\0' || id == 0 ||
11061                             id > UINT16_MAX) {
11062                                 fprintf(stderr,
11063                                         "%s %s: invalid mirror ID '%s'\n",
11064                                         progname, argv[0], optarg);
11065                                 return rc;
11066                         }
11067
11068                         mirror_id = (__u16)id;
11069                         break;
11070                 }
11071                 case 'i':
11072                         inputfile = optarg;
11073                         break;
11074                 default:
11075                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11076                                 progname, argv[optind - 1]);
11077                         /* fallthrough */
11078                 case 'h':
11079                         return CMD_HELP;
11080                 }
11081         }
11082
11083         if (argc == optind) {
11084                 fprintf(stderr, "%s %s: no mirrored file provided\n",
11085                         progname, argv[0]);
11086                 return rc;
11087         } else if (argc > optind + 1) {
11088                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
11089                 return rc;
11090         }
11091
11092         if (mirror_id == 0) {
11093                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
11094                         progname, argv[0]);
11095                 return rc;
11096         }
11097
11098         /* open mirror file */
11099         fname = argv[optind];
11100         fd = open(fname, O_DIRECT | O_WRONLY);
11101         if (fd < 0) {
11102                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
11103                         progname, argv[0], fname, strerror(errno));
11104                 return rc;
11105         }
11106
11107         /* verify mirror id */
11108         rc = verify_mirror_id_by_fd(fd, mirror_id);
11109         if (rc) {
11110                 fprintf(stderr,
11111                         "%s %s: cannot find mirror with ID %u in '%s'\n",
11112                         progname, argv[0], mirror_id, fname);
11113                 goto close_fd;
11114         }
11115
11116         /* open input file */
11117         if (inputfile) {
11118                 rc = check_same_file(fd, inputfile);
11119                 if (rc == 0) {
11120                         fprintf(stderr,
11121                         "%s %s: input file cannot be the mirrored file\n",
11122                                 progname, argv[0]);
11123                         goto close_fd;
11124                 }
11125                 if (rc < 0)
11126                         goto close_fd;
11127
11128                 inputfd = open(inputfile, O_RDONLY, 0644);
11129                 if (inputfd < 0) {
11130                         fprintf(stderr, "%s %s: cannot open file '%s': %s\n",
11131                                 progname, argv[0], inputfile, strerror(errno));
11132                         rc = -errno;
11133                         goto close_fd;
11134                 }
11135         } else {
11136                 inputfd = STDIN_FILENO;
11137         }
11138
11139         /* allocate buffer */
11140         rc = posix_memalign(&buf, page_size, buflen);
11141         if (rc) {
11142                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
11143                         progname, argv[0], rc);
11144                 goto close_inputfd;
11145         }
11146
11147         /* prepare target mirror components instantiation */
11148         ioc.lil_mode = LL_LEASE_WRLCK;
11149         ioc.lil_flags = LL_LEASE_RESYNC;
11150         ioc.lil_mirror_id = mirror_id;
11151         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
11152         if (rc < 0) {
11153                 fprintf(stderr,
11154                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
11155                         progname, argv[0], fname, strerror(errno));
11156                 goto free_buf;
11157         }
11158
11159         pos = 0;
11160         while (1) {
11161                 ssize_t bytes_read;
11162                 ssize_t written;
11163                 size_t to_write;
11164
11165                 rc = llapi_lease_check(fd);
11166                 if (rc != LL_LEASE_WRLCK) {
11167                         fprintf(stderr, "%s %s: '%s' lost lease lock\n",
11168                                 progname, argv[0], fname);
11169                         goto free_buf;
11170                 }
11171
11172                 bytes_read = read(inputfd, buf, buflen);
11173                 if (bytes_read < 0) {
11174                         rc = bytes_read;
11175                         fprintf(stderr,
11176                                 "%s %s: fail to read data from '%s': %s\n",
11177                                 progname, argv[0], inputfile ? : "STDIN",
11178                                 strerror(errno));
11179                         rc = -errno;
11180                         goto free_buf;
11181                 }
11182
11183                 /* EOF reached */
11184                 if (bytes_read == 0)
11185                         break;
11186
11187                 /* round up to page align to make direct IO happy. */
11188                 to_write = (bytes_read + page_size - 1) & ~(page_size - 1);
11189
11190                 written = llapi_mirror_write(fd, mirror_id, buf, to_write,
11191                                              pos);
11192                 if (written < 0) {
11193                         rc = written;
11194                         fprintf(stderr,
11195                               "%s %s: fail to write to mirror %u: %s\n",
11196                                 progname, argv[0], mirror_id,
11197                                 strerror(-rc));
11198                         goto free_buf;
11199                 }
11200
11201                 pos += bytes_read;
11202         }
11203
11204         if (pos & (page_size - 1)) {
11205                 rc = llapi_mirror_truncate(fd, mirror_id, pos);
11206                 if (rc < 0)
11207                         goto free_buf;
11208         }
11209
11210         ioc.lil_mode = LL_LEASE_UNLCK;
11211         ioc.lil_flags = LL_LEASE_RESYNC_DONE;
11212         ioc.lil_count = 0;
11213         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
11214         if (rc <= 0) {
11215                 if (rc == 0)
11216                         rc = -EBUSY;
11217                 fprintf(stderr,
11218                         "%s %s: release lease lock of '%s' failed: %s\n",
11219                         progname, argv[0], fname, strerror(errno));
11220                 goto free_buf;
11221         }
11222
11223         rc = 0;
11224
11225 free_buf:
11226         free(buf);
11227 close_inputfd:
11228         if (inputfile)
11229                 close(inputfd);
11230 close_fd:
11231         close(fd);
11232
11233         return rc;
11234 }
11235
11236 static inline int get_other_mirror_ids(int fd, __u16 *ids, __u16 exclude_id)
11237 {
11238         struct llapi_layout *layout;
11239         struct collect_ids_data cid = { .cid_ids = ids,
11240                                         .cid_count = 0,
11241                                         .cid_exclude = exclude_id, };
11242         int rc;
11243
11244         layout = llapi_layout_get_by_fd(fd, 0);
11245         if (!layout) {
11246                 fprintf(stderr, "could not get layout\n");
11247                 return -EINVAL;
11248         }
11249
11250         rc = llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
11251         if (rc < 0) {
11252                 fprintf(stderr, "failed to iterate layout\n");
11253                 llapi_layout_free(layout);
11254
11255                 return rc;
11256         }
11257         llapi_layout_free(layout);
11258
11259         return cid.cid_count;
11260 }
11261
11262 #ifndef MIRROR_ID_NEG
11263 #define MIRROR_ID_NEG         0x8000
11264 #endif
11265
11266 static inline int lfs_mirror_copy(int argc, char **argv)
11267 {
11268         int rc = CMD_HELP;
11269         __u16 read_mirror_id = 0;
11270         __u16 ids[128] = { 0 };
11271         int count = 0;
11272         struct llapi_layout *layout = NULL;
11273         struct llapi_resync_comp comp_array[1024] = { { 0 } };
11274         int comp_size = 0;
11275         char *fname;
11276         int fd = 0;
11277         int c;
11278         int i;
11279         ssize_t copied;
11280         struct ll_ioc_lease *ioc = NULL;
11281         struct ll_ioc_lease_id *resync_ioc;
11282         struct option long_opts[] = {
11283         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11284         { .val = 'i',   .name = "read-mirror",  .has_arg = required_argument },
11285         { .val = 'o',   .name = "write-mirror", .has_arg = required_argument },
11286         { .name = NULL } };
11287         char cmd[PATH_MAX];
11288
11289         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
11290         progname = cmd;
11291         while ((c = getopt_long(argc, argv, "hi:o:", long_opts, NULL)) >= 0) {
11292                 char *end;
11293
11294                 switch (c) {
11295                 case 'i': {
11296                         unsigned long int id;
11297
11298                         errno = 0;
11299                         id = strtoul(optarg, &end, 0);
11300                         if (errno != 0 || *end != '\0' || id == 0 ||
11301                             id > UINT16_MAX) {
11302                                 fprintf(stderr,
11303                                         "%s: invalid read mirror ID '%s'\n",
11304                                         progname, optarg);
11305                                 return rc;
11306                         }
11307
11308                         read_mirror_id = (__u16)id;
11309                         break;
11310                 }
11311                 case 'o':
11312                         if (!strcmp(optarg, "-1")) {
11313                                 /* specify all other mirrors */
11314                                 ids[0] = (__u16)-1;
11315                                 count = 1;
11316                         } else {
11317                                 count = parse_mirror_ids((__u16 *)ids,
11318                                                          ARRAY_SIZE(ids),
11319                                                          optarg);
11320                                 if (count < 0)
11321                                         return rc;
11322                         }
11323                         break;
11324                 default:
11325                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11326                                 progname, argv[optind - 1]);
11327                         /* fallthrough */
11328                 case 'h':
11329                         return CMD_HELP;
11330                 }
11331         }
11332
11333         if (argc == optind) {
11334                 fprintf(stderr, "%s %s: no mirrored file provided\n",
11335                         progname, argv[0]);
11336                 return rc;
11337         } else if (argc > optind + 1) {
11338                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
11339                 return rc;
11340         }
11341
11342         if (read_mirror_id == 0) {
11343                 fprintf(stderr,
11344                         "%s %s: no valid read mirror ID %d is provided\n",
11345                         progname, argv[0], read_mirror_id);
11346                 return rc;
11347         }
11348
11349         if (count == 0) {
11350                 fprintf(stderr,
11351                         "%s %s: no write mirror ID is provided\n",
11352                         progname, argv[0]);
11353                 return rc;
11354         }
11355
11356         for (i = 0; i < count; i++) {
11357                 if (read_mirror_id == ids[i]) {
11358                         fprintf(stderr,
11359                         "%s %s: read and write mirror ID cannot be the same\n",
11360                                 progname, argv[0]);
11361                         return rc;
11362                 }
11363         }
11364
11365         /* open mirror file */
11366         fname = argv[optind];
11367
11368         fd = open(fname, O_DIRECT | O_RDWR);
11369         if (fd < 0) {
11370                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
11371                         progname, argv[0], fname, strerror(errno));
11372                 return rc;
11373         }
11374
11375         /* write to all other mirrors */
11376         if (ids[0] == (__u16)-1) {
11377                 count = get_other_mirror_ids(fd, ids, read_mirror_id);
11378                 if (count <= 0) {
11379                         rc = count;
11380                         fprintf(stderr,
11381                         "%s %s: failed to get other mirror ids in '%s': %d\n",
11382                                 progname, argv[0], fname, rc);
11383                         goto close_fd;
11384                 }
11385         }
11386
11387         /* verify mirror id */
11388         rc = verify_mirror_id_by_fd(fd, read_mirror_id);
11389         if (rc) {
11390                 fprintf(stderr,
11391                         "%s %s: cannot find mirror with ID %u in '%s'\n",
11392                         progname, argv[0], read_mirror_id, fname);
11393                 goto close_fd;
11394         }
11395
11396         for (i = 0; i < count; i++) {
11397                 rc = verify_mirror_id_by_fd(fd, ids[i]);
11398                 if (rc) {
11399                         fprintf(stderr,
11400                         "%s %s: cannot find mirror with ID %u in '%s'\n",
11401                                 progname, argv[0], ids[i], fname);
11402                         goto close_fd;
11403                 }
11404         }
11405
11406         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
11407         if (!ioc) {
11408                 fprintf(stderr,
11409                         "%s %s: cannot alloc comp id array for ioc: %s\n",
11410                         progname, argv[0], strerror(errno));
11411                 rc = -errno;
11412                 goto close_fd;
11413         }
11414
11415         /* get stale component info */
11416         layout = llapi_layout_get_by_fd(fd, 0);
11417         if (!layout) {
11418                 fprintf(stderr, "%s %s: failed to get layout of '%s': %s\n",
11419                         progname, argv[0], fname, strerror(errno));
11420                 rc = -errno;
11421                 goto free_ioc;
11422         }
11423         comp_size = llapi_mirror_find_stale(layout, comp_array,
11424                                             ARRAY_SIZE(comp_array),
11425                                             ids, count);
11426         llapi_layout_free(layout);
11427         if (comp_size < 0) {
11428                 rc = comp_size;
11429                 goto free_ioc;
11430         }
11431
11432         /* prepare target mirror components instantiation */
11433         resync_ioc = (struct ll_ioc_lease_id *)ioc;
11434         resync_ioc->lil_mode = LL_LEASE_WRLCK;
11435         resync_ioc->lil_flags = LL_LEASE_RESYNC;
11436         if (count == 1)
11437                 resync_ioc->lil_mirror_id = ids[0];
11438         else
11439                 resync_ioc->lil_mirror_id = read_mirror_id | MIRROR_ID_NEG;
11440         rc = llapi_lease_set(fd, ioc);
11441         if (rc < 0) {
11442                 fprintf(stderr,
11443                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
11444                         progname, argv[0], fname, strerror(errno));
11445                 goto free_ioc;
11446         }
11447
11448         copied = llapi_mirror_copy_many(fd, read_mirror_id, ids, count);
11449         if (copied < 0) {
11450                 rc = copied;
11451                 fprintf(stderr, "%s %s: copy error: %d\n",
11452                         progname, argv[0], rc);
11453                 goto free_ioc;
11454         }
11455
11456         fprintf(stdout, "mirror copied successfully: ");
11457         for (i = 0; i < copied; i++)
11458                 fprintf(stdout, "%d ", ids[i]);
11459         fprintf(stdout, "\n");
11460
11461         ioc->lil_mode = LL_LEASE_UNLCK;
11462         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
11463         ioc->lil_count = 0;
11464         for (i = 0; i < comp_size; i++) {
11465                 int j;
11466
11467                 for (j = 0; j < copied; j++) {
11468                         if (comp_array[i].lrc_mirror_id != ids[j])
11469                                 continue;
11470
11471                         ioc->lil_ids[ioc->lil_count] = comp_array[i].lrc_id;
11472                         ioc->lil_count++;
11473                 }
11474         }
11475         rc = llapi_lease_set(fd, ioc);
11476         if (rc <= 0) {
11477                 if (rc == 0)
11478                         rc = -EBUSY;
11479                 fprintf(stderr,
11480                         "%s %s: release lease lock of '%s' failed: %s\n",
11481                         progname, argv[0], fname, strerror(errno));
11482                 goto free_ioc;
11483         }
11484
11485         rc = 0;
11486
11487 free_ioc:
11488         free(ioc);
11489 close_fd:
11490         close(fd);
11491
11492         return rc;
11493 }
11494
11495 /**
11496  * struct verify_chunk - Mirror chunk to be verified.
11497  * @chunk:        [start, end) of the chunk.
11498  * @mirror_count: Number of mirror ids in @mirror_id array.
11499  * @mirror_id:    Array of valid mirror ids that cover the chunk.
11500  */
11501 struct verify_chunk {
11502         struct lu_extent chunk;
11503         unsigned int mirror_count;
11504         __u16 mirror_id[LUSTRE_MIRROR_COUNT_MAX];
11505 };
11506
11507 /**
11508  * print_chunks() - Print chunk information.
11509  * @fname:       Mirrored file name.
11510  * @chunks:      Array of chunks.
11511  * @chunk_count: Number of chunks in @chunks array.
11512  *
11513  * This function prints [start, end) of each chunk in @chunks
11514  * for mirrored file @fname, and also prints the valid mirror ids
11515  * that cover the chunk.
11516  *
11517  * Return: void.
11518  */
11519 static inline
11520 void print_chunks(const char *fname, struct verify_chunk *chunks,
11521                   int chunk_count)
11522 {
11523         int i;
11524         int j;
11525
11526         fprintf(stdout, "Chunks to be verified in %s:\n", fname);
11527         for (i = 0; i < chunk_count; i++) {
11528                 fprintf(stdout, DEXT, PEXT(&chunks[i].chunk));
11529
11530                 if (chunks[i].mirror_count == 0)
11531                         fprintf(stdout, "\t[");
11532                 else {
11533                         fprintf(stdout, "\t[%u", chunks[i].mirror_id[0]);
11534                         for (j = 1; j < chunks[i].mirror_count; j++)
11535                                 fprintf(stdout, ", %u", chunks[i].mirror_id[j]);
11536                 }
11537                 fprintf(stdout, "]\t%u\n", chunks[i].mirror_count);
11538         }
11539         fprintf(stdout, "\n");
11540 }
11541
11542 /**
11543  * print_checksums() - Print CRC-32 checksum values.
11544  * @chunk: A chunk and its corresponding valid mirror ids.
11545  * @crc:   CRC-32 checksum values on the chunk for each valid mirror.
11546  *
11547  * This function prints CRC-32 checksum values on @chunk for
11548  * each valid mirror that covers it.
11549  *
11550  * Return: void.
11551  */
11552 static inline
11553 void print_checksums(struct verify_chunk *chunk, unsigned long *crc)
11554 {
11555         int i;
11556
11557         fprintf(stdout,
11558                 "CRC-32 checksum value for chunk "DEXT":\n",
11559                 PEXT(&chunk->chunk));
11560         for (i = 0; i < chunk->mirror_count; i++)
11561                 fprintf(stdout, "Mirror %u:\t%#lx\n",
11562                         chunk->mirror_id[i], crc[i]);
11563         fprintf(stdout, "\n");
11564 }
11565
11566 /**
11567  * filter_mirror_id() - Filter specified mirror ids.
11568  * @chunks:      Array of chunks.
11569  * @chunk_count: Number of chunks in @chunks array.
11570  * @mirror_ids:  Specified mirror ids to be verified.
11571  * @ids_nr:      Number of specified mirror ids.
11572  *
11573  * This function scans valid mirror ids that cover each chunk in @chunks
11574  * and filters specified mirror ids.
11575  *
11576  * Return: void.
11577  */
11578 static inline
11579 void filter_mirror_id(struct verify_chunk *chunks, int chunk_count,
11580                       __u16 *mirror_ids, int ids_nr)
11581 {
11582         int i;
11583         int j;
11584         int k;
11585         __u16 valid_id[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
11586         unsigned int valid_count = 0;
11587
11588         for (i = 0; i < chunk_count; i++) {
11589                 if (chunks[i].mirror_count == 0)
11590                         continue;
11591
11592                 valid_count = 0;
11593                 for (j = 0; j < ids_nr; j++) {
11594                         for (k = 0; k < chunks[i].mirror_count; k++) {
11595                                 if (chunks[i].mirror_id[k] == mirror_ids[j]) {
11596                                         valid_id[valid_count] = mirror_ids[j];
11597                                         valid_count++;
11598                                         break;
11599                                 }
11600                         }
11601                 }
11602
11603                 memcpy(chunks[i].mirror_id, valid_id,
11604                        sizeof(__u16) * valid_count);
11605                 chunks[i].mirror_count = valid_count;
11606         }
11607 }
11608
11609 /**
11610  * lfs_mirror_prepare_chunk() - Find mirror chunks to be verified.
11611  * @layout:      Mirror component list.
11612  * @chunks:      Array of chunks.
11613  * @chunks_size: Array size of @chunks.
11614  *
11615  * This function scans the components in @layout from offset 0 to LUSTRE_EOF
11616  * to find out chunk segments and store them in @chunks array.
11617  *
11618  * The @mirror_id array in each element of @chunks will store the valid
11619  * mirror ids that cover the chunk. If a mirror component covering the
11620  * chunk has LCME_FL_STALE or LCME_FL_OFFLINE flag, then the mirror id
11621  * will not be stored into the @mirror_id array, and the chunk for that
11622  * mirror will not be verified.
11623  *
11624  * The @mirror_count in each element of @chunks will store the number of
11625  * mirror ids in @mirror_id array. If @mirror_count is 0, it indicates the
11626  * chunk is invalid in all of the mirrors. And if @mirror_count is 1, it
11627  * indicates the chunk is valid in only one mirror. In both cases, the
11628  * chunk will not be verified.
11629  *
11630  * Here is an example:
11631  *
11632  *  0      1M     2M     3M     4M           EOF
11633  *  +------+-------------+--------------------+
11634  *  |      |             |      S             |       mirror1
11635  *  +------+------+------+------+-------------+
11636  *  |             |   S  |   S  |             |       mirror2
11637  *  +-------------+------+------+-------------+
11638  *
11639  * prepared @chunks array will contain 5 elements:
11640  * (([0, 1M), [1, 2], 2),
11641  *  ([1M, 2M), [1, 2], 2),
11642  *  ([2M, 3M), [1], 1),
11643  *  ([3M, 4M], [], 0),
11644  *  ([4M, EOF), [2], 1))
11645  *
11646  * Return: the actual array size of @chunks on success
11647  *         or a negative error code on failure.
11648  */
11649 static inline
11650 int lfs_mirror_prepare_chunk(struct llapi_layout *layout,
11651                              struct verify_chunk *chunks,
11652                              size_t chunks_size)
11653 {
11654         uint64_t start;
11655         uint64_t end;
11656         uint32_t mirror_id;
11657         uint32_t flags;
11658         int idx = 0;
11659         int i = 0;
11660         int rc = 0;
11661
11662         memset(chunks, 0, sizeof(*chunks) * chunks_size);
11663
11664         while (1) {
11665                 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
11666                 if (rc < 0) {
11667                         fprintf(stderr,
11668                                 "%s: move to the first layout component: %s.\n",
11669                                 progname, strerror(errno));
11670                         goto error;
11671                 }
11672
11673                 i = 0;
11674                 rc = 0;
11675                 chunks[idx].chunk.e_end = LUSTRE_EOF;
11676                 while (rc == 0) {
11677                         rc = llapi_layout_comp_extent_get(layout, &start, &end);
11678                         if (rc < 0) {
11679                                 fprintf(stderr,
11680                                         "%s: llapi_layout_comp_extent_get failed: %s.\n",
11681                                         progname, strerror(errno));
11682                                 goto error;
11683                         }
11684
11685                         if (start > chunks[idx].chunk.e_start ||
11686                             end <= chunks[idx].chunk.e_start)
11687                                 goto next;
11688
11689                         if (end < chunks[idx].chunk.e_end)
11690                                 chunks[idx].chunk.e_end = end;
11691
11692                         rc = llapi_layout_comp_flags_get(layout, &flags);
11693                         if (rc < 0) {
11694                                 fprintf(stderr,
11695                                         "%s: llapi_layout_comp_flags_get failed: %s.\n",
11696                                         progname, strerror(errno));
11697                                 goto error;
11698                         }
11699
11700                         if (flags & LCME_FL_STALE || flags & LCME_FL_OFFLINE)
11701                                 goto next;
11702
11703                         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
11704                         if (rc < 0) {
11705                                 fprintf(stderr,
11706                                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
11707                                         progname, strerror(errno));
11708                                 goto error;
11709                         }
11710
11711                         chunks[idx].mirror_id[i] = mirror_id;
11712                         i++;
11713                         if (i >= ARRAY_SIZE(chunks[idx].mirror_id)) {
11714                                 fprintf(stderr,
11715                                         "%s: mirror_id array is too small.\n",
11716                                         progname);
11717                                 rc = -EINVAL;
11718                                 goto error;
11719                         }
11720
11721 next:
11722                         rc = llapi_layout_comp_use(layout,
11723                                                    LLAPI_LAYOUT_COMP_USE_NEXT);
11724                         if (rc < 0) {
11725                                 fprintf(stderr,
11726                                         "%s: move to the next layout component: %s.\n",
11727                                         progname, strerror(errno));
11728                                 goto error;
11729                         }
11730                 } /* loop through all components */
11731
11732                 chunks[idx].mirror_count = i;
11733
11734                 if (chunks[idx].chunk.e_end == LUSTRE_EOF)
11735                         break;
11736
11737                 idx++;
11738                 if (idx >= chunks_size) {
11739                         fprintf(stderr, "%s: chunks array is too small.\n",
11740                                 progname);
11741                         rc = -EINVAL;
11742                         goto error;
11743                 }
11744
11745                 chunks[idx].chunk.e_start = chunks[idx - 1].chunk.e_end;
11746         }
11747
11748 error:
11749         return rc < 0 ? rc : idx + 1;
11750 }
11751
11752 /**
11753  * lfs_mirror_verify_chunk() - Verify a chunk.
11754  * @fd:        File descriptor of the mirrored file.
11755  * @file_size: Size of the mirrored file.
11756  * @chunk:     A chunk and its corresponding valid mirror ids.
11757  * @verbose:   Verbose mode.
11758  *
11759  * This function verifies a @chunk contains exactly the same data
11760  * ammong the mirrors that cover it.
11761  *
11762  * If @verbose is specified, then the function will print where the
11763  * differences are if the data do not match. Otherwise, it will
11764  * just return an error in that case.
11765  *
11766  * Return: 0 on success or a negative error code on failure.
11767  */
11768 static inline
11769 int lfs_mirror_verify_chunk(int fd, size_t file_size,
11770                             struct verify_chunk *chunk, int verbose)
11771 {
11772         const size_t buflen = 4 * 1024 * 1024; /* 4M */
11773         void *buf;
11774         size_t page_size = sysconf(_SC_PAGESIZE);
11775         ssize_t bytes_read;
11776         ssize_t bytes_done;
11777         size_t count;
11778         off_t pos;
11779         unsigned long crc;
11780         unsigned long crc_array[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
11781         int i;
11782         int rc = 0;
11783
11784         if (file_size == 0)
11785                 return 0;
11786
11787         rc = posix_memalign(&buf, page_size, buflen);
11788         if (rc) /* error code is returned directly */
11789                 return -rc;
11790
11791         if (verbose > 1) {
11792                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
11793                         PEXT(&chunk->chunk));
11794                 for (i = 0; i < chunk->mirror_count; i++)
11795                         fprintf(stdout, " %u", chunk->mirror_id[i]);
11796                 fprintf(stdout, "\n");
11797         }
11798
11799         bytes_done = 0;
11800         count = MIN(chunk->chunk.e_end, file_size) - chunk->chunk.e_start;
11801         pos = chunk->chunk.e_start;
11802         while (bytes_done < count) {
11803                 /* compute initial CRC-32 checksum */
11804                 crc = crc32(0L, Z_NULL, 0);
11805                 memset(crc_array, 0, sizeof(crc_array));
11806
11807                 bytes_read = 0;
11808                 for (i = 0; i < chunk->mirror_count; i++) {
11809                         bytes_read = llapi_mirror_read(fd, chunk->mirror_id[i],
11810                                                        buf, buflen, pos);
11811                         if (bytes_read < 0) {
11812                                 rc = bytes_read;
11813                                 fprintf(stderr,
11814                                         "%s: failed to read data from mirror %u: %s.\n",
11815                                         progname, chunk->mirror_id[i],
11816                                         strerror(-rc));
11817                                 goto error;
11818                         }
11819
11820                         /* compute new CRC-32 checksum */
11821                         crc_array[i] = crc32(crc, buf, bytes_read);
11822                 }
11823
11824                 if (verbose)
11825                         print_checksums(chunk, crc_array);
11826
11827                 /* compare CRC-32 checksum values */
11828                 for (i = 1; i < chunk->mirror_count; i++) {
11829                         if (crc_array[i] != crc_array[0]) {
11830                                 rc = -EINVAL;
11831
11832                                 fprintf(stderr,
11833                                         "%s: chunk "DEXT" has different checksum value on mirror %u and mirror %u.\n",
11834                                         progname, PEXT(&chunk->chunk),
11835                                         chunk->mirror_id[0],
11836                                         chunk->mirror_id[i]);
11837                         }
11838                 }
11839
11840                 pos += bytes_read;
11841                 bytes_done += bytes_read;
11842         }
11843
11844         if (verbose > 1 && rc == 0) {
11845                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
11846                         PEXT(&chunk->chunk));
11847                 for (i = 0; i < chunk->mirror_count; i++)
11848                         fprintf(stdout, " %u", chunk->mirror_id[i]);
11849                 fprintf(stdout, " PASS\n\n");
11850         }
11851
11852 error:
11853         free(buf);
11854         return rc;
11855 }
11856
11857 /**
11858  * lfs_mirror_verify_file() - Verify a mirrored file.
11859  * @fname:      Mirrored file name.
11860  * @mirror_ids: Specified mirror ids to be verified.
11861  * @ids_nr:     Number of specified mirror ids.
11862  * @verbose:    Verbose mode.
11863  *
11864  * This function verifies that each SYNC mirror of a mirrored file
11865  * specified by @fname contains exactly the same data.
11866  *
11867  * If @mirror_ids is specified, then the function will verify the
11868  * mirrors specified by @mirror_ids contain exactly the same data.
11869  *
11870  * If @verbose is specified, then the function will print where the
11871  * differences are if the data do not match. Otherwise, it will
11872  * just return an error in that case.
11873  *
11874  * Return: 0 on success or a negative error code on failure.
11875  */
11876 static inline
11877 int lfs_mirror_verify_file(const char *fname, __u16 *mirror_ids, int ids_nr,
11878                            int verbose)
11879 {
11880         struct verify_chunk chunks_array[1024] = { };
11881         struct llapi_layout *layout = NULL;
11882         struct stat stbuf;
11883         uint32_t flr_state;
11884         int fd;
11885         int chunk_count = 0;
11886         int idx = 0;
11887         int rc = 0;
11888         int rc1 = 0;
11889         int rc2 = 0;
11890
11891         if (stat(fname, &stbuf) < 0) {
11892                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
11893                         progname, fname, strerror(errno));
11894                 rc = -errno;
11895                 goto error;
11896         }
11897
11898         if (!S_ISREG(stbuf.st_mode)) {
11899                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
11900                         progname, fname);
11901                 rc = -EINVAL;
11902                 goto error;
11903         }
11904
11905         if (stbuf.st_size == 0) {
11906                 if (verbose)
11907                         fprintf(stdout, "%s: '%s' file size is 0.\n",
11908                                 progname, fname);
11909                 rc = 0;
11910                 goto error;
11911         }
11912
11913         fd = open(fname, O_DIRECT | O_RDONLY);
11914         if (fd < 0) {
11915                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
11916                         progname, fname, strerror(errno));
11917                 rc = -errno;
11918                 goto error;
11919         }
11920
11921         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
11922         if (rc < 0) {
11923                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
11924                         progname, fname, strerror(errno));
11925                 goto close_fd;
11926         }
11927
11928         layout = llapi_layout_get_by_fd(fd, 0);
11929         if (!layout) {
11930                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
11931                         progname, fname, strerror(errno));
11932                 rc = -errno;
11933                 llapi_lease_release(fd);
11934                 goto close_fd;
11935         }
11936
11937         rc = llapi_layout_flags_get(layout, &flr_state);
11938         if (rc < 0) {
11939                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
11940                         progname, fname, strerror(errno));
11941                 rc = -errno;
11942                 goto free_layout;
11943         }
11944
11945         flr_state &= LCM_FL_FLR_MASK;
11946         switch (flr_state) {
11947         case LCM_FL_NONE:
11948                 rc = -EINVAL;
11949                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
11950                         progname, fname, llapi_layout_flags_string(flr_state));
11951                 goto free_layout;
11952         default:
11953                 break;
11954         }
11955
11956         /* find out mirror chunks to be verified */
11957         chunk_count = lfs_mirror_prepare_chunk(layout, chunks_array,
11958                                                ARRAY_SIZE(chunks_array));
11959         if (chunk_count < 0) {
11960                 rc = chunk_count;
11961                 goto free_layout;
11962         }
11963
11964         if (ids_nr > 0)
11965                 /* filter specified mirror ids */
11966                 filter_mirror_id(chunks_array, chunk_count, mirror_ids, ids_nr);
11967
11968         if (verbose > 2)
11969                 print_chunks(fname, chunks_array, chunk_count);
11970
11971         for (idx = 0; idx < chunk_count; idx++) {
11972                 if (chunks_array[idx].chunk.e_start >= stbuf.st_size) {
11973                         if (verbose)
11974                                 fprintf(stdout,
11975                                         "%s: '%s' chunk "DEXT" exceeds file size %#llx: skipped\n",
11976                                         progname, fname,
11977                                         PEXT(&chunks_array[idx].chunk),
11978                                         (unsigned long long)stbuf.st_size);
11979                         break;
11980                 }
11981
11982                 if (chunks_array[idx].mirror_count == 0) {
11983                         fprintf(stderr,
11984                                 "%s: '%s' chunk "DEXT" is invalid in all of the mirrors: ",
11985                                 progname, fname,
11986                                 PEXT(&chunks_array[idx].chunk));
11987                         if (verbose) {
11988                                 fprintf(stderr, "skipped\n");
11989                                 continue;
11990                         }
11991                         rc = -EINVAL;
11992                         fprintf(stderr, "failed\n");
11993                         goto free_layout;
11994                 }
11995
11996                 if (chunks_array[idx].mirror_count == 1) {
11997                         if (verbose)
11998                                 fprintf(stdout,
11999                                         "%s: '%s' chunk "DEXT" is only valid in mirror %u: skipped\n",
12000                                         progname, fname,
12001                                         PEXT(&chunks_array[idx].chunk),
12002                                         chunks_array[idx].mirror_id[0]);
12003                         continue;
12004                 }
12005
12006                 rc = llapi_lease_check(fd);
12007                 if (rc != LL_LEASE_RDLCK) {
12008                         fprintf(stderr, "%s: '%s' lost lease lock.\n",
12009                                 progname, fname);
12010                         goto free_layout;
12011                 }
12012
12013                 /* verify one chunk */
12014                 rc1 = lfs_mirror_verify_chunk(fd, stbuf.st_size,
12015                                               &chunks_array[idx], verbose);
12016                 if (rc1 < 0) {
12017                         rc2 = rc1;
12018                         if (!verbose) {
12019                                 rc = rc1;
12020                                 goto free_layout;
12021                         }
12022                 }
12023         }
12024
12025         if (rc2 < 0)
12026                 rc = rc2;
12027
12028 free_layout:
12029         llapi_layout_free(layout);
12030         llapi_lease_release(fd);
12031 close_fd:
12032         close(fd);
12033 error:
12034         return rc;
12035 }
12036
12037 /**
12038  * lfs_mirror_verify() - Parse and execute lfs mirror verify command.
12039  * @argc: The count of lfs mirror verify command line arguments.
12040  * @argv: Array of strings for lfs mirror verify command line arguments.
12041  *
12042  * This function parses lfs mirror verify command and verifies the
12043  * specified mirrored file(s).
12044  *
12045  * Return: 0 on success or a negative error code on failure.
12046  */
12047 static inline int lfs_mirror_verify(int argc, char **argv)
12048 {
12049         __u16 mirror_ids[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
12050         int ids_nr = 0;
12051         int c;
12052         int verbose = 0;
12053         int rc = 0;
12054         int rc1 = 0;
12055         char cmd[PATH_MAX];
12056
12057         struct option long_opts[] = {
12058         { .val = 'h',   .name = "help",         .has_arg = no_argument },
12059         { .val = 'o',   .name = "only",         .has_arg = required_argument },
12060         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
12061         { .name = NULL } };
12062
12063         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12064         progname = cmd;
12065         while ((c = getopt_long(argc, argv, "ho:v", long_opts, NULL)) >= 0) {
12066                 switch (c) {
12067                 case 'o':
12068                         rc = parse_mirror_ids(mirror_ids,
12069                                               ARRAY_SIZE(mirror_ids),
12070                                               optarg);
12071                         if (rc < 0) {
12072                                 fprintf(stderr,
12073                                         "%s: bad mirror ids '%s'.\n",
12074                                         progname, optarg);
12075                                 goto error;
12076                         }
12077                         ids_nr = rc;
12078                         if (ids_nr < 2) {
12079                                 fprintf(stderr,
12080                                         "%s: at least 2 mirror ids needed with '--only' option.\n",
12081                                         progname);
12082                                 rc = CMD_HELP;
12083                                 goto error;
12084                         }
12085                         break;
12086                 case 'v':
12087                         verbose++;
12088                         break;
12089                 default:
12090                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12091                                 progname, argv[optind - 1]);
12092                         /* fallthrough */
12093                 case 'h':
12094                         rc = CMD_HELP;
12095                         goto error;
12096                 }
12097         }
12098
12099         if (argc == optind) {
12100                 fprintf(stderr, "%s: no file name given.\n", progname);
12101                 rc = CMD_HELP;
12102                 goto error;
12103         }
12104
12105         if (ids_nr > 0 && argc > optind + 1) {
12106                 fprintf(stderr,
12107                         "%s: '--only' cannot be used upon multiple files.\n",
12108                         progname);
12109                 rc = CMD_HELP;
12110                 goto error;
12111         }
12112
12113         if (ids_nr > 0) {
12114                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
12115                 if (rc < 0)
12116                         goto error;
12117         }
12118
12119         rc = 0;
12120         for (; optind < argc; optind++) {
12121                 rc1 = lfs_mirror_verify_file(argv[optind], mirror_ids, ids_nr,
12122                                              verbose);
12123                 if (rc1 < 0)
12124                         rc = rc1;
12125         }
12126 error:
12127         return rc;
12128 }
12129
12130 /**
12131  * lfs_mirror() - Parse and execute lfs mirror commands.
12132  * @argc: The count of lfs mirror command line arguments.
12133  * @argv: Array of strings for lfs mirror command line arguments.
12134  *
12135  * This function parses lfs mirror commands and performs the
12136  * corresponding functions specified in mirror_cmdlist[].
12137  *
12138  * Return: 0 on success or an error code on failure.
12139  */
12140 static int lfs_mirror(int argc, char **argv)
12141 {
12142         char cmd[PATH_MAX];
12143         int rc = 0;
12144
12145         setlinebuf(stdout);
12146
12147         Parser_init("lfs-mirror > ", mirror_cmdlist);
12148
12149         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12150         progname = cmd;
12151         program_invocation_short_name = cmd;
12152         if (argc > 1)
12153                 rc = Parser_execarg(argc - 1, argv + 1, mirror_cmdlist);
12154         else
12155                 rc = Parser_commands();
12156
12157         return rc < 0 ? -rc : rc;
12158 }
12159
12160 static void lustre_som_swab(struct lustre_som_attrs *attrs)
12161 {
12162 #if __BYTE_ORDER == __BIG_ENDIAN
12163         __swab16s(&attrs->lsa_valid);
12164         __swab64s(&attrs->lsa_size);
12165         __swab64s(&attrs->lsa_blocks);
12166 #endif
12167 }
12168
12169 enum lfs_som_type {
12170         LFS_SOM_SIZE = 0x1,
12171         LFS_SOM_BLOCKS = 0x2,
12172         LFS_SOM_FLAGS = 0x4,
12173         LFS_SOM_ATTR_ALL = LFS_SOM_SIZE | LFS_SOM_BLOCKS |
12174                            LFS_SOM_FLAGS,
12175 };
12176
12177 static int lfs_getsom(int argc, char **argv)
12178 {
12179         const char *path;
12180         struct lustre_som_attrs *attrs;
12181         char buf[sizeof(*attrs) + 64];
12182         enum lfs_som_type type = LFS_SOM_ATTR_ALL;
12183         int rc = 0, c;
12184
12185         while ((c = getopt(argc, argv, "bfhs")) != -1) {
12186                 switch (c) {
12187                 case 'b':
12188                         type = LFS_SOM_BLOCKS;
12189                         break;
12190                 case 'f':
12191                         type = LFS_SOM_FLAGS;
12192                         break;
12193                 case 's':
12194                         type = LFS_SOM_SIZE;
12195                         break;
12196                 default:
12197                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12198                                 progname, argv[optind - 1]);
12199                         /* fallthrough */
12200                 case 'h':
12201                         return CMD_HELP;
12202                 }
12203         }
12204
12205         argc -= optind;
12206         argv += optind;
12207
12208         if (argc != 1) {
12209                 fprintf(stderr, "%s: %s\n",
12210                         progname, argc == 0 ? "miss file target" :
12211                         "input more than 2 files");
12212                 return CMD_HELP;
12213         }
12214
12215         path = argv[0];
12216         attrs = (void *)buf;
12217         rc = lgetxattr(path, "trusted.som", attrs, sizeof(buf));
12218         if (rc < 0) {
12219                 rc = -errno;
12220                 fprintf(stderr, "%s failed to get som xattr: %s (%d)\n",
12221                         argv[0], strerror(errno), errno);
12222                 return rc;
12223         }
12224
12225         lustre_som_swab(attrs);
12226
12227         switch (type) {
12228         case LFS_SOM_ATTR_ALL:
12229                 printf("file: %s size: %llu blocks: %llu flags: %x\n",
12230                        path, (unsigned long long)attrs->lsa_size,
12231                        (unsigned long long)attrs->lsa_blocks,
12232                        attrs->lsa_valid);
12233                 break;
12234         case LFS_SOM_SIZE:
12235                 printf("%llu\n", (unsigned long long)attrs->lsa_size);
12236                 break;
12237         case LFS_SOM_BLOCKS:
12238                 printf("%llu\n", (unsigned long long)attrs->lsa_blocks);
12239                 break;
12240         case LFS_SOM_FLAGS:
12241                 printf("%x\n", attrs->lsa_valid);
12242                 break;
12243         default:
12244                 fprintf(stderr, "%s: unknown option\n", progname);
12245                 return CMD_HELP;
12246         }
12247
12248         return 0;
12249 }
12250
12251 /**
12252  * lfs_mirror_list_commands() - List lfs mirror commands.
12253  * @argc: The count of command line arguments.
12254  * @argv: Array of strings for command line arguments.
12255  *
12256  * This function lists lfs mirror commands defined in mirror_cmdlist[].
12257  *
12258  * Return: 0 on success.
12259  */
12260 static int lfs_mirror_list_commands(int argc, char **argv)
12261 {
12262         char buffer[81] = "";
12263
12264         Parser_list_commands(mirror_cmdlist, buffer, sizeof(buffer),
12265                              NULL, 0, 4);
12266
12267         return 0;
12268 }
12269
12270 static int lfs_pcc_attach(int argc, char **argv)
12271 {
12272         struct option long_opts[] = {
12273         { .val = 'h',   .name = "help", .has_arg = no_argument },
12274         { .val = 'i',   .name = "id",   .has_arg = required_argument },
12275         { .name = NULL } };
12276         int c;
12277         int rc = 0;
12278         __u32 archive_id = 0;
12279         const char *path;
12280         char *end;
12281         char fullpath[PATH_MAX];
12282         enum lu_pcc_type type = LU_PCC_READWRITE;
12283
12284         optind = 0;
12285         while ((c = getopt_long(argc, argv, "hi:",
12286                                 long_opts, NULL)) != -1) {
12287                 switch (c) {
12288                 case 'i':
12289                         errno = 0;
12290                         archive_id = strtoul(optarg, &end, 0);
12291                         if (errno != 0 || *end != '\0' ||
12292                             archive_id == 0 || archive_id > UINT32_MAX) {
12293                                 fprintf(stderr,
12294                                         "error: %s: bad archive ID '%s'\n",
12295                                         progname, optarg);
12296                                 return CMD_HELP;
12297                         }
12298                         break;
12299                 default:
12300                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12301                                 progname, argv[optind - 1]);
12302                         /* fallthrough */
12303                 case 'h':
12304                         return CMD_HELP;
12305                 }
12306         }
12307
12308         if (archive_id == 0) {
12309                 fprintf(stderr, "%s: must specify attach ID\n", argv[0]);
12310                 return CMD_HELP;
12311         }
12312
12313         if (argc <= optind) {
12314                 fprintf(stderr, "%s: must specify one or more file names\n",
12315                         argv[0]);
12316                 return CMD_HELP;
12317         }
12318
12319         while (optind < argc) {
12320                 int rc2;
12321
12322                 path = argv[optind++];
12323                 if (!realpath(path, fullpath)) {
12324                         fprintf(stderr, "%s: could not find path '%s': %s\n",
12325                                 argv[0], path, strerror(errno));
12326                         if (rc == 0)
12327                                 rc = -EINVAL;
12328                         continue;
12329                 }
12330
12331                 rc2 = llapi_pcc_attach(fullpath, archive_id, type);
12332                 if (rc2 < 0) {
12333                         fprintf(stderr,
12334                                 "%s: cannot attach '%s' to PCC with archive ID '%u': %s\n",
12335                                 argv[0], path, archive_id, strerror(-rc2));
12336                         if (rc == 0)
12337                                 rc = rc2;
12338                 }
12339         }
12340         return rc;
12341 }
12342
12343 static int lfs_pcc_attach_fid(int argc, char **argv)
12344 {
12345         struct option long_opts[] = {
12346         { .val = 'h',   .name = "help", .has_arg = no_argument },
12347         { .val = 'i',   .name = "id",   .has_arg = required_argument },
12348         { .val = 'm',   .name = "mnt",  .has_arg = required_argument },
12349         { .name = NULL } };
12350         int c;
12351         int rc = 0;
12352         __u32 archive_id = 0;
12353         char *end;
12354         const char *mntpath = NULL;
12355         const char *fidstr;
12356         enum lu_pcc_type type = LU_PCC_READWRITE;
12357
12358         optind = 0;
12359         while ((c = getopt_long(argc, argv, "hi:m:",
12360                                 long_opts, NULL)) != -1) {
12361                 switch (c) {
12362                 case 'i':
12363                         errno = 0;
12364                         archive_id = strtoul(optarg, &end, 0);
12365                         if (errno != 0 || *end != '\0' ||
12366                             archive_id > UINT32_MAX) {
12367                                 fprintf(stderr,
12368                                         "error: %s: bad archive ID '%s'\n",
12369                                         argv[0], optarg);
12370                                 return CMD_HELP;
12371                         }
12372                         break;
12373                 case 'm':
12374                         mntpath = optarg;
12375                         break;
12376                 default:
12377                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12378                                 progname, argv[optind - 1]);
12379                         /* fallthrough */
12380                 case 'h':
12381                         return CMD_HELP;
12382                 }
12383         }
12384
12385         if (archive_id == 0) {
12386                 fprintf(stderr, "%s: must specify an archive ID\n", argv[0]);
12387                 return CMD_HELP;
12388         }
12389
12390         if (!mntpath) {
12391                 fprintf(stderr, "%s: must specify Lustre mount point\n",
12392                         argv[0]);
12393                 return CMD_HELP;
12394         }
12395
12396         if (argc <= optind) {
12397                 fprintf(stderr, "%s: must specify one or more fids\n", argv[0]);
12398                 return CMD_HELP;
12399         }
12400
12401         while (optind < argc) {
12402                 int rc2;
12403
12404                 fidstr = argv[optind++];
12405
12406                 rc2 = llapi_pcc_attach_fid_str(mntpath, fidstr,
12407                                                archive_id, type);
12408                 if (rc2 < 0) {
12409                         fprintf(stderr,
12410                                 "%s: cannot attach '%s' on '%s' to PCC with archive ID '%u': %s\n",
12411                                 argv[0], fidstr, mntpath, archive_id,
12412                                 strerror(rc2));
12413                 }
12414                 if (rc == 0 && rc2 < 0)
12415                         rc = rc2;
12416         }
12417         return rc;
12418 }
12419
12420 static int lfs_pcc_detach(int argc, char **argv)
12421 {
12422         struct option long_opts[] = {
12423         { .val = 'h',   .name = "help", .has_arg = no_argument },
12424         { .val = 'k',   .name = "keep", .has_arg = no_argument },
12425         { .name = NULL } };
12426         int c;
12427         int rc = 0;
12428         const char *path;
12429         char fullpath[PATH_MAX];
12430         __u32 detach_opt = PCC_DETACH_OPT_UNCACHE;
12431
12432         optind = 0;
12433         while ((c = getopt_long(argc, argv, "hk",
12434                                 long_opts, NULL)) != -1) {
12435                 switch (c) {
12436                 case 'k':
12437                         detach_opt = PCC_DETACH_OPT_NONE;
12438                         break;
12439                 default:
12440                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12441                                 progname, argv[optind - 1]);
12442                         /* fallthrough */
12443                 case 'h':
12444                         return CMD_HELP;
12445                 }
12446         }
12447
12448         while (optind < argc) {
12449                 int rc2;
12450
12451                 path = argv[optind++];
12452                 if (!realpath(path, fullpath)) {
12453                         fprintf(stderr, "%s: could not find path '%s': %s\n",
12454                                 argv[0], path, strerror(errno));
12455                         if (rc == 0)
12456                                 rc = -EINVAL;
12457                         continue;
12458                 }
12459
12460                 rc2 = llapi_pcc_detach_file(fullpath, detach_opt);
12461                 if (rc2 < 0) {
12462                         rc2 = -errno;
12463                         fprintf(stderr,
12464                                 "%s: cannot detach '%s' from PCC: %s\n",
12465                                 argv[0], path, strerror(errno));
12466                         if (rc == 0)
12467                                 rc = rc2;
12468                 }
12469         }
12470         return rc;
12471 }
12472
12473 static int lfs_pcc_detach_fid(int argc, char **argv)
12474 {
12475         struct option long_opts[] = {
12476         { .val = 'h',   .name = "help", .has_arg = no_argument },
12477         { .val = 'k',   .name = "keep", .has_arg = no_argument },
12478         { .name = NULL } };
12479         int c;
12480         int rc = 0;
12481         const char *fid;
12482         const char *mntpath;
12483         __u32 detach_opt = PCC_DETACH_OPT_UNCACHE;
12484
12485         optind = 0;
12486         while ((c = getopt_long(argc, argv, "hk",
12487                                 long_opts, NULL)) != -1) {
12488                 switch (c) {
12489                 case 'k':
12490                         detach_opt = PCC_DETACH_OPT_NONE;
12491                         break;
12492                 default:
12493                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12494                                 progname, argv[optind - 1]);
12495                         /* fallthrough */
12496                 case 'h':
12497                         return CMD_HELP;
12498                 }
12499         }
12500
12501         mntpath = argv[optind++];
12502
12503         while (optind < argc) {
12504                 int rc2;
12505
12506                 fid = argv[optind++];
12507
12508                 rc2 = llapi_pcc_detach_fid_str(mntpath, fid, detach_opt);
12509                 if (rc2 < 0) {
12510                         fprintf(stderr,
12511                                 "%s: cannot detach '%s' on '%s' from PCC: %s\n",
12512                                 argv[0], fid, mntpath, strerror(-rc2));
12513                         if (rc == 0)
12514                                 rc = rc2;
12515                 }
12516         }
12517         return rc;
12518 }
12519
12520 static int lfs_pcc_state(int argc, char **argv)
12521 {
12522         int rc = 0;
12523         const char *path;
12524         char fullpath[PATH_MAX];
12525         struct lu_pcc_state state;
12526
12527         optind = 1;
12528
12529         if (argc <= 1) {
12530                 fprintf(stderr, "%s: must specify one or more file names\n",
12531                         progname);
12532                 return CMD_HELP;
12533         }
12534
12535         while (optind < argc) {
12536                 int rc2;
12537
12538                 path = argv[optind++];
12539                 if (!realpath(path, fullpath)) {
12540                         fprintf(stderr, "%s: could not find path '%s': %s\n",
12541                                 argv[0], path, strerror(errno));
12542                         if (rc == 0)
12543                                 rc = -EINVAL;
12544                         continue;
12545                 }
12546
12547                 rc2 = llapi_pcc_state_get(fullpath, &state);
12548                 if (rc2 < 0) {
12549                         if (rc == 0)
12550                                 rc = rc2;
12551                         fprintf(stderr,
12552                                 "%s: cannot get PCC state of '%s': %s\n",
12553                                 argv[0], path, strerror(-rc2));
12554                         continue;
12555                 }
12556
12557                 printf("file: %s", path);
12558                 printf(", type: %s", pcc_type2string(state.pccs_type));
12559                 if (state.pccs_type == LU_PCC_NONE &&
12560                     state.pccs_open_count == 0) {
12561                         printf("\n");
12562                         continue;
12563                 }
12564
12565                 printf(", PCC file: %s", state.pccs_path);
12566                 printf(", user number: %u", state.pccs_open_count);
12567                 printf(", flags: %x", state.pccs_flags);
12568                 printf("\n");
12569         }
12570         return rc;
12571 }
12572
12573 /**
12574  * lfs_pcc_list_commands() - List lfs pcc commands.
12575  * @argc: The count of command line arguments.
12576  * @argv: Array of strings for command line arguments.
12577  *
12578  * This function lists lfs pcc commands defined in pcc_cmdlist[].
12579  *
12580  * Return: 0 on success.
12581  */
12582 static int lfs_pcc_list_commands(int argc, char **argv)
12583 {
12584         char buffer[81] = "";
12585
12586         Parser_list_commands(pcc_cmdlist, buffer, sizeof(buffer),
12587                              NULL, 0, 4);
12588
12589         return 0;
12590 }
12591
12592 /**
12593  * lfs_pcc() - Parse and execute lfs pcc commands.
12594  * @argc: The count of lfs pcc command line arguments.
12595  * @argv: Array of strings for lfs pcc command line arguments.
12596  *
12597  * This function parses lfs pcc commands and performs the
12598  * corresponding functions specified in pcc_cmdlist[].
12599  *
12600  * Return: 0 on success or an error code on failure.
12601  */
12602 static int lfs_pcc(int argc, char **argv)
12603 {
12604         char cmd[PATH_MAX];
12605         int rc = 0;
12606
12607         setlinebuf(stdout);
12608
12609         Parser_init("lfs-pcc > ", pcc_cmdlist);
12610
12611         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12612         progname = cmd;
12613         program_invocation_short_name = cmd;
12614         if (argc > 1)
12615                 rc = Parser_execarg(argc - 1, argv + 1, pcc_cmdlist);
12616         else
12617                 rc = Parser_commands();
12618
12619         return rc < 0 ? -rc : rc;
12620 }
12621
12622 static int lfs_list_commands(int argc, char **argv)
12623 {
12624         char buffer[81] = ""; /* 80 printable chars + terminating NUL */
12625
12626         Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
12627
12628         return 0;
12629 }
12630
12631 int main(int argc, char **argv)
12632 {
12633         int rc;
12634
12635         /* Ensure that liblustreapi constructor has run */
12636         if (!llapi_liblustreapi_initialized())
12637                 fprintf(stderr, "liblustreapi was not properly initialized\n");
12638
12639         setlinebuf(stdout);
12640         opterr = 0;
12641
12642         Parser_init("lfs > ", cmdlist);
12643
12644         progname = program_invocation_short_name; /* Used in error messages */
12645         if (argc > 1) {
12646                 llapi_set_command_name(argv[1]);
12647                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
12648                 llapi_clear_command_name();
12649         } else {
12650                 rc = Parser_commands();
12651         }
12652
12653         return rc < 0 ? -rc : rc;
12654 }
12655
12656 #ifdef _LUSTRE_IDL_H_
12657 /* Everything we need here should be included by lustreapi.h. */
12658 # error "lfs should not depend on lustre_idl.h"
12659 #endif /* _LUSTRE_IDL_H_ */