Whamcloud - gitweb
LU-14975 dne: dir migration in non-recursive mode
[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] [--directory|-d]\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         /* used with "lfs migrate -m" */
3452         { .val = 'd',   .name = "directory",    .has_arg = no_argument},
3453         /* --non-direct is only valid in migrate mode */
3454         { .val = 'D',   .name = "non-direct",   .has_arg = no_argument },
3455         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument},
3456         { .val = 'E',   .name = "component-end",
3457                                                 .has_arg = required_argument},
3458         { .val = 'f',   .name = "file",         .has_arg = required_argument },
3459 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
3460 /* find { .val = 'g',   .name = "gid",          .has_arg = no_argument }, */
3461 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
3462         { .val = 'h',   .name = "help",         .has_arg = no_argument },
3463         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument},
3464         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument},
3465         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument},
3466         { .val = 'I',   .name = "comp-id",      .has_arg = required_argument},
3467         { .val = 'I',   .name = "component-id", .has_arg = required_argument},
3468 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
3469         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
3470         { .val = 'm',   .name = "mdt",          .has_arg = required_argument},
3471         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument},
3472         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument},
3473         /* --non-block is only valid in migrate mode */
3474         { .val = 'n',   .name = "non-block",    .has_arg = no_argument },
3475         { .val = 'N',   .name = "mirror-count", .has_arg = optional_argument},
3476         { .val = 'o',   .name = "ost",          .has_arg = required_argument },
3477 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3478         { .val = 'o',   .name = "ost-list",     .has_arg = required_argument },
3479         { .val = 'o',   .name = "ost_list",     .has_arg = required_argument },
3480 #endif
3481         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
3482 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
3483 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
3484 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
3485         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
3486         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
3487 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
3488 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
3489 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
3490 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
3491         /* --verbose is only valid in migrate mode */
3492         { .val = 'v',   .name = "verbose",      .has_arg = no_argument},
3493         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
3494 /* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/
3495         { .val = 'y',   .name = "yaml",         .has_arg = required_argument },
3496         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument},
3497         { .val = 'z',   .name = "extension-size", .has_arg = required_argument},
3498         { .name = NULL } };
3499
3500         setstripe_args_init(&lsa);
3501
3502         migrate_mode = (opc == SO_MIGRATE);
3503         mirror_mode = (opc == SO_MIRROR_CREATE || opc == SO_MIRROR_EXTEND);
3504         setstripe_mode = (opc == SO_SETSTRIPE);
3505         if (opc == SO_MIRROR_DELETE) {
3506                 delete = 1;
3507                 mirror_flags = MF_DESTROY;
3508         }
3509
3510         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
3511         progname = cmd;
3512         while ((c = getopt_long(argc, argv,
3513                                 "bc:C:dDE:f:hH:i:I:m:N::no:p:L:s:S:vx:y:z:",
3514                                 long_opts, NULL)) >= 0) {
3515                 size_units = 1;
3516                 switch (c) {
3517                 case 0:
3518                         /* Long options. */
3519                         break;
3520                 case LFS_COMP_ADD_OPT:
3521                         comp_add = 1;
3522                         break;
3523                 case LFS_COMP_DEL_OPT:
3524                         comp_del = 1;
3525                         break;
3526                 case LFS_COMP_FLAGS_OPT:
3527                         result = comp_str2flags(optarg, &lsa.lsa_comp_flags,
3528                                                 &lsa.lsa_comp_neg_flags);
3529                         if (result != 0)
3530                                 goto usage_error;
3531                         if (mirror_mode && lsa.lsa_comp_neg_flags) {
3532                                 fprintf(stderr,
3533                                         "%s: inverted flags are not supported\n",
3534                                         progname);
3535                                 goto usage_error;
3536                         }
3537                         break;
3538                 case LFS_COMP_SET_OPT:
3539                         comp_set = 1;
3540                         break;
3541                 case LFS_COMP_NO_VERIFY_OPT:
3542                         mirror_flags |= MF_NO_VERIFY;
3543                         break;
3544                 case LFS_MIRROR_ID_OPT: {
3545                         unsigned long int id;
3546
3547                         errno = 0;
3548                         id = strtoul(optarg, &end, 0);
3549                         if (errno != 0 || *end != '\0' || id == 0 ||
3550                             id > UINT16_MAX) {
3551                                 fprintf(stderr,
3552                                         "%s %s: invalid mirror ID '%s'\n",
3553                                         progname, argv[0], optarg);
3554                                 goto usage_error;
3555                         }
3556
3557                         mirror_id = (__u16)id;
3558                         break;
3559                 }
3560                 case LFS_LAYOUT_FLAGS_OPT: {
3561                         uint32_t neg_flags;
3562
3563                         /* check for numeric flags (foreign and mirror cases) */
3564                         if (setstripe_mode && !mirror_mode && !last_mirror) {
3565                                 errno = 0;
3566                                 flags = strtoul(optarg, &end, 16);
3567                                 if (errno != 0 || *end != '\0' ||
3568                                     flags >= UINT32_MAX) {
3569                                         fprintf(stderr,
3570                                                 "%s %s: invalid hex flags '%s'\n",
3571                                                 progname, argv[0], optarg);
3572                                         return CMD_HELP;
3573                                 }
3574                                 if (!foreign_mode) {
3575                                         fprintf(stderr,
3576                                                 "%s %s: hex flags must be specified with --foreign option\n",
3577                                                 progname, argv[0]);
3578                                         return CMD_HELP;
3579                                 }
3580                                 break;
3581                         }
3582
3583                         if (!mirror_mode || !last_mirror) {
3584                                 fprintf(stderr,
3585                                         "error: %s: --flags must be specified with --mirror-count|-N option\n",
3586                                         progname);
3587                                 goto usage_error;
3588                         }
3589
3590                         result = comp_str2flags(optarg, &last_mirror->m_flags,
3591                                                 &neg_flags);
3592                         if (result != 0)
3593                                 goto usage_error;
3594
3595                         if (neg_flags) {
3596                                 fprintf(stderr,
3597                                         "%s: inverted flags are not supported\n",
3598                                         progname);
3599                                 result = -EINVAL;
3600                                 goto usage_error;
3601                         }
3602                         if (last_mirror->m_flags & ~LCME_USER_MIRROR_FLAGS) {
3603                                 fprintf(stderr,
3604                                         "%s: unsupported mirror flags: %s\n",
3605                                         progname, optarg);
3606                                 result = -EINVAL;
3607                                 goto error;
3608                         }
3609                         break;
3610                 }
3611                 case LFS_LAYOUT_FOREIGN_OPT:
3612                         if (optarg) {
3613                                 /* check pure numeric */
3614                                 type = strtoul(optarg, &end, 0);
3615                                 if (*end) {
3616                                         /* check name */
3617                                         type = check_foreign_type_name(optarg);
3618                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
3619                                                 fprintf(stderr,
3620                                                         "%s %s: unrecognized foreign type '%s'\n",
3621                                                         progname, argv[0],
3622                                                         optarg);
3623                                                 return CMD_HELP;
3624                                         }
3625                                 } else if (type >= UINT32_MAX) {
3626                                         fprintf(stderr,
3627                                                 "%s %s: invalid foreign type '%s'\n",
3628                                                 progname, argv[0], optarg);
3629                                         return CMD_HELP;
3630                                 }
3631                         }
3632                         foreign_mode = true;
3633                         break;
3634                 case LFS_MODE_OPT:
3635                         mode_opt = optarg;
3636                         if (mode_opt) {
3637                                 mode = strtoul(mode_opt, &end, 8);
3638                                 if (*end != '\0') {
3639                                         fprintf(stderr,
3640                                                 "%s %s: bad mode '%s'\n",
3641                                                 progname, argv[0], mode_opt);
3642                                         return CMD_HELP;
3643                                 }
3644                                 previous_umask = umask(0);
3645                         }
3646                         break;
3647                 case LFS_LAYOUT_COPY:
3648                         from_copy = true;
3649                         template = optarg;
3650                         break;
3651                 case 'b':
3652                         if (!migrate_mode) {
3653                                 fprintf(stderr,
3654                                         "%s %s: -b|--block valid only for migrate command\n",
3655                                         progname, argv[0]);
3656                                 goto usage_error;
3657                         }
3658                         migration_block = true;
3659                         break;
3660                 case 'C':
3661                         if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) {
3662                                 fprintf(stderr,
3663                                         "%s %s: -C|--overstripe-count incompatible with DoM layout\n",
3664                                         progname, argv[0]);
3665                                 goto usage_error;
3666                         }
3667                         lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
3668                         /* fall through */
3669                 case 'c':
3670                         errno = 0;
3671                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
3672                         if (errno != 0 || *end != '\0'||
3673                             lsa.lsa_stripe_count < -1 ||
3674                             lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
3675                                 fprintf(stderr,
3676                                         "%s %s: invalid stripe count '%s'\n",
3677                                         progname, argv[0], optarg);
3678                                 goto usage_error;
3679                         }
3680
3681                         if (lsa.lsa_stripe_count == -1)
3682                                 lsa.lsa_stripe_count = LLAPI_LAYOUT_WIDE;
3683                         break;
3684                 case 'd':
3685                         if (migrate_mode) {
3686                                 migrate_mdt_param.fp_max_depth = 1;
3687                         } else {
3688                                 /* delete the default striping pattern */
3689                                 delete = 1;
3690                                 if (opc == SO_MIRROR_SPLIT) {
3691                                         if (has_m_file) {
3692                                                 fprintf(stderr,
3693                                                       "%s %s: -d cannot used with -f\n",
3694                                                         progname, argv[0]);
3695                                                 goto usage_error;
3696                                         }
3697                                         mirror_flags |= MF_DESTROY;
3698                                 }
3699                         }
3700                         break;
3701                 case 'D':
3702                         if (!migrate_mode) {
3703                                 fprintf(stderr,
3704                                         "%s %s: -D|--non-direct is valid only for migrate command\n",
3705                                         progname, argv[0]);
3706                                 goto usage_error;
3707                         }
3708                         migration_flags |= MIGRATION_NONDIRECT;
3709                         break;
3710                 case 'E':
3711                         if (lsa.lsa_comp_end != 0) {
3712                                 result = comp_args_to_layout(lpp, &lsa, true);
3713                                 if (result) {
3714                                         fprintf(stderr, "%s: invalid layout\n",
3715                                                 progname);
3716                                         goto usage_error;
3717                                 }
3718
3719                                 setstripe_args_init_inherit(&lsa);
3720                         }
3721
3722                         if (arg_is_eof(optarg)) {
3723                                 lsa.lsa_comp_end = LUSTRE_EOF;
3724                         } else {
3725                                 result = llapi_parse_size(optarg,
3726                                                           &lsa.lsa_comp_end,
3727                                                           &size_units, 0);
3728                                 /* assume units of KB if too small */
3729                                 if (lsa.lsa_comp_end < 4096)
3730                                         lsa.lsa_comp_end *= 1024;
3731                                 if (result ||
3732                                     lsa.lsa_comp_end & (LOV_MIN_STRIPE_SIZE - 1)) {
3733                                         fprintf(stderr,
3734                                                 "%s %s: invalid component end '%s'\n",
3735                                                 progname, argv[0], optarg);
3736                                         goto usage_error;
3737                                 }
3738                         }
3739                         break;
3740                 case 'H':
3741                         if (!migrate_mode) {
3742                                 fprintf(stderr,
3743                                         "--mdt-hash is valid only for migrate command\n");
3744                                 return CMD_HELP;
3745                         }
3746
3747                         lsa.lsa_pattern = check_hashtype(optarg);
3748                         if (lsa.lsa_pattern == 0) {
3749                                 fprintf(stderr,
3750                                         "%s %s: bad stripe hash type '%s'\n",
3751                                         progname, argv[0], optarg);
3752                                 return CMD_HELP;
3753                         }
3754                         break;
3755                 case 'i':
3756                         errno = 0;
3757                         lsa.lsa_stripe_off = strtol(optarg, &end, 0);
3758                         if (errno != 0 || *end != '\0' ||
3759                             lsa.lsa_stripe_off < -1 ||
3760                             lsa.lsa_stripe_off > LOV_V1_INSANE_STRIPE_COUNT) {
3761                                 fprintf(stderr,
3762                                         "%s %s: invalid stripe offset '%s'\n",
3763                                         progname, argv[0], optarg);
3764                                 goto usage_error;
3765                         }
3766                         if (lsa.lsa_stripe_off == -1)
3767                                 lsa.lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
3768                         break;
3769                 case 'I':
3770                         comp_id = strtoul(optarg, &end, 0);
3771                         if (*end != '\0' || comp_id == 0 ||
3772                             comp_id > LCME_ID_MAX) {
3773                                 fprintf(stderr,
3774                                         "%s %s: invalid component ID '%s'\n",
3775                                         progname, argv[0], optarg);
3776                                 goto usage_error;
3777                         }
3778                         break;
3779                 case 'f':
3780                         if (opc != SO_MIRROR_EXTEND && opc != SO_MIRROR_SPLIT) {
3781                                 fprintf(stderr,
3782                                         "error: %s: invalid option: %s\n",
3783                                         progname, argv[optopt + 1]);
3784                                 goto usage_error;
3785                         }
3786                         if (opc == SO_MIRROR_EXTEND) {
3787                                 if (!last_mirror) {
3788                                         fprintf(stderr,
3789                                 "error: %s: '-N' must exist in front of '%s'\n",
3790                                                 progname, argv[optopt + 1]);
3791                                         goto usage_error;
3792                                 }
3793                                 last_mirror->m_file = optarg;
3794                                 last_mirror->m_count = 1;
3795                         } else {
3796                                 /* mirror split */
3797                                 if (!mirror_list)
3798                                         mirror_list = lfs_mirror_alloc();
3799                                 mirror_list->m_file = optarg;
3800                         }
3801                         has_m_file = true;
3802                         break;
3803                 case 'L':
3804                         if (strcmp(argv[optind - 1], "mdt") == 0) {
3805                                 /* Can be only the first component */
3806                                 if (layout) {
3807                                         result = -EINVAL;
3808                                         fprintf(stderr,
3809                                                 "error: 'mdt' layout can be only the first one\n");
3810                                         goto error;
3811                                 }
3812                                 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
3813                                         result = -EFBIG;
3814                                         fprintf(stderr,
3815                                                 "error: 'mdt' layout size is too big\n");
3816                                         goto error;
3817                                 }
3818                                 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
3819                                 lsa.lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
3820                         } else if (strcmp(argv[optind - 1], "raid0") != 0) {
3821                                 result = -EINVAL;
3822                                 fprintf(stderr,
3823                                         "error: layout '%s' is unknown, supported layouts are: 'mdt', 'raid0'\n",
3824                                         argv[optind]);
3825                                 goto error;
3826                         }
3827                         break;
3828                 case 'm':
3829                         if (!migrate_mode) {
3830                                 fprintf(stderr,
3831                                         "%s %s: -m|--mdt-index is valid only for migrate command\n",
3832                                         progname, argv[0]);
3833                                 goto usage_error;
3834                         }
3835                         migrate_mdt_mode = true;
3836                         lsa.lsa_nr_tgts = parse_targets(tgts,
3837                                                 sizeof(tgts) / sizeof(__u32),
3838                                                 lsa.lsa_nr_tgts, optarg, NULL);
3839                         if (lsa.lsa_nr_tgts < 0) {
3840                                 fprintf(stderr,
3841                                         "%s: invalid MDT target(s) '%s'\n",
3842                                         progname, optarg);
3843                                 goto usage_error;
3844                         }
3845
3846                         lsa.lsa_tgts = tgts;
3847                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
3848                                 lsa.lsa_stripe_off = tgts[0];
3849                         break;
3850                 case 'n':
3851                         if (!migrate_mode) {
3852                                 fprintf(stderr,
3853                                         "%s %s: -n|--non-block valid only for migrate command\n",
3854                                         progname, argv[0]);
3855                                 goto usage_error;
3856                         }
3857                         migration_flags |= MIGRATION_NONBLOCK;
3858                         break;
3859                 case 'N':
3860                         if (opc == SO_SETSTRIPE) {
3861                                 opc = SO_MIRROR_CREATE;
3862                                 mirror_mode = true;
3863                         }
3864                         mirror_count = 1;
3865                         if (optarg) {
3866                                 errno = 0;
3867                                 mirror_count = strtoul(optarg, &end, 0);
3868                                 if (errno != 0 || *end != '\0' ||
3869                                     mirror_count == 0 ||
3870                                     mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
3871                                         fprintf(stderr,
3872                                                 "error: %s: bad mirror count: %s\n",
3873                                                 progname, optarg);
3874                                         result = -EINVAL;
3875                                         goto error;
3876                                 }
3877                         }
3878
3879                         new_mirror = lfs_mirror_alloc();
3880                         new_mirror->m_count = mirror_count;
3881
3882                         if (!mirror_list)
3883                                 mirror_list = new_mirror;
3884
3885                         if (last_mirror) {
3886                                 /* wrap up last mirror */
3887                                 if (!setstripe_args_specified(&lsa))
3888                                         last_mirror->m_inherit = true;
3889                                 if (lsa.lsa_comp_end == 0)
3890                                         lsa.lsa_comp_end = LUSTRE_EOF;
3891
3892                                 result = comp_args_to_layout(lpp, &lsa, true);
3893                                 if (result) {
3894                                         lfs_mirror_free(new_mirror);
3895                                         goto error;
3896                                 }
3897
3898                                 setstripe_args_init_inherit(&lsa);
3899
3900                                 last_mirror->m_next = new_mirror;
3901                         }
3902
3903                         last_mirror = new_mirror;
3904                         lpp = &last_mirror->m_layout;
3905                         break;
3906                 case 'o':
3907 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3908                         if (strcmp(argv[optind - 1], "--ost-list") == 0)
3909                                 fprintf(stderr,
3910                                         "warning: '--ost-list' is deprecated, use '--ost' instead\n");
3911 #endif
3912                         if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) {
3913                                 fprintf(stderr,
3914                                         "%s %s: -o|--ost incompatible with DoM layout\n",
3915                                         progname, argv[0]);
3916                                 goto usage_error;
3917                         }
3918                         /*
3919                          * -o allows overstriping, and must note it because
3920                          * parse_targets is shared with MDT striping, which
3921                          * does not allow duplicates
3922                          */
3923                         lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
3924                         lsa.lsa_nr_tgts = parse_targets(tgts,
3925                                                 sizeof(tgts) / sizeof(__u32),
3926                                                 lsa.lsa_nr_tgts, optarg,
3927                                                 &lsa.lsa_pattern);
3928                         if (lsa.lsa_nr_tgts < 0) {
3929                                 fprintf(stderr,
3930                                         "%s %s: invalid OST target(s) '%s'\n",
3931                                         progname, argv[0], optarg);
3932                                 goto usage_error;
3933                         }
3934
3935                         lsa.lsa_tgts = tgts;
3936                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
3937                                 lsa.lsa_stripe_off = tgts[0];
3938                         break;
3939                 case 'p':
3940                         if (!optarg)
3941                                 goto usage_error;
3942                         lsa.lsa_pool_name = optarg;
3943
3944                         if (strlen(lsa.lsa_pool_name) == 0 ||
3945                             strncmp(lsa.lsa_pool_name, "none",
3946                                     LOV_MAXPOOLNAME) == 0)
3947                                 lsa.lsa_pool_name = NULL;
3948                         break;
3949                 case 'S':
3950                         result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
3951                                                   &size_units, 0);
3952                         /* assume units of KB if too small to be valid */
3953                         if (lsa.lsa_stripe_size < 4096)
3954                                 lsa.lsa_stripe_size *= 1024;
3955                         if (result ||
3956                             lsa.lsa_stripe_size & (LOV_MIN_STRIPE_SIZE - 1)) {
3957                                 fprintf(stderr,
3958                                         "%s %s: invalid stripe size '%s'\n",
3959                                         progname, argv[0], optarg);
3960                                 goto usage_error;
3961                         }
3962                         break;
3963                 case 'v':
3964                         if (!migrate_mode) {
3965                                 fprintf(stderr,
3966                                         "%s %s: -v|--verbose valid only for migrate command\n",
3967                                         progname, argv[0]);
3968                                 goto usage_error;
3969                         }
3970                         migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
3971                         migration_flags = MIGRATION_VERBOSE;
3972                         break;
3973                 case 'x':
3974                         xattr = optarg;
3975                         break;
3976                 case 'y':
3977                         from_yaml = true;
3978                         template = optarg;
3979                         break;
3980                 case 'z':
3981                         result = llapi_parse_size(optarg,
3982                                                   &lsa.lsa_extension_size,
3983                                                   &size_units, 0);
3984                         if (result) {
3985                                 fprintf(stderr,
3986                                         "%s %s: invalid extension size '%s'\n",
3987                                         progname, argv[0], optarg);
3988                                 goto usage_error;
3989                         }
3990
3991                         lsa.lsa_extension_comp = true;
3992                         break;
3993                 default:
3994                         fprintf(stderr, "%s: unrecognized option '%s'\n",
3995                                 progname, argv[optind - 1]);
3996                 case 'h':
3997                         goto usage_error;
3998                 }
3999         }
4000
4001         fname = argv[optind];
4002
4003         if (optind == argc) {
4004                 fprintf(stderr, "%s %s: FILE must be specified\n",
4005                         progname, argv[0]);
4006                 goto usage_error;
4007         }
4008
4009         /* lfs migrate $filename should keep the file's layout by default */
4010         if (migrate_mode && !layout && !from_yaml &&
4011             !setstripe_args_specified(&lsa) && !lsa.lsa_pool_name)
4012                 from_copy = true;
4013
4014         if (xattr && !foreign_mode) {
4015                 /*
4016                  * only print a warning as this is harmless and will be ignored
4017                  */
4018                 fprintf(stderr,
4019                         "%s %s: xattr has been specified for non-foreign layout\n",
4020                         progname, argv[0]);
4021         } else if (foreign_mode && !xattr) {
4022                 fprintf(stderr,
4023                         "%s %s: xattr must be provided in foreign mode\n",
4024                         progname, argv[0]);
4025                 goto usage_error;
4026         }
4027
4028         if (foreign_mode && (!setstripe_mode || comp_add | comp_del ||
4029             comp_set || comp_id || delete || from_copy ||
4030             setstripe_args_specified(&lsa) || lsa.lsa_nr_tgts ||
4031             lsa.lsa_tgts)) {
4032                 fprintf(stderr,
4033                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
4034                         progname, argv[0]);
4035                 return CMD_HELP;
4036         }
4037
4038         if (mirror_mode && mirror_count == 0) {
4039                 fprintf(stderr,
4040                         "error: %s: --mirror-count|-N option is required\n",
4041                         progname);
4042                 result = -EINVAL;
4043                 goto error;
4044         }
4045
4046         if (mirror_mode) {
4047                 if (!setstripe_args_specified(&lsa))
4048                         last_mirror->m_inherit = true;
4049                 if (lsa.lsa_comp_end == 0)
4050                         lsa.lsa_comp_end = LUSTRE_EOF;
4051         }
4052
4053         if (lsa.lsa_comp_end != 0) {
4054                 result = comp_args_to_layout(lpp, &lsa, true);
4055                 if (result) {
4056                         fprintf(stderr, "error: %s: invalid layout\n",
4057                                 progname);
4058                         result = -EINVAL;
4059                         goto error;
4060                 }
4061         }
4062
4063         if (mirror_flags & MF_NO_VERIFY) {
4064                 if (opc != SO_MIRROR_EXTEND) {
4065                         fprintf(stderr,
4066                                 "error: %s: --no-verify is valid only for lfs mirror extend command\n",
4067                                 progname);
4068                         result = -EINVAL;
4069                         goto error;
4070                 } else if (!has_m_file) {
4071                         fprintf(stderr,
4072                                 "error: %s: --no-verify must be specified with -f <victim_file> option\n",
4073                                 progname);
4074                         result = -EINVAL;
4075                         goto error;
4076                 }
4077         }
4078
4079         if (comp_set && !comp_id && !lsa.lsa_pool_name) {
4080                 fprintf(stderr,
4081                         "%s %s: --component-set doesn't have component-id set\n",
4082                         progname, argv[0]);
4083                 goto usage_error;
4084         }
4085
4086         if ((delete + comp_set + comp_del + comp_add) > 1) {
4087                 fprintf(stderr,
4088                         "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
4089                         progname, argv[0]);
4090                 goto usage_error;
4091         }
4092
4093         if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
4094                        lsa.lsa_comp_flags != 0 || layout != NULL)) {
4095                 fprintf(stderr,
4096                         "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
4097                         progname, argv[0]);
4098                 goto usage_error;
4099         }
4100
4101         if ((comp_set || comp_del) &&
4102             (setstripe_args_specified(&lsa) || layout != NULL)) {
4103                 fprintf(stderr,
4104                         "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
4105                         progname, argv[0]);
4106                 goto usage_error;
4107         }
4108
4109         if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
4110                 fprintf(stderr,
4111                         "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
4112                         progname, argv[0]);
4113                 goto usage_error;
4114         }
4115
4116         if (comp_add || comp_del) {
4117                 struct stat st;
4118
4119                 result = lstat(fname, &st);
4120                 if (result == 0 && S_ISDIR(st.st_mode)) {
4121                         fprintf(stderr,
4122                                 "%s setstripe: cannot use --component-add or --component-del for directory\n",
4123                                 progname);
4124                         goto usage_error;
4125                 }
4126
4127                 if (mirror_mode) {
4128                         fprintf(stderr,
4129                                 "error: %s: can't use --component-add or --component-del for mirror operation\n",
4130                                 progname);
4131                         goto usage_error;
4132                 }
4133         }
4134
4135         if (comp_add) {
4136                 if (!layout) {
4137                         fprintf(stderr,
4138                                 "%s %s: option -E must be specified with --component-add\n",
4139                                 progname, argv[0]);
4140                         goto usage_error;
4141                 }
4142         }
4143
4144         if (from_yaml && from_copy) {
4145                 fprintf(stderr,
4146                         "%s: can't specify --yaml and --copy together\n",
4147                         progname);
4148                 goto error;
4149         }
4150
4151         if ((from_yaml || from_copy) &&
4152             (setstripe_args_specified(&lsa) || layout != NULL)) {
4153                 fprintf(stderr,
4154                         "error: %s: can't specify --yaml or --copy with -c, -S, -i, -o, -p or -E options.\n",
4155                         argv[0]);
4156                 goto error;
4157         }
4158
4159         if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
4160                 fprintf(stderr,
4161                         "%s %s: options --non-block and --block are mutually exclusive\n",
4162                         progname, argv[0]);
4163                 goto usage_error;
4164         }
4165
4166         if (!comp_del && !comp_set && opc != SO_MIRROR_SPLIT &&
4167             opc != SO_MIRROR_DELETE && comp_id != 0) {
4168                 fprintf(stderr,
4169                         "%s: option -I can only be used with --component-del or --component-set or lfs mirror split\n",
4170                         progname);
4171                 goto usage_error;
4172         }
4173
4174         if (migrate_mdt_mode) {
4175                 struct lmv_user_md *lmu;
4176
4177                 /* initialize migrate mdt parameters */
4178                 lmu = calloc(1, lmv_user_md_size(lsa.lsa_nr_tgts,
4179                                                  LMV_USER_MAGIC_SPECIFIC));
4180                 if (!lmu) {
4181                         fprintf(stderr,
4182                                 "%s %s: cannot allocate memory for lmv_user_md: %s\n",
4183                                 progname, argv[0], strerror(ENOMEM));
4184                         result = -ENOMEM;
4185                         goto error;
4186                 }
4187                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
4188                         lmu->lum_stripe_count = lsa.lsa_stripe_count;
4189                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT) {
4190                         fprintf(stderr,
4191                                 "%s %s: migrate should specify MDT index\n",
4192                                 progname, argv[0]);
4193                         free(lmu);
4194                         goto usage_error;
4195                 }
4196                 lmu->lum_stripe_offset = lsa.lsa_stripe_off;
4197                 if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
4198                         lmu->lum_hash_type = lsa.lsa_pattern;
4199                 else
4200                         lmu->lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
4201                 if (lsa.lsa_pool_name) {
4202                         strncpy(lmu->lum_pool_name, lsa.lsa_pool_name,
4203                                 sizeof(lmu->lum_pool_name) - 1);
4204                         lmu->lum_pool_name[sizeof(lmu->lum_pool_name) - 1] = 0;
4205                 }
4206                 if (lsa.lsa_nr_tgts > 1) {
4207                         int i;
4208
4209                         if (lsa.lsa_stripe_count > 0 &&
4210                             lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
4211                             lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
4212                                 fprintf(stderr,
4213                                         "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
4214                                         progname, lsa.lsa_stripe_count,
4215                                         lsa.lsa_nr_tgts);
4216                                 free(lmu);
4217                                 goto usage_error;
4218                         }
4219
4220                         lmu->lum_magic = LMV_USER_MAGIC_SPECIFIC;
4221                         lmu->lum_stripe_count = lsa.lsa_nr_tgts;
4222                         for (i = 0; i < lsa.lsa_nr_tgts; i++)
4223                                 lmu->lum_objects[i].lum_mds = lsa.lsa_tgts[i];
4224                 } else {
4225                         lmu->lum_magic = LMV_USER_MAGIC;
4226                 }
4227
4228                 migrate_mdt_param.fp_lmv_md = lmu;
4229                 migrate_mdt_param.fp_migrate = 1;
4230         } else if (!layout) {
4231                 if (lsa_args_stripe_count_check(&lsa))
4232                         goto usage_error;
4233
4234                 /* initialize stripe parameters */
4235                 param = calloc(1, offsetof(typeof(*param),
4236                                lsp_osts[lsa.lsa_nr_tgts]));
4237                 if (!param) {
4238                         fprintf(stderr,
4239                                 "%s %s: cannot allocate memory for parameters: %s\n",
4240                                 progname, argv[0], strerror(ENOMEM));
4241                         result = -ENOMEM;
4242                         goto error;
4243                 }
4244
4245                 if (lsa.lsa_stripe_size != LLAPI_LAYOUT_DEFAULT)
4246                         param->lsp_stripe_size = lsa.lsa_stripe_size;
4247                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
4248                         if (lsa.lsa_stripe_count == LLAPI_LAYOUT_WIDE)
4249                                 param->lsp_stripe_count = -1;
4250                         else
4251                                 param->lsp_stripe_count = lsa.lsa_stripe_count;
4252                 }
4253                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4254                         param->lsp_stripe_offset = -1;
4255                 else
4256                         param->lsp_stripe_offset = lsa.lsa_stripe_off;
4257                 param->lsp_stripe_pattern =
4258                                 llapi_pattern_to_lov(lsa.lsa_pattern);
4259                 if (param->lsp_stripe_pattern == EINVAL) {
4260                         fprintf(stderr, "error: %s: invalid stripe pattern\n",
4261                                 argv[0]);
4262                         free(param);
4263                         goto usage_error;
4264                 }
4265                 param->lsp_pool = lsa.lsa_pool_name;
4266                 param->lsp_is_specific = false;
4267
4268                 if (lsa.lsa_nr_tgts > 0) {
4269                         param->lsp_is_specific = true;
4270                         param->lsp_stripe_count = lsa.lsa_nr_tgts;
4271                         memcpy(param->lsp_osts, tgts,
4272                                sizeof(*tgts) * lsa.lsa_nr_tgts);
4273                 }
4274         }
4275
4276         if (from_yaml) {
4277                 /* generate a layout from a YAML template */
4278                 result = lfs_comp_create_from_yaml(template, &layout,
4279                                                    &lsa, tgts);
4280                 if (result) {
4281                         fprintf(stderr,
4282                                 "error: %s: can't create composite layout from template file %s\n",
4283                                 argv[0], template);
4284                         goto error;
4285                 }
4286         }
4287
4288         if (layout != NULL || mirror_list != NULL) {
4289                 if (mirror_list)
4290                         result = mirror_adjust_first_extents(mirror_list);
4291                 else
4292                         result = layout_adjust_first_extent(fname, layout,
4293                                                             comp_add);
4294                 if (result == -ENODATA)
4295                         comp_add = 0;
4296                 else if (result != 0) {
4297                         fprintf(stderr, "error: %s: invalid layout\n",
4298                                 progname);
4299                         goto error;
4300                 }
4301         }
4302
4303         for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
4304                 if (from_copy) {
4305                         layout = llapi_layout_get_by_path(template ?: fname, 0);
4306                         if (!layout) {
4307                                 fprintf(stderr,
4308                                         "%s: can't create composite layout from file %s: %s\n",
4309                                         progname, template ?: fname,
4310                                         strerror(errno));
4311                                 result = -errno;
4312                                 goto error;
4313                         }
4314                 }
4315
4316                 if (migrate_mdt_mode) {
4317                         result = llapi_migrate_mdt(fname, &migrate_mdt_param);
4318                 } else if (migrate_mode) {
4319                         result = lfs_migrate(fname, migration_flags, param,
4320                                              layout);
4321                 } else if (comp_set != 0) {
4322                         result = lfs_component_set(fname, comp_id,
4323                                                    lsa.lsa_pool_name,
4324                                                    lsa.lsa_comp_flags,
4325                                                    lsa.lsa_comp_neg_flags);
4326                 } else if (comp_del != 0) {
4327                         result = lfs_component_del(fname, comp_id,
4328                                                    lsa.lsa_comp_flags,
4329                                                    lsa.lsa_comp_neg_flags);
4330                 } else if (comp_add != 0) {
4331                         result = lfs_component_add(fname, layout);
4332                 } else if (opc == SO_MIRROR_CREATE) {
4333                         result = mirror_create(fname, mirror_list);
4334                 } else if (opc == SO_MIRROR_EXTEND) {
4335                         result = mirror_extend(fname, mirror_list,
4336                                                mirror_flags);
4337                 } else if (opc == SO_MIRROR_SPLIT || opc == SO_MIRROR_DELETE) {
4338                         if (!mirror_id && !comp_id && !lsa.lsa_pool_name) {
4339                                 fprintf(stderr,
4340                                         "%s: no mirror id, component id, or pool name specified to delete from '%s'\n",
4341                                         progname, fname);
4342                                 goto usage_error;
4343                         }
4344                         if (lsa.lsa_pool_name)
4345                                 mirror_flags |= MF_COMP_POOL;
4346                         else if (mirror_id != 0)
4347                                 comp_id = mirror_id;
4348                         else
4349                                 mirror_flags |= MF_COMP_ID;
4350                         if (has_m_file && !strcmp(fname, mirror_list->m_file)) {
4351                                 fprintf(stderr,
4352                                         "%s: the file specified by -f cannot be same as the source file '%s'\n",
4353                                         progname, fname);
4354                                 goto usage_error;
4355                         }
4356                         result = mirror_split(fname, comp_id, lsa.lsa_pool_name,
4357                                               mirror_flags,
4358                                               has_m_file ? mirror_list->m_file :
4359                                               NULL);
4360                 } else if (layout) {
4361                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
4362                                                       mode, layout);
4363                         if (result >= 0) {
4364                                 close(result);
4365                                 result = 0;
4366                         }
4367                 } else if (foreign_mode) {
4368                         result = llapi_file_create_foreign(fname, mode, type,
4369                                                            flags, xattr);
4370                         if (result >= 0) {
4371                                 close(result);
4372                                 result = 0;
4373                         }
4374                 } else {
4375                         result = llapi_file_open_param(fname,
4376                                                        O_CREAT | O_WRONLY,
4377                                                        mode, param);
4378                         if (result >= 0) {
4379                                 close(result);
4380                                 result = 0;
4381                         }
4382                 }
4383                 if (result) {
4384                         /* Save the first error encountered. */
4385                         if (result2 == 0)
4386                                 result2 = result;
4387                         continue;
4388                 }
4389         }
4390
4391         if (mode_opt)
4392                 umask(previous_umask);
4393
4394         free(param);
4395         free(migrate_mdt_param.fp_lmv_md);
4396         llapi_layout_free(layout);
4397         lfs_mirror_list_free(mirror_list);
4398         return result2;
4399 usage_error:
4400         result = CMD_HELP;
4401 error:
4402         llapi_layout_free(layout);
4403         lfs_mirror_list_free(mirror_list);
4404         return result;
4405 }
4406
4407 static int lfs_poollist(int argc, char **argv)
4408 {
4409         if (argc != 2)
4410                 return CMD_HELP;
4411
4412         return llapi_poollist(argv[1]);
4413 }
4414
4415 #define FP_DEFAULT_TIME_MARGIN (24 * 60 * 60)
4416 static time_t set_time(struct find_param *param, time_t *time, time_t *set,
4417                        char *str)
4418 {
4419         long long t = 0;
4420         int sign = 0;
4421         char *endptr = "AD";
4422         char *timebuf;
4423
4424         if (str[0] == '+')
4425                 sign = 1;
4426         else if (str[0] == '-')
4427                 sign = -1;
4428
4429         if (sign)
4430                 str++;
4431
4432         for (timebuf = str; *endptr && *(endptr + 1); timebuf = endptr + 1) {
4433                 long long val = strtoll(timebuf, &endptr, 0);
4434                 int unit = 1;
4435
4436                 switch (*endptr) {
4437                 case  'y':
4438                         unit *= 52; /* 52 weeks + 1 day below */
4439                 case  'w':      /* fallthrough */
4440                         unit *= 7;
4441                         if (param->fp_time_margin == FP_DEFAULT_TIME_MARGIN)
4442                                 param->fp_time_margin *= (1 + unit / 52);
4443                         unit += (*endptr == 'y'); /* +1 day for 365 days/year */
4444                 case '\0': /* days are default unit if none used */
4445                 case  'd':      /* fallthrough */
4446                         unit *= 24;
4447                 case  'h':      /* fallthrough */
4448                         unit *= 60;
4449                 case  'm':      /* fallthrough */
4450                         unit *= 60;
4451                 case  's':      /* fallthrough */
4452                         break;
4453                         /* don't need to multiply by 1 for seconds */
4454                 default:
4455                         fprintf(stderr,
4456                                 "%s find: bad time string '%s': %s\n",
4457                                 progname, timebuf, strerror(EINVAL));
4458                         return LONG_MAX;
4459                 }
4460
4461                 if (param->fp_time_margin == 0 ||
4462                     (*endptr && unit < param->fp_time_margin))
4463                         param->fp_time_margin = unit;
4464
4465                 t += val * unit;
4466         }
4467         if (*time < t) {
4468                 if (sign != 0)
4469                         str--;
4470                 fprintf(stderr, "%s find: bad time '%s': too large\n",
4471                         progname, str);
4472                 return LONG_MAX;
4473         }
4474
4475         *set = *time - t;
4476
4477         return sign;
4478 }
4479
4480 static int str2quotaid(__u32 *id, const char *arg)
4481 {
4482         unsigned long int projid_tmp = 0;
4483         char *endptr = NULL;
4484
4485         projid_tmp = strtoul(arg, &endptr, 10);
4486         if (*endptr != '\0')
4487                 return -EINVAL;
4488         /* UINT32_MAX is not allowed - see projid_valid()/INVALID_PROJID */
4489         if (projid_tmp >= UINT32_MAX)
4490                 return -ERANGE;
4491
4492         *id = projid_tmp;
4493         return 0;
4494 }
4495
4496 static int name2uid(unsigned int *id, const char *name)
4497 {
4498         struct passwd *passwd;
4499
4500         passwd = getpwnam(name);
4501         if (!passwd)
4502                 return -ENOENT;
4503         *id = passwd->pw_uid;
4504
4505         return 0;
4506 }
4507
4508 static int name2gid(unsigned int *id, const char *name)
4509 {
4510         struct group *group;
4511
4512         group = getgrnam(name);
4513         if (!group)
4514                 return -ENOENT;
4515         *id = group->gr_gid;
4516
4517         return 0;
4518 }
4519
4520 static inline int name2projid(unsigned int *id, const char *name)
4521 {
4522         return -ENOTSUP;
4523 }
4524
4525 static int uid2name(char **name, unsigned int id)
4526 {
4527         struct passwd *passwd;
4528
4529         passwd = getpwuid(id);
4530         if (!passwd)
4531                 return -ENOENT;
4532         *name = passwd->pw_name;
4533
4534         return 0;
4535 }
4536
4537 static inline int gid2name(char **name, unsigned int id)
4538 {
4539         struct group *group;
4540
4541         group = getgrgid(id);
4542         if (!group)
4543                 return -ENOENT;
4544         *name = group->gr_name;
4545
4546         return 0;
4547 }
4548
4549 static int name2layout(__u32 *layout, char *name)
4550 {
4551         char *ptr, *layout_name;
4552
4553         *layout = 0;
4554         for (ptr = name; ; ptr = NULL) {
4555                 layout_name = strtok(ptr, ",");
4556                 if (!layout_name)
4557                         break;
4558                 if (strcmp(layout_name, "released") == 0)
4559                         *layout |= LOV_PATTERN_F_RELEASED;
4560                 else if (strcmp(layout_name, "raid0") == 0)
4561                         *layout |= LOV_PATTERN_RAID0;
4562                 else if (strcmp(layout_name, "mdt") == 0)
4563                         *layout |= LOV_PATTERN_MDT;
4564                 else if (strcmp(layout_name, "overstriping") == 0)
4565                         *layout |= LOV_PATTERN_OVERSTRIPING;
4566                 else
4567                         return -1;
4568         }
4569         return 0;
4570 }
4571
4572 static int parse_symbolic(const char *input, mode_t *outmode, const char **end)
4573 {
4574         int loop;
4575         int user, group, other;
4576         int who, all;
4577         char c, op;
4578         mode_t perm;
4579         mode_t usermask;
4580         mode_t previous_flags;
4581
4582         user = group = other = 0;
4583         all = 0;
4584         loop = 1;
4585         perm = 0;
4586         previous_flags = 0;
4587         *end = input;
4588         usermask = 0;
4589
4590         while (loop) {
4591                 switch (*input) {
4592                 case 'u':
4593                         user = 1;
4594                         break;
4595                 case 'g':
4596                         group = 1;
4597                         break;
4598                 case 'o':
4599                         other = 1;
4600                         break;
4601                 case 'a':
4602                         user = group = other = 1;
4603                         all = 1;
4604                         break;
4605                 default:
4606                         loop = 0;
4607                 }
4608
4609                 if (loop)
4610                         input++;
4611         }
4612
4613         who = user || group || other;
4614         if (!who) {
4615                 /* get the umask */
4616                 usermask = umask(0022);
4617                 umask(usermask);
4618                 usermask &= 07777;
4619         }
4620
4621         if (*input == '-' || *input == '+' || *input == '=')
4622                 op = *input++;
4623         else
4624                 /* operation is required */
4625                 return -1;
4626
4627         /* get the flags in *outmode */
4628         switch (*input) {
4629         case 'u':
4630                 previous_flags = (*outmode & 0700);
4631                 perm |= user  ? previous_flags : 0;
4632                 perm |= group ? (previous_flags >> 3) : 0;
4633                 perm |= other ? (previous_flags >> 6) : 0;
4634                 input++;
4635                 goto write_perm;
4636         case 'g':
4637                 previous_flags = (*outmode & 0070);
4638                 perm |= user  ? (previous_flags << 3) : 0;
4639                 perm |= group ? previous_flags : 0;
4640                 perm |= other ? (previous_flags >> 3) : 0;
4641                 input++;
4642                 goto write_perm;
4643         case 'o':
4644                 previous_flags = (*outmode & 0007);
4645                 perm |= user  ? (previous_flags << 6) : 0;
4646                 perm |= group ? (previous_flags << 3) : 0;
4647                 perm |= other ? previous_flags : 0;
4648                 input++;
4649                 goto write_perm;
4650         default:
4651                 break;
4652         }
4653
4654         /* this part is optional,
4655          * if empty perm = 0 and *outmode is not modified
4656          */
4657         loop = 1;
4658         while (loop) {
4659                 c = *input;
4660                 switch (c) {
4661                 case 'r':
4662                         perm |= user  ? 0400 : 0;
4663                         perm |= group ? 0040 : 0;
4664                         perm |= other ? 0004 : 0;
4665                         /* set read permission for uog except for umask's
4666                          * permissions
4667                          */
4668                         perm |= who   ? 0 : (0444 & ~usermask);
4669                         break;
4670                 case 'w':
4671                         perm |= user  ? 0200 : 0;
4672                         perm |= group ? 0020 : 0;
4673                         perm |= other ? 0002 : 0;
4674                         /* set write permission for uog except for umask'
4675                          * permissions
4676                          */
4677                         perm |= who   ? 0 : (0222 & ~usermask);
4678                         break;
4679                 case 'x':
4680                         perm |= user  ? 0100 : 0;
4681                         perm |= group ? 0010 : 0;
4682                         perm |= other ? 0001 : 0;
4683                         /* set execute permission for uog except for umask'
4684                          * permissions
4685                          */
4686                         perm |= who   ? 0 : (0111 & ~usermask);
4687                         break;
4688                 case 'X':
4689                         /*
4690                          * Adds execute permission to 'u', 'g' and/or 'g' if
4691                          * specified and either 'u', 'g' or 'o' already has
4692                          * execute permissions.
4693                          */
4694                         if ((*outmode & 0111) != 0) {
4695                                 perm |= user  ? 0100 : 0;
4696                                 perm |= group ? 0010 : 0;
4697                                 perm |= other ? 0001 : 0;
4698                                 perm |= !who  ? 0111 : 0;
4699                         }
4700                         break;
4701                 case 's':
4702                         /* s is ignored if o is given, but it's not an error */
4703                         if (other && !group && !user)
4704                                 break;
4705                         perm |= user  ? S_ISUID : 0;
4706                         perm |= group ? S_ISGID : 0;
4707                         break;
4708                 case 't':
4709                         /* 't' should be used when 'a' is given
4710                          * or who is empty
4711                          */
4712                         perm |= (!who || all) ? S_ISVTX : 0;
4713                         /* using ugo with t is not an error */
4714                         break;
4715                 default:
4716                         loop = 0;
4717                         break;
4718                 }
4719                 if (loop)
4720                         input++;
4721         }
4722
4723 write_perm:
4724         /* uog flags should be only one character long */
4725         if (previous_flags && (*input != '\0' && *input != ','))
4726                 return -1;
4727
4728         switch (op) {
4729         case '-':
4730                 /* remove the flags from outmode */
4731                 *outmode &= ~perm;
4732                 break;
4733         case '+':
4734                 /* add the flags to outmode */
4735                 *outmode |= perm;
4736                 break;
4737         case '=':
4738                 /* set the flags of outmode to perm */
4739                 if (perm != 0)
4740                         *outmode = perm;
4741                 break;
4742         }
4743
4744         *end = input;
4745         return 0;
4746 }
4747
4748 static int str2mode_t(const char *input, mode_t *outmode)
4749 {
4750         int ret;
4751         const char *iter;
4752
4753         ret = 0;
4754
4755         if (*input >= '0' && *input <= '7') {
4756                 /* parse octal representation */
4757                 char *end;
4758
4759                 iter = input;
4760
4761                 /* look for invalid digits in octal representation */
4762                 while (isdigit(*iter))
4763                         if (*iter++ > '7')
4764                                 return -1;
4765
4766                 errno = 0;
4767                 *outmode = strtoul(input, &end, 8);
4768
4769                 if (errno != 0 || *outmode > 07777) {
4770                         *outmode = 0;
4771                         ret = -1;
4772                 }
4773
4774         } else if (*input == '8' || *input == '9') {
4775                 /* error: invalid octal number */
4776                 ret = -1;
4777         } else {
4778                 /* parse coma seperated list of symbolic representation */
4779                 int rc;
4780                 const char *end;
4781
4782                 *outmode = 0;
4783                 rc = 0;
4784                 end = NULL;
4785
4786                 do {
4787                         rc = parse_symbolic(input, outmode, &end);
4788                         if (rc)
4789                                 return -1;
4790
4791                         input = end+1;
4792                 } while (*end == ',');
4793
4794                 if (*end != '\0')
4795                         ret = -1;
4796         }
4797         return ret;
4798 }
4799
4800 static int lfs_find(int argc, char **argv)
4801 {
4802         int c, rc;
4803         int ret = 0;
4804         time_t t;
4805         struct find_param param = {
4806                 .fp_max_depth = -1,
4807                 .fp_quiet = 1,
4808                 .fp_time_margin = FP_DEFAULT_TIME_MARGIN,
4809         };
4810         struct option long_opts[] = {
4811         { .val = 'A',   .name = "atime",        .has_arg = required_argument },
4812         { .val = 'b',   .name = "blocks",       .has_arg = required_argument },
4813         { .val = 'B',   .name = "btime",        .has_arg = required_argument },
4814         { .val = 'B',   .name = "Btime",        .has_arg = required_argument },
4815         { .val = LFS_COMP_COUNT_OPT,
4816                         .name = "comp-count",   .has_arg = required_argument },
4817         { .val = LFS_COMP_COUNT_OPT,
4818                         .name = "component-count",
4819                                                 .has_arg = required_argument },
4820         { .val = LFS_COMP_FLAGS_OPT,
4821                         .name = "comp-flags",   .has_arg = required_argument },
4822         { .val = LFS_COMP_FLAGS_OPT,
4823                         .name = "component-flags",
4824                                                 .has_arg = required_argument },
4825         { .val = LFS_COMP_START_OPT,
4826                         .name = "comp-start",   .has_arg = required_argument },
4827         { .val = LFS_COMP_START_OPT,
4828                         .name = "component-start",
4829                                                 .has_arg = required_argument },
4830         { .val = LFS_MIRROR_STATE_OPT,
4831                         .name = "mirror-state", .has_arg = required_argument },
4832         { .val = LFS_NEWERXY_OPT,
4833                         .name = "newer",        .has_arg = required_argument},
4834         { .val = LFS_NEWERXY_OPT,
4835                         .name = "neweraa",      .has_arg = required_argument},
4836         { .val = LFS_NEWERXY_OPT,
4837                         .name = "neweram",      .has_arg = required_argument},
4838         { .val = LFS_NEWERXY_OPT,
4839                         .name = "newerac",      .has_arg = required_argument},
4840         { .val = LFS_NEWERXY_OPT,
4841                         .name = "newerab",      .has_arg = required_argument},
4842         { .val = LFS_NEWERXY_OPT,
4843                         .name = "newerma",      .has_arg = required_argument},
4844         { .val = LFS_NEWERXY_OPT,
4845                         .name = "newermm",      .has_arg = required_argument},
4846         { .val = LFS_NEWERXY_OPT,
4847                         .name = "newermc",      .has_arg = required_argument},
4848         { .val = LFS_NEWERXY_OPT,
4849                         .name = "newermb",      .has_arg = required_argument},
4850         { .val = LFS_NEWERXY_OPT,
4851                         .name = "newerca",      .has_arg = required_argument},
4852         { .val = LFS_NEWERXY_OPT,
4853                         .name = "newercm",      .has_arg = required_argument},
4854         { .val = LFS_NEWERXY_OPT,
4855                         .name = "newercc",      .has_arg = required_argument},
4856         { .val = LFS_NEWERXY_OPT,
4857                         .name = "newercb",      .has_arg = required_argument},
4858         { .val = LFS_NEWERXY_OPT,
4859                         .name = "newerba",      .has_arg = required_argument},
4860         { .val = LFS_NEWERXY_OPT,
4861                         .name = "newerbm",      .has_arg = required_argument},
4862         { .val = LFS_NEWERXY_OPT,
4863                         .name = "newerbc",      .has_arg = required_argument},
4864         { .val = LFS_NEWERXY_OPT,
4865                         .name = "newerbb",      .has_arg = required_argument},
4866         { .val = LFS_NEWERXY_OPT,
4867                         .name = "newerBa",      .has_arg = required_argument},
4868         { .val = LFS_NEWERXY_OPT,
4869                         .name = "newerBm",      .has_arg = required_argument},
4870         { .val = LFS_NEWERXY_OPT,
4871                         .name = "newerBc",      .has_arg = required_argument},
4872         { .val = LFS_NEWERXY_OPT,
4873                         .name = "newerBB",      .has_arg = required_argument},
4874         { .val = LFS_NEWERXY_OPT,
4875                         .name = "newerat",      .has_arg = required_argument},
4876         { .val = LFS_NEWERXY_OPT,
4877                         .name = "newermt",      .has_arg = required_argument},
4878         { .val = LFS_NEWERXY_OPT,
4879                         .name = "newerct",      .has_arg = required_argument},
4880         { .val = LFS_NEWERXY_OPT,
4881                         .name = "newerbt",      .has_arg = required_argument},
4882         { .val = LFS_NEWERXY_OPT,
4883                         .name = "newerBt",      .has_arg = required_argument},
4884         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument },
4885         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument },
4886         { .val = 'C',   .name = "ctime",        .has_arg = required_argument },
4887 /* getstripe { .val = 'd', .name = "directory", .has_arg = no_argument }, */
4888         { .val = 'D',   .name = "maxdepth",     .has_arg = required_argument },
4889         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument },
4890         { .val = 'E',   .name = "component-end",
4891                                                 .has_arg = required_argument },
4892 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
4893         { .val = LFS_LAYOUT_FOREIGN_OPT,
4894                         .name = "foreign",      .has_arg = optional_argument},
4895         { .val = 'g',   .name = "gid",          .has_arg = required_argument },
4896         { .val = 'G',   .name = "group",        .has_arg = required_argument },
4897         { .val = 'h',   .name = "help",         .has_arg = no_argument },
4898         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
4899         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument },
4900         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument },
4901 /* getstripe { .val = 'I', .name = "comp-id",   .has_arg = required_argument }*/
4902         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
4903         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
4904         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
4905         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
4906         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument },
4907         { .val = 'M',   .name = "mtime",        .has_arg = required_argument },
4908         { .val = 'n',   .name = "name",         .has_arg = required_argument },
4909         { .val = 'N',   .name = "mirror-count", .has_arg = required_argument },
4910 /* find { .val = 'o'    .name = "or", .has_arg = no_argument }, like find(1) */
4911         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
4912         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
4913         /* no short option for pool yet, can be 'p' after 2.18 */
4914         { .val = LFS_POOL_OPT,
4915                         .name = "pool",         .has_arg = required_argument },
4916         { .val = '0',   .name = "print0",       .has_arg = no_argument },
4917         { .val = 'P',   .name = "print",        .has_arg = no_argument },
4918         { .val = LFS_PROJID_OPT,
4919                         .name = "projid",       .has_arg = required_argument },
4920 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
4921 /* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
4922 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
4923         { .val = 's',   .name = "size",         .has_arg = required_argument },
4924         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
4925         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
4926         { .val = 't',   .name = "type",         .has_arg = required_argument },
4927         { .val = LFS_FIND_PERM,
4928                         .name = "perm",         .has_arg = required_argument },
4929         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
4930         { .val = 'u',   .name = "uid",          .has_arg = required_argument },
4931         { .val = 'U',   .name = "user",         .has_arg = required_argument },
4932         { .val = 'z',   .name = "extension-size",
4933                                                 .has_arg = required_argument },
4934         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument },
4935 /* getstripe { .val = 'v', .name = "verbose",   .has_arg = no_argument }, */
4936 /* getstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
4937         { .name = NULL } };
4938         int optidx = 0;
4939         int pathstart = -1;
4940         int pathend = -1;
4941         int pathbad = -1;
4942         int neg_opt = 0;
4943         time_t *xtime;
4944         int *xsign;
4945         int isoption;
4946         char *endptr;
4947
4948         time(&t);
4949
4950         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
4951         while ((c = getopt_long_only(argc, argv,
4952                 "-0A:b:B:c:C:D:E:g:G:hH:i:L:m:M:n:N:O:Ppqrs:S:t:T:u:U:vz:",
4953                 long_opts, &optidx)) >= 0) {
4954                 xtime = NULL;
4955                 xsign = NULL;
4956                 if (neg_opt)
4957                         --neg_opt;
4958                 /* '!' is part of option */
4959                 /*
4960                  * when getopt_long_only() finds a string which is not
4961                  * an option nor a known option argument it returns 1
4962                  * in that case if we already have found pathstart and pathend
4963                  * (i.e. we have the list of pathnames),
4964                  * the only supported value is "!"
4965                  */
4966                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
4967                 if (!isoption && pathend != -1) {
4968                         fprintf(stderr,
4969                                 "err: %s: filename|dirname must either precede options or follow options\n",
4970                                 argv[0]);
4971                         ret = CMD_HELP;
4972                         goto err;
4973                 }
4974                 if (!isoption && pathstart == -1)
4975                         pathstart = optind - 1;
4976                 if (isoption && pathstart != -1 && pathend == -1)
4977                         pathend = optind - 2;
4978                 switch (c) {
4979                 case 0:
4980                         /* Long options. */
4981                         break;
4982                 case 1:
4983                         /*
4984                          * unknown; opt is "!" or path component,
4985                          * checking done above.
4986                          */
4987                         if (strcmp(optarg, "!") == 0)
4988                                 neg_opt = 2;
4989                         break;
4990                 case 'A':
4991                         xtime = &param.fp_atime;
4992                         xsign = &param.fp_asign;
4993                         param.fp_exclude_atime = !!neg_opt;
4994                         /* no break, this falls through to 'B' for btime */
4995                 case 'B':
4996                         if (c == 'B') {
4997                                 xtime = &param.fp_btime;
4998                                 xsign = &param.fp_bsign;
4999                                 param.fp_exclude_btime = !!neg_opt;
5000                         }
5001                         /* no break, this falls through to 'C' for ctime */
5002                 case 'C':
5003                         if (c == 'C') {
5004                                 xtime = &param.fp_ctime;
5005                                 xsign = &param.fp_csign;
5006                                 param.fp_exclude_ctime = !!neg_opt;
5007                         }
5008                         /* no break, this falls through to 'M' for mtime */
5009                 case 'M':
5010                         if (c == 'M') {
5011                                 xtime = &param.fp_mtime;
5012                                 xsign = &param.fp_msign;
5013                                 param.fp_exclude_mtime = !!neg_opt;
5014                         }
5015                         rc = set_time(&param, &t, xtime, optarg);
5016                         if (rc == LONG_MAX) {
5017                                 ret = -1;
5018                                 goto err;
5019                         }
5020                         if (rc)
5021                                 *xsign = rc;
5022                         break;
5023                 case 'b':
5024                         if (optarg[0] == '+') {
5025                                 param.fp_blocks_sign = -1;
5026                                 optarg++;
5027                         } else if (optarg[0] == '-') {
5028                                 param.fp_blocks_sign =  1;
5029                                 optarg++;
5030                         }
5031
5032                         param.fp_blocks_units = 1024;
5033                         ret = llapi_parse_size(optarg, &param.fp_blocks,
5034                                                &param.fp_blocks_units, 0);
5035                         if (ret) {
5036                                 fprintf(stderr, "error: bad blocks '%s'\n",
5037                                         optarg);
5038                                 goto err;
5039                         }
5040                         param.fp_check_blocks = 1;
5041                         param.fp_exclude_blocks = !!neg_opt;
5042                         break;
5043                 case LFS_COMP_COUNT_OPT:
5044                         if (optarg[0] == '+') {
5045                                 param.fp_comp_count_sign = -1;
5046                                 optarg++;
5047                         } else if (optarg[0] == '-') {
5048                                 param.fp_comp_count_sign =  1;
5049                                 optarg++;
5050                         }
5051
5052                         errno = 0;
5053                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
5054                         if (errno != 0 || *endptr != '\0' ||
5055                             param.fp_comp_count > UINT32_MAX) {
5056                                 fprintf(stderr,
5057                                         "error: bad component count '%s'\n",
5058                                         optarg);
5059                                 goto err;
5060                         }
5061                         param.fp_check_comp_count = 1;
5062                         param.fp_exclude_comp_count = !!neg_opt;
5063                         break;
5064                 case LFS_COMP_FLAGS_OPT:
5065                         rc = comp_str2flags(optarg, &param.fp_comp_flags,
5066                                             &param.fp_comp_neg_flags);
5067                         if (rc) {
5068                                 fprintf(stderr,
5069                                         "error: bad component flags '%s'\n",
5070                                         optarg);
5071                                 goto err;
5072                         }
5073                         param.fp_check_comp_flags = 1;
5074                         if (neg_opt) {
5075                                 __u32 flags = param.fp_comp_neg_flags;
5076
5077                                 param.fp_comp_neg_flags = param.fp_comp_flags;
5078                                 param.fp_comp_flags = flags;
5079                         }
5080                         break;
5081                 case LFS_COMP_START_OPT:
5082                         if (optarg[0] == '+') {
5083                                 param.fp_comp_start_sign = -1;
5084                                 optarg++;
5085                         } else if (optarg[0] == '-') {
5086                                 param.fp_comp_start_sign =  1;
5087                                 optarg++;
5088                         }
5089
5090                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
5091                                               &param.fp_comp_start_units, 0);
5092                         if (rc) {
5093                                 fprintf(stderr,
5094                                         "error: bad component start '%s'\n",
5095                                         optarg);
5096                                 goto err;
5097                         }
5098                         param.fp_check_comp_start = 1;
5099                         param.fp_exclude_comp_start = !!neg_opt;
5100                         break;
5101                 case LFS_MIRROR_STATE_OPT:
5102                         rc = mirror_str2state(optarg, &param.fp_mirror_state,
5103                                               &param.fp_mirror_neg_state);
5104                         if (rc) {
5105                                 fprintf(stderr,
5106                                         "error: bad mirrored file state '%s'\n",
5107                                         optarg);
5108                                 goto err;
5109                         }
5110                         param.fp_check_mirror_state = 1;
5111                         if (neg_opt) {
5112                                 __u16 state = param.fp_mirror_neg_state;
5113
5114                                 param.fp_mirror_neg_state =
5115                                         param.fp_mirror_state;
5116                                 param.fp_mirror_state = state;
5117                         }
5118                         break;
5119                 case 'c':
5120                         if (optarg[0] == '+') {
5121                                 param.fp_stripe_count_sign = -1;
5122                                 optarg++;
5123                         } else if (optarg[0] == '-') {
5124                                 param.fp_stripe_count_sign =  1;
5125                                 optarg++;
5126                         }
5127
5128                         errno = 0;
5129                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
5130                         if (errno != 0 || *endptr != '\0' ||
5131                             param.fp_stripe_count > LOV_MAX_STRIPE_COUNT) {
5132                                 fprintf(stderr,
5133                                         "error: bad stripe_count '%s'\n",
5134                                         optarg);
5135                                 ret = -1;
5136                                 goto err;
5137                         }
5138                         param.fp_check_stripe_count = 1;
5139                         param.fp_exclude_stripe_count = !!neg_opt;
5140                         break;
5141                 case 'D':
5142                         errno = 0;
5143                         param.fp_max_depth = strtol(optarg, 0, 0);
5144                         if (errno != 0 || param.fp_max_depth < 0) {
5145                                 fprintf(stderr,
5146                                         "error: bad maxdepth '%s'\n",
5147                                         optarg);
5148                                 ret = -1;
5149                                 goto err;
5150                         }
5151                         break;
5152                 case 'E':
5153                         if (optarg[0] == '+') {
5154                                 param.fp_comp_end_sign = -1;
5155                                 optarg++;
5156                         } else if (optarg[0] == '-') {
5157                                 param.fp_comp_end_sign =  1;
5158                                 optarg++;
5159                         }
5160
5161                         if (arg_is_eof(optarg)) {
5162                                 param.fp_comp_end = LUSTRE_EOF;
5163                                 param.fp_comp_end_units = 1;
5164                                 rc = 0;
5165                         } else {
5166                                 rc = llapi_parse_size(optarg,
5167                                                 &param.fp_comp_end,
5168                                                 &param.fp_comp_end_units, 0);
5169                                 /* assume units of KB if too small */
5170                                 if (param.fp_comp_end < 4096)
5171                                         param.fp_comp_end *= 1024;
5172                         }
5173                         if (rc) {
5174                                 fprintf(stderr,
5175                                         "error: bad component end '%s'\n",
5176                                         optarg);
5177                                 goto err;
5178                         }
5179                         param.fp_check_comp_end = 1;
5180                         param.fp_exclude_comp_end = !!neg_opt;
5181                         break;
5182                 case LFS_LAYOUT_FOREIGN_OPT: {
5183                         /* all types by default */
5184                         uint32_t type = LU_FOREIGN_TYPE_UNKNOWN;
5185
5186                         if (optarg) {
5187                                 /* check pure numeric */
5188                                 type = strtoul(optarg, &endptr, 0);
5189                                 if (*endptr) {
5190                                         /* check name */
5191                                         type = check_foreign_type_name(optarg);
5192                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
5193                                                 fprintf(stderr,
5194                                                         "%s %s: unknown foreign type '%s'\n",
5195                                                         progname, argv[0],
5196                                                         optarg);
5197                                                 return CMD_HELP;
5198                                         }
5199                                 } else if (type >= UINT32_MAX) {
5200                                         fprintf(stderr,
5201                                                 "%s %s: invalid foreign type '%s'\n",
5202                                                 progname, argv[0], optarg);
5203                                         return CMD_HELP;
5204                                 }
5205                         }
5206                         param.fp_foreign_type = type;
5207                         param.fp_check_foreign = 1;
5208                         param.fp_exclude_foreign = !!neg_opt;
5209                         break;
5210                 }
5211                 case LFS_NEWERXY_OPT: {
5212                         char x = 'm';
5213                         char y = 'm';
5214                         int xidx;
5215                         int negidx;
5216                         time_t *newery;
5217                         time_t ref = time(NULL);
5218
5219                         /* no need to check bad options, they won't get here */
5220                         if (strlen(long_opts[optidx].name) == 7) {
5221                                 x = long_opts[optidx].name[5];
5222                                 y = long_opts[optidx].name[6];
5223                         }
5224
5225                         if (y == 't') {
5226                                 static const char *const fmts[] = {
5227                                         "%Y-%m-%d %H:%M:%S",
5228                                         "%Y-%m-%d %H:%M",
5229                                         "%Y-%m-%d",
5230                                         "%H:%M:%S", /* sometime today */
5231                                         "%H:%M",
5232                                         "@%s",
5233                                         "%s",
5234                                         NULL };
5235                                 struct tm tm;
5236                                 bool found = false;
5237                                 int i;
5238
5239                                 for (i = 0; fmts[i] != NULL; i++) {
5240                                         char *ptr;
5241
5242                                         /* Init for times relative to today */
5243                                         if (strncmp(fmts[i], "%H", 2) == 0)
5244                                                 localtime_r(&ref, &tm);
5245                                         else
5246                                                 memset(&tm, 0, sizeof(tm));
5247                                         ptr = strptime(optarg, fmts[i], &tm);
5248                                         /* Skip spaces */
5249                                         while (ptr && isspace(*ptr))
5250                                                 ptr++;
5251                                         if (ptr == optarg + strlen(optarg)) {
5252                                                 found = true;
5253                                                 break;
5254                                         }
5255                                 }
5256
5257                                 if (!found) {
5258                                         fprintf(stderr,
5259                                                 "%s: invalid time '%s'\n",
5260                                                 progname, optarg);
5261                                         fprintf(stderr,
5262                                                 "supported formats are:\n  ");
5263                                         for (i = 0; fmts[i] != NULL; i++)
5264                                                 fprintf(stderr, "'%s', ",
5265                                                         fmts[i]);
5266                                         fprintf(stderr, "\n");
5267                                         ret = -EINVAL;
5268                                         goto err;
5269                                 }
5270
5271                                 ref = mktime(&tm);
5272                         } else if (y == 'b' || y == 'B') {
5273                                 lstatx_t stx;
5274
5275                                 rc = llapi_get_lum_file(optarg, NULL, &stx,
5276                                                         NULL, 0);
5277                                 if (rc || !(stx.stx_mask & STATX_BTIME)) {
5278                                         if (!(stx.stx_mask & STATX_BTIME))
5279                                                 ret = -EOPNOTSUPP;
5280                                         else
5281                                                 ret = -errno;
5282                                         fprintf(stderr,
5283                                                 "%s: get btime failed '%s': %s\n",
5284                                                 progname, optarg,
5285                                                 strerror(-ret));
5286                                         goto err;
5287                                 }
5288
5289                                 ref = stx.stx_btime.tv_sec;
5290                         } else {
5291                                 struct stat statbuf;
5292
5293                                 if (stat(optarg, &statbuf) < 0) {
5294                                         fprintf(stderr,
5295                                                 "%s: cannot stat file '%s': %s\n",
5296                                                 progname, optarg,
5297                                                 strerror(errno));
5298                                         ret = -errno;
5299                                         goto err;
5300                                 }
5301
5302                                 switch (y) {
5303                                 case 'a':
5304                                         ref = statbuf.st_atime;
5305                                         break;
5306                                 case 'm':
5307                                         ref = statbuf.st_mtime;
5308                                         break;
5309                                 case 'c':
5310                                         ref = statbuf.st_ctime;
5311                                         break;
5312                                 default:
5313                                         fprintf(stderr,
5314                                                 "%s: invalid Y argument: '%c'\n",
5315                                                 progname, x);
5316                                         ret = -EINVAL;
5317                                         goto err;
5318                                 }
5319                         }
5320
5321                         switch (x) {
5322                         case 'a':
5323                                 xidx = NEWERXY_ATIME;
5324                                 break;
5325                         case 'm':
5326                                 xidx = NEWERXY_MTIME;
5327                                 break;
5328                         case 'c':
5329                                 xidx = NEWERXY_CTIME;
5330                                 break;
5331                         case 'b':
5332                         case 'B':
5333                                 xidx = NEWERXY_BTIME;
5334                                 break;
5335                         default:
5336                                 fprintf(stderr,
5337                                         "%s: invalid X argument: '%c'\n",
5338                                         progname, x);
5339                                 ret = -EINVAL;
5340                                 goto err;
5341                         }
5342
5343                         negidx = !!neg_opt;
5344                         newery = &param.fp_newery[xidx][negidx];
5345
5346                         if (*newery == 0) {
5347                                 *newery = ref;
5348                         } else {
5349                                 if (negidx)
5350                                         *newery = *newery > ref ? ref : *newery;
5351                                 else
5352                                         *newery = *newery > ref ? *newery : ref;
5353                         }
5354                         param.fp_newerxy = 1;
5355                         break;
5356                 }
5357                 case 'g':
5358                 case 'G':
5359                         rc = name2gid(&param.fp_gid, optarg);
5360                         if (rc) {
5361                                 if (str2quotaid(&param.fp_gid, optarg)) {
5362                                         fprintf(stderr,
5363                                                 "Group/GID: %s cannot be found.\n",
5364                                                 optarg);
5365                                         ret = -1;
5366                                         goto err;
5367                                 }
5368                         }
5369                         param.fp_exclude_gid = !!neg_opt;
5370                         param.fp_check_gid = 1;
5371                         break;
5372                 case 'H':
5373                         rc = mdthash_input(optarg, &param.fp_hash_inflags,
5374                                            &param.fp_hash_exflags,
5375                                            &param.fp_hash_type);
5376                         if (rc) {
5377                                 ret = -1;
5378                                 goto err;
5379                         }
5380                         if (param.fp_hash_inflags || param.fp_hash_exflags)
5381                                 param.fp_check_hash_flag = 1;
5382                         param.fp_exclude_hash_type = !!neg_opt;
5383                         break;
5384                 case 'l':
5385                         param.fp_lazy = 1;
5386                         break;
5387                 case 'L':
5388                         ret = name2layout(&param.fp_layout, optarg);
5389                         if (ret)
5390                                 goto err;
5391                         param.fp_exclude_layout = !!neg_opt;
5392                         param.fp_check_layout = 1;
5393                         break;
5394                 case 'u':
5395                 case 'U':
5396                         rc = name2uid(&param.fp_uid, optarg);
5397                         if (rc) {
5398                                 if (str2quotaid(&param.fp_uid, optarg)) {
5399                                         fprintf(stderr,
5400                                                 "User/UID: %s cannot be found.\n",
5401                                                 optarg);
5402                                         ret = -1;
5403                                         goto err;
5404                                 }
5405                         }
5406                         param.fp_exclude_uid = !!neg_opt;
5407                         param.fp_check_uid = 1;
5408                         break;
5409                 case 'n':
5410                         param.fp_pattern = (char *)optarg;
5411                         param.fp_exclude_pattern = !!neg_opt;
5412                         break;
5413                 case 'N':
5414                         if (optarg[0] == '+') {
5415                                 param.fp_mirror_count_sign = -1;
5416                                 optarg++;
5417                         } else if (optarg[0] == '-') {
5418                                 param.fp_mirror_count_sign =  1;
5419                                 optarg++;
5420                         }
5421
5422                         errno = 0;
5423                         param.fp_mirror_count = strtoul(optarg, &endptr, 0);
5424                         if (errno != 0 || *endptr != '\0' ||
5425                             param.fp_mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
5426                                 fprintf(stderr,
5427                                         "error: bad mirror count '%s'\n",
5428                                         optarg);
5429                                 goto err;
5430                         }
5431                         param.fp_check_mirror_count = 1;
5432                         param.fp_exclude_mirror_count = !!neg_opt;
5433                         break;
5434                 case 'm':
5435                 case 'i':
5436                 case 'O': {
5437                         char *buf, *token, *next, *p;
5438                         int len = 1;
5439                         void *tmp;
5440
5441                         buf = strdup(optarg);
5442                         if (!buf) {
5443                                 ret = -ENOMEM;
5444                                 goto err;
5445                         }
5446
5447                         param.fp_exclude_obd = !!neg_opt;
5448
5449                         token = buf;
5450                         while (token && *token) {
5451                                 token = strchr(token, ',');
5452                                 if (token) {
5453                                         len++;
5454                                         token++;
5455                                 }
5456                         }
5457                         if (c == 'm') {
5458                                 param.fp_exclude_mdt = !!neg_opt;
5459                                 param.fp_num_alloc_mdts += len;
5460                                 tmp = realloc(param.fp_mdt_uuid,
5461                                               param.fp_num_alloc_mdts *
5462                                               sizeof(*param.fp_mdt_uuid));
5463                                 if (!tmp) {
5464                                         ret = -ENOMEM;
5465                                         goto err_free;
5466                                 }
5467
5468                                 param.fp_mdt_uuid = tmp;
5469                         } else {
5470                                 param.fp_exclude_obd = !!neg_opt;
5471                                 param.fp_num_alloc_obds += len;
5472                                 tmp = realloc(param.fp_obd_uuid,
5473                                               param.fp_num_alloc_obds *
5474                                               sizeof(*param.fp_obd_uuid));
5475                                 if (!tmp) {
5476                                         ret = -ENOMEM;
5477                                         goto err_free;
5478                                 }
5479
5480                                 param.fp_obd_uuid = tmp;
5481                         }
5482                         for (token = buf; token && *token; token = next) {
5483                                 struct obd_uuid *puuid;
5484
5485                                 if (c == 'm') {
5486                                         puuid =
5487                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
5488                                 } else {
5489                                         puuid =
5490                                         &param.fp_obd_uuid[param.fp_num_obds++];
5491                                 }
5492                                 p = strchr(token, ',');
5493                                 next = 0;
5494                                 if (p) {
5495                                         *p = 0;
5496                                         next = p+1;
5497                                 }
5498
5499                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
5500                                         ret = -E2BIG;
5501                                         goto err_free;
5502                                 }
5503
5504                                 strncpy(puuid->uuid, token,
5505                                         sizeof(puuid->uuid));
5506                         }
5507 err_free:
5508                         if (buf)
5509                                 free(buf);
5510                         break;
5511                 }
5512 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 18, 53, 0)
5513                 case 'p':
5514 #endif
5515                 case LFS_POOL_OPT:
5516                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
5517                                 fprintf(stderr,
5518                                         "Pool name %s is too long (max %d)\n",
5519                                         optarg, LOV_MAXPOOLNAME);
5520                                 ret = -1;
5521                                 goto err;
5522                         }
5523                         /*
5524                          * We do check for empty pool because empty pool
5525                          * is used to find V1 LOV attributes
5526                          */
5527                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
5528                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
5529                         param.fp_exclude_pool = !!neg_opt;
5530                         param.fp_check_pool = 1;
5531                         break;
5532 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 14, 53, 0)
5533                 case 'p': /* want this for --pool, to match getstripe/find */
5534                         fprintf(stderr,
5535                                 "warning: -p deprecated, use --print0 or -0\n");
5536 #endif
5537                 case '0':
5538                         param.fp_zero_end = 1;
5539                         break;
5540                 case 'P': /* we always print, this option is a no-op */
5541                         break;
5542                 case LFS_PROJID_OPT:
5543                         rc = name2projid(&param.fp_projid, optarg);
5544                         if (rc) {
5545                                 if (str2quotaid(&param.fp_projid, optarg)) {
5546                                         fprintf(stderr,
5547                                                 "Invalid project ID: %s\n",
5548                                                 optarg);
5549                                         ret = -1;
5550                                         goto err;
5551                                 }
5552                         }
5553                         param.fp_exclude_projid = !!neg_opt;
5554                         param.fp_check_projid = 1;
5555                         break;
5556                 case 's':
5557                         if (optarg[0] == '+') {
5558                                 param.fp_size_sign = -1;
5559                                 optarg++;
5560                         } else if (optarg[0] == '-') {
5561                                 param.fp_size_sign =  1;
5562                                 optarg++;
5563                         }
5564
5565                         ret = llapi_parse_size(optarg, &param.fp_size,
5566                                                &param.fp_size_units, 0);
5567                         if (ret) {
5568                                 fprintf(stderr, "error: bad file size '%s'\n",
5569                                         optarg);
5570                                 goto err;
5571                         }
5572                         param.fp_check_size = 1;
5573                         param.fp_exclude_size = !!neg_opt;
5574                         break;
5575                 case 'S':
5576                         if (optarg[0] == '+') {
5577                                 param.fp_stripe_size_sign = -1;
5578                                 optarg++;
5579                         } else if (optarg[0] == '-') {
5580                                 param.fp_stripe_size_sign =  1;
5581                                 optarg++;
5582                         }
5583
5584                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
5585                                                &param.fp_stripe_size_units, 0);
5586                         /* assume units of KB if too small to be valid */
5587                         if (param.fp_stripe_size < 4096)
5588                                 param.fp_stripe_size *= 1024;
5589                         if (ret) {
5590                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
5591                                         optarg);
5592                                 goto err;
5593                         }
5594                         param.fp_check_stripe_size = 1;
5595                         param.fp_exclude_stripe_size = !!neg_opt;
5596                         break;
5597                 case 't':
5598                         param.fp_exclude_type = !!neg_opt;
5599                         switch (optarg[0]) {
5600                         case 'b':
5601                                 param.fp_type = S_IFBLK;
5602                                 break;
5603                         case 'c':
5604                                 param.fp_type = S_IFCHR;
5605                                 break;
5606                         case 'd':
5607                                 param.fp_type = S_IFDIR;
5608                                 break;
5609                         case 'f':
5610                                 param.fp_type = S_IFREG;
5611                                 break;
5612                         case 'l':
5613                                 param.fp_type = S_IFLNK;
5614                                 break;
5615                         case 'p':
5616                                 param.fp_type = S_IFIFO;
5617                                 break;
5618                         case 's':
5619                                 param.fp_type = S_IFSOCK;
5620                                 break;
5621                         default:
5622                                 fprintf(stderr, "%s: bad type '%s'\n",
5623                                         progname, optarg);
5624                                 ret = CMD_HELP;
5625                                 goto err;
5626                         }
5627                         break;
5628                 case LFS_FIND_PERM:
5629                         param.fp_exclude_perm = !!neg_opt;
5630                         param.fp_perm_sign = LFS_FIND_PERM_EXACT;
5631                         if (*optarg == '/') {
5632                                 param.fp_perm_sign = LFS_FIND_PERM_ANY;
5633                                 optarg++;
5634                         } else if (*optarg == '-') {
5635                                 param.fp_perm_sign = LFS_FIND_PERM_ALL;
5636                                 optarg++;
5637                         }
5638
5639                         if (str2mode_t(optarg, &param.fp_perm)) {
5640                                 fprintf(stderr, "error: invalid mode '%s'\n",
5641                                         optarg);
5642                                 ret = -1;
5643                                 goto err;
5644                         }
5645                         break;
5646                 case 'T':
5647                         if (optarg[0] == '+') {
5648                                 param.fp_mdt_count_sign = -1;
5649                                 optarg++;
5650                         } else if (optarg[0] == '-') {
5651                                 param.fp_mdt_count_sign =  1;
5652                                 optarg++;
5653                         }
5654
5655                         errno = 0;
5656                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
5657                         if (errno != 0 || *endptr != '\0' ||
5658                             param.fp_mdt_count >= UINT32_MAX) {
5659                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
5660                                         optarg);
5661                                 ret = -1;
5662                                 goto err;
5663                         }
5664                         param.fp_check_mdt_count = 1;
5665                         param.fp_exclude_mdt_count = !!neg_opt;
5666                         break;
5667                 case 'z':
5668                         if (optarg[0] == '+') {
5669                                 param.fp_ext_size_sign = -1;
5670                                 optarg++;
5671                         } else if (optarg[0] == '-') {
5672                                 param.fp_ext_size_sign =  1;
5673                                 optarg++;
5674                         }
5675
5676                         ret = llapi_parse_size(optarg, &param.fp_ext_size,
5677                                                &param.fp_ext_size_units, 0);
5678                         if (ret) {
5679                                 fprintf(stderr, "error: bad ext-size '%s'\n",
5680                                         optarg);
5681                                 goto err;
5682                         }
5683                         param.fp_ext_size /= SEL_UNIT_SIZE;
5684                         param.fp_ext_size_units /= SEL_UNIT_SIZE;
5685                         param.fp_check_ext_size = 1;
5686                         param.fp_exclude_ext_size = !!neg_opt;
5687                         break;
5688                 default:
5689                         fprintf(stderr, "%s: unrecognized option '%s'\n",
5690                                 progname, argv[optind - 1]);
5691                 case 'h':
5692                         ret = CMD_HELP;
5693                         goto err;
5694                 }
5695         }
5696
5697         if (pathstart == -1) {
5698                 fprintf(stderr, "error: %s: no filename|pathname\n",
5699                         argv[0]);
5700                 ret = CMD_HELP;
5701                 goto err;
5702         } else if (pathend == -1) {
5703                 /* no options */
5704                 pathend = argc;
5705         }
5706
5707         do {
5708                 rc = llapi_find(argv[pathstart], &param);
5709                 if (rc && !ret) {
5710                         ret = rc;
5711                         pathbad = pathstart;
5712                 }
5713         } while (++pathstart < pathend);
5714
5715         if (ret)
5716                 fprintf(stderr, "%s: failed for '%s': %s\n",
5717                         progname, argv[pathbad], strerror(-rc));
5718
5719 err:
5720         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
5721                 free(param.fp_obd_uuid);
5722
5723         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
5724                 free(param.fp_mdt_uuid);
5725
5726         return ret;
5727 }
5728
5729 static int lfs_getstripe_internal(int argc, char **argv,
5730                                   struct find_param *param)
5731 {
5732         struct option long_opts[] = {
5733 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
5734 /* find { .val = 'b',   .name = "blocks",       .has_arg = required_argument }*/
5735 /* find { .val = 'B',   .name = "btime",        .has_arg = required_argument }*/
5736 /* find { .val = 'B',   .name = "Btime",        .has_arg = required_argument }*/
5737         { .val = LFS_COMP_COUNT_OPT,
5738                         .name = "comp-count",   .has_arg = no_argument },
5739         { .val = LFS_COMP_COUNT_OPT,
5740                 .name = "component-count",      .has_arg = no_argument },
5741         { .val = LFS_COMP_FLAGS_OPT,
5742                         .name = "comp-flags",   .has_arg = optional_argument },
5743         { .val = LFS_COMP_FLAGS_OPT,
5744                 .name = "component-flags",      .has_arg = optional_argument },
5745         { .val = LFS_COMP_START_OPT,
5746                         .name = "comp-start",   .has_arg = optional_argument },
5747         { .val = LFS_COMP_START_OPT,
5748                 .name = "component-start",      .has_arg = optional_argument },
5749         { .val = LFS_MIRROR_INDEX_OPT,
5750                 .name = "mirror-index",         .has_arg = required_argument },
5751         { .val = LFS_MIRROR_ID_OPT,
5752                 .name = "mirror-id",            .has_arg = required_argument },
5753         { .val = 'c',   .name = "stripe-count", .has_arg = no_argument },
5754         { .val = 'c',   .name = "stripe_count", .has_arg = no_argument },
5755 /* find { .val = 'C',   .name = "ctime",        .has_arg = required_argument }*/
5756         { .val = 'd',   .name = "directory",    .has_arg = no_argument },
5757         { .val = 'D',   .name = "default",      .has_arg = no_argument },
5758         { .val = 'E',   .name = "comp-end",     .has_arg = optional_argument },
5759         { .val = 'E',   .name = "component-end", .has_arg = optional_argument },
5760         { .val = 'F',   .name = "fid",          .has_arg = no_argument },
5761         { .val = 'g',   .name = "generation",   .has_arg = no_argument },
5762 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
5763         { .val = 'h',   .name = "help",         .has_arg = no_argument },
5764 /* dirstripe { .val = 'H', .name = "mdt-hash",  .has_arg = required_argument }*/
5765         { .val = 'i',   .name = "stripe-index", .has_arg = no_argument },
5766         { .val = 'i',   .name = "stripe_index", .has_arg = no_argument },
5767         { .val = 'I',   .name = "comp-id",      .has_arg = optional_argument },
5768         { .val = 'I',   .name = "component-id", .has_arg = optional_argument },
5769 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
5770         { .val = 'L',   .name = "layout",       .has_arg = no_argument },
5771         { .val = 'm',   .name = "mdt",          .has_arg = no_argument },
5772         { .val = 'm',   .name = "mdt-index",    .has_arg = no_argument },
5773         { .val = 'm',   .name = "mdt_index",    .has_arg = no_argument },
5774 /* find { .val = 'M',   .name = "mtime",        .has_arg = required_argument }*/
5775 /* find { .val = 'n',   .name = "name",         .has_arg = required_argument }*/
5776         { .val = 'N',   .name = "mirror-count", .has_arg = no_argument },
5777         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
5778         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
5779         { .val = 'p',   .name = "pool",         .has_arg = no_argument },
5780 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
5781         { .val = 'q',   .name = "quiet",        .has_arg = no_argument },
5782         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
5783         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
5784         { .val = 'S',   .name = "stripe-size",  .has_arg = no_argument },
5785         { .val = 'S',   .name = "stripe_size",  .has_arg = no_argument },
5786 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
5787 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
5788 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
5789 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
5790         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
5791 /* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/
5792         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
5793         { .val = 'z',   .name = "extension-size", .has_arg = no_argument },
5794         { .val = 'z',   .name = "ext-size",     .has_arg = no_argument },
5795         { .name = NULL } };
5796         int c, rc;
5797         int neg_opt = 0;
5798         int pathstart = -1, pathend = -1;
5799         int isoption;
5800         char *end, *tmp;
5801
5802         while ((c = getopt_long(argc, argv,
5803                         "-cdDE::FghiI::LmMNoO:pqrRsSvyz",
5804                         long_opts, NULL)) != -1) {
5805                 if (neg_opt)
5806                         --neg_opt;
5807
5808                 /* '!' is part of option */
5809                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
5810                 if (!isoption && pathend != -1) {
5811                         fprintf(stderr,
5812                                 "error: %s: filename|dirname must either precede options or follow options\n",
5813                                 argv[0]);
5814                         return CMD_HELP;
5815                 }
5816                 if (!isoption && pathstart == -1)
5817                         pathstart = optind - 1;
5818                 if (isoption && pathstart != -1 && pathend == -1)
5819                         pathend = optind - 2;
5820
5821                 switch (c) {
5822                 case 1:
5823                         /* unknown: opt is "!" */
5824                         if (strcmp(optarg, "!") == 0)
5825                                 neg_opt = 2;
5826                         break;
5827                 case 'c':
5828                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5829                                 param->fp_verbose |= VERBOSE_COUNT;
5830                                 param->fp_max_depth = 0;
5831                         }
5832                         break;
5833                 case LFS_COMP_COUNT_OPT:
5834                         param->fp_verbose |= VERBOSE_COMP_COUNT;
5835                         param->fp_max_depth = 0;
5836                         break;
5837                 case LFS_COMP_FLAGS_OPT:
5838                         if (optarg) {
5839                                 rc = comp_str2flags(optarg,
5840                                                     &param->fp_comp_flags,
5841                                                     &param->fp_comp_neg_flags);
5842                                 if (rc != 0) {
5843                                         fprintf(stderr,
5844                                                 "error: %s bad component flags '%s'.\n",
5845                                                 argv[0], optarg);
5846                                         return CMD_HELP;
5847                                 }
5848                                 param->fp_check_comp_flags = 1;
5849                         } else {
5850                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
5851                                 param->fp_max_depth = 0;
5852                         }
5853                         break;
5854                 case LFS_COMP_START_OPT:
5855                         if (optarg) {
5856                                 tmp = optarg;
5857                                 if (tmp[0] == '+') {
5858                                         param->fp_comp_start_sign = -1;
5859                                         tmp++;
5860                                 } else if (tmp[0] == '-') {
5861                                         param->fp_comp_start_sign = 1;
5862                                         tmp++;
5863                                 }
5864                                 rc = llapi_parse_size(tmp,
5865                                                 &param->fp_comp_start,
5866                                                 &param->fp_comp_start_units, 0);
5867                                 if (rc != 0) {
5868                                         fprintf(stderr,
5869                                                 "error: %s bad component start '%s'.\n",
5870                                                 argv[0], tmp);
5871                                         return CMD_HELP;
5872                                 }
5873                                 param->fp_check_comp_start = 1;
5874                         } else {
5875                                 param->fp_verbose |= VERBOSE_COMP_START;
5876                                 param->fp_max_depth = 0;
5877                         }
5878                         break;
5879                 case LFS_MIRROR_INDEX_OPT: {
5880                         unsigned long int mirror_index;
5881
5882                         if (optarg[0] == '+') {
5883                                 param->fp_mirror_index_sign = -1;
5884                                 optarg++;
5885                         } else if (optarg[0] == '-') {
5886                                 param->fp_mirror_index_sign = 1;
5887                                 optarg++;
5888                         }
5889
5890                         errno = 0;
5891                         mirror_index = strtoul(optarg, &end, 0);
5892                         if (errno != 0 || *end != '\0' ||
5893                             mirror_index > UINT16_MAX || (mirror_index == 0 &&
5894                             param->fp_mirror_index_sign == 0 && neg_opt == 0)) {
5895                                 fprintf(stderr,
5896                                         "%s %s: invalid mirror index '%s'\n",
5897                                         progname, argv[0], optarg);
5898                                 return CMD_HELP;
5899                         }
5900
5901                         param->fp_mirror_index = (__u16)mirror_index;
5902
5903                         if (param->fp_mirror_id != 0) {
5904                                 fprintf(stderr,
5905                                         "%s %s: can't specify both mirror index and mirror ID\n",
5906                                         progname, argv[0]);
5907                                 return CMD_HELP;
5908                         }
5909                         param->fp_check_mirror_index = 1;
5910                         param->fp_exclude_mirror_index = !!neg_opt;
5911                         break;
5912                 }
5913                 case LFS_MIRROR_ID_OPT: {
5914                         unsigned long int mirror_id;
5915
5916                         if (optarg[0] == '+') {
5917                                 param->fp_mirror_id_sign = -1;
5918                                 optarg++;
5919                         } else if (optarg[0] == '-') {
5920                                 param->fp_mirror_id_sign = 1;
5921                                 optarg++;
5922                         }
5923
5924                         errno = 0;
5925                         mirror_id = strtoul(optarg, &end, 0);
5926                         if (errno != 0 || *end != '\0' ||
5927                             mirror_id > UINT16_MAX || (mirror_id == 0 &&
5928                             param->fp_mirror_id_sign == 0 && neg_opt == 0)) {
5929                                 fprintf(stderr,
5930                                         "%s %s: invalid mirror ID '%s'\n",
5931                                         progname, argv[0], optarg);
5932                                 return CMD_HELP;
5933                         }
5934
5935                         param->fp_mirror_id = (__u16)mirror_id;
5936
5937                         if (param->fp_mirror_index != 0) {
5938                                 fprintf(stderr,
5939                                         "%s %s: can't specify both mirror index and mirror ID\n",
5940                                         progname, argv[0]);
5941                                 return CMD_HELP;
5942                         }
5943                         param->fp_check_mirror_id = 1;
5944                         param->fp_exclude_mirror_id = !!neg_opt;
5945                         break;
5946                 }
5947                 case 'd':
5948                         param->fp_max_depth = 0;
5949                         break;
5950                 case 'D':
5951                         param->fp_get_default_lmv = 1;
5952                         break;
5953                 case 'E':
5954                         if (optarg) {
5955                                 tmp = optarg;
5956                                 if (tmp[0] == '+') {
5957                                         param->fp_comp_end_sign = -1;
5958                                         tmp++;
5959                                 } else if (tmp[0] == '-') {
5960                                         param->fp_comp_end_sign = 1;
5961                                         tmp++;
5962                                 }
5963
5964                                 if (arg_is_eof(tmp)) {
5965                                         param->fp_comp_end = LUSTRE_EOF;
5966                                         param->fp_comp_end_units = 1;
5967                                         rc = 0;
5968                                 } else {
5969                                         rc = llapi_parse_size(tmp,
5970                                                 &param->fp_comp_end,
5971                                                 &param->fp_comp_end_units, 0);
5972                                         /* assume units of KB if too small */
5973                                         if (param->fp_comp_end < 4096)
5974                                                 param->fp_comp_end *= 1024;
5975                                 }
5976                                 if (rc != 0) {
5977                                         fprintf(stderr,
5978                                                 "error: %s bad component end '%s'.\n",
5979                                                 argv[0], tmp);
5980                                         return CMD_HELP;
5981                                 }
5982                                 param->fp_check_comp_end = 1;
5983                         } else {
5984                                 param->fp_verbose |= VERBOSE_COMP_END;
5985                                 param->fp_max_depth = 0;
5986                         }
5987                         break;
5988                 case 'F':
5989                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5990                                 param->fp_verbose |= VERBOSE_DFID;
5991                                 param->fp_max_depth = 0;
5992                         }
5993                         break;
5994                 case 'g':
5995                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
5996                                 param->fp_verbose |= VERBOSE_GENERATION;
5997                                 param->fp_max_depth = 0;
5998                         }
5999                         break;
6000                 case 'i':
6001                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6002                                 param->fp_verbose |= VERBOSE_STRIPE_OFFSET;
6003                                 param->fp_max_depth = 0;
6004                         }
6005                         break;
6006                 case 'I':
6007                         if (optarg) {
6008                                 param->fp_comp_id = strtoul(optarg, &end, 0);
6009                                 if (*end != '\0' || param->fp_comp_id == 0 ||
6010                                     param->fp_comp_id > LCME_ID_MAX) {
6011                                         fprintf(stderr,
6012                                                 "error: %s bad component id '%s'\n",
6013                                                 argv[0], optarg);
6014                                         return CMD_HELP;
6015                                 }
6016                                 param->fp_check_comp_id = 1;
6017                         } else {
6018                                 param->fp_max_depth = 0;
6019                                 param->fp_verbose |= VERBOSE_COMP_ID;
6020                         }
6021                         break;
6022                 case 'L':
6023                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6024                                 param->fp_verbose |= VERBOSE_PATTERN;
6025                                 param->fp_max_depth = 0;
6026                         }
6027                         break;
6028 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6029                 case 'M':
6030                         fprintf(stderr,
6031                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
6032 #endif
6033                 case 'm':
6034                         if (!(param->fp_verbose & VERBOSE_DETAIL))
6035                                 param->fp_max_depth = 0;
6036                         param->fp_verbose |= VERBOSE_MDTINDEX;
6037                         break;
6038                 case 'N':
6039                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6040                                 param->fp_verbose |= VERBOSE_MIRROR_COUNT;
6041                                 param->fp_max_depth = 0;
6042                         }
6043                         break;
6044                 case 'O':
6045                         if (param->fp_obd_uuid) {
6046                                 fprintf(stderr,
6047                                         "error: %s: only one obduuid allowed",
6048                                         argv[0]);
6049                                 return CMD_HELP;
6050                         }
6051                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
6052                         break;
6053                 case 'p':
6054                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6055                                 param->fp_verbose |= VERBOSE_POOL;
6056                                 param->fp_max_depth = 0;
6057                         }
6058                         break;
6059                 case 'q':
6060                         param->fp_quiet++;
6061                         break;
6062                 case 'r':
6063                         param->fp_recursive = 1;
6064                         break;
6065                 case 'R':
6066                         param->fp_raw = 1;
6067                         break;
6068                 case 'S':
6069                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6070                                 param->fp_verbose |= VERBOSE_STRIPE_SIZE;
6071                                 param->fp_max_depth = 0;
6072                         }
6073                         break;
6074                 case 'v':
6075                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
6076                         break;
6077                 case 'y':
6078                         param->fp_yaml = 1;
6079                         break;
6080                 case 'z':
6081                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6082                                 param->fp_verbose |= VERBOSE_EXT_SIZE;
6083                                 param->fp_max_depth = 0;
6084                         }
6085                         break;
6086                 default:
6087                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6088                                 progname, argv[optind - 1]);
6089                 case 'h':
6090                         return CMD_HELP;
6091                 }
6092         }
6093
6094         if (pathstart == -1) {
6095                 fprintf(stderr, "error: %s: no filename|pathname\n",
6096                                 argv[0]);
6097                 return CMD_HELP;
6098         } else if (pathend == -1) {
6099                 /* no options */
6100                 pathend = argc;
6101         }
6102
6103         if (pathend > argc)
6104                 return CMD_HELP;
6105
6106         if (param->fp_recursive)
6107                 param->fp_max_depth = -1;
6108         else if (param->fp_verbose & VERBOSE_DETAIL)
6109                 param->fp_max_depth = 1;
6110
6111         if (!param->fp_verbose)
6112                 param->fp_verbose = VERBOSE_DEFAULT;
6113         if (param->fp_quiet)
6114                 param->fp_verbose = VERBOSE_OBJID;
6115
6116         do {
6117                 rc = llapi_getstripe(argv[pathstart], param);
6118         } while (++pathstart < pathend && !rc);
6119
6120         if (rc)
6121                 fprintf(stderr, "error: %s failed for %s.\n",
6122                         argv[0], argv[optind - 1]);
6123         return rc;
6124 }
6125
6126 static int lfs_tgts(int argc, char **argv)
6127 {
6128         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
6129         struct find_param param;
6130         int index = 0, rc = 0;
6131
6132         if (argc > 2)
6133                 return CMD_HELP;
6134
6135         if (argc == 2 && !realpath(argv[1], path)) {
6136                 rc = -errno;
6137                 fprintf(stderr, "error: invalid path '%s': %s\n",
6138                         argv[1], strerror(-rc));
6139                 return rc;
6140         }
6141
6142         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
6143                 /* Check if we have a mount point */
6144                 if (mntdir[0] == '\0')
6145                         continue;
6146
6147                 memset(&param, 0, sizeof(param));
6148                 if (!strcmp(argv[0], "mdts"))
6149                         param.fp_get_lmv = 1;
6150
6151                 rc = llapi_ostlist(mntdir, &param);
6152                 if (rc) {
6153                         fprintf(stderr, "error: %s: failed on %s\n",
6154                                 argv[0], mntdir);
6155                 }
6156                 if (path[0] != '\0')
6157                         break;
6158                 memset(mntdir, 0, PATH_MAX);
6159         }
6160
6161         return rc;
6162 }
6163
6164 static int lfs_getstripe(int argc, char **argv)
6165 {
6166         struct find_param param = { 0 };
6167
6168         param.fp_max_depth = 1;
6169         return lfs_getstripe_internal(argc, argv, &param);
6170 }
6171
6172 /* functions */
6173 static int lfs_getdirstripe(int argc, char **argv)
6174 {
6175         struct find_param param = { 0 };
6176         struct option long_opts[] = {
6177         { .val = 'c',   .name = "mdt-count",     .has_arg = no_argument },
6178         { .val = 'D',   .name = "default",       .has_arg = no_argument },
6179         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6180         { .val = 'H',   .name = "mdt-hash",      .has_arg = no_argument },
6181         { .val = 'i',   .name = "mdt-index",     .has_arg = no_argument },
6182         { .val = 'm',   .name = "mdt-index",     .has_arg = no_argument },
6183         { .val = 'O',   .name = "obd",           .has_arg = required_argument },
6184         { .val = 'r',   .name = "recursive",     .has_arg = no_argument },
6185         { .val = 'T',   .name = "mdt-count",     .has_arg = no_argument },
6186         { .val = 'v',   .name = "verbose",       .has_arg = no_argument },
6187         { .val = 'X',   .name = "max-inherit",   .has_arg = no_argument },
6188         { .val = 'y',   .name = "yaml",          .has_arg = no_argument },
6189         { .val = LFS_INHERIT_RR_OPT,
6190                         .name = "max-inherit-rr", .has_arg = no_argument },
6191         { .name = NULL } };
6192         int c, rc;
6193
6194         param.fp_get_lmv = 1;
6195
6196         while ((c = getopt_long(argc, argv,
6197                                 "cDhHimO:rtTvXy", long_opts, NULL)) != -1) {
6198                 switch (c) {
6199                 case 'c':
6200                 case 'T':
6201                         param.fp_verbose |= VERBOSE_COUNT;
6202                         break;
6203                 case 'D':
6204                         param.fp_get_default_lmv = 1;
6205                         break;
6206 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6207                 case 't':
6208                         fprintf(stderr,
6209                                 "warning: '-t' deprecated, use '--mdt-hash' or '-H' instead\n");
6210                         /* fallthrough */
6211 #endif
6212                 case 'H':
6213                         param.fp_verbose |= VERBOSE_HASH_TYPE;
6214                         break;
6215                 case 'i': /* fallthrough */
6216                 case 'm':
6217                         param.fp_verbose |= VERBOSE_STRIPE_OFFSET;
6218                         break;
6219                 case 'O':
6220                         if (param.fp_obd_uuid) {
6221                                 fprintf(stderr,
6222                                         "%s: only one obduuid allowed",
6223                                         progname);
6224                                 return CMD_HELP;
6225                         }
6226                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
6227                         break;
6228                 case 'r':
6229                         param.fp_recursive = 1;
6230                         break;
6231                 case 'v':
6232                         param.fp_verbose |= VERBOSE_DETAIL;
6233                         break;
6234                 case 'X':
6235                         param.fp_verbose |= VERBOSE_INHERIT;
6236                         break;
6237                 case LFS_INHERIT_RR_OPT:
6238                         param.fp_verbose |= VERBOSE_INHERIT_RR;
6239                         break;
6240                 case 'y':
6241                         param.fp_yaml = 1;
6242                         break;
6243                 default:
6244                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6245                                 progname, argv[optind - 1]);
6246                         /* fallthrough */
6247                 case 'h':
6248                         return CMD_HELP;
6249                 }
6250         }
6251
6252         if (optind >= argc)
6253                 return CMD_HELP;
6254
6255         if (param.fp_recursive)
6256                 param.fp_max_depth = -1;
6257
6258         if (!param.fp_verbose)
6259                 param.fp_verbose = VERBOSE_DEFAULT;
6260
6261         do {
6262                 rc = llapi_getstripe(argv[optind], &param);
6263         } while (++optind < argc && !rc);
6264
6265         if (rc)
6266                 fprintf(stderr, "error: %s failed for %s.\n",
6267                         argv[0], argv[optind - 1]);
6268         return rc;
6269 }
6270
6271 enum mntdf_flags {
6272         MNTDF_INODES    = 0x0001,
6273         MNTDF_COOKED    = 0x0002,
6274         MNTDF_LAZY      = 0x0004,
6275         MNTDF_VERBOSE   = 0x0008,
6276         MNTDF_SHOW      = 0x0010,
6277         MNTDF_DECIMAL   = 0x0020,
6278 };
6279
6280 #define COOK(value, base)                                       \
6281 ({                                                              \
6282         int radix = 0;                                          \
6283         while (value > base) {                                  \
6284                 value /= base;                                  \
6285                 radix++;                                        \
6286         }                                                       \
6287         radix;                                                  \
6288 })
6289 #define UUF     "%-20s"
6290 #define CSF     "%11s"
6291 #define CDF     "%11llu"
6292 #define HDF     "%8.1f%c"
6293 #define RSF     "%4s"
6294 #define RDF     "%3d%%"
6295
6296 static inline int obd_statfs_ratio(const struct obd_statfs *st, bool inodes)
6297 {
6298         double avail, used, ratio = 0;
6299
6300         if (inodes) {
6301                 avail = st->os_ffree;
6302                 used = st->os_files - st->os_ffree;
6303         } else {
6304                 avail = st->os_bavail;
6305                 used = st->os_blocks - st->os_bfree;
6306         }
6307         if (avail + used > 0)
6308                 ratio = used / (used + avail) * 100;
6309
6310         /* Round up to match df(1) usage percentage */
6311         return (ratio - (int)ratio) > 0 ? (int)(ratio + 1) : (int)ratio;
6312 }
6313
6314 /*
6315  * This is to identify various problem states for "lfs df" if .osn_err = true,
6316  * so only show flags reflecting those states by default. Informational states
6317  * are only shown with "-v" and use lower-case names to distinguish them.
6318  * UNUSED[12] were for "EROFS = 30" until 1.6 but are now available for use.
6319  */
6320 static struct obd_statfs_state_names {
6321         enum obd_statfs_state   osn_state;
6322         const char              osn_name;
6323         bool                    osn_err;
6324 } oss_names[] = {
6325         { .osn_state = OS_STATFS_DEGRADED,   .osn_name = 'D', .osn_err = true },
6326         { .osn_state = OS_STATFS_READONLY,   .osn_name = 'R', .osn_err = true },
6327         { .osn_state = OS_STATFS_NOPRECREATE,.osn_name = 'N', .osn_err = true },
6328         { .osn_state = OS_STATFS_UNUSED1,    .osn_name = '?', .osn_err = true },
6329         { .osn_state = OS_STATFS_UNUSED2,    .osn_name = '?', .osn_err = true },
6330         { .osn_state = OS_STATFS_ENOSPC,     .osn_name = 'S', .osn_err = true },
6331         { .osn_state = OS_STATFS_ENOINO,     .osn_name = 'I', .osn_err = true },
6332         { .osn_state = OS_STATFS_SUM,        .osn_name = 'a', /* aggregate */ },
6333         { .osn_state = OS_STATFS_NONROT,     .osn_name = 'f', /* flash */     },
6334 };
6335
6336 static int showdf(char *mntdir, struct obd_statfs *stat,
6337                   char *uuid, enum mntdf_flags flags,
6338                   char *type, int index, int rc)
6339 {
6340         long long avail, used, total;
6341         int ratio = 0;
6342         char *suffix = flags & MNTDF_DECIMAL ? "kMGTPEZY" : "KMGTPEZY";
6343         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
6344         char tbuf[3 * sizeof(__u64)];
6345         char ubuf[3 * sizeof(__u64)];
6346         char abuf[3 * sizeof(__u64)];
6347         char rbuf[3 * sizeof(__u64)];
6348
6349         if (!uuid || !stat)
6350                 return -EINVAL;
6351
6352         switch (rc) {
6353         case 0:
6354                 if (flags & MNTDF_INODES) {
6355                         avail = stat->os_ffree;
6356                         used = stat->os_files - stat->os_ffree;
6357                         total = stat->os_files;
6358                 } else {
6359                         int shift = flags & MNTDF_COOKED ? 0 : 10;
6360
6361                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
6362                         used  = ((stat->os_blocks - stat->os_bfree) *
6363                                  stat->os_bsize) >> shift;
6364                         total = (stat->os_blocks * stat->os_bsize) >> shift;
6365                 }
6366
6367                 ratio = obd_statfs_ratio(stat, flags & MNTDF_INODES);
6368
6369                 if (flags & MNTDF_COOKED) {
6370                         int base = flags & MNTDF_DECIMAL ? 1000 : 1024;
6371                         double cook_val;
6372                         int i;
6373
6374                         cook_val = (double)total;
6375                         i = COOK(cook_val, base);
6376                         if (i > 0)
6377                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
6378                                          suffix[i - 1]);
6379                         else
6380                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
6381
6382                         cook_val = (double)used;
6383                         i = COOK(cook_val, base);
6384                         if (i > 0)
6385                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
6386                                          suffix[i - 1]);
6387                         else
6388                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
6389
6390                         cook_val = (double)avail;
6391                         i = COOK(cook_val, base);
6392                         if (i > 0)
6393                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
6394                                          suffix[i - 1]);
6395                         else
6396                                 snprintf(abuf, sizeof(abuf), CDF, avail);
6397                 } else {
6398                         snprintf(tbuf, sizeof(tbuf), CDF, total);
6399                         snprintf(ubuf, sizeof(tbuf), CDF, used);
6400                         snprintf(abuf, sizeof(tbuf), CDF, avail);
6401                 }
6402
6403                 sprintf(rbuf, RDF, ratio);
6404                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
6405                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
6406                 if (type)
6407                         printf("[%s:%d]", type, index);
6408
6409                 if (stat->os_state) {
6410                         uint32_t i;
6411
6412                         printf(" ");
6413                         for (i = 0; i < ARRAY_SIZE(oss_names); i++) {
6414                                 if (oss_names[i].osn_state & stat->os_state &&
6415                                     (oss_names[i].osn_err ||
6416                                      flags & MNTDF_VERBOSE))
6417                                         printf("%c", oss_names[i].osn_name);
6418                         }
6419                 }
6420
6421                 printf("\n");
6422                 break;
6423         case -ENODATA:
6424                 printf(UUF": inactive device\n", uuid);
6425                 break;
6426         default:
6427                 printf(UUF": %s\n", uuid, strerror(-rc));
6428                 break;
6429         }
6430
6431         return 0;
6432 }
6433
6434 struct ll_stat_type {
6435         int   st_op;
6436         char *st_name;
6437 };
6438
6439 #define LL_STATFS_MAX   LOV_MAX_STRIPE_COUNT
6440
6441 struct ll_statfs_data {
6442         int                     sd_index;
6443         struct obd_statfs       sd_st;
6444 };
6445
6446 struct ll_statfs_buf {
6447         int                     sb_count;
6448         struct ll_statfs_data   sb_buf[LL_STATFS_MAX];
6449 };
6450
6451 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags,
6452                  int ops, struct ll_statfs_buf *lsb)
6453 {
6454         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
6455         struct obd_uuid uuid_buf;
6456         char *poolname = NULL;
6457         struct ll_stat_type types[] = {
6458                 { .st_op = LL_STATFS_LMV,       .st_name = "MDT" },
6459                 { .st_op = LL_STATFS_LOV,       .st_name = "OST" },
6460                 { .st_name = NULL } };
6461         struct ll_stat_type *tp;
6462         __u64 ost_files = 0;
6463         __u64 ost_ffree = 0;
6464         __u32 index;
6465         __u32 type;
6466         int fd;
6467         int rc = 0;
6468         int rc2;
6469
6470         if (pool) {
6471                 poolname = strchr(pool, '.');
6472                 if (poolname) {
6473                         if (strncmp(fsname, pool, strlen(fsname))) {
6474                                 fprintf(stderr, "filesystem name incorrect\n");
6475                                 return -ENODEV;
6476                         }
6477                         poolname++;
6478                 } else
6479                         poolname = pool;
6480         }
6481
6482         fd = open(mntdir, O_RDONLY);
6483         if (fd < 0) {
6484                 rc = -errno;
6485                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
6486                         strerror(errno));
6487                 return rc;
6488         }
6489
6490         if (flags & MNTDF_SHOW) {
6491                 if (flags & MNTDF_INODES)
6492                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
6493                                "UUID", "Inodes", "IUsed", "IFree",
6494                                "IUse%", "Mounted on");
6495                 else
6496                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
6497                                "UUID",
6498                                flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
6499                                "Used", "Available", "Use%", "Mounted on");
6500         }
6501
6502         for (tp = types; tp->st_name != NULL; tp++) {
6503                 bool have_ost = false;
6504
6505                 if (!(tp->st_op & ops))
6506                         continue;
6507
6508                 for (index = 0; ; index++) {
6509                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
6510                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
6511                         type = flags & MNTDF_LAZY ?
6512                                 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
6513                         rc2 = llapi_obd_fstatfs(fd, type, index,
6514                                                &stat_buf, &uuid_buf);
6515                         if (rc2 == -ENODEV)
6516                                 break;
6517                         if (rc2 == -EAGAIN)
6518                                 continue;
6519                         if (rc2 == -ENODATA) { /* Inactive device, OK. */
6520                                 if (!(flags & MNTDF_VERBOSE))
6521                                         continue;
6522                         } else if (rc2 < 0 && rc == 0) {
6523                                 rc = rc2;
6524                         }
6525
6526                         /*
6527                          * If we have OSTs then don't report MDT block counts.
6528                          * For MDT-only filesystems the expectation is that all
6529                          * layouts have a DoM component.  For filesystems with
6530                          * OSTs, files are not necessarily going to store data
6531                          * on MDTs, and MDT space is limited to a fraction of
6532                          * OST space, so don't include it in the summary.
6533                          */
6534                         if (tp->st_op == LL_STATFS_LOV && !have_ost) {
6535                                 have_ost = true;
6536                                 sum.os_blocks = 0;
6537                                 sum.os_bfree = 0;
6538                                 sum.os_bavail = 0;
6539                         }
6540
6541                         if (poolname && tp->st_op == LL_STATFS_LOV &&
6542                             llapi_search_ost(fsname, poolname,
6543                                              obd_uuid2str(&uuid_buf)) != 1)
6544                                 continue;
6545
6546                         /*
6547                          * the llapi_obd_fstatfs() call may have returned with
6548                          * an error, but if it filled in uuid_buf we will at
6549                          * lease use that to print out a message for that OBD.
6550                          * If we didn't get anything in the uuid_buf, then fill
6551                          * it in so that we can print an error message.
6552                          */
6553                         if (uuid_buf.uuid[0] == '\0')
6554                                 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
6555                                          "%s%04x", tp->st_name, index);
6556                         if (!rc && lsb) {
6557                                 lsb->sb_buf[lsb->sb_count].sd_index = index;
6558                                 lsb->sb_buf[lsb->sb_count].sd_st = stat_buf;
6559                                 lsb->sb_count++;
6560                         }
6561                         if (flags & MNTDF_SHOW)
6562                                 showdf(mntdir, &stat_buf,
6563                                        obd_uuid2str(&uuid_buf), flags,
6564                                        tp->st_name, index, rc2);
6565
6566                         if (rc2)
6567                                 continue;
6568
6569                         if (tp->st_op == LL_STATFS_LMV) {
6570                                 sum.os_ffree += stat_buf.os_ffree;
6571                                 sum.os_files += stat_buf.os_files;
6572                         } else /* if (tp->st_op == LL_STATFS_LOV) */ {
6573                                 ost_files += stat_buf.os_files;
6574                                 ost_ffree += stat_buf.os_ffree;
6575                         }
6576                         sum.os_blocks += stat_buf.os_blocks *
6577                                          stat_buf.os_bsize;
6578                         sum.os_bfree  += stat_buf.os_bfree *
6579                                          stat_buf.os_bsize;
6580                         sum.os_bavail += stat_buf.os_bavail *
6581                                          stat_buf.os_bsize;
6582                 }
6583         }
6584
6585         close(fd);
6586
6587         /*
6588          * If we have _some_ OSTs, but don't have as many free objects on the
6589          * OST as inodes on the MDTs, reduce the reported number of inodes
6590          * to compensate, so that the "inodes in use" number is correct.
6591          * This should be kept in sync with ll_statfs_internal().
6592          */
6593         if (ost_files && ost_ffree < sum.os_ffree) {
6594                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
6595                 sum.os_ffree = ost_ffree;
6596         }
6597         if (flags & MNTDF_SHOW) {
6598                 printf("\n");
6599                 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
6600                 printf("\n");
6601         }
6602
6603         return rc;
6604 }
6605
6606 enum {
6607         LAYOUT_INHERIT_UNSET    = -2,
6608 };
6609
6610 /* functions */
6611 static int lfs_setdirstripe(int argc, char **argv)
6612 {
6613         char *dname;
6614         struct lfs_setstripe_args lsa = { 0 };
6615         struct llapi_stripe_param *param = NULL;
6616         __u32 mdts[LMV_MAX_STRIPE_COUNT] = { 0 };
6617         char *end;
6618         int c;
6619         char *mode_opt = NULL;
6620         bool default_stripe = false;
6621         bool delete = false;
6622         bool foreign_mode = false;
6623         mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
6624         mode_t previous_mode = 0;
6625         char *xattr = NULL;
6626         __u32 type = LU_FOREIGN_TYPE_SYMLINK, flags = 0;
6627         int max_inherit = LAYOUT_INHERIT_UNSET;
6628         int max_inherit_rr = LAYOUT_INHERIT_UNSET;
6629         struct option long_opts[] = {
6630         { .val = 'c',   .name = "count",        .has_arg = required_argument },
6631         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
6632         { .val = 'd',   .name = "delete",       .has_arg = no_argument },
6633         { .val = 'D',   .name = "default",      .has_arg = no_argument },
6634         { .val = 'D',   .name = "default_stripe", .has_arg = no_argument },
6635         { .val = LFS_LAYOUT_FLAGS_OPT,
6636                         .name = "flags",        .has_arg = required_argument },
6637         { .val = LFS_LAYOUT_FOREIGN_OPT,
6638                         .name = "foreign",      .has_arg = optional_argument},
6639         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6640         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
6641 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 17, 53, 0)
6642         { .val = 'i',   .name = "mdt-index",    .has_arg = required_argument },
6643         { .val = 'i',   .name = "mdt",          .has_arg = required_argument },
6644 #else
6645 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
6646         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
6647         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
6648 #endif
6649 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6650         { .val = 'i',   .name = "index",        .has_arg = required_argument },
6651 #endif
6652         { .val = 'o',   .name = "mode",         .has_arg = required_argument },
6653 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6654         { .val = 't',   .name = "hash-type",    .has_arg = required_argument },
6655 #endif
6656         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
6657         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
6658         { .val = 'X',   .name = "max-inherit",  .has_arg = required_argument },
6659         { .val = LFS_INHERIT_RR_OPT,
6660                         .name = "max-inherit-rr", .has_arg = required_argument},
6661 /* setstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
6662         { .name = NULL } };
6663         int result = 0;
6664
6665         setstripe_args_init(&lsa);
6666
6667         while ((c = getopt_long(argc, argv, "c:dDi:hH:m:o:t:T:x:X:",
6668                                 long_opts, NULL)) >= 0) {
6669                 switch (c) {
6670                 case 0:
6671                         /* Long options. */
6672                         break;
6673                 case 'c':
6674                 case 'T':
6675                         errno = 0;
6676                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
6677                         if (errno != 0 || *end != '\0' ||
6678                             lsa.lsa_stripe_count < -1 ||
6679                             lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
6680                                 fprintf(stderr,
6681                                         "%s: invalid stripe count '%s'\n",
6682                                         progname, optarg);
6683                                 return CMD_HELP;
6684                         }
6685                         break;
6686                 case 'd':
6687                         delete = true;
6688                         default_stripe = true;
6689                         break;
6690                 case 'D':
6691                         default_stripe = true;
6692                         break;
6693                 case LFS_LAYOUT_FOREIGN_OPT:
6694                         if (optarg) {
6695                                 /* check pure numeric */
6696                                 type = strtoul(optarg, &end, 0);
6697                                 if (*end) {
6698                                         /* check name */
6699                                         type = check_foreign_type_name(optarg);
6700                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
6701                                                 fprintf(stderr,
6702                                                         "%s %s: unknown foreign type '%s'\n",
6703                                                         progname, argv[0],
6704                                                         optarg);
6705                                                 return CMD_HELP;
6706                                         }
6707                                 } else if (type >= UINT32_MAX) {
6708                                         fprintf(stderr,
6709                                                 "%s %s: invalid foreign type '%s'\n",
6710                                                 progname, argv[0], optarg);
6711                                         return CMD_HELP;
6712                                 }
6713                         }
6714                         foreign_mode = true;
6715                         break;
6716                 case LFS_LAYOUT_FLAGS_OPT:
6717                         errno = 0;
6718                         flags = strtoul(optarg, &end, 16);
6719                         if (errno != 0 || *end != '\0' ||
6720                             flags >= UINT32_MAX) {
6721                                 fprintf(stderr,
6722                                         "%s %s: invalid hex flags '%s'\n",
6723                                         progname, argv[0], optarg);
6724                                 return CMD_HELP;
6725                         }
6726                         if (!foreign_mode) {
6727                                 fprintf(stderr,
6728                                         "%s %s: hex flags must be specified with --foreign option\n",
6729                                         progname, argv[0]);
6730                                 return CMD_HELP;
6731                         }
6732                         break;
6733 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6734                 case 't':
6735                         fprintf(stderr,
6736                                 "warning: '--hash-type' and '-t' deprecated, use '--mdt-hash' or '-H' instead\n");
6737                         /* fallthrough */
6738 #endif
6739                 case 'H':
6740                         lsa.lsa_pattern = check_hashtype(optarg);
6741                         if (lsa.lsa_pattern == 0) {
6742                                 fprintf(stderr,
6743                                         "%s %s: bad stripe hash type '%s'\n",
6744                                         progname, argv[0], optarg);
6745                                 return CMD_HELP;
6746                         }
6747                         break;
6748                 case 'i':
6749 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 17, 53, 0)
6750                 case 'm':
6751 #endif
6752 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6753                         if (strcmp(argv[optind - 1], "--index") == 0)
6754                                 fprintf(stderr,
6755                                         "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
6756                                         progname, argv[0]);
6757 #endif
6758                         lsa.lsa_nr_tgts = parse_targets(mdts,
6759                                                 sizeof(mdts) / sizeof(__u32),
6760                                                 lsa.lsa_nr_tgts, optarg, NULL);
6761                         if (lsa.lsa_nr_tgts < 0) {
6762                                 fprintf(stderr,
6763                                         "%s %s: invalid MDT target(s) '%s'\n",
6764                                         progname, argv[0], optarg);
6765                                 return CMD_HELP;
6766                         }
6767
6768                         lsa.lsa_tgts = mdts;
6769                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
6770                                 lsa.lsa_stripe_off = mdts[0];
6771                         break;
6772 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 15, 53, 0)
6773                 case 'm':
6774                         fprintf(stderr,
6775                                 "warning: '-m' is deprecated, use '--mode' or '-o' instead\n");
6776 #endif
6777                 case 'o':
6778                         mode_opt = optarg;
6779                         break;
6780                 case 'x':
6781                         xattr = optarg;
6782                         break;
6783                 case 'X':
6784                         if (!default_stripe) {
6785                                 fprintf(stderr,
6786                                         "%s %s: '--max-inherit' must be specified with '-D'\n",
6787                                         progname, argv[0]);
6788                                 return CMD_HELP;
6789                         }
6790                         errno = 0;
6791                         max_inherit = strtol(optarg, &end, 10);
6792                         if (errno != 0 || *end != '\0' || max_inherit < -2) {
6793                                 fprintf(stderr,
6794                                         "%s %s: invalid max-inherit '%s'\n",
6795                                         progname, argv[0], optarg);
6796                                 return CMD_HELP;
6797                         }
6798                         if (max_inherit == 0) {
6799                                 max_inherit = LMV_INHERIT_NONE;
6800                         } else if (max_inherit == -1) {
6801                                 max_inherit = LMV_INHERIT_UNLIMITED;
6802                         } else if (max_inherit > LMV_INHERIT_MAX) {
6803                                 fprintf(stderr,
6804                                         "%s %s: max-inherit %d exceeds maximum %u\n",
6805                                         progname, argv[0], max_inherit,
6806                                         LMV_INHERIT_MAX);
6807                                 return CMD_HELP;
6808                         }
6809                         break;
6810                 case LFS_INHERIT_RR_OPT:
6811                         if (!default_stripe) {
6812                                 fprintf(stderr,
6813                                         "%s %s: '--max-inherit-rr' must be specified with '-D'\n",
6814                                         progname, argv[0]);
6815                                 return CMD_HELP;
6816                         }
6817                         errno = 0;
6818                         max_inherit_rr = strtol(optarg, &end, 10);
6819                         if (errno != 0 || *end != '\0' || max_inherit_rr < -2) {
6820                                 fprintf(stderr,
6821                                         "%s %s: invalid max-inherit-rr '%s'\n",
6822                                         progname, argv[0], optarg);
6823                                 return CMD_HELP;
6824                         }
6825                         if (max_inherit_rr == 0) {
6826                                 max_inherit_rr = LMV_INHERIT_RR_NONE;
6827                         } else if (max_inherit_rr == -1) {
6828                                 max_inherit_rr = LMV_INHERIT_RR_UNLIMITED;
6829                         } else if (max_inherit_rr > LMV_INHERIT_RR_MAX) {
6830                                 fprintf(stderr,
6831                                         "%s %s: max-inherit-rr %d exceeds maximum %u\n",
6832                                         progname, argv[0], max_inherit_rr,
6833                                         LMV_INHERIT_RR_MAX);
6834                                 return CMD_HELP;
6835                         }
6836                         break;
6837                 default:
6838                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6839                                 progname, argv[optind - 1]);
6840                         /* fallthrough */
6841                 case 'h':
6842                         return CMD_HELP;
6843                 }
6844         }
6845
6846         if (optind == argc) {
6847                 fprintf(stderr, "%s %s: DIR must be specified\n",
6848                         progname, argv[0]);
6849                 return CMD_HELP;
6850         }
6851
6852         if (xattr && !foreign_mode) {
6853                 /*
6854                  * only print a warning as this is armless and will be
6855                  * ignored
6856                  */
6857                 fprintf(stderr,
6858                         "%s %s: xattr has been specified for non-foreign layout\n",
6859                         progname, argv[0]);
6860         } else if (foreign_mode && !xattr) {
6861                 fprintf(stderr,
6862                         "%s %s: xattr must be provided in foreign mode\n",
6863                         progname, argv[0]);
6864                 return CMD_HELP;
6865         }
6866
6867         if (foreign_mode && (delete || default_stripe || lsa.lsa_nr_tgts ||
6868             lsa.lsa_tgts || setstripe_args_specified(&lsa))) {
6869                 fprintf(stderr,
6870                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
6871                         progname, argv[0]);
6872                 return CMD_HELP;
6873         }
6874
6875         if (!delete && lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT &&
6876             lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT && !foreign_mode) {
6877                 /* if no parameters set, create directory on least-used MDTs */
6878                 lsa.lsa_stripe_off = LMV_OFFSET_DEFAULT;
6879                 lsa.lsa_stripe_count = 1;
6880         }
6881
6882         if (delete &&
6883             (lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
6884              lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)) {
6885                 fprintf(stderr,
6886                         "%s %s: cannot specify -d with -c or -i options\n",
6887                         progname, argv[0]);
6888                 return CMD_HELP;
6889         }
6890
6891         if (mode_opt) {
6892                 mode = strtoul(mode_opt, &end, 8);
6893                 if (*end != '\0') {
6894                         fprintf(stderr,
6895                                 "%s %s: bad MODE '%s'\n",
6896                                 progname, argv[0], mode_opt);
6897                         return CMD_HELP;
6898                 }
6899                 previous_mode = umask(0);
6900         }
6901
6902         if (max_inherit_rr != LAYOUT_INHERIT_UNSET &&
6903             lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT &&
6904             lsa.lsa_stripe_off != LMV_OFFSET_DEFAULT) {
6905                 fprintf(stderr,
6906                         "%s %s: max-inherit-rr needs mdt-index=-1, not %lld\n",
6907                         progname, argv[0], lsa.lsa_stripe_off);
6908                 return CMD_HELP;
6909         }
6910
6911         /* foreign LMV/dir case */
6912         if (foreign_mode) {
6913                 if (argc > optind + 1) {
6914                         fprintf(stderr,
6915                                 "%s %s: cannot specify multiple foreign dirs\n",
6916                                 progname, argv[0]);
6917                         return CMD_HELP;
6918                 }
6919
6920                 dname = argv[optind];
6921                 result = llapi_dir_create_foreign(dname, mode, type, flags,
6922                                                   xattr);
6923                 if (result != 0)
6924                         fprintf(stderr,
6925                                 "%s mkdir: can't create foreign dir '%s': %s\n",
6926                                 progname, dname, strerror(-result));
6927                 return result;
6928         }
6929
6930         /*
6931          * initialize stripe parameters, in case param is converted to specific,
6932          * i.e, 'lfs mkdir -i -1 -c N', always allocate space for lsp_tgts.
6933          */
6934         param = calloc(1, offsetof(typeof(*param),
6935                        lsp_tgts[lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ?
6936                                 lsa.lsa_stripe_count : lsa.lsa_nr_tgts]));
6937         if (!param) {
6938                 fprintf(stderr,
6939                         "%s %s: cannot allocate memory for parameters: %s\n",
6940                         progname, argv[0], strerror(ENOMEM));
6941                 return CMD_HELP;
6942         }
6943
6944         /* if "lfs setdirstripe -D -i -1" is used, assume 1-stripe directory */
6945         if (default_stripe && lsa.lsa_stripe_off == LMV_OFFSET_DEFAULT &&
6946             (lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT ||
6947              lsa.lsa_stripe_count == 0))
6948                 lsa.lsa_stripe_count = 1;
6949         if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
6950                 param->lsp_stripe_count = lsa.lsa_stripe_count;
6951         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
6952                 param->lsp_stripe_offset = LMV_OFFSET_DEFAULT;
6953         else
6954                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
6955         if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
6956                 param->lsp_stripe_pattern = lsa.lsa_pattern;
6957         else
6958                 param->lsp_stripe_pattern = LMV_HASH_TYPE_UNKNOWN;
6959         param->lsp_pool = lsa.lsa_pool_name;
6960         param->lsp_is_specific = false;
6961         if (default_stripe) {
6962                 if (max_inherit == LAYOUT_INHERIT_UNSET)
6963                         max_inherit = LMV_INHERIT_DEFAULT;
6964                 if (max_inherit_rr == LAYOUT_INHERIT_UNSET)
6965                         max_inherit_rr = LMV_INHERIT_RR_DEFAULT;
6966                 param->lsp_max_inherit = max_inherit;
6967                 param->lsp_max_inherit_rr = max_inherit_rr;
6968         }
6969         if (strcmp(argv[0], "mkdir") == 0)
6970                 param->lsp_is_create = true;
6971         if (lsa.lsa_nr_tgts > 1) {
6972                 if (lsa.lsa_stripe_count > 0 &&
6973                     lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
6974                     lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
6975                         fprintf(stderr,
6976                                 "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
6977                                 argv[0], lsa.lsa_stripe_count,
6978                                 lsa.lsa_nr_tgts);
6979                         free(param);
6980                         return CMD_HELP;
6981                 }
6982
6983                 param->lsp_is_specific = true;
6984                 param->lsp_stripe_count = lsa.lsa_nr_tgts;
6985                 memcpy(param->lsp_tgts, mdts, sizeof(*mdts) * lsa.lsa_nr_tgts);
6986         }
6987
6988         dname = argv[optind];
6989         do {
6990                 if (default_stripe) {
6991                         result = llapi_dir_set_default_lmv(dname, param);
6992                         if (result)
6993                                 fprintf(stderr,
6994                                         "%s setdirstripe: cannot set default stripe on dir '%s': %s\n",
6995                                         progname, dname, strerror(-result));
6996                         continue;
6997                 }
6998
6999                 result = llapi_dir_create(dname, mode, param);
7000                 if (result)
7001                         fprintf(stderr,
7002                                 "%s setdirstripe: cannot create dir '%s': %s\n",
7003                                 progname, dname, strerror(-result));
7004         } while (!result && (dname = argv[++optind]));
7005
7006         if (mode_opt)
7007                 umask(previous_mode);
7008
7009         free(param);
7010         return result;
7011 }
7012
7013 /* functions */
7014 static int lfs_rmentry(int argc, char **argv)
7015 {
7016         char *dname;
7017         int   index;
7018         int   result = 0;
7019
7020         if (argc <= 1) {
7021                 fprintf(stderr, "error: %s: missing dirname\n",
7022                         argv[0]);
7023                 return CMD_HELP;
7024         }
7025
7026         index = 1;
7027         dname = argv[index];
7028         while (dname) {
7029                 result = llapi_direntry_remove(dname);
7030                 if (result) {
7031                         fprintf(stderr,
7032                                 "error: %s: remove dir entry '%s' failed\n",
7033                                 argv[0], dname);
7034                         break;
7035                 }
7036                 dname = argv[++index];
7037         }
7038         return result;
7039 }
7040
7041 static int lfs_unlink_foreign(int argc, char **argv)
7042 {
7043         char *name;
7044         int   index;
7045         int   result = 0;
7046
7047         if (argc <= 1) {
7048                 fprintf(stderr, "error: %s: missing pathname\n",
7049                         argv[0]);
7050                 return CMD_HELP;
7051         }
7052
7053         index = 1;
7054         name = argv[index];
7055         while (name != NULL) {
7056                 result = llapi_unlink_foreign(name);
7057                 if (result) {
7058                         fprintf(stderr,
7059                                 "error: %s: unlink foreign entry '%s' failed\n",
7060                                 argv[0], name);
7061                         break;
7062                 }
7063                 name = argv[++index];
7064         }
7065         return result;
7066 }
7067
7068 static int lfs_mv(int argc, char **argv)
7069 {
7070         struct lmv_user_md lmu = { LMV_USER_MAGIC };
7071         struct find_param param = {
7072                 .fp_max_depth = -1,
7073                 .fp_mdt_index = -1,
7074         };
7075         char *end;
7076         int c;
7077         int rc = 0;
7078         struct option long_opts[] = {
7079         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
7080         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
7081         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7082         { .name = NULL } };
7083
7084         while ((c = getopt_long(argc, argv, "m:M:v", long_opts, NULL)) != -1) {
7085                 switch (c) {
7086 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7087                 case 'M':
7088                         fprintf(stderr,
7089                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
7090 #endif
7091                 case 'm':
7092                         errno = 0;
7093                         lmu.lum_stripe_offset = strtoul(optarg, &end, 0);
7094                         if (errno != 0 || *end != '\0' ||
7095                             lmu.lum_stripe_offset >= UINT32_MAX) {
7096                                 fprintf(stderr, "%s mv: bad MDT index '%s'\n",
7097                                         progname, optarg);
7098                                 return CMD_HELP;
7099                         }
7100                         break;
7101                 case 'v':
7102                         param.fp_verbose = VERBOSE_DETAIL;
7103                         break;
7104                 default:
7105                         fprintf(stderr, "%s mv: unrecognized option '%s'\n",
7106                                 progname, argv[optind - 1]);
7107                         return CMD_HELP;
7108                 }
7109         }
7110
7111         if (lmu.lum_stripe_offset == LMV_OFFSET_DEFAULT) {
7112                 fprintf(stderr, "%s mv: MDT index must be specified\n",
7113                         progname);
7114                 return CMD_HELP;
7115         }
7116
7117         if (optind >= argc) {
7118                 fprintf(stderr, "%s mv: DIR must be specified\n", progname);
7119                 return CMD_HELP;
7120         }
7121
7122         lmu.lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
7123
7124         /* initialize migrate mdt parameters */
7125         param.fp_lmv_md = &lmu;
7126         param.fp_migrate = 1;
7127         rc = llapi_migrate_mdt(argv[optind], &param);
7128         if (rc != 0)
7129                 fprintf(stderr, "%s mv: cannot migrate '%s' to MDT%04x: %s\n",
7130                         progname, argv[optind], lmu.lum_stripe_offset,
7131                         strerror(-rc));
7132         return rc;
7133 }
7134
7135 static int lfs_osts(int argc, char **argv)
7136 {
7137         return lfs_tgts(argc, argv);
7138 }
7139
7140 static int lfs_mdts(int argc, char **argv)
7141 {
7142         return lfs_tgts(argc, argv);
7143 }
7144
7145 static int lfs_df(int argc, char **argv)
7146 {
7147         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
7148         enum mntdf_flags flags = MNTDF_SHOW;
7149         int ops = LL_STATFS_LMV | LL_STATFS_LOV;
7150         int c, rc = 0, rc1 = 0, index = 0, arg_idx = 0;
7151         char fsname[PATH_MAX] = "", *pool_name = NULL;
7152         struct option long_opts[] = {
7153         { .val = 'h',   .name = "human-readable", .has_arg = no_argument },
7154         { .val = 'H',   .name = "si",           .has_arg = no_argument },
7155         { .val = 'i',   .name = "inodes",       .has_arg = no_argument },
7156         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
7157         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
7158         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7159         { .name = NULL} };
7160
7161         while ((c = getopt_long(argc, argv, "hHilp:v", long_opts, NULL)) != -1) {
7162                 switch (c) {
7163                 case 'h':
7164                         flags = (flags & ~MNTDF_DECIMAL) | MNTDF_COOKED;
7165                         break;
7166                 case 'H':
7167                         flags |= MNTDF_COOKED | MNTDF_DECIMAL;
7168                         break;
7169                 case 'i':
7170                         flags |= MNTDF_INODES;
7171                         break;
7172                 case 'l':
7173                         flags |= MNTDF_LAZY;
7174                         break;
7175                 case 'p':
7176                         pool_name = optarg;
7177                         break;
7178                 case 'v':
7179                         flags |= MNTDF_VERBOSE;
7180                         break;
7181                 default:
7182                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7183                                 progname, argv[optind - 1]);
7184                         return CMD_HELP;
7185                 }
7186         }
7187
7188         /* Handle case where path is not specified */
7189         if (optind == argc) {
7190                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7191                         /* Check if we have a mount point */
7192                         if (mntdir[0] == '\0')
7193                                 continue;
7194
7195                         rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
7196                         if (rc || path[0] != '\0')
7197                                 break;
7198
7199                         fsname[0] = '\0'; /* avoid matching in next loop */
7200                         mntdir[0] = '\0'; /* avoid matching in next loop */
7201                         path[0] = '\0'; /* clean for next loop */
7202                 }
7203                 return rc;
7204         }
7205
7206         /* Loop through all the remaining arguments. These are Lustre FS
7207          * paths.
7208          */
7209         for (arg_idx = optind; arg_idx <= argc - 1; arg_idx++) {
7210                 bool valid = false;
7211
7212                 fsname[0] = '\0'; /* start clean */
7213                 mntdir[0] = '\0'; /* start clean */
7214                 path[0] = '\0';   /* start clean */
7215
7216                 /* path does not exists at all */
7217                 if (!realpath(argv[arg_idx], path)) {
7218                         rc = -errno;
7219                         fprintf(stderr, "error: invalid path '%s': %s\n",
7220                                 argv[arg_idx], strerror(-rc));
7221                         /* save first seen error */
7222                         if (!rc1)
7223                                 rc1 = rc;
7224
7225                         continue;
7226                 }
7227
7228                 /* path exists but may not be a Lustre filesystem */
7229                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7230                         /* Check if we have a mount point */
7231                         if (mntdir[0] == '\0')
7232                                 continue;
7233
7234                         rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
7235                         if (rc || path[0] != '\0') {
7236                                 valid = true;
7237
7238                                 /* save first seen error */
7239                                 if (!rc1)
7240                                         rc1 = rc;
7241                                 break;
7242                         }
7243                 }
7244
7245                 if (!valid) {
7246                         llapi_printf(LLAPI_MSG_ERROR,
7247                                      "%s:%s Not a Lustre filesystem\n",
7248                                      argv[0], argv[arg_idx]);
7249                         /* save first seen error */
7250                         if (!rc1)
7251                                 rc1 = -EOPNOTSUPP;
7252                 }
7253         }
7254
7255         return rc1;
7256 }
7257
7258 static int print_instance(const char *mntdir, char *buf, size_t buflen,
7259                           bool opt_instance, bool opt_fsname, bool opt_mntdir)
7260 {
7261         int rc = 0;
7262
7263         if (opt_fsname == opt_instance) { /* both true or both false */
7264                 rc = llapi_getname(mntdir, buf, buflen);
7265         } else if (opt_fsname) {
7266                 /*
7267                  * llapi_search_mounts() fills @buf with fsname, but that is not
7268                  * called if explicit paths are specified on the command-line
7269                  */
7270                 if (buf[0] == '\0')
7271                         rc = llapi_get_fsname(mntdir, buf, buflen);
7272         } else /* if (opt_instance) */ {
7273                 rc = llapi_get_instance(mntdir, buf, buflen);
7274         }
7275
7276         if (rc < 0) {
7277                 fprintf(stderr, "cannot get instance for '%s': %s\n",
7278                         mntdir, strerror(-rc));
7279                 return rc;
7280         }
7281
7282         if (opt_mntdir)
7283                 printf("%s %s\n", buf, mntdir);
7284         else
7285                 printf("%s\n", buf);
7286
7287         return 0;
7288 }
7289
7290 static int lfs_getname(int argc, char **argv)
7291 {
7292         struct option long_opts[] = {
7293         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7294         { .val = 'i',   .name = "instance",     .has_arg = no_argument },
7295         { .val = 'n',   .name = "fsname",       .has_arg = no_argument },
7296         { .name = NULL} };
7297         bool opt_instance = false, opt_fsname = false;
7298         char fsname[PATH_MAX] = "";
7299         int rc = 0, rc2, c;
7300
7301         while ((c = getopt_long(argc, argv, "hin", long_opts, NULL)) != -1) {
7302                 switch (c) {
7303                 case 'i':
7304                         opt_instance = true;
7305                         break;
7306                 case 'n':
7307                         opt_fsname = true;
7308                         break;
7309                 default:
7310                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7311                                 progname, argv[optind - 1]);
7312                         /* fallthrough */
7313                 case 'h':
7314                         return CMD_HELP;
7315                 }
7316         }
7317
7318         if (optind == argc) { /* no paths specified, get all paths. */
7319                 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "";
7320                 int index = 0;
7321
7322                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7323                         rc2 = print_instance(mntdir, fsname, sizeof(fsname),
7324                                              opt_instance, opt_fsname, true);
7325                         if (!rc)
7326                                 rc = rc2;
7327                         path[0] = fsname[0] = mntdir[0] = '\0';
7328                 }
7329         } else { /* paths specified, only attempt to search these. */
7330                 bool opt_mntdir;
7331
7332                 /* if only one path is given, print only requested info */
7333                 opt_mntdir = argc - optind > 1 || (opt_instance == opt_fsname);
7334
7335                 for (; optind < argc; optind++) {
7336                         rc2 = print_instance(argv[optind], fsname,
7337                                              sizeof(fsname), opt_instance,
7338                                              opt_fsname, opt_mntdir);
7339                         if (!rc)
7340                                 rc = rc2;
7341                         fsname[0] = '\0';
7342                 }
7343         }
7344
7345         return rc;
7346 }
7347
7348 static int lfs_check(int argc, char **argv)
7349 {
7350         char mntdir[PATH_MAX] = {'\0'};
7351         int num_types = 1;
7352         char *obd_types[3];
7353         char obd_type1[4];
7354         char obd_type2[4];
7355         char obd_type3[4];
7356         int rc;
7357
7358         if (argc != 2) {
7359                 fprintf(stderr, "%s check: server type must be specified\n",
7360                         progname);
7361                 return CMD_HELP;
7362         }
7363
7364         obd_types[0] = obd_type1;
7365         obd_types[1] = obd_type2;
7366         obd_types[2] = obd_type3;
7367
7368         if (strcmp(argv[1], "osts") == 0) {
7369                 strcpy(obd_types[0], "osc");
7370         } else if (strcmp(argv[1], "mdts") == 0 ||
7371                    strcmp(argv[1], "mds") == 0) {
7372                 strcpy(obd_types[0], "mdc");
7373         } else if (strcmp(argv[1], "mgts") == 0) {
7374                 strcpy(obd_types[0], "mgc");
7375         } else if (strcmp(argv[1], "all") == 0 ||
7376                    strcmp(argv[1], "servers") == 0) {
7377                 num_types = 3;
7378                 strcpy(obd_types[0], "osc");
7379                 strcpy(obd_types[1], "mdc");
7380                 strcpy(obd_types[2], "mgc");
7381         } else {
7382                 fprintf(stderr, "%s check: unrecognized option '%s'\n",
7383                         progname, argv[1]);
7384                 return CMD_HELP;
7385         }
7386
7387         rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
7388         if (rc < 0 || mntdir[0] == '\0') {
7389                 fprintf(stderr,
7390                         "%s check: cannot find mounted Lustre filesystem: %s\n",
7391                         progname, (rc < 0) ? strerror(-rc) : strerror(ENODEV));
7392                 return rc;
7393         }
7394
7395         rc = llapi_target_check(num_types, obd_types, mntdir);
7396         if (rc)
7397                 fprintf(stderr, "%s check: cannot check target '%s': %s\n",
7398                         progname, argv[1], strerror(-rc));
7399
7400         return rc;
7401 }
7402
7403 #ifdef HAVE_SYS_QUOTA_H
7404 #define ADD_OVERFLOW(a, b) \
7405                      ((((a) + (b)) < (a)) ? \
7406                       ((a) = ULONG_MAX) : ((a) = (a) + (b)))
7407
7408 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
7409  * returns the value or ULONG_MAX on integer overflow or incorrect format
7410  * Notes:
7411  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
7412  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
7413  *        3. empty integer value is interpreted as 0
7414  */
7415 static unsigned long str2sec(const char *timestr)
7416 {
7417         const char spec[] = "smhdw";
7418         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
7419         unsigned long val = 0;
7420         char *tail;
7421
7422         if (strpbrk(timestr, spec) == NULL) {
7423                 /*
7424                  * no specifiers inside the time string,
7425                  * should treat it as an integer value
7426                  */
7427                 val = strtoul(timestr, &tail, 10);
7428                 return *tail ? ULONG_MAX : val;
7429         }
7430
7431         /* format string is XXwXXdXXhXXmXXs */
7432         while (*timestr) {
7433                 unsigned long v;
7434                 int ind;
7435                 char *ptr;
7436
7437                 v = strtoul(timestr, &tail, 10);
7438                 if (v == ULONG_MAX || *tail == '\0')
7439                         /*
7440                          * value too large (ULONG_MAX or more)
7441                          * or missing specifier
7442                          */
7443                         goto error;
7444
7445                 ptr = strchr(spec, *tail);
7446                 if (!ptr)
7447                         /* unknown specifier */
7448                         goto error;
7449
7450                 ind = ptr - spec;
7451
7452                 /* check if product will overflow the type */
7453                 if (!(v < ULONG_MAX / mult[ind]))
7454                         goto error;
7455
7456                 ADD_OVERFLOW(val, mult[ind] * v);
7457                 if (val == ULONG_MAX)
7458                         goto error;
7459
7460                 timestr = tail + 1;
7461         }
7462
7463         return val;
7464
7465 error:
7466         return ULONG_MAX;
7467 }
7468
7469 #define ARG2ULL(nr, str, def_units)                                     \
7470 do {                                                                    \
7471         unsigned long long limit, units = def_units;                    \
7472         int rc;                                                         \
7473                                                                         \
7474         rc = llapi_parse_size(str, &limit, &units, 1);                  \
7475         if (rc < 0) {                                                   \
7476                 fprintf(stderr, "%s: invalid limit '%s'\n",             \
7477                         progname, str);                                 \
7478                 return CMD_HELP;                                        \
7479         }                                                               \
7480         nr = limit;                                                     \
7481 } while (0)
7482
7483 static inline int has_times_option(int argc, char **argv)
7484 {
7485         int i;
7486
7487         for (i = 1; i < argc; i++)
7488                 if (!strcmp(argv[i], "-t"))
7489                         return 1;
7490
7491         return 0;
7492 }
7493
7494 static inline int lfs_verify_poolarg(char *pool)
7495 {
7496         if (strnlen(optarg, LOV_MAXPOOLNAME + 1) > LOV_MAXPOOLNAME) {
7497                 fprintf(stderr,
7498                         "Pool name '%.*s' is longer than %d\n",
7499                         LOV_MAXPOOLNAME, pool, LOV_MAXPOOLNAME);
7500                 return 1;
7501         }
7502         return 0;
7503 }
7504
7505 /* special grace time, only notify the user when its quota is over soft limit
7506  * but doesn't block new writes until the hard limit is reached.
7507  */
7508 #define NOTIFY_GRACE            "notify"
7509 #define NOTIFY_GRACE_TIME       LQUOTA_GRACE_MASK
7510
7511 #ifndef toqb
7512 static inline __u64 lustre_stoqb(size_t space)
7513 {
7514         return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
7515 }
7516 #else
7517 #define lustre_stoqb   toqb
7518 #endif
7519
7520 int lfs_setquota_times(int argc, char **argv, struct if_quotactl *qctl)
7521 {
7522         int c, rc;
7523         char *mnt, *obd_type = (char *)qctl->obd_type;
7524         struct obd_dqblk *dqb = &qctl->qc_dqblk;
7525         struct obd_dqinfo *dqi = &qctl->qc_dqinfo;
7526         struct option long_opts[] = {
7527         { .val = 'b',   .name = "block-grace",  .has_arg = required_argument },
7528         { .val = 'g',   .name = "group",        .has_arg = no_argument },
7529         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7530         { .val = 'i',   .name = "inode-grace",  .has_arg = required_argument },
7531         { .val = 'p',   .name = "projid",       .has_arg = no_argument },
7532         { .val = 't',   .name = "times",        .has_arg = no_argument },
7533         { .val = 'u',   .name = "user",         .has_arg = no_argument },
7534         { .val = LFS_POOL_OPT,
7535                         .name = "pool",         .has_arg = required_argument },
7536         { .name = NULL } };
7537         int qtype;
7538
7539         qctl->qc_cmd  = LUSTRE_Q_SETINFO;
7540         qctl->qc_type = ALLQUOTA;
7541
7542         while ((c = getopt_long(argc, argv, "b:ghi:ptu",
7543                                 long_opts, NULL)) != -1) {
7544                 switch (c) {
7545                 case 'u':
7546                         qtype = USRQUOTA;
7547                         goto quota_type;
7548                 case 'g':
7549                         qtype = GRPQUOTA;
7550                         goto quota_type;
7551                 case 'p':
7552                         qtype = PRJQUOTA;
7553 quota_type:
7554                         if (qctl->qc_type != ALLQUOTA) {
7555                                 fprintf(stderr,
7556                                         "%s: -u/g/p cannot be used more than once\n",
7557                                         progname);
7558                                 return CMD_HELP;
7559                         }
7560                         qctl->qc_type = qtype;
7561                         break;
7562                 case 'b':
7563                         if (strncmp(optarg, NOTIFY_GRACE,
7564                                     strlen(NOTIFY_GRACE)) == 0) {
7565                                 dqi->dqi_bgrace = NOTIFY_GRACE_TIME;
7566                         } else {
7567                                 dqi->dqi_bgrace = str2sec(optarg);
7568                                 if (dqi->dqi_bgrace >= NOTIFY_GRACE_TIME) {
7569                                         fprintf(stderr,
7570                                                 "%s: bad block-grace: %s\n",
7571                                                 progname, optarg);
7572                                         return CMD_HELP;
7573                                 }
7574                         }
7575                         dqb->dqb_valid |= QIF_BTIME;
7576                         break;
7577                 case 'i':
7578                         if (strncmp(optarg, NOTIFY_GRACE,
7579                                     strlen(NOTIFY_GRACE)) == 0) {
7580                                 dqi->dqi_igrace = NOTIFY_GRACE_TIME;
7581                         } else {
7582                                 dqi->dqi_igrace = str2sec(optarg);
7583                                 if (dqi->dqi_igrace >= NOTIFY_GRACE_TIME) {
7584                                         fprintf(stderr,
7585                                                 "%s: bad inode-grace: %s\n",
7586                                                 progname, optarg);
7587                                         return CMD_HELP;
7588                                 }
7589                         }
7590                         dqb->dqb_valid |= QIF_ITIME;
7591                         break;
7592                 case 't': /* Yes, of course! */
7593                         break;
7594                 case LFS_POOL_OPT:
7595                         if (lfs_verify_poolarg(optarg))
7596                                 return -1;
7597                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
7598                         qctl->qc_cmd  = LUSTRE_Q_SETINFOPOOL;
7599                         break;
7600                 /* getopt prints error message for us when opterr != 0 */
7601                 default:
7602                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7603                                 progname, argv[optind - 1]);
7604                         /* fallthrough */
7605                 case 'h':
7606                         return CMD_HELP;
7607                 }
7608         }
7609
7610         if (qctl->qc_type == ALLQUOTA) {
7611                 fprintf(stderr, "%s: neither -u, -g nor -p specified\n",
7612                         progname);
7613                 return CMD_HELP;
7614         }
7615
7616         if (optind != argc - 1) {
7617                 fprintf(stderr, "%s: unexpected parameter '%s'\n",
7618                         progname, argv[optind + 1]);
7619                 return CMD_HELP;
7620         }
7621
7622         mnt = argv[optind];
7623         rc = llapi_quotactl(mnt, qctl);
7624         if (rc) {
7625                 if (*obd_type)
7626                         fprintf(stderr, "%s %s ", obd_type,
7627                                 obd_uuid2str(&qctl->obd_uuid));
7628                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
7629                 return rc;
7630         }
7631
7632         return 0;
7633 }
7634
7635 #define BSLIMIT (1 << 0)
7636 #define BHLIMIT (1 << 1)
7637 #define ISLIMIT (1 << 2)
7638 #define IHLIMIT (1 << 3)
7639
7640 int lfs_setquota(int argc, char **argv)
7641 {
7642         int c, rc = 0;
7643         struct if_quotactl *qctl;
7644         char *mnt, *obd_type;
7645         struct obd_dqblk *dqb;
7646         struct option long_opts[] = {
7647         { .val = 'b',   .name = "block-softlimit",
7648                                                 .has_arg = required_argument },
7649         { .val = 'B',   .name = "block-hardlimit",
7650                                                 .has_arg = required_argument },
7651         { .val = 'd',   .name = "default",      .has_arg = no_argument },
7652         { .val = 'g',   .name = "group",        .has_arg = required_argument },
7653         { .val = 'G',   .name = "default-grp",  .has_arg = no_argument },
7654         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7655         { .val = 'i',   .name = "inode-softlimit",
7656                                                 .has_arg = required_argument },
7657         { .val = 'I',   .name = "inode-hardlimit",
7658                                                 .has_arg = required_argument },
7659         { .val = 'p',   .name = "projid",       .has_arg = required_argument },
7660         { .val = 'P',   .name = "default-prj",  .has_arg = no_argument },
7661         { .val = 'u',   .name = "user",         .has_arg = required_argument },
7662         { .val = 'U',   .name = "default-usr",  .has_arg = no_argument },
7663         { .val = LFS_POOL_OPT,
7664                         .name = "pool",         .has_arg = required_argument },
7665         { .name = NULL } };
7666         unsigned int limit_mask = 0;
7667         bool use_default = false;
7668         int qtype, qctl_len;
7669
7670         qctl_len = sizeof(*qctl) + LOV_MAXPOOLNAME + 1;
7671         qctl = malloc(qctl_len);
7672         if (!qctl)
7673                 return -ENOMEM;
7674
7675         memset(qctl, 0, qctl_len);
7676         obd_type = (char *)qctl->obd_type;
7677         dqb = &qctl->qc_dqblk;
7678
7679         if (has_times_option(argc, argv)) {
7680                 rc = lfs_setquota_times(argc, argv, qctl);
7681                 goto out;
7682         }
7683
7684         qctl->qc_cmd  = LUSTRE_Q_SETQUOTA;
7685         qctl->qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
7686                                    * so it can be used as a marker that qc_type
7687                                    * isn't reinitialized from command line
7688                                    */
7689
7690         while ((c = getopt_long(argc, argv, "b:B:dg:Ghi:I:p:Pu:U",
7691                 long_opts, NULL)) != -1) {
7692                 switch (c) {
7693                 case 'U':
7694                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
7695                         qtype = USRQUOTA;
7696                         qctl->qc_id = 0;
7697                         goto quota_type_def;
7698                 case 'u':
7699                         qtype = USRQUOTA;
7700                         rc = name2uid(&qctl->qc_id, optarg);
7701                         goto quota_type;
7702                 case 'G':
7703                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
7704                         qtype = GRPQUOTA;
7705                         qctl->qc_id = 0;
7706                         goto quota_type_def;
7707                 case 'g':
7708                         qtype = GRPQUOTA;
7709                         rc = name2gid(&qctl->qc_id, optarg);
7710                         goto quota_type;
7711                 case 'P':
7712                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
7713                         qtype = PRJQUOTA;
7714                         qctl->qc_id = 0;
7715                         goto quota_type_def;
7716                 case 'p':
7717                         qtype = PRJQUOTA;
7718                         rc = name2projid(&qctl->qc_id, optarg);
7719 quota_type:
7720                         if (rc) {
7721                                 if (str2quotaid(&qctl->qc_id, optarg)) {
7722                                         fprintf(stderr,
7723                                                 "%s setquota: invalid id '%s'\n",
7724                                                 progname, optarg);
7725                                         rc = -1;
7726                                         goto out;
7727                                 }
7728                         }
7729
7730                         if (qctl->qc_id == 0) {
7731                                 fprintf(stderr,
7732                                         "%s setquota: can't set quota for root usr/group/project.\n",
7733                                         progname);
7734                                 rc = -1;
7735                                 goto out;
7736                         }
7737
7738 quota_type_def:
7739                         if (qctl->qc_type != ALLQUOTA) {
7740                                 fprintf(stderr,
7741                                         "%s setquota: only one of -u, -U, -g, -G, -p or -P may be specified\n",
7742                                         progname);
7743                                 rc = CMD_HELP;
7744                                 goto out;
7745                         }
7746                         qctl->qc_type = qtype;
7747                         break;
7748                 case 'd':
7749                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
7750                         use_default = true;
7751                         break;
7752                 case 'b':
7753                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
7754                         dqb->dqb_bsoftlimit >>= 10;
7755                         limit_mask |= BSLIMIT;
7756                         if (dqb->dqb_bsoftlimit &&
7757                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
7758                                 fprintf(stderr,
7759                                         "%s setquota: warning: block softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
7760                                         progname,
7761                                         (unsigned long long)dqb->dqb_bsoftlimit,
7762                                         progname);
7763                         break;
7764                 case 'B':
7765                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
7766                         dqb->dqb_bhardlimit >>= 10;
7767                         limit_mask |= BHLIMIT;
7768                         if (dqb->dqb_bhardlimit &&
7769                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
7770                                 fprintf(stderr,
7771                                         "%s setquota: warning: block hardlimit '%llu' smaller than minimum qunit size\n"
7772                                         "See '%s help setquota' or Lustre manual for details\n",
7773                                         progname,
7774                                         (unsigned long long)dqb->dqb_bhardlimit,
7775                                         progname);
7776                         break;
7777                 case 'i':
7778                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
7779                         limit_mask |= ISLIMIT;
7780                         if (dqb->dqb_isoftlimit &&
7781                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
7782                                 fprintf(stderr,
7783                                         "%s setquota: warning: inode softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
7784                                         progname,
7785                                         (unsigned long long)dqb->dqb_isoftlimit,
7786                                         progname);
7787                         break;
7788                 case 'I':
7789                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
7790                         limit_mask |= IHLIMIT;
7791                         if (dqb->dqb_ihardlimit &&
7792                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
7793                                 fprintf(stderr,
7794                                         "%s setquota: warning: inode hardlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
7795                                         progname,
7796                                         (unsigned long long)dqb->dqb_ihardlimit,
7797                                         progname);
7798                         break;
7799                 case LFS_POOL_OPT:
7800                         if (lfs_verify_poolarg(optarg)) {
7801                                 rc = -1;
7802                                 goto out;
7803                         }
7804                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
7805                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_SETDEFAULT ?
7806                                                 LUSTRE_Q_SETDEFAULT_POOL :
7807                                                 LUSTRE_Q_SETQUOTAPOOL;
7808                         break;
7809                 default:
7810                         fprintf(stderr,
7811                                 "%s setquota: unrecognized option '%s'\n",
7812                                 progname, argv[optind - 1]);
7813                         /* fallthrough */
7814                 case 'h':
7815                         rc = CMD_HELP;
7816                         goto out;
7817                 }
7818         }
7819
7820         if (qctl->qc_type == ALLQUOTA) {
7821                 fprintf(stderr,
7822                         "%s setquota: either -u or -g must be specified\n",
7823                         progname);
7824                 rc = CMD_HELP;
7825                 goto out;
7826         }
7827
7828         if (!use_default && limit_mask == 0) {
7829                 fprintf(stderr,
7830                         "%s setquota: at least one limit must be specified\n",
7831                         progname);
7832                 rc = CMD_HELP;
7833                 goto out;
7834         }
7835
7836         if (use_default && limit_mask != 0) {
7837                 fprintf(stderr,
7838                         "%s setquota: limits should not be specified when using default quota\n",
7839                         progname);
7840                 rc = CMD_HELP;
7841                 goto out;
7842         }
7843
7844         if (use_default && qctl->qc_id == 0) {
7845                 fprintf(stderr,
7846                         "%s setquota: can not set default quota for root user/group/project\n",
7847                         progname);
7848                 rc = CMD_HELP;
7849                 goto out;
7850         }
7851
7852         if (optind != argc - 1) {
7853                 fprintf(stderr,
7854                         "%s setquota: filesystem not specified or unexpected argument '%s'\n",
7855                         progname, argv[optind]);
7856                 rc = CMD_HELP;
7857                 goto out;
7858         }
7859
7860         mnt = argv[optind];
7861
7862         if (use_default) {
7863                 dqb->dqb_bhardlimit = 0;
7864                 dqb->dqb_bsoftlimit = 0;
7865                 dqb->dqb_ihardlimit = 0;
7866                 dqb->dqb_isoftlimit = 0;
7867                 dqb->dqb_itime = 0;
7868                 dqb->dqb_btime = 0;
7869                 dqb->dqb_valid |= QIF_LIMITS | QIF_TIMES;
7870                 /* do not set inode limits for Pool Quotas */
7871                 if (qctl->qc_cmd  == LUSTRE_Q_SETDEFAULT_POOL)
7872                         dqb->dqb_valid ^= QIF_ILIMITS | QIF_ITIME;
7873         } else if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
7874                    (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
7875                 /* sigh, we can't just set blimits/ilimits */
7876                 struct if_quotactl tmp_qctl = {.qc_cmd  = LUSTRE_Q_GETQUOTA,
7877                                                .qc_type = qctl->qc_type,
7878                                                .qc_id   = qctl->qc_id};
7879
7880                 rc = llapi_quotactl(mnt, &tmp_qctl);
7881                 if (rc < 0)
7882                         goto out;
7883
7884                 if (!(limit_mask & BHLIMIT))
7885                         dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
7886                 if (!(limit_mask & BSLIMIT))
7887                         dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
7888                 if (!(limit_mask & IHLIMIT))
7889                         dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
7890                 if (!(limit_mask & ISLIMIT))
7891                         dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
7892
7893                 /* Keep grace times if we have got no softlimit arguments */
7894                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
7895                         dqb->dqb_valid |= QIF_BTIME;
7896                         dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
7897                 }
7898
7899                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
7900                         dqb->dqb_valid |= QIF_ITIME;
7901                         dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
7902                 }
7903         }
7904
7905         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
7906         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
7907
7908         rc = llapi_quotactl(mnt, qctl);
7909         if (rc) {
7910                 if (*obd_type)
7911                         fprintf(stderr,
7912                                 "%s setquota: cannot quotactl '%s' '%s': %s\n",
7913                                 progname, obd_type,
7914                                 obd_uuid2str(&qctl->obd_uuid), strerror(-rc));
7915                 else
7916                         fprintf(stderr,
7917                                 "%s setquota: quotactl failed: %s\n",
7918                                 progname, strerror(-rc));
7919         }
7920 out:
7921         if (rc)
7922                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
7923
7924         free(qctl);
7925         return rc;
7926 }
7927
7928 /* Converts seconds value into format string
7929  * result is returned in buf
7930  * Notes:
7931  *        1. result is in descenting order: 1w2d3h4m5s
7932  *        2. zero fields are not filled (except for p. 3): 5d1s
7933  *        3. zero seconds value is presented as "0s"
7934  */
7935 static char *__sec2str(time_t seconds, char *buf)
7936 {
7937         const char spec[] = "smhdw";
7938         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
7939         unsigned long c;
7940         char *tail = buf;
7941         int i;
7942
7943         for (i = ARRAY_SIZE(mult) - 1 ; i >= 0; i--) {
7944                 c = seconds / mult[i];
7945
7946                 if (c > 0 || (i == 0 && buf == tail))
7947                         tail += scnprintf(tail, 40-(tail-buf), "%lu%c", c,
7948                                           spec[i]);
7949
7950                 seconds %= mult[i];
7951         }
7952
7953         return tail;
7954 }
7955
7956 static void sec2str(time_t seconds, char *buf, int rc)
7957 {
7958         char *tail = buf;
7959
7960         if (rc)
7961                 *tail++ = '[';
7962
7963         tail = __sec2str(seconds, tail);
7964
7965         if (rc && tail - buf < 39) {
7966                 *tail++ = ']';
7967                 *tail++ = 0;
7968         }
7969 }
7970
7971 static void diff2str(time_t seconds, char *buf, time_t now)
7972 {
7973         buf[0] = 0;
7974         if (!seconds)
7975                 return;
7976         if (seconds <= now) {
7977                 strcpy(buf, "none");
7978                 return;
7979         }
7980         __sec2str(seconds - now, buf);
7981 }
7982
7983 static void print_quota_title(char *name, struct if_quotactl *qctl,
7984                               bool human_readable, bool show_default)
7985 {
7986         if (show_default) {
7987                 printf("Disk default %s quota:\n", qtype_name(qctl->qc_type));
7988                 printf("%15s %8s%8s%8s %8s%8s%8s\n",
7989                        "Filesystem", "bquota", "blimit", "bgrace",
7990                        "iquota", "ilimit", "igrace");
7991         } else {
7992                 printf("Disk quotas for %s %s (%cid %u):\n",
7993                        qtype_name(qctl->qc_type), name,
7994                        *qtype_name(qctl->qc_type), qctl->qc_id);
7995                 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
7996                        "Filesystem", human_readable ? "used" : "kbytes",
7997                        "quota", "limit", "grace",
7998                        "files", "quota", "limit", "grace");
7999         }
8000 }
8001
8002 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
8003 {
8004         if (!h) {
8005                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
8006         } else {
8007                 if (num >> 40)
8008                         snprintf(buf, buflen, "%5.4gP",
8009                                  (double)num / ((__u64)1 << 40));
8010                 else if (num >> 30)
8011                         snprintf(buf, buflen, "%5.4gT",
8012                                  (double)num / (1 << 30));
8013                 else if (num >> 20)
8014                         snprintf(buf, buflen, "%5.4gG",
8015                                  (double)num / (1 << 20));
8016                 else if (num >> 10)
8017                         snprintf(buf, buflen, "%5.4gM",
8018                                  (double)num / (1 << 10));
8019                 else
8020                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
8021         }
8022 }
8023
8024 #ifdef HAVE_NATIVE_CLIENT
8025 /* In the current Lustre implementation, the grace time is either the time
8026  * or the timestamp to be used after some quota ID exceeds the soft limt,
8027  * 48 bits should be enough, its high 16 bits can be used as quota flags.
8028  */
8029 #define LQUOTA_GRACE_BITS       48
8030 #define LQUOTA_GRACE_MASK       ((1ULL << LQUOTA_GRACE_BITS) - 1)
8031 #define LQUOTA_GRACE_MAX        LQUOTA_GRACE_MASK
8032 #define LQUOTA_GRACE(t)         (t & LQUOTA_GRACE_MASK)
8033 #define LQUOTA_FLAG(t)          (t >> LQUOTA_GRACE_BITS)
8034 #define LQUOTA_GRACE_FLAG(t, f) ((__u64)t | (__u64)f << LQUOTA_GRACE_BITS)
8035 #endif
8036
8037 #define STRBUF_LEN      24
8038 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
8039                         int rc, bool h, bool show_default)
8040 {
8041         time_t now;
8042
8043         time(&now);
8044
8045         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA ||
8046             qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
8047             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT ||
8048             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL) {
8049                 int bover = 0, iover = 0;
8050                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
8051                 char numbuf[3][STRBUF_LEN + 2]; /* 2 for brackets or wildcard */
8052                 char timebuf[40];
8053                 char strbuf[STRBUF_LEN];
8054
8055                 if (dqb->dqb_bhardlimit &&
8056                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
8057                         bover = 1;
8058                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
8059                         if (dqb->dqb_btime > now)
8060                                 bover = 2;
8061                         else
8062                                 bover = 3;
8063                 }
8064
8065                 if (dqb->dqb_ihardlimit &&
8066                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
8067                         iover = 1;
8068                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
8069                         if (dqb->dqb_itime > now)
8070                                 iover = 2;
8071                         else
8072                                 iover = 3;
8073                 }
8074
8075                 if (strlen(mnt) > 15)
8076                         printf("%s\n%15s", mnt, "");
8077                 else
8078                         printf("%15s", mnt);
8079
8080                 if (bover)
8081                         diff2str(dqb->dqb_btime, timebuf, now);
8082                 else if (show_default)
8083                         snprintf(timebuf, sizeof(timebuf), "%llu",
8084                                  (unsigned long long)dqb->dqb_btime);
8085
8086                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
8087                            strbuf, sizeof(strbuf), h);
8088                 if (rc == -EREMOTEIO)
8089                         sprintf(numbuf[0], "%s*", strbuf);
8090                 else
8091                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
8092                                 "%s" : "[%s]", strbuf);
8093
8094                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
8095                 if (type == QC_GENERAL)
8096                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
8097                                 "%s" : "[%s]", strbuf);
8098                 else
8099                         sprintf(numbuf[1], "%s", "-");
8100
8101                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
8102                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
8103                         "%s" : "[%s]", strbuf);
8104
8105                 if (show_default)
8106                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
8107                 else
8108                         printf(" %7s%c %6s %7s %7s",
8109                                numbuf[0], bover ? '*' : ' ', numbuf[1],
8110                                numbuf[2], bover > 1 ? timebuf : "-");
8111
8112                 if (iover)
8113                         diff2str(dqb->dqb_itime, timebuf, now);
8114                 else if (show_default)
8115                         snprintf(timebuf, sizeof(timebuf), "%llu",
8116                                  (unsigned long long)dqb->dqb_itime);
8117
8118                 snprintf(numbuf[0], sizeof(numbuf),
8119                          (dqb->dqb_valid & QIF_INODES) ? "%ju" : "[%ju]",
8120                          (uintmax_t)dqb->dqb_curinodes);
8121
8122                 if (type == QC_GENERAL)
8123                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
8124                                 "%ju" : "[%ju]",
8125                                 (uintmax_t)dqb->dqb_isoftlimit);
8126                 else
8127                         sprintf(numbuf[1], "%s", "-");
8128
8129                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
8130                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
8131
8132                 if (show_default)
8133                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
8134                 else if (type != QC_OSTIDX)
8135                         printf(" %7s%c %6s %7s %7s",
8136                                numbuf[0], iover ? '*' : ' ', numbuf[1],
8137                                numbuf[2], iover > 1 ? timebuf : "-");
8138                 else
8139                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
8140                 printf("\n");
8141         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO || LUSTRE_Q_GETINFOPOOL ||
8142                    qctl->qc_cmd == Q_GETOINFO) {
8143                 char bgtimebuf[40];
8144                 char igtimebuf[40];
8145
8146                 if (qctl->qc_dqinfo.dqi_bgrace == NOTIFY_GRACE_TIME)
8147                         strncpy(bgtimebuf, NOTIFY_GRACE, 40);
8148                 else
8149                         sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
8150                 if (qctl->qc_dqinfo.dqi_igrace == NOTIFY_GRACE_TIME)
8151                         strncpy(igtimebuf, NOTIFY_GRACE, 40);
8152                 else
8153                         sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
8154
8155                 printf("Block grace time: %s; Inode grace time: %s\n",
8156                        bgtimebuf, igtimebuf);
8157         }
8158 }
8159
8160 static int tgt_name2index(const char *tgtname, unsigned int *idx)
8161 {
8162         char *dash, *endp;
8163
8164         /* format is "lustre-OST0001" */
8165         dash = memchr(tgtname, '-', LUSTRE_MAXFSNAME + 1);
8166         if (!dash) {
8167                 fprintf(stderr, "wrong tgtname format '%s'\n", tgtname);
8168                 return -EINVAL;
8169         }
8170         dash += 4;
8171
8172         *idx = strtoul(dash, &endp, 16);
8173         if (*idx > 0xffff) {
8174                 fprintf(stderr, "wrong index %s\n", tgtname);
8175                 return -ERANGE;
8176         }
8177
8178         return 0;
8179 }
8180
8181 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
8182                            bool h, __u64 *total)
8183 {
8184         int rc = 0, rc1 = 0, count = 0, i = 0;
8185         char **list = NULL, *buffer = NULL;
8186         __u32 valid = qctl->qc_valid;
8187
8188         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL && is_mdt)
8189                 return 0;
8190
8191         /* Is it correct for the case OST0000, OST0002, OST0003 -
8192          * we will ask OST0001 that is absent and won't ask OST0003? */
8193         rc = llapi_get_obd_count(mnt, &count, is_mdt);
8194         if (rc) {
8195                 fprintf(stderr, "can not get %s count: %s\n",
8196                         is_mdt ? "mdt" : "ost", strerror(-rc));
8197                 return rc;
8198         }
8199
8200         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
8201                 char fname[PATH_MAX];
8202                 char fsname[LUSTRE_MAXFSNAME + 1];
8203                 int bufsize = sizeof(struct obd_uuid) * count;
8204
8205                 rc = llapi_search_fsname(mnt, fsname);
8206                 if (rc) {
8207                         fprintf(stderr, "cannot get fsname for mountpoint %s\n",
8208                                 mnt);
8209                         goto out;
8210                 }
8211                 buffer = malloc(bufsize + sizeof(*list) * count);
8212                 if (!buffer)
8213                         return -ENOMEM;
8214                 list = (char **)(buffer + bufsize);
8215                 snprintf(fname, PATH_MAX, "%s.%s", fsname, qctl->qc_poolname);
8216                 count = llapi_get_poolmembers(fname, list, count,
8217                                               buffer, bufsize);
8218                 if (count <= 0)
8219                         goto out;
8220         }
8221
8222         for (i = 0; i < count; i++) {
8223                 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
8224                         unsigned int index;
8225
8226                         if (tgt_name2index(list[i], &index))
8227                                 continue;
8228                         qctl->qc_idx = index;
8229                 } else {
8230                         qctl->qc_idx = i;
8231                 }
8232
8233                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
8234                 rc = llapi_quotactl(mnt, qctl);
8235                 if (rc) {
8236                         /* It is remote client case. */
8237                         if (rc == -EOPNOTSUPP) {
8238                                 rc = 0;
8239                                 goto out;
8240                         }
8241
8242                         if (!rc1)
8243                                 rc1 = rc;
8244                         fprintf(stderr, "quotactl %s%d failed.\n",
8245                                 is_mdt ? "mdt" : "ost", qctl->qc_idx);
8246                         continue;
8247                 }
8248
8249                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
8250                             qctl->qc_valid, 0, h, false);
8251                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
8252                                    qctl->qc_dqblk.dqb_bhardlimit;
8253         }
8254 out:
8255         if (buffer)
8256                 free(buffer);
8257         qctl->qc_valid = valid;
8258         return rc ? : rc1;
8259 }
8260
8261 static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
8262                            int verbose, int quiet, bool human_readable,
8263                            bool show_default)
8264 {
8265         int rc1 = 0, rc2 = 0, rc3 = 0;
8266         char *obd_type = (char *)qctl->obd_type;
8267         char *obd_uuid = (char *)qctl->obd_uuid.uuid;
8268         __u64 total_ialloc = 0, total_balloc = 0;
8269         bool use_default_for_blk = false;
8270         bool use_default_for_file = false;
8271         int inacc;
8272
8273         rc1 = llapi_quotactl(mnt, qctl);
8274         if (rc1 < 0) {
8275                 switch (rc1) {
8276                 case -ESRCH:
8277                         fprintf(stderr, "%s quotas are not enabled.\n",
8278                                 qtype_name(qctl->qc_type));
8279                         goto out;
8280                 case -EPERM:
8281                         fprintf(stderr, "Permission denied.\n");
8282                 case -ENODEV:
8283                 case -ENOENT:
8284                         /* We already got error message. */
8285                         goto out;
8286                 default:
8287                         fprintf(stderr, "Unexpected quotactl error: %s\n",
8288                                 strerror(-rc1));
8289                 }
8290         }
8291
8292         if (!show_default && qctl->qc_id == 0) {
8293                 qctl->qc_dqblk.dqb_bhardlimit = 0;
8294                 qctl->qc_dqblk.dqb_bsoftlimit = 0;
8295                 qctl->qc_dqblk.dqb_ihardlimit = 0;
8296                 qctl->qc_dqblk.dqb_isoftlimit = 0;
8297                 qctl->qc_dqblk.dqb_btime = 0;
8298                 qctl->qc_dqblk.dqb_itime = 0;
8299                 qctl->qc_dqblk.dqb_valid |= QIF_LIMITS | QIF_TIMES;
8300         }
8301
8302         if (qctl->qc_dqblk.dqb_valid & QIF_BTIME &&
8303             LQUOTA_FLAG(qctl->qc_dqblk.dqb_btime) & LQUOTA_FLAG_DEFAULT) {
8304                 use_default_for_blk = true;
8305                 qctl->qc_dqblk.dqb_btime &= LQUOTA_GRACE_MASK;
8306         }
8307
8308         if (qctl->qc_dqblk.dqb_valid & QIF_ITIME &&
8309             LQUOTA_FLAG(qctl->qc_dqblk.dqb_itime) & LQUOTA_FLAG_DEFAULT) {
8310                 use_default_for_file = true;
8311                 qctl->qc_dqblk.dqb_itime &= LQUOTA_GRACE_MASK;
8312         }
8313
8314         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
8315              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
8316              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL ||
8317              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) && !quiet)
8318                 print_quota_title(name, qctl, human_readable, show_default);
8319
8320         if (rc1 && *obd_type)
8321                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
8322
8323         if (qctl->qc_valid != QC_GENERAL)
8324                 mnt = "";
8325
8326         inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
8327                  qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
8328                 ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
8329                  (QIF_LIMITS|QIF_USAGE));
8330
8331         print_quota(mnt, qctl, QC_GENERAL, rc1, human_readable, show_default);
8332
8333         if (!show_default && verbose &&
8334             qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO &&
8335             qctl->qc_cmd != LUSTRE_Q_GETINFOPOOL) {
8336                 char strbuf[STRBUF_LEN];
8337
8338                 rc2 = print_obd_quota(mnt, qctl, 1, human_readable,
8339                                       &total_ialloc);
8340                 rc3 = print_obd_quota(mnt, qctl, 0, human_readable,
8341                                       &total_balloc);
8342                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
8343                            human_readable);
8344                 printf("Total allocated inode limit: %ju, total allocated block limit: %s\n",
8345                        (uintmax_t)total_ialloc, strbuf);
8346         }
8347
8348         if (use_default_for_blk)
8349                 printf("%cid %u is using default block quota setting\n",
8350                        *qtype_name(qctl->qc_type), qctl->qc_id);
8351
8352         if (use_default_for_file)
8353                 printf("%cid %u is using default file quota setting\n",
8354                        *qtype_name(qctl->qc_type), qctl->qc_id);
8355
8356         if (rc1 || rc2 || rc3 || inacc)
8357                 printf("Some errors happened when getting quota info. Some devices may be not working or deactivated. The data in \"[]\" is inaccurate.\n");
8358 out:
8359         if (rc1)
8360                 return rc1;
8361         if (rc2)
8362                 return rc2;
8363         if (rc3)
8364                 return rc3;
8365         if (inacc)
8366                 return -EIO;
8367
8368         return 0;
8369 }
8370
8371 static int lfs_project(int argc, char **argv)
8372 {
8373         int ret = 0, err = 0, c, i;
8374         struct project_handle_control phc = { 0 };
8375         enum lfs_project_ops_t op;
8376
8377         phc.newline = true;
8378         phc.assign_projid = false;
8379         /* default action */
8380         op = LFS_PROJECT_LIST;
8381
8382         while ((c = getopt(argc, argv, "p:cCsdkr0")) != -1) {
8383                 switch (c) {
8384                 case 'c':
8385                         if (op != LFS_PROJECT_LIST) {
8386                                 fprintf(stderr,
8387                                         "%s: cannot specify '-c' '-C' '-s' together\n",
8388                                         progname);
8389                                 return CMD_HELP;
8390                         }
8391
8392                         op = LFS_PROJECT_CHECK;
8393                         break;
8394                 case 'C':
8395                         if (op != LFS_PROJECT_LIST) {
8396                                 fprintf(stderr,
8397                                         "%s: cannot specify '-c' '-C' '-s' together\n",
8398                                         progname);
8399                                 return CMD_HELP;
8400                         }
8401
8402                         op = LFS_PROJECT_CLEAR;
8403                         break;
8404                 case 's':
8405                         if (op != LFS_PROJECT_LIST) {
8406                                 fprintf(stderr,
8407                                         "%s: cannot specify '-c' '-C' '-s' together\n",
8408                                         progname);
8409                                 return CMD_HELP;
8410                         }
8411
8412                         phc.set_inherit = true;
8413                         op = LFS_PROJECT_SET;
8414                         break;
8415                 case 'd':
8416                         phc.dironly = true;
8417                         break;
8418                 case 'k':
8419                         phc.keep_projid = true;
8420                         break;
8421                 case 'r':
8422                         phc.recursive = true;
8423                         break;
8424                 case 'p':
8425                         if (str2quotaid(&phc.projid, optarg)) {
8426                                 fprintf(stderr,
8427                                         "Invalid project ID: %s\n",
8428                                         optarg);
8429                                 return CMD_HELP;
8430                         }
8431
8432                         phc.assign_projid = true;
8433
8434                         break;
8435                 case '0':
8436                         phc.newline = false;
8437                         break;
8438                 default:
8439                         fprintf(stderr, "%s: invalid option '%c'\n",
8440                                 progname, optopt);
8441                         return CMD_HELP;
8442                 }
8443         }
8444
8445         if (phc.assign_projid && op == LFS_PROJECT_LIST) {
8446                 op = LFS_PROJECT_SET;
8447                 phc.set_projid = true;
8448         } else if (phc.assign_projid && op == LFS_PROJECT_SET) {
8449                 phc.set_projid = true;
8450         }
8451
8452         switch (op) {
8453         case LFS_PROJECT_CHECK:
8454                 if (phc.keep_projid) {
8455                         fprintf(stderr,
8456                                 "%s: '-k' is useless together with '-c'\n",
8457                                 progname);
8458                         return CMD_HELP;
8459                 }
8460                 break;
8461         case LFS_PROJECT_CLEAR:
8462                 if (!phc.newline) {
8463                         fprintf(stderr,
8464                                 "%s: '-0' is useless together with '-C'\n",
8465                                 progname);
8466                         return CMD_HELP;
8467                 }
8468                 if (phc.assign_projid) {
8469                         fprintf(stderr,
8470                                 "%s: '-p' is useless together with '-C'\n",
8471                                 progname);
8472                         return CMD_HELP;
8473                 }
8474                 break;
8475         case LFS_PROJECT_SET:
8476                 if (!phc.newline) {
8477                         fprintf(stderr,
8478                                 "%s: '-0' is useless together with '-s'\n",
8479                                 progname);
8480                         return CMD_HELP;
8481                 }
8482                 if (phc.keep_projid) {
8483                         fprintf(stderr,
8484                                 "%s: '-k' is useless together with '-s'\n",
8485                                 progname);
8486                         return CMD_HELP;
8487                 }
8488                 break;
8489         default:
8490                 if (!phc.newline) {
8491                         fprintf(stderr,
8492                                 "%s: '-0' is useless for list operations\n",
8493                                 progname);
8494                         return CMD_HELP;
8495                 }
8496                 break;
8497         }
8498
8499         argv += optind;
8500         argc -= optind;
8501         if (argc == 0) {
8502                 fprintf(stderr, "%s: missing file or directory target(s)\n",
8503                         progname);
8504                 return CMD_HELP;
8505         }
8506
8507         for (i = 0; i < argc; i++) {
8508                 switch (op) {
8509                 case LFS_PROJECT_CHECK:
8510                         err = lfs_project_check(argv[i], &phc);
8511                         break;
8512                 case LFS_PROJECT_LIST:
8513                         err = lfs_project_list(argv[i], &phc);
8514                         break;
8515                 case LFS_PROJECT_CLEAR:
8516                         err = lfs_project_clear(argv[i], &phc);
8517                         break;
8518                 case LFS_PROJECT_SET:
8519                         err = lfs_project_set(argv[i], &phc);
8520                         break;
8521                 default:
8522                         break;
8523                 }
8524                 if (err && !ret)
8525                         ret = err;
8526         }
8527
8528         return ret;
8529 }
8530
8531 static int lfs_quota(int argc, char **argv)
8532 {
8533         int c;
8534         char *mnt, *name = NULL;
8535         struct if_quotactl *qctl;
8536         char *obd_uuid;
8537         int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
8538         __u32 valid = QC_GENERAL, idx = 0;
8539         bool human_readable = false;
8540         bool show_default = false;
8541         int qtype;
8542         bool show_pools = false;
8543         struct option long_opts[] = {
8544         { .val = LFS_POOL_OPT, .name = "pool", .has_arg = optional_argument },
8545         { .name = NULL } };
8546         char **poollist = NULL;
8547         char *buf = NULL;
8548         int poolcount, i;
8549
8550         qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1);
8551         if (!qctl)
8552                 return -ENOMEM;
8553
8554         qctl->qc_cmd = LUSTRE_Q_GETQUOTA;
8555         qctl->qc_type = ALLQUOTA;
8556         obd_uuid = (char *)qctl->obd_uuid.uuid;
8557
8558         while ((c = getopt_long(argc, argv, "gGi:I:o:pPqtuUvh",
8559                 long_opts, NULL)) != -1) {
8560                 switch (c) {
8561                 case 'U':
8562                         show_default = true;
8563                 case 'u':
8564                         qtype = USRQUOTA;
8565                         goto quota_type;
8566                 case 'G':
8567                         show_default = true;
8568                 case 'g':
8569                         qtype = GRPQUOTA;
8570                         goto quota_type;
8571                 case 'P':
8572                         show_default = true;
8573                 case 'p':
8574                         qtype = PRJQUOTA;
8575 quota_type:
8576                         if (qctl->qc_type != ALLQUOTA) {
8577                                 fprintf(stderr,
8578                                         "%s quota: only one of -u, -g, or -p may be specified\n",
8579                                         progname);
8580                                 rc = CMD_HELP;
8581                                 goto out;
8582                         }
8583                         qctl->qc_type = qtype;
8584                         break;
8585                 case 't':
8586                         qctl->qc_cmd = LUSTRE_Q_GETINFO;
8587                         break;
8588                 case 'o':
8589                         valid = qctl->qc_valid = QC_UUID;
8590                         snprintf(obd_uuid, sizeof(*obd_uuid), "%s", optarg);
8591                         break;
8592                 case 'i':
8593                         valid = qctl->qc_valid = QC_MDTIDX;
8594                         idx = qctl->qc_idx = atoi(optarg);
8595                         if (idx == 0 && *optarg != '0') {
8596                                 fprintf(stderr,
8597                                         "%s quota: invalid MDT index '%s'\n",
8598                                         progname, optarg);
8599                                 rc = CMD_HELP;
8600                                 goto out;
8601                         }
8602                         break;
8603                 case 'I':
8604                         valid = qctl->qc_valid = QC_OSTIDX;
8605                         idx = qctl->qc_idx = atoi(optarg);
8606                         if (idx == 0 && *optarg != '0') {
8607                                 fprintf(stderr,
8608                                         "%s quota: invalid OST index '%s'\n",
8609                                         progname, optarg);
8610                                 rc = CMD_HELP;
8611                                 goto out;
8612                         }
8613                         break;
8614                 case 'v':
8615                         verbose = 1;
8616                         break;
8617                 case 'q':
8618                         quiet = 1;
8619                         break;
8620                 case 'h':
8621                         human_readable = true;
8622                         break;
8623                 case LFS_POOL_OPT:
8624                         if ((!optarg) && (argv[optind] != NULL) &&
8625                                 (argv[optind][0] != '-') &&
8626                                 (argv[optind][0] != '/')) {
8627                                 optarg = argv[optind++];
8628                                 if (lfs_verify_poolarg(optarg)) {
8629                                         rc = -EINVAL;
8630                                         goto out;
8631                                 }
8632                                 strncpy(qctl->qc_poolname, optarg,
8633                                         LOV_MAXPOOLNAME);
8634                                 if (qctl->qc_cmd == LUSTRE_Q_GETINFO)
8635                                         qctl->qc_cmd = LUSTRE_Q_GETINFOPOOL;
8636                                 else
8637                                         qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
8638                                 break;
8639                         }
8640
8641                         /* optarg is NULL */
8642                         show_pools = true;
8643                         qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
8644                         break;
8645                 default:
8646                         fprintf(stderr, "%s quota: unrecognized option '%s'\n",
8647                                 progname, argv[optind - 1]);
8648                         rc = CMD_HELP;
8649                         goto out;
8650                 }
8651         }
8652
8653         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
8654         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
8655              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
8656              qctl->qc_type == ALLQUOTA &&
8657              optind == argc - 1 && !show_default) {
8658                 qctl->qc_idx = idx;
8659
8660                 for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) {
8661                         qctl->qc_type = qtype;
8662                         qctl->qc_valid = valid;
8663                         if (qtype == USRQUOTA) {
8664                                 qctl->qc_id = geteuid();
8665                                 rc = uid2name(&name, qctl->qc_id);
8666                         } else {
8667                                 qctl->qc_id = getegid();
8668                                 rc = gid2name(&name, qctl->qc_id);
8669                                 memset(&qctl->qc_dqblk, 0,
8670                                        sizeof(qctl->qc_dqblk));
8671                         }
8672                         if (rc)
8673                                 name = "<unknown>";
8674                         mnt = argv[optind];
8675                         rc1 = get_print_quota(mnt, name, qctl, verbose, quiet,
8676                                               human_readable, show_default);
8677                         if (rc1 && !rc)
8678                                 rc = rc1;
8679                 }
8680                 goto out;
8681         /* lfs quota -u username /path/to/lustre/mount */
8682         } else if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
8683                    qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
8684                 /* options should be followed by u/g-name and mntpoint */
8685                 if ((!show_default && optind + 2 != argc) ||
8686                     (show_default && optind + 1 != argc) ||
8687                     qctl->qc_type == ALLQUOTA) {
8688                         fprintf(stderr,
8689                                 "%s quota: name and mount point must be specified\n",
8690                                 progname);
8691                         rc = CMD_HELP;
8692                         goto out;
8693                 }
8694
8695                 if (!show_default) {
8696                         name = argv[optind++];
8697                         switch (qctl->qc_type) {
8698                         case USRQUOTA:
8699                                 rc = name2uid(&qctl->qc_id, name);
8700                                 break;
8701                         case GRPQUOTA:
8702                                 rc = name2gid(&qctl->qc_id, name);
8703                                 break;
8704                         case PRJQUOTA:
8705                                 rc = name2projid(&qctl->qc_id, name);
8706                                 break;
8707                         default:
8708                                 rc = -ENOTSUP;
8709                                 break;
8710                         }
8711                 } else {
8712                         qctl->qc_valid = QC_GENERAL;
8713                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ?
8714                                         LUSTRE_Q_GETDEFAULT_POOL :
8715                                         LUSTRE_Q_GETDEFAULT;
8716                         qctl->qc_id = 0;
8717                 }
8718
8719                 if (rc) {
8720                         if (str2quotaid(&qctl->qc_id, name)) {
8721                                 fprintf(stderr, "%s quota: invalid id '%s'\n",
8722                                         progname, name);
8723                                 rc = CMD_HELP;
8724                                 goto out;
8725                         }
8726                 }
8727         } else if (optind + 1 != argc || qctl->qc_type == ALLQUOTA) {
8728                 fprintf(stderr, "%s quota: missing quota info argument(s)\n",
8729                         progname);
8730                 rc = CMD_HELP;
8731                 goto out;
8732         }
8733
8734         mnt = argv[optind];
8735         if (show_pools) {
8736                 char *p;
8737
8738                 i = 0;
8739                 rc = llapi_get_poolbuf(mnt, &buf, &poollist, &poolcount);
8740                 if (rc)
8741                         goto out;
8742
8743                 for (i = 0; i < poolcount; i++) {
8744                         p = memchr(poollist[i], '.', MAXNAMLEN);
8745                         if (!p) {
8746                                 fprintf(stderr, "bad string format %.*s\n",
8747                                         MAXNAMLEN, poollist[i]);
8748                                 rc = -EINVAL;
8749                                 goto out;
8750                         }
8751                         p++;
8752                         printf("Quotas for pool: %s\n", p);
8753                         strncpy(qctl->qc_poolname, p, LOV_MAXPOOLNAME);
8754                         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
8755                                              human_readable, show_default);
8756                         if (rc)
8757                                 break;
8758                 }
8759                 goto out;
8760         }
8761
8762         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
8763                              human_readable, show_default);
8764 out:
8765         free(buf);
8766         free(qctl);
8767         return rc;
8768 }
8769 #endif /* HAVE_SYS_QUOTA_H! */
8770
8771 static int flushctx_ioctl(char *mp)
8772 {
8773         int fd, rc;
8774
8775         fd = open(mp, O_RDONLY);
8776         if (fd == -1) {
8777                 fprintf(stderr, "flushctx: error open %s: %s\n",
8778                         mp, strerror(errno));
8779                 return -1;
8780         }
8781
8782         rc = ioctl(fd, LL_IOC_FLUSHCTX);
8783         if (rc == -1)
8784                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
8785                         mp, strerror(errno));
8786
8787         close(fd);
8788         return rc;
8789 }
8790
8791 static int lfs_flushctx(int argc, char **argv)
8792 {
8793         int     kdestroy = 0, reap = 0, c;
8794         char    mntdir[PATH_MAX] = {'\0'};
8795         int     index = 0;
8796         int     rc = 0;
8797
8798         while ((c = getopt(argc, argv, "kr")) != -1) {
8799                 switch (c) {
8800                 case 'k':
8801                         kdestroy = 1;
8802                         break;
8803                 case 'r':
8804                         reap = 1;
8805                         break;
8806                 default:
8807                         fprintf(stderr,
8808                                 "error: %s: option '-%c' unrecognized\n",
8809                                 argv[0], c);
8810                         return CMD_HELP;
8811                 }
8812         }
8813
8814         if (kdestroy) {
8815                 rc = system("kdestroy > /dev/null");
8816                 if (rc) {
8817                         rc = WEXITSTATUS(rc);
8818                         fprintf(stderr,
8819                                 "error destroying tickets: %d, continuing\n",
8820                                 rc);
8821                 }
8822         }
8823
8824         if (optind >= argc) {
8825                 /* flush for all mounted lustre fs. */
8826                 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
8827                         /* Check if we have a mount point */
8828                         if (mntdir[0] == '\0')
8829                                 continue;
8830
8831                         if (flushctx_ioctl(mntdir))
8832                                 rc = -1;
8833
8834                         mntdir[0] = '\0'; /* avoid matching in next loop */
8835                 }
8836         } else {
8837                 /* flush fs as specified */
8838                 while (optind < argc) {
8839                         if (flushctx_ioctl(argv[optind++]))
8840                                 rc = -1;
8841                 }
8842         }
8843
8844         if (reap) {
8845                 rc = system("keyctl reap > /dev/null");
8846                 if (rc != 0) {
8847                         rc = WEXITSTATUS(rc);
8848                         fprintf(stderr, "error reaping keyring: %d\n", rc);
8849                 }
8850         }
8851
8852         return rc;
8853 }
8854
8855 static int lfs_changelog(int argc, char **argv)
8856 {
8857         void *changelog_priv;
8858         struct changelog_rec *rec;
8859         long long startrec = 0, endrec = 0;
8860         char *mdd;
8861         struct option long_opts[] = {
8862                 { .val = 'f', .name = "follow", .has_arg = no_argument },
8863                 { .name = NULL } };
8864         char short_opts[] = "f";
8865         int rc, follow = 0;
8866
8867         while ((rc = getopt_long(argc, argv, short_opts,
8868                 long_opts, NULL)) != -1) {
8869                 switch (rc) {
8870                 case 'f':
8871                         follow++;
8872                         break;
8873                 default:
8874                         fprintf(stderr,
8875                                 "%s changelog: unrecognized option '%s'\n",
8876                                 progname, argv[optind - 1]);
8877                         return CMD_HELP;
8878                 }
8879         }
8880         if (optind >= argc) {
8881                 fprintf(stderr, "%s changelog: mdtname must be specified\n",
8882                         progname);
8883                 return CMD_HELP;
8884         }
8885
8886         mdd = argv[optind++];
8887         if (argc > optind) {
8888                 errno = 0;
8889                 startrec = strtoll(argv[optind++], NULL, 10);
8890                 if (errno != 0 || startrec < 0) {
8891                         fprintf(stderr,
8892                                 "%s changelog: bad startrec\n",
8893                                 progname);
8894                         return CMD_HELP;
8895                 }
8896         }
8897
8898         if (argc > optind) {
8899                 errno = 0;
8900                 endrec = strtoll(argv[optind++], NULL, 10);
8901                 if (errno != 0 || endrec < 0) {
8902                         fprintf(stderr,
8903                                 "%s changelog: bad endrec\n",
8904                                 progname);
8905                         return CMD_HELP;
8906                 }
8907         }
8908
8909         rc = llapi_changelog_start(&changelog_priv,
8910                                    CHANGELOG_FLAG_BLOCK |
8911                                    CHANGELOG_FLAG_JOBID |
8912                                    CHANGELOG_FLAG_EXTRA_FLAGS |
8913                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
8914                                    mdd, startrec);
8915         if (rc < 0) {
8916                 fprintf(stderr, "%s changelog: cannot start changelog: %s\n",
8917                         progname, strerror(errno = -rc));
8918                 return rc;
8919         }
8920
8921         rc = llapi_changelog_set_xflags(changelog_priv,
8922                                         CHANGELOG_EXTRA_FLAG_UIDGID |
8923                                         CHANGELOG_EXTRA_FLAG_NID |
8924                                         CHANGELOG_EXTRA_FLAG_OMODE |
8925                                         CHANGELOG_EXTRA_FLAG_XATTR);
8926         if (rc < 0) {
8927                 fprintf(stderr,
8928                         "%s changelog: cannot set xflags for changelog: %s\n",
8929                         progname, strerror(errno = -rc));
8930                 return rc;
8931         }
8932
8933         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
8934                 time_t secs;
8935                 struct tm ts;
8936
8937                 if (endrec && rec->cr_index > endrec) {
8938                         llapi_changelog_free(&rec);
8939                         break;
8940                 }
8941                 if (rec->cr_index < startrec) {
8942                         llapi_changelog_free(&rec);
8943                         continue;
8944                 }
8945
8946                 secs = rec->cr_time >> 30;
8947                 gmtime_r(&secs, &ts);
8948                 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
8949                        "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
8950                        changelog_type2str(rec->cr_type),
8951                        ts.tm_hour, ts.tm_min, ts.tm_sec,
8952                        (int)(rec->cr_time & ((1 << 30) - 1)),
8953                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
8954                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
8955
8956                 if (rec->cr_flags & CLF_JOBID) {
8957                         struct changelog_ext_jobid *jid =
8958                                 changelog_rec_jobid(rec);
8959
8960                         if (jid->cr_jobid[0] != '\0')
8961                                 printf(" j=%s", jid->cr_jobid);
8962                 }
8963
8964                 if (rec->cr_flags & CLF_EXTRA_FLAGS) {
8965                         struct changelog_ext_extra_flags *ef =
8966                                 changelog_rec_extra_flags(rec);
8967
8968                         printf(" ef=0x%llx",
8969                                (unsigned long long)ef->cr_extra_flags);
8970
8971                         if (ef->cr_extra_flags & CLFE_UIDGID) {
8972                                 struct changelog_ext_uidgid *uidgid =
8973                                         changelog_rec_uidgid(rec);
8974
8975                                 printf(" u=%llu:%llu",
8976                                        (unsigned long long)uidgid->cr_uid,
8977                                        (unsigned long long)uidgid->cr_gid);
8978                         }
8979                         if (ef->cr_extra_flags & CLFE_NID) {
8980                                 struct changelog_ext_nid *nid =
8981                                         changelog_rec_nid(rec);
8982
8983                                 printf(" nid=%s",
8984                                        libcfs_nid2str(nid->cr_nid));
8985                         }
8986
8987                         if (ef->cr_extra_flags & CLFE_OPEN) {
8988                                 struct changelog_ext_openmode *omd =
8989                                         changelog_rec_openmode(rec);
8990                                 char mode[] = "---";
8991
8992                                 /* exec mode must be exclusive */
8993                                 if (omd->cr_openflags & MDS_FMODE_EXEC) {
8994                                         mode[2] = 'x';
8995                                 } else {
8996                                         if (omd->cr_openflags & MDS_FMODE_READ)
8997                                                 mode[0] = 'r';
8998                                         if (omd->cr_openflags &
8999                                             (MDS_FMODE_WRITE |
9000                                              MDS_OPEN_TRUNC |
9001                                              MDS_OPEN_APPEND))
9002                                                 mode[1] = 'w';
9003                                 }
9004
9005                                 if (strcmp(mode, "---") != 0)
9006                                         printf(" m=%s", mode);
9007                         }
9008
9009                         if (ef->cr_extra_flags & CLFE_XATTR) {
9010                                 struct changelog_ext_xattr *xattr =
9011                                         changelog_rec_xattr(rec);
9012
9013                                 if (xattr->cr_xattr[0] != '\0')
9014                                         printf(" x=%s", xattr->cr_xattr);
9015                         }
9016                 }
9017
9018                 if (!fid_is_zero(&rec->cr_pfid))
9019                         printf(" p="DFID, PFID(&rec->cr_pfid));
9020                 if (rec->cr_namelen)
9021                         printf(" %.*s", rec->cr_namelen,
9022                                changelog_rec_name(rec));
9023
9024                 if (rec->cr_flags & CLF_RENAME) {
9025                         struct changelog_ext_rename *rnm =
9026                                 changelog_rec_rename(rec);
9027
9028                         if (!fid_is_zero(&rnm->cr_sfid))
9029                                 printf(" s="DFID" sp="DFID" %.*s",
9030                                        PFID(&rnm->cr_sfid),
9031                                        PFID(&rnm->cr_spfid),
9032                                        (int)changelog_rec_snamelen(rec),
9033                                        changelog_rec_sname(rec));
9034                 }
9035                 printf("\n");
9036
9037                 llapi_changelog_free(&rec);
9038         }
9039
9040         llapi_changelog_fini(&changelog_priv);
9041
9042         if (rc < 0)
9043                 fprintf(stderr, "%s changelog: cannot access changelog: %s\n",
9044                         progname, strerror(errno = -rc));
9045
9046         return (rc == 1 ? 0 : rc);
9047 }
9048
9049 static int lfs_changelog_clear(int argc, char **argv)
9050 {
9051         long long endrec;
9052         int rc;
9053
9054         if (argc != 4)
9055                 return CMD_HELP;
9056
9057         errno = 0;
9058         endrec = strtoll(argv[3], NULL, 10);
9059         if (errno != 0 || endrec < 0) {
9060                 fprintf(stderr,
9061                         "%s: bad endrec '%s'\n",
9062                         argv[0], argv[3]);
9063                 return CMD_HELP;
9064         }
9065
9066         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
9067
9068         if (rc == -EINVAL)
9069                 fprintf(stderr, "%s: record out of range: %llu\n",
9070                         argv[0], endrec);
9071         else if (rc == -ENOENT)
9072                 fprintf(stderr, "%s: no changelog user: %s\n",
9073                         argv[0], argv[2]);
9074         else if (rc)
9075                 fprintf(stderr, "%s error: %s\n", argv[0],
9076                         strerror(-rc));
9077
9078         if (rc)
9079                 errno = -rc;
9080
9081         return rc;
9082 }
9083
9084 static void rstripc(char *str, int c)
9085 {
9086         char *end = str + strlen(str);
9087
9088         for (; str < end && end[-1] == c; --end)
9089                 end[-1] = '\0';
9090 }
9091
9092 static int lfs_fid2path(int argc, char **argv)
9093 {
9094         struct option long_opts[] = {
9095                 { .val = 'c',   .name = "cur",  .has_arg = no_argument },
9096                 { .val = 'c',   .name = "current",      .has_arg = no_argument },
9097                 { .val = 'c',   .name = "print-link",   .has_arg = no_argument },
9098                 { .val = 'f',   .name = "print-fid",    .has_arg = no_argument },
9099                 { .val = 'l',   .name = "link", .has_arg = required_argument },
9100                 { .name = NULL } };
9101         char short_opts[] = "cfl:pr:";
9102         bool print_link = false;
9103         bool print_fid = false;
9104         bool print_mnt_dir;
9105         char mnt_dir[PATH_MAX] = "";
9106         int mnt_fd = -1;
9107         char *path_or_fsname;
9108         long long recno = -1;
9109         int linkno = -1;
9110         char *endptr = NULL;
9111         int rc = 0;
9112         int c;
9113         int i;
9114
9115         while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
9116                 switch (c) {
9117                 case 'c':
9118                         print_link = true;
9119                         break;
9120                 case 'f':
9121                         print_fid = true;
9122                         break;
9123                 case 'l':
9124                         errno = 0;
9125                         linkno = strtol(optarg, &endptr, 10);
9126                         if (errno != 0 || *endptr != '\0' || linkno < 0) {
9127                                 fprintf(stderr,
9128                                         "%s fid2path: invalid linkno '%s'\n",
9129                                         progname, optarg);
9130                                 return CMD_HELP;
9131                         }
9132                         break;
9133                 case 'r':
9134                         /* recno is something to do with changelogs
9135                          * that was never implemented. We just pass it
9136                          * through for the MDT to ignore.
9137                          */
9138                         errno = 0;
9139                         recno = strtoll(optarg, &endptr, 10);
9140                         if (errno != 0 || *endptr != '\0' || recno < 0) {
9141                                 fprintf(stderr,
9142                                         "%s fid2path: invalid recno '%s'\n",
9143                                         progname, optarg);
9144                                 return CMD_HELP;
9145                         }
9146                         break;
9147                 default:
9148                         fprintf(stderr,
9149                                 "%s fid2path: unrecognized option '%s'\n",
9150                                 progname, argv[optind - 1]);
9151                         return CMD_HELP;
9152                 }
9153         }
9154
9155         if (argc - optind < 2) {
9156                 fprintf(stderr,
9157                         "Usage: %s fid2path FSNAME|ROOT FID...\n",
9158                         progname);
9159                 return CMD_HELP;
9160         }
9161
9162         path_or_fsname = argv[optind];
9163
9164         if (*path_or_fsname == '/') {
9165                 print_mnt_dir = true;
9166                 rc = llapi_search_mounts(path_or_fsname, 0, mnt_dir, NULL);
9167         } else {
9168                 print_mnt_dir = false;
9169                 rc = llapi_search_rootpath(mnt_dir, path_or_fsname);
9170         }
9171
9172         if (rc < 0) {
9173                 fprintf(stderr,
9174                         "%s fid2path: cannot resolve mount point for '%s': %s\n",
9175                         progname, path_or_fsname, strerror(-rc));
9176                 goto out;
9177         }
9178
9179         mnt_fd = open(mnt_dir, O_RDONLY | O_DIRECTORY);
9180         if (mnt_fd < 0) {
9181                 fprintf(stderr,
9182                         "%s fid2path: cannot open mount point for '%s': %s\n",
9183                         progname, path_or_fsname, strerror(-rc));
9184                 goto out;
9185         }
9186
9187         /* Strip trailing slashes from mnt_dir. */
9188         rstripc(mnt_dir + 1, '/');
9189
9190         for (i = optind + 1; i < argc; i++) {
9191                 const char *fid_str = argv[i];
9192                 struct lu_fid fid;
9193                 int rc2;
9194
9195                 rc2 = llapi_fid_parse(fid_str, &fid, NULL);
9196                 if (rc2 < 0) {
9197                         fprintf(stderr,
9198                                 "%s fid2path: invalid FID '%s'\n",
9199                                 progname, fid_str);
9200                         if (rc == 0)
9201                                 rc = rc2;
9202
9203                         continue;
9204                 }
9205
9206                 int linktmp = (linkno >= 0) ? linkno : 0;
9207                 while (1) {
9208                         int oldtmp = linktmp;
9209                         long long rectmp = recno;
9210                         char path_buf[PATH_MAX];
9211
9212                         rc2 = llapi_fid2path_at(mnt_fd, &fid,
9213                                 path_buf, sizeof(path_buf), &rectmp, &linktmp);
9214                         if (rc2 < 0) {
9215                                 fprintf(stderr,
9216                                         "%s fid2path: cannot find %s %s: %s\n",
9217                                         progname, path_or_fsname, fid_str,
9218                                         strerror(-rc2));
9219                                 if (rc == 0)
9220                                         rc = rc2;
9221                                 break;
9222                         }
9223
9224                         if (print_fid)
9225                                 printf("%s ", fid_str);
9226
9227                         if (print_link)
9228                                 printf("%d ", linktmp);
9229
9230                         /* You may think this looks wrong or weird (and it is!)
9231                          * but we are actually trying to preserve the old quirky
9232                          * behaviors (enforced by our old quirky tests!) that
9233                          * make lfs so much fun to work on:
9234                          *
9235                          *   lustre 0x200000007:0x1:0x0 => "/"
9236                          *   /mnt/lustre 0x200000007:0x1:0x0 => "/mnt/lustre//"
9237                          *
9238                          * Note that llapi_fid2path() returns "" for the root
9239                          * FID. */
9240
9241                         printf("%s%s%s\n",
9242                                print_mnt_dir ? mnt_dir : "",
9243                                (print_mnt_dir || *path_buf == '\0') ? "/" : "",
9244                                path_buf);
9245
9246                         if (linkno >= 0)
9247                                 /* specified linkno */
9248                                 break;
9249
9250                         if (oldtmp == linktmp)
9251                                 /* no more links */
9252                                 break;
9253                 }
9254         }
9255 out:
9256         if (!(mnt_fd < 0))
9257                 close(mnt_fd);
9258
9259         return rc;
9260 }
9261
9262 static int lfs_path2fid(int argc, char **argv)
9263 {
9264         struct option long_opts[] = {
9265                 { .val = 'p', .name = "parents", .has_arg = no_argument },
9266                 { .name = NULL } };
9267         char            **path;
9268         const char        short_opts[] = "p";
9269         const char       *sep = "";
9270         struct lu_fid     fid;
9271         int               rc = 0;
9272         bool              show_parents = false;
9273
9274         while ((rc = getopt_long(argc, argv, short_opts,
9275                                  long_opts, NULL)) != -1) {
9276                 switch (rc) {
9277                 case 'p':
9278                         show_parents = true;
9279                         break;
9280                 default:
9281                         fprintf(stderr,
9282                                 "%s path2fid: unrecognized option '%s'\n",
9283                                 progname, argv[optind - 1]);
9284                         return CMD_HELP;
9285                 }
9286         }
9287
9288         if (optind > argc - 1) {
9289                 fprintf(stderr, "%s path2fid: FILE... must be specified\n",
9290                         progname);
9291                 return CMD_HELP;
9292         } else if (optind < argc - 1) {
9293                 sep = ": ";
9294         }
9295
9296         rc = 0;
9297         for (path = argv + optind; *path != NULL; path++) {
9298                 int err = 0;
9299
9300                 if (!show_parents) {
9301                         err = llapi_path2fid(*path, &fid);
9302                         if (!err)
9303                                 printf("%s%s"DFID"\n",
9304                                        *sep != '\0' ? *path : "", sep,
9305                                        PFID(&fid));
9306                 } else {
9307                         char            name[NAME_MAX + 1];
9308                         unsigned int    linkno = 0;
9309
9310                         while ((err = llapi_path2parent(*path, linkno, &fid,
9311                                                 name, sizeof(name))) == 0) {
9312                                 if (*sep != '\0' && linkno == 0)
9313                                         printf("%s%s", *path, sep);
9314
9315                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
9316                                        PFID(&fid), name);
9317                                 linkno++;
9318                         }
9319
9320                         /* err == -ENODATA is end-of-loop */
9321                         if (linkno > 0 && err == -ENODATA) {
9322                                 printf("\n");
9323                                 err = 0;
9324                         }
9325                 }
9326
9327                 if (err) {
9328                         fprintf(stderr,
9329                                 "%s path2fid: cannot get %sfid for '%s': %s\n",
9330                                 progname, show_parents ? "parent " : "", *path,
9331                                 strerror(-err));
9332                         if (rc == 0) {
9333                                 rc = err;
9334                                 errno = -err;
9335                         }
9336                 }
9337         }
9338
9339         return rc;
9340 }
9341
9342 #define MAX_ERRNO       4095
9343 #define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO)
9344
9345 static int lfs_rmfid_and_show_errors(const char *device, struct fid_array *fa)
9346 {
9347         int rc, rc2, k;
9348
9349         rc = llapi_rmfid(device, fa);
9350         if (rc < 0) {
9351                 fprintf(stderr, "%s rmfid: cannot remove FIDs: %s\n",
9352                         progname, strerror(-rc));
9353                 return rc;
9354         }
9355
9356         for (k = 0; k < fa->fa_nr; k++) {
9357                 rc2 = (__s32)fa->fa_fids[k].f_ver;
9358                 if (!IS_ERR_VALUE(rc2))
9359                         continue;
9360
9361                 if (rc == 0)
9362                         rc = rc2;
9363
9364                 fa->fa_fids[k].f_ver = 0;
9365                 fprintf(stderr, "%s rmfid: cannot remove "DFID": %s\n",
9366                         progname, PFID(&fa->fa_fids[k]), strerror(-rc2));
9367         }
9368
9369         return rc;
9370 }
9371
9372 static int lfs_rmfid(int argc, char **argv)
9373 {
9374         char *fidstr, *device;
9375         int rc = 0, rc2, nr;
9376         struct fid_array *fa;
9377
9378         if (optind > argc - 1) {
9379                 fprintf(stderr, "%s rmfid: missing dirname\n", progname);
9380                 return CMD_HELP;
9381         }
9382
9383         device = argv[optind++];
9384
9385         nr = argc - optind;
9386         fa = malloc(offsetof(struct fid_array, fa_fids[nr + 1]));
9387         if (!fa)
9388                 return -ENOMEM;
9389
9390         fa->fa_nr = 0;
9391         rc = 0;
9392         while (optind < argc) {
9393                 int found;
9394
9395                 fidstr = argv[optind++];
9396                 while (*fidstr == '[')
9397                         fidstr++;
9398                 found = sscanf(fidstr, SFID, RFID(&fa->fa_fids[fa->fa_nr]));
9399                 if (found != 3) {
9400                         fprintf(stderr, "unrecognized FID: %s\n",
9401                                 argv[optind - 1]);
9402                         exit(1);
9403                 }
9404                 fa->fa_nr++;
9405                 if (fa->fa_nr == OBD_MAX_FIDS_IN_ARRAY) {
9406                         /* start another batch */
9407                         rc2 = lfs_rmfid_and_show_errors(device, fa);
9408                         if (rc2 && !rc)
9409                                 rc = rc2;
9410                         fa->fa_nr = 0;
9411                 }
9412         }
9413         if (fa->fa_nr) {
9414                 rc2 = lfs_rmfid_and_show_errors(device, fa);
9415                 if (rc2 && !rc)
9416                         rc = rc2;
9417         }
9418
9419         return rc;
9420 }
9421
9422 static int lfs_data_version(int argc, char **argv)
9423 {
9424         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
9425         __u64 data_version;
9426         char *path;
9427         int fd;
9428         int rc;
9429         int c;
9430
9431         if (argc < 2) {
9432                 fprintf(stderr, "%s: FILE must be specified\n",
9433                         progname);
9434                 return CMD_HELP;
9435         }
9436
9437         while ((c = getopt(argc, argv, "hnrw")) != -1) {
9438                 switch (c) {
9439                 case 'n':
9440                         data_version_flags = 0;
9441                         break;
9442                 case 'r':
9443                         data_version_flags |= LL_DV_RD_FLUSH;
9444                         break;
9445                 case 'w':
9446                         data_version_flags |= LL_DV_WR_FLUSH;
9447                         break;
9448                 default:
9449                         fprintf(stderr,
9450                                 "%s data_version: unrecognized option '%s'\n",
9451                                 progname, argv[optind - 1]);
9452                         /* fallthrough */
9453                 case 'h':
9454                         return CMD_HELP;
9455                 }
9456         }
9457         if (optind == argc) {
9458                 fprintf(stderr, "%s data_version: FILE must be specified\n",
9459                         progname);
9460                 return CMD_HELP;
9461         }
9462
9463         path = argv[optind];
9464         fd = open(path, O_RDONLY);
9465         if (fd < 0) {
9466                 rc = -errno;
9467                 fprintf(stderr, "%s data_version: cannot open file '%s': %s\n",
9468                         progname, path, strerror(-rc));
9469                 return rc;
9470         }
9471
9472         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
9473         if (rc < 0)
9474                 fprintf(stderr,
9475                         "%s data_version: cannot get version for '%s': %s\n",
9476                         progname, path, strerror(-rc));
9477         else
9478                 printf("%ju" "\n", (uintmax_t)data_version);
9479
9480         close(fd);
9481         return rc;
9482 }
9483
9484 static int lfs_hsm_state(int argc, char **argv)
9485 {
9486         int rc;
9487         int i = 1;
9488         char *path;
9489         struct hsm_user_state hus;
9490
9491         if (argc < 2)
9492                 return CMD_HELP;
9493
9494         do {
9495                 path = argv[i];
9496
9497                 rc = llapi_hsm_state_get(path, &hus);
9498                 if (rc) {
9499                         fprintf(stderr, "can't get hsm state for %s: %s\n",
9500                                 path, strerror(errno = -rc));
9501                         return rc;
9502                 }
9503
9504                 /* Display path name and status flags */
9505                 printf("%s: (0x%08x)", path, hus.hus_states);
9506
9507                 if (hus.hus_states & HS_RELEASED)
9508                         printf(" released");
9509                 if (hus.hus_states & HS_EXISTS)
9510                         printf(" exists");
9511                 if (hus.hus_states & HS_DIRTY)
9512                         printf(" dirty");
9513                 if (hus.hus_states & HS_ARCHIVED)
9514                         printf(" archived");
9515                 /* Display user-settable flags */
9516                 if (hus.hus_states & HS_NORELEASE)
9517                         printf(" never_release");
9518                 if (hus.hus_states & HS_NOARCHIVE)
9519                         printf(" never_archive");
9520                 if (hus.hus_states & HS_LOST)
9521                         printf(" lost_from_hsm");
9522
9523                 if (hus.hus_archive_id != 0)
9524                         printf(", archive_id:%d", hus.hus_archive_id);
9525                 printf("\n");
9526
9527         } while (++i < argc);
9528
9529         return 0;
9530 }
9531
9532 #define LFS_HSM_SET   0
9533 #define LFS_HSM_CLEAR 1
9534
9535 /**
9536  * Generic function to set or clear HSM flags.
9537  * Used by hsm_set and hsm_clear.
9538  *
9539  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
9540  */
9541 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
9542 {
9543         struct option long_opts[] = {
9544         { .val = 'A',   .name = "archived",     .has_arg = no_argument },
9545         { .val = 'a',   .name = "noarchive",    .has_arg = no_argument },
9546         { .val = 'd',   .name = "dirty",        .has_arg = no_argument },
9547         { .val = 'e',   .name = "exists",       .has_arg = no_argument },
9548         { .val = 'h',   .name = "help",         .has_arg = no_argument },
9549         { .val = 'i',   .name = "archive-id",   .has_arg = required_argument },
9550         { .val = 'l',   .name = "lost",         .has_arg = no_argument },
9551         { .val = 'r',   .name = "norelease",    .has_arg = no_argument },
9552         { .name = NULL } };
9553         __u64 mask = 0;
9554         int c, rc;
9555         char *path;
9556         __u32 archive_id = 0;
9557         char *end = NULL;
9558
9559         if (argc < 3)
9560                 return CMD_HELP;
9561
9562         while ((c = getopt_long(argc, argv, "aAdehi:lr",
9563                                 long_opts, NULL)) != -1) {
9564                 switch (c) {
9565                 case 'l':
9566                         mask |= HS_LOST;
9567                         break;
9568                 case 'a':
9569                         mask |= HS_NOARCHIVE;
9570                         break;
9571                 case 'A':
9572                         mask |= HS_ARCHIVED;
9573                         break;
9574                 case 'r':
9575                         mask |= HS_NORELEASE;
9576                         break;
9577                 case 'd':
9578                         mask |= HS_DIRTY;
9579                         break;
9580                 case 'e':
9581                         mask |= HS_EXISTS;
9582                         break;
9583                 case 'i':
9584                         errno = 0;
9585                         archive_id = strtol(optarg, &end, 10);
9586                         if (errno != 0 || *end != '\0' || archive_id < 0) {
9587                                 fprintf(stderr,
9588                                         "%s: invalid archive_id: '%s'\n",
9589                                         progname, end);
9590                                 return CMD_HELP;
9591                         }
9592                         break;
9593                 default:
9594                         fprintf(stderr, "%s: unrecognized option '%s'\n",
9595                                 progname, argv[optind - 1]);
9596                         /* fallthrough */
9597                 case 'h':
9598                         return CMD_HELP;
9599                 }
9600         }
9601
9602         /* User should have specified a flag */
9603         if (mask == 0)
9604                 return CMD_HELP;
9605
9606         while (optind < argc) {
9607                 path = argv[optind];
9608
9609                 /* If mode == 0, this means we apply the mask. */
9610                 if (mode == LFS_HSM_SET)
9611                         rc = llapi_hsm_state_set(path, mask, 0, archive_id);
9612                 else
9613                         rc = llapi_hsm_state_set(path, 0, mask, 0);
9614
9615                 if (rc != 0) {
9616                         fprintf(stderr, "Can't change hsm flags for %s: %s\n",
9617                                 path, strerror(errno = -rc));
9618                         return rc;
9619                 }
9620                 optind++;
9621         }
9622
9623         return 0;
9624 }
9625
9626 static int lfs_hsm_action(int argc, char **argv)
9627 {
9628         int                              rc;
9629         int                              i = 1;
9630         char                            *path;
9631         struct hsm_current_action        hca;
9632         struct hsm_extent                he;
9633         enum hsm_user_action             hua;
9634         enum hsm_progress_states         hps;
9635
9636         if (argc < 2)
9637                 return CMD_HELP;
9638
9639         do {
9640                 path = argv[i];
9641
9642                 rc = llapi_hsm_current_action(path, &hca);
9643                 if (rc) {
9644                         fprintf(stderr, "can't get hsm action for %s: %s\n",
9645                                 path, strerror(errno = -rc));
9646                         return rc;
9647                 }
9648                 he = hca.hca_location;
9649                 hua = hca.hca_action;
9650                 hps = hca.hca_state;
9651
9652                 printf("%s: %s", path, hsm_user_action2name(hua));
9653
9654                 /* Skip file without action */
9655                 if (hca.hca_action == HUA_NONE) {
9656                         printf("\n");
9657                         continue;
9658                 }
9659
9660                 printf(" %s ", hsm_progress_state2name(hps));
9661
9662                 if ((hps == HPS_RUNNING) &&
9663                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
9664                         printf("(%llu bytes moved)\n",
9665                                (unsigned long long)he.length);
9666                 else if ((he.offset + he.length) == LUSTRE_EOF)
9667                         printf("(from %llu to EOF)\n",
9668                                (unsigned long long)he.offset);
9669                 else
9670                         printf("(from %llu to %llu)\n",
9671                                (unsigned long long)he.offset,
9672                                (unsigned long long)(he.offset + he.length));
9673
9674         } while (++i < argc);
9675
9676         return 0;
9677 }
9678
9679 static int lfs_hsm_set(int argc, char **argv)
9680 {
9681         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
9682 }
9683
9684 static int lfs_hsm_clear(int argc, char **argv)
9685 {
9686         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
9687 }
9688
9689 /**
9690  * Check file state and return its fid, to be used by lfs_hsm_request().
9691  *
9692  * \param[in]     file      Path to file to check
9693  * \param[in,out] fid       Pointer to allocated lu_fid struct.
9694  * \param[in,out] last_dev  Pointer to last device id used.
9695  *
9696  * \return 0 on success.
9697  */
9698 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
9699                                 dev_t *last_dev)
9700 {
9701         struct stat     st;
9702         int             rc;
9703
9704         rc = lstat(file, &st);
9705         if (rc) {
9706                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
9707                 return -errno;
9708         }
9709         /*
9710          * Checking for regular file as archiving as posix copytool
9711          * rejects archiving files other than regular files
9712          */
9713         if (!S_ISREG(st.st_mode)) {
9714                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
9715                 return CMD_HELP;
9716         }
9717         /* A request should be ... */
9718         if (*last_dev != st.st_dev && *last_dev != 0) {
9719                 fprintf(stderr,
9720                         "All files should be on the same filesystem: %s\n",
9721                         file);
9722                 return -EINVAL;
9723         }
9724         *last_dev = st.st_dev;
9725
9726         rc = llapi_path2fid(file, fid);
9727         if (rc) {
9728                 fprintf(stderr, "Cannot read FID of %s: %s\n",
9729                         file, strerror(-rc));
9730                 return rc;
9731         }
9732         return 0;
9733 }
9734
9735 /* Fill an HSM HUR item with a given file name.
9736  *
9737  * If mntpath is set, then the filename is actually a FID, and no
9738  * lookup on the filesystem will be performed.
9739  *
9740  * \param[in]  hur         the user request to fill
9741  * \param[in]  idx         index of the item inside the HUR to fill
9742  * \param[in]  mntpath     mountpoint of Lustre
9743  * \param[in]  fname       filename (if mtnpath is NULL)
9744  *                         or FID (if mntpath is set)
9745  * \param[in]  last_dev    pointer to last device id used
9746  *
9747  * \retval 0 on success
9748  * \retval CMD_HELP or a negative errno on error
9749  */
9750 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
9751                          const char *mntpath, const char *fname,
9752                          dev_t *last_dev)
9753 {
9754         struct hsm_user_item *hui = &hur->hur_user_item[idx];
9755         int rc;
9756
9757         hui->hui_extent.length = -1;
9758
9759         if (mntpath) {
9760                 rc = llapi_fid_parse(fname, &hui->hui_fid, NULL);
9761                 if (rc)
9762                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
9763                                 fname);
9764         } else {
9765                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
9766         }
9767
9768         if (rc == 0)
9769                 hur->hur_request.hr_itemcount++;
9770
9771         return rc;
9772 }
9773
9774 static int lfs_hsm_request(int argc, char **argv, int action)
9775 {
9776         struct option long_opts[] = {
9777         { .val = 'a',   .name = "archive",      .has_arg = required_argument },
9778         { .val = 'D',   .name = "data",         .has_arg = required_argument },
9779         { .val = 'h',   .name = "help",         .has_arg = no_argument },
9780         { .val = 'l',   .name = "filelist",     .has_arg = required_argument },
9781         { .val = 'm',   .name = "mntpath",      .has_arg = required_argument },
9782         { .name = NULL } };
9783         dev_t last_dev = 0;
9784         struct hsm_user_request *hur, *oldhur;
9785         int c, i;
9786         size_t len;
9787         int nbfile;
9788         char *line = NULL;
9789         char *filelist = NULL;
9790         char fullpath[PATH_MAX];
9791         char *opaque = NULL;
9792         int opaque_len = 0;
9793         int archive_id = 0;
9794         FILE *fp;
9795         int nbfile_alloc = 0;
9796         char *some_file = NULL;
9797         char *mntpath = NULL;
9798         int rc;
9799
9800         if (argc < 2)
9801                 return CMD_HELP;
9802
9803         while ((c = getopt_long(argc, argv, "a:D:hl:m:",
9804                                 long_opts, NULL)) != -1) {
9805                 switch (c) {
9806                 case 'l':
9807                         filelist = optarg;
9808                         break;
9809                 case 'D':
9810                         opaque = optarg;
9811                         break;
9812                 case 'a':
9813                         if (action != HUA_ARCHIVE &&
9814                             action != HUA_REMOVE) {
9815                                 fprintf(stderr,
9816                                         "error: -a is supported only when archiving or removing\n");
9817                                 return CMD_HELP;
9818                         }
9819                         archive_id = atoi(optarg);
9820                         break;
9821                 case 'm':
9822                         if (!some_file) {
9823                                 mntpath = optarg;
9824                                 some_file = strdup(optarg);
9825                         }
9826                         break;
9827                 default:
9828                         fprintf(stderr, "%s: unrecognized option '%s'\n",
9829                                 progname, argv[optind - 1]);
9830                         /* fallthrough */
9831                 case 'h':
9832                         return CMD_HELP;
9833                 }
9834         }
9835
9836         /* All remaining args are files, so we have at least nbfile */
9837         nbfile = argc - optind;
9838
9839         if ((nbfile == 0) && (!filelist))
9840                 return CMD_HELP;
9841
9842         if (opaque)
9843                 opaque_len = strlen(opaque);
9844
9845         /*
9846          * Alloc the request structure with enough place to store all files
9847          * from command line.
9848          */
9849         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
9850         if (!hur) {
9851                 fprintf(stderr, "Cannot create the request: %s\n",
9852                         strerror(errno));
9853                 return errno;
9854         }
9855         nbfile_alloc = nbfile;
9856
9857         hur->hur_request.hr_action = action;
9858         hur->hur_request.hr_archive_id = archive_id;
9859         hur->hur_request.hr_flags = 0;
9860
9861         /* All remaining args are files, add them */
9862         if (nbfile != 0 && some_file == NULL)
9863                 some_file = strdup(argv[optind]);
9864
9865         for (i = 0; i < nbfile; i++) {
9866                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
9867                                    &last_dev);
9868                 if (rc)
9869                         goto out_free;
9870         }
9871
9872         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
9873
9874         /* If a filelist was specified, read the filelist from it. */
9875         if (filelist) {
9876                 fp = fopen(filelist, "r");
9877                 if (!fp) {
9878                         fprintf(stderr, "Cannot read the file list %s: %s\n",
9879                                 filelist, strerror(errno));
9880                         rc = -errno;
9881                         goto out_free;
9882                 }
9883
9884                 while ((rc = getline(&line, &len, fp)) != -1) {
9885                         /*
9886                          * If allocated buffer was too small, get something
9887                          * larger
9888                          */
9889                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
9890                                 ssize_t size;
9891
9892                                 nbfile_alloc = nbfile_alloc * 2 + 1;
9893                                 oldhur = hur;
9894                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
9895                                                                    opaque_len);
9896                                 if (!hur) {
9897                                         fprintf(stderr,
9898                                                 "hsm: cannot allocate the request: %s\n",
9899                                                 strerror(errno));
9900                                         hur = oldhur;
9901                                         rc = -errno;
9902                                         fclose(fp);
9903                                         goto out_free;
9904                                 }
9905                                 size = hur_len(oldhur);
9906                                 if (size < 0) {
9907                                         fprintf(stderr,
9908                                                 "hsm: cannot allocate %u files + %u bytes data\n",
9909                                                 oldhur->hur_request.hr_itemcount,
9910                                                 oldhur->hur_request.hr_data_len);
9911                                         free(hur);
9912                                         hur = oldhur;
9913                                         rc = -E2BIG;
9914                                         fclose(fp);
9915                                         goto out_free;
9916                                 }
9917                                 memcpy(hur, oldhur, size);
9918                                 free(oldhur);
9919                         }
9920
9921                         /* Chop CR */
9922                         if (line[strlen(line) - 1] == '\n')
9923                                 line[strlen(line) - 1] = '\0';
9924
9925                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
9926                                            mntpath, line, &last_dev);
9927                         if (rc) {
9928                                 fclose(fp);
9929                                 goto out_free;
9930                         }
9931
9932                         if (!some_file) {
9933                                 some_file = line;
9934                                 line = NULL;
9935                         }
9936                 }
9937
9938                 rc = fclose(fp);
9939                 free(line);
9940         }
9941
9942         /* If a --data was used, add it to the request */
9943         hur->hur_request.hr_data_len = opaque_len;
9944         if (opaque)
9945                 memcpy(hur_data(hur), opaque, opaque_len);
9946
9947         /* Send the HSM request */
9948         if (realpath(some_file, fullpath) == NULL) {
9949                 fprintf(stderr, "Could not find path '%s': %s\n",
9950                         some_file, strerror(errno));
9951         }
9952         rc = llapi_hsm_request(fullpath, hur);
9953         if (rc) {
9954                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
9955                         some_file, strerror(-rc));
9956                 goto out_free;
9957         }
9958
9959 out_free:
9960         free(some_file);
9961         free(hur);
9962         return rc;
9963 }
9964
9965 static int lfs_hsm_archive(int argc, char **argv)
9966 {
9967         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
9968 }
9969
9970 static int lfs_hsm_restore(int argc, char **argv)
9971 {
9972         return lfs_hsm_request(argc, argv, HUA_RESTORE);
9973 }
9974
9975 static int lfs_hsm_release(int argc, char **argv)
9976 {
9977         return lfs_hsm_request(argc, argv, HUA_RELEASE);
9978 }
9979
9980 static int lfs_hsm_remove(int argc, char **argv)
9981 {
9982         return lfs_hsm_request(argc, argv, HUA_REMOVE);
9983 }
9984
9985 static int lfs_hsm_cancel(int argc, char **argv)
9986 {
9987         return lfs_hsm_request(argc, argv, HUA_CANCEL);
9988 }
9989
9990 static int lfs_swap_layouts(int argc, char **argv)
9991 {
9992         if (argc != 3)
9993                 return CMD_HELP;
9994
9995         return llapi_swap_layouts(argv[1], argv[2], 0, 0,
9996                                   SWAP_LAYOUTS_KEEP_MTIME |
9997                                   SWAP_LAYOUTS_KEEP_ATIME);
9998 }
9999
10000 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
10001
10002 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
10003
10004 int lfs_get_mode(const char *string)
10005 {
10006         enum lock_mode_user mode;
10007
10008         for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
10009                 if (lock_mode_names[mode] == NULL)
10010                         continue;
10011                 if (strcasecmp(string, lock_mode_names[mode]) == 0)
10012                         return mode;
10013         }
10014
10015         return -EINVAL;
10016 }
10017
10018 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
10019 {
10020         enum lu_ladvise_type advice;
10021
10022         for (advice = 0;
10023              advice < ARRAY_SIZE(ladvise_names); advice++) {
10024                 if (ladvise_names[advice] == NULL)
10025                         continue;
10026                 if (strcmp(string, ladvise_names[advice]) == 0)
10027                         return advice;
10028         }
10029
10030         return LU_LADVISE_INVALID;
10031 }
10032
10033 static int lfs_ladvise(int argc, char **argv)
10034 {
10035         struct option long_opts[] = {
10036         { .val = 'a',   .name = "advice",       .has_arg = required_argument },
10037         { .val = 'b',   .name = "background",   .has_arg = no_argument },
10038         { .val = 'e',   .name = "end",          .has_arg = required_argument },
10039         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10040         { .val = 'l',   .name = "length",       .has_arg = required_argument },
10041         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
10042         { .val = 's',   .name = "start",        .has_arg = required_argument },
10043         { .val = 'u',   .name = "unset",        .has_arg = no_argument },
10044         { .name = NULL } };
10045         struct llapi_lu_ladvise advice;
10046         enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
10047         unsigned long long start = 0;
10048         unsigned long long end = LUSTRE_EOF;
10049         unsigned long long length = 0;
10050         unsigned long long size_units;
10051         unsigned long long flags = 0;
10052         int c, fd, rc = 0;
10053         const char *path;
10054         int mode = 0;
10055
10056         optind = 0;
10057         while ((c = getopt_long(argc, argv, "a:be:hl:m:s:u",
10058                                 long_opts, NULL)) != -1) {
10059                 switch (c) {
10060                 case 'a':
10061                         advice_type = lfs_get_ladvice(optarg);
10062                         if (advice_type == LU_LADVISE_INVALID) {
10063                                 fprintf(stderr,
10064                                         "%s: invalid advice type '%s'\n",
10065                                         progname, optarg);
10066                                 fprintf(stderr, "Valid types:");
10067
10068                                 for (advice_type = 0;
10069                                      advice_type < ARRAY_SIZE(ladvise_names);
10070                                      advice_type++) {
10071                                         if (ladvise_names[advice_type] == NULL)
10072                                                 continue;
10073                                         fprintf(stderr, " %s",
10074                                                 ladvise_names[advice_type]);
10075                                 }
10076                                 fprintf(stderr, "\n");
10077
10078                                 return CMD_HELP;
10079                         }
10080                         break;
10081                 case 'b':
10082                         flags |= LF_ASYNC;
10083                         break;
10084                 case 'u':
10085                         flags |= LF_UNSET;
10086                         break;
10087                 case 'e':
10088                         size_units = 1;
10089                         rc = llapi_parse_size(optarg, &end,
10090                                               &size_units, 0);
10091                         if (rc) {
10092                                 fprintf(stderr, "%s: bad end offset '%s'\n",
10093                                         argv[0], optarg);
10094                                 return CMD_HELP;
10095                         }
10096                         break;
10097                 case 's':
10098                         size_units = 1;
10099                         rc = llapi_parse_size(optarg, &start,
10100                                               &size_units, 0);
10101                         if (rc) {
10102                                 fprintf(stderr,
10103                                         "%s: bad start offset '%s'\n",
10104                                         argv[0], optarg);
10105                                 return CMD_HELP;
10106                         }
10107                         break;
10108                 case 'l':
10109                         size_units = 1;
10110                         rc = llapi_parse_size(optarg, &length,
10111                                               &size_units, 0);
10112                         if (rc) {
10113                                 fprintf(stderr, "%s: bad length '%s'\n",
10114                                         argv[0], optarg);
10115                                 return CMD_HELP;
10116                         }
10117                         break;
10118                 case 'm':
10119                         mode = lfs_get_mode(optarg);
10120                         if (mode < 0) {
10121                                 fprintf(stderr,
10122                                         "%s: bad mode '%s', valid modes are READ or WRITE\n",
10123                                         argv[0], optarg);
10124                                 return CMD_HELP;
10125                         }
10126                         break;
10127                 default:
10128                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10129                                 progname, argv[optind - 1]);
10130                         /* fallthrough */
10131                 case 'h':
10132                         return CMD_HELP;
10133                 }
10134         }
10135
10136         if (advice_type == LU_LADVISE_INVALID) {
10137                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
10138                 fprintf(stderr, "Valid types:");
10139                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
10140                      advice_type++) {
10141                         if (ladvise_names[advice_type] == NULL)
10142                                 continue;
10143                         fprintf(stderr, " %s", ladvise_names[advice_type]);
10144                 }
10145                 fprintf(stderr, "\n");
10146                 return CMD_HELP;
10147         }
10148
10149         if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
10150                 fprintf(stderr,
10151                         "%s: Lock no expand advice is a per file descriptor advice, so when called from lfs, it does nothing.\n",
10152                         argv[0]);
10153                 return CMD_HELP;
10154         }
10155
10156         if (argc <= optind) {
10157                 fprintf(stderr, "%s: please give one or more file names\n",
10158                         argv[0]);
10159                 return CMD_HELP;
10160         }
10161
10162         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
10163                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
10164                         argv[0]);
10165                 return CMD_HELP;
10166         }
10167
10168         if (end == LUSTRE_EOF && length != 0)
10169                 end = start + length;
10170
10171         if (end <= start) {
10172                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
10173                         argv[0], start, end);
10174                 return CMD_HELP;
10175         }
10176
10177         if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
10178                 fprintf(stderr, "%s: mode is only valid with lockahead\n",
10179                         argv[0]);
10180                 return CMD_HELP;
10181         }
10182
10183         if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
10184                 fprintf(stderr, "%s: mode is required with lockahead\n",
10185                         argv[0]);
10186                 return CMD_HELP;
10187         }
10188
10189         while (optind < argc) {
10190                 int rc2;
10191
10192                 path = argv[optind++];
10193
10194                 fd = open(path, O_RDONLY);
10195                 if (fd < 0) {
10196                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
10197                                 argv[0], path, strerror(errno));
10198                         rc2 = -errno;
10199                         goto next;
10200                 }
10201
10202                 advice.lla_start = start;
10203                 advice.lla_end = end;
10204                 advice.lla_advice = advice_type;
10205                 advice.lla_value1 = 0;
10206                 advice.lla_value2 = 0;
10207                 advice.lla_value3 = 0;
10208                 advice.lla_value4 = 0;
10209                 if (advice_type == LU_LADVISE_LOCKAHEAD) {
10210                         advice.lla_lockahead_mode = mode;
10211                         advice.lla_peradvice_flags = flags;
10212                 }
10213
10214                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
10215                 close(fd);
10216                 if (rc2 < 0) {
10217                         fprintf(stderr,
10218                                 "%s: cannot give advice '%s' to file '%s': %s\n",
10219                                 argv[0], ladvise_names[advice_type],
10220                                 path, strerror(errno));
10221
10222                         goto next;
10223                 }
10224
10225 next:
10226                 if (rc == 0 && rc2 < 0)
10227                         rc = rc2;
10228         }
10229         return rc;
10230 }
10231
10232 static const char *const heat_names[] = LU_HEAT_NAMES;
10233
10234 static int lfs_heat_get(int argc, char **argv)
10235 {
10236         struct lu_heat *heat;
10237         int rc = 0, rc2;
10238         char *path;
10239         int fd;
10240         int i;
10241
10242         if (argc <= 1)
10243                 return CMD_HELP;
10244
10245         heat = calloc(sizeof(*heat) + sizeof(__u64) * OBD_HEAT_COUNT, 1);
10246         if (!heat) {
10247                 fprintf(stderr, "%s: memory allocation failed\n", argv[0]);
10248                 return -ENOMEM;
10249         }
10250
10251         optind = 1;
10252         while (optind < argc) {
10253                 path = argv[optind++];
10254
10255                 fd = open(path, O_RDONLY);
10256                 if (fd < 0) {
10257                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
10258                                 argv[0], path, strerror(errno));
10259                         rc2 = -errno;
10260                         goto next;
10261                 }
10262
10263                 heat->lh_count = OBD_HEAT_COUNT;
10264                 rc2 = llapi_heat_get(fd, heat);
10265                 close(fd);
10266                 if (rc2 < 0) {
10267                         fprintf(stderr,
10268                                 "%s: cannot get heat of file '%s': %s\n",
10269                                 argv[0], path, strerror(errno));
10270                         goto next;
10271                 }
10272
10273                 printf("flags: %x\n", heat->lh_flags);
10274                 for (i = 0; i < heat->lh_count; i++)
10275                         printf("%s: %llu\n", heat_names[i],
10276                                (unsigned long long)heat->lh_heat[i]);
10277 next:
10278                 if (rc == 0 && rc2 < 0)
10279                         rc = rc2;
10280         }
10281
10282         free(heat);
10283         return rc;
10284 }
10285
10286 static int lfs_heat_set(int argc, char **argv)
10287 {
10288         struct option long_opts[] = {
10289         { .val = 'c',   .name = "clear",        .has_arg = no_argument },
10290         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10291         { .val = 'o',   .name = "off",          .has_arg = no_argument },
10292         { .val = 'O',   .name = "on",           .has_arg = no_argument },
10293         { .name = NULL } };
10294         enum lu_heat_flag flags = 0;
10295         int rc = 0, rc2;
10296         char *path;
10297         int fd;
10298         int c;
10299
10300         if (argc <= 1)
10301                 return CMD_HELP;
10302
10303         optind = 0;
10304         while ((c = getopt_long(argc, argv, "choO", long_opts, NULL)) != -1) {
10305                 switch (c) {
10306                 case 'c':
10307                         flags |= LU_HEAT_FLAG_CLEAR;
10308                         break;
10309                 case 'o':
10310                         flags |= LU_HEAT_FLAG_CLEAR;
10311                         flags |= LU_HEAT_FLAG_OFF;
10312                         break;
10313                 case 'O':
10314                         flags &= ~LU_HEAT_FLAG_OFF;
10315                         break;
10316                 default:
10317                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10318                                 progname, argv[optind - 1]);
10319                         /* fallthrough */
10320                 case 'h':
10321                         return CMD_HELP;
10322                 }
10323         }
10324
10325         if (argc <= optind) {
10326                 fprintf(stderr, "%s: please give one or more file names\n",
10327                         argv[0]);
10328                 return CMD_HELP;
10329         }
10330
10331         while (optind < argc) {
10332                 path = argv[optind++];
10333
10334                 fd = open(path, O_RDONLY);
10335                 if (fd < 0) {
10336                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
10337                                 argv[0], path, strerror(errno));
10338                         rc2 = -errno;
10339                         goto next;
10340                 }
10341
10342                 rc2 = llapi_heat_set(fd, flags);
10343                 close(fd);
10344                 if (rc2 < 0) {
10345                         fprintf(stderr,
10346                                 "%s: cannot setflags heat of file '%s': %s\n",
10347                                 argv[0], path, strerror(errno));
10348                         goto next;
10349                 }
10350 next:
10351                 if (rc == 0 && rc2 < 0)
10352                         rc = rc2;
10353         }
10354         return rc;
10355 }
10356
10357 /**
10358  * The input string contains a comma delimited list of component ids and
10359  * ranges, for example "1,2-4,7".
10360  */
10361 static int parse_mirror_ids(__u16 *ids, int size, char *arg)
10362 {
10363         bool end_of_loop = false;
10364         char *ptr = NULL;
10365         int nr = 0;
10366         int rc;
10367
10368         if (!arg)
10369                 return -EINVAL;
10370
10371         while (!end_of_loop) {
10372                 int start_index;
10373                 int end_index;
10374                 int i;
10375                 char *endptr = NULL;
10376
10377                 rc = -EINVAL;
10378                 ptr = strchrnul(arg, ',');
10379                 end_of_loop = *ptr == '\0';
10380                 *ptr = '\0';
10381
10382                 start_index = strtol(arg, &endptr, 0);
10383                 if (endptr == arg) /* no data at all */
10384                         break;
10385                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
10386                         break;
10387                 if (start_index < 0)
10388                         break;
10389
10390                 end_index = start_index;
10391                 if (*endptr == '-') {
10392                         end_index = strtol(endptr + 1, &endptr, 0);
10393                         if (*endptr != '\0')
10394                                 break;
10395                         if (end_index < start_index)
10396                                 break;
10397                 }
10398
10399                 for (i = start_index; i <= end_index && size > 0; i++) {
10400                         int j;
10401
10402                         /* remove duplicate */
10403                         for (j = 0; j < nr; j++) {
10404                                 if (ids[j] == i)
10405                                         break;
10406                         }
10407                         if (j == nr) { /* no duplicate */
10408                                 ids[nr++] = i;
10409                                 --size;
10410                         }
10411                 }
10412
10413                 if (size == 0 && i < end_index)
10414                         break;
10415
10416                 *ptr = ',';
10417                 arg = ++ptr;
10418                 rc = 0;
10419         }
10420         if (!end_of_loop && ptr)
10421                 *ptr = ',';
10422
10423         return rc < 0 ? rc : nr;
10424 }
10425
10426 /**
10427  * struct verify_mirror_id - Mirror id to be verified.
10428  * @mirror_id:   A specified mirror id.
10429  * @is_valid_id: @mirror_id is valid or not in the mirrored file.
10430  */
10431 struct verify_mirror_id {
10432         __u16 mirror_id;
10433         bool is_valid_id;
10434 };
10435
10436 /**
10437  * compare_mirror_ids() - Compare mirror ids.
10438  * @layout: Mirror component list.
10439  * @cbdata: Callback data in verify_mirror_id structure.
10440  *
10441  * This is a callback function called by llapi_layout_comp_iterate()
10442  * to compare the specified mirror id with the one in the current
10443  * component of @layout. If they are the same, then the specified
10444  * mirror id is valid.
10445  *
10446  * Return: a negative error code on failure or
10447  *         LLAPI_LAYOUT_ITER_CONT: Proceed iteration
10448  *         LLAPI_LAYOUT_ITER_STOP: Stop iteration
10449  */
10450 static inline
10451 int compare_mirror_ids(struct llapi_layout *layout, void *cbdata)
10452 {
10453         struct verify_mirror_id *mirror_id_cbdata =
10454                                  (struct verify_mirror_id *)cbdata;
10455         uint32_t mirror_id;
10456         int rc = 0;
10457
10458         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
10459         if (rc < 0) {
10460                 rc = -errno;
10461                 fprintf(stderr,
10462                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
10463                         progname, strerror(errno));
10464                 return rc;
10465         }
10466
10467         if (mirror_id_cbdata->mirror_id == mirror_id) {
10468                 mirror_id_cbdata->is_valid_id = true;
10469                 return LLAPI_LAYOUT_ITER_STOP;
10470         }
10471
10472         return LLAPI_LAYOUT_ITER_CONT;
10473 }
10474
10475 /**
10476  * verify_mirror_ids() - Verify specified mirror ids.
10477  * @fname:      Mirrored file name.
10478  * @mirror_ids: Specified mirror ids to be verified.
10479  * @ids_nr:     Number of specified mirror ids.
10480  *
10481  * This function verifies that specified @mirror_ids are valid
10482  * in the mirrored file @fname.
10483  *
10484  * Return: 0 on success or a negative error code on failure.
10485  */
10486 static inline
10487 int verify_mirror_ids(const char *fname, __u16 *mirror_ids, int ids_nr)
10488 {
10489         struct llapi_layout *layout = NULL;
10490         struct verify_mirror_id mirror_id_cbdata = { 0 };
10491         struct stat stbuf;
10492         uint32_t flr_state;
10493         int i;
10494         int fd;
10495         int rc = 0;
10496         int rc2 = 0;
10497
10498         if (ids_nr <= 0)
10499                 return -EINVAL;
10500
10501         if (stat(fname, &stbuf) < 0) {
10502                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
10503                         progname, fname, strerror(errno));
10504                 rc = -errno;
10505                 goto error;
10506         }
10507
10508         if (!S_ISREG(stbuf.st_mode)) {
10509                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
10510                         progname, fname);
10511                 rc = -EINVAL;
10512                 goto error;
10513         }
10514
10515         fd = open(fname, O_DIRECT | O_RDONLY);
10516         if (fd < 0) {
10517                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
10518                         progname, fname, strerror(errno));
10519                 rc = -errno;
10520                 goto error;
10521         }
10522
10523         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
10524         if (rc < 0) {
10525                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
10526                         progname, fname, strerror(errno));
10527                 goto close_fd;
10528         }
10529
10530         layout = llapi_layout_get_by_fd(fd, 0);
10531         if (!layout) {
10532                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
10533                         progname, fname, strerror(errno));
10534                 rc = -errno;
10535                 llapi_lease_release(fd);
10536                 goto close_fd;
10537         }
10538
10539         rc = llapi_layout_flags_get(layout, &flr_state);
10540         if (rc < 0) {
10541                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
10542                         progname, fname, strerror(errno));
10543                 rc = -errno;
10544                 goto free_layout;
10545         }
10546
10547         flr_state &= LCM_FL_FLR_MASK;
10548         switch (flr_state) {
10549         case LCM_FL_NONE:
10550                 rc = -EINVAL;
10551                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
10552                         progname, fname, llapi_layout_flags_string(flr_state));
10553                 goto free_layout;
10554         default:
10555                 break;
10556         }
10557
10558         rc2 = 0;
10559         for (i = 0; i < ids_nr; i++) {
10560                 mirror_id_cbdata.mirror_id = mirror_ids[i];
10561                 mirror_id_cbdata.is_valid_id = false;
10562
10563                 rc = llapi_layout_comp_iterate(layout, compare_mirror_ids,
10564                                                &mirror_id_cbdata);
10565                 if (rc < 0) {
10566                         rc = -errno;
10567                         fprintf(stderr,
10568                                 "%s: '%s' failed to verify mirror id: %u.\n",
10569                                 progname, fname, mirror_ids[i]);
10570                         goto free_layout;
10571                 }
10572
10573                 if (!mirror_id_cbdata.is_valid_id) {
10574                         rc2 = -EINVAL;
10575                         fprintf(stderr,
10576                                 "%s: '%s' invalid specified mirror id: %u.\n",
10577                                 progname, fname, mirror_ids[i]);
10578                 }
10579         }
10580         rc = rc2;
10581
10582 free_layout:
10583         llapi_layout_free(layout);
10584         llapi_lease_release(fd);
10585 close_fd:
10586         close(fd);
10587 error:
10588         return rc;
10589 }
10590
10591 static inline
10592 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
10593                            __u16 *mirror_ids, int ids_nr)
10594 {
10595         struct llapi_resync_comp comp_array[1024] = { { 0 } };
10596         struct llapi_layout *layout;
10597         struct stat stbuf;
10598         uint32_t flr_state;
10599         uint64_t start;
10600         uint64_t end;
10601         int comp_size = 0;
10602         int idx;
10603         int fd;
10604         int rc;
10605         int rc2;
10606
10607         if (stat(fname, &stbuf) < 0) {
10608                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
10609                         progname, fname, strerror(errno));
10610                 rc = -errno;
10611                 goto error;
10612         }
10613         if (!S_ISREG(stbuf.st_mode)) {
10614                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
10615                         progname, fname);
10616                 rc = -EINVAL;
10617                 goto error;
10618         }
10619
10620         fd = open(fname, O_DIRECT | O_RDWR);
10621         if (fd < 0) {
10622                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
10623                         progname, fname, strerror(errno));
10624                 rc = -errno;
10625                 goto error;
10626         }
10627
10628         layout = llapi_layout_get_by_fd(fd, 0);
10629         if (!layout) {
10630                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
10631                         progname, fname, strerror(errno));
10632                 rc = -errno;
10633                 goto close_fd;
10634         }
10635
10636         rc = llapi_layout_flags_get(layout, &flr_state);
10637         if (rc) {
10638                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
10639                         progname, fname, strerror(errno));
10640                 rc = -errno;
10641                 goto free_layout;
10642         }
10643
10644         flr_state &= LCM_FL_FLR_MASK;
10645         if (flr_state == LCM_FL_NONE) {
10646                 rc = -EINVAL;
10647                 fprintf(stderr, "%s: '%s' is not a FLR file.\n",
10648                         progname, fname);
10649                 goto free_layout;
10650         }
10651
10652         /* get stale component info */
10653         comp_size = llapi_mirror_find_stale(layout, comp_array,
10654                                             ARRAY_SIZE(comp_array),
10655                                             mirror_ids, ids_nr);
10656         if (comp_size <= 0) {
10657                 rc = comp_size;
10658                 goto free_layout;
10659         }
10660
10661         ioc->lil_mode = LL_LEASE_WRLCK;
10662         ioc->lil_flags = LL_LEASE_RESYNC;
10663         rc = llapi_lease_set(fd, ioc);
10664         if (rc < 0) {
10665                 if (rc == -EALREADY)
10666                         rc = 0;
10667                 else
10668                         fprintf(stderr,
10669                             "%s: '%s' llapi_lease_get_ext resync failed: %s.\n",
10670                                 progname, fname, strerror(-rc));
10671                 goto free_layout;
10672         }
10673
10674         /* get the read range [start, end) */
10675         start = comp_array[0].lrc_start;
10676         end = comp_array[0].lrc_end;
10677         for (idx = 1; idx < comp_size; idx++) {
10678                 if (comp_array[idx].lrc_start < start)
10679                         start = comp_array[idx].lrc_start;
10680                 if (end < comp_array[idx].lrc_end)
10681                         end = comp_array[idx].lrc_end;
10682         }
10683
10684         rc = llapi_lease_check(fd);
10685         if (rc != LL_LEASE_WRLCK) {
10686                 fprintf(stderr, "%s: '%s' lost lease lock.\n",
10687                         progname, fname);
10688                 goto free_layout;
10689         }
10690
10691         rc = llapi_mirror_resync_many(fd, layout, comp_array, comp_size,
10692                                       start, end);
10693         if (rc < 0)
10694                 fprintf(stderr, "%s: '%s' llapi_mirror_resync_many: %s.\n",
10695                         progname, fname, strerror(-rc));
10696
10697         rc = migrate_set_timestamps(fd, &stbuf);
10698         if (rc < 0) {
10699                 fprintf(stderr, "%s: '%s' cannot set timestamps: %s\n",
10700                         progname, fname, strerror(-rc));
10701                 goto free_layout;
10702         }
10703
10704         /* need to do the lease unlock even resync fails */
10705         ioc->lil_mode = LL_LEASE_UNLCK;
10706         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
10707         ioc->lil_count = 0;
10708         for (idx = 0; idx < comp_size; idx++) {
10709                 if (comp_array[idx].lrc_synced) {
10710                         ioc->lil_ids[ioc->lil_count] = comp_array[idx].lrc_id;
10711                         ioc->lil_count++;
10712                 }
10713         }
10714
10715         rc2 = llapi_lease_set(fd, ioc);
10716         /**
10717          * llapi_lease_set returns lease mode when it request to unlock
10718          * the lease lock.
10719          */
10720         if (rc2 <= 0) {
10721                 /* rc2 == 0 means lost lease lock */
10722                 if (rc2 == 0 && rc == 0)
10723                         rc = -EBUSY;
10724                 else
10725                         rc = rc2;
10726                 fprintf(stderr, "%s: resync file '%s' failed: %s.\n",
10727                         progname, fname,
10728                         rc2 == 0 ? "lost lease lock" : strerror(-rc2));
10729
10730                 llapi_lease_release(fd);
10731                 goto free_layout;
10732         }
10733
10734 free_layout:
10735         llapi_layout_free(layout);
10736 close_fd:
10737         close(fd);
10738 error:
10739         return rc;
10740 }
10741
10742 static inline int lfs_mirror_resync(int argc, char **argv)
10743 {
10744         struct option long_opts[] = {
10745         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10746         { .val = 'o',   .name = "only",         .has_arg = required_argument },
10747         { .name = NULL } };
10748         struct ll_ioc_lease *ioc = NULL;
10749         __u16 mirror_ids[128] = { 0 };
10750         int ids_nr = 0;
10751         int c;
10752         int rc = 0;
10753
10754         while ((c = getopt_long(argc, argv, "ho:", long_opts, NULL)) >= 0) {
10755                 switch (c) {
10756                 case 'o':
10757                         rc = parse_mirror_ids(mirror_ids,
10758                                         sizeof(mirror_ids) / sizeof(__u16),
10759                                         optarg);
10760                         if (rc < 0) {
10761                                 fprintf(stderr,
10762                                         "%s: bad mirror ids '%s'.\n",
10763                                         argv[0], optarg);
10764                                 goto error;
10765                         }
10766                         ids_nr = rc;
10767                         break;
10768                 default:
10769                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10770                                 progname, argv[optind - 1]);
10771                         /* fallthrough */
10772                 case 'h':
10773                         rc = CMD_HELP;
10774                         goto error;
10775                 }
10776         }
10777
10778         if (argc == optind) {
10779                 fprintf(stderr, "%s: no file name given.\n", argv[0]);
10780                 rc = CMD_HELP;
10781                 goto error;
10782         }
10783
10784         if (ids_nr > 0 && argc > optind + 1) {
10785                 fprintf(stderr,
10786                     "%s: option '--only' cannot be used upon multiple files.\n",
10787                         argv[0]);
10788                 rc = CMD_HELP;
10789                 goto error;
10790         }
10791
10792         if (ids_nr > 0) {
10793                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
10794                 if (rc < 0)
10795                         goto error;
10796         }
10797
10798         /* set the lease on the file */
10799         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
10800         if (!ioc) {
10801                 fprintf(stderr, "%s: cannot alloc id array for ioc: %s.\n",
10802                         argv[0], strerror(errno));
10803                 rc = -errno;
10804                 goto error;
10805         }
10806
10807         for (; optind < argc; optind++) {
10808                 rc = lfs_mirror_resync_file(argv[optind], ioc,
10809                                             mirror_ids, ids_nr);
10810                 /* ignore previous file's error, continue with next file */
10811
10812                 /* reset ioc */
10813                 memset(ioc, 0, sizeof(*ioc) + sizeof(__u32) * 4096);
10814         }
10815
10816         free(ioc);
10817 error:
10818         return rc;
10819 }
10820
10821 static inline int verify_mirror_id_by_fd(int fd, __u16 mirror_id)
10822 {
10823         struct llapi_layout *layout;
10824         int rc;
10825
10826         layout = llapi_layout_get_by_fd(fd, 0);
10827         if (!layout) {
10828                 fprintf(stderr, "could not get layout.\n");
10829                 return  -EINVAL;
10830         }
10831
10832         rc = llapi_layout_comp_iterate(layout, find_mirror_id, &mirror_id);
10833         if (rc < 0) {
10834                 fprintf(stderr, "failed to iterate layout\n");
10835                 llapi_layout_free(layout);
10836
10837                 return rc;
10838         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
10839                 fprintf(stderr, "does not find mirror with ID %u\n", mirror_id);
10840                 llapi_layout_free(layout);
10841
10842                 return -EINVAL;
10843         }
10844         llapi_layout_free(layout);
10845
10846         return 0;
10847 }
10848
10849 /**
10850  * Check whether two files are the same file
10851  * \retval      0  same file
10852  * \retval      1  not the same file
10853  * \retval      <0 error code
10854  */
10855 static inline int check_same_file(int fd, const char *f2)
10856 {
10857         struct stat stbuf1;
10858         struct stat stbuf2;
10859
10860         if (fstat(fd, &stbuf1) < 0)
10861                 return -errno;
10862
10863         if (stat(f2, &stbuf2) < 0)
10864                 return 1;
10865
10866         if (stbuf1.st_rdev == stbuf2.st_rdev &&
10867             stbuf1.st_ino == stbuf2.st_ino)
10868                 return 0;
10869
10870         return 1;
10871 }
10872
10873 static inline int lfs_mirror_read(int argc, char **argv)
10874 {
10875         int rc = CMD_HELP;
10876         __u16 mirror_id = 0;
10877         const char *outfile = NULL;
10878         char *fname;
10879         int fd = 0;
10880         int outfd;
10881         int c;
10882         void *buf;
10883         const size_t buflen = 4 << 20;
10884         off_t pos;
10885         struct option long_opts[] = {
10886         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10887         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
10888         { .val = 'o',   .name = "outfile",      .has_arg = required_argument },
10889         { .name = NULL } };
10890
10891         while ((c = getopt_long(argc, argv, "hN:o:", long_opts, NULL)) >= 0) {
10892                 char *end;
10893
10894                 switch (c) {
10895                 case 'N': {
10896                         unsigned long int id;
10897
10898                         errno = 0;
10899                         id = strtoul(optarg, &end, 0);
10900                         if (errno != 0 || *end != '\0' || id == 0 ||
10901                             id > UINT16_MAX) {
10902                                 fprintf(stderr,
10903                                         "%s %s: invalid mirror ID '%s'\n",
10904                                         progname, argv[0], optarg);
10905                                 return rc;
10906                         }
10907
10908                         mirror_id = (__u16)id;
10909                         break;
10910                 }
10911                 case 'o':
10912                         outfile = optarg;
10913                         break;
10914                 default:
10915                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10916                                 progname, argv[optind - 1]);
10917                         /* fallthrough */
10918                 case 'h':
10919                         return CMD_HELP;
10920                 }
10921         }
10922
10923         if (argc == optind) {
10924                 fprintf(stderr, "%s %s: no mirrored file provided\n",
10925                         progname, argv[0]);
10926                 return rc;
10927         } else if (argc > optind + 1) {
10928                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
10929                 return rc;
10930         }
10931
10932         if (mirror_id == 0) {
10933                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
10934                         progname, argv[0]);
10935                 return rc;
10936         }
10937
10938         /* open mirror file */
10939         fname = argv[optind];
10940         fd = open(fname, O_DIRECT | O_RDONLY);
10941         if (fd < 0) {
10942                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
10943                         progname, argv[0], fname, strerror(errno));
10944                 return rc;
10945         }
10946
10947         /* verify mirror id */
10948         rc = verify_mirror_id_by_fd(fd, mirror_id);
10949         if (rc) {
10950                 fprintf(stderr,
10951                         "%s %s: cannot find mirror with ID %u in '%s'\n",
10952                         progname, argv[0], mirror_id, fname);
10953                 goto close_fd;
10954         }
10955
10956         /* open output file - O_EXCL ensures output is not the same as input */
10957         if (outfile) {
10958                 outfd = open(outfile, O_EXCL | O_WRONLY | O_CREAT, 0644);
10959                 if (outfd < 0) {
10960                         fprintf(stderr, "%s %s: cannot create file '%s': %s\n",
10961                                 progname, argv[0], outfile, strerror(errno));
10962                         rc = -errno;
10963                         goto close_fd;
10964                 }
10965         } else {
10966                 outfd = STDOUT_FILENO;
10967         }
10968
10969         /* allocate buffer */
10970         rc = posix_memalign(&buf, sysconf(_SC_PAGESIZE), buflen);
10971         if (rc) {
10972                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
10973                                 progname, argv[0], rc);
10974                 goto close_outfd;
10975         }
10976
10977         pos = 0;
10978         while (1) {
10979                 ssize_t bytes_read;
10980                 ssize_t written = 0;
10981
10982                 bytes_read = llapi_mirror_read(fd, mirror_id, buf, buflen, pos);
10983                 if (bytes_read < 0) {
10984                         rc = bytes_read;
10985                         fprintf(stderr,
10986                                 "%s %s: fail to read data from mirror %u: %s\n",
10987                                 progname, argv[0], mirror_id, strerror(-rc));
10988                         goto free_buf;
10989                 }
10990
10991                 /* EOF reached */
10992                 if (bytes_read == 0)
10993                         break;
10994
10995                 while (written < bytes_read) {
10996                         ssize_t written2;
10997
10998                         written2 = write(outfd, buf + written,
10999                                          bytes_read - written);
11000                         if (written2 < 0) {
11001                                 fprintf(stderr,
11002                                         "%s %s: fail to write %s: %s\n",
11003                                         progname, argv[0], outfile ? : "STDOUT",
11004                                         strerror(errno));
11005                                 rc = -errno;
11006                                 goto free_buf;
11007                         }
11008                         written += written2;
11009                 }
11010
11011                 if (written != bytes_read) {
11012                         fprintf(stderr,
11013                 "%s %s: written %ld bytes does not match with %ld read.\n",
11014                                 progname, argv[0], written, bytes_read);
11015                         rc = -EIO;
11016                         goto free_buf;
11017                 }
11018
11019                 pos += bytes_read;
11020         }
11021
11022         fsync(outfd);
11023         rc = 0;
11024
11025 free_buf:
11026         free(buf);
11027 close_outfd:
11028         if (outfile)
11029                 close(outfd);
11030 close_fd:
11031         close(fd);
11032
11033         return rc;
11034 }
11035
11036 static inline int lfs_mirror_write(int argc, char **argv)
11037 {
11038         int rc = CMD_HELP;
11039         __u16 mirror_id = 0;
11040         const char *inputfile = NULL;
11041         char *fname;
11042         int fd = 0;
11043         int inputfd;
11044         int c;
11045         void *buf;
11046         const size_t buflen = 4 << 20;
11047         off_t pos;
11048         size_t page_size = sysconf(_SC_PAGESIZE);
11049         struct ll_ioc_lease_id ioc;
11050         struct option long_opts[] = {
11051         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11052         { .val = 'i',   .name = "inputfile",    .has_arg = required_argument },
11053         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
11054         { .name = NULL } };
11055
11056         while ((c = getopt_long(argc, argv, "hi:N:", long_opts, NULL)) >= 0) {
11057                 char *end;
11058
11059                 switch (c) {
11060                 case 'N': {
11061                         unsigned long int id;
11062
11063                         errno = 0;
11064                         id = strtoul(optarg, &end, 0);
11065                         if (errno != 0 || *end != '\0' || id == 0 ||
11066                             id > UINT16_MAX) {
11067                                 fprintf(stderr,
11068                                         "%s %s: invalid mirror ID '%s'\n",
11069                                         progname, argv[0], optarg);
11070                                 return rc;
11071                         }
11072
11073                         mirror_id = (__u16)id;
11074                         break;
11075                 }
11076                 case 'i':
11077                         inputfile = optarg;
11078                         break;
11079                 default:
11080                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11081                                 progname, argv[optind - 1]);
11082                         /* fallthrough */
11083                 case 'h':
11084                         return CMD_HELP;
11085                 }
11086         }
11087
11088         if (argc == optind) {
11089                 fprintf(stderr, "%s %s: no mirrored file provided\n",
11090                         progname, argv[0]);
11091                 return rc;
11092         } else if (argc > optind + 1) {
11093                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
11094                 return rc;
11095         }
11096
11097         if (mirror_id == 0) {
11098                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
11099                         progname, argv[0]);
11100                 return rc;
11101         }
11102
11103         /* open mirror file */
11104         fname = argv[optind];
11105         fd = open(fname, O_DIRECT | O_WRONLY);
11106         if (fd < 0) {
11107                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
11108                         progname, argv[0], fname, strerror(errno));
11109                 return rc;
11110         }
11111
11112         /* verify mirror id */
11113         rc = verify_mirror_id_by_fd(fd, mirror_id);
11114         if (rc) {
11115                 fprintf(stderr,
11116                         "%s %s: cannot find mirror with ID %u in '%s'\n",
11117                         progname, argv[0], mirror_id, fname);
11118                 goto close_fd;
11119         }
11120
11121         /* open input file */
11122         if (inputfile) {
11123                 rc = check_same_file(fd, inputfile);
11124                 if (rc == 0) {
11125                         fprintf(stderr,
11126                         "%s %s: input file cannot be the mirrored file\n",
11127                                 progname, argv[0]);
11128                         goto close_fd;
11129                 }
11130                 if (rc < 0)
11131                         goto close_fd;
11132
11133                 inputfd = open(inputfile, O_RDONLY, 0644);
11134                 if (inputfd < 0) {
11135                         fprintf(stderr, "%s %s: cannot open file '%s': %s\n",
11136                                 progname, argv[0], inputfile, strerror(errno));
11137                         rc = -errno;
11138                         goto close_fd;
11139                 }
11140         } else {
11141                 inputfd = STDIN_FILENO;
11142         }
11143
11144         /* allocate buffer */
11145         rc = posix_memalign(&buf, page_size, buflen);
11146         if (rc) {
11147                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
11148                         progname, argv[0], rc);
11149                 goto close_inputfd;
11150         }
11151
11152         /* prepare target mirror components instantiation */
11153         ioc.lil_mode = LL_LEASE_WRLCK;
11154         ioc.lil_flags = LL_LEASE_RESYNC;
11155         ioc.lil_mirror_id = mirror_id;
11156         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
11157         if (rc < 0) {
11158                 fprintf(stderr,
11159                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
11160                         progname, argv[0], fname, strerror(errno));
11161                 goto free_buf;
11162         }
11163
11164         pos = 0;
11165         while (1) {
11166                 ssize_t bytes_read;
11167                 ssize_t written;
11168                 size_t to_write;
11169
11170                 rc = llapi_lease_check(fd);
11171                 if (rc != LL_LEASE_WRLCK) {
11172                         fprintf(stderr, "%s %s: '%s' lost lease lock\n",
11173                                 progname, argv[0], fname);
11174                         goto free_buf;
11175                 }
11176
11177                 bytes_read = read(inputfd, buf, buflen);
11178                 if (bytes_read < 0) {
11179                         rc = bytes_read;
11180                         fprintf(stderr,
11181                                 "%s %s: fail to read data from '%s': %s\n",
11182                                 progname, argv[0], inputfile ? : "STDIN",
11183                                 strerror(errno));
11184                         rc = -errno;
11185                         goto free_buf;
11186                 }
11187
11188                 /* EOF reached */
11189                 if (bytes_read == 0)
11190                         break;
11191
11192                 /* round up to page align to make direct IO happy. */
11193                 to_write = (bytes_read + page_size - 1) & ~(page_size - 1);
11194
11195                 written = llapi_mirror_write(fd, mirror_id, buf, to_write,
11196                                              pos);
11197                 if (written < 0) {
11198                         rc = written;
11199                         fprintf(stderr,
11200                               "%s %s: fail to write to mirror %u: %s\n",
11201                                 progname, argv[0], mirror_id,
11202                                 strerror(-rc));
11203                         goto free_buf;
11204                 }
11205
11206                 pos += bytes_read;
11207         }
11208
11209         if (pos & (page_size - 1)) {
11210                 rc = llapi_mirror_truncate(fd, mirror_id, pos);
11211                 if (rc < 0)
11212                         goto free_buf;
11213         }
11214
11215         ioc.lil_mode = LL_LEASE_UNLCK;
11216         ioc.lil_flags = LL_LEASE_RESYNC_DONE;
11217         ioc.lil_count = 0;
11218         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
11219         if (rc <= 0) {
11220                 if (rc == 0)
11221                         rc = -EBUSY;
11222                 fprintf(stderr,
11223                         "%s %s: release lease lock of '%s' failed: %s\n",
11224                         progname, argv[0], fname, strerror(errno));
11225                 goto free_buf;
11226         }
11227
11228         rc = 0;
11229
11230 free_buf:
11231         free(buf);
11232 close_inputfd:
11233         if (inputfile)
11234                 close(inputfd);
11235 close_fd:
11236         close(fd);
11237
11238         return rc;
11239 }
11240
11241 static inline int get_other_mirror_ids(int fd, __u16 *ids, __u16 exclude_id)
11242 {
11243         struct llapi_layout *layout;
11244         struct collect_ids_data cid = { .cid_ids = ids,
11245                                         .cid_count = 0,
11246                                         .cid_exclude = exclude_id, };
11247         int rc;
11248
11249         layout = llapi_layout_get_by_fd(fd, 0);
11250         if (!layout) {
11251                 fprintf(stderr, "could not get layout\n");
11252                 return -EINVAL;
11253         }
11254
11255         rc = llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
11256         if (rc < 0) {
11257                 fprintf(stderr, "failed to iterate layout\n");
11258                 llapi_layout_free(layout);
11259
11260                 return rc;
11261         }
11262         llapi_layout_free(layout);
11263
11264         return cid.cid_count;
11265 }
11266
11267 #ifndef MIRROR_ID_NEG
11268 #define MIRROR_ID_NEG         0x8000
11269 #endif
11270
11271 static inline int lfs_mirror_copy(int argc, char **argv)
11272 {
11273         int rc = CMD_HELP;
11274         __u16 read_mirror_id = 0;
11275         __u16 ids[128] = { 0 };
11276         int count = 0;
11277         struct llapi_layout *layout = NULL;
11278         struct llapi_resync_comp comp_array[1024] = { { 0 } };
11279         int comp_size = 0;
11280         char *fname;
11281         int fd = 0;
11282         int c;
11283         int i;
11284         ssize_t copied;
11285         struct ll_ioc_lease *ioc = NULL;
11286         struct ll_ioc_lease_id *resync_ioc;
11287         struct option long_opts[] = {
11288         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11289         { .val = 'i',   .name = "read-mirror",  .has_arg = required_argument },
11290         { .val = 'o',   .name = "write-mirror", .has_arg = required_argument },
11291         { .name = NULL } };
11292         char cmd[PATH_MAX];
11293
11294         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
11295         progname = cmd;
11296         while ((c = getopt_long(argc, argv, "hi:o:", long_opts, NULL)) >= 0) {
11297                 char *end;
11298
11299                 switch (c) {
11300                 case 'i': {
11301                         unsigned long int id;
11302
11303                         errno = 0;
11304                         id = strtoul(optarg, &end, 0);
11305                         if (errno != 0 || *end != '\0' || id == 0 ||
11306                             id > UINT16_MAX) {
11307                                 fprintf(stderr,
11308                                         "%s: invalid read mirror ID '%s'\n",
11309                                         progname, optarg);
11310                                 return rc;
11311                         }
11312
11313                         read_mirror_id = (__u16)id;
11314                         break;
11315                 }
11316                 case 'o':
11317                         if (!strcmp(optarg, "-1")) {
11318                                 /* specify all other mirrors */
11319                                 ids[0] = (__u16)-1;
11320                                 count = 1;
11321                         } else {
11322                                 count = parse_mirror_ids((__u16 *)ids,
11323                                                          ARRAY_SIZE(ids),
11324                                                          optarg);
11325                                 if (count < 0)
11326                                         return rc;
11327                         }
11328                         break;
11329                 default:
11330                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11331                                 progname, argv[optind - 1]);
11332                         /* fallthrough */
11333                 case 'h':
11334                         return CMD_HELP;
11335                 }
11336         }
11337
11338         if (argc == optind) {
11339                 fprintf(stderr, "%s %s: no mirrored file provided\n",
11340                         progname, argv[0]);
11341                 return rc;
11342         } else if (argc > optind + 1) {
11343                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
11344                 return rc;
11345         }
11346
11347         if (read_mirror_id == 0) {
11348                 fprintf(stderr,
11349                         "%s %s: no valid read mirror ID %d is provided\n",
11350                         progname, argv[0], read_mirror_id);
11351                 return rc;
11352         }
11353
11354         if (count == 0) {
11355                 fprintf(stderr,
11356                         "%s %s: no write mirror ID is provided\n",
11357                         progname, argv[0]);
11358                 return rc;
11359         }
11360
11361         for (i = 0; i < count; i++) {
11362                 if (read_mirror_id == ids[i]) {
11363                         fprintf(stderr,
11364                         "%s %s: read and write mirror ID cannot be the same\n",
11365                                 progname, argv[0]);
11366                         return rc;
11367                 }
11368         }
11369
11370         /* open mirror file */
11371         fname = argv[optind];
11372
11373         fd = open(fname, O_DIRECT | O_RDWR);
11374         if (fd < 0) {
11375                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
11376                         progname, argv[0], fname, strerror(errno));
11377                 return rc;
11378         }
11379
11380         /* write to all other mirrors */
11381         if (ids[0] == (__u16)-1) {
11382                 count = get_other_mirror_ids(fd, ids, read_mirror_id);
11383                 if (count <= 0) {
11384                         rc = count;
11385                         fprintf(stderr,
11386                         "%s %s: failed to get other mirror ids in '%s': %d\n",
11387                                 progname, argv[0], fname, rc);
11388                         goto close_fd;
11389                 }
11390         }
11391
11392         /* verify mirror id */
11393         rc = verify_mirror_id_by_fd(fd, read_mirror_id);
11394         if (rc) {
11395                 fprintf(stderr,
11396                         "%s %s: cannot find mirror with ID %u in '%s'\n",
11397                         progname, argv[0], read_mirror_id, fname);
11398                 goto close_fd;
11399         }
11400
11401         for (i = 0; i < count; i++) {
11402                 rc = verify_mirror_id_by_fd(fd, ids[i]);
11403                 if (rc) {
11404                         fprintf(stderr,
11405                         "%s %s: cannot find mirror with ID %u in '%s'\n",
11406                                 progname, argv[0], ids[i], fname);
11407                         goto close_fd;
11408                 }
11409         }
11410
11411         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
11412         if (!ioc) {
11413                 fprintf(stderr,
11414                         "%s %s: cannot alloc comp id array for ioc: %s\n",
11415                         progname, argv[0], strerror(errno));
11416                 rc = -errno;
11417                 goto close_fd;
11418         }
11419
11420         /* get stale component info */
11421         layout = llapi_layout_get_by_fd(fd, 0);
11422         if (!layout) {
11423                 fprintf(stderr, "%s %s: failed to get layout of '%s': %s\n",
11424                         progname, argv[0], fname, strerror(errno));
11425                 rc = -errno;
11426                 goto free_ioc;
11427         }
11428         comp_size = llapi_mirror_find_stale(layout, comp_array,
11429                                             ARRAY_SIZE(comp_array),
11430                                             ids, count);
11431         llapi_layout_free(layout);
11432         if (comp_size < 0) {
11433                 rc = comp_size;
11434                 goto free_ioc;
11435         }
11436
11437         /* prepare target mirror components instantiation */
11438         resync_ioc = (struct ll_ioc_lease_id *)ioc;
11439         resync_ioc->lil_mode = LL_LEASE_WRLCK;
11440         resync_ioc->lil_flags = LL_LEASE_RESYNC;
11441         if (count == 1)
11442                 resync_ioc->lil_mirror_id = ids[0];
11443         else
11444                 resync_ioc->lil_mirror_id = read_mirror_id | MIRROR_ID_NEG;
11445         rc = llapi_lease_set(fd, ioc);
11446         if (rc < 0) {
11447                 fprintf(stderr,
11448                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
11449                         progname, argv[0], fname, strerror(errno));
11450                 goto free_ioc;
11451         }
11452
11453         copied = llapi_mirror_copy_many(fd, read_mirror_id, ids, count);
11454         if (copied < 0) {
11455                 rc = copied;
11456                 fprintf(stderr, "%s %s: copy error: %d\n",
11457                         progname, argv[0], rc);
11458                 goto free_ioc;
11459         }
11460
11461         fprintf(stdout, "mirror copied successfully: ");
11462         for (i = 0; i < copied; i++)
11463                 fprintf(stdout, "%d ", ids[i]);
11464         fprintf(stdout, "\n");
11465
11466         ioc->lil_mode = LL_LEASE_UNLCK;
11467         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
11468         ioc->lil_count = 0;
11469         for (i = 0; i < comp_size; i++) {
11470                 int j;
11471
11472                 for (j = 0; j < copied; j++) {
11473                         if (comp_array[i].lrc_mirror_id != ids[j])
11474                                 continue;
11475
11476                         ioc->lil_ids[ioc->lil_count] = comp_array[i].lrc_id;
11477                         ioc->lil_count++;
11478                 }
11479         }
11480         rc = llapi_lease_set(fd, ioc);
11481         if (rc <= 0) {
11482                 if (rc == 0)
11483                         rc = -EBUSY;
11484                 fprintf(stderr,
11485                         "%s %s: release lease lock of '%s' failed: %s\n",
11486                         progname, argv[0], fname, strerror(errno));
11487                 goto free_ioc;
11488         }
11489
11490         rc = 0;
11491
11492 free_ioc:
11493         free(ioc);
11494 close_fd:
11495         close(fd);
11496
11497         return rc;
11498 }
11499
11500 /**
11501  * struct verify_chunk - Mirror chunk to be verified.
11502  * @chunk:        [start, end) of the chunk.
11503  * @mirror_count: Number of mirror ids in @mirror_id array.
11504  * @mirror_id:    Array of valid mirror ids that cover the chunk.
11505  */
11506 struct verify_chunk {
11507         struct lu_extent chunk;
11508         unsigned int mirror_count;
11509         __u16 mirror_id[LUSTRE_MIRROR_COUNT_MAX];
11510 };
11511
11512 /**
11513  * print_chunks() - Print chunk information.
11514  * @fname:       Mirrored file name.
11515  * @chunks:      Array of chunks.
11516  * @chunk_count: Number of chunks in @chunks array.
11517  *
11518  * This function prints [start, end) of each chunk in @chunks
11519  * for mirrored file @fname, and also prints the valid mirror ids
11520  * that cover the chunk.
11521  *
11522  * Return: void.
11523  */
11524 static inline
11525 void print_chunks(const char *fname, struct verify_chunk *chunks,
11526                   int chunk_count)
11527 {
11528         int i;
11529         int j;
11530
11531         fprintf(stdout, "Chunks to be verified in %s:\n", fname);
11532         for (i = 0; i < chunk_count; i++) {
11533                 fprintf(stdout, DEXT, PEXT(&chunks[i].chunk));
11534
11535                 if (chunks[i].mirror_count == 0)
11536                         fprintf(stdout, "\t[");
11537                 else {
11538                         fprintf(stdout, "\t[%u", chunks[i].mirror_id[0]);
11539                         for (j = 1; j < chunks[i].mirror_count; j++)
11540                                 fprintf(stdout, ", %u", chunks[i].mirror_id[j]);
11541                 }
11542                 fprintf(stdout, "]\t%u\n", chunks[i].mirror_count);
11543         }
11544         fprintf(stdout, "\n");
11545 }
11546
11547 /**
11548  * print_checksums() - Print CRC-32 checksum values.
11549  * @chunk: A chunk and its corresponding valid mirror ids.
11550  * @crc:   CRC-32 checksum values on the chunk for each valid mirror.
11551  *
11552  * This function prints CRC-32 checksum values on @chunk for
11553  * each valid mirror that covers it.
11554  *
11555  * Return: void.
11556  */
11557 static inline
11558 void print_checksums(struct verify_chunk *chunk, unsigned long *crc)
11559 {
11560         int i;
11561
11562         fprintf(stdout,
11563                 "CRC-32 checksum value for chunk "DEXT":\n",
11564                 PEXT(&chunk->chunk));
11565         for (i = 0; i < chunk->mirror_count; i++)
11566                 fprintf(stdout, "Mirror %u:\t%#lx\n",
11567                         chunk->mirror_id[i], crc[i]);
11568         fprintf(stdout, "\n");
11569 }
11570
11571 /**
11572  * filter_mirror_id() - Filter specified mirror ids.
11573  * @chunks:      Array of chunks.
11574  * @chunk_count: Number of chunks in @chunks array.
11575  * @mirror_ids:  Specified mirror ids to be verified.
11576  * @ids_nr:      Number of specified mirror ids.
11577  *
11578  * This function scans valid mirror ids that cover each chunk in @chunks
11579  * and filters specified mirror ids.
11580  *
11581  * Return: void.
11582  */
11583 static inline
11584 void filter_mirror_id(struct verify_chunk *chunks, int chunk_count,
11585                       __u16 *mirror_ids, int ids_nr)
11586 {
11587         int i;
11588         int j;
11589         int k;
11590         __u16 valid_id[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
11591         unsigned int valid_count = 0;
11592
11593         for (i = 0; i < chunk_count; i++) {
11594                 if (chunks[i].mirror_count == 0)
11595                         continue;
11596
11597                 valid_count = 0;
11598                 for (j = 0; j < ids_nr; j++) {
11599                         for (k = 0; k < chunks[i].mirror_count; k++) {
11600                                 if (chunks[i].mirror_id[k] == mirror_ids[j]) {
11601                                         valid_id[valid_count] = mirror_ids[j];
11602                                         valid_count++;
11603                                         break;
11604                                 }
11605                         }
11606                 }
11607
11608                 memcpy(chunks[i].mirror_id, valid_id,
11609                        sizeof(__u16) * valid_count);
11610                 chunks[i].mirror_count = valid_count;
11611         }
11612 }
11613
11614 /**
11615  * lfs_mirror_prepare_chunk() - Find mirror chunks to be verified.
11616  * @layout:      Mirror component list.
11617  * @chunks:      Array of chunks.
11618  * @chunks_size: Array size of @chunks.
11619  *
11620  * This function scans the components in @layout from offset 0 to LUSTRE_EOF
11621  * to find out chunk segments and store them in @chunks array.
11622  *
11623  * The @mirror_id array in each element of @chunks will store the valid
11624  * mirror ids that cover the chunk. If a mirror component covering the
11625  * chunk has LCME_FL_STALE or LCME_FL_OFFLINE flag, then the mirror id
11626  * will not be stored into the @mirror_id array, and the chunk for that
11627  * mirror will not be verified.
11628  *
11629  * The @mirror_count in each element of @chunks will store the number of
11630  * mirror ids in @mirror_id array. If @mirror_count is 0, it indicates the
11631  * chunk is invalid in all of the mirrors. And if @mirror_count is 1, it
11632  * indicates the chunk is valid in only one mirror. In both cases, the
11633  * chunk will not be verified.
11634  *
11635  * Here is an example:
11636  *
11637  *  0      1M     2M     3M     4M           EOF
11638  *  +------+-------------+--------------------+
11639  *  |      |             |      S             |       mirror1
11640  *  +------+------+------+------+-------------+
11641  *  |             |   S  |   S  |             |       mirror2
11642  *  +-------------+------+------+-------------+
11643  *
11644  * prepared @chunks array will contain 5 elements:
11645  * (([0, 1M), [1, 2], 2),
11646  *  ([1M, 2M), [1, 2], 2),
11647  *  ([2M, 3M), [1], 1),
11648  *  ([3M, 4M], [], 0),
11649  *  ([4M, EOF), [2], 1))
11650  *
11651  * Return: the actual array size of @chunks on success
11652  *         or a negative error code on failure.
11653  */
11654 static inline
11655 int lfs_mirror_prepare_chunk(struct llapi_layout *layout,
11656                              struct verify_chunk *chunks,
11657                              size_t chunks_size)
11658 {
11659         uint64_t start;
11660         uint64_t end;
11661         uint32_t mirror_id;
11662         uint32_t flags;
11663         int idx = 0;
11664         int i = 0;
11665         int rc = 0;
11666
11667         memset(chunks, 0, sizeof(*chunks) * chunks_size);
11668
11669         while (1) {
11670                 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
11671                 if (rc < 0) {
11672                         fprintf(stderr,
11673                                 "%s: move to the first layout component: %s.\n",
11674                                 progname, strerror(errno));
11675                         goto error;
11676                 }
11677
11678                 i = 0;
11679                 rc = 0;
11680                 chunks[idx].chunk.e_end = LUSTRE_EOF;
11681                 while (rc == 0) {
11682                         rc = llapi_layout_comp_extent_get(layout, &start, &end);
11683                         if (rc < 0) {
11684                                 fprintf(stderr,
11685                                         "%s: llapi_layout_comp_extent_get failed: %s.\n",
11686                                         progname, strerror(errno));
11687                                 goto error;
11688                         }
11689
11690                         if (start > chunks[idx].chunk.e_start ||
11691                             end <= chunks[idx].chunk.e_start)
11692                                 goto next;
11693
11694                         if (end < chunks[idx].chunk.e_end)
11695                                 chunks[idx].chunk.e_end = end;
11696
11697                         rc = llapi_layout_comp_flags_get(layout, &flags);
11698                         if (rc < 0) {
11699                                 fprintf(stderr,
11700                                         "%s: llapi_layout_comp_flags_get failed: %s.\n",
11701                                         progname, strerror(errno));
11702                                 goto error;
11703                         }
11704
11705                         if (flags & LCME_FL_STALE || flags & LCME_FL_OFFLINE)
11706                                 goto next;
11707
11708                         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
11709                         if (rc < 0) {
11710                                 fprintf(stderr,
11711                                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
11712                                         progname, strerror(errno));
11713                                 goto error;
11714                         }
11715
11716                         chunks[idx].mirror_id[i] = mirror_id;
11717                         i++;
11718                         if (i >= ARRAY_SIZE(chunks[idx].mirror_id)) {
11719                                 fprintf(stderr,
11720                                         "%s: mirror_id array is too small.\n",
11721                                         progname);
11722                                 rc = -EINVAL;
11723                                 goto error;
11724                         }
11725
11726 next:
11727                         rc = llapi_layout_comp_use(layout,
11728                                                    LLAPI_LAYOUT_COMP_USE_NEXT);
11729                         if (rc < 0) {
11730                                 fprintf(stderr,
11731                                         "%s: move to the next layout component: %s.\n",
11732                                         progname, strerror(errno));
11733                                 goto error;
11734                         }
11735                 } /* loop through all components */
11736
11737                 chunks[idx].mirror_count = i;
11738
11739                 if (chunks[idx].chunk.e_end == LUSTRE_EOF)
11740                         break;
11741
11742                 idx++;
11743                 if (idx >= chunks_size) {
11744                         fprintf(stderr, "%s: chunks array is too small.\n",
11745                                 progname);
11746                         rc = -EINVAL;
11747                         goto error;
11748                 }
11749
11750                 chunks[idx].chunk.e_start = chunks[idx - 1].chunk.e_end;
11751         }
11752
11753 error:
11754         return rc < 0 ? rc : idx + 1;
11755 }
11756
11757 /**
11758  * lfs_mirror_verify_chunk() - Verify a chunk.
11759  * @fd:        File descriptor of the mirrored file.
11760  * @file_size: Size of the mirrored file.
11761  * @chunk:     A chunk and its corresponding valid mirror ids.
11762  * @verbose:   Verbose mode.
11763  *
11764  * This function verifies a @chunk contains exactly the same data
11765  * ammong the mirrors that cover it.
11766  *
11767  * If @verbose is specified, then the function will print where the
11768  * differences are if the data do not match. Otherwise, it will
11769  * just return an error in that case.
11770  *
11771  * Return: 0 on success or a negative error code on failure.
11772  */
11773 static inline
11774 int lfs_mirror_verify_chunk(int fd, size_t file_size,
11775                             struct verify_chunk *chunk, int verbose)
11776 {
11777         const size_t buflen = 4 * 1024 * 1024; /* 4M */
11778         void *buf;
11779         size_t page_size = sysconf(_SC_PAGESIZE);
11780         ssize_t bytes_read;
11781         ssize_t bytes_done;
11782         size_t count;
11783         off_t pos;
11784         unsigned long crc;
11785         unsigned long crc_array[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
11786         int i;
11787         int rc = 0;
11788
11789         if (file_size == 0)
11790                 return 0;
11791
11792         rc = posix_memalign(&buf, page_size, buflen);
11793         if (rc) /* error code is returned directly */
11794                 return -rc;
11795
11796         if (verbose > 1) {
11797                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
11798                         PEXT(&chunk->chunk));
11799                 for (i = 0; i < chunk->mirror_count; i++)
11800                         fprintf(stdout, " %u", chunk->mirror_id[i]);
11801                 fprintf(stdout, "\n");
11802         }
11803
11804         bytes_done = 0;
11805         count = MIN(chunk->chunk.e_end, file_size) - chunk->chunk.e_start;
11806         pos = chunk->chunk.e_start;
11807         while (bytes_done < count) {
11808                 /* compute initial CRC-32 checksum */
11809                 crc = crc32(0L, Z_NULL, 0);
11810                 memset(crc_array, 0, sizeof(crc_array));
11811
11812                 bytes_read = 0;
11813                 for (i = 0; i < chunk->mirror_count; i++) {
11814                         bytes_read = llapi_mirror_read(fd, chunk->mirror_id[i],
11815                                                        buf, buflen, pos);
11816                         if (bytes_read < 0) {
11817                                 rc = bytes_read;
11818                                 fprintf(stderr,
11819                                         "%s: failed to read data from mirror %u: %s.\n",
11820                                         progname, chunk->mirror_id[i],
11821                                         strerror(-rc));
11822                                 goto error;
11823                         }
11824
11825                         /* compute new CRC-32 checksum */
11826                         crc_array[i] = crc32(crc, buf, bytes_read);
11827                 }
11828
11829                 if (verbose)
11830                         print_checksums(chunk, crc_array);
11831
11832                 /* compare CRC-32 checksum values */
11833                 for (i = 1; i < chunk->mirror_count; i++) {
11834                         if (crc_array[i] != crc_array[0]) {
11835                                 rc = -EINVAL;
11836
11837                                 fprintf(stderr,
11838                                         "%s: chunk "DEXT" has different checksum value on mirror %u and mirror %u.\n",
11839                                         progname, PEXT(&chunk->chunk),
11840                                         chunk->mirror_id[0],
11841                                         chunk->mirror_id[i]);
11842                         }
11843                 }
11844
11845                 pos += bytes_read;
11846                 bytes_done += bytes_read;
11847         }
11848
11849         if (verbose > 1 && rc == 0) {
11850                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
11851                         PEXT(&chunk->chunk));
11852                 for (i = 0; i < chunk->mirror_count; i++)
11853                         fprintf(stdout, " %u", chunk->mirror_id[i]);
11854                 fprintf(stdout, " PASS\n\n");
11855         }
11856
11857 error:
11858         free(buf);
11859         return rc;
11860 }
11861
11862 /**
11863  * lfs_mirror_verify_file() - Verify a mirrored file.
11864  * @fname:      Mirrored file name.
11865  * @mirror_ids: Specified mirror ids to be verified.
11866  * @ids_nr:     Number of specified mirror ids.
11867  * @verbose:    Verbose mode.
11868  *
11869  * This function verifies that each SYNC mirror of a mirrored file
11870  * specified by @fname contains exactly the same data.
11871  *
11872  * If @mirror_ids is specified, then the function will verify the
11873  * mirrors specified by @mirror_ids contain exactly the same data.
11874  *
11875  * If @verbose is specified, then the function will print where the
11876  * differences are if the data do not match. Otherwise, it will
11877  * just return an error in that case.
11878  *
11879  * Return: 0 on success or a negative error code on failure.
11880  */
11881 static inline
11882 int lfs_mirror_verify_file(const char *fname, __u16 *mirror_ids, int ids_nr,
11883                            int verbose)
11884 {
11885         struct verify_chunk chunks_array[1024] = { };
11886         struct llapi_layout *layout = NULL;
11887         struct stat stbuf;
11888         uint32_t flr_state;
11889         int fd;
11890         int chunk_count = 0;
11891         int idx = 0;
11892         int rc = 0;
11893         int rc1 = 0;
11894         int rc2 = 0;
11895
11896         if (stat(fname, &stbuf) < 0) {
11897                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
11898                         progname, fname, strerror(errno));
11899                 rc = -errno;
11900                 goto error;
11901         }
11902
11903         if (!S_ISREG(stbuf.st_mode)) {
11904                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
11905                         progname, fname);
11906                 rc = -EINVAL;
11907                 goto error;
11908         }
11909
11910         if (stbuf.st_size == 0) {
11911                 if (verbose)
11912                         fprintf(stdout, "%s: '%s' file size is 0.\n",
11913                                 progname, fname);
11914                 rc = 0;
11915                 goto error;
11916         }
11917
11918         fd = open(fname, O_DIRECT | O_RDONLY);
11919         if (fd < 0) {
11920                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
11921                         progname, fname, strerror(errno));
11922                 rc = -errno;
11923                 goto error;
11924         }
11925
11926         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
11927         if (rc < 0) {
11928                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
11929                         progname, fname, strerror(errno));
11930                 goto close_fd;
11931         }
11932
11933         layout = llapi_layout_get_by_fd(fd, 0);
11934         if (!layout) {
11935                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
11936                         progname, fname, strerror(errno));
11937                 rc = -errno;
11938                 llapi_lease_release(fd);
11939                 goto close_fd;
11940         }
11941
11942         rc = llapi_layout_flags_get(layout, &flr_state);
11943         if (rc < 0) {
11944                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
11945                         progname, fname, strerror(errno));
11946                 rc = -errno;
11947                 goto free_layout;
11948         }
11949
11950         flr_state &= LCM_FL_FLR_MASK;
11951         switch (flr_state) {
11952         case LCM_FL_NONE:
11953                 rc = -EINVAL;
11954                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
11955                         progname, fname, llapi_layout_flags_string(flr_state));
11956                 goto free_layout;
11957         default:
11958                 break;
11959         }
11960
11961         /* find out mirror chunks to be verified */
11962         chunk_count = lfs_mirror_prepare_chunk(layout, chunks_array,
11963                                                ARRAY_SIZE(chunks_array));
11964         if (chunk_count < 0) {
11965                 rc = chunk_count;
11966                 goto free_layout;
11967         }
11968
11969         if (ids_nr > 0)
11970                 /* filter specified mirror ids */
11971                 filter_mirror_id(chunks_array, chunk_count, mirror_ids, ids_nr);
11972
11973         if (verbose > 2)
11974                 print_chunks(fname, chunks_array, chunk_count);
11975
11976         for (idx = 0; idx < chunk_count; idx++) {
11977                 if (chunks_array[idx].chunk.e_start >= stbuf.st_size) {
11978                         if (verbose)
11979                                 fprintf(stdout,
11980                                         "%s: '%s' chunk "DEXT" exceeds file size %#llx: skipped\n",
11981                                         progname, fname,
11982                                         PEXT(&chunks_array[idx].chunk),
11983                                         (unsigned long long)stbuf.st_size);
11984                         break;
11985                 }
11986
11987                 if (chunks_array[idx].mirror_count == 0) {
11988                         fprintf(stderr,
11989                                 "%s: '%s' chunk "DEXT" is invalid in all of the mirrors: ",
11990                                 progname, fname,
11991                                 PEXT(&chunks_array[idx].chunk));
11992                         if (verbose) {
11993                                 fprintf(stderr, "skipped\n");
11994                                 continue;
11995                         }
11996                         rc = -EINVAL;
11997                         fprintf(stderr, "failed\n");
11998                         goto free_layout;
11999                 }
12000
12001                 if (chunks_array[idx].mirror_count == 1) {
12002                         if (verbose)
12003                                 fprintf(stdout,
12004                                         "%s: '%s' chunk "DEXT" is only valid in mirror %u: skipped\n",
12005                                         progname, fname,
12006                                         PEXT(&chunks_array[idx].chunk),
12007                                         chunks_array[idx].mirror_id[0]);
12008                         continue;
12009                 }
12010
12011                 rc = llapi_lease_check(fd);
12012                 if (rc != LL_LEASE_RDLCK) {
12013                         fprintf(stderr, "%s: '%s' lost lease lock.\n",
12014                                 progname, fname);
12015                         goto free_layout;
12016                 }
12017
12018                 /* verify one chunk */
12019                 rc1 = lfs_mirror_verify_chunk(fd, stbuf.st_size,
12020                                               &chunks_array[idx], verbose);
12021                 if (rc1 < 0) {
12022                         rc2 = rc1;
12023                         if (!verbose) {
12024                                 rc = rc1;
12025                                 goto free_layout;
12026                         }
12027                 }
12028         }
12029
12030         if (rc2 < 0)
12031                 rc = rc2;
12032
12033 free_layout:
12034         llapi_layout_free(layout);
12035         llapi_lease_release(fd);
12036 close_fd:
12037         close(fd);
12038 error:
12039         return rc;
12040 }
12041
12042 /**
12043  * lfs_mirror_verify() - Parse and execute lfs mirror verify command.
12044  * @argc: The count of lfs mirror verify command line arguments.
12045  * @argv: Array of strings for lfs mirror verify command line arguments.
12046  *
12047  * This function parses lfs mirror verify command and verifies the
12048  * specified mirrored file(s).
12049  *
12050  * Return: 0 on success or a negative error code on failure.
12051  */
12052 static inline int lfs_mirror_verify(int argc, char **argv)
12053 {
12054         __u16 mirror_ids[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
12055         int ids_nr = 0;
12056         int c;
12057         int verbose = 0;
12058         int rc = 0;
12059         int rc1 = 0;
12060         char cmd[PATH_MAX];
12061
12062         struct option long_opts[] = {
12063         { .val = 'h',   .name = "help",         .has_arg = no_argument },
12064         { .val = 'o',   .name = "only",         .has_arg = required_argument },
12065         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
12066         { .name = NULL } };
12067
12068         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12069         progname = cmd;
12070         while ((c = getopt_long(argc, argv, "ho:v", long_opts, NULL)) >= 0) {
12071                 switch (c) {
12072                 case 'o':
12073                         rc = parse_mirror_ids(mirror_ids,
12074                                               ARRAY_SIZE(mirror_ids),
12075                                               optarg);
12076                         if (rc < 0) {
12077                                 fprintf(stderr,
12078                                         "%s: bad mirror ids '%s'.\n",
12079                                         progname, optarg);
12080                                 goto error;
12081                         }
12082                         ids_nr = rc;
12083                         if (ids_nr < 2) {
12084                                 fprintf(stderr,
12085                                         "%s: at least 2 mirror ids needed with '--only' option.\n",
12086                                         progname);
12087                                 rc = CMD_HELP;
12088                                 goto error;
12089                         }
12090                         break;
12091                 case 'v':
12092                         verbose++;
12093                         break;
12094                 default:
12095                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12096                                 progname, argv[optind - 1]);
12097                         /* fallthrough */
12098                 case 'h':
12099                         rc = CMD_HELP;
12100                         goto error;
12101                 }
12102         }
12103
12104         if (argc == optind) {
12105                 fprintf(stderr, "%s: no file name given.\n", progname);
12106                 rc = CMD_HELP;
12107                 goto error;
12108         }
12109
12110         if (ids_nr > 0 && argc > optind + 1) {
12111                 fprintf(stderr,
12112                         "%s: '--only' cannot be used upon multiple files.\n",
12113                         progname);
12114                 rc = CMD_HELP;
12115                 goto error;
12116         }
12117
12118         if (ids_nr > 0) {
12119                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
12120                 if (rc < 0)
12121                         goto error;
12122         }
12123
12124         rc = 0;
12125         for (; optind < argc; optind++) {
12126                 rc1 = lfs_mirror_verify_file(argv[optind], mirror_ids, ids_nr,
12127                                              verbose);
12128                 if (rc1 < 0)
12129                         rc = rc1;
12130         }
12131 error:
12132         return rc;
12133 }
12134
12135 /**
12136  * lfs_mirror() - Parse and execute lfs mirror commands.
12137  * @argc: The count of lfs mirror command line arguments.
12138  * @argv: Array of strings for lfs mirror command line arguments.
12139  *
12140  * This function parses lfs mirror commands and performs the
12141  * corresponding functions specified in mirror_cmdlist[].
12142  *
12143  * Return: 0 on success or an error code on failure.
12144  */
12145 static int lfs_mirror(int argc, char **argv)
12146 {
12147         char cmd[PATH_MAX];
12148         int rc = 0;
12149
12150         setlinebuf(stdout);
12151
12152         Parser_init("lfs-mirror > ", mirror_cmdlist);
12153
12154         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12155         progname = cmd;
12156         program_invocation_short_name = cmd;
12157         if (argc > 1)
12158                 rc = Parser_execarg(argc - 1, argv + 1, mirror_cmdlist);
12159         else
12160                 rc = Parser_commands();
12161
12162         return rc < 0 ? -rc : rc;
12163 }
12164
12165 static void lustre_som_swab(struct lustre_som_attrs *attrs)
12166 {
12167 #if __BYTE_ORDER == __BIG_ENDIAN
12168         __swab16s(&attrs->lsa_valid);
12169         __swab64s(&attrs->lsa_size);
12170         __swab64s(&attrs->lsa_blocks);
12171 #endif
12172 }
12173
12174 enum lfs_som_type {
12175         LFS_SOM_SIZE = 0x1,
12176         LFS_SOM_BLOCKS = 0x2,
12177         LFS_SOM_FLAGS = 0x4,
12178         LFS_SOM_ATTR_ALL = LFS_SOM_SIZE | LFS_SOM_BLOCKS |
12179                            LFS_SOM_FLAGS,
12180 };
12181
12182 static int lfs_getsom(int argc, char **argv)
12183 {
12184         const char *path;
12185         struct lustre_som_attrs *attrs;
12186         char buf[sizeof(*attrs) + 64];
12187         enum lfs_som_type type = LFS_SOM_ATTR_ALL;
12188         int rc = 0, c;
12189
12190         while ((c = getopt(argc, argv, "bfhs")) != -1) {
12191                 switch (c) {
12192                 case 'b':
12193                         type = LFS_SOM_BLOCKS;
12194                         break;
12195                 case 'f':
12196                         type = LFS_SOM_FLAGS;
12197                         break;
12198                 case 's':
12199                         type = LFS_SOM_SIZE;
12200                         break;
12201                 default:
12202                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12203                                 progname, argv[optind - 1]);
12204                         /* fallthrough */
12205                 case 'h':
12206                         return CMD_HELP;
12207                 }
12208         }
12209
12210         argc -= optind;
12211         argv += optind;
12212
12213         if (argc != 1) {
12214                 fprintf(stderr, "%s: %s\n",
12215                         progname, argc == 0 ? "miss file target" :
12216                         "input more than 2 files");
12217                 return CMD_HELP;
12218         }
12219
12220         path = argv[0];
12221         attrs = (void *)buf;
12222         rc = lgetxattr(path, "trusted.som", attrs, sizeof(buf));
12223         if (rc < 0) {
12224                 rc = -errno;
12225                 fprintf(stderr, "%s failed to get som xattr: %s (%d)\n",
12226                         argv[0], strerror(errno), errno);
12227                 return rc;
12228         }
12229
12230         lustre_som_swab(attrs);
12231
12232         switch (type) {
12233         case LFS_SOM_ATTR_ALL:
12234                 printf("file: %s size: %llu blocks: %llu flags: %x\n",
12235                        path, (unsigned long long)attrs->lsa_size,
12236                        (unsigned long long)attrs->lsa_blocks,
12237                        attrs->lsa_valid);
12238                 break;
12239         case LFS_SOM_SIZE:
12240                 printf("%llu\n", (unsigned long long)attrs->lsa_size);
12241                 break;
12242         case LFS_SOM_BLOCKS:
12243                 printf("%llu\n", (unsigned long long)attrs->lsa_blocks);
12244                 break;
12245         case LFS_SOM_FLAGS:
12246                 printf("%x\n", attrs->lsa_valid);
12247                 break;
12248         default:
12249                 fprintf(stderr, "%s: unknown option\n", progname);
12250                 return CMD_HELP;
12251         }
12252
12253         return 0;
12254 }
12255
12256 /**
12257  * lfs_mirror_list_commands() - List lfs mirror commands.
12258  * @argc: The count of command line arguments.
12259  * @argv: Array of strings for command line arguments.
12260  *
12261  * This function lists lfs mirror commands defined in mirror_cmdlist[].
12262  *
12263  * Return: 0 on success.
12264  */
12265 static int lfs_mirror_list_commands(int argc, char **argv)
12266 {
12267         char buffer[81] = "";
12268
12269         Parser_list_commands(mirror_cmdlist, buffer, sizeof(buffer),
12270                              NULL, 0, 4);
12271
12272         return 0;
12273 }
12274
12275 static int lfs_pcc_attach(int argc, char **argv)
12276 {
12277         struct option long_opts[] = {
12278         { .val = 'h',   .name = "help", .has_arg = no_argument },
12279         { .val = 'i',   .name = "id",   .has_arg = required_argument },
12280         { .name = NULL } };
12281         int c;
12282         int rc = 0;
12283         __u32 archive_id = 0;
12284         const char *path;
12285         char *end;
12286         char fullpath[PATH_MAX];
12287         enum lu_pcc_type type = LU_PCC_READWRITE;
12288
12289         optind = 0;
12290         while ((c = getopt_long(argc, argv, "hi:",
12291                                 long_opts, NULL)) != -1) {
12292                 switch (c) {
12293                 case 'i':
12294                         errno = 0;
12295                         archive_id = strtoul(optarg, &end, 0);
12296                         if (errno != 0 || *end != '\0' ||
12297                             archive_id == 0 || archive_id > UINT32_MAX) {
12298                                 fprintf(stderr,
12299                                         "error: %s: bad archive ID '%s'\n",
12300                                         progname, optarg);
12301                                 return CMD_HELP;
12302                         }
12303                         break;
12304                 default:
12305                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12306                                 progname, argv[optind - 1]);
12307                         /* fallthrough */
12308                 case 'h':
12309                         return CMD_HELP;
12310                 }
12311         }
12312
12313         if (archive_id == 0) {
12314                 fprintf(stderr, "%s: must specify attach ID\n", argv[0]);
12315                 return CMD_HELP;
12316         }
12317
12318         if (argc <= optind) {
12319                 fprintf(stderr, "%s: must specify one or more file names\n",
12320                         argv[0]);
12321                 return CMD_HELP;
12322         }
12323
12324         while (optind < argc) {
12325                 int rc2;
12326
12327                 path = argv[optind++];
12328                 if (!realpath(path, fullpath)) {
12329                         fprintf(stderr, "%s: could not find path '%s': %s\n",
12330                                 argv[0], path, strerror(errno));
12331                         if (rc == 0)
12332                                 rc = -EINVAL;
12333                         continue;
12334                 }
12335
12336                 rc2 = llapi_pcc_attach(fullpath, archive_id, type);
12337                 if (rc2 < 0) {
12338                         fprintf(stderr,
12339                                 "%s: cannot attach '%s' to PCC with archive ID '%u': %s\n",
12340                                 argv[0], path, archive_id, strerror(-rc2));
12341                         if (rc == 0)
12342                                 rc = rc2;
12343                 }
12344         }
12345         return rc;
12346 }
12347
12348 static int lfs_pcc_attach_fid(int argc, char **argv)
12349 {
12350         struct option long_opts[] = {
12351         { .val = 'h',   .name = "help", .has_arg = no_argument },
12352         { .val = 'i',   .name = "id",   .has_arg = required_argument },
12353         { .val = 'm',   .name = "mnt",  .has_arg = required_argument },
12354         { .name = NULL } };
12355         int c;
12356         int rc = 0;
12357         __u32 archive_id = 0;
12358         char *end;
12359         const char *mntpath = NULL;
12360         const char *fidstr;
12361         enum lu_pcc_type type = LU_PCC_READWRITE;
12362
12363         optind = 0;
12364         while ((c = getopt_long(argc, argv, "hi:m:",
12365                                 long_opts, NULL)) != -1) {
12366                 switch (c) {
12367                 case 'i':
12368                         errno = 0;
12369                         archive_id = strtoul(optarg, &end, 0);
12370                         if (errno != 0 || *end != '\0' ||
12371                             archive_id > UINT32_MAX) {
12372                                 fprintf(stderr,
12373                                         "error: %s: bad archive ID '%s'\n",
12374                                         argv[0], optarg);
12375                                 return CMD_HELP;
12376                         }
12377                         break;
12378                 case 'm':
12379                         mntpath = optarg;
12380                         break;
12381                 default:
12382                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12383                                 progname, argv[optind - 1]);
12384                         /* fallthrough */
12385                 case 'h':
12386                         return CMD_HELP;
12387                 }
12388         }
12389
12390         if (archive_id == 0) {
12391                 fprintf(stderr, "%s: must specify an archive ID\n", argv[0]);
12392                 return CMD_HELP;
12393         }
12394
12395         if (!mntpath) {
12396                 fprintf(stderr, "%s: must specify Lustre mount point\n",
12397                         argv[0]);
12398                 return CMD_HELP;
12399         }
12400
12401         if (argc <= optind) {
12402                 fprintf(stderr, "%s: must specify one or more fids\n", argv[0]);
12403                 return CMD_HELP;
12404         }
12405
12406         while (optind < argc) {
12407                 int rc2;
12408
12409                 fidstr = argv[optind++];
12410
12411                 rc2 = llapi_pcc_attach_fid_str(mntpath, fidstr,
12412                                                archive_id, type);
12413                 if (rc2 < 0) {
12414                         fprintf(stderr,
12415                                 "%s: cannot attach '%s' on '%s' to PCC with archive ID '%u': %s\n",
12416                                 argv[0], fidstr, mntpath, archive_id,
12417                                 strerror(rc2));
12418                 }
12419                 if (rc == 0 && rc2 < 0)
12420                         rc = rc2;
12421         }
12422         return rc;
12423 }
12424
12425 static int lfs_pcc_detach(int argc, char **argv)
12426 {
12427         struct option long_opts[] = {
12428         { .val = 'h',   .name = "help", .has_arg = no_argument },
12429         { .val = 'k',   .name = "keep", .has_arg = no_argument },
12430         { .name = NULL } };
12431         int c;
12432         int rc = 0;
12433         const char *path;
12434         char fullpath[PATH_MAX];
12435         __u32 detach_opt = PCC_DETACH_OPT_UNCACHE;
12436
12437         optind = 0;
12438         while ((c = getopt_long(argc, argv, "hk",
12439                                 long_opts, NULL)) != -1) {
12440                 switch (c) {
12441                 case 'k':
12442                         detach_opt = PCC_DETACH_OPT_NONE;
12443                         break;
12444                 default:
12445                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12446                                 progname, argv[optind - 1]);
12447                         /* fallthrough */
12448                 case 'h':
12449                         return CMD_HELP;
12450                 }
12451         }
12452
12453         while (optind < argc) {
12454                 int rc2;
12455
12456                 path = argv[optind++];
12457                 if (!realpath(path, fullpath)) {
12458                         fprintf(stderr, "%s: could not find path '%s': %s\n",
12459                                 argv[0], path, strerror(errno));
12460                         if (rc == 0)
12461                                 rc = -EINVAL;
12462                         continue;
12463                 }
12464
12465                 rc2 = llapi_pcc_detach_file(fullpath, detach_opt);
12466                 if (rc2 < 0) {
12467                         rc2 = -errno;
12468                         fprintf(stderr,
12469                                 "%s: cannot detach '%s' from PCC: %s\n",
12470                                 argv[0], path, strerror(errno));
12471                         if (rc == 0)
12472                                 rc = rc2;
12473                 }
12474         }
12475         return rc;
12476 }
12477
12478 static int lfs_pcc_detach_fid(int argc, char **argv)
12479 {
12480         struct option long_opts[] = {
12481         { .val = 'h',   .name = "help", .has_arg = no_argument },
12482         { .val = 'k',   .name = "keep", .has_arg = no_argument },
12483         { .name = NULL } };
12484         int c;
12485         int rc = 0;
12486         const char *fid;
12487         const char *mntpath;
12488         __u32 detach_opt = PCC_DETACH_OPT_UNCACHE;
12489
12490         optind = 0;
12491         while ((c = getopt_long(argc, argv, "hk",
12492                                 long_opts, NULL)) != -1) {
12493                 switch (c) {
12494                 case 'k':
12495                         detach_opt = PCC_DETACH_OPT_NONE;
12496                         break;
12497                 default:
12498                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12499                                 progname, argv[optind - 1]);
12500                         /* fallthrough */
12501                 case 'h':
12502                         return CMD_HELP;
12503                 }
12504         }
12505
12506         mntpath = argv[optind++];
12507
12508         while (optind < argc) {
12509                 int rc2;
12510
12511                 fid = argv[optind++];
12512
12513                 rc2 = llapi_pcc_detach_fid_str(mntpath, fid, detach_opt);
12514                 if (rc2 < 0) {
12515                         fprintf(stderr,
12516                                 "%s: cannot detach '%s' on '%s' from PCC: %s\n",
12517                                 argv[0], fid, mntpath, strerror(-rc2));
12518                         if (rc == 0)
12519                                 rc = rc2;
12520                 }
12521         }
12522         return rc;
12523 }
12524
12525 static int lfs_pcc_state(int argc, char **argv)
12526 {
12527         int rc = 0;
12528         const char *path;
12529         char fullpath[PATH_MAX];
12530         struct lu_pcc_state state;
12531
12532         optind = 1;
12533
12534         if (argc <= 1) {
12535                 fprintf(stderr, "%s: must specify one or more file names\n",
12536                         progname);
12537                 return CMD_HELP;
12538         }
12539
12540         while (optind < argc) {
12541                 int rc2;
12542
12543                 path = argv[optind++];
12544                 if (!realpath(path, fullpath)) {
12545                         fprintf(stderr, "%s: could not find path '%s': %s\n",
12546                                 argv[0], path, strerror(errno));
12547                         if (rc == 0)
12548                                 rc = -EINVAL;
12549                         continue;
12550                 }
12551
12552                 rc2 = llapi_pcc_state_get(fullpath, &state);
12553                 if (rc2 < 0) {
12554                         if (rc == 0)
12555                                 rc = rc2;
12556                         fprintf(stderr,
12557                                 "%s: cannot get PCC state of '%s': %s\n",
12558                                 argv[0], path, strerror(-rc2));
12559                         continue;
12560                 }
12561
12562                 printf("file: %s", path);
12563                 printf(", type: %s", pcc_type2string(state.pccs_type));
12564                 if (state.pccs_type == LU_PCC_NONE &&
12565                     state.pccs_open_count == 0) {
12566                         printf("\n");
12567                         continue;
12568                 }
12569
12570                 printf(", PCC file: %s", state.pccs_path);
12571                 printf(", user number: %u", state.pccs_open_count);
12572                 printf(", flags: %x", state.pccs_flags);
12573                 printf("\n");
12574         }
12575         return rc;
12576 }
12577
12578 /**
12579  * lfs_pcc_list_commands() - List lfs pcc commands.
12580  * @argc: The count of command line arguments.
12581  * @argv: Array of strings for command line arguments.
12582  *
12583  * This function lists lfs pcc commands defined in pcc_cmdlist[].
12584  *
12585  * Return: 0 on success.
12586  */
12587 static int lfs_pcc_list_commands(int argc, char **argv)
12588 {
12589         char buffer[81] = "";
12590
12591         Parser_list_commands(pcc_cmdlist, buffer, sizeof(buffer),
12592                              NULL, 0, 4);
12593
12594         return 0;
12595 }
12596
12597 /**
12598  * lfs_pcc() - Parse and execute lfs pcc commands.
12599  * @argc: The count of lfs pcc command line arguments.
12600  * @argv: Array of strings for lfs pcc command line arguments.
12601  *
12602  * This function parses lfs pcc commands and performs the
12603  * corresponding functions specified in pcc_cmdlist[].
12604  *
12605  * Return: 0 on success or an error code on failure.
12606  */
12607 static int lfs_pcc(int argc, char **argv)
12608 {
12609         char cmd[PATH_MAX];
12610         int rc = 0;
12611
12612         setlinebuf(stdout);
12613
12614         Parser_init("lfs-pcc > ", pcc_cmdlist);
12615
12616         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12617         progname = cmd;
12618         program_invocation_short_name = cmd;
12619         if (argc > 1)
12620                 rc = Parser_execarg(argc - 1, argv + 1, pcc_cmdlist);
12621         else
12622                 rc = Parser_commands();
12623
12624         return rc < 0 ? -rc : rc;
12625 }
12626
12627 static int lfs_list_commands(int argc, char **argv)
12628 {
12629         char buffer[81] = ""; /* 80 printable chars + terminating NUL */
12630
12631         Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
12632
12633         return 0;
12634 }
12635
12636 int main(int argc, char **argv)
12637 {
12638         int rc;
12639
12640         /* Ensure that liblustreapi constructor has run */
12641         if (!llapi_liblustreapi_initialized())
12642                 fprintf(stderr, "liblustreapi was not properly initialized\n");
12643
12644         setlinebuf(stdout);
12645         opterr = 0;
12646
12647         Parser_init("lfs > ", cmdlist);
12648
12649         progname = program_invocation_short_name; /* Used in error messages */
12650         if (argc > 1) {
12651                 llapi_set_command_name(argv[1]);
12652                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
12653                 llapi_clear_command_name();
12654         } else {
12655                 rc = Parser_commands();
12656         }
12657
12658         return rc < 0 ? -rc : rc;
12659 }
12660
12661 #ifdef _LUSTRE_IDL_H_
12662 /* Everything we need here should be included by lustreapi.h. */
12663 # error "lfs should not depend on lustre_idl.h"
12664 #endif /* _LUSTRE_IDL_H_ */