Whamcloud - gitweb
45669942f9dbe73bcdb53e7b3c9bb312e37cd765
[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 #include <uapi/linux/lustre/lustre_idl.h>
81
82 #ifndef NSEC_PER_SEC
83 # define NSEC_PER_SEC 1000000000UL
84 #endif
85 #define ONE_MB 0x100000
86
87 /* all functions */
88 static int lfs_find(int argc, char **argv);
89 static int lfs_getstripe(int argc, char **argv);
90 static int lfs_getdirstripe(int argc, char **argv);
91 static int lfs_setdirstripe(int argc, char **argv);
92 static int lfs_rmentry(int argc, char **argv);
93 static int lfs_unlink_foreign(int argc, char **argv);
94 static int lfs_osts(int argc, char **argv);
95 static int lfs_mdts(int argc, char **argv);
96 static int lfs_df(int argc, char **argv);
97 static int lfs_getname(int argc, char **argv);
98 static int lfs_check(int argc, char **argv);
99 #ifdef HAVE_SYS_QUOTA_H
100 static int lfs_setquota(int argc, char **argv);
101 static int lfs_quota(int argc, char **argv);
102 static int lfs_project(int argc, char **argv);
103 #endif
104 static int lfs_flushctx(int argc, char **argv);
105 static int lfs_poollist(int argc, char **argv);
106 static int lfs_changelog(int argc, char **argv);
107 static int lfs_changelog_clear(int argc, char **argv);
108 static int lfs_fid2path(int argc, char **argv);
109 static int lfs_path2fid(int argc, char **argv);
110 static int lfs_rmfid(int argc, char **argv);
111 static int lfs_data_version(int argc, char **argv);
112 static int lfs_hsm_state(int argc, char **argv);
113 static int lfs_hsm_set(int argc, char **argv);
114 static int lfs_hsm_clear(int argc, char **argv);
115 static int lfs_hsm_action(int argc, char **argv);
116 static int lfs_hsm_archive(int argc, char **argv);
117 static int lfs_hsm_restore(int argc, char **argv);
118 static int lfs_hsm_release(int argc, char **argv);
119 static int lfs_hsm_remove(int argc, char **argv);
120 static int lfs_hsm_cancel(int argc, char **argv);
121 static int lfs_swap_layouts(int argc, char **argv);
122 static int lfs_mv(int argc, char **argv);
123 static int lfs_ladvise(int argc, char **argv);
124 static int lfs_getsom(int argc, char **argv);
125 static int lfs_heat_get(int argc, char **argv);
126 static int lfs_heat_set(int argc, char **argv);
127 static int lfs_mirror(int argc, char **argv);
128 static inline int lfs_mirror_resync(int argc, char **argv);
129 static inline int lfs_mirror_verify(int argc, char **argv);
130 static inline int lfs_mirror_read(int argc, char **argv);
131 static inline int lfs_mirror_write(int argc, char **argv);
132 static inline int lfs_mirror_copy(int argc, char **argv);
133 static int lfs_pcc_attach(int argc, char **argv);
134 static int lfs_pcc_attach_fid(int argc, char **argv);
135 static int lfs_pcc_detach(int argc, char **argv);
136 static int lfs_pcc_detach_fid(int argc, char **argv);
137 static int lfs_pcc_state(int argc, char **argv);
138 static int lfs_pcc(int argc, char **argv);
139
140 static int lfs_migrate_to_dom(int fd_src, int fd_dst, char *name,
141                               __u64 migration_flags,
142                               unsigned long long bandwidth_bytes_sec,
143                               long stats_interval_sec);
144
145 struct pool_to_id_cbdata {
146         const char *pool;
147         __u32 id;
148 };
149
150 static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata);
151 static int find_mirror_id_by_pool(struct llapi_layout *layout, void *cbdata);
152
153 enum setstripe_origin {
154         SO_SETSTRIPE,
155         SO_MIGRATE,
156         SO_MIGRATE_MDT,
157         SO_MIRROR_CREATE,
158         SO_MIRROR_EXTEND,
159         SO_MIRROR_SPLIT,
160         SO_MIRROR_DELETE,
161 };
162
163 static int lfs_setstripe_internal(int argc, char **argv,
164                                   enum setstripe_origin opc);
165
166 static inline int lfs_setstripe(int argc, char **argv)
167 {
168         return lfs_setstripe_internal(argc, argv, SO_SETSTRIPE);
169 }
170
171 static inline int lfs_setstripe_migrate(int argc, char **argv)
172 {
173         return lfs_setstripe_internal(argc, argv, SO_MIGRATE);
174 }
175
176 static inline int lfs_mirror_create(int argc, char **argv)
177 {
178         return lfs_setstripe_internal(argc, argv, SO_MIRROR_CREATE);
179 }
180
181 static inline int lfs_mirror_extend(int argc, char **argv)
182 {
183         return lfs_setstripe_internal(argc, argv, SO_MIRROR_EXTEND);
184 }
185
186 static inline int lfs_mirror_split(int argc, char **argv)
187 {
188         return lfs_setstripe_internal(argc, argv, SO_MIRROR_SPLIT);
189 }
190
191 static inline int lfs_mirror_delete(int argc, char **argv)
192 {
193         return lfs_setstripe_internal(argc, argv, SO_MIRROR_DELETE);
194 }
195
196 /* Setstripe and migrate share mostly the same parameters */
197 #define SSM_CMD_COMMON(cmd) \
198         "usage: "cmd" [--component-end|-E COMP_END]\n"                  \
199         "                 [--copy=LUSTRE_SRC]\n"                        \
200         "                 [--extension-size|--ext-size|-z SIZE]\n"      \
201         "                 [--help|-h] [--layout|-L PATTERN]\n"          \
202         "                 [--layout|-L PATTERN]\n"                      \
203         "                 [--mirror-count|-N[MIRROR_COUNT]]\n"          \
204         "                 [--ost|-o OST_INDICES]\n"                     \
205         "                 [--overstripe-count|-C STRIPE_COUNT]\n"       \
206         "                 [--pool|-p POOL_NAME]\n"                      \
207         "                 [--stripe-count|-c STRIPE_COUNT]\n"           \
208         "                 [--stripe-index|-i START_OST_IDX]\n"          \
209         "                 [--stripe-size|-S STRIPE_SIZE]\n"             \
210         "                 [--yaml|-y YAML_TEMPLATE_FILE]\n"
211
212 /* XXX: A temporary solution for transition to help text update */
213 #define SSM_CMD_COMMON_1(cmd) \
214         "usage: "cmd" [--component-add|--component-del|--delete|-d]\n"  \
215         "                 [--comp-set --comp-id|-I COMP_ID|--comp-flags=COMP_FLAGS]\n"  \
216         "                 [--component-end|-E END_OFFSET]\n"            \
217         "                 [--copy=SOURCE_LAYOUT_FILE]|--yaml|-y YAML_TEMPLATE_FILE]\n"  \
218         "                 [--extension-size|--ext-size|-z EXT_SIZE]\n"  \
219         "                 [--help|-h]\n"                                \
220         "                 [--foreign=FOREIGN_TYPE --xattr|-x LAYOUT]\n" \
221         "                 [--layout|-L PATTERN] [--mode FILE_MODE]\n"   \
222         "                 [--mirror-count|-N[MIRROR_COUNT]]\n"          \
223         "                 [--ost|-o OST_INDEX[,OST_INDEX,...]]\n"       \
224         "                 [--overstripe-count|-C STRIPE_COUNT]\n"       \
225         "                 [--pool|-p POOL_NAME]\n"                      \
226         "                 [--stripe-count|-c STRIPE_COUNT]\n"           \
227         "                 [--stripe-index|-i START_OST_IDX]\n"          \
228         "                 [--stripe-size|-S STRIPE_SIZE]\n"             \
229         "                 FILENAME|DIRECTORY\n"
230
231 #define MIRROR_EXTEND_USAGE                                             \
232         "                 {--mirror-count|-N[MIRROR_COUNT]}\n"          \
233         "                 [SETSTRIPE_OPTIONS|-f|--file VICTIM_FILE]\n"  \
234         "                 [--no-verify]\n"
235
236 #define MIGRATE_USAGE                                                   \
237         SSM_CMD_COMMON("migrate  ")                                     \
238         "                 [--block|-b] [--non-block|-n]\n"              \
239         "                 [--non-direct|-D] [--verbose|-v]\n"           \
240         "                 FILENAME\n"
241
242 #define SETDIRSTRIPE_USAGE                                              \
243         "               [--mdt-count|-c stripe_count>\n"                \
244         "               [--help|-h] [--mdt-hash|-H mdt_hash]\n"         \
245         "               [--mdt-index|-i mdt_index[,mdt_index,...]\n"    \
246         "               [--default|-D] [--mode|-o mode]\n"              \
247         "               [--max-inherit|-X max_inherit]\n"               \
248         "               [--max-inherit-rr max_inherit_rr] <dir>\n"      \
249         "To create dir with a foreign (free format) layout :\n"         \
250         "setdirstripe|mkdir --foreign[=FOREIGN_TYPE] -x|-xattr STRING " \
251         "               [--mode|-o MODE] [--flags HEX] DIRECTORY\n"
252
253 /**
254  * command_t mirror_cmdlist - lfs mirror commands.
255  */
256 command_t mirror_cmdlist[] = {
257         { .pc_name = "create", .pc_func = lfs_mirror_create,
258           .pc_help = "Create a mirrored file.\n"
259                 "usage: lfs mirror create --mirror-count|-N[MIRROR_COUNT]\n"
260                 "           [SETSTRIPE_OPTIONS] ... FILENAME|DIRECTORY ...\n" },
261         { .pc_name = "delete", .pc_func = lfs_mirror_delete,
262           .pc_help = "Delete a mirror from a file.\n"
263         "usage: lfs mirror delete {--mirror-id <mirror_id> |\n"
264         "\t               --component-id|--comp-id|-I COMP_ID |\n"
265         "\t               -p <pool>} MIRRORED_FILE ...\n"
266         },
267         { .pc_name = "extend", .pc_func = lfs_mirror_extend,
268           .pc_help = "Extend a mirrored file.\n"
269                 "usage: lfs mirror extend "
270                 "{--mirror-count|-N[MIRROR_COUNT]} [--no-verify]|\n"
271         "\t\t--stats|--stats-interval=<sec>|\n"
272         "\t\t--W <bandwidth>|--bandwidth-limit=<bandwidth>\n"
273         "\t\t[SETSTRIPE_OPTIONS|-f VICTIM_FILE] ... FILENAME ...\n" },
274         { .pc_name = "split", .pc_func = lfs_mirror_split,
275           .pc_help = "Split a mirrored file.\n"
276         "usage: lfs mirror split {--mirror-id MIRROR_ID |\n"
277         "\t             --component-id|-I COMP_ID|-p POOL} [--destroy|-d]\n"
278         "\t             [-f NEW_FILE] MIRRORED_FILE ...\n" },
279         { .pc_name = "read", .pc_func = lfs_mirror_read,
280           .pc_help = "Read the content of a specified mirror of a file.\n"
281                 "usage: lfs mirror read {--mirror-id|-N MIRROR_ID}\n"
282                 "\t\t[--outfile|-o <output_file>] <mirrored_file>\n" },
283         { .pc_name = "write", .pc_func = lfs_mirror_write,
284           .pc_help = "Write to a specified mirror of a file.\n"
285                 "usage: lfs mirror write {--mirror-id|-N MIRROR_ID}\n"
286                 "\t\t[--inputfile|-i <input_file>] <mirrored_file>\n" },
287         { .pc_name = "copy", .pc_func = lfs_mirror_copy,
288           .pc_help = "Copy a specified mirror to other mirror(s) of a file.\n"
289                 "usage: lfs mirror copy {--read-mirror|-i MIRROR_ID0}\n"
290                 "\t\t{--write-mirror|-o MIRROR_ID1[,...]} <mirrored_file>\n" },
291         { .pc_name = "resync", .pc_func = lfs_mirror_resync,
292           .pc_help = "Resynchronizes out-of-sync mirrored file(s).\n"
293                 "usage: lfs mirror resync [--only MIRROR_ID[,...]>]|\n"
294                 "\t\t--stats|--stats-interval=<sec>|\n"
295                 "\t\t--W <bandwidth>|--bandwidth-limit=<bandwidth>\n"
296                 "\t\t<mirrored_file> [<mirrored_file2>...]\n" },
297         { .pc_name = "verify", .pc_func = lfs_mirror_verify,
298           .pc_help = "Verify mirrored file(s).\n"
299                 "usage: lfs mirror verify [--only MIRROR_ID[,...]]\n"
300                 "\t\t[--verbose|-v] <mirrored_file> [<mirrored_file2> ...]\n" },
301         { .pc_help = NULL }
302 };
303
304 /**
305  * command_t pcc_cmdlist - lfs pcc commands.
306  */
307 command_t pcc_cmdlist[] = {
308         { .pc_name = "attach", .pc_func = lfs_pcc_attach,
309           .pc_help = "Attach given files to the Persistent Client Cache.\n"
310                 "usage: lfs pcc attach <--id|-i NUM> <file> ...\n"
311                 "\t-i: archive id for RW-PCC\n" },
312         { .pc_name = "attach_fid", .pc_func = lfs_pcc_attach_fid,
313           .pc_help = "Attach given files into PCC by FID(s).\n"
314                 "usage: lfs pcc attach_id {--id|-i NUM} {--mnt|-m MOUNTPOINT} FID ...\n"
315                 "\t-i: archive id for RW-PCC\n"
316                 "\t-m: Lustre mount point\n" },
317         { .pc_name = "state", .pc_func = lfs_pcc_state,
318           .pc_help = "Display the PCC state for given files.\n"
319                 "usage: lfs pcc state <file> ...\n" },
320         { .pc_name = "detach", .pc_func = lfs_pcc_detach,
321           .pc_help = "Detach given files from the Persistent Client Cache.\n"
322                 "usage: lfs pcc detach <file> ...\n" },
323         { .pc_name = "detach_fid", .pc_func = lfs_pcc_detach_fid,
324           .pc_help = "Detach given files from PCC by FID(s).\n"
325                 "usage: lfs pcc detach_fid <mntpath> <fid>...\n" },
326         { .pc_help = NULL }
327 };
328
329 /* all available commands */
330 command_t cmdlist[] = {
331         {"setstripe", lfs_setstripe, 0,
332          "Create a file with specified striping/composite layout, or\n"
333          "set the default layout on an existing directory.\n"
334           SSM_CMD_COMMON_1("setstripe")},
335         {"getstripe", lfs_getstripe, 0,
336          "List the layout pattern for a given file or files in a\n"
337          "directory or recursively for all files in a directory tree.\n"
338          "Usage: getstripe [--ost|-O OST_NAME] [--quiet|-q] [--verbose|-v]\n"
339          "                 [--stripe-count|-c] [--stripe-index|-i] [--fid|-F]\n"
340          "                 [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
341          "                 [--mdt-index|-m] [--recursive|-r] [--raw|-R]\n"
342          "                 [--layout|-L] [--generation|-g] [--yaml|-y]\n"
343          "                 [--help|-h] [--hex-idx]\n"
344          "                 [--component-id|-I[=COMP_ID]]\n"
345          "                 [--component-flags[=COMP_FLAGS]]\n"
346          "                 [--component-count]\n"
347          "                 [--extension-size|--ext-size|-z]\n"
348          "                 [--component-start[=[+-]START_OFFSET]]\n"
349          "                 [--component-end|-E[[+-]END_OFFSET]]\n"
350          "                 [[!] --mirror-index=[+-]MIRROR_INDEX |\n"
351          "                 [!] --mirror-id=[+-]MIRROR_ID] [--mirror-count|-N]\n"
352          "                 [--no-follow]\n"
353          "                 FILENAME|DIRECTORY"},
354         {"setdirstripe", lfs_setdirstripe, 0,
355          "Create striped directory on specified MDT, same as mkdir.\n"
356          "May be restricted to root or group users, depending on settings.\n"
357          "usage: setdirstripe [OPTION] <directory>\n"
358          SETDIRSTRIPE_USAGE},
359         {"getdirstripe", lfs_getdirstripe, 0,
360          "To list the layout pattern info for a given directory\n"
361          "or recursively for all directories in a directory tree.\n"
362          "usage: getdirstripe [--mdt-count|-c] [--mdt-index|-m|-i]\n"
363          "                    [--help|-h] [--hex-idx] [--mdt-hash|-H]\n"
364          "                    [--obd|-O UUID] [--recursive|-r] [--raw|-R]\n"
365          "                    [--yaml|-y] [--verbose|-v] [--default|-D]\n"
366          "                    [--max-inherit|-X]\n"
367          "                    [--max-inherit-rr] <dir> ..."},
368         {"mkdir", lfs_setdirstripe, 0,
369          "Create striped directory on specified MDT, same as setdirstripe.\n"
370          "usage: mkdir [OPTION] <directory>\n"
371          SETDIRSTRIPE_USAGE},
372         {"rm_entry", lfs_rmentry, 0,
373          "To remove the name entry of the remote directory. Note: This\n"
374          "command will only delete the name entry, i.e. the remote directory\n"
375          "will become inaccessable after this command. This can only be done\n"
376          "by the administrator\n"
377          "usage: rm_entry <dir>\n"},
378         {"rmentry", lfs_rmentry, 0, "remove a dir entry, same as 'rm_entry'\n"},
379         {"unlink_foreign", lfs_unlink_foreign, 0,
380          "To remove the foreign file/dir.\n"
381          "Note: This is for files/dirs prevented to be removed using\n"
382          "unlink/rmdir, but works also for regular ones\n"
383          "usage: unlink_foreign <foreign_dir/file> [<foreign_dir/file> ...]\n"},
384         {"pool_list", lfs_poollist, 0,
385          "List pools or pool OSTs\n"
386          "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
387         {"find", lfs_find, 0,
388          "find files matching given attributes recursively in directory tree.\n"
389          "usage: find <directory|filename> ...\n"
390          "     [[!] --atime|-A [+-]N[smhdwy]] [[!] --btime|-B [+-]N[smhdwy]]\n"
391          "     [[!] --ctime|-C [+-]N[smhdwy]] [[!] --mtime|-M [+-]N[smhdwy]]\n"
392          "     [[!] --attrs=[^]ATTR[,...]]\n"
393          "     [[!] --blocks|-b N] [[!] --component-count [+-]<comp_cnt>]\n"
394          "     [[!] --component-start [+-]N[kMGTPE]]\n"
395          "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
396          "     [[!] --component-flags {init,stale,prefer,prefrd,prefwr,offline,nosync,extension}]\n"
397          "     [[!] --extension-size|--ext-size|-z [+-]N[kMGT]]\n"
398          "     [[!] --foreign[=<foreign_type>]]\n"
399          "     [[!] --gid|-g|--group|-G <gid>|<gname>] [--help|-h]\n"
400          "     [[!] --layout|-L released,raid0,mdt] [--lazy|-l] [[!] --links [+-]n]\n"
401          "     [--maxdepth|-D N] [[!] --mdt-count|-T [+-]<stripes>]\n"
402          "     [[!] --mdt-hash|-H <[^][blm],[^]fnv_1a_64,all_char,crush,...>\n"
403          "     [[!] --mdt-index|--mdt|-m <uuid|index,...>]\n"
404          "     [[!] --mirror-count|-N [+-]<n>]\n"
405          "     [[!] --mirror-state <[^]state>]\n"
406          "     [[!] --name|-n <pattern>] [[!] --newer[XY] <reference>]\n"
407          "     [[!] --ost|-O <uuid|index,...>] [[!] --perm [/-]mode]\n"
408          "     [[!] --pool <pool>] [--print|-P] [--print0|-0] [--printf <format>]\n"
409          "     [[!] --projid <projid>] [[!] --size|-s [+-]N[bkMGTPE]]\n"
410          "     [[!] --stripe-count|-c [+-]<stripes>]\n"
411          "     [[!] --stripe-index|-i <index,...>]\n"
412          "     [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
413          "     [[!] --uid|-u|--user|-U <uid>|<uname>]\n"
414          "\t !: used before an option indicates 'NOT' requested attribute\n"
415          "\t -: used before a value indicates less than requested value\n"
416          "\t +: used before a value indicates more than requested value\n"
417          "\t ^: used before a flag indicates to exclude it\n"},
418         {"check", lfs_check, 0,
419          "Display the status of MGTs, MDTs or OSTs (as specified in the command)\n"
420          "or all the servers (MGTs, MDTs and OSTs) [for specified path only].\n"
421          "usage: check {mgts|osts|mdts|all} [path]"},
422         {"osts", lfs_osts, 0, "list OSTs connected to client "
423          "[for specified path only]\n" "usage: osts [path]"},
424         {"mdts", lfs_mdts, 0, "list MDTs connected to client "
425          "[for specified path only]\n" "usage: mdts [path]"},
426         {"df", lfs_df, 0,
427          "report filesystem disk space usage or inodes usage "
428          "of each MDS and all OSDs or a batch belonging to a specific pool.\n"
429          "Usage: df [--inodes|-i] [--human-readable|-h] [--lazy|-l]\n"
430          "          [--pool|-p <fsname>[.<pool>]] [path]"},
431         {"getname", lfs_getname, 0,
432          "list instances and specified mount points [for specified path only]\n"
433          "Usage: getname [--help|-h] [--instance|-i] [--fsname|-n] [path ...]"},
434 #ifdef HAVE_SYS_QUOTA_H
435         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
436          "usage: setquota [-t][-D] {-u|-U|-g|-G|-p|-P} {-b|-B|-i|-I LIMIT} [--pool POOL] FILESYSTEM\n"
437          "       setquota {-u|-g|-p} --delete FILESYSTEM\n"},
438         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
439          "usage: quota [-q] [-v] [-h] [-o OBD_UUID|-i MDT_IDX|-I OST_IDX]\n"
440          "             [{-u|-g|-p} UNAME|UID|GNAME|GID|PROJID]\n"
441          "             [--pool <OST pool name>] <filesystem>\n"
442          "       quota -t <-u|-g|-p> [--pool <OST pool name>] <filesystem>\n"
443          "       quota [-q] [-v] [h] {-U|-G|-P} [--pool <OST pool name>] <filesystem>"},
444         {"project", lfs_project, 0,
445          "Change or list project attribute for specified file or directory.\n"
446          "usage: project [-d|-r] <file|directory...>\n"
447          "         list project ID and flags on file(s) or directories\n"
448          "       project [-p id] [-s] [-r] <file|directory...>\n"
449          "         set project ID and/or inherit flag for specified file(s) or directories\n"
450          "       project -c [-d|-r [-p id] [-0]] <file|directory...>\n"
451          "         check project ID and flags on file(s) or directories, print outliers\n"
452          "       project -C [-d|-r] [-k] <file|directory...>\n"
453          "         clear the project inherit flag and ID on the file or directory\n"
454         },
455 #endif
456         {"flushctx", lfs_flushctx, 0,
457          "Flush security context for current user.\n"
458          "usage: flushctx [-k] [-r] [mountpoint...]"},
459         {"changelog", lfs_changelog, 0,
460          "Show the metadata changes on an MDT."
461          "\nusage: changelog <mdtname> [startrec [endrec]]"},
462         {"changelog_clear", lfs_changelog_clear, 0,
463          "Indicate that old changelog records up to <endrec> are no longer of "
464          "interest to consumer <id>, allowing the system to free up space.\n"
465          "An <endrec> of 0 means all records.\n"
466          "usage: changelog_clear <mdtname> <id> <endrec>"},
467         {"fid2path", lfs_fid2path, 0,
468          "Resolve the full path(s) for given FID(s). For a specific hardlink "
469          "specify link number <linkno>.\n"
470          "usage: fid2path [--print0|-0] [--print-fid|-f] [--print-link|-c] "
471          "[--link|-l <linkno>] [--name|-n] <fsname|root> <fid>..."},
472         {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
473          "usage: path2fid [--parents] <path> ..."},
474         {"rmfid", lfs_rmfid, 0, "Remove file(s) by FID(s)\n"
475          "usage: rmfid <fsname|rootpath> <fid> ..."},
476         {"data_version", lfs_data_version, 0, "Display file data version for "
477          "a given path.\n" "usage: data_version [-n|-r|-w] <path>"},
478         {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
479          "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
480         {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
481          "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
482          "[--archived] [--lost] [--archive-id NUM] <file> ..."},
483         {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
484          "files.\n"
485          "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
486          "[--archived] [--lost] <file> ..."},
487         {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
488          "given files.\n" "usage: hsm_action <file> ..."},
489         {"hsm_archive", lfs_hsm_archive, 0,
490          "Archive file to external storage.\n"
491          "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
492          "<file> ..."},
493         {"hsm_restore", lfs_hsm_restore, 0,
494          "Restore file from external storage.\n"
495          "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
496         {"hsm_release", lfs_hsm_release, 0,
497          "Release files from Lustre.\n"
498          "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
499         {"hsm_remove", lfs_hsm_remove, 0,
500          "Remove file copy from external storage.\n"
501          "usage: hsm_remove [--filelist FILELIST] [--data DATA] "
502          "[--archive NUM]\n"
503          "                  (FILE [FILE ...] | "
504          "--mntpath MOUNTPATH FID [FID ...])\n"
505          "\n"
506          "Note: To remove an archived copy of a file already deleted from a "
507          "Lustre FS, the\n"
508          "--mntpath option and a list of FIDs must be specified"
509         },
510         {"hsm_cancel", lfs_hsm_cancel, 0,
511          "Cancel requests related to specified files.\n"
512          "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
513         {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
514          "usage: swap_layouts <path1> <path2>"},
515         {"migrate", lfs_setstripe_migrate, 0,
516          "migrate directories and their inodes between MDTs.\n"
517          "usage: migrate [--mdt-count|-c STRIPE_COUNT] [--directory|-d]\n"
518          "               [--mdt-hash|-H HASH_TYPE]\n"
519          "               [--mdt-index|-m START_MDT_INDEX] [--verbose|-v]\n"
520          "               DIRECTORY\n"
521          "\n"
522          "migrate file objects from one OST layout to another\n"
523          "(may be not safe with concurent writes).\n"
524          MIGRATE_USAGE },
525         {"mv", lfs_mv, 0,
526          "To move directories between MDTs. This command is deprecated, "
527          "use \"migrate\" instead.\n"
528          "usage: mv <directory|filename> [--mdt-index|-m MDT_INDEX] "
529          "[--verbose|-v]\n"},
530         {"ladvise", lfs_ladvise, 0,
531          "Provide servers with advice about access patterns for a file.\n"
532          "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
533          "               [--background|-b] [--unset|-u]\n\n"
534          "               {--end|-e END[kMGT]|--length|-l LENGTH[kMGT]}\n"
535          "               {[--mode|-m [READ,WRITE]}\n"
536          "               <file> ...\n"},
537         {"mirror", lfs_mirror, mirror_cmdlist,
538          "lfs commands used to manage files with mirrored components:\n"
539          "lfs mirror create - create a mirrored file or directory\n"
540          "lfs mirror extend - add mirror(s) to an existing file\n"
541          "lfs mirror split  - split a mirror from an existing mirrored file\n"
542          "lfs mirror resync - resynchronize out-of-sync mirrored file(s)\n"
543          "lfs mirror read   - read a mirror content of a mirrored file\n"
544          "lfs mirror write  - write to a mirror of a mirrored file\n"
545          "lfs mirror copy   - copy a mirror to other mirror(s) of a file\n"
546          "lfs mirror verify - verify mirrored file(s)\n"},
547         {"getsom", lfs_getsom, 0, "To list the SOM info for a given file.\n"
548          "usage: getsom [-s] [-b] [-f] <path>\n"
549          "\t-s: Only show the size value of the SOM data for a given file\n"
550          "\t-b: Only show the blocks value of the SOM data for a given file\n"
551          "\t-f: Only show the flags value of the SOM data for a given file\n"},
552         {"heat_get", lfs_heat_get, 0,
553          "To get heat of files.\n"
554          "usage: heat_get <file> ...\n"},
555         {"heat_set", lfs_heat_set, 0,
556          "To set heat flags of files.\n"
557          "usage: heat_set [--clear|-c] [--off|-o] [--on|-O] <file> ...\n"
558          "\t--clear|-c: Clear file heat for given files\n"
559          "\t--off|-o:   Turn off file heat for given files\n"
560          "\t--on|-O:    Turn on file heat for given files\n"},
561         {"pcc", lfs_pcc, pcc_cmdlist,
562          "lfs commands used to interact with PCC features:\n"
563          "lfs pcc attach - attach given files to Persistent Client Cache\n"
564          "lfs pcc attach_fid - attach given files into PCC by FID(s)\n"
565          "lfs pcc state  - display the PCC state for given files\n"
566          "lfs pcc detach - detach given files from Persistent Client Cache\n"
567          "lfs pcc detach_fid - detach given files from PCC by FID(s)\n"},
568         { 0, 0, 0, NULL }
569 };
570
571 static int check_hashtype(const char *hashtype)
572 {
573         int type_num = atoi(hashtype);
574         int i;
575
576         /* numeric hash type */
577         if (hashtype && lmv_is_known_hash_type(type_num))
578                 return type_num;
579         /* string hash type */
580         for (i = LMV_HASH_TYPE_ALL_CHARS; i < ARRAY_SIZE(mdt_hash_name); i++)
581                 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
582                         return i;
583
584         return 0;
585 }
586
587 static uint32_t check_foreign_type_name(const char *foreign_type_name)
588 {
589         uint32_t i;
590
591         for (i = 0; i < LU_FOREIGN_TYPE_UNKNOWN; i++) {
592                 if (!lu_foreign_types[i].lft_name)
593                         break;
594                 if (strcmp(foreign_type_name,
595                            lu_foreign_types[i].lft_name) == 0)
596                         return lu_foreign_types[i].lft_type;
597         }
598
599         return LU_FOREIGN_TYPE_UNKNOWN;
600 }
601
602 static const char *error_loc = "syserror";
603
604 static int
605 migrate_open_files(const char *name, __u64 migration_flags,
606                    const struct llapi_stripe_param *param,
607                    struct llapi_layout *layout, int *fd_src_ptr,
608                    int *fd_dst_ptr)
609 {
610         int                      fd_src = -1;
611         int                      fd_dst = -1;
612         int                      rflags;
613         int                      mdt_index;
614         int                      random_value;
615         char                     parent[PATH_MAX];
616         char                     volatile_file[PATH_MAX];
617         char                    *ptr;
618         int                      rc;
619         struct stat              st;
620         struct stat              stv;
621
622         if (!param && !layout) {
623                 error_loc = "layout information";
624                 return -EINVAL;
625         }
626
627         /* search for file directory pathname */
628         if (strlen(name) > sizeof(parent) - 1) {
629                 error_loc = "source file name";
630                 return -ERANGE;
631         }
632
633         strncpy(parent, name, sizeof(parent));
634         ptr = strrchr(parent, '/');
635         if (!ptr) {
636                 if (!getcwd(parent, sizeof(parent))) {
637                         error_loc = "getcwd";
638                         return -errno;
639                 }
640         } else {
641                 if (ptr == parent) /* leading '/' */
642                         ptr = parent + 1;
643                 *ptr = '\0';
644         }
645
646         /* even if the file is only read, WR mode is nedeed to allow
647          * layout swap on fd
648          */
649         /* Allow migrating even without the key on encrypted files */
650         rflags = O_RDWR | O_NOATIME | O_CIPHERTEXT;
651         if (!(migration_flags & LLAPI_MIGRATION_NONDIRECT))
652                 rflags |= O_DIRECT;
653 source_open:
654         fd_src = open(name, rflags);
655         if (fd_src < 0) {
656                 /* If encrypted file without the key,
657                  * retry mirror extend in O_DIRECT.
658                  */
659                 if (errno == ENOKEY && !(rflags & O_DIRECT) &&
660                     migration_flags & LLAPI_MIGRATION_MIRROR) {
661                         rflags |= O_DIRECT;
662                         goto source_open;
663                 }
664                 rc = -errno;
665                 error_loc = "cannot open source file";
666                 return rc;
667         }
668
669         rc = llapi_file_fget_mdtidx(fd_src, &mdt_index);
670         if (rc < 0) {
671                 error_loc = "cannot get MDT index";
672                 goto out;
673         }
674
675         do {
676                 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW |
677                         /* Allow migrating without the key on encrypted files */
678                         O_CIPHERTEXT;
679                 mode_t open_mode = S_IRUSR | S_IWUSR;
680
681                 if (rflags & O_DIRECT)
682                         open_flags |= O_DIRECT;
683                 random_value = random();
684                 rc = snprintf(volatile_file, sizeof(volatile_file),
685                               "%s/%s:%.4X:%.4X:fd=%.2d", parent,
686                               LUSTRE_VOLATILE_HDR, mdt_index,
687                               random_value, fd_src);
688                 if (rc >= sizeof(volatile_file)) {
689                         rc = -ENAMETOOLONG;
690                         break;
691                 }
692
693                 /* create, open a volatile file, use caching (ie no directio) */
694                 if (layout) {
695                         /* Returns -1 and sets errno on error: */
696                         fd_dst = llapi_layout_file_open(volatile_file,
697                                                          open_flags, open_mode,
698                                                          layout);
699                         if (fd_dst < 0)
700                                 fd_dst = -errno;
701                 } else {
702                         /* Does the right thing on error: */
703                         fd_dst = llapi_file_open_param(volatile_file,
704                                                         open_flags,
705                                                         open_mode, param);
706                 }
707         } while (fd_dst < 0 && (rc = fd_dst) == -EEXIST);
708
709         if (rc < 0) {
710                 error_loc = "cannot create volatile file";
711                 goto out;
712         }
713
714         /*
715          * In case the MDT does not support creation of volatile files
716          * we should try to unlink it.
717          */
718         (void)unlink(volatile_file);
719
720         /*
721          * Not-owner (root?) special case.
722          * Need to set owner/group of volatile file like original.
723          * This will allow to pass related check during layout_swap.
724          */
725         rc = fstat(fd_src, &st);
726         if (rc != 0) {
727                 rc = -errno;
728                 error_loc = "cannot stat source file";
729                 goto out;
730         }
731
732         rc = fstat(fd_dst, &stv);
733         if (rc != 0) {
734                 rc = -errno;
735                 error_loc = "cannot stat volatile";
736                 goto out;
737         }
738
739         if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
740                 rc = fchown(fd_dst, st.st_uid, st.st_gid);
741                 if (rc != 0) {
742                         rc = -errno;
743                         error_loc = "cannot change ownwership of volatile";
744                         goto out;
745                 }
746         }
747
748 out:
749         if (rc < 0) {
750                 if (fd_src > 0)
751                         close(fd_src);
752                 if (fd_dst > 0)
753                         close(fd_dst);
754         } else {
755                 *fd_src_ptr = fd_src;
756                 *fd_dst_ptr = fd_dst;
757                 error_loc = NULL;
758         }
759         return rc;
760 }
761
762 struct timespec timespec_sub(struct timespec *before, struct timespec *after)
763 {
764         struct timespec ret;
765
766         ret.tv_sec = after->tv_sec - before->tv_sec;
767         if (after->tv_nsec < before->tv_nsec) {
768                 ret.tv_sec--;
769                 ret.tv_nsec = NSEC_PER_SEC + after->tv_nsec - before->tv_nsec;
770         } else {
771                 ret.tv_nsec = after->tv_nsec - before->tv_nsec;
772         }
773
774         return ret;
775 }
776
777 static void stats_log(struct timespec *now, struct timespec *start_time,
778                       ssize_t read_bytes, size_t write_bytes,
779                       off_t file_size_bytes)
780 {
781         struct timespec diff = timespec_sub(start_time, now);
782
783         if (file_size_bytes == 0)
784                 return;
785
786         if (diff.tv_sec == 0 && diff.tv_nsec == 0)
787                 return;
788
789         printf("- { seconds: %li, rmbps: %5.2g, wmbps: %5.2g, copied: %lu, size: %lu, pct: %lu%% }\n",
790                 diff.tv_sec,
791                 (double) read_bytes/((ONE_MB * diff.tv_sec) +
792                         ((ONE_MB * diff.tv_nsec)/NSEC_PER_SEC)),
793                 (double) write_bytes/((ONE_MB * diff.tv_sec) +
794                         ((ONE_MB * diff.tv_nsec)/NSEC_PER_SEC)),
795                 write_bytes/ONE_MB, file_size_bytes/ONE_MB,
796                 ((write_bytes*100)/file_size_bytes));
797 }
798
799 static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int),
800                              unsigned long long bandwidth_bytes_sec,
801                              long stats_interval_sec, off_t file_size_bytes)
802 {
803         struct llapi_layout *layout;
804         size_t buf_size = 64 * ONE_MB;
805         uint64_t stripe_size = ONE_MB;
806         void *buf = NULL;
807         off_t pos = 0;
808         off_t data_end = 0;
809         size_t page_size = sysconf(_SC_PAGESIZE);
810         bool sparse;
811         int rc;
812         size_t write_bytes = 0;
813         ssize_t read_bytes = 0;
814         struct timespec start_time;
815         struct timespec now;
816         struct timespec last_bw_print;
817
818         layout = llapi_layout_get_by_fd(fd_src, 0);
819         if (layout) {
820                 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
821                 if (rc == 0) {
822                         /* We like big bufs */
823                         if (stripe_size > buf_size)
824                                 buf_size = stripe_size;
825                         else
826                                 /* Trim to stripe_size multiple */
827                                 buf_size -= buf_size % stripe_size;
828                 }
829
830                 llapi_layout_free(layout);
831         }
832
833         /* limit transfer size to what can be sent in one second */
834         if (bandwidth_bytes_sec && bandwidth_bytes_sec < buf_size)
835                 buf_size = (bandwidth_bytes_sec + stripe_size - 1) &
836                         ~(stripe_size - 1);
837
838         /* Use a page-aligned buffer for direct I/O */
839         rc = posix_memalign(&buf, page_size, buf_size);
840         if (rc != 0)
841                 return -rc;
842
843         sparse = llapi_file_is_sparse(fd_src);
844         if (sparse) {
845                 rc = ftruncate(fd_dst, pos);
846                 if (rc < 0) {
847                         rc = -errno;
848                         free(buf);
849                         return rc;
850                 }
851         }
852
853         clock_gettime(CLOCK_MONOTONIC, &start_time);
854         now = last_bw_print = start_time;
855
856         while (1) {
857                 off_t data_off;
858                 size_t to_read, to_write;
859                 ssize_t rsize;
860
861                 if (sparse && pos >= data_end) {
862                         size_t data_size;
863
864                         data_off = llapi_data_seek(fd_src, pos, &data_size);
865                         if (data_off < 0) {
866                                 /* Non-fatal, switch to full copy */
867                                 sparse = false;
868                                 continue;
869                         }
870                         /* hole at the end of file, truncate up to it */
871                         if (!data_size) {
872                                 rc = ftruncate(fd_dst, data_off);
873                                 if (rc < 0)
874                                         goto out;
875                         }
876                         pos = data_off & ~(page_size - 1);
877                         data_end = data_off + data_size;
878                         to_read = ((data_end - pos - 1) | (page_size - 1)) + 1;
879                         to_read = MIN(to_read, buf_size);
880                 } else {
881                         to_read = buf_size;
882                 }
883
884                 if (check_file) {
885                         rc = check_file(fd_src);
886                         if (rc < 0)
887                                 goto out;
888                 }
889
890                 rsize = pread(fd_src, buf, to_read, pos);
891                 read_bytes += rsize;
892                 if (rsize < 0) {
893                         rc = -errno;
894                         goto out;
895                 }
896                 /* EOF */
897                 if (rsize == 0)
898                         break;
899
900                 to_write = rsize;
901                 while (to_write > 0) {
902                         unsigned long long write_target;
903                         ssize_t written;
904                         struct timespec diff;
905
906                         written = pwrite(fd_dst, buf, to_write, pos);
907                         if (written < 0) {
908                                 rc = -errno;
909                                 goto out;
910                         }
911                         pos += written;
912                         to_write -= written;
913                         write_bytes += written;
914
915                         if (bandwidth_bytes_sec == 0)
916                                 continue;
917
918                         clock_gettime(CLOCK_MONOTONIC, &now);
919                         diff = timespec_sub(&start_time, &now);
920                         write_target = ((bandwidth_bytes_sec * diff.tv_sec) +
921                                 ((bandwidth_bytes_sec *
922                                 diff.tv_nsec)/NSEC_PER_SEC));
923
924                         if (write_target < write_bytes) {
925                                 unsigned long long excess;
926                                 struct timespec delay = { 0, 0 };
927
928                                 excess = write_bytes - write_target;
929
930                                 if (excess == 0)
931                                         continue;
932
933                                 delay.tv_sec = excess / bandwidth_bytes_sec;
934                                 delay.tv_nsec = (excess % bandwidth_bytes_sec) *
935                                         NSEC_PER_SEC / bandwidth_bytes_sec;
936
937                                 do {
938                                         rc = clock_nanosleep(CLOCK_MONOTONIC, 0,
939                                                              &delay, &delay);
940                                 } while (rc < 0 && errno == EINTR);
941
942                                 if (rc < 0) {
943                                         if (stats_interval_sec)
944                                                 fprintf(stderr,
945                                                         "error %s: delay for bandwidth control failed: %s\n",
946                                                         progname,
947                                                         strerror(-rc));
948                                         rc = 0;
949                                 }
950                         }
951                 }
952
953                 clock_gettime(CLOCK_MONOTONIC, &now);
954                 if (stats_interval_sec && (write_bytes != file_size_bytes) &&
955                         (now.tv_sec >= last_bw_print.tv_sec +
956                         stats_interval_sec)) {
957                         stats_log(&now, &start_time,
958                                   read_bytes, write_bytes,
959                                   file_size_bytes);
960                         last_bw_print = now;
961                 }
962
963                 if (rc || rsize < to_read)
964                         break;
965         }
966
967         /* Output at least one log, regardless of stats_interval */
968         if (stats_interval_sec) {
969                 clock_gettime(CLOCK_MONOTONIC, &now);
970                 stats_log(&now, &start_time, read_bytes, write_bytes,
971                           file_size_bytes);
972         }
973
974         rc = fsync(fd_dst);
975         if (rc < 0)
976                 rc = -errno;
977 out:
978         /* Try to avoid page cache pollution after migration. */
979         (void)posix_fadvise(fd_src, 0, 0, POSIX_FADV_DONTNEED);
980         (void)posix_fadvise(fd_dst, 0, 0, POSIX_FADV_DONTNEED);
981
982         free(buf);
983         return rc;
984 }
985
986 static int migrate_set_timestamps(int fd, const struct stat *st)
987 {
988         struct timeval tv[2] = {
989                 {.tv_sec = st->st_atime},
990                 {.tv_sec = st->st_mtime}
991         };
992
993         return futimes(fd, tv);
994 }
995
996 static int migrate_block(int fd_src, int fd_dst,
997                          unsigned long long bandwidth_bytes_sec,
998                          long stats_interval_sec)
999 {
1000         struct stat st;
1001         __u64   dv1;
1002         int     gid;
1003         int     rc;
1004         int     rc2;
1005
1006         do
1007                 gid = random();
1008         while (gid == 0);
1009
1010
1011         /* The grouplock blocks all concurrent accesses to the file. */
1012         rc = llapi_group_lock(fd_src, gid);
1013         if (rc < 0) {
1014                 error_loc = "cannot get group lock";
1015                 return rc;
1016         }
1017
1018         rc = fstat(fd_src, &st);
1019         if (rc < 0) {
1020                 error_loc = "cannot stat source file";
1021                 rc = -errno;
1022                 goto out_unlock;
1023         }
1024
1025         /*
1026          * LL_DV_RD_FLUSH should not be set, otherwise the servers will try to
1027          * get extent locks on the OST objects. This will conflict with our
1028          * extent group locks.
1029          */
1030         rc = llapi_get_data_version(fd_src, &dv1, 0);
1031         if (rc < 0) {
1032                 error_loc = "cannot get dataversion";
1033                 goto out_unlock;
1034         }
1035
1036         rc = migrate_copy_data(fd_src, fd_dst, NULL, bandwidth_bytes_sec,
1037                                stats_interval_sec, st.st_size);
1038         if (rc < 0) {
1039                 error_loc = "data copy failed";
1040                 goto out_unlock;
1041         }
1042
1043         /* Make sure we keep original atime/mtime values */
1044         rc = migrate_set_timestamps(fd_dst, &st);
1045         if (rc < 0) {
1046                 error_loc = "set target file timestamp failed";
1047                 goto out_unlock;
1048         }
1049
1050         /*
1051          * swap layouts
1052          * for a migration we need to check data version on file did
1053          * not change.
1054          *
1055          * Pass in gid=0 since we already own grouplock.
1056          */
1057         rc = llapi_fswap_layouts_grouplock(fd_src, fd_dst, dv1, 0, 0,
1058                                            SWAP_LAYOUTS_CHECK_DV1);
1059         if (rc == -EAGAIN) {
1060                 error_loc = "file changed";
1061                 goto out_unlock;
1062         } else if (rc < 0) {
1063                 error_loc = "cannot swap layout";
1064                 goto out_unlock;
1065         }
1066
1067 out_unlock:
1068         rc2 = llapi_group_unlock(fd_src, gid);
1069         if (rc2 < 0 && rc == 0) {
1070                 error_loc = "unlock group lock";
1071                 rc = rc2;
1072         }
1073
1074         return rc;
1075 }
1076
1077 /**
1078  * Internal helper for migrate_copy_data(). Check lease and report error if
1079  * need be.
1080  *
1081  * \param[in]  fd           File descriptor on which to check the lease.
1082  *
1083  * \retval 0       Migration can keep on going.
1084  * \retval -errno  Error occurred, abort migration.
1085  */
1086 static int check_lease(int fd)
1087 {
1088         int rc;
1089
1090         rc = llapi_lease_check(fd);
1091         if (rc > 0)
1092                 return 0; /* llapi_check_lease returns > 0 on success. */
1093
1094         return -EBUSY;
1095 }
1096
1097 static int migrate_nonblock(int fd_src, int fd_dst,
1098                             unsigned long long bandwidth_bytes_sec,
1099                             long stats_interval_sec)
1100 {
1101         struct stat st;
1102         __u64   dv1;
1103         __u64   dv2;
1104         int     rc;
1105
1106         rc = fstat(fd_src, &st);
1107         if (rc < 0) {
1108                 error_loc = "cannot stat source file";
1109                 return -errno;
1110         }
1111
1112         rc = llapi_get_data_version(fd_src, &dv1, LL_DV_RD_FLUSH);
1113         if (rc < 0) {
1114                 error_loc = "cannot get data version";
1115                 return rc;
1116         }
1117
1118         rc = migrate_copy_data(fd_src, fd_dst, check_lease,
1119                                bandwidth_bytes_sec,
1120                                stats_interval_sec, st.st_size);
1121         if (rc < 0) {
1122                 error_loc = "data copy failed";
1123                 return rc;
1124         }
1125
1126         rc = llapi_get_data_version(fd_src, &dv2, LL_DV_RD_FLUSH);
1127         if (rc != 0) {
1128                 error_loc = "cannot get data version";
1129                 return rc;
1130         }
1131
1132         if (dv1 != dv2) {
1133                 rc = -EAGAIN;
1134                 error_loc = "source file changed";
1135                 return rc;
1136         }
1137
1138         /* Make sure we keep original atime/mtime values */
1139         rc = migrate_set_timestamps(fd_dst, &st);
1140         if (rc < 0) {
1141                 error_loc = "set target file timestamp failed";
1142                 return -errno;
1143         }
1144         return 0;
1145 }
1146
1147 static
1148 int lfs_layout_compid_by_pool(char *fname, const char *pool, int *comp_id)
1149 {
1150         struct pool_to_id_cbdata data = { .pool = pool };
1151         struct llapi_layout *layout = NULL;
1152         int rc;
1153
1154         layout = llapi_layout_get_by_path(fname, 0);
1155         if (!layout) {
1156                 fprintf(stderr,
1157                         "error %s: file '%s' couldn't get layout: rc=%d\n",
1158                         progname, fname, errno);
1159                 rc = -errno;
1160                 goto free_layout;
1161         }
1162         rc = llapi_layout_sanity(layout, false, true);
1163         if (rc < 0) {
1164                 llapi_layout_sanity_perror(errno);
1165                 goto free_layout;
1166         }
1167         rc = llapi_layout_comp_iterate(layout, find_comp_id_by_pool, &data);
1168         if (rc < 0)
1169                 goto free_layout;
1170
1171         *comp_id = data.id;
1172         rc = 0;
1173
1174 free_layout:
1175         if (layout)
1176                 llapi_layout_free(layout);
1177         return rc;
1178 }
1179
1180 static int lfs_component_set(char *fname, int comp_id, const char *pool,
1181                              __u32 flags, __u32 neg_flags)
1182 {
1183         __u32 ids[2];
1184         __u32 flags_array[2];
1185         size_t count = 0;
1186         int rc;
1187
1188         if (!comp_id) {
1189                 if (pool == NULL) {
1190                         fprintf(stderr,
1191                                 "error %s: neither component id nor pool is specified\n",
1192                                 progname);
1193                         return -EINVAL;
1194                 }
1195                 rc = lfs_layout_compid_by_pool(fname, pool, &comp_id);
1196                 if (rc)
1197                         return rc;
1198         }
1199
1200         if (flags) {
1201                 ids[count] = comp_id;
1202                 flags_array[count] = flags;
1203                 ++count;
1204         }
1205
1206         if (neg_flags) {
1207                 if (neg_flags & LCME_FL_STALE) {
1208                         fprintf(stderr,
1209                                 "%s: cannot clear 'stale' flags from component. Please use lfs-mirror-resync(1) instead\n",
1210                                 progname);
1211                         return -EINVAL;
1212                 }
1213
1214                 ids[count] = comp_id;
1215                 flags_array[count] = neg_flags | LCME_FL_NEG;
1216                 ++count;
1217         }
1218
1219         rc = llapi_layout_file_comp_set(fname, ids, flags_array, count);
1220         if (rc) {
1221                 if (errno == EUCLEAN) {
1222                         rc = -errno;
1223                         fprintf(stderr,
1224                                 "%s: cannot set 'stale' flag on component '%#x' of the last non-stale mirror of '%s'\n",
1225                                 progname, comp_id, fname);
1226                 } else {
1227                         fprintf(stderr,
1228                                 "%s: cannot change the flags of component '%#x' of file '%s': %x / ^(%x)\n",
1229                                 progname, comp_id, fname, flags, neg_flags);
1230                 }
1231         }
1232
1233         return rc;
1234 }
1235
1236 static int lfs_component_del(char *fname, __u32 comp_id,
1237                              __u32 flags, __u32 neg_flags)
1238 {
1239         int     rc = 0;
1240
1241         if (flags && neg_flags) {
1242                 fprintf(stderr,
1243                         "%s: cannot specify both positive and negative flags\n",
1244                         progname);
1245                 return -EINVAL;
1246         }
1247
1248         if (!flags && neg_flags)
1249                 flags = neg_flags | LCME_FL_NEG;
1250
1251         if (flags && comp_id) {
1252                 fprintf(stderr,
1253                         "%s: cannot specify component ID and flags at the same time\n",
1254                         progname);
1255                 return -EINVAL;
1256         }
1257
1258         if (!flags && !comp_id) {
1259                 fprintf(stderr,
1260                         "%s: neither flags nor component ID is specified\n",
1261                         progname);
1262                 return -EINVAL;
1263         }
1264
1265         if (flags) {
1266                 if (flags & ~LCME_KNOWN_FLAGS) {
1267                         fprintf(stderr,
1268                                 "%s setstripe: unknown flags %#x\n",
1269                                 progname, flags);
1270                         return -EINVAL;
1271                 }
1272         } else if (comp_id > LCME_ID_MAX) {
1273                 fprintf(stderr, "%s setstripe: invalid component id %u\n",
1274                         progname, comp_id);
1275                 return -EINVAL;
1276         }
1277
1278         rc = llapi_layout_file_comp_del(fname, comp_id, flags);
1279         if (rc)
1280                 fprintf(stderr,
1281                         "%s setstripe: cannot delete component %#x from '%s': %s\n",
1282                         progname, comp_id, fname, strerror(errno));
1283         return rc;
1284 }
1285
1286 static int lfs_component_add(char *fname, struct llapi_layout *layout)
1287 {
1288         int     rc;
1289
1290         if (!layout)
1291                 return -EINVAL;
1292
1293         rc = llapi_layout_file_comp_add(fname, layout);
1294         if (rc)
1295                 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
1296                         fname, strerror(errno));
1297         return rc;
1298 }
1299
1300 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
1301                                 struct llapi_layout *layout)
1302 {
1303         struct stat     st;
1304         int     fd;
1305
1306         if (!layout)
1307                 return -EINVAL;
1308
1309         fd = lstat(fname, &st);
1310         if (fd == 0 && S_ISDIR(st.st_mode))
1311                 open_flags = O_DIRECTORY | O_RDONLY;
1312
1313         fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
1314         if (fd < 0)
1315                 fprintf(stderr, "%s: cannot %s '%s': %s\n", progname,
1316                         S_ISDIR(st.st_mode) ?
1317                                 "set default composite layout for" :
1318                                 "create composite file",
1319                         fname, strerror(errno));
1320         return fd;
1321 }
1322
1323 static int lfs_migrate(char *name, __u64 migration_flags,
1324                         struct llapi_stripe_param *param,
1325                         struct llapi_layout *layout,
1326                         unsigned long long bandwidth_bytes_sec,
1327                         long stats_interval_sec)
1328 {
1329         struct llapi_layout *existing;
1330         uint64_t dom_new, dom_cur;
1331         int fd_src = -1;
1332         int fd_dst = -1;
1333         int rc;
1334
1335         rc = migrate_open_files(name, migration_flags, param, layout,
1336                                 &fd_src, &fd_dst);
1337         if (rc < 0)
1338                 goto out;
1339
1340         rc = llapi_layout_dom_size(layout, &dom_new);
1341         if (rc) {
1342                 error_loc = "cannot get new layout DoM size";
1343                 goto out;
1344         }
1345         /* special case for migration to DOM layout*/
1346         existing = llapi_layout_get_by_fd(fd_src, 0);
1347         if (!existing) {
1348                 error_loc = "cannot get existing layout";
1349                 goto out;
1350         }
1351
1352         rc = llapi_layout_dom_size(existing, &dom_cur);
1353         if (rc) {
1354                 error_loc = "cannot get current layout DoM size";
1355                 goto out;
1356         }
1357
1358         /*
1359          * if file has DoM layout already then migration is possible to
1360          * the new layout with the same DoM component via swap layout,
1361          * if new layout used bigger DOM size, then mirroring is used
1362          */
1363         if (dom_new > dom_cur) {
1364                 rc = lfs_migrate_to_dom(fd_src, fd_dst, name,
1365                                         migration_flags,
1366                                         bandwidth_bytes_sec,
1367                                         stats_interval_sec);
1368                 if (rc)
1369                         error_loc = "cannot migrate to DOM layout";
1370                 goto out_closed;
1371         }
1372
1373         if (stats_interval_sec)
1374                 printf("%s:\n", name);
1375
1376         if (!(migration_flags & LLAPI_MIGRATION_NONBLOCK)) {
1377                 /*
1378                  * Blocking mode (forced if servers do not support file lease).
1379                  * It is also the default mode, since we cannot distinguish
1380                  * between a broken lease and a server that does not support
1381                  * atomic swap/close (LU-6785)
1382                  */
1383                 rc = migrate_block(fd_src, fd_dst, bandwidth_bytes_sec,
1384                                    stats_interval_sec);
1385                 goto out;
1386         }
1387
1388         rc = llapi_lease_acquire(fd_src, LL_LEASE_RDLCK);
1389         if (rc < 0) {
1390                 error_loc = "cannot get lease";
1391                 goto out;
1392         }
1393
1394         rc = migrate_nonblock(fd_src, fd_dst, bandwidth_bytes_sec,
1395                               stats_interval_sec);
1396         if (rc < 0) {
1397                 llapi_lease_release(fd_src);
1398                 goto out;
1399         }
1400
1401         /*
1402          * Atomically put lease, swap layouts and close.
1403          * for a migration we need to check data version on file did
1404          * not change.
1405          */
1406         rc = llapi_fswap_layouts(fd_src, fd_dst, 0, 0, SWAP_LAYOUTS_CLOSE);
1407         if (rc < 0) {
1408                 error_loc = "cannot swap layout";
1409                 goto out;
1410         }
1411
1412 out:
1413         if (fd_src >= 0)
1414                 close(fd_src);
1415
1416         if (fd_dst >= 0)
1417                 close(fd_dst);
1418 out_closed:
1419         if (rc < 0)
1420                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1421                         progname, name, error_loc, strerror(-rc));
1422         else if (migration_flags & LLAPI_MIGRATION_VERBOSE)
1423                 printf("%s\n", name);
1424
1425         return rc;
1426 }
1427
1428 static int comp_str2flags(char *string, __u32 *flags, __u32 *neg_flags)
1429 {
1430         char *name;
1431         char *dup_string = NULL;
1432         int rc = 0;
1433
1434         *flags = 0;
1435         *neg_flags = 0;
1436
1437         if (!string || !string[0])
1438                 return -EINVAL;
1439
1440         dup_string = strdup(string);
1441         if (!dup_string) {
1442                 llapi_printf(LLAPI_MSG_ERROR,
1443                              "%s: insufficient memory\n",
1444                              progname);
1445                 return -ENOMEM;
1446         }
1447
1448         for (name = strtok(dup_string, ","); name; name = strtok(NULL, ",")) {
1449                 bool found = false;
1450                 int i;
1451
1452                 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1453                         __u32 comp_flag = comp_flags_table[i].cfn_flag;
1454                         const char *comp_name = comp_flags_table[i].cfn_name;
1455
1456                         if (strcmp(name, comp_name) == 0) {
1457                                 *flags |= comp_flag;
1458                                 found = true;
1459                         } else if (strncmp(name, "^", 1) == 0 &&
1460                                    strcmp(name + 1, comp_name) == 0) {
1461                                 *neg_flags |= comp_flag;
1462                                 found = true;
1463                         }
1464                 }
1465                 if (!found) {
1466                         llapi_printf(LLAPI_MSG_ERROR,
1467                                      "%s: component flag '%s' not supported\n",
1468                                      progname, name);
1469                         rc = -EINVAL;
1470                         goto out_free;
1471                 }
1472         }
1473
1474         if (!*flags && !*neg_flags)
1475                 rc = -EINVAL;
1476
1477         /* don't allow to set and exclude the same flag */
1478         if (*flags & *neg_flags)
1479                 rc = -EINVAL;
1480
1481 out_free:
1482         free(dup_string);
1483         return rc;
1484 }
1485
1486 static int mdthash_input(char *string, __u32 *inflags,
1487                          __u32 *exflags, __u32 *type)
1488 {
1489         char *name;
1490         struct mhf_list {
1491                 char *name;
1492                 __u32 flag;
1493         } mhflist[] = {
1494                 {"migrating", LMV_HASH_FLAG_MIGRATION},
1495                 {"bad_type", LMV_HASH_FLAG_BAD_TYPE},
1496                 {"badtype", LMV_HASH_FLAG_BAD_TYPE},
1497                 {"lost_lmv", LMV_HASH_FLAG_LOST_LMV},
1498                 {"lostlmv", LMV_HASH_FLAG_LOST_LMV},
1499         };
1500
1501         if (string == NULL)
1502                 return -EINVAL;
1503
1504         *inflags = 0;
1505         *exflags = 0;
1506         *type = 0;
1507         for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1508                 bool found = false;
1509                 int i;
1510
1511                 for (i = 0; i < ARRAY_SIZE(mhflist); i++) {
1512                         if (strcmp(name, mhflist[i].name) == 0 ||
1513                             name[0] == mhflist[i].name[0]) {
1514                                 *inflags |= mhflist[i].flag;
1515                                 found = true;
1516                         } else if (name[0] == '^' &&
1517                                    (strcmp(name + 1, mhflist[i].name) == 0 ||
1518                                     name[1] == mhflist[i].name[0])) {
1519                                 *exflags |= mhflist[i].flag;
1520                                 found = true;
1521                         }
1522                 }
1523                 if (!found) {
1524                         i = check_hashtype(name);
1525                         if (i > 0) {
1526                                 *type |= 1 << i;
1527                                 continue;
1528                         }
1529                         llapi_printf(LLAPI_MSG_ERROR,
1530                                      "%s: invalid mdt_hash value '%s'\n",
1531                                      progname, name);
1532                         return -EINVAL;
1533                 }
1534         }
1535
1536         /* don't allow to include and exclude the same flag */
1537         if (*inflags & *exflags) {
1538                 llapi_printf(LLAPI_MSG_ERROR,
1539                              "%s: include and exclude same flag '%s'\n",
1540                              progname, string);
1541                 return -EINVAL;
1542         }
1543
1544         return 0;
1545 }
1546
1547 static int mirror_str2state(char *string, __u16 *state, __u16 *neg_state)
1548 {
1549         if (!string)
1550                 return -EINVAL;
1551
1552         *state = 0;
1553         *neg_state = 0;
1554
1555         if (strncmp(string, "^", 1) == 0) {
1556                 *neg_state = llapi_layout_string_flags(string + 1);
1557                 if (*neg_state != 0)
1558                         return 0;
1559         } else {
1560                 *state = llapi_layout_string_flags(string);
1561                 if (*state != 0)
1562                         return 0;
1563         }
1564
1565         llapi_printf(LLAPI_MSG_ERROR,
1566                      "%s: mirrored file state '%s' not supported\n",
1567                      progname, string);
1568         return -EINVAL;
1569 }
1570
1571 /**
1572  * struct mirror_args - Command-line arguments for mirror(s).
1573  * @m_count:  Number of mirrors to be created with this layout.
1574  * @m_flags:  Mirror level flags, only 'prefer' is supported.
1575  * @m_layout: Mirror layout.
1576  * @m_file:   A victim file. Its layout will be split and used as a mirror.
1577  * @m_next:   Point to the next node of the list.
1578  *
1579  * Command-line arguments for mirror(s) will be parsed and stored in
1580  * a linked list that consists of this structure.
1581  */
1582 struct mirror_args {
1583         __u32                   m_count;
1584         __u32                   m_flags;
1585         struct llapi_layout     *m_layout;
1586         const char              *m_file;
1587         struct mirror_args      *m_next;
1588         bool                    m_inherit;
1589 };
1590
1591 /**
1592  * enum mirror_flags - Flags for extending a mirrored file.
1593  * @MF_NO_VERIFY: Indicates not to verify the mirror(s) from victim file(s)
1594  *             in case the victim file(s) contains the same data as the
1595  *             original mirrored file.
1596  * @MF_DESTROY: Indicates to delete the mirror from the mirrored file.
1597  * @MF_COMP_ID: specified component id instead of mirror id
1598  *
1599  * Flags for extending a mirrored file.
1600  */
1601 enum mirror_flags {
1602         MF_NO_VERIFY    = 0x1,
1603         MF_DESTROY      = 0x2,
1604         MF_COMP_ID      = 0x4,
1605         MF_COMP_POOL    = 0x8,
1606 };
1607
1608 /**
1609  * mirror_create_sanity_check() - Check mirror list.
1610  * @list:  A linked list that stores the mirror arguments.
1611  *
1612  * This function does a sanity check on @list for creating
1613  * a mirrored file.
1614  *
1615  * Return: 0 on success or a negative error code on failure.
1616  */
1617 static int mirror_create_sanity_check(const char *fname,
1618                                       struct mirror_args *list)
1619 {
1620         int rc = 0;
1621         bool has_m_file = false;
1622         char fsname[MAX_OBD_NAME + 1] = { 0 };
1623         bool has_m_layout = false;
1624
1625         if (!list)
1626                 return -EINVAL;
1627
1628         if (fname) {
1629                 rc = llapi_search_fsname(fname, fsname);
1630                 if (rc) {
1631                         fprintf(stderr,
1632                                 "error: %s: file '%s' has no fsname\n",
1633                                         progname, fname);
1634                         return rc;
1635                 }
1636         }
1637
1638         while (list) {
1639                 if (list->m_file) {
1640                         has_m_file = true;
1641                         llapi_layout_free(list->m_layout);
1642
1643                         list->m_layout =
1644                                 llapi_layout_get_by_path(list->m_file, 0);
1645                         if (!list->m_layout) {
1646                                 fprintf(stderr,
1647                                         "error: %s: file '%s' has no layout\n",
1648                                         progname, list->m_file);
1649                                 return -ENODATA;
1650                         }
1651                 } else {
1652                         has_m_layout = true;
1653                         if (!list->m_layout) {
1654                                 fprintf(stderr, "error: %s: no mirror layout\n",
1655                                         progname);
1656                                 return -EINVAL;
1657                         }
1658                 }
1659                 rc = llapi_layout_v2_sanity(list->m_layout, false, true,
1660                                             fsname);
1661                 if (rc) {
1662                         llapi_layout_sanity_perror(rc);
1663                         return rc;
1664                 }
1665
1666                 list = list->m_next;
1667         }
1668
1669         if (has_m_file && has_m_layout) {
1670                 fprintf(stderr,
1671                         "error: %s: -f <victim_file> option should not be specified with setstripe options\n",
1672                         progname);
1673                 return -EINVAL;
1674         }
1675
1676         return 0;
1677 }
1678
1679 static int mirror_set_flags(struct llapi_layout *layout, void *cbdata)
1680 {
1681         __u32 mirror_flags = *(__u32 *)cbdata;
1682         uint32_t flags;
1683         int rc;
1684
1685         rc = llapi_layout_comp_flags_get(layout, &flags);
1686         if (rc < 0)
1687                 return rc;
1688
1689         if (!flags) {
1690                 rc = llapi_layout_comp_flags_set(layout, mirror_flags);
1691                 if (rc)
1692                         return rc;
1693         }
1694
1695         return LLAPI_LAYOUT_ITER_CONT;
1696 }
1697
1698 /**
1699  * mirror_create() - Create a mirrored file.
1700  * @fname:        The file to be created.
1701  * @mirror_list:  A linked list that stores the mirror arguments.
1702  *
1703  * This function creates a mirrored file @fname with the mirror(s)
1704  * from @mirror_list.
1705  *
1706  * Return: 0 on success or a negative error code on failure.
1707  */
1708 static int mirror_create(char *fname, struct mirror_args *mirror_list)
1709 {
1710         struct llapi_layout *layout = NULL;
1711         struct mirror_args *cur_mirror = NULL;
1712         uint16_t mirror_count = 0;
1713         int i = 0;
1714         int rc = 0;
1715
1716         rc = mirror_create_sanity_check(fname, mirror_list);
1717         if (rc)
1718                 return rc;
1719
1720         cur_mirror = mirror_list;
1721         while (cur_mirror) {
1722                 rc = llapi_layout_comp_iterate(cur_mirror->m_layout,
1723                                                mirror_set_flags,
1724                                                &cur_mirror->m_flags);
1725                 if (rc) {
1726                         rc = -errno;
1727                         fprintf(stderr, "%s: failed to set mirror flags\n",
1728                                 progname);
1729                         goto error;
1730                 }
1731
1732                 for (i = 0; i < cur_mirror->m_count; i++) {
1733                         rc = llapi_layout_merge(&layout, cur_mirror->m_layout);
1734                         if (rc) {
1735                                 rc = -errno;
1736                                 fprintf(stderr,
1737                                         "error: %s: merge layout failed: %s\n",
1738                                         progname, strerror(errno));
1739                                 goto error;
1740                         }
1741                 }
1742                 mirror_count += cur_mirror->m_count;
1743                 cur_mirror = cur_mirror->m_next;
1744         }
1745
1746         if (!layout) {
1747                 fprintf(stderr, "error: %s: layout is NULL\n", progname);
1748                 return -EINVAL;
1749         }
1750
1751         rc = llapi_layout_mirror_count_set(layout, mirror_count);
1752         if (rc) {
1753                 rc = -errno;
1754                 fprintf(stderr, "error: %s: set mirror count failed: %s\n",
1755                         progname, strerror(errno));
1756                 goto error;
1757         }
1758
1759         rc = lfs_component_create(fname, O_CREAT | O_WRONLY, 0666,
1760                                   layout);
1761         if (rc >= 0) {
1762                 close(rc);
1763                 rc = 0;
1764         }
1765
1766 error:
1767         llapi_layout_free(layout);
1768         return rc;
1769 }
1770
1771 /**
1772  * Compare files and check lease on @fd.
1773  *
1774  * \retval bytes number of bytes are the same
1775  */
1776 static ssize_t mirror_file_compare(int fd_src, int fd_dst)
1777 {
1778         const size_t buflen = 4 * 1024 * 1024; /* 4M */
1779         void *buf;
1780         ssize_t bytes_done = 0;
1781         ssize_t bytes_read = 0;
1782
1783         buf = malloc(buflen * 2);
1784         if (!buf)
1785                 return -ENOMEM;
1786
1787         while (1) {
1788                 if (!llapi_lease_check(fd_src)) {
1789                         bytes_done = -EBUSY;
1790                         break;
1791                 }
1792
1793                 bytes_read = read(fd_src, buf, buflen);
1794                 if (bytes_read <= 0)
1795                         break;
1796
1797                 if (bytes_read != read(fd_dst, buf + buflen, buflen))
1798                         break;
1799
1800                 /*
1801                  * XXX: should compute the checksum on each buffer and then
1802                  * compare checksum to avoid cache collision
1803                  */
1804                 if (memcmp(buf, buf + buflen, bytes_read))
1805                         break;
1806
1807                 bytes_done += bytes_read;
1808         }
1809
1810         free(buf);
1811
1812         return bytes_done;
1813 }
1814
1815 static int mirror_extend_file(const char *fname, const char *victim_file,
1816                               enum mirror_flags mirror_flags)
1817 {
1818         int fd = -1;
1819         int fdv = -1;
1820         struct stat stbuf;
1821         struct stat stbuf_v;
1822         struct ll_ioc_lease *data = NULL;
1823         int rc;
1824
1825         fd = open(fname, O_RDWR);
1826         if (fd < 0) {
1827                 error_loc = "open source file";
1828                 rc = -errno;
1829                 goto out;
1830         }
1831
1832         fdv = open(victim_file, O_RDWR);
1833         if (fdv < 0) {
1834                 error_loc = "open target file";
1835                 rc = -errno;
1836                 goto out;
1837         }
1838
1839         if (fstat(fd, &stbuf) || fstat(fdv, &stbuf_v)) {
1840                 error_loc = "stat source or target file";
1841                 rc = -errno;
1842                 goto out;
1843         }
1844
1845         if (stbuf.st_dev != stbuf_v.st_dev) {
1846                 error_loc = "stat source and target file";
1847                 rc = -EXDEV;
1848                 goto out;
1849         }
1850
1851         /* mirrors should be of the same size */
1852         if (stbuf.st_size != stbuf_v.st_size) {
1853                 error_loc = "file sizes don't match";
1854                 rc = -EINVAL;
1855                 goto out;
1856         }
1857
1858         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1859         if (rc < 0) {
1860                 error_loc = "cannot get lease";
1861                 goto out;
1862         }
1863
1864         if (!(mirror_flags & MF_NO_VERIFY)) {
1865                 ssize_t ret;
1866                 /* mirrors should have the same contents */
1867                 ret = mirror_file_compare(fd, fdv);
1868                 if (ret != stbuf.st_size) {
1869                         error_loc = "file busy or contents don't match";
1870                         rc = ret < 0 ? ret : -EINVAL;
1871                         goto out;
1872                 }
1873         }
1874
1875         /* Get rid of caching pages from clients */
1876         rc = llapi_file_flush(fd);
1877         if (rc < 0) {
1878                 error_loc = "cannot get data version";
1879                 goto out;
1880         }
1881
1882         rc = llapi_file_flush(fdv);
1883         if (rc < 0) {
1884                 error_loc = "cannot get data version";
1885                 goto out;
1886         }
1887
1888         rc = migrate_set_timestamps(fd, &stbuf);
1889         if (rc < 0) {
1890                 error_loc = "cannot set source file timestamp";
1891                 goto out;
1892         }
1893
1894         /* Atomically put lease, merge layouts and close. */
1895         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
1896         if (!data) {
1897                 error_loc = "memory allocation";
1898                 goto out;
1899         }
1900         data->lil_mode = LL_LEASE_UNLCK;
1901         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
1902         data->lil_count = 1;
1903         data->lil_ids[0] = fdv;
1904         rc = llapi_lease_set(fd, data);
1905         if (rc < 0) {
1906                 error_loc = "cannot merge layout";
1907                 goto out;
1908         } else if (rc == 0) {
1909                 rc = -EBUSY;
1910                 error_loc = "lost lease lock";
1911                 goto out;
1912         }
1913         rc = 0;
1914
1915 out:
1916         if (data)
1917                 free(data);
1918         if (fd >= 0)
1919                 close(fd);
1920         if (fdv >= 0)
1921                 close(fdv);
1922         if (!rc)
1923                 (void) unlink(victim_file);
1924         if (rc < 0)
1925                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1926                         progname, fname, error_loc, strerror(-rc));
1927         return rc;
1928 }
1929
1930 static int mirror_extend_layout(char *name, struct llapi_layout *m_layout,
1931                                 bool inherit, uint32_t flags,
1932                                 unsigned long long bandwidth_bytes_sec,
1933                                 long stats_interval_sec)
1934 {
1935         struct llapi_layout *f_layout = NULL;
1936         struct ll_ioc_lease *data = NULL;
1937         struct stat st;
1938         int fd_src = -1;
1939         int fd_dst = -1;
1940         int rc = 0;
1941
1942         if (inherit) {
1943                 f_layout = llapi_layout_get_by_path(name, 0);
1944                 if (!f_layout) {
1945                         rc = -EINVAL;
1946                         fprintf(stderr, "%s: cannot get layout\n", progname);
1947                         goto out;
1948                 }
1949                 rc = llapi_layout_get_last_init_comp(f_layout);
1950                 if (rc) {
1951                         fprintf(stderr, "%s: cannot get the last init comp\n",
1952                                 progname);
1953                         goto out;
1954                 }
1955                 rc = llapi_layout_mirror_inherit(f_layout, m_layout);
1956                 if (rc) {
1957                         fprintf(stderr,
1958                                 "%s: cannot inherit from the last init comp\n",
1959                                 progname);
1960                         goto out;
1961                 }
1962         }
1963
1964         llapi_layout_comp_flags_set(m_layout, flags);
1965         rc = migrate_open_files(name,
1966                              LLAPI_MIGRATION_NONDIRECT | LLAPI_MIGRATION_MIRROR,
1967                              NULL, m_layout, &fd_src, &fd_dst);
1968         if (rc < 0)
1969                 goto out;
1970
1971         rc = llapi_lease_acquire(fd_src, LL_LEASE_RDLCK);
1972         if (rc < 0) {
1973                 error_loc = "cannot get lease";
1974                 goto out;
1975         }
1976
1977         rc = fstat(fd_src, &st);
1978         if (rc < 0) {
1979                 error_loc = "cannot stat source file";
1980                 goto out;
1981         }
1982
1983         if (stats_interval_sec)
1984                 printf("%s:\n", name);
1985
1986         rc = migrate_nonblock(fd_src, fd_dst, bandwidth_bytes_sec,
1987                               stats_interval_sec);
1988         if (rc < 0) {
1989                 llapi_lease_release(fd_src);
1990                 goto out;
1991         }
1992
1993         rc = migrate_set_timestamps(fd_src, &st);
1994         if (rc < 0) {
1995                 error_loc = "cannot set source file timestamp";
1996                 goto out;
1997         }
1998
1999         /* Atomically put lease, merge layouts and close. */
2000         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
2001         if (!data) {
2002                 error_loc = "memory allocation";
2003                 goto out;
2004         }
2005         data->lil_mode = LL_LEASE_UNLCK;
2006         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
2007         data->lil_count = 1;
2008         data->lil_ids[0] = fd_dst;
2009         rc = llapi_lease_set(fd_src, data);
2010         if (rc < 0) {
2011                 error_loc = "cannot merge layout";
2012                 goto out;
2013         } else if (rc == 0) {
2014                 rc = -EBUSY;
2015                 error_loc = "lost lease lock";
2016                 goto out;
2017         }
2018         rc = 0;
2019
2020 out:
2021         if (data)
2022                 free(data);
2023         if (fd_src >= 0)
2024                 close(fd_src);
2025         if (fd_dst >= 0)
2026                 close(fd_dst);
2027         if (rc < 0)
2028                 fprintf(stderr, "error: %s: %s: %s: %s\n",
2029                         progname, name, error_loc, strerror(-rc));
2030         return rc;
2031 }
2032
2033 static int mirror_extend(char *fname, struct mirror_args *mirror_list,
2034                          enum mirror_flags mirror_flags,
2035                          unsigned long long bandwidth_bytes_sec,
2036                          long stats_interval_sec)
2037 {
2038         int rc = 0;
2039
2040         while (mirror_list) {
2041                 if (mirror_list->m_file) {
2042                         rc = mirror_extend_file(fname, mirror_list->m_file,
2043                                                 mirror_flags);
2044                 } else {
2045                         __u32 mirror_count = mirror_list->m_count;
2046
2047                         while (mirror_count > 0) {
2048                                 rc = mirror_extend_layout(fname,
2049                                                         mirror_list->m_layout,
2050                                                         mirror_list->m_inherit,
2051                                                         mirror_list->m_flags,
2052                                                         bandwidth_bytes_sec,
2053                                                         stats_interval_sec);
2054                                 if (rc)
2055                                         break;
2056
2057                                 --mirror_count;
2058                         }
2059                 }
2060                 if (rc)
2061                         break;
2062
2063                 mirror_list = mirror_list->m_next;
2064         }
2065
2066         return rc;
2067 }
2068
2069 static int find_mirror_id(struct llapi_layout *layout, void *cbdata)
2070 {
2071         uint32_t id;
2072         int rc;
2073
2074         rc = llapi_layout_mirror_id_get(layout, &id);
2075         if (rc < 0)
2076                 return rc;
2077
2078         if ((__u16)id == *(__u16 *)cbdata)
2079                 return LLAPI_LAYOUT_ITER_STOP;
2080
2081         return LLAPI_LAYOUT_ITER_CONT;
2082 }
2083
2084 static int find_comp_id(struct llapi_layout *layout, void *cbdata)
2085 {
2086         uint32_t id;
2087         int rc;
2088
2089         rc = llapi_layout_comp_id_get(layout, &id);
2090         if (rc < 0)
2091                 return rc;
2092
2093         if (id == *(__u32 *)cbdata)
2094                 return LLAPI_LAYOUT_ITER_STOP;
2095
2096         return LLAPI_LAYOUT_ITER_CONT;
2097 }
2098
2099 static int find_mirror_id_by_pool(struct llapi_layout *layout, void *cbdata)
2100 {
2101         char buf[LOV_MAXPOOLNAME + 1];
2102         struct pool_to_id_cbdata *d = (void *)cbdata;
2103         uint32_t id;
2104         int rc;
2105
2106         rc = llapi_layout_pool_name_get(layout, buf, sizeof(buf));
2107         if (rc < 0)
2108                 return rc;
2109         if (strcmp(d->pool, buf))
2110                 return LLAPI_LAYOUT_ITER_CONT;
2111
2112         rc = llapi_layout_mirror_id_get(layout, &id);
2113         if (rc < 0)
2114                 return rc;
2115         d->id = id;
2116
2117         return LLAPI_LAYOUT_ITER_STOP;
2118 }
2119
2120 static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata)
2121 {
2122         char buf[LOV_MAXPOOLNAME + 1];
2123         struct pool_to_id_cbdata *d = (void *)cbdata;
2124         uint32_t id;
2125         int rc;
2126
2127         rc = llapi_layout_pool_name_get(layout, buf, sizeof(buf));
2128         if (rc < 0)
2129                 return rc;
2130         if (strcmp(d->pool, buf))
2131                 return LLAPI_LAYOUT_ITER_CONT;
2132
2133         rc = llapi_layout_comp_id_get(layout, &id);
2134         if (rc < 0)
2135                 return rc;
2136         d->id = id;
2137
2138         return LLAPI_LAYOUT_ITER_STOP;
2139 }
2140
2141 struct collect_ids_data {
2142         __u16   *cid_ids;
2143         int     cid_count;
2144         __u16   cid_exclude;
2145 };
2146
2147 static int collect_mirror_id(struct llapi_layout *layout, void *cbdata)
2148 {
2149         struct collect_ids_data *cid = cbdata;
2150         uint32_t id;
2151         int rc;
2152
2153         rc = llapi_layout_mirror_id_get(layout, &id);
2154         if (rc < 0)
2155                 return rc;
2156
2157         if ((__u16)id != cid->cid_exclude) {
2158                 int i;
2159
2160                 for (i = 0; i < cid->cid_count; i++) {
2161                         /* already collected the mirror id */
2162                         if (id == cid->cid_ids[i])
2163                                 return LLAPI_LAYOUT_ITER_CONT;
2164                 }
2165                 cid->cid_ids[cid->cid_count] = id;
2166                 cid->cid_count++;
2167         }
2168
2169         return LLAPI_LAYOUT_ITER_CONT;
2170 }
2171
2172 /**
2173  * last_non_stale_mirror() - Check if a mirror is the last non-stale mirror.
2174  * @mirror_id: Mirror id to be checked.
2175  * @layout:    Mirror component list.
2176  *
2177  * This function checks if a mirror with specified @mirror_id is the last
2178  * non-stale mirror of a layout @layout.
2179  *
2180  * Return: true or false.
2181  */
2182 static inline
2183 bool last_non_stale_mirror(__u16 mirror_id, struct llapi_layout *layout)
2184 {
2185         __u16 mirror_ids[128] = { 0 };
2186         struct collect_ids_data cid = { .cid_ids = mirror_ids,
2187                                         .cid_count = 0,
2188                                         .cid_exclude = mirror_id, };
2189         int i;
2190
2191         llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
2192
2193         for (i = 0; i < cid.cid_count; i++) {
2194                 struct llapi_resync_comp comp_array[1024] = { { 0 } };
2195                 int comp_size = 0;
2196
2197                 comp_size = llapi_mirror_find_stale(layout, comp_array,
2198                                                     ARRAY_SIZE(comp_array),
2199                                                     &mirror_ids[i], 1);
2200                 if (comp_size == 0)
2201                         return false;
2202         }
2203
2204         return true;
2205 }
2206
2207 static int mirror_split(const char *fname, __u32 id, const char *pool,
2208                         enum mirror_flags mflags, const char *victim_file)
2209 {
2210         struct llapi_layout *layout;
2211         char parent[PATH_MAX];
2212         char victim[PATH_MAX];
2213         int flags = O_CREAT | O_EXCL | O_LOV_DELAY_CREATE | O_NOFOLLOW;
2214         char *ptr;
2215         struct ll_ioc_lease *data;
2216         uint16_t mirror_count;
2217         __u32 mirror_id;
2218         int mdt_index;
2219         int fd, fdv;
2220         bool purge = true; /* delete mirror by setting fdv=fd */
2221         bool is_encrypted;
2222         int rc;
2223
2224         if (victim_file && (strcmp(fname, victim_file) == 0)) {
2225                 fprintf(stderr,
2226                         "error %s: the source file '%s' and -f file are the same\n",
2227                         progname, fname);
2228                 return -EINVAL;
2229         }
2230
2231         /* check fname contains mirror with mirror_id/comp_id */
2232         layout = llapi_layout_get_by_path(fname, 0);
2233         if (!layout) {
2234                 fprintf(stderr,
2235                         "error %s: file '%s' couldn't get layout\n",
2236                         progname, fname);
2237                 return -EINVAL;
2238         }
2239
2240         rc = llapi_layout_sanity(layout, false, true);
2241         if (rc) {
2242                 llapi_layout_sanity_perror(rc);
2243                 goto free_layout;
2244         }
2245
2246         rc = llapi_layout_mirror_count_get(layout, &mirror_count);
2247         if (rc) {
2248                 fprintf(stderr,
2249                         "error %s: file '%s' couldn't get mirror count\n",
2250                         progname, fname);
2251                 goto free_layout;
2252         }
2253         if (mirror_count < 2) {
2254                 fprintf(stderr,
2255                         "error %s: file '%s' has %d component, cannot split\n",
2256                         progname, fname, mirror_count);
2257                 goto free_layout;
2258         }
2259
2260         if (mflags & MF_COMP_POOL) {
2261                 struct pool_to_id_cbdata data = { .pool = pool };
2262
2263                 rc = llapi_layout_comp_iterate(layout, find_mirror_id_by_pool,
2264                                                &data);
2265                 mirror_id = data.id;
2266         } else if (mflags & MF_COMP_ID) {
2267                 rc = llapi_layout_comp_iterate(layout, find_comp_id, &id);
2268                 mirror_id = mirror_id_of(id);
2269         } else {
2270                 rc = llapi_layout_comp_iterate(layout, find_mirror_id, &id);
2271                 mirror_id = id;
2272         }
2273         if (rc < 0) {
2274                 fprintf(stderr, "error %s: failed to iterate layout of '%s'\n",
2275                         progname, fname);
2276                 goto free_layout;
2277         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
2278                 if (mflags & MF_COMP_POOL) {
2279                         fprintf(stderr,
2280                                 "error %s: file '%s' does not contain mirror with pool '%s'\n",
2281                                 progname, fname, pool);
2282                         goto free_layout;
2283                 } else if (mflags & MF_COMP_ID) {
2284                         fprintf(stderr,
2285                                 "error %s: file '%s' does not contain mirror with comp-id %u\n",
2286                                 progname, fname, id);
2287                         goto free_layout;
2288                 } else {
2289                         fprintf(stderr,
2290                                 "error %s: file '%s' does not contain mirror with id %u\n",
2291                                 progname, fname, id);
2292                         goto free_layout;
2293                 }
2294         }
2295
2296         if (last_non_stale_mirror(mirror_id, layout)) {
2297                 rc = -EUCLEAN;
2298                 fprintf(stderr,
2299                         "%s: cannot destroy the last non-stale mirror of file '%s'\n",
2300                         progname, fname);
2301                 goto free_layout;
2302         }
2303
2304         if (!victim_file && mflags & MF_DESTROY)
2305                 /* Allow mirror split even without the key on encrypted files,
2306                  * and in this case of a 'split -d', open file with O_DIRECT
2307                  * (no IOs will be done).
2308                  */
2309                 fd = open(fname, O_RDWR | O_DIRECT | O_CIPHERTEXT);
2310         else
2311                 fd = open(fname, O_RDWR);
2312
2313         if (fd < 0) {
2314                 fprintf(stderr,
2315                         "error %s: open file '%s' failed: %s\n",
2316                         progname, fname, strerror(errno));
2317                 goto free_layout;
2318         }
2319
2320         /* get victim file directory pathname */
2321         if (strlen(fname) > sizeof(parent) - 1) {
2322                 fprintf(stderr, "error %s: file name of '%s' too long\n",
2323                         progname, fname);
2324                 rc = -ERANGE;
2325                 goto close_fd;
2326         }
2327         strncpy(parent, fname, sizeof(parent));
2328         ptr = strrchr(parent, '/');
2329         if (!ptr) {
2330                 if (!getcwd(parent, sizeof(parent))) {
2331                         fprintf(stderr, "error %s: getcwd failed: %s\n",
2332                                 progname, strerror(errno));
2333                         rc = -errno;
2334                         goto close_fd;
2335                 }
2336         } else {
2337                 if (ptr == parent)
2338                         ptr = parent + 1;
2339                 *ptr = '\0';
2340         }
2341
2342         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
2343         if (rc < 0) {
2344                 fprintf(stderr, "%s: cannot get MDT index of '%s'\n",
2345                         progname, fname);
2346                 goto close_fd;
2347         }
2348
2349         rc = llapi_file_is_encrypted(fd);
2350         if (rc < 0) {
2351                 fprintf(stderr, "%s: cannot get flags of '%s': %d\n",
2352                         progname, fname, rc);
2353                 goto close_fd;
2354         }
2355         is_encrypted = rc;
2356
2357 again:
2358         if (!victim_file) {
2359                 /* use a temp file to store the splitted layout */
2360                 if (mflags & MF_DESTROY) {
2361                         char file_path[PATH_MAX];
2362                         unsigned int rnumber;
2363                         int open_flags;
2364
2365                         if (last_non_stale_mirror(mirror_id, layout)) {
2366                                 rc = -EUCLEAN;
2367                                 fprintf(stderr,
2368                                         "%s: cannot destroy the last non-stale mirror of file '%s'\n",
2369                                         progname, fname);
2370                                 goto close_fd;
2371                         }
2372
2373                         if (purge) {
2374                                 /* don't use volatile file for mirror destroy */
2375                                 fdv = fd;
2376                         } else {
2377                                 /**
2378                                  * try the old way to delete mirror using
2379                                  * volatile file.
2380                                  */
2381                                 do {
2382                                         rnumber = random();
2383                                         rc = snprintf(file_path,
2384                                                       sizeof(file_path),
2385                                                       "%s/" LUSTRE_VOLATILE_HDR ":%.4X:%.4X:fd=%.2d",
2386                                                       parent, mdt_index,
2387                                                       rnumber, fd);
2388                                         if (rc < 0 ||
2389                                             rc >= sizeof(file_path)) {
2390                                                 fdv = -ENAMETOOLONG;
2391                                                 break;
2392                                         }
2393
2394                                         open_flags = O_RDWR |
2395                                              (O_LOV_DELAY_CREATE & ~O_ACCMODE) |
2396                                              O_CREAT | O_EXCL | O_NOFOLLOW |
2397                                              /* O_DIRECT for mirror split -d */
2398                                              O_DIRECT |
2399                                              /* Allow split without the key */
2400                                              O_CIPHERTEXT;
2401                                         fdv = open(file_path, open_flags,
2402                                                    S_IRUSR | S_IWUSR);
2403                                         if (fdv < 0)
2404                                                 rc = -errno;
2405                                 } while (fdv < 0 && rc == -EEXIST);
2406                         }
2407                 } else {
2408                         if (is_encrypted) {
2409                                 rc = -1;
2410                                 fprintf(stderr,
2411                                         "error %s: not permitted on encrypted file '%s': %d\n",
2412                                         progname, fname, rc);
2413                                 goto close_fd;
2414                         }
2415
2416                         snprintf(victim, sizeof(victim), "%s.mirror~%u",
2417                                  fname, mirror_id);
2418                         fdv = open(victim, flags, S_IRUSR | S_IWUSR);
2419                 }
2420         } else {
2421                 /* user specified victim file */
2422                 if (is_encrypted) {
2423                         rc = -1;
2424                         fprintf(stderr,
2425                                 "error %s: not permitted on encrypted file '%s': %d\n",
2426                                 progname, fname, rc);
2427                         goto close_fd;
2428                 }
2429                 fdv = open(victim_file, flags, S_IRUSR | S_IWUSR);
2430         }
2431
2432         if (fdv < 0) {
2433                 fprintf(stderr,
2434                         "error %s: create victim file failed: %s\n",
2435                         progname, strerror(errno));
2436                 goto close_fd;
2437         }
2438
2439         /* get lease lock of fname */
2440         rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
2441         if (rc < 0) {
2442                 fprintf(stderr,
2443                         "error %s: cannot get lease of file '%s': %d\n",
2444                         progname, fname, rc);
2445                 goto close_victim;
2446         }
2447
2448         /* Atomatically put lease, split layouts and close. */
2449         data = malloc(offsetof(typeof(*data), lil_ids[2]));
2450         if (!data) {
2451                 rc = -ENOMEM;
2452                 goto close_victim;
2453         }
2454
2455         data->lil_mode = LL_LEASE_UNLCK;
2456         data->lil_flags = LL_LEASE_LAYOUT_SPLIT;
2457         data->lil_count = 2;
2458         data->lil_ids[0] = fdv;
2459         data->lil_ids[1] = mirror_id;
2460         rc = llapi_lease_set(fd, data);
2461         if (rc <= 0) {
2462                 if ((rc == -EINVAL || rc == -EBUSY) && purge) {
2463                         /* could be old MDS which prohibit fd==fdv */
2464                         purge = false;
2465                         goto again;
2466
2467                 }
2468                 if (rc == 0) /* lost lease lock */
2469                         rc = -EBUSY;
2470                 fprintf(stderr,
2471                         "error %s: cannot split '%s': %s\n",
2472                         progname, fname, strerror(-rc));
2473         } else {
2474                 rc = 0;
2475         }
2476         free(data);
2477
2478 close_victim:
2479         if (!purge)
2480                 close(fdv);
2481 close_fd:
2482         close(fd);
2483 free_layout:
2484         llapi_layout_free(layout);
2485         return rc;
2486 }
2487
2488 static inline
2489 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
2490                            __u16 *mirror_ids, int ids_nr,
2491                            long stats_interval_sec, long bandwidth_bytes_sec);
2492
2493
2494 static int lfs_migrate_to_dom(int fd_src, int fd_dst, char *name,
2495                               __u64 migration_flags,
2496                               unsigned long long bandwidth_bytes_sec,
2497                               long stats_interval_sec)
2498 {
2499         struct ll_ioc_lease *data = NULL;
2500         int rc;
2501
2502         rc = llapi_lease_acquire(fd_src, LL_LEASE_RDLCK);
2503         if (rc < 0) {
2504                 error_loc = "cannot get lease";
2505                 goto out_close;
2506         }
2507
2508         if (stats_interval_sec)
2509                 printf("%s:\n", name);
2510
2511         rc = migrate_nonblock(fd_src, fd_dst, bandwidth_bytes_sec,
2512                               stats_interval_sec);
2513         if (rc < 0)
2514                 goto out_release;
2515
2516         /* Atomically put lease, merge layouts, resync and close. */
2517         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
2518         if (!data) {
2519                 error_loc = "memory allocation";
2520                 goto out_release;
2521         }
2522         data->lil_mode = LL_LEASE_UNLCK;
2523         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
2524         data->lil_count = 1;
2525         data->lil_ids[0] = fd_dst;
2526         rc = llapi_lease_set(fd_src, data);
2527         if (rc < 0) {
2528                 error_loc = "cannot merge layout";
2529                 goto out_close;
2530         } else if (rc == 0) {
2531                 rc = -EBUSY;
2532                 error_loc = "lost lease lock";
2533                 goto out_close;
2534         }
2535         close(fd_src);
2536         close(fd_dst);
2537
2538         rc = lfs_mirror_resync_file(name, data, NULL, 0,
2539                                     stats_interval_sec,
2540                                     bandwidth_bytes_sec);
2541         if (rc) {
2542                 error_loc = "cannot resync file";
2543                 goto out;
2544         }
2545
2546         /* delete first mirror now */
2547         rc = mirror_split(name, 1, NULL, MF_DESTROY, NULL);
2548         if (rc < 0)
2549                 error_loc = "cannot delete old layout";
2550         goto out;
2551
2552 out_release:
2553         llapi_lease_release(fd_src);
2554 out_close:
2555         close(fd_src);
2556         close(fd_dst);
2557 out:
2558         if (rc < 0)
2559                 fprintf(stderr, "error: %s: %s: %s: %s\n",
2560                         progname, name, error_loc, strerror(-rc));
2561         else if (migration_flags & LLAPI_MIGRATION_VERBOSE)
2562                 printf("%s\n", name);
2563         if (data)
2564                 free(data);
2565         return rc;
2566 }
2567
2568 /**
2569  * Parse a string containing an target index list into an array of integers.
2570  *
2571  * The input string contains a comma delimited list of individual
2572  * indices and ranges, for example "1,2-4,7". Add the indices into the
2573  * \a tgts array and remove duplicates.
2574  *
2575  * \param[out] tgts             array to store indices in
2576  * \param[in] size              size of \a tgts array
2577  * \param[in] offset            starting index in \a tgts
2578  * \param[in] arg               string containing OST index list
2579  * \param[in/out] overstriping  index list may contain duplicates
2580  *
2581  * \retval positive    number of indices in \a tgts
2582  * \retval -EINVAL     unable to parse \a arg
2583  */
2584 static int parse_targets(__u32 *tgts, int size, int offset, char *arg,
2585                          unsigned long long *pattern)
2586 {
2587         int rc;
2588         int nr = offset;
2589         int slots = size - offset;
2590         char *ptr = NULL;
2591         bool overstriped = false;
2592         bool end_of_loop;
2593
2594         if (!arg)
2595                 return -EINVAL;
2596
2597         end_of_loop = false;
2598         while (!end_of_loop) {
2599                 int start_index = 0;
2600                 int end_index = 0;
2601                 int i;
2602                 char *endptr = NULL;
2603
2604                 rc = -EINVAL;
2605
2606                 ptr = strchrnul(arg, ',');
2607
2608                 end_of_loop = *ptr == '\0';
2609                 *ptr = '\0';
2610
2611                 errno = 0;
2612                 start_index = strtol(arg, &endptr, 0);
2613                 if (endptr == arg) /* no data at all */
2614                         break;
2615                 if (errno != 0 || start_index < -1 ||
2616                     (*endptr != '-' && *endptr != '\0'))
2617                         break;
2618
2619                 end_index = start_index;
2620                 if (*endptr == '-') {
2621                         errno = 0;
2622                         end_index = strtol(endptr + 1, &endptr, 0);
2623                         if (errno != 0 || *endptr != '\0' || end_index < -1)
2624                                 break;
2625                         if (end_index < start_index)
2626                                 break;
2627                 }
2628
2629                 for (i = start_index; i <= end_index && slots > 0; i++) {
2630                         int j;
2631
2632                         /* remove duplicate */
2633                         for (j = 0; j < offset; j++) {
2634                                 if (tgts[j] == i && pattern &&
2635                                     *pattern == LLAPI_LAYOUT_OVERSTRIPING)
2636                                         overstriped = true;
2637                                 else if (tgts[j] == i)
2638                                         return -EINVAL;
2639                         }
2640
2641                         j = offset;
2642
2643                         if (j == offset) { /* check complete */
2644                                 tgts[nr++] = i;
2645                                 --slots;
2646                         }
2647                 }
2648
2649                 if (slots == 0 && i < end_index)
2650                         break;
2651
2652                 *ptr = ',';
2653                 arg = ++ptr;
2654                 offset = nr;
2655                 rc = 0;
2656         }
2657         if (!end_of_loop && ptr)
2658                 *ptr = ',';
2659
2660         if (!overstriped && pattern)
2661                 *pattern = LLAPI_LAYOUT_DEFAULT;
2662
2663         return rc < 0 ? rc : nr;
2664 }
2665
2666 struct lfs_setstripe_args {
2667         unsigned long long       lsa_comp_end;
2668         unsigned long long       lsa_stripe_size;
2669         unsigned long long       lsa_extension_size;
2670         long long                lsa_stripe_count;
2671         long long                lsa_stripe_off;
2672         __u32                    lsa_comp_flags;
2673         __u32                    lsa_comp_neg_flags;
2674         unsigned long long       lsa_pattern;
2675         unsigned int             lsa_mirror_count;
2676         int                      lsa_nr_tgts;
2677         bool                     lsa_first_comp;
2678         bool                     lsa_extension_comp;
2679         __u32                   *lsa_tgts;
2680         char                    *lsa_pool_name;
2681 };
2682
2683 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
2684 {
2685         unsigned int mirror_count = lsa->lsa_mirror_count;
2686         bool first_comp = lsa->lsa_first_comp;
2687
2688         memset(lsa, 0, sizeof(*lsa));
2689
2690         lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
2691         lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
2692         lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2693         lsa->lsa_pattern = LLAPI_LAYOUT_RAID0;
2694         lsa->lsa_pool_name = NULL;
2695
2696         lsa->lsa_mirror_count = mirror_count;
2697         lsa->lsa_first_comp = first_comp;
2698 }
2699
2700 /**
2701  * setstripe_args_init_inherit() - Initialize and inherit stripe options.
2702  * @lsa: Stripe options to be initialized and inherited.
2703  *
2704  * This function initializes stripe options in @lsa and inherit
2705  * stripe_size, stripe_count and OST pool_name options.
2706  *
2707  * Return: void.
2708  */
2709 static inline void setstripe_args_init_inherit(struct lfs_setstripe_args *lsa)
2710 {
2711         unsigned long long stripe_size;
2712         long long stripe_count;
2713         char *pool_name = NULL;
2714
2715         stripe_size = lsa->lsa_stripe_size;
2716         stripe_count = lsa->lsa_stripe_count;
2717         pool_name = lsa->lsa_pool_name;
2718
2719         setstripe_args_init(lsa);
2720
2721         lsa->lsa_stripe_size = stripe_size;
2722         lsa->lsa_stripe_count = stripe_count;
2723         lsa->lsa_pool_name = pool_name;
2724 }
2725
2726 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
2727 {
2728         return (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT ||
2729                 lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ||
2730                 lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
2731                 lsa->lsa_pattern != LLAPI_LAYOUT_RAID0 ||
2732                 lsa->lsa_comp_end != 0);
2733 }
2734
2735 static int lsa_args_stripe_count_check(struct lfs_setstripe_args *lsa)
2736 {
2737         if (lsa->lsa_nr_tgts) {
2738                 if (lsa->lsa_nr_tgts < 0 ||
2739                     lsa->lsa_nr_tgts >= LOV_MAX_STRIPE_COUNT) {
2740                         fprintf(stderr, "Invalid nr_tgts(%d)\n",
2741                                 lsa->lsa_nr_tgts);
2742                         errno = EINVAL;
2743                         return -1;
2744                 }
2745
2746                 if (lsa->lsa_stripe_count > 0 &&
2747                     lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
2748                     lsa->lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
2749                     lsa->lsa_nr_tgts != lsa->lsa_stripe_count) {
2750                         fprintf(stderr, "stripe_count(%lld) != nr_tgts(%d)\n",
2751                                 lsa->lsa_stripe_count,
2752                                 lsa->lsa_nr_tgts);
2753                         errno = EINVAL;
2754                         return -1;
2755                 }
2756         }
2757
2758         return 0;
2759
2760 }
2761
2762 /**
2763  * comp_args_to_layout() - Create or extend a composite layout.
2764  * @composite:       Pointer to the composite layout.
2765  * @lsa:             Stripe options for the new component.
2766  *
2767  * This function creates or extends a composite layout by adding a new
2768  * component with stripe options from @lsa.
2769  *
2770  * When modified, adjust llapi_stripe_param_verify() if needed as well.
2771  *
2772  * Return: 0 on success or an error code on failure.
2773  */
2774 static int comp_args_to_layout(struct llapi_layout **composite,
2775                                struct lfs_setstripe_args *lsa,
2776                                bool set_extent)
2777 {
2778         struct llapi_layout *layout = *composite;
2779         uint64_t prev_end = 0;
2780         uint64_t size;
2781         int i = 0, rc;
2782
2783 new_comp:
2784         if (!layout) {
2785                 layout = llapi_layout_alloc();
2786                 if (!layout) {
2787                         fprintf(stderr, "Alloc llapi_layout failed. %s\n",
2788                                 strerror(errno));
2789                         errno = ENOMEM;
2790                         return -1;
2791                 }
2792                 *composite = layout;
2793                 lsa->lsa_first_comp = true;
2794         } else {
2795                 uint64_t start;
2796
2797                 /*
2798                  * Get current component extent, current component
2799                  * must be the tail component.
2800                  */
2801                 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
2802                 if (rc) {
2803                         fprintf(stderr, "Get comp extent failed. %s\n",
2804                                 strerror(errno));
2805                         return rc;
2806                 }
2807
2808                 if (lsa->lsa_first_comp) {
2809                         prev_end = 0;
2810                         rc = llapi_layout_add_first_comp(layout);
2811                 } else {
2812                         rc = llapi_layout_comp_add(layout);
2813                 }
2814                 if (rc) {
2815                         fprintf(stderr, "Add component failed. %s\n",
2816                                 strerror(errno));
2817                         return rc;
2818                 }
2819         }
2820
2821         rc = llapi_layout_comp_flags_set(layout, lsa->lsa_comp_flags);
2822         if (rc) {
2823                 fprintf(stderr, "Set flags 0x%x failed: %s\n",
2824                         lsa->lsa_comp_flags, strerror(errno));
2825                 return rc;
2826         }
2827
2828         if (set_extent) {
2829                 uint64_t comp_end = lsa->lsa_comp_end;
2830
2831                 /*
2832                  * The extendable component is 0-length, so it can be removed
2833                  * if there is insufficient space to extend it.
2834                  */
2835                 if (lsa->lsa_extension_comp)
2836                         comp_end = prev_end;
2837
2838                 rc = llapi_layout_comp_extent_set(layout, prev_end,
2839                                                   comp_end);
2840                 if (rc) {
2841                         fprintf(stderr, "Set extent [%lu, %lu) failed. %s\n",
2842                                 prev_end, comp_end, strerror(errno));
2843                         return rc;
2844                 }
2845         }
2846         /* reset lsa_first_comp */
2847         lsa->lsa_first_comp = false;
2848
2849         /* Data-on-MDT component setting */
2850         if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
2851                 /* Yaml support */
2852                 if (lsa->lsa_stripe_count == 0)
2853                         lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
2854                 if (lsa->lsa_stripe_size == lsa->lsa_comp_end)
2855                         lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
2856                 if (lsa->lsa_stripe_off == -1 ||
2857                     lsa->lsa_stripe_off == 0)
2858                         lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2859                 /*
2860                  * In case of Data-on-MDT patterns the only extra option
2861                  * applicable is stripe size option.
2862                  */
2863                 if (lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
2864                         fprintf(stderr,
2865                                 "Option 'stripe-count' can't be specified with Data-on-MDT component: %lld\n",
2866                                 lsa->lsa_stripe_count);
2867                         errno = EINVAL;
2868                         return -1;
2869                 }
2870                 if (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT &&
2871                     lsa->lsa_stripe_size != lsa->lsa_comp_end - prev_end) {
2872                         fprintf(stderr,
2873                                 "Option 'stripe-size' can't be specified with Data-on-MDT component: %llu\n",
2874                                 lsa->lsa_stripe_size);
2875                         errno = EINVAL;
2876                         return -1;
2877                 }
2878                 if (lsa->lsa_nr_tgts != 0) {
2879                         fprintf(stderr,
2880                                 "Option 'ost-list' can't be specified with Data-on-MDT component: '%i'\n",
2881                                 lsa->lsa_nr_tgts);
2882                         errno = EINVAL;
2883                         return -1;
2884                 }
2885                 if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
2886                         fprintf(stderr,
2887                                 "Option 'stripe-offset' can't be specified with Data-on-MDT component: %lld\n",
2888                                 lsa->lsa_stripe_off);
2889                         errno = EINVAL;
2890                         return -1;
2891                 }
2892                 if (lsa->lsa_pool_name != 0) {
2893                         fprintf(stderr,
2894                                 "Option 'pool' can't be specified with Data-on-MDT component: '%s'\n",
2895                                 lsa->lsa_pool_name);
2896                         errno = EINVAL;
2897                         return -1;
2898                 }
2899
2900                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
2901                 if (rc) {
2902                         fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
2903                                 lsa->lsa_pattern,
2904                                 strerror(errno));
2905                         return rc;
2906                 }
2907                 /* Data-on-MDT component has always single stripe up to end */
2908                 lsa->lsa_stripe_size = lsa->lsa_comp_end;
2909         } else if (lsa->lsa_pattern == LLAPI_LAYOUT_OVERSTRIPING) {
2910                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
2911                 if (rc) {
2912                         fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
2913                                 lsa->lsa_pattern,
2914                                 strerror(errno));
2915                         return rc;
2916                 }
2917         }
2918
2919         size = lsa->lsa_comp_flags & LCME_FL_EXTENSION ?
2920                 lsa->lsa_extension_size : lsa->lsa_stripe_size;
2921
2922         if (lsa->lsa_comp_flags & LCME_FL_EXTENSION)
2923                 rc = llapi_layout_extension_size_set(layout, size);
2924         else
2925                 rc = llapi_layout_stripe_size_set(layout, size);
2926
2927         if (rc) {
2928                 fprintf(stderr, "Set stripe size %lu failed: %s\n",
2929                         size, strerror(errno));
2930                 return rc;
2931         }
2932
2933         rc = llapi_layout_stripe_count_set(layout, lsa->lsa_stripe_count);
2934         if (rc) {
2935                 fprintf(stderr, "Set stripe count %lld failed: %s\n",
2936                         lsa->lsa_stripe_count, strerror(errno));
2937                 return rc;
2938         }
2939
2940         if (lsa->lsa_pool_name) {
2941                 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
2942                 if (rc) {
2943                         fprintf(stderr, "Set pool name: %s failed. %s\n",
2944                                 lsa->lsa_pool_name, strerror(errno));
2945                         return rc;
2946                 }
2947         } else {
2948                 rc = llapi_layout_pool_name_set(layout, "");
2949                 if (rc) {
2950                         fprintf(stderr, "Clear pool name failed: %s\n",
2951                                 strerror(errno));
2952                         return rc;
2953                 }
2954         }
2955
2956         rc = lsa_args_stripe_count_check(lsa);
2957         if (rc)
2958                 return rc;
2959
2960         if (lsa->lsa_nr_tgts > 0) {
2961                 bool found = false;
2962
2963                 for (i = 0; i < lsa->lsa_nr_tgts; i++) {
2964                         rc = llapi_layout_ost_index_set(layout, i,
2965                                                         lsa->lsa_tgts[i]);
2966                         if (rc)
2967                                 break;
2968
2969                         /* Make sure stripe offset is in OST list. */
2970                         if (lsa->lsa_tgts[i] == lsa->lsa_stripe_off)
2971                                 found = true;
2972                 }
2973                 if (!found) {
2974                         fprintf(stderr, "Invalid stripe offset '%lld', not in the target list",
2975                                 lsa->lsa_stripe_off);
2976                         errno = EINVAL;
2977                         return -1;
2978                 }
2979         } else if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT &&
2980                    lsa->lsa_stripe_off != -1) {
2981                 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
2982         }
2983         if (rc) {
2984                 fprintf(stderr, "Set ost index %d failed. %s\n",
2985                         i, strerror(errno));
2986                 return rc;
2987         }
2988
2989         /* Create the second, virtual component of extension space */
2990         if (lsa->lsa_extension_comp) {
2991                 lsa->lsa_comp_flags |= LCME_FL_EXTENSION;
2992                 lsa->lsa_extension_comp = false;
2993                 goto new_comp;
2994         }
2995
2996         return rc;
2997 }
2998
2999 static int build_component(struct llapi_layout **layout,
3000                            struct lfs_setstripe_args *lsa, bool set_extent)
3001 {
3002         int rc;
3003
3004         rc = comp_args_to_layout(layout, lsa, set_extent);
3005         if (rc)
3006                 return rc;
3007
3008         if (lsa->lsa_mirror_count > 0) {
3009                 rc = llapi_layout_mirror_count_set(*layout,
3010                                                    lsa->lsa_mirror_count);
3011                 if (rc)
3012                         return rc;
3013
3014                 rc = llapi_layout_flags_set(*layout, LCM_FL_RDONLY);
3015                 if (rc)
3016                         return rc;
3017                 lsa->lsa_mirror_count = 0;
3018         }
3019
3020         return rc;
3021 }
3022
3023 static int build_prev_component(struct llapi_layout **layout,
3024                                 struct lfs_setstripe_args *prev,
3025                                 struct lfs_setstripe_args *lsa,
3026                                 bool set_extent)
3027 {
3028         int extension = lsa->lsa_comp_flags & LCME_FL_EXTENSION;
3029         int rc;
3030
3031         if (prev->lsa_stripe_size) {
3032                 if (extension) {
3033                         prev->lsa_comp_end = lsa->lsa_comp_end;
3034                         prev->lsa_extension_size = lsa->lsa_extension_size;
3035                         prev->lsa_extension_comp = true;
3036                 }
3037
3038                 rc = build_component(layout, prev, true);
3039                 if (rc)
3040                         return rc;
3041         }
3042
3043         /*
3044          * Copy lsa to previous lsa;
3045          * if this is an extension component, make the previous invalid;
3046          */
3047         if (extension)
3048                 prev->lsa_stripe_size = 0;
3049         else
3050                 *prev = *lsa;
3051
3052         return 0;
3053 }
3054
3055 #ifndef LCME_TEMPLATE_FLAGS
3056 #define LCME_TEMPLATE_FLAGS     (LCME_FL_PREF_RW | LCME_FL_NOSYNC | \
3057                                  LCME_FL_EXTENSION)
3058 #endif
3059
3060 static int build_layout_from_yaml_node(struct cYAML *node,
3061                                        struct llapi_layout **layout,
3062                                        struct lfs_setstripe_args *lsa,
3063                                        struct lfs_setstripe_args *prevp)
3064 {
3065         struct lfs_setstripe_args prev = { 0 };
3066         __u32 *osts = lsa->lsa_tgts;
3067         char *string;
3068         int rc = 0;
3069
3070         if (!prevp)
3071                 prevp = &prev;
3072
3073         while (node) {
3074                 string = node->cy_string;
3075
3076                 if (node->cy_type == CYAML_TYPE_OBJECT) {
3077                         /* go deep to sub blocks */
3078                         if (string && !strncmp(string, "component", 9) &&
3079                             strncmp(string, "component0", 10) &&
3080                             strncmp(string, "components", 10)) {
3081                                 rc = build_prev_component(layout, prevp, lsa,
3082                                                           true);
3083                                 if (rc)
3084                                         return rc;
3085
3086                                 /* initialize lsa. */
3087                                 setstripe_args_init(lsa);
3088                                 lsa->lsa_first_comp = false;
3089                                 lsa->lsa_tgts = osts;
3090                         }
3091
3092                         rc = build_layout_from_yaml_node(node->cy_child, layout,
3093                                                          lsa, prevp);
3094                         if (rc)
3095                                 return rc;
3096                 } else {
3097                         if (!node->cy_string)
3098                                 return -EINVAL;
3099
3100                         /* skip leading lmm_ if present, to simplify parsing */
3101                         if (strncmp(string, "lmm_", 4) == 0)
3102                                 string += 4;
3103
3104                         if (node->cy_type == CYAML_TYPE_STRING) {
3105                                 if (!strcmp(string, "lcme_extent.e_end")) {
3106                                         if (!strcmp(node->cy_valuestring, "EOF") ||
3107                                             !strcmp(node->cy_valuestring, "eof"))
3108                                                 lsa->lsa_comp_end = LUSTRE_EOF;
3109                                 } else if (!strcmp(string, "pool")) {
3110                                         lsa->lsa_pool_name = node->cy_valuestring;
3111                                 } else if (!strcmp(string, "pattern")) {
3112                                         if (!strcmp(node->cy_valuestring, "mdt"))
3113                                                 lsa->lsa_pattern = LLAPI_LAYOUT_MDT;
3114                                         if (!strcmp(node->cy_valuestring,
3115                                                     "raid0,overstriped"))
3116                                                 lsa->lsa_pattern =
3117                                                         LLAPI_LAYOUT_OVERSTRIPING;
3118                                 } else if (!strcmp(string, "lcme_flags")) {
3119                                         rc = comp_str2flags(node->cy_valuestring,
3120                                                             &lsa->lsa_comp_flags,
3121                                                             &lsa->lsa_comp_neg_flags);
3122                                         if (rc)
3123                                                 return rc;
3124                                         /*
3125                                          * Only template flags have meaning in
3126                                          * the layout for a new file
3127                                          */
3128                                         lsa->lsa_comp_flags &= LCME_TEMPLATE_FLAGS;
3129                                 }
3130                         } else if (node->cy_type == CYAML_TYPE_NUMBER) {
3131                                 if (!strcmp(string, "lcm_mirror_count")) {
3132                                         lsa->lsa_mirror_count = node->cy_valueint;
3133                                 } else if (!strcmp(string, "lcme_extent.e_start")) {
3134                                         if (node->cy_valueint == 0)
3135                                                 lsa->lsa_first_comp = true;
3136                                 } else if (!strcmp(string, "lcme_extent.e_end")) {
3137                                         if (node->cy_valueint == -1)
3138                                                 lsa->lsa_comp_end = LUSTRE_EOF;
3139                                         else
3140                                                 lsa->lsa_comp_end = node->cy_valueint;
3141                                 } else if (!strcmp(string, "stripe_count")) {
3142                                         lsa->lsa_stripe_count = node->cy_valueint;
3143                                 } else if (!strcmp(string, "stripe_size")) {
3144                                         lsa->lsa_stripe_size = node->cy_valueint;
3145                                 } else if (!strcmp(string, "extension_size")) {
3146                                         lsa->lsa_extension_size = node->cy_valueint;
3147                                         lsa->lsa_extension_comp = true;
3148                                 } else if (!strcmp(string, "stripe_offset")) {
3149                                         lsa->lsa_stripe_off = node->cy_valueint;
3150                                 } else if (!strcmp(string, "l_ost_idx")) {
3151                                         osts[lsa->lsa_nr_tgts] = node->cy_valueint;
3152                                         lsa->lsa_nr_tgts++;
3153                                 }
3154                         }
3155                 }
3156                 node = node->cy_next;
3157         }
3158
3159         if (prevp == &prev) {
3160                 rc = build_prev_component(layout, prevp, lsa, true);
3161                 if (rc)
3162                         return rc;
3163
3164                 if (!(lsa->lsa_comp_flags & LCME_FL_EXTENSION))
3165                         rc = build_component(layout, lsa, *layout != NULL);
3166         }
3167
3168         return rc;
3169 }
3170
3171 static int lfs_comp_create_from_yaml(char *template,
3172                                      struct llapi_layout **layout,
3173                                      struct lfs_setstripe_args *lsa,
3174                                      __u32 *osts)
3175 {
3176         struct cYAML *tree = NULL, *err_rc = NULL;
3177         int rc = 0;
3178
3179         tree = cYAML_build_tree(template, NULL, 0, &err_rc, false);
3180         if (!tree) {
3181                 fprintf(stderr, "%s: cannot parse YAML file %s\n",
3182                         progname, template);
3183                 cYAML_build_error(-EINVAL, -1, "yaml", "from comp yaml",
3184                                   "can't parse", &err_rc);
3185                 cYAML_print_tree2file(stderr, err_rc);
3186                 cYAML_free_tree(err_rc);
3187                 rc = -EINVAL;
3188                 goto err;
3189         }
3190
3191         /* initialize lsa for plain file */
3192         setstripe_args_init(lsa);
3193         lsa->lsa_tgts = osts;
3194
3195         rc = build_layout_from_yaml_node(tree, layout, lsa, NULL);
3196         if (rc) {
3197                 fprintf(stderr, "%s: cannot build layout from YAML file %s.\n",
3198                         progname, template);
3199                 goto err;
3200         }
3201         /* clean clean lsa */
3202         setstripe_args_init(lsa);
3203
3204 err:
3205         if (tree)
3206                 cYAML_free_tree(tree);
3207         return rc;
3208 }
3209
3210 /**
3211  * Get the extension size from the next (SEL) component and extend the
3212  * current component on it. The start of the next component is to be
3213  * adjusted as well.
3214  *
3215  * \param[in] layout    the current layout
3216  * \param[in] start     the start of the current component
3217  * \param[in,out] end   the end of the current component
3218  * \param[in] offset    the offset to adjust the end position to instead of
3219  *                      extension size
3220  *
3221  * \retval 0            - extended successfully
3222  * \retval < 0          - error
3223  */
3224 static int layout_extend_comp(struct llapi_layout *layout,
3225                               uint64_t start, uint64_t *end,
3226                               uint64_t offset)
3227 {
3228         uint64_t size, next_start, next_end;
3229         int rc;
3230
3231         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
3232         if (rc < 0) {
3233                 fprintf(stderr,
3234                         "%s setstripe: cannot move component cursor: %s\n",
3235                         progname, strerror(errno));
3236                 return rc;
3237         }
3238
3239         /*
3240          * Even if the @size will not be used below, this will fail if
3241          * this is not a SEL component - a good confirmation we are
3242          * working on right components.
3243          */
3244         rc = llapi_layout_extension_size_get(layout, &size);
3245         if (rc < 0) {
3246                 fprintf(stderr,
3247                         "%s setstripe: cannot get component ext size: %s\n",
3248                         progname, strerror(errno));
3249                 return rc;
3250         }
3251
3252         rc = llapi_layout_comp_extent_get(layout, &next_start, &next_end);
3253         if (rc) {
3254                 fprintf(stderr, "%s setstripe: cannot get extent: %s\n",
3255                         progname, strerror(errno));
3256                 return rc;
3257         }
3258
3259         next_start += offset ?: size;
3260         rc = llapi_layout_comp_extent_set(layout, next_start, next_end);
3261         if (rc) {
3262                 fprintf(stderr, "%s setstripe: cannot set extent: %s\n",
3263                         progname, strerror(errno));
3264                 return rc;
3265         }
3266
3267         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_PREV);
3268         if (rc < 0) {
3269                 fprintf(stderr,
3270                         "%s setstripe: cannot move component cursor: %s\n",
3271                         progname, strerror(errno));
3272                 return rc;
3273         }
3274
3275         *end += offset ?: size;
3276         rc = llapi_layout_comp_extent_set(layout, start, *end);
3277         if (rc) {
3278                 fprintf(stderr, "%s setstripe: cannot set extent: %s\n",
3279                         progname, strerror(errno));
3280                 return rc;
3281         }
3282
3283         return 0;
3284 }
3285
3286 /**
3287  * In 'lfs setstripe --component-add' mode, we need to fetch the extent
3288  * end of the last component in the existing file, and adjust the
3289  * first extent start of the components to be added accordingly.
3290  *
3291  * In the create mode, we need to check if the first component is an extendable
3292  * SEL component and extend its length to the extension size (first component
3293  * of the PFL file is initialised at the create time, cannot be 0-lenght.
3294  */
3295 static int layout_adjust_first_extent(char *fname, struct llapi_layout *layout,
3296                                       bool comp_add)
3297 {
3298         struct llapi_layout *head;
3299         uint64_t start = 0, prev_end = 0;
3300         uint64_t end;
3301         int rc, ret = 0;
3302
3303         if (!layout || !(comp_add || llapi_layout_is_composite(layout)))
3304                 return 0;
3305
3306         errno = 0;
3307         while (comp_add) {
3308                 head = llapi_layout_get_by_path(fname, 0);
3309                 if (!head) {
3310                         fprintf(stderr,
3311                                 "%s setstripe: cannot read layout from '%s': %s\n",
3312                                 progname, fname, strerror(errno));
3313                         return -EINVAL;
3314                 } else if (errno == ENODATA) {
3315                         /*
3316                          * file without LOVEA, this component-add will be turned
3317                          * into a component-create.
3318                          */
3319                         llapi_layout_free(head);
3320                         ret = -ENODATA;
3321
3322                         /*
3323                          * the new layout will be added to an empty one, it
3324                          * still needs to be adjusted below
3325                          */
3326                         comp_add = 0;
3327                         break;
3328                 } else if (!llapi_layout_is_composite(head)) {
3329                         fprintf(stderr,
3330                                 "%s setstripe: '%s' not a composite file\n",
3331                                 progname, fname);
3332                         llapi_layout_free(head);
3333                         return -EINVAL;
3334                 }
3335
3336                 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
3337                 if (rc) {
3338                         fprintf(stderr,
3339                                 "%s setstripe: cannot get prev extent: %s\n",
3340                                 progname, strerror(errno));
3341                         llapi_layout_free(head);
3342                         return rc;
3343                 }
3344
3345                 llapi_layout_free(head);
3346                 break;
3347         }
3348
3349         /* Make sure we use the first component of the layout to be added. */
3350         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
3351         if (rc < 0) {
3352                 fprintf(stderr,
3353                         "%s setstripe: cannot move component cursor: %s\n",
3354                         progname, strerror(errno));
3355                 return rc;
3356         }
3357
3358         rc = llapi_layout_comp_extent_get(layout, &start, &end);
3359         if (rc) {
3360                 fprintf(stderr, "%s setstripe: cannot get extent: %s\n",
3361                         progname, strerror(errno));
3362                 return rc;
3363         }
3364
3365         if (start == 0 && end == 0) {
3366                 rc = layout_extend_comp(layout, start, &end,
3367                                         comp_add ? prev_end : 0);
3368                 if (rc)
3369                         return rc;
3370         }
3371
3372         if (start > prev_end || end < prev_end) {
3373                 fprintf(stderr,
3374                         "%s setstripe: first extent [%lu, %lu) not adjacent with extent end %lu\n",
3375                         progname, start, end, prev_end);
3376                 return -EINVAL;
3377         }
3378
3379         rc = llapi_layout_comp_extent_set(layout, prev_end, end);
3380         if (rc) {
3381                 fprintf(stderr,
3382                         "%s setstripe: cannot set component extent [%lu, %lu): %s\n",
3383                         progname, prev_end, end, strerror(errno));
3384                 return rc;
3385         }
3386
3387         return ret;
3388 }
3389
3390 static int mirror_adjust_first_extents(struct mirror_args *list)
3391 {
3392         int rc = 0;
3393
3394         if (!list)
3395                 return 0;
3396
3397         while (list) {
3398                 rc = layout_adjust_first_extent(NULL, list->m_layout, false);
3399                 if (rc)
3400                         break;
3401                 list = list->m_next;
3402         }
3403
3404         return rc;
3405 }
3406
3407 static inline bool arg_is_eof(char *arg)
3408 {
3409         return !strncmp(arg, "-1", strlen("-1")) ||
3410                !strncmp(arg, "EOF", strlen("EOF")) ||
3411                !strncmp(arg, "eof", strlen("eof"));
3412 }
3413
3414 /**
3415  * lfs_mirror_alloc() - Allocate a mirror argument structure.
3416  *
3417  * Return: Valid mirror_args pointer on success and
3418  *         NULL if memory allocation fails.
3419  */
3420 static struct mirror_args *lfs_mirror_alloc(void)
3421 {
3422         struct mirror_args *mirror = NULL;
3423
3424         while (1) {
3425                 mirror = calloc(1, sizeof(*mirror));
3426                 if (mirror) {
3427                         mirror->m_inherit = false;
3428                         break;
3429                 }
3430
3431                 sleep(1);
3432         }
3433
3434         return mirror;
3435 }
3436
3437 /**
3438  * lfs_mirror_free() - Free memory allocated for a mirror argument
3439  *                     structure.
3440  * @mirror: Previously allocated mirror argument structure by
3441  *          lfs_mirror_alloc().
3442  *
3443  * Free memory allocated for @mirror.
3444  *
3445  * Return: void.
3446  */
3447 static void lfs_mirror_free(struct mirror_args *mirror)
3448 {
3449         if (mirror->m_layout)
3450                 llapi_layout_free(mirror->m_layout);
3451         free(mirror);
3452 }
3453
3454 /**
3455  * lfs_mirror_list_free() - Free memory allocated for a mirror list.
3456  * @mirror_list: Previously allocated mirror list.
3457  *
3458  * Free memory allocated for @mirror_list.
3459  *
3460  * Return: void.
3461  */
3462 static void lfs_mirror_list_free(struct mirror_args *mirror_list)
3463 {
3464         struct mirror_args *next_mirror = NULL;
3465
3466         while (mirror_list) {
3467                 next_mirror = mirror_list->m_next;
3468                 lfs_mirror_free(mirror_list);
3469                 mirror_list = next_mirror;
3470         }
3471 }
3472
3473 enum {
3474         LFS_SETQUOTA_DELETE = (CHAR_MAX + 1),
3475         LFS_POOL_OPT,
3476         LFS_COMP_COUNT_OPT,
3477         LFS_COMP_START_OPT,
3478         LFS_COMP_FLAGS_OPT,
3479         LFS_COMP_DEL_OPT,
3480         LFS_COMP_SET_OPT,
3481         LFS_COMP_ADD_OPT,
3482         LFS_COMP_NO_VERIFY_OPT,
3483         LFS_PROJID_OPT,
3484         LFS_LAYOUT_FLAGS_OPT, /* used for mirror and foreign flags */
3485         LFS_MIRROR_ID_OPT,
3486         LFS_MIRROR_STATE_OPT,
3487         LFS_LAYOUT_COPY,
3488         LFS_MIRROR_INDEX_OPT,
3489         LFS_LAYOUT_FOREIGN_OPT,
3490         LFS_MODE_OPT,
3491         LFS_NEWERXY_OPT,
3492         LFS_INHERIT_RR_OPT,
3493         LFS_FIND_PERM,
3494         LFS_PRINTF_OPT,
3495         LFS_NO_FOLLOW_OPT,
3496         LFS_HEX_IDX_OPT,
3497         LFS_STATS_OPT,
3498         LFS_STATS_INTERVAL_OPT,
3499         LFS_LINKS_OPT,
3500         LFS_ATTRS_OPT
3501 };
3502
3503 #ifndef LCME_USER_MIRROR_FLAGS
3504 /* The mirror flags can be set by users at creation time. */
3505 #define LCME_USER_MIRROR_FLAGS  (LCME_FL_PREF_RW)
3506 #endif
3507
3508 /* functions */
3509 static int lfs_setstripe_internal(int argc, char **argv,
3510                                   enum setstripe_origin opc)
3511 {
3512         struct lfs_setstripe_args        lsa = { 0 };
3513         struct llapi_stripe_param       *param = NULL;
3514         struct find_param                migrate_mdt_param = {
3515                 .fp_max_depth = -1,
3516                 .fp_mdt_index = -1,
3517         };
3518         char                            *fname;
3519         int                              result = 0;
3520         int                              result2 = 0;
3521         char                            *end;
3522         int                              c;
3523         int                              delete = 0;
3524         unsigned long long               size_units = 1;
3525         bool                             migrate_mode = false;
3526         bool                             migrate_mdt_mode = false;
3527         bool                             setstripe_mode = false;
3528         bool                             migration_block = false;
3529         __u64                            migration_flags = 0;
3530         __u32                            tgts[LOV_MAX_STRIPE_COUNT] = { 0 };
3531         int                              comp_del = 0, comp_set = 0;
3532         int                              comp_add = 0;
3533         __u32                            comp_id = 0;
3534         struct llapi_layout             *layout = NULL;
3535         struct llapi_layout             **lpp = &layout;
3536         bool                             mirror_mode = false;
3537         bool                             has_m_file = false;
3538         __u32                            mirror_count = 0;
3539         enum mirror_flags                mirror_flags = 0;
3540         struct mirror_args              *mirror_list = NULL;
3541         struct mirror_args              *new_mirror = NULL;
3542         struct mirror_args              *last_mirror = NULL;
3543         __u16                            mirror_id = 0;
3544         char                             cmd[PATH_MAX];
3545         bool from_yaml = false;
3546         bool from_copy = false;
3547         char *template = NULL;
3548         bool foreign_mode = false;
3549         char *xattr = NULL;
3550         uint32_t type = LU_FOREIGN_TYPE_NONE, flags = 0;
3551         char *mode_opt = NULL;
3552         mode_t previous_umask = 0;
3553         mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
3554         unsigned long long bandwidth_bytes_sec = 0;
3555         unsigned long long bandwidth_unit = ONE_MB;
3556         long stats_interval_sec = 0;
3557
3558         struct option long_opts[] = {
3559 /* find { .val = '0',   .name = "null",         .has_arg = no_argument }, */
3560 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
3561         /* --block is only valid in migrate mode */
3562         { .val = 'b',   .name = "block",        .has_arg = no_argument },
3563 /* find { .val = 'B',   .name = "btime",        .has_arg = required_argument }*/
3564         { .val = LFS_COMP_ADD_OPT,
3565                         .name = "comp-add",     .has_arg = no_argument },
3566         { .val = LFS_COMP_ADD_OPT,
3567                         .name = "component-add", .has_arg = no_argument },
3568         { .val = LFS_COMP_DEL_OPT,
3569                         .name = "comp-del",     .has_arg = no_argument },
3570         { .val = LFS_COMP_DEL_OPT,
3571                         .name = "component-del", .has_arg = no_argument },
3572         { .val = LFS_COMP_FLAGS_OPT,
3573                         .name = "comp-flags",   .has_arg = required_argument },
3574         { .val = LFS_COMP_FLAGS_OPT,
3575                         .name = "component-flags",
3576                                                 .has_arg = required_argument },
3577         { .val = LFS_COMP_SET_OPT,
3578                         .name = "comp-set",     .has_arg = no_argument },
3579         { .val = LFS_COMP_SET_OPT,
3580                         .name = "component-set",
3581                                                 .has_arg = no_argument},
3582         { .val = LFS_COMP_NO_VERIFY_OPT,
3583                         .name = "no-verify",    .has_arg = no_argument},
3584         { .val = LFS_LAYOUT_FLAGS_OPT,
3585                         .name = "flags",        .has_arg = required_argument},
3586         { .val = LFS_LAYOUT_FOREIGN_OPT,
3587                         .name = "foreign",      .has_arg = optional_argument},
3588         { .val = LFS_MIRROR_ID_OPT,
3589                         .name = "mirror-id",    .has_arg = required_argument},
3590         { .val = LFS_MODE_OPT,
3591                         .name = "mode",         .has_arg = required_argument},
3592         { .val = LFS_LAYOUT_COPY,
3593                         .name = "copy",         .has_arg = required_argument},
3594         { .val = LFS_STATS_OPT,
3595                         .name = "stats",        .has_arg = no_argument},
3596         { .val = LFS_STATS_INTERVAL_OPT,
3597                         .name = "stats-interval",
3598                                                 .has_arg = required_argument},
3599         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument},
3600         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument},
3601         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument},
3602         { .val = 'C',   .name = "overstripe-count",
3603                                                 .has_arg = required_argument},
3604         { .val = 'd',   .name = "delete",       .has_arg = no_argument},
3605         { .val = 'd',   .name = "destroy",      .has_arg = no_argument},
3606         /* used with "lfs migrate -m" */
3607         { .val = 'd',   .name = "directory",    .has_arg = no_argument},
3608         /* --non-direct is only valid in migrate mode */
3609         { .val = 'D',   .name = "non-direct",   .has_arg = no_argument },
3610         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument},
3611         { .val = 'E',   .name = "component-end",
3612                                                 .has_arg = required_argument},
3613         { .val = 'f',   .name = "file",         .has_arg = required_argument },
3614 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
3615 /* find { .val = 'g',   .name = "gid",          .has_arg = no_argument }, */
3616 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
3617         { .val = 'h',   .name = "help",         .has_arg = no_argument },
3618         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument},
3619         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument},
3620         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument},
3621         { .val = 'I',   .name = "comp-id",      .has_arg = required_argument},
3622         { .val = 'I',   .name = "component-id", .has_arg = required_argument},
3623 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
3624         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
3625         { .val = 'm',   .name = "mdt",          .has_arg = required_argument},
3626         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument},
3627         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument},
3628         /* --non-block is only valid in migrate mode */
3629         { .val = 'n',   .name = "non-block",    .has_arg = no_argument },
3630         { .val = 'N',   .name = "mirror-count", .has_arg = optional_argument},
3631         { .val = 'o',   .name = "ost",          .has_arg = required_argument },
3632 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3633         { .val = 'o',   .name = "ost-list",     .has_arg = required_argument },
3634         { .val = 'o',   .name = "ost_list",     .has_arg = required_argument },
3635 #endif
3636         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
3637 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
3638 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
3639 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
3640         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
3641         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
3642 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
3643 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
3644 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
3645 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
3646         /* --verbose is only valid in migrate mode */
3647         { .val = 'v',   .name = "verbose",      .has_arg = no_argument},
3648         { .val = 'W',   .name = "bandwidth",    .has_arg = required_argument },
3649         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
3650 /* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/
3651         { .val = 'y',   .name = "yaml",         .has_arg = required_argument },
3652         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument},
3653         { .val = 'z',   .name = "extension-size", .has_arg = required_argument},
3654         { .name = NULL } };
3655
3656         setstripe_args_init(&lsa);
3657
3658         migrate_mode = (opc == SO_MIGRATE);
3659         mirror_mode = (opc == SO_MIRROR_CREATE || opc == SO_MIRROR_EXTEND);
3660         setstripe_mode = (opc == SO_SETSTRIPE);
3661         if (opc == SO_MIRROR_DELETE) {
3662                 delete = 1;
3663                 mirror_flags = MF_DESTROY;
3664         }
3665
3666         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
3667         progname = cmd;
3668         while ((c = getopt_long(argc, argv,
3669                                 "bc:C:dDE:f:hH:i:I:m:N::no:p:L:s:S:vx:W:y:z:",
3670                                 long_opts, NULL)) >= 0) {
3671                 size_units = 1;
3672                 switch (c) {
3673                 case 0:
3674                         /* Long options. */
3675                         break;
3676                 case LFS_COMP_ADD_OPT:
3677                         comp_add = 1;
3678                         break;
3679                 case LFS_COMP_DEL_OPT:
3680                         comp_del = 1;
3681                         break;
3682                 case LFS_COMP_FLAGS_OPT:
3683                         result = comp_str2flags(optarg, &lsa.lsa_comp_flags,
3684                                                 &lsa.lsa_comp_neg_flags);
3685                         if (result != 0)
3686                                 goto usage_error;
3687                         if (mirror_mode && lsa.lsa_comp_neg_flags) {
3688                                 fprintf(stderr,
3689                                         "%s: inverted flags are not supported\n",
3690                                         progname);
3691                                 goto usage_error;
3692                         }
3693                         break;
3694                 case LFS_COMP_SET_OPT:
3695                         comp_set = 1;
3696                         break;
3697                 case LFS_COMP_NO_VERIFY_OPT:
3698                         mirror_flags |= MF_NO_VERIFY;
3699                         break;
3700                 case LFS_MIRROR_ID_OPT: {
3701                         unsigned long int id;
3702
3703                         errno = 0;
3704                         id = strtoul(optarg, &end, 0);
3705                         if (errno != 0 || *end != '\0' || id == 0 ||
3706                             id > UINT16_MAX) {
3707                                 fprintf(stderr,
3708                                         "%s %s: invalid mirror ID '%s'\n",
3709                                         progname, argv[0], optarg);
3710                                 goto usage_error;
3711                         }
3712
3713                         mirror_id = (__u16)id;
3714                         break;
3715                 }
3716                 case LFS_LAYOUT_FLAGS_OPT: {
3717                         uint32_t neg_flags;
3718
3719                         /* check for numeric flags (foreign and mirror cases) */
3720                         if (setstripe_mode && !mirror_mode && !last_mirror) {
3721                                 errno = 0;
3722                                 flags = strtoul(optarg, &end, 16);
3723                                 if (errno != 0 || *end != '\0' ||
3724                                     flags >= UINT32_MAX) {
3725                                         fprintf(stderr,
3726                                                 "%s %s: invalid hex flags '%s'\n",
3727                                                 progname, argv[0], optarg);
3728                                         return CMD_HELP;
3729                                 }
3730                                 if (!foreign_mode) {
3731                                         fprintf(stderr,
3732                                                 "%s %s: hex flags must be specified with --foreign option\n",
3733                                                 progname, argv[0]);
3734                                         return CMD_HELP;
3735                                 }
3736                                 break;
3737                         }
3738
3739                         if (!mirror_mode || !last_mirror) {
3740                                 fprintf(stderr,
3741                                         "error: %s: --flags must be specified with --mirror-count|-N option\n",
3742                                         progname);
3743                                 goto usage_error;
3744                         }
3745
3746                         result = comp_str2flags(optarg, &last_mirror->m_flags,
3747                                                 &neg_flags);
3748                         if (result != 0)
3749                                 goto usage_error;
3750
3751                         if (neg_flags) {
3752                                 fprintf(stderr,
3753                                         "%s: inverted flags are not supported\n",
3754                                         progname);
3755                                 result = -EINVAL;
3756                                 goto usage_error;
3757                         }
3758                         if (last_mirror->m_flags & ~LCME_USER_MIRROR_FLAGS) {
3759                                 fprintf(stderr,
3760                                         "%s: unsupported mirror flags: %s\n",
3761                                         progname, optarg);
3762                                 result = -EINVAL;
3763                                 goto error;
3764                         }
3765                         break;
3766                 }
3767                 case LFS_LAYOUT_FOREIGN_OPT:
3768                         if (optarg) {
3769                                 /* check pure numeric */
3770                                 type = strtoul(optarg, &end, 0);
3771                                 if (*end) {
3772                                         /* check name */
3773                                         type = check_foreign_type_name(optarg);
3774                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
3775                                                 fprintf(stderr,
3776                                                         "%s %s: unrecognized foreign type '%s'\n",
3777                                                         progname, argv[0],
3778                                                         optarg);
3779                                                 return CMD_HELP;
3780                                         }
3781                                 } else if (type >= UINT32_MAX) {
3782                                         fprintf(stderr,
3783                                                 "%s %s: invalid foreign type '%s'\n",
3784                                                 progname, argv[0], optarg);
3785                                         return CMD_HELP;
3786                                 }
3787                         }
3788                         foreign_mode = true;
3789                         break;
3790                 case LFS_MODE_OPT:
3791                         mode_opt = optarg;
3792                         if (mode_opt) {
3793                                 mode = strtoul(mode_opt, &end, 8);
3794                                 if (*end != '\0') {
3795                                         fprintf(stderr,
3796                                                 "%s %s: bad mode '%s'\n",
3797                                                 progname, argv[0], mode_opt);
3798                                         return CMD_HELP;
3799                                 }
3800                                 previous_umask = umask(0);
3801                         }
3802                         break;
3803                 case LFS_LAYOUT_COPY:
3804                         from_copy = true;
3805                         template = optarg;
3806                         break;
3807                 case LFS_STATS_OPT:
3808                         stats_interval_sec = 5;
3809                         break;
3810                 case LFS_STATS_INTERVAL_OPT:
3811                         stats_interval_sec = strtol(optarg, &end, 0);
3812                         if (stats_interval_sec == 0 && errno) {
3813                                 fprintf(stderr,
3814                                         "%s %s: invalid stats interval %s\n",
3815                                         progname, argv[0], optarg);
3816                                 goto usage_error;
3817                         }
3818                         break;
3819                 case 'b':
3820                         if (!migrate_mode) {
3821                                 fprintf(stderr,
3822                                         "%s %s: -b|--block valid only for migrate command\n",
3823                                         progname, argv[0]);
3824                                 goto usage_error;
3825                         }
3826                         migration_block = true;
3827                         break;
3828                 case 'C':
3829                         if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) {
3830                                 fprintf(stderr,
3831                                         "%s %s: -C|--overstripe-count incompatible with DoM layout\n",
3832                                         progname, argv[0]);
3833                                 goto usage_error;
3834                         }
3835                         lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
3836                         fallthrough;
3837                 case 'c':
3838                         errno = 0;
3839                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
3840                         if (errno != 0 || *end != '\0'|| optarg == end ||
3841                             lsa.lsa_stripe_count < -1 ||
3842                             lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
3843                                 fprintf(stderr,
3844                                         "%s %s: invalid stripe count '%s'\n",
3845                                         progname, argv[0], optarg);
3846                                 goto usage_error;
3847                         }
3848
3849                         if (lsa.lsa_stripe_count == -1)
3850                                 lsa.lsa_stripe_count = LLAPI_LAYOUT_WIDE;
3851                         break;
3852                 case 'd':
3853                         if (migrate_mode) {
3854                                 migrate_mdt_param.fp_max_depth = 1;
3855                         } else {
3856                                 /* delete the default striping pattern */
3857                                 delete = 1;
3858                                 if (opc == SO_MIRROR_SPLIT) {
3859                                         if (has_m_file) {
3860                                                 fprintf(stderr,
3861                                                       "%s %s: -d cannot used with -f\n",
3862                                                         progname, argv[0]);
3863                                                 goto usage_error;
3864                                         }
3865                                         mirror_flags |= MF_DESTROY;
3866                                 }
3867                         }
3868                         break;
3869                 case 'D':
3870                         if (!migrate_mode) {
3871                                 fprintf(stderr,
3872                                         "%s %s: -D|--non-direct is valid only for migrate command\n",
3873                                         progname, argv[0]);
3874                                 goto usage_error;
3875                         }
3876                         migration_flags |= LLAPI_MIGRATION_NONDIRECT;
3877                         break;
3878                 case 'E':
3879                         if (lsa.lsa_comp_end != 0) {
3880                                 result = comp_args_to_layout(lpp, &lsa, true);
3881                                 if (result) {
3882                                         fprintf(stderr, "%s: invalid layout\n",
3883                                                 progname);
3884                                         goto usage_error;
3885                                 }
3886
3887                                 setstripe_args_init_inherit(&lsa);
3888                         }
3889
3890                         if (arg_is_eof(optarg)) {
3891                                 lsa.lsa_comp_end = LUSTRE_EOF;
3892                         } else {
3893                                 result = llapi_parse_size(optarg,
3894                                                           &lsa.lsa_comp_end,
3895                                                           &size_units, 0);
3896                                 /* assume units of KB if too small */
3897                                 if (lsa.lsa_comp_end < 4096)
3898                                         lsa.lsa_comp_end *= 1024;
3899                                 if (result ||
3900                                     lsa.lsa_comp_end & (LOV_MIN_STRIPE_SIZE - 1)) {
3901                                         fprintf(stderr,
3902                                                 "%s %s: invalid component end '%s'\n",
3903                                                 progname, argv[0], optarg);
3904                                         goto usage_error;
3905                                 }
3906                         }
3907                         break;
3908                 case 'H':
3909                         if (!migrate_mode) {
3910                                 fprintf(stderr,
3911                                         "--mdt-hash is valid only for migrate command\n");
3912                                 return CMD_HELP;
3913                         }
3914
3915                         lsa.lsa_pattern = check_hashtype(optarg);
3916                         if (lsa.lsa_pattern == 0) {
3917                                 fprintf(stderr,
3918                                         "%s %s: bad stripe hash type '%s'\n",
3919                                         progname, argv[0], optarg);
3920                                 return CMD_HELP;
3921                         }
3922                         break;
3923                 case 'i':
3924                         errno = 0;
3925                         lsa.lsa_stripe_off = strtol(optarg, &end, 0);
3926                         if (errno != 0 || *end != '\0' || optarg == end ||
3927                             lsa.lsa_stripe_off < -1 ||
3928                             lsa.lsa_stripe_off > LOV_V1_INSANE_STRIPE_COUNT) {
3929                                 fprintf(stderr,
3930                                         "%s %s: invalid stripe offset '%s'\n",
3931                                         progname, argv[0], optarg);
3932                                 goto usage_error;
3933                         }
3934                         if (lsa.lsa_stripe_off == -1)
3935                                 lsa.lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
3936                         break;
3937                 case 'I':
3938                         comp_id = strtoul(optarg, &end, 0);
3939                         if (*end != '\0' || comp_id == 0 ||
3940                             comp_id > LCME_ID_MAX) {
3941                                 fprintf(stderr,
3942                                         "%s %s: invalid component ID '%s'\n",
3943                                         progname, argv[0], optarg);
3944                                 goto usage_error;
3945                         }
3946                         break;
3947                 case 'f':
3948                         if (opc != SO_MIRROR_EXTEND && opc != SO_MIRROR_SPLIT) {
3949                                 fprintf(stderr,
3950                                         "error: %s: invalid option: %s\n",
3951                                         progname, argv[optopt + 1]);
3952                                 goto usage_error;
3953                         }
3954                         if (opc == SO_MIRROR_EXTEND) {
3955                                 if (!last_mirror) {
3956                                         fprintf(stderr,
3957                                 "error: %s: '-N' must exist in front of '%s'\n",
3958                                                 progname, argv[optopt + 1]);
3959                                         goto usage_error;
3960                                 }
3961                                 last_mirror->m_file = optarg;
3962                                 last_mirror->m_count = 1;
3963                         } else {
3964                                 /* mirror split */
3965                                 if (!mirror_list)
3966                                         mirror_list = lfs_mirror_alloc();
3967                                 mirror_list->m_file = optarg;
3968                         }
3969                         has_m_file = true;
3970                         break;
3971                 case 'L':
3972                         if (strcmp(argv[optind - 1], "mdt") == 0) {
3973                                 /* Can be only the first component */
3974                                 if (layout) {
3975                                         result = -EINVAL;
3976                                         fprintf(stderr,
3977                                                 "error: 'mdt' layout can be only the first one\n");
3978                                         goto error;
3979                                 }
3980                                 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
3981                                         result = -EFBIG;
3982                                         fprintf(stderr,
3983                                                 "error: 'mdt' layout size is too big\n");
3984                                         goto error;
3985                                 }
3986                                 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
3987                                 lsa.lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
3988                         } else if (strcmp(argv[optind - 1], "raid0") != 0) {
3989                                 result = -EINVAL;
3990                                 fprintf(stderr,
3991                                         "error: layout '%s' is unknown, supported layouts are: 'mdt', 'raid0'\n",
3992                                         argv[optind]);
3993                                 goto error;
3994                         }
3995                         break;
3996                 case 'm':
3997                         if (!migrate_mode) {
3998                                 fprintf(stderr,
3999                                         "%s %s: -m|--mdt-index is valid only for migrate command\n",
4000                                         progname, argv[0]);
4001                                 goto usage_error;
4002                         }
4003                         migrate_mdt_mode = true;
4004                         lsa.lsa_nr_tgts = parse_targets(tgts,
4005                                                 sizeof(tgts) / sizeof(__u32),
4006                                                 lsa.lsa_nr_tgts, optarg, NULL);
4007                         if (lsa.lsa_nr_tgts < 0) {
4008                                 fprintf(stderr,
4009                                         "%s: invalid MDT target(s) '%s'\n",
4010                                         progname, optarg);
4011                                 goto usage_error;
4012                         }
4013
4014                         lsa.lsa_tgts = tgts;
4015                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4016                                 lsa.lsa_stripe_off = tgts[0];
4017                         break;
4018                 case 'n':
4019                         if (!migrate_mode) {
4020                                 fprintf(stderr,
4021                                         "%s %s: -n|--non-block valid only for migrate command\n",
4022                                         progname, argv[0]);
4023                                 goto usage_error;
4024                         }
4025                         migration_flags |= LLAPI_MIGRATION_NONBLOCK;
4026                         break;
4027                 case 'N':
4028                         if (opc == SO_SETSTRIPE) {
4029                                 opc = SO_MIRROR_CREATE;
4030                                 mirror_mode = true;
4031                         }
4032                         mirror_count = 1;
4033                         if (optarg) {
4034                                 errno = 0;
4035                                 mirror_count = strtoul(optarg, &end, 0);
4036                                 if (errno != 0 || *end != '\0' ||
4037                                     mirror_count == 0 ||
4038                                     mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
4039                                         fprintf(stderr,
4040                                                 "error: %s: bad mirror count: %s\n",
4041                                                 progname, optarg);
4042                                         result = -EINVAL;
4043                                         goto error;
4044                                 }
4045                         }
4046
4047                         new_mirror = lfs_mirror_alloc();
4048                         new_mirror->m_count = mirror_count;
4049
4050                         if (!mirror_list)
4051                                 mirror_list = new_mirror;
4052
4053                         if (last_mirror) {
4054                                 /* wrap up last mirror */
4055                                 if (!setstripe_args_specified(&lsa))
4056                                         last_mirror->m_inherit = true;
4057                                 if (lsa.lsa_comp_end == 0)
4058                                         lsa.lsa_comp_end = LUSTRE_EOF;
4059
4060                                 result = comp_args_to_layout(lpp, &lsa, true);
4061                                 if (result) {
4062                                         lfs_mirror_free(new_mirror);
4063                                         goto error;
4064                                 }
4065
4066                                 setstripe_args_init_inherit(&lsa);
4067
4068                                 last_mirror->m_next = new_mirror;
4069                         }
4070
4071                         last_mirror = new_mirror;
4072                         lpp = &last_mirror->m_layout;
4073                         break;
4074                 case 'o':
4075 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
4076                         if (strcmp(argv[optind - 1], "--ost-list") == 0)
4077                                 fprintf(stderr,
4078                                         "warning: '--ost-list' is deprecated, use '--ost' instead\n");
4079 #endif
4080                         if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) {
4081                                 fprintf(stderr,
4082                                         "%s %s: -o|--ost incompatible with DoM layout\n",
4083                                         progname, argv[0]);
4084                                 goto usage_error;
4085                         }
4086                         /*
4087                          * -o allows overstriping, and must note it because
4088                          * parse_targets is shared with MDT striping, which
4089                          * does not allow duplicates
4090                          */
4091                         lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
4092                         lsa.lsa_nr_tgts = parse_targets(tgts,
4093                                                 sizeof(tgts) / sizeof(__u32),
4094                                                 lsa.lsa_nr_tgts, optarg,
4095                                                 &lsa.lsa_pattern);
4096                         if (lsa.lsa_nr_tgts < 0) {
4097                                 fprintf(stderr,
4098                                         "%s %s: invalid OST target(s) '%s'\n",
4099                                         progname, argv[0], optarg);
4100                                 goto usage_error;
4101                         }
4102
4103                         lsa.lsa_tgts = tgts;
4104                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4105                                 lsa.lsa_stripe_off = tgts[0];
4106                         break;
4107                 case 'p':
4108                         if (!optarg)
4109                                 goto usage_error;
4110
4111                         if (optarg[0] == '\0' || lov_pool_is_inherited(optarg))
4112                                 lsa.lsa_pool_name = NULL;
4113                         else
4114                                 lsa.lsa_pool_name = optarg;
4115                         break;
4116                 case 'S':
4117                         result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
4118                                                   &size_units, 0);
4119                         /* assume units of KB if too small to be valid */
4120                         if (lsa.lsa_stripe_size < 4096)
4121                                 lsa.lsa_stripe_size *= 1024;
4122                         if (result ||
4123                             lsa.lsa_stripe_size & (LOV_MIN_STRIPE_SIZE - 1)) {
4124                                 fprintf(stderr,
4125                                         "%s %s: invalid stripe size '%s'\n",
4126                                         progname, argv[0], optarg);
4127                                 goto usage_error;
4128                         }
4129                         break;
4130                 case 'v':
4131                         if (!migrate_mode) {
4132                                 fprintf(stderr,
4133                                         "%s %s: -v|--verbose valid only for migrate command\n",
4134                                         progname, argv[0]);
4135                                 goto usage_error;
4136                         }
4137                         migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
4138                         migration_flags = LLAPI_MIGRATION_VERBOSE;
4139                         break;
4140                 case 'x':
4141                         xattr = optarg;
4142                         break;
4143                 case 'W':
4144                         if (!migrate_mode && !mirror_mode) {
4145                                 fprintf(stderr,
4146                                         "--bandwidth is valid only for migrate and mirror mode\n");
4147                                 goto error;
4148                         }
4149                         if (llapi_parse_size(optarg, &bandwidth_bytes_sec,
4150                                              &bandwidth_unit, 0) < 0) {
4151                                 fprintf(stderr,
4152                                         "error: %s: bad value for bandwidth '%s'\n",
4153                                         argv[0], optarg);
4154                                 goto error;
4155                         }
4156                         break;
4157                 case 'y':
4158                         from_yaml = true;
4159                         template = optarg;
4160                         break;
4161                 case 'z':
4162                         result = llapi_parse_size(optarg,
4163                                                   &lsa.lsa_extension_size,
4164                                                   &size_units, 0);
4165                         if (result) {
4166                                 fprintf(stderr,
4167                                         "%s %s: invalid extension size '%s'\n",
4168                                         progname, argv[0], optarg);
4169                                 goto usage_error;
4170                         }
4171
4172                         lsa.lsa_extension_comp = true;
4173                         break;
4174                 default:
4175                         fprintf(stderr, "%s: unrecognized option '%s'\n",
4176                                 progname, argv[optind - 1]);
4177                 case 'h':
4178                         goto usage_error;
4179                 }
4180         }
4181
4182         fname = argv[optind];
4183
4184         if (optind == argc) {
4185                 fprintf(stderr, "%s %s: FILE must be specified\n",
4186                         progname, argv[0]);
4187                 goto usage_error;
4188         }
4189
4190         /* lfs migrate $filename should keep the file's layout by default */
4191         if (migrate_mode && !layout && !from_yaml &&
4192             !setstripe_args_specified(&lsa) && !lsa.lsa_pool_name)
4193                 from_copy = true;
4194
4195         if (xattr && !foreign_mode) {
4196                 /*
4197                  * only print a warning as this is harmless and will be ignored
4198                  */
4199                 fprintf(stderr,
4200                         "%s %s: xattr has been specified for non-foreign layout\n",
4201                         progname, argv[0]);
4202         } else if (foreign_mode && !xattr) {
4203                 fprintf(stderr,
4204                         "%s %s: xattr must be provided in foreign mode\n",
4205                         progname, argv[0]);
4206                 goto usage_error;
4207         }
4208
4209         if (foreign_mode && (!setstripe_mode || comp_add | comp_del ||
4210             comp_set || comp_id || delete || from_copy ||
4211             setstripe_args_specified(&lsa) || lsa.lsa_nr_tgts ||
4212             lsa.lsa_tgts)) {
4213                 fprintf(stderr,
4214                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
4215                         progname, argv[0]);
4216                 return CMD_HELP;
4217         }
4218
4219         if (mirror_mode && mirror_count == 0) {
4220                 fprintf(stderr,
4221                         "error: %s: --mirror-count|-N option is required\n",
4222                         progname);
4223                 result = -EINVAL;
4224                 goto error;
4225         }
4226
4227         if (mirror_mode) {
4228                 if (!setstripe_args_specified(&lsa))
4229                         last_mirror->m_inherit = true;
4230                 if (lsa.lsa_comp_end == 0)
4231                         lsa.lsa_comp_end = LUSTRE_EOF;
4232         }
4233
4234         if (lsa.lsa_comp_end != 0) {
4235                 result = comp_args_to_layout(lpp, &lsa, true);
4236                 if (result) {
4237                         fprintf(stderr, "error: %s: invalid layout\n",
4238                                 progname);
4239                         result = -EINVAL;
4240                         goto error;
4241                 }
4242         }
4243
4244         if (mirror_flags & MF_NO_VERIFY) {
4245                 if (opc != SO_MIRROR_EXTEND) {
4246                         fprintf(stderr,
4247                                 "error: %s: --no-verify is valid only for lfs mirror extend command\n",
4248                                 progname);
4249                         result = -EINVAL;
4250                         goto error;
4251                 } else if (!has_m_file) {
4252                         fprintf(stderr,
4253                                 "error: %s: --no-verify must be specified with -f <victim_file> option\n",
4254                                 progname);
4255                         result = -EINVAL;
4256                         goto error;
4257                 }
4258         }
4259
4260         if (comp_set && !comp_id && !lsa.lsa_pool_name) {
4261                 fprintf(stderr,
4262                         "%s %s: --component-set doesn't have component-id set\n",
4263                         progname, argv[0]);
4264                 goto usage_error;
4265         }
4266
4267         if ((delete + comp_set + comp_del + comp_add) > 1) {
4268                 fprintf(stderr,
4269                         "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
4270                         progname, argv[0]);
4271                 goto usage_error;
4272         }
4273
4274         if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
4275                        lsa.lsa_comp_flags != 0 || layout != NULL)) {
4276                 fprintf(stderr,
4277                         "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
4278                         progname, argv[0]);
4279                 goto usage_error;
4280         }
4281
4282         if ((comp_set || comp_del) &&
4283             (setstripe_args_specified(&lsa) || layout != NULL)) {
4284                 fprintf(stderr,
4285                         "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
4286                         progname, argv[0]);
4287                 goto usage_error;
4288         }
4289
4290         if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
4291                 fprintf(stderr,
4292                         "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
4293                         progname, argv[0]);
4294                 goto usage_error;
4295         }
4296
4297         if (comp_add || comp_del) {
4298                 struct stat st;
4299
4300                 result = lstat(fname, &st);
4301                 if (result == 0 && S_ISDIR(st.st_mode)) {
4302                         fprintf(stderr,
4303                                 "%s setstripe: cannot use --component-add or --component-del for directory\n",
4304                                 progname);
4305                         goto usage_error;
4306                 }
4307
4308                 if (mirror_mode) {
4309                         fprintf(stderr,
4310                                 "error: %s: can't use --component-add or --component-del for mirror operation\n",
4311                                 progname);
4312                         goto usage_error;
4313                 }
4314         }
4315
4316         if (comp_add) {
4317                 if (!layout) {
4318                         fprintf(stderr,
4319                                 "%s %s: option -E must be specified with --component-add\n",
4320                                 progname, argv[0]);
4321                         goto usage_error;
4322                 }
4323         }
4324
4325         if (from_yaml && from_copy) {
4326                 fprintf(stderr,
4327                         "%s: can't specify --yaml and --copy together\n",
4328                         progname);
4329                 goto error;
4330         }
4331
4332         if ((from_yaml || from_copy) &&
4333             (setstripe_args_specified(&lsa) || layout != NULL)) {
4334                 fprintf(stderr,
4335                         "error: %s: can't specify --yaml or --copy with -c, -S, -i, -o, -p or -E options.\n",
4336                         argv[0]);
4337                 goto error;
4338         }
4339
4340         if ((migration_flags & LLAPI_MIGRATION_NONBLOCK) && migration_block) {
4341                 fprintf(stderr,
4342                         "%s %s: options --non-block and --block are mutually exclusive\n",
4343                         progname, argv[0]);
4344                 goto usage_error;
4345         }
4346
4347         if (!comp_del && !comp_set && opc != SO_MIRROR_SPLIT &&
4348             opc != SO_MIRROR_DELETE && comp_id != 0) {
4349                 fprintf(stderr,
4350                         "%s: option -I can only be used with --component-del or --component-set or lfs mirror split\n",
4351                         progname);
4352                 goto usage_error;
4353         }
4354
4355         if (migrate_mdt_mode) {
4356                 struct lmv_user_md *lmu;
4357
4358                 /* initialize migrate mdt parameters */
4359                 lmu = calloc(1, lmv_user_md_size(lsa.lsa_nr_tgts,
4360                                                  LMV_USER_MAGIC_SPECIFIC));
4361                 if (!lmu) {
4362                         fprintf(stderr,
4363                                 "%s %s: cannot allocate memory for lmv_user_md: %s\n",
4364                                 progname, argv[0], strerror(ENOMEM));
4365                         result = -ENOMEM;
4366                         goto error;
4367                 }
4368                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
4369                         lmu->lum_stripe_count = lsa.lsa_stripe_count;
4370                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT) {
4371                         fprintf(stderr,
4372                                 "%s %s: migrate should specify MDT index\n",
4373                                 progname, argv[0]);
4374                         free(lmu);
4375                         goto usage_error;
4376                 }
4377                 lmu->lum_stripe_offset = lsa.lsa_stripe_off;
4378                 if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
4379                         lmu->lum_hash_type = lsa.lsa_pattern;
4380                 else
4381                         lmu->lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
4382                 if (lsa.lsa_pool_name) {
4383                         strncpy(lmu->lum_pool_name, lsa.lsa_pool_name,
4384                                 sizeof(lmu->lum_pool_name) - 1);
4385                         lmu->lum_pool_name[sizeof(lmu->lum_pool_name) - 1] = 0;
4386                 }
4387                 if (lsa.lsa_nr_tgts > 1) {
4388                         int i;
4389
4390                         if (lsa.lsa_stripe_count > 0 &&
4391                             lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
4392                             lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
4393                                 fprintf(stderr,
4394                                         "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
4395                                         progname, lsa.lsa_stripe_count,
4396                                         lsa.lsa_nr_tgts);
4397                                 free(lmu);
4398                                 goto usage_error;
4399                         }
4400
4401                         lmu->lum_magic = LMV_USER_MAGIC_SPECIFIC;
4402                         lmu->lum_stripe_count = lsa.lsa_nr_tgts;
4403                         for (i = 0; i < lsa.lsa_nr_tgts; i++)
4404                                 lmu->lum_objects[i].lum_mds = lsa.lsa_tgts[i];
4405                 } else {
4406                         lmu->lum_magic = LMV_USER_MAGIC;
4407                 }
4408
4409                 migrate_mdt_param.fp_lmv_md = lmu;
4410                 migrate_mdt_param.fp_migrate = 1;
4411         } else if (!layout) {
4412                 if (lsa_args_stripe_count_check(&lsa))
4413                         goto usage_error;
4414
4415                 /* initialize stripe parameters */
4416                 param = calloc(1, offsetof(typeof(*param),
4417                                lsp_osts[lsa.lsa_nr_tgts]));
4418                 if (!param) {
4419                         fprintf(stderr,
4420                                 "%s %s: cannot allocate memory for parameters: %s\n",
4421                                 progname, argv[0], strerror(ENOMEM));
4422                         result = -ENOMEM;
4423                         goto error;
4424                 }
4425
4426                 if (lsa.lsa_stripe_size != LLAPI_LAYOUT_DEFAULT)
4427                         param->lsp_stripe_size = lsa.lsa_stripe_size;
4428                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
4429                         if (lsa.lsa_stripe_count == LLAPI_LAYOUT_WIDE)
4430                                 param->lsp_stripe_count = -1;
4431                         else
4432                                 param->lsp_stripe_count = lsa.lsa_stripe_count;
4433                 }
4434                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4435                         param->lsp_stripe_offset = -1;
4436                 else
4437                         param->lsp_stripe_offset = lsa.lsa_stripe_off;
4438                 param->lsp_stripe_pattern =
4439                                 llapi_pattern_to_lov(lsa.lsa_pattern);
4440                 if (param->lsp_stripe_pattern == EINVAL) {
4441                         fprintf(stderr, "error: %s: invalid stripe pattern\n",
4442                                 argv[0]);
4443                         free(param);
4444                         goto usage_error;
4445                 }
4446                 param->lsp_pool = lsa.lsa_pool_name;
4447                 param->lsp_is_specific = false;
4448
4449                 if (lsa.lsa_nr_tgts > 0) {
4450                         param->lsp_is_specific = true;
4451                         param->lsp_stripe_count = lsa.lsa_nr_tgts;
4452                         memcpy(param->lsp_osts, tgts,
4453                                sizeof(*tgts) * lsa.lsa_nr_tgts);
4454                 }
4455         }
4456
4457         if (from_yaml) {
4458                 /* generate a layout from a YAML template */
4459                 result = lfs_comp_create_from_yaml(template, &layout,
4460                                                    &lsa, tgts);
4461                 if (result) {
4462                         fprintf(stderr,
4463                                 "error: %s: can't create composite layout from template file %s\n",
4464                                 argv[0], template);
4465                         goto error;
4466                 }
4467         }
4468
4469         if (layout != NULL || mirror_list != NULL) {
4470                 if (mirror_list)
4471                         result = mirror_adjust_first_extents(mirror_list);
4472                 else
4473                         result = layout_adjust_first_extent(fname, layout,
4474                                                             comp_add);
4475                 if (result == -ENODATA)
4476                         comp_add = 0;
4477                 else if (result != 0) {
4478                         fprintf(stderr, "error: %s: invalid layout\n",
4479                                 progname);
4480                         goto error;
4481                 }
4482         }
4483
4484         for (fname = argv[optind]; (optind < argc) && (fname != NULL);
4485              fname = argv[++optind]) {
4486                 if (from_copy) {
4487                         layout = llapi_layout_get_by_path(template ?: fname, 0);
4488                         if (!layout) {
4489                                 fprintf(stderr,
4490                                         "%s: can't create composite layout from file %s: %s\n",
4491                                         progname, template ?: fname,
4492                                         strerror(errno));
4493                                 result = -errno;
4494                                 goto error;
4495                         }
4496                 }
4497
4498                 if (migrate_mdt_mode) {
4499                         result = llapi_migrate_mdt(fname, &migrate_mdt_param);
4500                 } else if (migrate_mode) {
4501                         if (from_copy) {
4502                                 /*
4503                                  * Strip the source layout of specific
4504                                  * OST object/index values.
4505                                  */
4506                                 result = llapi_layout_ost_index_set(layout, 0,
4507                                                 LLAPI_LAYOUT_DEFAULT);
4508                                 if (result) {
4509                                         fprintf(stderr,
4510                                                 "%s: set default ost index failed: %s\n",
4511                                                 progname, strerror(errno));
4512                                         result = -errno;
4513                                         goto error;
4514                                 }
4515                         }
4516
4517                         result = lfs_migrate(fname, migration_flags, param,
4518                                              layout, bandwidth_bytes_sec,
4519                                              stats_interval_sec);
4520                 } else if (comp_set != 0) {
4521                         result = lfs_component_set(fname, comp_id,
4522                                                    lsa.lsa_pool_name,
4523                                                    lsa.lsa_comp_flags,
4524                                                    lsa.lsa_comp_neg_flags);
4525                 } else if (comp_del != 0) {
4526                         result = lfs_component_del(fname, comp_id,
4527                                                    lsa.lsa_comp_flags,
4528                                                    lsa.lsa_comp_neg_flags);
4529                 } else if (comp_add != 0) {
4530                         result = lfs_component_add(fname, layout);
4531                 } else if (opc == SO_MIRROR_CREATE) {
4532                         result = mirror_create(fname, mirror_list);
4533                 } else if (opc == SO_MIRROR_EXTEND) {
4534                         result = mirror_extend(fname, mirror_list,
4535                                                mirror_flags,
4536                                                bandwidth_bytes_sec,
4537                                                stats_interval_sec);
4538                 } else if (opc == SO_MIRROR_SPLIT || opc == SO_MIRROR_DELETE) {
4539                         if (!mirror_id && !comp_id && !lsa.lsa_pool_name) {
4540                                 fprintf(stderr,
4541                                         "%s: no mirror id, component id, or pool name specified to delete from '%s'\n",
4542                                         progname, fname);
4543                                 goto usage_error;
4544                         }
4545                         if (lsa.lsa_pool_name)
4546                                 mirror_flags |= MF_COMP_POOL;
4547                         else if (mirror_id != 0)
4548                                 comp_id = mirror_id;
4549                         else
4550                                 mirror_flags |= MF_COMP_ID;
4551                         if (has_m_file && !strcmp(fname, mirror_list->m_file)) {
4552                                 fprintf(stderr,
4553                                         "%s: the file specified by -f cannot be same as the source file '%s'\n",
4554                                         progname, fname);
4555                                 goto usage_error;
4556                         }
4557                         result = mirror_split(fname, comp_id, lsa.lsa_pool_name,
4558                                               mirror_flags,
4559                                               has_m_file ? mirror_list->m_file :
4560                                               NULL);
4561                 } else if (layout) {
4562                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
4563                                                       mode, layout);
4564                         if (result >= 0) {
4565                                 close(result);
4566                                 result = 0;
4567                         }
4568                 } else if (foreign_mode) {
4569                         result = llapi_file_create_foreign(fname, mode, type,
4570                                                            flags, xattr);
4571                         if (result >= 0) {
4572                                 close(result);
4573                                 result = 0;
4574                         }
4575                 } else {
4576                         result = llapi_file_open_param(fname,
4577                                                        O_CREAT | O_WRONLY,
4578                                                        mode, param);
4579                         if (result >= 0) {
4580                                 close(result);
4581                                 result = 0;
4582                         }
4583                 }
4584                 if (result) {
4585                         /* Save the first error encountered. */
4586                         if (result2 == 0)
4587                                 result2 = result;
4588                         continue;
4589                 }
4590         }
4591
4592         if (mode_opt)
4593                 umask(previous_umask);
4594
4595         free(param);
4596         free(migrate_mdt_param.fp_lmv_md);
4597         llapi_layout_free(layout);
4598         lfs_mirror_list_free(mirror_list);
4599         return result2;
4600 usage_error:
4601         result = CMD_HELP;
4602 error:
4603         llapi_layout_free(layout);
4604         lfs_mirror_list_free(mirror_list);
4605         return result;
4606 }
4607
4608 static int lfs_poollist(int argc, char **argv)
4609 {
4610         if (argc != 2)
4611                 return CMD_HELP;
4612
4613         return llapi_poollist(argv[1]);
4614 }
4615
4616 #define FP_DEFAULT_TIME_MARGIN (24 * 60 * 60)
4617 static int set_time(struct find_param *param, time_t *time, time_t *set,
4618                     char *str)
4619 {
4620         long long t = 0;
4621         int sign = 0;
4622         char *endptr = "AD";
4623         char *timebuf;
4624
4625         if (str[0] == '+')
4626                 sign = 1;
4627         else if (str[0] == '-')
4628                 sign = -1;
4629
4630         if (sign)
4631                 str++;
4632
4633         for (timebuf = str; *endptr && *(endptr + 1); timebuf = endptr + 1) {
4634                 long long val = strtoll(timebuf, &endptr, 0);
4635                 int unit = 1;
4636
4637                 switch (*endptr) {
4638                 case  'y':
4639                         unit *= 52; /* 52 weeks + 1 day below */
4640                         fallthrough;
4641                 case  'w':
4642                         unit *= 7;
4643                         if (param->fp_time_margin == FP_DEFAULT_TIME_MARGIN)
4644                                 param->fp_time_margin *= (1 + unit / 52);
4645                         unit += (*endptr == 'y'); /* +1 day for 365 days/year */
4646                         fallthrough;
4647                 case '\0': /* days are default unit if none used */
4648                         fallthrough;
4649                 case  'd':
4650                         unit *= 24;
4651                         fallthrough;
4652                 case  'h':
4653                         unit *= 60;
4654                         fallthrough;
4655                 case  'm':
4656                         unit *= 60;
4657                         fallthrough;
4658                 case  's':
4659                         break;
4660                         /* don't need to multiply by 1 for seconds */
4661                 default:
4662                         fprintf(stderr,
4663                                 "%s find: bad time string '%s': %s\n",
4664                                 progname, timebuf, strerror(EINVAL));
4665                         return INT_MAX;
4666                 }
4667
4668                 if (param->fp_time_margin == 0 ||
4669                     (*endptr && unit < param->fp_time_margin))
4670                         param->fp_time_margin = unit;
4671
4672                 t += val * unit;
4673         }
4674         if (*time < t) {
4675                 if (sign != 0)
4676                         str--;
4677                 fprintf(stderr, "%s find: bad time '%s': too large\n",
4678                         progname, str);
4679                 return INT_MAX;
4680         }
4681
4682         *set = *time - t;
4683
4684         return sign;
4685 }
4686
4687 static int str2quotaid(__u32 *id, const char *arg)
4688 {
4689         unsigned long int projid_tmp = 0;
4690         char *endptr = NULL;
4691
4692         projid_tmp = strtoul(arg, &endptr, 10);
4693         if (*endptr != '\0')
4694                 return -EINVAL;
4695         /* UINT32_MAX is not allowed - see projid_valid()/INVALID_PROJID */
4696         if (projid_tmp >= UINT32_MAX)
4697                 return -ERANGE;
4698
4699         *id = projid_tmp;
4700         return 0;
4701 }
4702
4703 static int name2uid(unsigned int *id, const char *name)
4704 {
4705         struct passwd *passwd;
4706
4707         passwd = getpwnam(name);
4708         if (!passwd)
4709                 return -ENOENT;
4710         *id = passwd->pw_uid;
4711
4712         return 0;
4713 }
4714
4715 static int name2gid(unsigned int *id, const char *name)
4716 {
4717         struct group *group;
4718
4719         group = getgrnam(name);
4720         if (!group)
4721                 return -ENOENT;
4722         *id = group->gr_gid;
4723
4724         return 0;
4725 }
4726
4727 static inline int name2projid(unsigned int *id, const char *name)
4728 {
4729         return -ENOTSUP;
4730 }
4731
4732 static int uid2name(char **name, unsigned int id)
4733 {
4734         struct passwd *passwd;
4735
4736         passwd = getpwuid(id);
4737         if (!passwd)
4738                 return -ENOENT;
4739         *name = passwd->pw_name;
4740
4741         return 0;
4742 }
4743
4744 static inline int gid2name(char **name, unsigned int id)
4745 {
4746         struct group *group;
4747
4748         group = getgrgid(id);
4749         if (!group)
4750                 return -ENOENT;
4751         *name = group->gr_name;
4752
4753         return 0;
4754 }
4755
4756 static int name2layout(__u32 *layout, char *name)
4757 {
4758         char *ptr, *layout_name;
4759
4760         *layout = 0;
4761         for (ptr = name; ; ptr = NULL) {
4762                 layout_name = strtok(ptr, ",");
4763                 if (!layout_name)
4764                         break;
4765                 if (strcmp(layout_name, "released") == 0)
4766                         *layout |= LOV_PATTERN_F_RELEASED;
4767                 else if (strcmp(layout_name, "raid0") == 0)
4768                         *layout |= LOV_PATTERN_RAID0;
4769                 else if (strcmp(layout_name, "mdt") == 0)
4770                         *layout |= LOV_PATTERN_MDT;
4771                 else if (strcmp(layout_name, "overstriping") == 0)
4772                         *layout |= LOV_PATTERN_OVERSTRIPING;
4773                 else
4774                         return -1;
4775         }
4776         return 0;
4777 }
4778
4779 static int name2attrs(char *name, __u64 *attrs, __u64 *neg_attrs)
4780 {
4781         char *ptr, *attr_name = name;
4782         struct attrs_name *ap;
4783         int islongopt = 0; /* 1 true; 0 not known yet; -1 false. */
4784
4785         *attrs = 0;
4786         *neg_attrs = 0;
4787
4788         if (strchr(name, ','))
4789                 islongopt = 1;
4790
4791         for (ptr = name; ; ptr = NULL) {
4792                 if (islongopt != -1)
4793                         attr_name = strtok(ptr, ",");
4794                 else
4795                         attr_name = attr_name + 1;
4796                 if (!attr_name || *attr_name == '\0')
4797                         break;
4798
4799                 for (ap = (struct attrs_name *)attrs_array;
4800                      ap->an_attr != 0;
4801                      ap++) {
4802                         if (islongopt != -1 &&
4803                             strcmp(attr_name, ap->an_name) == 0) {
4804                                 *attrs |= ap->an_attr;
4805                                 islongopt = 1;
4806                                 break;
4807                         } else if (islongopt != -1 && attr_name[0] == '^' &&
4808                                    strcmp(attr_name + 1, ap->an_name) == 0) {
4809                                 *neg_attrs |= ap->an_attr;
4810                                 islongopt = 1;
4811                                 break;
4812                         } else if (islongopt != 1 &&
4813                                    *attr_name == ap->an_shortname) {
4814                                 *attrs |= ap->an_attr;
4815                                 islongopt = -1;
4816                                 break;
4817                         } else if (islongopt != 1 && *attr_name == '^' &&
4818                                    attr_name[1] == ap->an_shortname) {
4819                                 *neg_attrs |= ap->an_attr;
4820                                 islongopt = -1;
4821                                 attr_name++;
4822                                 break;
4823                         }
4824                 }
4825
4826                 if (ap->an_attr == 0) {
4827                         /* provided attr is unknown */
4828                         fprintf(stderr, "error: bad attribute name '%s'\n",
4829                                 attr_name);
4830                         return -1;
4831                 }
4832         }
4833         return 0;
4834 }
4835
4836 static int parse_symbolic(const char *input, mode_t *outmode, const char **end)
4837 {
4838         int loop;
4839         int user, group, other;
4840         int who, all;
4841         char c, op;
4842         mode_t perm;
4843         mode_t usermask;
4844         mode_t previous_flags;
4845
4846         user = group = other = 0;
4847         all = 0;
4848         loop = 1;
4849         perm = 0;
4850         previous_flags = 0;
4851         *end = input;
4852         usermask = 0;
4853
4854         while (loop) {
4855                 switch (*input) {
4856                 case 'u':
4857                         user = 1;
4858                         break;
4859                 case 'g':
4860                         group = 1;
4861                         break;
4862                 case 'o':
4863                         other = 1;
4864                         break;
4865                 case 'a':
4866                         user = group = other = 1;
4867                         all = 1;
4868                         break;
4869                 default:
4870                         loop = 0;
4871                 }
4872
4873                 if (loop)
4874                         input++;
4875         }
4876
4877         who = user || group || other;
4878         if (!who) {
4879                 /* get the umask */
4880                 usermask = umask(0022);
4881                 umask(usermask);
4882                 usermask &= 07777;
4883         }
4884
4885         if (*input == '-' || *input == '+' || *input == '=')
4886                 op = *input++;
4887         else
4888                 /* operation is required */
4889                 return -1;
4890
4891         /* get the flags in *outmode */
4892         switch (*input) {
4893         case 'u':
4894                 previous_flags = (*outmode & 0700);
4895                 perm |= user  ? previous_flags : 0;
4896                 perm |= group ? (previous_flags >> 3) : 0;
4897                 perm |= other ? (previous_flags >> 6) : 0;
4898                 input++;
4899                 goto write_perm;
4900         case 'g':
4901                 previous_flags = (*outmode & 0070);
4902                 perm |= user  ? (previous_flags << 3) : 0;
4903                 perm |= group ? previous_flags : 0;
4904                 perm |= other ? (previous_flags >> 3) : 0;
4905                 input++;
4906                 goto write_perm;
4907         case 'o':
4908                 previous_flags = (*outmode & 0007);
4909                 perm |= user  ? (previous_flags << 6) : 0;
4910                 perm |= group ? (previous_flags << 3) : 0;
4911                 perm |= other ? previous_flags : 0;
4912                 input++;
4913                 goto write_perm;
4914         default:
4915                 break;
4916         }
4917
4918         /* this part is optional,
4919          * if empty perm = 0 and *outmode is not modified
4920          */
4921         loop = 1;
4922         while (loop) {
4923                 c = *input;
4924                 switch (c) {
4925                 case 'r':
4926                         perm |= user  ? 0400 : 0;
4927                         perm |= group ? 0040 : 0;
4928                         perm |= other ? 0004 : 0;
4929                         /* set read permission for uog except for umask's
4930                          * permissions
4931                          */
4932                         perm |= who   ? 0 : (0444 & ~usermask);
4933                         break;
4934                 case 'w':
4935                         perm |= user  ? 0200 : 0;
4936                         perm |= group ? 0020 : 0;
4937                         perm |= other ? 0002 : 0;
4938                         /* set write permission for uog except for umask'
4939                          * permissions
4940                          */
4941                         perm |= who   ? 0 : (0222 & ~usermask);
4942                         break;
4943                 case 'x':
4944                         perm |= user  ? 0100 : 0;
4945                         perm |= group ? 0010 : 0;
4946                         perm |= other ? 0001 : 0;
4947                         /* set execute permission for uog except for umask'
4948                          * permissions
4949                          */
4950                         perm |= who   ? 0 : (0111 & ~usermask);
4951                         break;
4952                 case 'X':
4953                         /*
4954                          * Adds execute permission to 'u', 'g' and/or 'g' if
4955                          * specified and either 'u', 'g' or 'o' already has
4956                          * execute permissions.
4957                          */
4958                         if ((*outmode & 0111) != 0) {
4959                                 perm |= user  ? 0100 : 0;
4960                                 perm |= group ? 0010 : 0;
4961                                 perm |= other ? 0001 : 0;
4962                                 perm |= !who  ? 0111 : 0;
4963                         }
4964                         break;
4965                 case 's':
4966                         /* s is ignored if o is given, but it's not an error */
4967                         if (other && !group && !user)
4968                                 break;
4969                         perm |= user  ? S_ISUID : 0;
4970                         perm |= group ? S_ISGID : 0;
4971                         break;
4972                 case 't':
4973                         /* 't' should be used when 'a' is given
4974                          * or who is empty
4975                          */
4976                         perm |= (!who || all) ? S_ISVTX : 0;
4977                         /* using ugo with t is not an error */
4978                         break;
4979                 default:
4980                         loop = 0;
4981                         break;
4982                 }
4983                 if (loop)
4984                         input++;
4985         }
4986
4987 write_perm:
4988         /* uog flags should be only one character long */
4989         if (previous_flags && (*input != '\0' && *input != ','))
4990                 return -1;
4991
4992         switch (op) {
4993         case '-':
4994                 /* remove the flags from outmode */
4995                 *outmode &= ~perm;
4996                 break;
4997         case '+':
4998                 /* add the flags to outmode */
4999                 *outmode |= perm;
5000                 break;
5001         case '=':
5002                 /* set the flags of outmode to perm */
5003                 if (perm != 0)
5004                         *outmode = perm;
5005                 break;
5006         }
5007
5008         *end = input;
5009         return 0;
5010 }
5011
5012 static int str2mode_t(const char *input, mode_t *outmode)
5013 {
5014         int ret;
5015         const char *iter;
5016
5017         ret = 0;
5018
5019         if (*input >= '0' && *input <= '7') {
5020                 /* parse octal representation */
5021                 char *end;
5022
5023                 iter = input;
5024
5025                 /* look for invalid digits in octal representation */
5026                 while (isdigit(*iter))
5027                         if (*iter++ > '7')
5028                                 return -1;
5029
5030                 errno = 0;
5031                 *outmode = strtoul(input, &end, 8);
5032
5033                 if (errno != 0 || *outmode > 07777) {
5034                         *outmode = 0;
5035                         ret = -1;
5036                 }
5037
5038         } else if (*input == '8' || *input == '9') {
5039                 /* error: invalid octal number */
5040                 ret = -1;
5041         } else {
5042                 /* parse coma seperated list of symbolic representation */
5043                 int rc;
5044                 const char *end;
5045
5046                 *outmode = 0;
5047                 rc = 0;
5048                 end = NULL;
5049
5050                 do {
5051                         rc = parse_symbolic(input, outmode, &end);
5052                         if (rc)
5053                                 return -1;
5054
5055                         input = end+1;
5056                 } while (*end == ',');
5057
5058                 if (*end != '\0')
5059                         ret = -1;
5060         }
5061         return ret;
5062 }
5063
5064 static int lfs_find(int argc, char **argv)
5065 {
5066         int c, rc;
5067         int ret = 0;
5068         time_t t;
5069         struct find_param param = {
5070                 .fp_max_depth = -1,
5071                 .fp_quiet = 1,
5072                 .fp_time_margin = FP_DEFAULT_TIME_MARGIN,
5073         };
5074         struct option long_opts[] = {
5075         { .val = 'A',   .name = "atime",        .has_arg = required_argument },
5076         { .val = LFS_ATTRS_OPT,
5077                         .name = "attrs",        .has_arg = required_argument },
5078         { .val = 'b',   .name = "blocks",       .has_arg = required_argument },
5079         { .val = 'B',   .name = "btime",        .has_arg = required_argument },
5080         { .val = 'B',   .name = "Btime",        .has_arg = required_argument },
5081         { .val = LFS_COMP_COUNT_OPT,
5082                         .name = "comp-count",   .has_arg = required_argument },
5083         { .val = LFS_COMP_COUNT_OPT,
5084                         .name = "component-count",
5085                                                 .has_arg = required_argument },
5086         { .val = LFS_COMP_FLAGS_OPT,
5087                         .name = "comp-flags",   .has_arg = required_argument },
5088         { .val = LFS_COMP_FLAGS_OPT,
5089                         .name = "component-flags",
5090                                                 .has_arg = required_argument },
5091         { .val = LFS_COMP_START_OPT,
5092                         .name = "comp-start",   .has_arg = required_argument },
5093         { .val = LFS_COMP_START_OPT,
5094                         .name = "component-start",
5095                                                 .has_arg = required_argument },
5096         { .val = LFS_MIRROR_STATE_OPT,
5097                         .name = "mirror-state", .has_arg = required_argument },
5098         { .val = LFS_NEWERXY_OPT,
5099                         .name = "newer",        .has_arg = required_argument},
5100         { .val = LFS_NEWERXY_OPT,
5101                         .name = "neweraa",      .has_arg = required_argument},
5102         { .val = LFS_NEWERXY_OPT,
5103                         .name = "neweram",      .has_arg = required_argument},
5104         { .val = LFS_NEWERXY_OPT,
5105                         .name = "newerac",      .has_arg = required_argument},
5106         { .val = LFS_NEWERXY_OPT,
5107                         .name = "newerab",      .has_arg = required_argument},
5108         { .val = LFS_NEWERXY_OPT,
5109                         .name = "newerma",      .has_arg = required_argument},
5110         { .val = LFS_NEWERXY_OPT,
5111                         .name = "newermm",      .has_arg = required_argument},
5112         { .val = LFS_NEWERXY_OPT,
5113                         .name = "newermc",      .has_arg = required_argument},
5114         { .val = LFS_NEWERXY_OPT,
5115                         .name = "newermb",      .has_arg = required_argument},
5116         { .val = LFS_NEWERXY_OPT,
5117                         .name = "newerca",      .has_arg = required_argument},
5118         { .val = LFS_NEWERXY_OPT,
5119                         .name = "newercm",      .has_arg = required_argument},
5120         { .val = LFS_NEWERXY_OPT,
5121                         .name = "newercc",      .has_arg = required_argument},
5122         { .val = LFS_NEWERXY_OPT,
5123                         .name = "newercb",      .has_arg = required_argument},
5124         { .val = LFS_NEWERXY_OPT,
5125                         .name = "newerba",      .has_arg = required_argument},
5126         { .val = LFS_NEWERXY_OPT,
5127                         .name = "newerbm",      .has_arg = required_argument},
5128         { .val = LFS_NEWERXY_OPT,
5129                         .name = "newerbc",      .has_arg = required_argument},
5130         { .val = LFS_NEWERXY_OPT,
5131                         .name = "newerbb",      .has_arg = required_argument},
5132         { .val = LFS_NEWERXY_OPT,
5133                         .name = "newerBa",      .has_arg = required_argument},
5134         { .val = LFS_NEWERXY_OPT,
5135                         .name = "newerBm",      .has_arg = required_argument},
5136         { .val = LFS_NEWERXY_OPT,
5137                         .name = "newerBc",      .has_arg = required_argument},
5138         { .val = LFS_NEWERXY_OPT,
5139                         .name = "newerBB",      .has_arg = required_argument},
5140         { .val = LFS_NEWERXY_OPT,
5141                         .name = "newerat",      .has_arg = required_argument},
5142         { .val = LFS_NEWERXY_OPT,
5143                         .name = "newermt",      .has_arg = required_argument},
5144         { .val = LFS_NEWERXY_OPT,
5145                         .name = "newerct",      .has_arg = required_argument},
5146         { .val = LFS_NEWERXY_OPT,
5147                         .name = "newerbt",      .has_arg = required_argument},
5148         { .val = LFS_NEWERXY_OPT,
5149                         .name = "newerBt",      .has_arg = required_argument},
5150         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument },
5151         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument },
5152         { .val = 'C',   .name = "ctime",        .has_arg = required_argument },
5153 /* getstripe { .val = 'd', .name = "directory", .has_arg = no_argument }, */
5154         { .val = 'D',   .name = "maxdepth",     .has_arg = required_argument },
5155         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument },
5156         { .val = 'E',   .name = "component-end",
5157                                                 .has_arg = required_argument },
5158 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
5159         { .val = LFS_LAYOUT_FOREIGN_OPT,
5160                         .name = "foreign",      .has_arg = optional_argument},
5161         { .val = 'g',   .name = "gid",          .has_arg = required_argument },
5162         { .val = 'G',   .name = "group",        .has_arg = required_argument },
5163         { .val = 'h',   .name = "help",         .has_arg = no_argument },
5164         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
5165         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument },
5166         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument },
5167 /* getstripe { .val = 'I', .name = "comp-id",   .has_arg = required_argument }*/
5168         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
5169         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
5170         { .val = LFS_LINKS_OPT,
5171                         .name = "links",        .has_arg = required_argument },
5172         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
5173         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
5174         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument },
5175         { .val = 'M',   .name = "mtime",        .has_arg = required_argument },
5176         { .val = 'n',   .name = "name",         .has_arg = required_argument },
5177         { .val = 'N',   .name = "mirror-count", .has_arg = required_argument },
5178 /* find { .val = 'o'    .name = "or", .has_arg = no_argument }, like find(1) */
5179         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
5180         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
5181         { .val = LFS_FIND_PERM,
5182                         .name = "perm",         .has_arg = required_argument },
5183         /* no short option for pool yet, can be 'p' after 2.18 */
5184         { .val = LFS_POOL_OPT,
5185                         .name = "pool",         .has_arg = required_argument },
5186         { .val = '0',   .name = "print0",       .has_arg = no_argument },
5187         { .val = 'P',   .name = "print",        .has_arg = no_argument },
5188         { .val = LFS_PRINTF_OPT,
5189                         .name = "printf",       .has_arg = required_argument },
5190         { .val = LFS_PROJID_OPT,
5191                         .name = "projid",       .has_arg = required_argument },
5192 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
5193 /* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
5194 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
5195         { .val = 's',   .name = "size",         .has_arg = required_argument },
5196         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
5197         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
5198         { .val = 't',   .name = "type",         .has_arg = required_argument },
5199         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
5200         { .val = 'u',   .name = "uid",          .has_arg = required_argument },
5201         { .val = 'U',   .name = "user",         .has_arg = required_argument },
5202 /* getstripe { .val = 'v', .name = "verbose",   .has_arg = no_argument }, */
5203 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }, */
5204         { .val = 'z',   .name = "extension-size",
5205                                                 .has_arg = required_argument },
5206         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument },
5207         { .name = NULL } };
5208         int prev_optind = optind;
5209         int optidx = 0;
5210         int pathstart = -1;
5211         int pathend = -1;
5212         int neg_opt = 0;
5213         time_t *xtime;
5214         int *xsign;
5215         int isoption;
5216         char *endptr;
5217
5218         time(&t);
5219
5220         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
5221         while ((c = getopt_long_only(argc, argv,
5222                 "-0A:b:B:c:C:D:E:g:G:hH:i:lL:m:M:n:N:O:Ppqrs:S:t:T:u:U:z:",
5223                 long_opts, &optidx)) >= 0) {
5224                 xtime = NULL;
5225                 xsign = NULL;
5226                 if (neg_opt)
5227                         --neg_opt;
5228                 /* '!' is part of option */
5229                 /*
5230                  * when getopt_long_only() finds a string which is not
5231                  * an option nor a known option argument it returns 1
5232                  * in that case if we already have found pathstart and pathend
5233                  * (i.e. we have the list of pathnames),
5234                  * the only supported value is "!"
5235                  */
5236                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
5237                 if (!isoption && pathend != -1) {
5238                         fprintf(stderr,
5239                                 "err: %s: filename|dirname must either precede options or follow options\n",
5240                                 argv[0]);
5241                         ret = CMD_HELP;
5242                         goto err;
5243                 }
5244                 if (!isoption && pathstart == -1)
5245                         pathstart = prev_optind;
5246                 if (isoption && pathstart != -1 && pathend == -1)
5247                         pathend = prev_optind;
5248
5249                 prev_optind = optind;
5250
5251                 switch (c) {
5252                 case 0:
5253                         /* Long options. */
5254                         break;
5255                 case 1:
5256                         /*
5257                          * unknown; opt is "!" or path component,
5258                          * checking done above.
5259                          */
5260                         if (strcmp(optarg, "!") == 0)
5261                                 neg_opt = 2;
5262                         break;
5263                 case 'A':
5264                         xtime = &param.fp_atime;
5265                         xsign = &param.fp_asign;
5266                         param.fp_exclude_atime = !!neg_opt;
5267                         /* no break, this falls through to 'B' for btime */
5268                         fallthrough;
5269                 case 'B':
5270                         if (c == 'B') {
5271                                 xtime = &param.fp_btime;
5272                                 xsign = &param.fp_bsign;
5273                                 param.fp_exclude_btime = !!neg_opt;
5274                         }
5275                         /* no break, this falls through to 'C' for ctime */
5276                         fallthrough;
5277                 case 'C':
5278                         if (c == 'C') {
5279                                 xtime = &param.fp_ctime;
5280                                 xsign = &param.fp_csign;
5281                                 param.fp_exclude_ctime = !!neg_opt;
5282                         }
5283                         /* no break, this falls through to 'M' for mtime */
5284                         fallthrough;
5285                 case 'M':
5286                         if (c == 'M') {
5287                                 xtime = &param.fp_mtime;
5288                                 xsign = &param.fp_msign;
5289                                 param.fp_exclude_mtime = !!neg_opt;
5290                         }
5291                         rc = set_time(&param, &t, xtime, optarg);
5292                         if (rc == INT_MAX) {
5293                                 ret = -1;
5294                                 goto err;
5295                         }
5296                         if (rc)
5297                                 *xsign = rc;
5298                         break;
5299                 case LFS_ATTRS_OPT:
5300                         ret = name2attrs(optarg, &param.fp_attrs,
5301                                          &param.fp_neg_attrs);
5302                         if (ret)
5303                                 goto err;
5304                         param.fp_exclude_attrs = !!neg_opt;
5305                         break;
5306                 case 'b':
5307                         if (optarg[0] == '+') {
5308                                 param.fp_blocks_sign = -1;
5309                                 optarg++;
5310                         } else if (optarg[0] == '-') {
5311                                 param.fp_blocks_sign =  1;
5312                                 optarg++;
5313                         }
5314
5315                         param.fp_blocks_units = 512;
5316                         ret = llapi_parse_size(optarg, &param.fp_blocks,
5317                                                &param.fp_blocks_units, 0);
5318                         if (ret) {
5319                                 fprintf(stderr, "error: bad blocks '%s'\n",
5320                                         optarg);
5321                                 goto err;
5322                         }
5323                         param.fp_check_blocks = 1;
5324                         param.fp_exclude_blocks = !!neg_opt;
5325                         break;
5326                 case LFS_COMP_COUNT_OPT:
5327                         if (optarg[0] == '+') {
5328                                 param.fp_comp_count_sign = -1;
5329                                 optarg++;
5330                         } else if (optarg[0] == '-') {
5331                                 param.fp_comp_count_sign =  1;
5332                                 optarg++;
5333                         }
5334
5335                         errno = 0;
5336                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
5337                         if (errno != 0 || *endptr != '\0' ||
5338                             param.fp_comp_count > UINT32_MAX) {
5339                                 fprintf(stderr,
5340                                         "error: bad component count '%s'\n",
5341                                         optarg);
5342                                 goto err;
5343                         }
5344                         param.fp_check_comp_count = 1;
5345                         param.fp_exclude_comp_count = !!neg_opt;
5346                         break;
5347                 case LFS_COMP_FLAGS_OPT:
5348                         rc = comp_str2flags(optarg, &param.fp_comp_flags,
5349                                             &param.fp_comp_neg_flags);
5350                         if (rc) {
5351                                 fprintf(stderr,
5352                                         "error: bad component flags '%s'\n",
5353                                         optarg);
5354                                 goto err;
5355                         }
5356                         param.fp_check_comp_flags = 1;
5357                         if (neg_opt) {
5358                                 __u32 flags = param.fp_comp_neg_flags;
5359
5360                                 param.fp_comp_neg_flags = param.fp_comp_flags;
5361                                 param.fp_comp_flags = flags;
5362                         }
5363                         break;
5364                 case LFS_COMP_START_OPT:
5365                         if (optarg[0] == '+') {
5366                                 param.fp_comp_start_sign = -1;
5367                                 optarg++;
5368                         } else if (optarg[0] == '-') {
5369                                 param.fp_comp_start_sign =  1;
5370                                 optarg++;
5371                         }
5372
5373                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
5374                                               &param.fp_comp_start_units, 0);
5375                         if (rc) {
5376                                 fprintf(stderr,
5377                                         "error: bad component start '%s'\n",
5378                                         optarg);
5379                                 goto err;
5380                         }
5381                         param.fp_check_comp_start = 1;
5382                         param.fp_exclude_comp_start = !!neg_opt;
5383                         break;
5384                 case LFS_MIRROR_STATE_OPT:
5385                         rc = mirror_str2state(optarg, &param.fp_mirror_state,
5386                                               &param.fp_mirror_neg_state);
5387                         if (rc) {
5388                                 fprintf(stderr,
5389                                         "error: bad mirrored file state '%s'\n",
5390                                         optarg);
5391                                 goto err;
5392                         }
5393                         param.fp_check_mirror_state = 1;
5394                         if (neg_opt) {
5395                                 __u16 state = param.fp_mirror_neg_state;
5396
5397                                 param.fp_mirror_neg_state =
5398                                         param.fp_mirror_state;
5399                                 param.fp_mirror_state = state;
5400                         }
5401                         break;
5402                 case 'c':
5403                         if (optarg[0] == '+') {
5404                                 param.fp_stripe_count_sign = -1;
5405                                 optarg++;
5406                         } else if (optarg[0] == '-') {
5407                                 param.fp_stripe_count_sign =  1;
5408                                 optarg++;
5409                         }
5410
5411                         errno = 0;
5412                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
5413                         if (errno != 0 || *endptr != '\0' ||
5414                             param.fp_stripe_count > LOV_MAX_STRIPE_COUNT) {
5415                                 fprintf(stderr,
5416                                         "error: bad stripe_count '%s'\n",
5417                                         optarg);
5418                                 ret = -1;
5419                                 goto err;
5420                         }
5421                         param.fp_check_stripe_count = 1;
5422                         param.fp_exclude_stripe_count = !!neg_opt;
5423                         break;
5424                 case 'D':
5425                         errno = 0;
5426                         param.fp_max_depth = strtol(optarg, 0, 0);
5427                         if (errno != 0 || param.fp_max_depth < 0) {
5428                                 fprintf(stderr,
5429                                         "error: bad maxdepth '%s'\n",
5430                                         optarg);
5431                                 ret = -1;
5432                                 goto err;
5433                         }
5434                         break;
5435                 case 'E':
5436                         if (optarg[0] == '+') {
5437                                 param.fp_comp_end_sign = -1;
5438                                 optarg++;
5439                         } else if (optarg[0] == '-') {
5440                                 param.fp_comp_end_sign =  1;
5441                                 optarg++;
5442                         }
5443
5444                         if (arg_is_eof(optarg)) {
5445                                 param.fp_comp_end = LUSTRE_EOF;
5446                                 param.fp_comp_end_units = 1;
5447                                 rc = 0;
5448                         } else {
5449                                 rc = llapi_parse_size(optarg,
5450                                                 &param.fp_comp_end,
5451                                                 &param.fp_comp_end_units, 0);
5452                                 /* assume units of KB if too small */
5453                                 if (param.fp_comp_end < 4096)
5454                                         param.fp_comp_end *= 1024;
5455                         }
5456                         if (rc) {
5457                                 fprintf(stderr,
5458                                         "error: bad component end '%s'\n",
5459                                         optarg);
5460                                 goto err;
5461                         }
5462                         param.fp_check_comp_end = 1;
5463                         param.fp_exclude_comp_end = !!neg_opt;
5464                         break;
5465                 case LFS_LAYOUT_FOREIGN_OPT: {
5466                         /* all types by default */
5467                         uint32_t type = LU_FOREIGN_TYPE_UNKNOWN;
5468
5469                         if (optarg) {
5470                                 /* check pure numeric */
5471                                 type = strtoul(optarg, &endptr, 0);
5472                                 if (*endptr) {
5473                                         /* check name */
5474                                         type = check_foreign_type_name(optarg);
5475                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
5476                                                 fprintf(stderr,
5477                                                         "%s %s: unknown foreign type '%s'\n",
5478                                                         progname, argv[0],
5479                                                         optarg);
5480                                                 return CMD_HELP;
5481                                         }
5482                                 } else if (type >= UINT32_MAX) {
5483                                         fprintf(stderr,
5484                                                 "%s %s: invalid foreign type '%s'\n",
5485                                                 progname, argv[0], optarg);
5486                                         return CMD_HELP;
5487                                 }
5488                         }
5489                         param.fp_foreign_type = type;
5490                         param.fp_check_foreign = 1;
5491                         param.fp_exclude_foreign = !!neg_opt;
5492                         break;
5493                 }
5494                 case LFS_NEWERXY_OPT: {
5495                         char x = 'm';
5496                         char y = 'm';
5497                         int xidx;
5498                         int negidx;
5499                         time_t *newery;
5500                         time_t ref = time(NULL);
5501
5502                         /* no need to check bad options, they won't get here */
5503                         if (strlen(long_opts[optidx].name) == 7) {
5504                                 x = long_opts[optidx].name[5];
5505                                 y = long_opts[optidx].name[6];
5506                         }
5507
5508                         if (y == 't') {
5509                                 static const char *const fmts[] = {
5510                                         "%Y-%m-%d %H:%M:%S",
5511                                         "%Y-%m-%d %H:%M",
5512                                         "%Y-%m-%d",
5513                                         "%H:%M:%S", /* sometime today */
5514                                         "%H:%M",
5515                                         "@%s",
5516                                         "%s",
5517                                         NULL };
5518                                 struct tm tm;
5519                                 bool found = false;
5520                                 int i;
5521
5522                                 for (i = 0; fmts[i] != NULL; i++) {
5523                                         char *ptr;
5524
5525                                         /* Init for times relative to today */
5526                                         if (strncmp(fmts[i], "%H", 2) == 0) {
5527                                                 localtime_r(&ref, &tm);
5528                                         } else {
5529                                                 memset(&tm, 0, sizeof(tm));
5530                                                 tm.tm_isdst = -1;
5531                                         }
5532                                         ptr = strptime(optarg, fmts[i], &tm);
5533                                         /* Skip spaces */
5534                                         while (ptr && isspace(*ptr))
5535                                                 ptr++;
5536                                         if (ptr == optarg + strlen(optarg)) {
5537                                                 found = true;
5538                                                 break;
5539                                         }
5540                                 }
5541
5542                                 if (!found) {
5543                                         fprintf(stderr,
5544                                                 "%s: invalid time '%s'\n",
5545                                                 progname, optarg);
5546                                         fprintf(stderr,
5547                                                 "supported formats are:\n  ");
5548                                         for (i = 0; fmts[i] != NULL; i++)
5549                                                 fprintf(stderr, "'%s', ",
5550                                                         fmts[i]);
5551                                         fprintf(stderr, "\n");
5552                                         ret = -EINVAL;
5553                                         goto err;
5554                                 }
5555
5556                                 ref = mktime(&tm);
5557                         } else if (y == 'b' || y == 'B') {
5558                                 lstatx_t stx;
5559
5560                                 rc = llapi_get_lum_file(optarg, NULL, &stx,
5561                                                         NULL, 0);
5562                                 if (rc || !(stx.stx_mask & STATX_BTIME)) {
5563                                         if (!(stx.stx_mask & STATX_BTIME))
5564                                                 ret = -EOPNOTSUPP;
5565                                         else
5566                                                 ret = -errno;
5567                                         fprintf(stderr,
5568                                                 "%s: get btime failed '%s': %s\n",
5569                                                 progname, optarg,
5570                                                 strerror(-ret));
5571                                         goto err;
5572                                 }
5573
5574                                 ref = stx.stx_btime.tv_sec;
5575                         } else {
5576                                 struct stat statbuf;
5577
5578                                 if (stat(optarg, &statbuf) < 0) {
5579                                         fprintf(stderr,
5580                                                 "%s: cannot stat file '%s': %s\n",
5581                                                 progname, optarg,
5582                                                 strerror(errno));
5583                                         ret = -errno;
5584                                         goto err;
5585                                 }
5586
5587                                 switch (y) {
5588                                 case 'a':
5589                                         ref = statbuf.st_atime;
5590                                         break;
5591                                 case 'm':
5592                                         ref = statbuf.st_mtime;
5593                                         break;
5594                                 case 'c':
5595                                         ref = statbuf.st_ctime;
5596                                         break;
5597                                 default:
5598                                         fprintf(stderr,
5599                                                 "%s: invalid Y argument: '%c'\n",
5600                                                 progname, x);
5601                                         ret = -EINVAL;
5602                                         goto err;
5603                                 }
5604                         }
5605
5606                         switch (x) {
5607                         case 'a':
5608                                 xidx = NEWERXY_ATIME;
5609                                 break;
5610                         case 'm':
5611                                 xidx = NEWERXY_MTIME;
5612                                 break;
5613                         case 'c':
5614                                 xidx = NEWERXY_CTIME;
5615                                 break;
5616                         case 'b':
5617                         case 'B':
5618                                 xidx = NEWERXY_BTIME;
5619                                 break;
5620                         default:
5621                                 fprintf(stderr,
5622                                         "%s: invalid X argument: '%c'\n",
5623                                         progname, x);
5624                                 ret = -EINVAL;
5625                                 goto err;
5626                         }
5627
5628                         negidx = !!neg_opt;
5629                         newery = &param.fp_newery[xidx][negidx];
5630
5631                         if (*newery == 0) {
5632                                 *newery = ref;
5633                         } else {
5634                                 if (negidx)
5635                                         *newery = *newery > ref ? ref : *newery;
5636                                 else
5637                                         *newery = *newery > ref ? *newery : ref;
5638                         }
5639                         param.fp_newerxy = 1;
5640                         break;
5641                 }
5642                 case 'g':
5643                 case 'G':
5644                         rc = name2gid(&param.fp_gid, optarg);
5645                         if (rc) {
5646                                 if (str2quotaid(&param.fp_gid, optarg)) {
5647                                         fprintf(stderr,
5648                                                 "Group/GID: %s cannot be found.\n",
5649                                                 optarg);
5650                                         ret = -1;
5651                                         goto err;
5652                                 }
5653                         }
5654                         param.fp_exclude_gid = !!neg_opt;
5655                         param.fp_check_gid = 1;
5656                         break;
5657                 case 'H':
5658                         rc = mdthash_input(optarg, &param.fp_hash_inflags,
5659                                            &param.fp_hash_exflags,
5660                                            &param.fp_hash_type);
5661                         if (rc) {
5662                                 ret = -1;
5663                                 goto err;
5664                         }
5665                         if (param.fp_hash_inflags || param.fp_hash_exflags)
5666                                 param.fp_check_hash_flag = 1;
5667                         param.fp_exclude_hash_type = !!neg_opt;
5668                         break;
5669                 case 'l':
5670                         param.fp_lazy = 1;
5671                         break;
5672                 case 'L':
5673                         ret = name2layout(&param.fp_layout, optarg);
5674                         if (ret)
5675                                 goto err;
5676                         param.fp_exclude_layout = !!neg_opt;
5677                         param.fp_check_layout = 1;
5678                         break;
5679                 case LFS_LINKS_OPT:
5680                         if (optarg[0] == '+') {
5681                                 param.fp_nlink_sign = -1;
5682                                 optarg++;
5683                         } else if (optarg[0] == '-') {
5684                                 param.fp_nlink_sign =  1;
5685                                 optarg++;
5686                         }
5687                         errno = 0;
5688                         param.fp_nlink = strtoul(optarg, &endptr, 0);
5689                         if (errno != 0 || *endptr != '\0' || !param.fp_nlink) {
5690                                 fprintf(stderr, "error: bad link count '%s'\n",
5691                                         optarg);
5692                                 ret = -1;
5693                                 goto err;
5694                         }
5695                         param.fp_exclude_nlink = !!neg_opt;
5696                         break;
5697                 case 'u':
5698                 case 'U':
5699                         rc = name2uid(&param.fp_uid, optarg);
5700                         if (rc) {
5701                                 if (str2quotaid(&param.fp_uid, optarg)) {
5702                                         fprintf(stderr,
5703                                                 "User/UID: %s cannot be found.\n",
5704                                                 optarg);
5705                                         ret = -1;
5706                                         goto err;
5707                                 }
5708                         }
5709                         param.fp_exclude_uid = !!neg_opt;
5710                         param.fp_check_uid = 1;
5711                         break;
5712                 case 'n':
5713                         param.fp_pattern = (char *)optarg;
5714                         param.fp_exclude_pattern = !!neg_opt;
5715                         break;
5716                 case 'N':
5717                         if (optarg[0] == '+') {
5718                                 param.fp_mirror_count_sign = -1;
5719                                 optarg++;
5720                         } else if (optarg[0] == '-') {
5721                                 param.fp_mirror_count_sign =  1;
5722                                 optarg++;
5723                         }
5724
5725                         errno = 0;
5726                         param.fp_mirror_count = strtoul(optarg, &endptr, 0);
5727                         if (errno != 0 || *endptr != '\0' ||
5728                             param.fp_mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
5729                                 fprintf(stderr,
5730                                         "error: bad mirror count '%s'\n",
5731                                         optarg);
5732                                 goto err;
5733                         }
5734                         param.fp_check_mirror_count = 1;
5735                         param.fp_exclude_mirror_count = !!neg_opt;
5736                         break;
5737                 case 'm':
5738                 case 'i':
5739                 case 'O': {
5740                         char *buf, *token, *next, *p;
5741                         int len = 1;
5742                         void *tmp;
5743
5744                         buf = strdup(optarg);
5745                         if (!buf) {
5746                                 ret = -ENOMEM;
5747                                 goto err;
5748                         }
5749
5750                         param.fp_exclude_obd = !!neg_opt;
5751
5752                         token = buf;
5753                         while (token && *token) {
5754                                 token = strchr(token, ',');
5755                                 if (token) {
5756                                         len++;
5757                                         token++;
5758                                 }
5759                         }
5760                         if (c == 'm') {
5761                                 param.fp_exclude_mdt = !!neg_opt;
5762                                 param.fp_num_alloc_mdts += len;
5763                                 tmp = realloc(param.fp_mdt_uuid,
5764                                               param.fp_num_alloc_mdts *
5765                                               sizeof(*param.fp_mdt_uuid));
5766                                 if (!tmp) {
5767                                         ret = -ENOMEM;
5768                                         goto err_free;
5769                                 }
5770
5771                                 param.fp_mdt_uuid = tmp;
5772                         } else {
5773                                 param.fp_exclude_obd = !!neg_opt;
5774                                 param.fp_num_alloc_obds += len;
5775                                 tmp = realloc(param.fp_obd_uuid,
5776                                               param.fp_num_alloc_obds *
5777                                               sizeof(*param.fp_obd_uuid));
5778                                 if (!tmp) {
5779                                         ret = -ENOMEM;
5780                                         goto err_free;
5781                                 }
5782
5783                                 param.fp_obd_uuid = tmp;
5784                         }
5785                         for (token = buf; token && *token; token = next) {
5786                                 struct obd_uuid *puuid;
5787
5788                                 if (c == 'm') {
5789                                         puuid =
5790                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
5791                                 } else {
5792                                         puuid =
5793                                         &param.fp_obd_uuid[param.fp_num_obds++];
5794                                 }
5795                                 p = strchr(token, ',');
5796                                 next = 0;
5797                                 if (p) {
5798                                         *p = 0;
5799                                         next = p+1;
5800                                 }
5801
5802                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
5803                                         ret = -E2BIG;
5804                                         goto err_free;
5805                                 }
5806
5807                                 strncpy(puuid->uuid, token,
5808                                         sizeof(puuid->uuid));
5809                         }
5810 err_free:
5811                         if (buf)
5812                                 free(buf);
5813                         break;
5814                 }
5815 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 18, 53, 0)
5816                 case 'p':
5817 #endif
5818                 case LFS_POOL_OPT:
5819                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
5820                                 fprintf(stderr,
5821                                         "Pool name %s is too long (max %d)\n",
5822                                         optarg, LOV_MAXPOOLNAME);
5823                                 ret = -1;
5824                                 goto err;
5825                         }
5826                         /*
5827                          * We do check for empty pool because empty pool
5828                          * is used to find V1 LOV attributes
5829                          */
5830                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
5831                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
5832                         param.fp_exclude_pool = !!neg_opt;
5833                         param.fp_check_pool = 1;
5834                         break;
5835                 case '0':
5836                         param.fp_zero_end = 1;
5837                         break;
5838                 case 'P': /* we always print, this option is a no-op */
5839                         break;
5840                 case LFS_PRINTF_OPT:
5841                         param.fp_format_printf_str = strdup(optarg);
5842                         break;
5843                 case LFS_PROJID_OPT:
5844                         rc = name2projid(&param.fp_projid, optarg);
5845                         if (rc) {
5846                                 if (str2quotaid(&param.fp_projid, optarg)) {
5847                                         fprintf(stderr,
5848                                                 "Invalid project ID: %s\n",
5849                                                 optarg);
5850                                         ret = -1;
5851                                         goto err;
5852                                 }
5853                         }
5854                         param.fp_exclude_projid = !!neg_opt;
5855                         param.fp_check_projid = 1;
5856                         break;
5857                 case 's':
5858                         if (optarg[0] == '+') {
5859                                 param.fp_size_sign = -1;
5860                                 optarg++;
5861                         } else if (optarg[0] == '-') {
5862                                 param.fp_size_sign =  1;
5863                                 optarg++;
5864                         }
5865
5866                         param.fp_size_units = 512;
5867                         ret = llapi_parse_size(optarg, &param.fp_size,
5868                                                &param.fp_size_units, 0);
5869                         if (ret) {
5870                                 fprintf(stderr, "error: bad file size '%s'\n",
5871                                         optarg);
5872                                 goto err;
5873                         }
5874                         param.fp_check_size = 1;
5875                         param.fp_exclude_size = !!neg_opt;
5876                         break;
5877                 case 'S':
5878                         if (optarg[0] == '+') {
5879                                 param.fp_stripe_size_sign = -1;
5880                                 optarg++;
5881                         } else if (optarg[0] == '-') {
5882                                 param.fp_stripe_size_sign =  1;
5883                                 optarg++;
5884                         }
5885
5886                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
5887                                                &param.fp_stripe_size_units, 0);
5888                         /* assume units of KB if too small to be valid */
5889                         if (param.fp_stripe_size < 4096)
5890                                 param.fp_stripe_size *= 1024;
5891                         if (ret) {
5892                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
5893                                         optarg);
5894                                 goto err;
5895                         }
5896                         param.fp_check_stripe_size = 1;
5897                         param.fp_exclude_stripe_size = !!neg_opt;
5898                         break;
5899                 case 't':
5900                         param.fp_exclude_type = !!neg_opt;
5901                         switch (optarg[0]) {
5902                         case 'b':
5903                                 param.fp_type = S_IFBLK;
5904                                 break;
5905                         case 'c':
5906                                 param.fp_type = S_IFCHR;
5907                                 break;
5908                         case 'd':
5909                                 param.fp_type = S_IFDIR;
5910                                 break;
5911                         case 'f':
5912                                 param.fp_type = S_IFREG;
5913                                 break;
5914                         case 'l':
5915                                 param.fp_type = S_IFLNK;
5916                                 break;
5917                         case 'p':
5918                                 param.fp_type = S_IFIFO;
5919                                 break;
5920                         case 's':
5921                                 param.fp_type = S_IFSOCK;
5922                                 break;
5923                         default:
5924                                 fprintf(stderr, "%s: bad type '%s'\n",
5925                                         progname, optarg);
5926                                 ret = CMD_HELP;
5927                                 goto err;
5928                         }
5929                         break;
5930                 case LFS_FIND_PERM:
5931                         param.fp_exclude_perm = !!neg_opt;
5932                         param.fp_perm_sign = LFS_FIND_PERM_EXACT;
5933                         if (*optarg == '/') {
5934                                 param.fp_perm_sign = LFS_FIND_PERM_ANY;
5935                                 optarg++;
5936                         } else if (*optarg == '-') {
5937                                 param.fp_perm_sign = LFS_FIND_PERM_ALL;
5938                                 optarg++;
5939                         }
5940
5941                         if (str2mode_t(optarg, &param.fp_perm)) {
5942                                 fprintf(stderr, "error: invalid mode '%s'\n",
5943                                         optarg);
5944                                 ret = -1;
5945                                 goto err;
5946                         }
5947                         break;
5948                 case 'T':
5949                         if (optarg[0] == '+') {
5950                                 param.fp_mdt_count_sign = -1;
5951                                 optarg++;
5952                         } else if (optarg[0] == '-') {
5953                                 param.fp_mdt_count_sign =  1;
5954                                 optarg++;
5955                         }
5956
5957                         errno = 0;
5958                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
5959                         if (errno != 0 || *endptr != '\0' ||
5960                             param.fp_mdt_count >= UINT32_MAX) {
5961                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
5962                                         optarg);
5963                                 ret = -1;
5964                                 goto err;
5965                         }
5966                         param.fp_check_mdt_count = 1;
5967                         param.fp_exclude_mdt_count = !!neg_opt;
5968                         break;
5969                 case 'z':
5970                         if (optarg[0] == '+') {
5971                                 param.fp_ext_size_sign = -1;
5972                                 optarg++;
5973                         } else if (optarg[0] == '-') {
5974                                 param.fp_ext_size_sign =  1;
5975                                 optarg++;
5976                         }
5977
5978                         ret = llapi_parse_size(optarg, &param.fp_ext_size,
5979                                                &param.fp_ext_size_units, 0);
5980                         if (ret) {
5981                                 fprintf(stderr, "error: bad ext-size '%s'\n",
5982                                         optarg);
5983                                 goto err;
5984                         }
5985                         param.fp_ext_size /= SEL_UNIT_SIZE;
5986                         param.fp_ext_size_units /= SEL_UNIT_SIZE;
5987                         param.fp_check_ext_size = 1;
5988                         param.fp_exclude_ext_size = !!neg_opt;
5989                         break;
5990                 default:
5991                         fprintf(stderr, "%s: unrecognized option '%s'\n",
5992                                 progname, argv[optind - 1]);
5993                 case 'h':
5994                         ret = CMD_HELP;
5995                         goto err;
5996                 }
5997         }
5998         if (!param.fp_verbose)
5999                 param.fp_verbose = VERBOSE_DEFAULT;
6000
6001         if (pathstart == -1) {
6002                 fprintf(stderr, "error: %s: no filename|pathname\n",
6003                         argv[0]);
6004                 ret = CMD_HELP;
6005                 goto err;
6006         } else if (pathend == -1) {
6007                 /* no options */
6008                 pathend = argc;
6009         }
6010
6011         do {
6012                 rc = llapi_find(argv[pathstart], &param);
6013                 if (rc) {
6014                         if (!ret)
6015                                 ret = rc;
6016
6017                         fprintf(stderr, "%s: failed for '%s': %s\n",
6018                                 progname, argv[pathstart], strerror(-rc));
6019                 }
6020         } while (++pathstart < pathend);
6021
6022 err:
6023         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
6024                 free(param.fp_obd_uuid);
6025
6026         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
6027                 free(param.fp_mdt_uuid);
6028
6029         if (param.fp_format_printf_str)
6030                 free(param.fp_format_printf_str);
6031
6032         return ret;
6033 }
6034
6035 static int lfs_getstripe_internal(int argc, char **argv,
6036                                   struct find_param *param)
6037 {
6038         struct option long_opts[] = {
6039 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
6040 /* find { .val = 'b',   .name = "blocks",       .has_arg = required_argument }*/
6041 /* find { .val = 'B',   .name = "btime",        .has_arg = required_argument }*/
6042 /* find { .val = 'B',   .name = "Btime",        .has_arg = required_argument }*/
6043         { .val = LFS_COMP_COUNT_OPT,
6044                         .name = "comp-count",   .has_arg = no_argument },
6045         { .val = LFS_COMP_COUNT_OPT,
6046                 .name = "component-count",      .has_arg = no_argument },
6047         { .val = LFS_COMP_FLAGS_OPT,
6048                         .name = "comp-flags",   .has_arg = optional_argument },
6049         { .val = LFS_COMP_FLAGS_OPT,
6050                 .name = "component-flags",      .has_arg = optional_argument },
6051         { .val = LFS_COMP_START_OPT,
6052                         .name = "comp-start",   .has_arg = optional_argument },
6053         { .val = LFS_COMP_START_OPT,
6054                 .name = "component-start",      .has_arg = optional_argument },
6055         { .val = 'c',   .name = "stripe-count", .has_arg = no_argument },
6056         { .val = 'c',   .name = "stripe_count", .has_arg = no_argument },
6057 /* find { .val = 'C',   .name = "ctime",        .has_arg = required_argument }*/
6058         { .val = 'd',   .name = "directory",    .has_arg = no_argument },
6059         { .val = 'D',   .name = "default",      .has_arg = no_argument },
6060         { .val = 'E',   .name = "comp-end",     .has_arg = optional_argument },
6061         { .val = 'E',   .name = "component-end", .has_arg = optional_argument },
6062         { .val = 'F',   .name = "fid",          .has_arg = no_argument },
6063         { .val = 'g',   .name = "generation",   .has_arg = no_argument },
6064 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
6065         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6066         { .val = LFS_HEX_IDX_OPT,
6067                         .name = "hex-idx",      .has_arg = no_argument },
6068 /* dirstripe { .val = 'H', .name = "mdt-hash",  .has_arg = required_argument }*/
6069         { .val = 'i',   .name = "stripe-index", .has_arg = no_argument },
6070         { .val = 'i',   .name = "stripe_index", .has_arg = no_argument },
6071         { .val = 'I',   .name = "comp-id",      .has_arg = optional_argument },
6072         { .val = 'I',   .name = "component-id", .has_arg = optional_argument },
6073 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
6074         { .val = 'L',   .name = "layout",       .has_arg = no_argument },
6075         { .val = 'm',   .name = "mdt",          .has_arg = no_argument },
6076         { .val = 'm',   .name = "mdt-index",    .has_arg = no_argument },
6077         { .val = 'm',   .name = "mdt_index",    .has_arg = no_argument },
6078 /* find { .val = 'M',   .name = "mtime",        .has_arg = required_argument }*/
6079 /* find { .val = 'n',   .name = "name",         .has_arg = required_argument }*/
6080         { .val = 'N',   .name = "mirror-count", .has_arg = no_argument },
6081         { .val = LFS_MIRROR_INDEX_OPT,
6082                         .name = "mirror-index", .has_arg = required_argument },
6083         { .val = LFS_MIRROR_ID_OPT,
6084                         .name = "mirror-id",    .has_arg = required_argument },
6085         { .val = LFS_NO_FOLLOW_OPT,
6086                         .name = "no-follow",    .has_arg = no_argument },
6087         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
6088         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
6089         { .val = 'p',   .name = "pool",         .has_arg = no_argument },
6090 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
6091         { .val = 'q',   .name = "quiet",        .has_arg = no_argument },
6092         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
6093         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
6094         { .val = 'S',   .name = "stripe-size",  .has_arg = no_argument },
6095         { .val = 'S',   .name = "stripe_size",  .has_arg = no_argument },
6096 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
6097 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
6098 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
6099 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
6100         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
6101 /* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/
6102 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }*/
6103         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
6104         { .val = 'z',   .name = "extension-size", .has_arg = no_argument },
6105         { .val = 'z',   .name = "ext-size",     .has_arg = no_argument },
6106         { .name = NULL } };
6107         int c, rc = 0;
6108         int neg_opt = 0;
6109         int pathstart = -1, pathend = -1;
6110         int isoption;
6111         char *end, *tmp;
6112
6113         while ((c = getopt_long(argc, argv,
6114                         "-cdDE::FghiI::LmMNoO:pqrRsSvyz",
6115                         long_opts, NULL)) != -1) {
6116                 if (neg_opt)
6117                         --neg_opt;
6118
6119                 /* '!' is part of option */
6120                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
6121                 if (!isoption && pathend != -1) {
6122                         fprintf(stderr,
6123                                 "error: %s: filename|dirname must either precede options or follow options\n",
6124                                 argv[0]);
6125                         return CMD_HELP;
6126                 }
6127                 if (!isoption && pathstart == -1)
6128                         pathstart = optind - 1;
6129                 if (isoption && pathstart != -1 && pathend == -1)
6130                         pathend = optind - 2;
6131
6132                 switch (c) {
6133                 case 1:
6134                         /* unknown: opt is "!" */
6135                         if (strcmp(optarg, "!") == 0)
6136                                 neg_opt = 2;
6137                         break;
6138                 case 'c':
6139                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6140                                 param->fp_verbose |= VERBOSE_COUNT;
6141                                 param->fp_max_depth = 0;
6142                         }
6143                         break;
6144                 case LFS_COMP_COUNT_OPT:
6145                         param->fp_verbose |= VERBOSE_COMP_COUNT;
6146                         param->fp_max_depth = 0;
6147                         break;
6148                 case LFS_COMP_FLAGS_OPT:
6149                         if (optarg) {
6150                                 rc = comp_str2flags(optarg,
6151                                                     &param->fp_comp_flags,
6152                                                     &param->fp_comp_neg_flags);
6153                                 if (rc != 0) {
6154                                         fprintf(stderr,
6155                                                 "error: %s bad component flags '%s'.\n",
6156                                                 argv[0], optarg);
6157                                         return CMD_HELP;
6158                                 }
6159                                 param->fp_check_comp_flags = 1;
6160                         } else {
6161                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
6162                                 param->fp_max_depth = 0;
6163                         }
6164                         break;
6165                 case LFS_COMP_START_OPT:
6166                         if (optarg) {
6167                                 tmp = optarg;
6168                                 if (tmp[0] == '+') {
6169                                         param->fp_comp_start_sign = -1;
6170                                         tmp++;
6171                                 } else if (tmp[0] == '-') {
6172                                         param->fp_comp_start_sign = 1;
6173                                         tmp++;
6174                                 }
6175                                 rc = llapi_parse_size(tmp,
6176                                                 &param->fp_comp_start,
6177                                                 &param->fp_comp_start_units, 0);
6178                                 if (rc != 0) {
6179                                         fprintf(stderr,
6180                                                 "error: %s bad component start '%s'.\n",
6181                                                 argv[0], tmp);
6182                                         return CMD_HELP;
6183                                 }
6184                                 param->fp_check_comp_start = 1;
6185                         } else {
6186                                 param->fp_verbose |= VERBOSE_COMP_START;
6187                                 param->fp_max_depth = 0;
6188                         }
6189                         break;
6190                 case LFS_MIRROR_INDEX_OPT: {
6191                         unsigned long int mirror_index;
6192
6193                         if (optarg[0] == '+') {
6194                                 param->fp_mirror_index_sign = -1;
6195                                 optarg++;
6196                         } else if (optarg[0] == '-') {
6197                                 param->fp_mirror_index_sign = 1;
6198                                 optarg++;
6199                         }
6200
6201                         errno = 0;
6202                         mirror_index = strtoul(optarg, &end, 0);
6203                         if (errno != 0 || *end != '\0' ||
6204                             mirror_index > UINT16_MAX || (mirror_index == 0 &&
6205                             param->fp_mirror_index_sign == 0 && neg_opt == 0)) {
6206                                 fprintf(stderr,
6207                                         "%s %s: invalid mirror index '%s'\n",
6208                                         progname, argv[0], optarg);
6209                                 return CMD_HELP;
6210                         }
6211
6212                         param->fp_mirror_index = (__u16)mirror_index;
6213
6214                         if (param->fp_mirror_id != 0) {
6215                                 fprintf(stderr,
6216                                         "%s %s: can't specify both mirror index and mirror ID\n",
6217                                         progname, argv[0]);
6218                                 return CMD_HELP;
6219                         }
6220                         param->fp_check_mirror_index = 1;
6221                         param->fp_exclude_mirror_index = !!neg_opt;
6222                         break;
6223                 }
6224                 case LFS_MIRROR_ID_OPT: {
6225                         unsigned long int mirror_id;
6226
6227                         if (optarg[0] == '+') {
6228                                 param->fp_mirror_id_sign = -1;
6229                                 optarg++;
6230                         } else if (optarg[0] == '-') {
6231                                 param->fp_mirror_id_sign = 1;
6232                                 optarg++;
6233                         }
6234
6235                         errno = 0;
6236                         mirror_id = strtoul(optarg, &end, 0);
6237                         if (errno != 0 || *end != '\0' ||
6238                             mirror_id > UINT16_MAX || (mirror_id == 0 &&
6239                             param->fp_mirror_id_sign == 0 && neg_opt == 0)) {
6240                                 fprintf(stderr,
6241                                         "%s %s: invalid mirror ID '%s'\n",
6242                                         progname, argv[0], optarg);
6243                                 return CMD_HELP;
6244                         }
6245
6246                         param->fp_mirror_id = (__u16)mirror_id;
6247
6248                         if (param->fp_mirror_index != 0) {
6249                                 fprintf(stderr,
6250                                         "%s %s: can't specify both mirror index and mirror ID\n",
6251                                         progname, argv[0]);
6252                                 return CMD_HELP;
6253                         }
6254                         param->fp_check_mirror_id = 1;
6255                         param->fp_exclude_mirror_id = !!neg_opt;
6256                         break;
6257                 }
6258                 case LFS_NO_FOLLOW_OPT:
6259                         param->fp_no_follow = true;
6260                         break;
6261                 case LFS_HEX_IDX_OPT:
6262                         param->fp_hex_idx = true;
6263                         break;
6264                 case 'd':
6265                         param->fp_max_depth = 0;
6266                         break;
6267                 case 'D':
6268                         param->fp_get_default_lmv = 1;
6269                         break;
6270                 case 'E':
6271                         if (optarg) {
6272                                 tmp = optarg;
6273                                 if (tmp[0] == '+') {
6274                                         param->fp_comp_end_sign = -1;
6275                                         tmp++;
6276                                 } else if (tmp[0] == '-') {
6277                                         param->fp_comp_end_sign = 1;
6278                                         tmp++;
6279                                 }
6280
6281                                 if (arg_is_eof(tmp)) {
6282                                         param->fp_comp_end = LUSTRE_EOF;
6283                                         param->fp_comp_end_units = 1;
6284                                         rc = 0;
6285                                 } else {
6286                                         rc = llapi_parse_size(tmp,
6287                                                 &param->fp_comp_end,
6288                                                 &param->fp_comp_end_units, 0);
6289                                         /* assume units of KB if too small */
6290                                         if (param->fp_comp_end < 4096)
6291                                                 param->fp_comp_end *= 1024;
6292                                 }
6293                                 if (rc != 0) {
6294                                         fprintf(stderr,
6295                                                 "error: %s bad component end '%s'.\n",
6296                                                 argv[0], tmp);
6297                                         return CMD_HELP;
6298                                 }
6299                                 param->fp_check_comp_end = 1;
6300                         } else {
6301                                 param->fp_verbose |= VERBOSE_COMP_END;
6302                                 param->fp_max_depth = 0;
6303                         }
6304                         break;
6305                 case 'F':
6306                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6307                                 param->fp_verbose |= VERBOSE_DFID;
6308                                 param->fp_max_depth = 0;
6309                         }
6310                         break;
6311                 case 'g':
6312                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6313                                 param->fp_verbose |= VERBOSE_GENERATION;
6314                                 param->fp_max_depth = 0;
6315                         }
6316                         break;
6317                 case 'i':
6318                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6319                                 param->fp_verbose |= VERBOSE_STRIPE_OFFSET;
6320                                 param->fp_max_depth = 0;
6321                         }
6322                         break;
6323                 case 'I':
6324                         if (optarg) {
6325                                 param->fp_comp_id = strtoul(optarg, &end, 0);
6326                                 if (*end != '\0' || param->fp_comp_id == 0 ||
6327                                     param->fp_comp_id > LCME_ID_MAX) {
6328                                         fprintf(stderr,
6329                                                 "error: %s bad component id '%s'\n",
6330                                                 argv[0], optarg);
6331                                         return CMD_HELP;
6332                                 }
6333                                 param->fp_check_comp_id = 1;
6334                         } else {
6335                                 param->fp_max_depth = 0;
6336                                 param->fp_verbose |= VERBOSE_COMP_ID;
6337                         }
6338                         break;
6339                 case 'L':
6340                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6341                                 param->fp_verbose |= VERBOSE_PATTERN;
6342                                 param->fp_max_depth = 0;
6343                         }
6344                         break;
6345 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6346                 case 'M':
6347                         fprintf(stderr,
6348                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
6349 #endif
6350                 case 'm':
6351                         if (!(param->fp_verbose & VERBOSE_DETAIL))
6352                                 param->fp_max_depth = 0;
6353                         param->fp_verbose |= VERBOSE_MDTINDEX;
6354                         break;
6355                 case 'N':
6356                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6357                                 param->fp_verbose |= VERBOSE_MIRROR_COUNT;
6358                                 param->fp_max_depth = 0;
6359                         }
6360                         break;
6361                 case 'O':
6362                         if (param->fp_obd_uuid) {
6363                                 fprintf(stderr,
6364                                         "error: %s: only one obduuid allowed",
6365                                         argv[0]);
6366                                 return CMD_HELP;
6367                         }
6368                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
6369                         break;
6370                 case 'p':
6371                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6372                                 param->fp_verbose |= VERBOSE_POOL;
6373                                 param->fp_max_depth = 0;
6374                         }
6375                         break;
6376                 case 'q':
6377                         param->fp_quiet++;
6378                         break;
6379                 case 'r':
6380                         param->fp_recursive = 1;
6381                         break;
6382                 case 'R':
6383                         param->fp_raw = 1;
6384                         break;
6385                 case 'S':
6386                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6387                                 param->fp_verbose |= VERBOSE_STRIPE_SIZE;
6388                                 param->fp_max_depth = 0;
6389                         }
6390                         break;
6391                 case 'v':
6392                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
6393                         break;
6394                 case 'y':
6395                         param->fp_yaml = 1;
6396                         break;
6397                 case 'z':
6398                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6399                                 param->fp_verbose |= VERBOSE_EXT_SIZE;
6400                                 param->fp_max_depth = 0;
6401                         }
6402                         break;
6403                 default:
6404                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6405                                 progname, argv[optind - 1]);
6406                 case 'h':
6407                         return CMD_HELP;
6408                 }
6409         }
6410
6411         if (pathstart == -1) {
6412                 fprintf(stderr, "error: %s: no filename|pathname\n",
6413                                 argv[0]);
6414                 return CMD_HELP;
6415         } else if (pathend == -1) {
6416                 /* no options */
6417                 pathend = argc;
6418         }
6419
6420         if (pathend > argc)
6421                 return CMD_HELP;
6422
6423         if (param->fp_recursive)
6424                 param->fp_max_depth = -1;
6425         else if (param->fp_verbose & VERBOSE_DETAIL)
6426                 param->fp_max_depth = 1;
6427
6428         if (!param->fp_verbose)
6429                 param->fp_verbose = VERBOSE_DEFAULT;
6430         if (param->fp_quiet)
6431                 param->fp_verbose = VERBOSE_OBJID;
6432
6433         do {
6434                 int rc2;
6435
6436                 rc2 = llapi_getstripe(argv[pathstart], param);
6437                 if (rc2) {
6438                         fprintf(stderr, "%s: %s for '%s' failed: %s\n",
6439                                 progname, argv[0], argv[pathstart],
6440                                 strerror(-rc2));
6441                         if (!rc)
6442                                 rc = rc2;
6443                 }
6444         } while (++pathstart < pathend);
6445
6446         return rc;
6447 }
6448
6449 static int lfs_tgts(int argc, char **argv)
6450 {
6451         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
6452         struct find_param param;
6453         int index = 0, rc = 0;
6454
6455         if (argc > 2)
6456                 return CMD_HELP;
6457
6458         if (argc == 2 && !realpath(argv[1], path)) {
6459                 rc = -errno;
6460                 fprintf(stderr, "error: invalid path '%s': %s\n",
6461                         argv[1], strerror(-rc));
6462                 return rc;
6463         }
6464
6465         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
6466                 /* Check if we have a mount point */
6467                 if (mntdir[0] == '\0')
6468                         continue;
6469
6470                 memset(&param, 0, sizeof(param));
6471                 if (!strcmp(argv[0], "mdts"))
6472                         param.fp_get_lmv = 1;
6473
6474                 rc = llapi_ostlist(mntdir, &param);
6475                 if (rc) {
6476                         fprintf(stderr, "error: %s: failed on %s\n",
6477                                 argv[0], mntdir);
6478                 }
6479                 if (path[0] != '\0')
6480                         break;
6481                 memset(mntdir, 0, PATH_MAX);
6482         }
6483
6484         return rc;
6485 }
6486
6487 static int lfs_getstripe(int argc, char **argv)
6488 {
6489         struct find_param param = { 0 };
6490
6491         param.fp_max_depth = 1;
6492         return lfs_getstripe_internal(argc, argv, &param);
6493 }
6494
6495 /* functions */
6496 static int lfs_getdirstripe(int argc, char **argv)
6497 {
6498         struct find_param param = { 0 };
6499         struct option long_opts[] = {
6500         { .val = 'c',   .name = "mdt-count",     .has_arg = no_argument },
6501         { .val = 'D',   .name = "default",       .has_arg = no_argument },
6502         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6503         { .val = 'H',   .name = "mdt-hash",      .has_arg = no_argument },
6504         { .val = LFS_HEX_IDX_OPT,
6505                         .name = "hex-idx",       .has_arg = no_argument },
6506         { .val = 'i',   .name = "mdt-index",     .has_arg = no_argument },
6507         { .val = 'm',   .name = "mdt-index",     .has_arg = no_argument },
6508         { .val = 'O',   .name = "obd",           .has_arg = required_argument },
6509         { .val = 'r',   .name = "recursive",     .has_arg = no_argument },
6510         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
6511         { .val = 'T',   .name = "mdt-count",     .has_arg = no_argument },
6512         { .val = 'v',   .name = "verbose",       .has_arg = no_argument },
6513         { .val = 'X',   .name = "max-inherit",   .has_arg = no_argument },
6514         { .val = LFS_INHERIT_RR_OPT,
6515                         .name = "max-inherit-rr", .has_arg = no_argument },
6516         { .val = 'y',   .name = "yaml",          .has_arg = no_argument },
6517         { .name = NULL } };
6518         int c, rc = 0;
6519
6520         param.fp_get_lmv = 1;
6521
6522         while ((c = getopt_long(argc, argv,
6523                                 "cDhHimO:rRtTvXy", long_opts, NULL)) != -1) {
6524                 switch (c) {
6525                 case 'c':
6526                 case 'T':
6527                         param.fp_verbose |= VERBOSE_COUNT;
6528                         break;
6529                 case 'D':
6530                         param.fp_get_default_lmv = 1;
6531                         break;
6532 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6533                 case 't':
6534                         fprintf(stderr,
6535                                 "warning: '-t' deprecated, use '--mdt-hash' or '-H' instead\n");
6536                         fallthrough;
6537 #endif
6538                 case 'H':
6539                         param.fp_verbose |= VERBOSE_HASH_TYPE;
6540                         break;
6541                 case LFS_HEX_IDX_OPT:
6542                         param.fp_hex_idx = 1;
6543                         break;
6544                 case 'i':
6545                         fallthrough;
6546                 case 'm':
6547                         param.fp_verbose |= VERBOSE_STRIPE_OFFSET;
6548                         break;
6549                 case 'O':
6550                         if (param.fp_obd_uuid) {
6551                                 fprintf(stderr,
6552                                         "%s: only one obduuid allowed",
6553                                         progname);
6554                                 return CMD_HELP;
6555                         }
6556                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
6557                         break;
6558                 case 'r':
6559                         param.fp_recursive = 1;
6560                         break;
6561                 case 'R':
6562                         param.fp_raw = 1;
6563                         break;
6564                 case 'v':
6565                         param.fp_verbose |= VERBOSE_DEFAULT;
6566                         param.fp_verbose |= VERBOSE_DETAIL;
6567                         break;
6568                 case 'X':
6569                         param.fp_verbose |= VERBOSE_INHERIT;
6570                         break;
6571                 case LFS_INHERIT_RR_OPT:
6572                         param.fp_verbose |= VERBOSE_INHERIT_RR;
6573                         break;
6574                 case 'y':
6575                         param.fp_yaml = 1;
6576                         break;
6577                 default:
6578                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6579                                 progname, argv[optind - 1]);
6580                         fallthrough;
6581                 case 'h':
6582                         return CMD_HELP;
6583                 }
6584         }
6585
6586         if (optind >= argc)
6587                 return CMD_HELP;
6588
6589         if (param.fp_recursive)
6590                 param.fp_max_depth = -1;
6591
6592         if (!param.fp_verbose)
6593                 param.fp_verbose = VERBOSE_DEFAULT;
6594
6595         do {
6596                 int rc2;
6597
6598                 rc2 = llapi_getstripe(argv[optind], &param);
6599                 if (rc2) {
6600                         fprintf(stderr, "%s: %s for '%s' failed: %s\n",
6601                                 progname, argv[0], argv[optind],
6602                                 strerror(-rc2));
6603                         if (!rc)
6604                                 rc = rc2;
6605                 }
6606         } while (++optind < argc);
6607
6608         return rc;
6609 }
6610
6611 enum mntdf_flags {
6612         MNTDF_INODES    = 0x0001,
6613         MNTDF_COOKED    = 0x0002,
6614         MNTDF_LAZY      = 0x0004,
6615         MNTDF_VERBOSE   = 0x0008,
6616         MNTDF_SHOW      = 0x0010,
6617         MNTDF_DECIMAL   = 0x0020,
6618 };
6619
6620 #define COOK(value, base)                                       \
6621 ({                                                              \
6622         int radix = 0;                                          \
6623         while (value > base) {                                  \
6624                 value /= base;                                  \
6625                 radix++;                                        \
6626         }                                                       \
6627         radix;                                                  \
6628 })
6629 #define UUF     "%-20s"
6630 #define CSF     "%11s"
6631 #define CDF     "%11llu"
6632 #define HDF     "%8.1f%c"
6633 #define RSF     "%4s"
6634 #define RDF     "%3d%%"
6635
6636 static inline int obd_statfs_ratio(const struct obd_statfs *st, bool inodes)
6637 {
6638         double avail, used, ratio = 0;
6639
6640         if (inodes) {
6641                 avail = st->os_ffree;
6642                 used = st->os_files - st->os_ffree;
6643         } else {
6644                 avail = st->os_bavail;
6645                 used = st->os_blocks - st->os_bfree;
6646         }
6647         if (avail + used > 0)
6648                 ratio = used / (used + avail) * 100;
6649
6650         /* Round up to match df(1) usage percentage */
6651         return (ratio - (int)ratio) > 0 ? (int)(ratio + 1) : (int)ratio;
6652 }
6653
6654 /*
6655  * This is to identify various problem states for "lfs df" if .osn_err = true,
6656  * so only show flags reflecting those states by default. Informational states
6657  * are only shown with "-v" and use lower-case names to distinguish them.
6658  * UNUSED[12] were for "EROFS = 30" until 1.6 but are now available for use.
6659  */
6660 static struct obd_statfs_state_names {
6661         enum obd_statfs_state   osn_state;
6662         const char              osn_name;
6663         bool                    osn_err;
6664 } oss_names[] = {
6665         { .osn_state = OS_STATFS_DEGRADED,   .osn_name = 'D', .osn_err = true },
6666         { .osn_state = OS_STATFS_READONLY,   .osn_name = 'R', .osn_err = true },
6667         { .osn_state = OS_STATFS_NOCREATE,   .osn_name = 'N', .osn_err = true },
6668         { .osn_state = OS_STATFS_UNUSED1,    .osn_name = '?', .osn_err = true },
6669         { .osn_state = OS_STATFS_UNUSED2,    .osn_name = '?', .osn_err = true },
6670         { .osn_state = OS_STATFS_ENOSPC,     .osn_name = 'S', .osn_err = true },
6671         { .osn_state = OS_STATFS_ENOINO,     .osn_name = 'I', .osn_err = true },
6672         { .osn_state = OS_STATFS_SUM,        .osn_name = 'a', /* aggregate */ },
6673         { .osn_state = OS_STATFS_NONROT,     .osn_name = 'f', /* flash */     },
6674 };
6675
6676 static int showdf(char *mntdir, struct obd_statfs *stat,
6677                   char *uuid, enum mntdf_flags flags,
6678                   char *type, int index, int rc)
6679 {
6680         long long avail, used, total;
6681         int ratio = 0;
6682         char *suffix = flags & MNTDF_DECIMAL ? "kMGTPEZY" : "KMGTPEZY";
6683         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
6684         char tbuf[3 * sizeof(__u64)];
6685         char ubuf[3 * sizeof(__u64)];
6686         char abuf[3 * sizeof(__u64)];
6687         char rbuf[3 * sizeof(__u64)];
6688
6689         if (!uuid || !stat)
6690                 return -EINVAL;
6691
6692         switch (rc) {
6693         case 0:
6694                 if (flags & MNTDF_INODES) {
6695                         avail = stat->os_ffree;
6696                         used = stat->os_files - stat->os_ffree;
6697                         total = stat->os_files;
6698                 } else {
6699                         int shift = flags & MNTDF_COOKED ? 0 : 10;
6700
6701                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
6702                         used  = ((stat->os_blocks - stat->os_bfree) *
6703                                  stat->os_bsize) >> shift;
6704                         total = (stat->os_blocks * stat->os_bsize) >> shift;
6705                 }
6706
6707                 ratio = obd_statfs_ratio(stat, flags & MNTDF_INODES);
6708
6709                 if (flags & MNTDF_COOKED) {
6710                         int base = flags & MNTDF_DECIMAL ? 1000 : 1024;
6711                         double cook_val;
6712                         int i;
6713
6714                         cook_val = (double)total;
6715                         i = COOK(cook_val, base);
6716                         if (i > 0)
6717                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
6718                                          suffix[i - 1]);
6719                         else
6720                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
6721
6722                         cook_val = (double)used;
6723                         i = COOK(cook_val, base);
6724                         if (i > 0)
6725                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
6726                                          suffix[i - 1]);
6727                         else
6728                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
6729
6730                         cook_val = (double)avail;
6731                         i = COOK(cook_val, base);
6732                         if (i > 0)
6733                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
6734                                          suffix[i - 1]);
6735                         else
6736                                 snprintf(abuf, sizeof(abuf), CDF, avail);
6737                 } else {
6738                         snprintf(tbuf, sizeof(tbuf), CDF, total);
6739                         snprintf(ubuf, sizeof(tbuf), CDF, used);
6740                         snprintf(abuf, sizeof(tbuf), CDF, avail);
6741                 }
6742
6743                 sprintf(rbuf, RDF, ratio);
6744                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
6745                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
6746                 if (type)
6747                         printf("[%s:%d]", type, index);
6748
6749                 if (stat->os_state) {
6750                         uint32_t i;
6751
6752                         printf(" ");
6753                         for (i = 0; i < ARRAY_SIZE(oss_names); i++) {
6754                                 if (oss_names[i].osn_state & stat->os_state &&
6755                                     (oss_names[i].osn_err ||
6756                                      flags & MNTDF_VERBOSE))
6757                                         printf("%c", oss_names[i].osn_name);
6758                         }
6759                 }
6760
6761                 printf("\n");
6762                 break;
6763         case -ENODATA:
6764                 printf(UUF": inactive device\n", uuid);
6765                 break;
6766         default:
6767                 printf(UUF": %s\n", uuid, strerror(-rc));
6768                 break;
6769         }
6770
6771         return 0;
6772 }
6773
6774 struct ll_stat_type {
6775         int   st_op;
6776         char *st_name;
6777 };
6778
6779 #define LL_STATFS_MAX   LOV_MAX_STRIPE_COUNT
6780
6781 struct ll_statfs_data {
6782         int                     sd_index;
6783         struct obd_statfs       sd_st;
6784 };
6785
6786 struct ll_statfs_buf {
6787         int                     sb_count;
6788         struct ll_statfs_data   sb_buf[LL_STATFS_MAX];
6789 };
6790
6791 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags,
6792                  int ops, struct ll_statfs_buf *lsb)
6793 {
6794         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
6795         struct obd_uuid uuid_buf;
6796         char *poolname = NULL;
6797         struct ll_stat_type types[] = {
6798                 { .st_op = LL_STATFS_LMV,       .st_name = "MDT" },
6799                 { .st_op = LL_STATFS_LOV,       .st_name = "OST" },
6800                 { .st_name = NULL } };
6801         struct ll_stat_type *tp;
6802         __u64 ost_files = 0;
6803         __u64 ost_ffree = 0;
6804         __u32 index;
6805         __u32 type;
6806         int fd;
6807         int rc = 0;
6808         int rc2;
6809
6810         if (pool) {
6811                 poolname = strchr(pool, '.');
6812                 if (poolname) {
6813                         if (strncmp(fsname, pool, strlen(fsname))) {
6814                                 fprintf(stderr, "filesystem name incorrect\n");
6815                                 return -ENODEV;
6816                         }
6817                         poolname++;
6818                 } else
6819                         poolname = pool;
6820         }
6821
6822         fd = open(mntdir, O_RDONLY);
6823         if (fd < 0) {
6824                 rc = -errno;
6825                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
6826                         strerror(errno));
6827                 return rc;
6828         }
6829
6830         if (flags & MNTDF_SHOW) {
6831                 if (flags & MNTDF_INODES)
6832                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
6833                                "UUID", "Inodes", "IUsed", "IFree",
6834                                "IUse%", "Mounted on");
6835                 else
6836                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
6837                                "UUID",
6838                                flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
6839                                "Used", "Available", "Use%", "Mounted on");
6840         }
6841
6842         for (tp = types; tp->st_name != NULL; tp++) {
6843                 bool have_ost = false;
6844
6845                 if (!(tp->st_op & ops))
6846                         continue;
6847
6848                 for (index = 0; index < LOV_ALL_STRIPES &&
6849                      (!lsb || lsb->sb_count < LL_STATFS_MAX); index++) {
6850                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
6851                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
6852                         type = flags & MNTDF_LAZY ?
6853                                 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
6854                         rc2 = llapi_obd_fstatfs(fd, type, index,
6855                                                 &stat_buf, &uuid_buf);
6856                         if (rc2 == -ENODEV)
6857                                 break;
6858                         if (rc2 == -EAGAIN)
6859                                 continue;
6860                         if (rc2 == -ENODATA) { /* Inactive device, OK. */
6861                                 if (!(flags & MNTDF_VERBOSE))
6862                                         continue;
6863                         } else if (rc2 < 0 && rc == 0) {
6864                                 rc = rc2;
6865                         }
6866
6867                         /*
6868                          * If we have OSTs then don't report MDT block counts.
6869                          * For MDT-only filesystems the expectation is that all
6870                          * layouts have a DoM component.  For filesystems with
6871                          * OSTs, files are not necessarily going to store data
6872                          * on MDTs, and MDT space is limited to a fraction of
6873                          * OST space, so don't include it in the summary.
6874                          */
6875                         if (tp->st_op == LL_STATFS_LOV && !have_ost) {
6876                                 have_ost = true;
6877                                 sum.os_blocks = 0;
6878                                 sum.os_bfree = 0;
6879                                 sum.os_bavail = 0;
6880                         }
6881
6882                         if (poolname && tp->st_op == LL_STATFS_LOV &&
6883                             llapi_search_ost(fsname, poolname,
6884                                              obd_uuid2str(&uuid_buf)) != 1)
6885                                 continue;
6886
6887                         /*
6888                          * the llapi_obd_fstatfs() call may have returned with
6889                          * an error, but if it filled in uuid_buf we will at
6890                          * lease use that to print out a message for that OBD.
6891                          * If we didn't get anything in the uuid_buf, then fill
6892                          * it in so that we can print an error message.
6893                          */
6894                         if (uuid_buf.uuid[0] == '\0')
6895                                 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
6896                                          "%s%04x", tp->st_name, index);
6897                         if (!rc && lsb) {
6898                                 lsb->sb_buf[lsb->sb_count].sd_index = index;
6899                                 lsb->sb_buf[lsb->sb_count].sd_st = stat_buf;
6900                                 lsb->sb_count++;
6901                         }
6902                         if (flags & MNTDF_SHOW)
6903                                 showdf(mntdir, &stat_buf,
6904                                        obd_uuid2str(&uuid_buf), flags,
6905                                        tp->st_name, index, rc2);
6906
6907                         if (rc2)
6908                                 continue;
6909
6910                         if (tp->st_op == LL_STATFS_LMV) {
6911                                 sum.os_ffree += stat_buf.os_ffree;
6912                                 sum.os_files += stat_buf.os_files;
6913                         } else /* if (tp->st_op == LL_STATFS_LOV) */ {
6914                                 ost_files += stat_buf.os_files;
6915                                 ost_ffree += stat_buf.os_ffree;
6916                         }
6917                         sum.os_blocks += stat_buf.os_blocks *
6918                                          stat_buf.os_bsize;
6919                         sum.os_bfree  += stat_buf.os_bfree *
6920                                          stat_buf.os_bsize;
6921                         sum.os_bavail += stat_buf.os_bavail *
6922                                          stat_buf.os_bsize;
6923                 }
6924         }
6925
6926         close(fd);
6927
6928         /*
6929          * If we have _some_ OSTs, but don't have as many free objects on the
6930          * OST as inodes on the MDTs, reduce the reported number of inodes
6931          * to compensate, so that the "inodes in use" number is correct.
6932          * This should be kept in sync with ll_statfs_internal().
6933          */
6934         if (ost_files && ost_ffree < sum.os_ffree) {
6935                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
6936                 sum.os_ffree = ost_ffree;
6937         }
6938         if (flags & MNTDF_SHOW) {
6939                 printf("\n");
6940                 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
6941                 printf("\n");
6942         }
6943
6944         return rc;
6945 }
6946
6947 enum {
6948         LAYOUT_INHERIT_UNSET    = -2,
6949 };
6950
6951 /* functions */
6952 static int lfs_setdirstripe(int argc, char **argv)
6953 {
6954         char *dname;
6955         struct lfs_setstripe_args lsa = { 0 };
6956         struct llapi_stripe_param *param = NULL;
6957         __u32 mdts[LMV_MAX_STRIPE_COUNT] = { 0 };
6958         char *end;
6959         int c;
6960         char *mode_opt = NULL;
6961         bool default_stripe = false;
6962         bool delete = false;
6963         bool foreign_mode = false;
6964         bool mdt_count_set = false;
6965         mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
6966         mode_t previous_mode = 0;
6967         char *xattr = NULL;
6968         __u32 type = LU_FOREIGN_TYPE_SYMLINK, flags = 0;
6969         int max_inherit = LAYOUT_INHERIT_UNSET;
6970         int max_inherit_rr = LAYOUT_INHERIT_UNSET;
6971         struct option long_opts[] = {
6972         { .val = 'c',   .name = "count",        .has_arg = required_argument },
6973         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
6974         { .val = 'd',   .name = "delete",       .has_arg = no_argument },
6975         { .val = 'D',   .name = "default",      .has_arg = no_argument },
6976         { .val = 'D',   .name = "default_stripe", .has_arg = no_argument },
6977         { .val = LFS_LAYOUT_FLAGS_OPT,
6978                         .name = "flags",        .has_arg = required_argument },
6979         { .val = LFS_LAYOUT_FOREIGN_OPT,
6980                         .name = "foreign",      .has_arg = optional_argument},
6981         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6982         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
6983 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 17, 53, 0)
6984         { .val = 'i',   .name = "mdt-index",    .has_arg = required_argument },
6985         { .val = 'i',   .name = "mdt",          .has_arg = required_argument },
6986 #else
6987 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
6988         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
6989         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
6990 #endif
6991 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6992         { .val = 'i',   .name = "index",        .has_arg = required_argument },
6993 #endif
6994         { .val = 'o',   .name = "mode",         .has_arg = required_argument },
6995 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6996         { .val = 't',   .name = "hash-type",    .has_arg = required_argument },
6997 #endif
6998         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
6999         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
7000         { .val = 'X',   .name = "max-inherit",  .has_arg = required_argument },
7001         { .val = LFS_INHERIT_RR_OPT,
7002                         .name = "max-inherit-rr", .has_arg = required_argument},
7003 /* setstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
7004 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }, */
7005         { .name = NULL } };
7006         int result = 0;
7007
7008         setstripe_args_init(&lsa);
7009
7010         while ((c = getopt_long(argc, argv, "c:dDi:hH:m:o:t:T:x:X:",
7011                                 long_opts, NULL)) >= 0) {
7012                 switch (c) {
7013                 case 0:
7014                         /* Long options. */
7015                         break;
7016                 case 'c':
7017                 case 'T':
7018                         errno = 0;
7019                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
7020                         if (errno != 0 || *end != '\0' ||
7021                             lsa.lsa_stripe_count < -1 ||
7022                             lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
7023                                 fprintf(stderr,
7024                                         "%s: invalid stripe count '%s'\n",
7025                                         progname, optarg);
7026                                 return CMD_HELP;
7027                         }
7028                         mdt_count_set = true;
7029                         break;
7030                 case 'd':
7031                         delete = true;
7032                         default_stripe = true;
7033                         break;
7034                 case 'D':
7035                         default_stripe = true;
7036                         break;
7037                 case LFS_LAYOUT_FOREIGN_OPT:
7038                         if (optarg) {
7039                                 /* check pure numeric */
7040                                 type = strtoul(optarg, &end, 0);
7041                                 if (*end) {
7042                                         /* check name */
7043                                         type = check_foreign_type_name(optarg);
7044                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
7045                                                 fprintf(stderr,
7046                                                         "%s %s: unknown foreign type '%s'\n",
7047                                                         progname, argv[0],
7048                                                         optarg);
7049                                                 return CMD_HELP;
7050                                         }
7051                                 } else if (type >= UINT32_MAX) {
7052                                         fprintf(stderr,
7053                                                 "%s %s: invalid foreign type '%s'\n",
7054                                                 progname, argv[0], optarg);
7055                                         return CMD_HELP;
7056                                 }
7057                         }
7058                         foreign_mode = true;
7059                         break;
7060                 case LFS_LAYOUT_FLAGS_OPT:
7061                         errno = 0;
7062                         flags = strtoul(optarg, &end, 16);
7063                         if (errno != 0 || *end != '\0' ||
7064                             flags >= UINT32_MAX) {
7065                                 fprintf(stderr,
7066                                         "%s %s: invalid hex flags '%s'\n",
7067                                         progname, argv[0], optarg);
7068                                 return CMD_HELP;
7069                         }
7070                         if (!foreign_mode) {
7071                                 fprintf(stderr,
7072                                         "%s %s: hex flags must be specified with --foreign option\n",
7073                                         progname, argv[0]);
7074                                 return CMD_HELP;
7075                         }
7076                         break;
7077 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7078                 case 't':
7079                         fprintf(stderr,
7080                                 "warning: '--hash-type' and '-t' deprecated, use '--mdt-hash' or '-H' instead\n");
7081                         fallthrough;
7082 #endif
7083                 case 'H':
7084                         lsa.lsa_pattern = check_hashtype(optarg);
7085                         if (lsa.lsa_pattern == 0) {
7086                                 fprintf(stderr,
7087                                         "%s %s: bad directory hash type '%s'\n",
7088                                         progname, argv[0], optarg);
7089                                 return CMD_HELP;
7090                         }
7091                         break;
7092                 case 'i':
7093 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 17, 53, 0)
7094                 case 'm':
7095 #endif
7096 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7097                         if (strcmp(argv[optind - 1], "--index") == 0)
7098                                 fprintf(stderr,
7099                                         "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
7100                                         progname, argv[0]);
7101 #endif
7102                         lsa.lsa_nr_tgts = parse_targets(mdts,
7103                                                 sizeof(mdts) / sizeof(__u32),
7104                                                 lsa.lsa_nr_tgts, optarg, NULL);
7105                         if (lsa.lsa_nr_tgts < 0) {
7106                                 fprintf(stderr,
7107                                         "%s %s: invalid MDT target(s) '%s'\n",
7108                                         progname, argv[0], optarg);
7109                                 return CMD_HELP;
7110                         }
7111
7112                         lsa.lsa_tgts = mdts;
7113                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
7114                                 lsa.lsa_stripe_off = mdts[0];
7115                         break;
7116                 case 'o':
7117                         mode_opt = optarg;
7118                         break;
7119                 case 'x':
7120                         xattr = optarg;
7121                         break;
7122                 case 'X':
7123                         errno = 0;
7124                         max_inherit = strtol(optarg, &end, 10);
7125                         if (errno != 0 || *end != '\0' || max_inherit < -2) {
7126                                 fprintf(stderr,
7127                                         "%s %s: invalid max-inherit '%s'\n",
7128                                         progname, argv[0], optarg);
7129                                 return CMD_HELP;
7130                         }
7131                         if (max_inherit == 0) {
7132                                 max_inherit = LMV_INHERIT_NONE;
7133                         } else if (max_inherit == -1) {
7134                                 max_inherit = LMV_INHERIT_UNLIMITED;
7135                         } else if (max_inherit > LMV_INHERIT_MAX) {
7136                                 fprintf(stderr,
7137                                         "%s %s: max-inherit %d exceeds maximum %u\n",
7138                                         progname, argv[0], max_inherit,
7139                                         LMV_INHERIT_MAX);
7140                                 return CMD_HELP;
7141                         }
7142                         break;
7143                 case LFS_INHERIT_RR_OPT:
7144                         if (!default_stripe) {
7145                                 fprintf(stderr,
7146                                         "%s %s: '--max-inherit-rr' must be specified with '-D'\n",
7147                                         progname, argv[0]);
7148                                 return CMD_HELP;
7149                         }
7150                         errno = 0;
7151                         max_inherit_rr = strtol(optarg, &end, 10);
7152                         if (errno != 0 || *end != '\0' || max_inherit_rr < -2) {
7153                                 fprintf(stderr,
7154                                         "%s %s: invalid max-inherit-rr '%s'\n",
7155                                         progname, argv[0], optarg);
7156                                 return CMD_HELP;
7157                         }
7158                         if (max_inherit_rr == 0) {
7159                                 max_inherit_rr = LMV_INHERIT_RR_NONE;
7160                         } else if (max_inherit_rr == -1) {
7161                                 max_inherit_rr = LMV_INHERIT_RR_UNLIMITED;
7162                         } else if (max_inherit_rr > LMV_INHERIT_RR_MAX) {
7163                                 fprintf(stderr,
7164                                         "%s %s: max-inherit-rr %d exceeds maximum %u\n",
7165                                         progname, argv[0], max_inherit_rr,
7166                                         LMV_INHERIT_RR_MAX);
7167                                 return CMD_HELP;
7168                         }
7169                         break;
7170                 default:
7171                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7172                                 progname, argv[optind - 1]);
7173                         fallthrough;
7174                 case 'h':
7175                         return CMD_HELP;
7176                 }
7177         }
7178
7179         if (optind == argc) {
7180                 fprintf(stderr, "%s %s: DIR must be specified\n",
7181                         progname, argv[0]);
7182                 return CMD_HELP;
7183         }
7184
7185         if (xattr && !foreign_mode) {
7186                 /*
7187                  * only print a warning as this is armless and will be
7188                  * ignored
7189                  */
7190                 fprintf(stderr,
7191                         "%s %s: xattr has been specified for non-foreign layout\n",
7192                         progname, argv[0]);
7193         } else if (foreign_mode && !xattr) {
7194                 fprintf(stderr,
7195                         "%s %s: xattr must be provided in foreign mode\n",
7196                         progname, argv[0]);
7197                 return CMD_HELP;
7198         }
7199
7200         if (foreign_mode && (delete || default_stripe || lsa.lsa_nr_tgts ||
7201             lsa.lsa_tgts || setstripe_args_specified(&lsa))) {
7202                 fprintf(stderr,
7203                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
7204                         progname, argv[0]);
7205                 return CMD_HELP;
7206         }
7207
7208         if (!delete && lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT &&
7209             lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT && !foreign_mode) {
7210                 /* if no parameters set, create directory on least-used MDTs */
7211                 lsa.lsa_stripe_off = LMV_OFFSET_DEFAULT;
7212                 lsa.lsa_stripe_count = 1;
7213         }
7214
7215         if (delete &&
7216             (lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
7217              lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)) {
7218                 fprintf(stderr,
7219                         "%s %s: cannot specify -d with -c or -i options\n",
7220                         progname, argv[0]);
7221                 return CMD_HELP;
7222         }
7223
7224         if (mode_opt) {
7225                 mode = strtoul(mode_opt, &end, 8);
7226                 if (*end != '\0') {
7227                         fprintf(stderr,
7228                                 "%s %s: bad MODE '%s'\n",
7229                                 progname, argv[0], mode_opt);
7230                         return CMD_HELP;
7231                 }
7232                 previous_mode = umask(0);
7233         }
7234
7235         /* check max-inherit and warn user in some cases */
7236         if (default_stripe &&
7237             (lsa.lsa_stripe_count < 0 || lsa.lsa_stripe_count > 1)) {
7238                 if (max_inherit == LMV_INHERIT_UNLIMITED)
7239                         fprintf(stderr,
7240                         "%s %s: unrecommended max-inherit=-1 when default stripe-count=%lld\n",
7241                         progname, argv[0], lsa.lsa_stripe_count);
7242                 else if (max_inherit > LMV_INHERIT_DEFAULT_STRIPED + 2 &&
7243                          max_inherit != LMV_INHERIT_NONE)
7244                         fprintf(stderr,
7245                                 "%s %s: unrecommended max-inherit=%d when default stripe-count=%lld\n",
7246                                 progname, argv[0], max_inherit,
7247                                 lsa.lsa_stripe_count);
7248         }
7249
7250         if (default_stripe && lsa.lsa_nr_tgts > 1 && !mdt_count_set) {
7251                 fprintf(stderr,
7252                         "%s %s: trying to create unrecommended default striped directory layout,\n"
7253                         "       '-D -i x,y,z' will stripe every new directory across all MDTs,\n"
7254                         "       add -c with the number of MDTs to do this anyway\n",
7255                         progname, argv[0]);
7256                 return CMD_HELP;
7257         }
7258
7259         if (max_inherit_rr != LAYOUT_INHERIT_UNSET &&
7260             lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT &&
7261             lsa.lsa_stripe_off != LMV_OFFSET_DEFAULT) {
7262                 fprintf(stderr,
7263                         "%s %s: max-inherit-rr needs mdt-index=-1, not %lld\n",
7264                         progname, argv[0], lsa.lsa_stripe_off);
7265                 return CMD_HELP;
7266         }
7267
7268         /* foreign LMV/dir case */
7269         if (foreign_mode) {
7270                 if (argc > optind + 1) {
7271                         fprintf(stderr,
7272                                 "%s %s: cannot specify multiple foreign dirs\n",
7273                                 progname, argv[0]);
7274                         return CMD_HELP;
7275                 }
7276
7277                 dname = argv[optind];
7278                 result = llapi_dir_create_foreign(dname, mode, type, flags,
7279                                                   xattr);
7280                 if (result != 0)
7281                         fprintf(stderr,
7282                                 "%s mkdir: can't create foreign dir '%s': %s\n",
7283                                 progname, dname, strerror(-result));
7284                 return result;
7285         }
7286
7287         /*
7288          * initialize stripe parameters, in case param is converted to specific,
7289          * i.e, 'lfs mkdir -i -1 -c N', always allocate space for lsp_tgts.
7290          */
7291         param = calloc(1, offsetof(typeof(*param),
7292                        lsp_tgts[lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ?
7293                                 lsa.lsa_stripe_count : lsa.lsa_nr_tgts]));
7294         if (!param) {
7295                 fprintf(stderr,
7296                         "%s %s: cannot allocate memory for parameters: %s\n",
7297                         progname, argv[0], strerror(ENOMEM));
7298                 return CMD_HELP;
7299         }
7300
7301         /* if "lfs setdirstripe -D -i -1" is used, assume 1-stripe directory */
7302         if (default_stripe && lsa.lsa_stripe_off == LMV_OFFSET_DEFAULT &&
7303             (lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT ||
7304              lsa.lsa_stripe_count == 0))
7305                 lsa.lsa_stripe_count = 1;
7306         if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
7307                 param->lsp_stripe_count = lsa.lsa_stripe_count;
7308         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
7309                 param->lsp_stripe_offset = LMV_OFFSET_DEFAULT;
7310         else
7311                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
7312         if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
7313                 param->lsp_stripe_pattern = lsa.lsa_pattern;
7314         else
7315                 param->lsp_stripe_pattern = LMV_HASH_TYPE_UNKNOWN;
7316         param->lsp_pool = lsa.lsa_pool_name;
7317         param->lsp_is_specific = false;
7318
7319         if (max_inherit == LAYOUT_INHERIT_UNSET) {
7320                 if (lsa.lsa_stripe_count == 0 || lsa.lsa_stripe_count == 1 ||
7321                     lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT)
7322                         max_inherit = LMV_INHERIT_DEFAULT_PLAIN;
7323                 else
7324                         max_inherit = LMV_INHERIT_DEFAULT_STRIPED;
7325         }
7326         param->lsp_max_inherit = max_inherit;
7327         if (default_stripe) {
7328
7329                 if (max_inherit_rr == LAYOUT_INHERIT_UNSET)
7330                         max_inherit_rr = LMV_INHERIT_RR_DEFAULT;
7331                 param->lsp_max_inherit_rr = max_inherit_rr;
7332         }
7333         if (strcmp(argv[0], "mkdir") == 0)
7334                 param->lsp_is_create = true;
7335         if (lsa.lsa_nr_tgts > 1) {
7336                 if (lsa.lsa_stripe_count > 0 &&
7337                     lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
7338                     lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
7339                         fprintf(stderr,
7340                                 "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
7341                                 argv[0], lsa.lsa_stripe_count,
7342                                 lsa.lsa_nr_tgts);
7343                         free(param);
7344                         return CMD_HELP;
7345                 }
7346
7347                 param->lsp_is_specific = true;
7348                 param->lsp_stripe_count = lsa.lsa_nr_tgts;
7349                 memcpy(param->lsp_tgts, mdts, sizeof(*mdts) * lsa.lsa_nr_tgts);
7350         }
7351
7352         dname = argv[optind];
7353         do {
7354                 if (default_stripe) {
7355                         result = llapi_dir_set_default_lmv(dname, param);
7356                         if (result)
7357                                 fprintf(stderr,
7358                                         "%s setdirstripe: cannot set default stripe on dir '%s': %s\n",
7359                                         progname, dname, strerror(-result));
7360                         continue;
7361                 }
7362
7363                 result = llapi_dir_create(dname, mode, param);
7364                 if (result)
7365                         fprintf(stderr,
7366                                 "%s setdirstripe: cannot create dir '%s': %s\n",
7367                                 progname, dname, strerror(-result));
7368         } while ((dname = argv[++optind]));
7369
7370         if (mode_opt)
7371                 umask(previous_mode);
7372
7373         free(param);
7374         return result;
7375 }
7376
7377 static int lfs_rmentry(int argc, char **argv)
7378 {
7379         char *dname;
7380         int index;
7381         int result = 0;
7382
7383         if (argc <= 1) {
7384                 fprintf(stderr, "error: %s: missing dirname\n",
7385                         argv[0]);
7386                 return CMD_HELP;
7387         }
7388
7389         index = 1;
7390         dname = argv[index];
7391         while (dname) {
7392                 int rc2;
7393
7394                 rc2 = llapi_direntry_remove(dname);
7395                 if (rc2) {
7396                         fprintf(stderr,
7397                                 "%s %s: remove dir entry '%s' failed: %s\n",
7398                                 progname, argv[0], dname, strerror(-rc2));
7399                         if (!result)
7400                                 result = rc2;
7401                 }
7402                 dname = argv[++index];
7403         }
7404         return result;
7405 }
7406
7407 static int lfs_unlink_foreign(int argc, char **argv)
7408 {
7409         char *name;
7410         int   index;
7411         int   result = 0;
7412
7413         if (argc <= 1) {
7414                 fprintf(stderr, "error: %s: missing pathname\n",
7415                         argv[0]);
7416                 return CMD_HELP;
7417         }
7418
7419         index = 1;
7420         name = argv[index];
7421         while (name != NULL) {
7422                 result = llapi_unlink_foreign(name);
7423                 if (result) {
7424                         fprintf(stderr,
7425                                 "error: %s: unlink foreign entry '%s' failed\n",
7426                                 argv[0], name);
7427                         break;
7428                 }
7429                 name = argv[++index];
7430         }
7431         return result;
7432 }
7433
7434 static int lfs_mv(int argc, char **argv)
7435 {
7436         struct lmv_user_md lmu = { LMV_USER_MAGIC };
7437         struct find_param param = {
7438                 .fp_max_depth = -1,
7439                 .fp_mdt_index = -1,
7440         };
7441         char *end;
7442         int c;
7443         int rc = 0;
7444         struct option long_opts[] = {
7445         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
7446         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
7447         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7448         { .name = NULL } };
7449
7450         while ((c = getopt_long(argc, argv, "m:M:v", long_opts, NULL)) != -1) {
7451                 switch (c) {
7452 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7453                 case 'M':
7454                         fprintf(stderr,
7455                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
7456 #endif
7457                 case 'm':
7458                         errno = 0;
7459                         lmu.lum_stripe_offset = strtoul(optarg, &end, 0);
7460                         if (errno != 0 || *end != '\0' ||
7461                             lmu.lum_stripe_offset >= UINT32_MAX) {
7462                                 fprintf(stderr, "%s mv: bad MDT index '%s'\n",
7463                                         progname, optarg);
7464                                 return CMD_HELP;
7465                         }
7466                         break;
7467                 case 'v':
7468                         param.fp_verbose = VERBOSE_DETAIL;
7469                         break;
7470                 default:
7471                         fprintf(stderr, "%s mv: unrecognized option '%s'\n",
7472                                 progname, argv[optind - 1]);
7473                         return CMD_HELP;
7474                 }
7475         }
7476
7477         if (lmu.lum_stripe_offset == LMV_OFFSET_DEFAULT) {
7478                 fprintf(stderr, "%s mv: MDT index must be specified\n",
7479                         progname);
7480                 return CMD_HELP;
7481         }
7482
7483         if (optind >= argc) {
7484                 fprintf(stderr, "%s mv: DIR must be specified\n", progname);
7485                 return CMD_HELP;
7486         }
7487
7488         lmu.lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
7489
7490         /* initialize migrate mdt parameters */
7491         param.fp_lmv_md = &lmu;
7492         param.fp_migrate = 1;
7493         rc = llapi_migrate_mdt(argv[optind], &param);
7494         if (rc != 0)
7495                 fprintf(stderr, "%s mv: cannot migrate '%s' to MDT%04x: %s\n",
7496                         progname, argv[optind], lmu.lum_stripe_offset,
7497                         strerror(-rc));
7498         return rc;
7499 }
7500
7501 static int lfs_osts(int argc, char **argv)
7502 {
7503         return lfs_tgts(argc, argv);
7504 }
7505
7506 static int lfs_mdts(int argc, char **argv)
7507 {
7508         return lfs_tgts(argc, argv);
7509 }
7510
7511 static int lfs_df(int argc, char **argv)
7512 {
7513         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
7514         enum mntdf_flags flags = MNTDF_SHOW;
7515         int ops = LL_STATFS_LMV | LL_STATFS_LOV;
7516         int c, rc = 0, rc1 = 0, index = 0, arg_idx = 0;
7517         char fsname[PATH_MAX] = "", *pool_name = NULL;
7518         struct option long_opts[] = {
7519         { .val = 'h',   .name = "human-readable", .has_arg = no_argument },
7520         { .val = 'H',   .name = "si",           .has_arg = no_argument },
7521         { .val = 'i',   .name = "inodes",       .has_arg = no_argument },
7522         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
7523         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
7524         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7525         { .name = NULL} };
7526
7527         while ((c = getopt_long(argc, argv, "hHilp:v", long_opts, NULL)) != -1) {
7528                 switch (c) {
7529                 case 'h':
7530                         flags = (flags & ~MNTDF_DECIMAL) | MNTDF_COOKED;
7531                         break;
7532                 case 'H':
7533                         flags |= MNTDF_COOKED | MNTDF_DECIMAL;
7534                         break;
7535                 case 'i':
7536                         flags |= MNTDF_INODES;
7537                         break;
7538                 case 'l':
7539                         flags |= MNTDF_LAZY;
7540                         break;
7541                 case 'p':
7542                         pool_name = optarg;
7543                         break;
7544                 case 'v':
7545                         flags |= MNTDF_VERBOSE;
7546                         break;
7547                 default:
7548                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7549                                 progname, argv[optind - 1]);
7550                         return CMD_HELP;
7551                 }
7552         }
7553
7554         /* Handle case where path is not specified */
7555         if (optind == argc) {
7556                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7557                         /* Check if we have a mount point */
7558                         if (mntdir[0] == '\0')
7559                                 continue;
7560
7561                         rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
7562                         if (rc || path[0] != '\0')
7563                                 break;
7564
7565                         fsname[0] = '\0'; /* avoid matching in next loop */
7566                         mntdir[0] = '\0'; /* avoid matching in next loop */
7567                         path[0] = '\0'; /* clean for next loop */
7568                 }
7569                 return rc;
7570         }
7571
7572         /* Loop through all the remaining arguments. These are Lustre FS
7573          * paths.
7574          */
7575         for (arg_idx = optind; arg_idx <= argc - 1; arg_idx++) {
7576                 bool valid = false;
7577
7578                 fsname[0] = '\0'; /* start clean */
7579                 mntdir[0] = '\0'; /* start clean */
7580                 path[0] = '\0';   /* start clean */
7581
7582                 /* path does not exists at all */
7583                 if (!realpath(argv[arg_idx], path)) {
7584                         rc = -errno;
7585                         fprintf(stderr, "error: invalid path '%s': %s\n",
7586                                 argv[arg_idx], strerror(-rc));
7587                         /* save first seen error */
7588                         if (!rc1)
7589                                 rc1 = rc;
7590
7591                         continue;
7592                 }
7593
7594                 /* path exists but may not be a Lustre filesystem */
7595                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7596                         /* Check if we have a mount point */
7597                         if (mntdir[0] == '\0')
7598                                 continue;
7599
7600                         rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
7601                         if (rc || path[0] != '\0') {
7602                                 valid = true;
7603
7604                                 /* save first seen error */
7605                                 if (!rc1)
7606                                         rc1 = rc;
7607                                 break;
7608                         }
7609                 }
7610
7611                 if (!valid) {
7612                         llapi_printf(LLAPI_MSG_ERROR,
7613                                      "%s:%s Not a Lustre filesystem\n",
7614                                      argv[0], argv[arg_idx]);
7615                         /* save first seen error */
7616                         if (!rc1)
7617                                 rc1 = -EOPNOTSUPP;
7618                 }
7619         }
7620
7621         return rc1;
7622 }
7623
7624 static int print_instance(const char *mntdir, char *buf, size_t buflen,
7625                           bool opt_instance, bool opt_fsname, bool opt_mntdir)
7626 {
7627         int rc = 0;
7628
7629         if (opt_fsname == opt_instance) { /* both true or both false */
7630                 rc = llapi_getname(mntdir, buf, buflen);
7631         } else if (opt_fsname) {
7632                 /*
7633                  * llapi_search_mounts() fills @buf with fsname, but that is not
7634                  * called if explicit paths are specified on the command-line
7635                  */
7636                 if (buf[0] == '\0')
7637                         rc = llapi_get_fsname(mntdir, buf, buflen);
7638         } else /* if (opt_instance) */ {
7639                 rc = llapi_get_instance(mntdir, buf, buflen);
7640         }
7641
7642         if (rc < 0) {
7643                 fprintf(stderr, "cannot get instance for '%s': %s\n",
7644                         mntdir, strerror(-rc));
7645                 return rc;
7646         }
7647
7648         if (opt_mntdir)
7649                 printf("%s %s\n", buf, mntdir);
7650         else
7651                 printf("%s\n", buf);
7652
7653         return 0;
7654 }
7655
7656 static int lfs_getname(int argc, char **argv)
7657 {
7658         struct option long_opts[] = {
7659         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7660         { .val = 'i',   .name = "instance",     .has_arg = no_argument },
7661         { .val = 'n',   .name = "fsname",       .has_arg = no_argument },
7662         { .name = NULL} };
7663         bool opt_instance = false, opt_fsname = false;
7664         char fsname[PATH_MAX] = "";
7665         int rc = 0, rc2, c;
7666
7667         while ((c = getopt_long(argc, argv, "hin", long_opts, NULL)) != -1) {
7668                 switch (c) {
7669                 case 'i':
7670                         opt_instance = true;
7671                         break;
7672                 case 'n':
7673                         opt_fsname = true;
7674                         break;
7675                 default:
7676                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7677                                 progname, argv[optind - 1]);
7678                         fallthrough;
7679                 case 'h':
7680                         return CMD_HELP;
7681                 }
7682         }
7683
7684         if (optind == argc) { /* no paths specified, get all paths. */
7685                 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "";
7686                 int index = 0;
7687
7688                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7689                         rc2 = print_instance(mntdir, fsname, sizeof(fsname),
7690                                              opt_instance, opt_fsname, true);
7691                         if (!rc)
7692                                 rc = rc2;
7693                         path[0] = fsname[0] = mntdir[0] = '\0';
7694                 }
7695         } else { /* paths specified, only attempt to search these. */
7696                 bool opt_mntdir;
7697
7698                 /* if only one path is given, print only requested info */
7699                 opt_mntdir = argc - optind > 1 || (opt_instance == opt_fsname);
7700
7701                 for (; optind < argc; optind++) {
7702                         rc2 = print_instance(argv[optind], fsname,
7703                                              sizeof(fsname), opt_instance,
7704                                              opt_fsname, opt_mntdir);
7705                         if (!rc)
7706                                 rc = rc2;
7707                         fsname[0] = '\0';
7708                 }
7709         }
7710
7711         return rc;
7712 }
7713
7714 static int lfs_check(int argc, char **argv)
7715 {
7716         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
7717         int num_types = 1;
7718         char *obd_types[3];
7719         char obd_type1[4];
7720         char obd_type2[4];
7721         char obd_type3[4];
7722         int rc;
7723
7724         if (argc < 2 || argc > 3) {
7725                 fprintf(stderr, "%s check: server type must be specified\n",
7726                         progname);
7727                 return CMD_HELP;
7728         }
7729
7730         obd_types[0] = obd_type1;
7731         obd_types[1] = obd_type2;
7732         obd_types[2] = obd_type3;
7733
7734         if (strcmp(argv[1], "osts") == 0) {
7735                 strcpy(obd_types[0], "osc");
7736         } else if (strcmp(argv[1], "mdts") == 0 ||
7737                    strcmp(argv[1], "mds") == 0) {
7738                 strcpy(obd_types[0], "mdc");
7739         } else if (strcmp(argv[1], "mgts") == 0) {
7740                 strcpy(obd_types[0], "mgc");
7741         } else if (strcmp(argv[1], "all") == 0 ||
7742                    strcmp(argv[1], "servers") == 0) {
7743                 num_types = 3;
7744                 strcpy(obd_types[0], "osc");
7745                 strcpy(obd_types[1], "mdc");
7746                 strcpy(obd_types[2], "mgc");
7747         } else {
7748                 fprintf(stderr, "%s check: unrecognized option '%s'\n",
7749                         progname, argv[1]);
7750                 return CMD_HELP;
7751         }
7752
7753         if (argc >= 3 && !realpath(argv[2], path)) {
7754                 rc = -errno;
7755                 fprintf(stderr, "error: invalid path '%s': %s\n",
7756                         argv[2], strerror(-rc));
7757                 return rc;
7758         }
7759
7760         rc = llapi_search_mounts(path, 0, mntdir, NULL);
7761         if (rc < 0 || mntdir[0] == '\0') {
7762                 fprintf(stderr,
7763                         "%s %s: cannot find mounted Lustre filesystem: %s\n",
7764                         progname, argv[0],
7765                         (rc < 0) ? strerror(-rc) : strerror(ENODEV));
7766                 return rc;
7767         }
7768
7769         rc = llapi_target_check(num_types, obd_types, path);
7770         if (rc)
7771                 fprintf(stderr, "%s %s: cannot check target '%s': %s\n",
7772                         progname, argv[0], argv[1], strerror(-rc));
7773
7774         return rc;
7775 }
7776
7777 #ifdef HAVE_SYS_QUOTA_H
7778 #define ADD_OVERFLOW(a, b) \
7779                      ((((a) + (b)) < (a)) ? \
7780                       ((a) = ULONG_MAX) : ((a) = (a) + (b)))
7781
7782 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
7783  * returns the value or ULONG_MAX on integer overflow or incorrect format
7784  * Notes:
7785  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
7786  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
7787  *        3. empty integer value is interpreted as 0
7788  */
7789 static unsigned long str2sec(const char *timestr)
7790 {
7791         const char spec[] = "smhdw";
7792         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
7793         unsigned long val = 0;
7794         char *tail;
7795
7796         if (strpbrk(timestr, spec) == NULL) {
7797                 /*
7798                  * no specifiers inside the time string,
7799                  * should treat it as an integer value
7800                  */
7801                 val = strtoul(timestr, &tail, 10);
7802                 return *tail ? ULONG_MAX : val;
7803         }
7804
7805         /* format string is XXwXXdXXhXXmXXs */
7806         while (*timestr) {
7807                 unsigned long v;
7808                 int ind;
7809                 char *ptr;
7810
7811                 v = strtoul(timestr, &tail, 10);
7812                 if (v == ULONG_MAX || *tail == '\0')
7813                         /*
7814                          * value too large (ULONG_MAX or more)
7815                          * or missing specifier
7816                          */
7817                         goto error;
7818
7819                 ptr = strchr(spec, *tail);
7820                 if (!ptr)
7821                         /* unknown specifier */
7822                         goto error;
7823
7824                 ind = ptr - spec;
7825
7826                 /* check if product will overflow the type */
7827                 if (!(v < ULONG_MAX / mult[ind]))
7828                         goto error;
7829
7830                 ADD_OVERFLOW(val, mult[ind] * v);
7831                 if (val == ULONG_MAX)
7832                         goto error;
7833
7834                 timestr = tail + 1;
7835         }
7836
7837         return val;
7838
7839 error:
7840         return ULONG_MAX;
7841 }
7842
7843 #define ARG2ULL(nr, str, def_units)                                     \
7844 do {                                                                    \
7845         unsigned long long limit, units = def_units;                    \
7846         int rc;                                                         \
7847                                                                         \
7848         rc = llapi_parse_size(str, &limit, &units, 1);                  \
7849         if (rc < 0) {                                                   \
7850                 fprintf(stderr, "%s: invalid limit '%s'\n",             \
7851                         progname, str);                                 \
7852                 return CMD_HELP;                                        \
7853         }                                                               \
7854         nr = limit;                                                     \
7855 } while (0)
7856
7857 static inline int has_times_option(int argc, char **argv)
7858 {
7859         int i;
7860
7861         for (i = 1; i < argc; i++)
7862                 if (!strcmp(argv[i], "-t"))
7863                         return 1;
7864
7865         return 0;
7866 }
7867
7868 static inline int lfs_verify_poolarg(char *pool)
7869 {
7870         if (strnlen(optarg, LOV_MAXPOOLNAME + 1) > LOV_MAXPOOLNAME) {
7871                 fprintf(stderr,
7872                         "Pool name '%.*s' is longer than %d\n",
7873                         LOV_MAXPOOLNAME, pool, LOV_MAXPOOLNAME);
7874                 return 1;
7875         }
7876         return 0;
7877 }
7878
7879 /* special grace time, only notify the user when its quota is over soft limit
7880  * but doesn't block new writes until the hard limit is reached.
7881  */
7882 #define NOTIFY_GRACE            "notify"
7883 #define NOTIFY_GRACE_TIME       LQUOTA_GRACE_MASK
7884
7885 #ifndef toqb
7886 static inline __u64 lustre_stoqb(size_t space)
7887 {
7888         return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
7889 }
7890 #else
7891 #define lustre_stoqb   toqb
7892 #endif
7893
7894 int lfs_setquota_times(int argc, char **argv, struct if_quotactl *qctl)
7895 {
7896         int c, rc;
7897         char *mnt, *obd_type = (char *)qctl->obd_type;
7898         struct obd_dqblk *dqb = &qctl->qc_dqblk;
7899         struct obd_dqinfo *dqi = &qctl->qc_dqinfo;
7900         struct option long_opts[] = {
7901         { .val = 'b',   .name = "block-grace",  .has_arg = required_argument },
7902         { .val = 'g',   .name = "group",        .has_arg = no_argument },
7903         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7904         { .val = 'i',   .name = "inode-grace",  .has_arg = required_argument },
7905         { .val = 'p',   .name = "projid",       .has_arg = no_argument },
7906         { .val = 't',   .name = "times",        .has_arg = no_argument },
7907         { .val = 'u',   .name = "user",         .has_arg = no_argument },
7908         { .val = LFS_POOL_OPT,
7909                         .name = "pool",         .has_arg = required_argument },
7910         { .name = NULL } };
7911         int qtype;
7912
7913         qctl->qc_cmd  = LUSTRE_Q_SETINFO;
7914         qctl->qc_type = ALLQUOTA;
7915
7916         while ((c = getopt_long(argc, argv, "b:ghi:ptu",
7917                                 long_opts, NULL)) != -1) {
7918                 switch (c) {
7919                 case 'u':
7920                         qtype = USRQUOTA;
7921                         goto quota_type;
7922                 case 'g':
7923                         qtype = GRPQUOTA;
7924                         goto quota_type;
7925                 case 'p':
7926                         qtype = PRJQUOTA;
7927 quota_type:
7928                         if (qctl->qc_type != ALLQUOTA) {
7929                                 fprintf(stderr,
7930                                         "%s: -u/g/p cannot be used more than once\n",
7931                                         progname);
7932                                 return CMD_HELP;
7933                         }
7934                         qctl->qc_type = qtype;
7935                         break;
7936                 case 'b':
7937                         if (strncmp(optarg, NOTIFY_GRACE,
7938                                     strlen(NOTIFY_GRACE)) == 0) {
7939                                 dqi->dqi_bgrace = NOTIFY_GRACE_TIME;
7940                         } else {
7941                                 dqi->dqi_bgrace = str2sec(optarg);
7942                                 if (dqi->dqi_bgrace >= NOTIFY_GRACE_TIME) {
7943                                         fprintf(stderr,
7944                                                 "%s: bad block-grace: %s\n",
7945                                                 progname, optarg);
7946                                         return CMD_HELP;
7947                                 }
7948                         }
7949                         dqb->dqb_valid |= QIF_BTIME;
7950                         break;
7951                 case 'i':
7952                         if (strncmp(optarg, NOTIFY_GRACE,
7953                                     strlen(NOTIFY_GRACE)) == 0) {
7954                                 dqi->dqi_igrace = NOTIFY_GRACE_TIME;
7955                         } else {
7956                                 dqi->dqi_igrace = str2sec(optarg);
7957                                 if (dqi->dqi_igrace >= NOTIFY_GRACE_TIME) {
7958                                         fprintf(stderr,
7959                                                 "%s: bad inode-grace: %s\n",
7960                                                 progname, optarg);
7961                                         return CMD_HELP;
7962                                 }
7963                         }
7964                         dqb->dqb_valid |= QIF_ITIME;
7965                         break;
7966                 case 't': /* Yes, of course! */
7967                         break;
7968                 case LFS_POOL_OPT:
7969                         if (lfs_verify_poolarg(optarg))
7970                                 return -1;
7971                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
7972                         qctl->qc_cmd  = LUSTRE_Q_SETINFOPOOL;
7973                         break;
7974                 /* getopt prints error message for us when opterr != 0 */
7975                 default:
7976                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7977                                 progname, argv[optind - 1]);
7978                         fallthrough;
7979                 case 'h':
7980                         return CMD_HELP;
7981                 }
7982         }
7983
7984         if (qctl->qc_type == ALLQUOTA) {
7985                 fprintf(stderr, "%s: neither -u, -g nor -p specified\n",
7986                         progname);
7987                 return CMD_HELP;
7988         }
7989
7990         if (optind != argc - 1) {
7991                 fprintf(stderr, "%s: unexpected parameter '%s'\n",
7992                         progname, argv[optind + 1]);
7993                 return CMD_HELP;
7994         }
7995
7996         mnt = argv[optind];
7997         rc = llapi_quotactl(mnt, qctl);
7998         if (rc) {
7999                 if (*obd_type)
8000                         fprintf(stderr, "%s %s ", obd_type,
8001                                 obd_uuid2str(&qctl->obd_uuid));
8002                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
8003                 return rc;
8004         }
8005
8006         return 0;
8007 }
8008
8009 static int lfs_reset_quota(char *mnt, struct if_quotactl *qctl)
8010 {
8011         struct if_quotactl tmp_qctl;
8012         int index, md_count, dt_count;
8013         int wait_phase = 0, wait_index = 0, wait_count = 0;
8014         int rc, rc2;
8015
8016         /* reset the quota ID, the existing quota setting will be returned */
8017         rc = llapi_quotactl(mnt, qctl);
8018         if (rc)
8019                 return rc;
8020
8021         /* sanity check */
8022         if ((qctl->qc_dqblk.dqb_valid & QIF_LIMITS) != QIF_LIMITS) {
8023                 fprintf(stderr,
8024                         "the existing quota settings are not returned!\n");
8025                 return -EINVAL;
8026         }
8027
8028         rc = llapi_get_obd_count(mnt, &md_count, 1);
8029         if (rc) {
8030                 fprintf(stderr, "can not get mdt count: %s\n", strerror(-rc));
8031                 return rc;
8032         }
8033
8034         rc = llapi_get_obd_count(mnt, &dt_count, 0);
8035         if (rc) {
8036                 fprintf(stderr, "can not get ost count: %s\n", strerror(-rc));
8037                 return rc;
8038         }
8039
8040         memset(&tmp_qctl, 0, sizeof(tmp_qctl));
8041         tmp_qctl.qc_type = qctl->qc_type;
8042         tmp_qctl.qc_id = qctl->qc_id;
8043         tmp_qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
8044
8045 retry:
8046         if (wait_phase == 0) {
8047                 for (index = wait_index; index < md_count; index++) {
8048                         tmp_qctl.qc_idx = index;
8049                         tmp_qctl.qc_valid = QC_MDTIDX;
8050                         rc = llapi_quotactl(mnt, &tmp_qctl);
8051                         if (rc == -ENODEV || rc == -ENODATA)
8052                                 continue;
8053                         if (rc) {
8054                                 fprintf(stderr, "quotactl mdt%d failed: %s\n",
8055                                         index, strerror(-rc));
8056                                 break;
8057                         }
8058                         /* check whether the md quota grant is reset */
8059                         if (tmp_qctl.qc_dqblk.dqb_valid & QIF_LIMITS &&
8060                             tmp_qctl.qc_dqblk.dqb_ihardlimit != 0)
8061                                 break;
8062                 }
8063
8064                 if (index < md_count) {
8065                         wait_phase = 0;
8066                         wait_index = index;
8067                         goto wait;
8068                 }
8069         } else {
8070                 for (index = wait_index; index < dt_count; index++) {
8071                         tmp_qctl.qc_idx = index;
8072                         tmp_qctl.qc_valid = QC_OSTIDX;
8073                         rc = llapi_quotactl(mnt, &tmp_qctl);
8074                         if (rc == -ENODEV || rc == -ENODATA)
8075                                 continue;
8076                         if (rc) {
8077                                 fprintf(stderr, "quotactl mdt%d failed: %s\n",
8078                                         index, strerror(-rc));
8079                                 break;
8080                         }
8081                         /* check whether the dt quota grant is reset */
8082                         if (tmp_qctl.qc_dqblk.dqb_valid & QIF_LIMITS &&
8083                             tmp_qctl.qc_dqblk.dqb_bhardlimit != 0)
8084                                 break;
8085                 }
8086
8087                 if (index < dt_count) {
8088                         wait_phase = 1;
8089                         wait_index = index;
8090                         goto wait;
8091                 }
8092         }
8093
8094         if (wait_phase == 0) {
8095                 wait_phase = 1;
8096                 goto retry;
8097         }
8098
8099         goto out;
8100
8101 wait:
8102         if (rc || wait_count > 30) {
8103                 fprintf(stderr, "fail to reset the quota ID %d on OBDs\n",
8104                         qctl->qc_id);
8105                 goto out;
8106         }
8107
8108         wait_count++;
8109         sleep(1);
8110         fprintf(stdout, "wait %d seconds for OBDs to reset the quota ID %u\n",
8111                 wait_count, qctl->qc_id);
8112         goto retry;
8113
8114
8115 out:
8116         /* restore the quota setting */
8117         if (qctl->qc_dqblk.dqb_isoftlimit == 0 &&
8118             qctl->qc_dqblk.dqb_ihardlimit == 0 &&
8119             qctl->qc_dqblk.dqb_bsoftlimit == 0 &&
8120             qctl->qc_dqblk.dqb_bhardlimit == 0)
8121                 return rc;
8122
8123         memcpy(&tmp_qctl, qctl, sizeof(tmp_qctl));
8124         tmp_qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
8125         rc2 = llapi_quotactl(mnt, &tmp_qctl);
8126         if (!rc2)
8127                 return rc;
8128
8129         fprintf(stderr,
8130                 "fail to restore the quota setting: %s, please restore it manually by\n  lfs setquota %s %d",
8131                 strerror(-rc2),
8132                 qctl->qc_type == USRQUOTA ? "-u" :
8133                                 (qctl->qc_type == GRPQUOTA ? "-g" : "-p"),
8134                 qctl->qc_id);
8135
8136         if (qctl->qc_dqblk.dqb_isoftlimit != 0)
8137                 fprintf(stderr, " -i %llu",
8138                         (unsigned long long)qctl->qc_dqblk.dqb_isoftlimit);
8139         if (qctl->qc_dqblk.dqb_ihardlimit != 0)
8140                 fprintf(stderr, " -I %llu",
8141                         (unsigned long long)qctl->qc_dqblk.dqb_ihardlimit);
8142         if (qctl->qc_dqblk.dqb_bsoftlimit != 0)
8143                 fprintf(stderr, " -b %llu",
8144                         (unsigned long long)qctl->qc_dqblk.dqb_bsoftlimit);
8145         if (qctl->qc_dqblk.dqb_bhardlimit != 0)
8146                 fprintf(stderr, " -B %llu",
8147                         (unsigned long long)qctl->qc_dqblk.dqb_bhardlimit);
8148
8149         fprintf(stderr, " %s\n", mnt);
8150         if (!rc)
8151                 rc = rc2;
8152
8153         return rc;
8154 }
8155
8156 #define BSLIMIT (1 << 0)
8157 #define BHLIMIT (1 << 1)
8158 #define ISLIMIT (1 << 2)
8159 #define IHLIMIT (1 << 3)
8160
8161 int lfs_setquota(int argc, char **argv)
8162 {
8163         int c, rc = 0;
8164         struct if_quotactl *qctl;
8165         char *mnt, *obd_type;
8166         struct obd_dqblk *dqb;
8167         struct option long_opts[] = {
8168         { .val = 'b',   .name = "block-softlimit",
8169                                                 .has_arg = required_argument },
8170         { .val = 'B',   .name = "block-hardlimit",
8171                                                 .has_arg = required_argument },
8172         { .val = 'd',   .name = "default",      .has_arg = no_argument },
8173         { .val = LFS_SETQUOTA_DELETE,
8174                         .name = "delete",       .has_arg = no_argument },
8175         { .val = 'g',   .name = "group",        .has_arg = required_argument },
8176         { .val = 'G',   .name = "default-grp",  .has_arg = no_argument },
8177         { .val = 'h',   .name = "help",         .has_arg = no_argument },
8178         { .val = 'i',   .name = "inode-softlimit",
8179                                                 .has_arg = required_argument },
8180         { .val = 'I',   .name = "inode-hardlimit",
8181                                                 .has_arg = required_argument },
8182         { .val = 'p',   .name = "projid",       .has_arg = required_argument },
8183         { .val = 'P',   .name = "default-prj",  .has_arg = no_argument },
8184         { .val = 'r',   .name = "reset",        .has_arg = no_argument },
8185         { .val = 'u',   .name = "user",         .has_arg = required_argument },
8186         { .val = 'U',   .name = "default-usr",  .has_arg = no_argument },
8187         { .val = LFS_POOL_OPT,
8188                         .name = "pool",         .has_arg = required_argument },
8189         { .name = NULL } };
8190         unsigned int limit_mask = 0;
8191         bool use_default = false;
8192         int qtype, qctl_len;
8193
8194         qctl_len = sizeof(*qctl) + LOV_MAXPOOLNAME + 1;
8195         qctl = malloc(qctl_len);
8196         if (!qctl)
8197                 return -ENOMEM;
8198
8199         memset(qctl, 0, qctl_len);
8200         obd_type = (char *)qctl->obd_type;
8201         dqb = &qctl->qc_dqblk;
8202
8203         if (has_times_option(argc, argv)) {
8204                 rc = lfs_setquota_times(argc, argv, qctl);
8205                 goto out;
8206         }
8207
8208         qctl->qc_cmd  = LUSTRE_Q_SETQUOTA;
8209         qctl->qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
8210                                    * so it can be used as a marker that qc_type
8211                                    * isn't reinitialized from command line
8212                                    */
8213         while ((c = getopt_long(argc, argv, "b:B:dDg:Ghi:I:p:Pru:U",
8214                 long_opts, NULL)) != -1) {
8215                 switch (c) {
8216                 case 'U':
8217                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8218                         qtype = USRQUOTA;
8219                         qctl->qc_id = 0;
8220                         goto quota_type_def;
8221                 case 'u':
8222                         qtype = USRQUOTA;
8223                         rc = name2uid(&qctl->qc_id, optarg);
8224                         goto quota_type;
8225                 case 'G':
8226                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8227                         qtype = GRPQUOTA;
8228                         qctl->qc_id = 0;
8229                         goto quota_type_def;
8230                 case 'g':
8231                         qtype = GRPQUOTA;
8232                         rc = name2gid(&qctl->qc_id, optarg);
8233                         goto quota_type;
8234                 case 'P':
8235                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8236                         qtype = PRJQUOTA;
8237                         qctl->qc_id = 0;
8238                         goto quota_type_def;
8239                 case 'p':
8240                         qtype = PRJQUOTA;
8241                         rc = name2projid(&qctl->qc_id, optarg);
8242 quota_type:
8243                         if (rc) {
8244                                 if (str2quotaid(&qctl->qc_id, optarg)) {
8245                                         fprintf(stderr,
8246                                                 "%s setquota: invalid id '%s'\n",
8247                                                 progname, optarg);
8248                                         rc = -1;
8249                                         goto out;
8250                                 }
8251                         }
8252
8253                         if (qctl->qc_id == 0) {
8254                                 fprintf(stderr,
8255                                         "%s setquota: can't set quota for root usr/group/project.\n",
8256                                         progname);
8257                                 rc = -1;
8258                                 goto out;
8259                         }
8260
8261 quota_type_def:
8262                         if (qctl->qc_type != ALLQUOTA) {
8263                                 fprintf(stderr,
8264                                         "%s setquota: only one of -u, -U, -g, -G, -p or -P may be specified\n",
8265                                         progname);
8266                                 rc = CMD_HELP;
8267                                 goto out;
8268                         }
8269                         qctl->qc_type = qtype;
8270                         break;
8271 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
8272                 case 'd':
8273                         fprintf(stderr,
8274                                 "%s setquota: '-d' deprecated, use '-D' or '--default'\n",
8275                                 progname);
8276                         fallthrough;
8277 #endif
8278                 case 'D':
8279                         use_default = true;
8280                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8281                         break;
8282                 case LFS_SETQUOTA_DELETE:
8283                         qctl->qc_cmd = LUSTRE_Q_DELETEQID;
8284                         break;
8285                 case 'b':
8286                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
8287                         dqb->dqb_bsoftlimit >>= 10;
8288                         limit_mask |= BSLIMIT;
8289                         if (dqb->dqb_bsoftlimit &&
8290                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
8291                                 fprintf(stderr,
8292                                         "%s setquota: warning: block softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8293                                         progname,
8294                                         (unsigned long long)dqb->dqb_bsoftlimit,
8295                                         progname);
8296                         break;
8297                 case 'B':
8298                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
8299                         dqb->dqb_bhardlimit >>= 10;
8300                         limit_mask |= BHLIMIT;
8301                         if (dqb->dqb_bhardlimit &&
8302                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
8303                                 fprintf(stderr,
8304                                         "%s setquota: warning: block hardlimit '%llu' smaller than minimum qunit size\n"
8305                                         "See '%s help setquota' or Lustre manual for details\n",
8306                                         progname,
8307                                         (unsigned long long)dqb->dqb_bhardlimit,
8308                                         progname);
8309                         break;
8310                 case 'i':
8311                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
8312                         limit_mask |= ISLIMIT;
8313                         if (dqb->dqb_isoftlimit &&
8314                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
8315                                 fprintf(stderr,
8316                                         "%s setquota: warning: inode softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8317                                         progname,
8318                                         (unsigned long long)dqb->dqb_isoftlimit,
8319                                         progname);
8320                         break;
8321                 case 'I':
8322                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
8323                         limit_mask |= IHLIMIT;
8324                         if (dqb->dqb_ihardlimit &&
8325                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
8326                                 fprintf(stderr,
8327                                         "%s setquota: warning: inode hardlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8328                                         progname,
8329                                         (unsigned long long)dqb->dqb_ihardlimit,
8330                                         progname);
8331                         break;
8332                 case LFS_POOL_OPT:
8333                         if (lfs_verify_poolarg(optarg)) {
8334                                 rc = -1;
8335                                 goto out;
8336                         }
8337                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
8338                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_SETDEFAULT ?
8339                                                 LUSTRE_Q_SETDEFAULT_POOL :
8340                                                 LUSTRE_Q_SETQUOTAPOOL;
8341                         break;
8342                 case 'r':
8343                         qctl->qc_cmd = LUSTRE_Q_RESETQID;
8344                         break;
8345                 default:
8346                         fprintf(stderr,
8347                                 "%s setquota: unrecognized option '%s'\n",
8348                                 progname, argv[optind - 1]);
8349                         fallthrough;
8350                 case 'h':
8351                         rc = CMD_HELP;
8352                         goto out;
8353                 }
8354         }
8355
8356         if (qctl->qc_type == ALLQUOTA) {
8357                 fprintf(stderr,
8358                         "%s setquota: either -u or -g must be specified\n",
8359                         progname);
8360                 rc = CMD_HELP;
8361                 goto out;
8362         }
8363
8364         if (!use_default && qctl->qc_cmd != LUSTRE_Q_DELETEQID &&
8365             qctl->qc_cmd != LUSTRE_Q_RESETQID && limit_mask == 0) {
8366                 fprintf(stderr,
8367                         "%s setquota: at least one limit must be specified\n",
8368                         progname);
8369                 rc = CMD_HELP;
8370                 goto out;
8371         }
8372
8373         if ((use_default || qctl->qc_cmd == LUSTRE_Q_DELETEQID ||
8374              qctl->qc_cmd == LUSTRE_Q_RESETQID) && limit_mask != 0) {
8375                 fprintf(stderr,
8376                         "%s setquota: limits should not be specified when using default quota, deleting or resetting quota ID\n",
8377                         progname);
8378                 rc = CMD_HELP;
8379                 goto out;
8380         }
8381
8382         if (use_default && qctl->qc_id == 0) {
8383                 fprintf(stderr,
8384                         "%s setquota: can not set default quota for root user/group/project\n",
8385                         progname);
8386                 rc = CMD_HELP;
8387                 goto out;
8388         }
8389
8390         if ((qctl->qc_cmd == LUSTRE_Q_DELETEQID ||
8391              qctl->qc_cmd == LUSTRE_Q_RESETQID)  && qctl->qc_id == 0) {
8392                 fprintf(stderr,
8393                         "%s setquota: can not delete or reset root user/group/project\n",
8394                         progname);
8395                 rc = CMD_HELP;
8396                 goto out;
8397         }
8398
8399         if (optind != argc - 1) {
8400                 fprintf(stderr,
8401                         "%s setquota: filesystem not specified or unexpected argument '%s'\n",
8402                         progname, argv[optind]);
8403                 rc = CMD_HELP;
8404                 goto out;
8405         }
8406
8407         mnt = argv[optind];
8408
8409         if (use_default) {
8410                 dqb->dqb_bhardlimit = 0;
8411                 dqb->dqb_bsoftlimit = 0;
8412                 dqb->dqb_ihardlimit = 0;
8413                 dqb->dqb_isoftlimit = 0;
8414                 dqb->dqb_itime = 0;
8415                 dqb->dqb_btime = 0;
8416                 dqb->dqb_valid |= QIF_LIMITS | QIF_TIMES;
8417                 /* do not set inode limits for Pool Quotas */
8418                 if (qctl->qc_cmd  == LUSTRE_Q_SETDEFAULT_POOL)
8419                         dqb->dqb_valid ^= QIF_ILIMITS | QIF_ITIME;
8420         } else if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
8421                    (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
8422                 /* sigh, we can't just set blimits/ilimits */
8423                 struct if_quotactl *tmp_qctl;
8424
8425                 tmp_qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1);
8426                 if (!tmp_qctl)
8427                         goto out;
8428
8429                 if (qctl->qc_cmd == LUSTRE_Q_SETQUOTAPOOL) {
8430                         tmp_qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
8431                         strncpy(tmp_qctl->qc_poolname, qctl->qc_poolname,
8432                                 LOV_MAXPOOLNAME);
8433                 } else {
8434                         tmp_qctl->qc_cmd  = LUSTRE_Q_GETQUOTA;
8435                 }
8436                 tmp_qctl->qc_type = qctl->qc_type;
8437                 tmp_qctl->qc_id = qctl->qc_id;
8438
8439                 rc = llapi_quotactl(mnt, tmp_qctl);
8440                 if (rc < 0) {
8441                         free(tmp_qctl);
8442                         goto out;
8443                 }
8444
8445                 if (!(limit_mask & BHLIMIT))
8446                         dqb->dqb_bhardlimit = tmp_qctl->qc_dqblk.dqb_bhardlimit;
8447                 if (!(limit_mask & BSLIMIT))
8448                         dqb->dqb_bsoftlimit = tmp_qctl->qc_dqblk.dqb_bsoftlimit;
8449                 if (!(limit_mask & IHLIMIT))
8450                         dqb->dqb_ihardlimit = tmp_qctl->qc_dqblk.dqb_ihardlimit;
8451                 if (!(limit_mask & ISLIMIT))
8452                         dqb->dqb_isoftlimit = tmp_qctl->qc_dqblk.dqb_isoftlimit;
8453
8454                 /* Keep grace times if we have got no softlimit arguments */
8455                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
8456                         dqb->dqb_valid |= QIF_BTIME;
8457                         dqb->dqb_btime = tmp_qctl->qc_dqblk.dqb_btime;
8458                 }
8459
8460                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
8461                         dqb->dqb_valid |= QIF_ITIME;
8462                         dqb->dqb_itime = tmp_qctl->qc_dqblk.dqb_itime;
8463                 }
8464                 free(tmp_qctl);
8465         }
8466
8467         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
8468         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
8469
8470         if (qctl->qc_cmd == LUSTRE_Q_RESETQID)
8471                 rc = lfs_reset_quota(mnt, qctl);
8472         else
8473                 rc = llapi_quotactl(mnt, qctl);
8474
8475         if (rc) {
8476                 if (*obd_type)
8477                         fprintf(stderr,
8478                                 "%s setquota: cannot quotactl '%s' '%s': %s\n",
8479                                 progname, obd_type,
8480                                 obd_uuid2str(&qctl->obd_uuid), strerror(-rc));
8481                 else
8482                         fprintf(stderr,
8483                                 "%s setquota: quotactl failed: %s\n",
8484                                 progname, strerror(-rc));
8485         }
8486 out:
8487         if (rc)
8488                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
8489
8490         free(qctl);
8491         return rc;
8492 }
8493
8494 /* Converts seconds value into format string
8495  * result is returned in buf
8496  * Notes:
8497  *        1. result is in descenting order: 1w2d3h4m5s
8498  *        2. zero fields are not filled (except for p. 3): 5d1s
8499  *        3. zero seconds value is presented as "0s"
8500  */
8501 static char *__sec2str(time_t seconds, char *buf)
8502 {
8503         const char spec[] = "smhdw";
8504         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
8505         unsigned long c;
8506         char *tail = buf;
8507         int i;
8508
8509         for (i = ARRAY_SIZE(mult) - 1 ; i >= 0; i--) {
8510                 c = seconds / mult[i];
8511
8512                 if (c > 0 || (i == 0 && buf == tail))
8513                         tail += scnprintf(tail, 40-(tail-buf), "%lu%c", c,
8514                                           spec[i]);
8515
8516                 seconds %= mult[i];
8517         }
8518
8519         return tail;
8520 }
8521
8522 static void sec2str(time_t seconds, char *buf, int rc)
8523 {
8524         char *tail = buf;
8525
8526         if (rc)
8527                 *tail++ = '[';
8528
8529         tail = __sec2str(seconds, tail);
8530
8531         if (rc && tail - buf < 39) {
8532                 *tail++ = ']';
8533                 *tail++ = 0;
8534         }
8535 }
8536
8537 static void diff2str(time_t seconds, char *buf, time_t now)
8538 {
8539         buf[0] = 0;
8540         if (!seconds)
8541                 return;
8542         if (seconds <= now) {
8543                 strcpy(buf, "expired");
8544                 return;
8545         }
8546         __sec2str(seconds - now, buf);
8547 }
8548
8549 static void print_quota_title(char *name, struct if_quotactl *qctl,
8550                               bool human_readable, bool show_default)
8551 {
8552         if (show_default) {
8553                 printf("Disk default %s quota:\n", qtype_name(qctl->qc_type));
8554                 printf("%15s %8s%8s%8s %8s%8s%8s\n",
8555                        "Filesystem", "bquota", "blimit", "bgrace",
8556                        "iquota", "ilimit", "igrace");
8557         } else {
8558                 printf("Disk quotas for %s %s (%cid %u):\n",
8559                        qtype_name(qctl->qc_type), name,
8560                        *qtype_name(qctl->qc_type), qctl->qc_id);
8561                 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
8562                        "Filesystem", human_readable ? "used" : "kbytes",
8563                        "quota", "limit", "grace",
8564                        "files", "quota", "limit", "grace");
8565         }
8566 }
8567
8568 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
8569 {
8570         if (!h) {
8571                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
8572         } else {
8573                 if (num >> 40)
8574                         snprintf(buf, buflen, "%5.4gP",
8575                                  (double)num / ((__u64)1 << 40));
8576                 else if (num >> 30)
8577                         snprintf(buf, buflen, "%5.4gT",
8578                                  (double)num / (1 << 30));
8579                 else if (num >> 20)
8580                         snprintf(buf, buflen, "%5.4gG",
8581                                  (double)num / (1 << 20));
8582                 else if (num >> 10)
8583                         snprintf(buf, buflen, "%5.4gM",
8584                                  (double)num / (1 << 10));
8585                 else
8586                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
8587         }
8588 }
8589
8590 #ifdef HAVE_NATIVE_CLIENT
8591 /* In the current Lustre implementation, the grace time is either the time
8592  * or the timestamp to be used after some quota ID exceeds the soft limt,
8593  * 48 bits should be enough, its high 16 bits can be used as quota flags.
8594  */
8595 #define LQUOTA_GRACE_BITS       48
8596 #define LQUOTA_GRACE_MASK       ((1ULL << LQUOTA_GRACE_BITS) - 1)
8597 #define LQUOTA_GRACE_MAX        LQUOTA_GRACE_MASK
8598 #define LQUOTA_GRACE(t)         (t & LQUOTA_GRACE_MASK)
8599 #define LQUOTA_FLAG(t)          (t >> LQUOTA_GRACE_BITS)
8600 #define LQUOTA_GRACE_FLAG(t, f) ((__u64)t | (__u64)f << LQUOTA_GRACE_BITS)
8601 #endif
8602
8603 #define STRBUF_LEN      24
8604 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
8605                         int rc, bool h, bool show_default)
8606 {
8607         time_t now;
8608
8609         time(&now);
8610
8611         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA ||
8612             qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
8613             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT ||
8614             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL) {
8615                 int bover = 0, iover = 0;
8616                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
8617                 char numbuf[3][STRBUF_LEN + 2]; /* 2 for brackets or wildcard */
8618                 char timebuf[40];
8619                 char strbuf[STRBUF_LEN];
8620
8621                 dqb->dqb_btime &= LQUOTA_GRACE_MASK;
8622                 dqb->dqb_itime &= LQUOTA_GRACE_MASK;
8623
8624                 if (dqb->dqb_bhardlimit &&
8625                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
8626                         bover = 1;
8627                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
8628                         if (dqb->dqb_btime > now)
8629                                 bover = 2;
8630                         else
8631                                 bover = 3;
8632                 }
8633
8634                 if (dqb->dqb_ihardlimit &&
8635                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
8636                         iover = 1;
8637                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
8638                         if (dqb->dqb_itime > now)
8639                                 iover = 2;
8640                         else
8641                                 iover = 3;
8642                 }
8643
8644                 if (strlen(mnt) > 15)
8645                         printf("%s\n%15s", mnt, "");
8646                 else
8647                         printf("%15s", mnt);
8648
8649                 if (show_default)
8650                         snprintf(timebuf, sizeof(timebuf), "%llu",
8651                                  (unsigned long long)dqb->dqb_btime);
8652                 else if (bover)
8653                         diff2str(dqb->dqb_btime, timebuf, now);
8654
8655                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
8656                            strbuf, sizeof(strbuf), h);
8657                 if (rc == -EREMOTEIO)
8658                         sprintf(numbuf[0], "%s*", strbuf);
8659                 else
8660                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
8661                                 "%s" : "[%s]", strbuf);
8662
8663                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
8664                 if (type == QC_GENERAL)
8665                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
8666                                 "%s" : "[%s]", strbuf);
8667                 else
8668                         sprintf(numbuf[1], "%s", "-");
8669
8670                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
8671                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
8672                         "%s" : "[%s]", strbuf);
8673
8674                 if (show_default)
8675                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
8676                 else
8677                         printf(" %7s%c %6s %7s %7s",
8678                                numbuf[0], bover ? '*' : ' ', numbuf[1],
8679                                numbuf[2], bover > 1 ? timebuf : "-");
8680
8681                 if (show_default)
8682                         snprintf(timebuf, sizeof(timebuf), "%llu",
8683                                  (unsigned long long)dqb->dqb_itime);
8684                 else if (iover)
8685                         diff2str(dqb->dqb_itime, timebuf, now);
8686
8687                 snprintf(numbuf[0], sizeof(numbuf),
8688                          (dqb->dqb_valid & QIF_INODES) ? "%ju" : "[%ju]",
8689                          (uintmax_t)dqb->dqb_curinodes);
8690
8691                 if (type == QC_GENERAL)
8692                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
8693                                 "%ju" : "[%ju]",
8694                                 (uintmax_t)dqb->dqb_isoftlimit);
8695                 else
8696                         sprintf(numbuf[1], "%s", "-");
8697
8698                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
8699                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
8700
8701                 if (show_default)
8702                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
8703                 else if (type != QC_OSTIDX)
8704                         printf(" %7s%c %6s %7s %7s",
8705                                numbuf[0], iover ? '*' : ' ', numbuf[1],
8706                                numbuf[2], iover > 1 ? timebuf : "-");
8707                 else
8708                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
8709                 printf("\n");
8710         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
8711                    qctl->qc_cmd == LUSTRE_Q_GETINFOPOOL ||
8712                    qctl->qc_cmd == Q_GETOINFO) {
8713                 char bgtimebuf[40];
8714                 char igtimebuf[40];
8715
8716                 if (qctl->qc_dqinfo.dqi_bgrace == NOTIFY_GRACE_TIME)
8717                         strncpy(bgtimebuf, NOTIFY_GRACE, 40);
8718                 else
8719                         sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
8720                 if (qctl->qc_dqinfo.dqi_igrace == NOTIFY_GRACE_TIME)
8721                         strncpy(igtimebuf, NOTIFY_GRACE, 40);
8722                 else
8723                         sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
8724
8725                 printf("Block grace time: %s; Inode grace time: %s\n",
8726                        bgtimebuf, igtimebuf);
8727         }
8728 }
8729
8730 static int tgt_name2index(const char *tgtname, unsigned int *idx)
8731 {
8732         char *dash, *endp;
8733
8734         /* format is "lustre-OST0001" */
8735         dash = memchr(tgtname, '-', LUSTRE_MAXFSNAME + 1);
8736         if (!dash) {
8737                 fprintf(stderr, "wrong tgtname format '%s'\n", tgtname);
8738                 return -EINVAL;
8739         }
8740         dash += 4;
8741
8742         *idx = strtoul(dash, &endp, 16);
8743         if (*idx > 0xffff) {
8744                 fprintf(stderr, "wrong index %s\n", tgtname);
8745                 return -ERANGE;
8746         }
8747
8748         return 0;
8749 }
8750
8751 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
8752                            bool h, __u64 *total)
8753 {
8754         int rc = 0, rc1 = 0, count = 0, i = 0;
8755         char **list = NULL, *buffer = NULL;
8756         __u32 valid = qctl->qc_valid;
8757
8758         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL && is_mdt)
8759                 return 0;
8760
8761         /* Is it correct for the case OST0000, OST0002, OST0003 -
8762          * we will ask OST0001 that is absent and won't ask OST0003? */
8763         rc = llapi_get_obd_count(mnt, &count, is_mdt);
8764         if (rc) {
8765                 fprintf(stderr, "can not get %s count: %s\n",
8766                         is_mdt ? "mdt" : "ost", strerror(-rc));
8767                 return rc;
8768         }
8769
8770         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
8771                 char fname[PATH_MAX];
8772                 char fsname[LUSTRE_MAXFSNAME + 1];
8773                 int bufsize = sizeof(struct obd_uuid) * count;
8774
8775                 rc = llapi_search_fsname(mnt, fsname);
8776                 if (rc) {
8777                         fprintf(stderr, "cannot get fsname for mountpoint %s\n",
8778                                 mnt);
8779                         goto out;
8780                 }
8781                 buffer = malloc(bufsize + sizeof(*list) * count);
8782                 if (!buffer)
8783                         return -ENOMEM;
8784                 list = (char **)(buffer + bufsize);
8785                 snprintf(fname, PATH_MAX, "%s.%s", fsname, qctl->qc_poolname);
8786                 count = llapi_get_poolmembers(fname, list, count,
8787                                               buffer, bufsize);
8788                 if (count <= 0)
8789                         goto out;
8790         }
8791
8792         for (i = 0; i < count; i++) {
8793                 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
8794                         unsigned int index;
8795
8796                         if (tgt_name2index(list[i], &index))
8797                                 continue;
8798                         qctl->qc_idx = index;
8799                 } else {
8800                         qctl->qc_idx = i;
8801                 }
8802
8803                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
8804                 rc = llapi_quotactl(mnt, qctl);
8805                 if (rc) {
8806                         /* It is remote client case. */
8807                         if (rc == -EOPNOTSUPP) {
8808                                 rc = 0;
8809                                 goto out;
8810                         }
8811
8812                         /* no target for this index yet */
8813                         if (rc == -ENODEV) {
8814                                 rc = 0;
8815                                 continue;
8816                         }
8817
8818                         /* inactive target */
8819                         if (rc == -ENODATA) {
8820                                 char name[UUID_MAX+8];
8821
8822                                 snprintf(name, sizeof(name), "%s[inact]",
8823                                         obd_uuid2str(&qctl->obd_uuid));
8824                                 memset(&qctl->qc_dqinfo, 0,
8825                                        sizeof(qctl->qc_dqinfo));
8826                                 memset(&qctl->qc_dqblk, 0,
8827                                        sizeof(qctl->qc_dqblk));
8828                                 print_quota(name, qctl, qctl->qc_valid, 0, h,
8829                                             false);
8830                                 rc = 0;
8831                                 continue;
8832                         }
8833
8834                         if (!rc1)
8835                                 rc1 = rc;
8836                         fprintf(stderr, "quotactl %s%d failed.\n",
8837                                 is_mdt ? "mdt" : "ost", qctl->qc_idx);
8838                         continue;
8839                 }
8840
8841                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
8842                             qctl->qc_valid, 0, h, false);
8843                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
8844                                    qctl->qc_dqblk.dqb_bhardlimit;
8845         }
8846 out:
8847         if (buffer)
8848                 free(buffer);
8849         qctl->qc_valid = valid;
8850         return rc ? : rc1;
8851 }
8852
8853 static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
8854                            int verbose, int quiet, bool human_readable,
8855                            bool show_default)
8856 {
8857         int rc1 = 0, rc2 = 0, rc3 = 0;
8858         char *obd_type = (char *)qctl->obd_type;
8859         char *obd_uuid = (char *)qctl->obd_uuid.uuid;
8860         __u64 total_ialloc = 0, total_balloc = 0;
8861         bool use_default_for_blk = false;
8862         bool use_default_for_file = false;
8863         int inacc;
8864
8865         rc1 = llapi_quotactl(mnt, qctl);
8866         if (rc1 < 0) {
8867                 switch (rc1) {
8868                 case -ESRCH:
8869                         fprintf(stderr, "%s quotas are not enabled.\n",
8870                                 qtype_name(qctl->qc_type));
8871                         goto out;
8872                 case -EPERM:
8873                         fprintf(stderr, "Permission denied.\n");
8874                 case -ENODEV:
8875                 case -ENOENT:
8876                         /* We already got error message. */
8877                         goto out;
8878                 default:
8879                         fprintf(stderr, "Unexpected quotactl error: %s\n",
8880                                 strerror(-rc1));
8881                 }
8882         }
8883
8884         if (!show_default && qctl->qc_id == 0) {
8885                 qctl->qc_dqblk.dqb_bhardlimit = 0;
8886                 qctl->qc_dqblk.dqb_bsoftlimit = 0;
8887                 qctl->qc_dqblk.dqb_ihardlimit = 0;
8888                 qctl->qc_dqblk.dqb_isoftlimit = 0;
8889                 qctl->qc_dqblk.dqb_btime = 0;
8890                 qctl->qc_dqblk.dqb_itime = 0;
8891                 qctl->qc_dqblk.dqb_valid |= QIF_LIMITS | QIF_TIMES;
8892         }
8893
8894         if (qctl->qc_dqblk.dqb_valid & QIF_BTIME &&
8895             LQUOTA_FLAG(qctl->qc_dqblk.dqb_btime) & LQUOTA_FLAG_DEFAULT) {
8896                 use_default_for_blk = true;
8897                 qctl->qc_dqblk.dqb_btime &= LQUOTA_GRACE_MASK;
8898         }
8899
8900         if (qctl->qc_dqblk.dqb_valid & QIF_ITIME &&
8901             LQUOTA_FLAG(qctl->qc_dqblk.dqb_itime) & LQUOTA_FLAG_DEFAULT) {
8902                 use_default_for_file = true;
8903                 qctl->qc_dqblk.dqb_itime &= LQUOTA_GRACE_MASK;
8904         }
8905
8906         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
8907              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
8908              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL ||
8909              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) && !quiet)
8910                 print_quota_title(name, qctl, human_readable, show_default);
8911
8912         if (rc1 && *obd_type)
8913                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
8914
8915         if (qctl->qc_valid != QC_GENERAL)
8916                 mnt = "";
8917
8918         inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
8919                  qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
8920                 ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
8921                  (QIF_LIMITS|QIF_USAGE));
8922
8923         print_quota(mnt, qctl, QC_GENERAL, rc1, human_readable, show_default);
8924
8925         if (!show_default && verbose &&
8926             qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO &&
8927             qctl->qc_cmd != LUSTRE_Q_GETINFOPOOL) {
8928                 char strbuf[STRBUF_LEN];
8929
8930                 rc2 = print_obd_quota(mnt, qctl, 1, human_readable,
8931                                       &total_ialloc);
8932                 rc3 = print_obd_quota(mnt, qctl, 0, human_readable,
8933                                       &total_balloc);
8934                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
8935                            human_readable);
8936                 printf("Total allocated inode limit: %ju, total allocated block limit: %s\n",
8937                        (uintmax_t)total_ialloc, strbuf);
8938         }
8939
8940         if (use_default_for_blk)
8941                 printf("%cid %u is using default block quota setting\n",
8942                        *qtype_name(qctl->qc_type), qctl->qc_id);
8943
8944         if (use_default_for_file)
8945                 printf("%cid %u is using default file quota setting\n",
8946                        *qtype_name(qctl->qc_type), qctl->qc_id);
8947
8948         if (rc1 || rc2 || rc3 || inacc)
8949                 printf("Some errors happened when getting quota info. Some devices may be not working or deactivated. The data in \"[]\" is inaccurate.\n");
8950 out:
8951         if (rc1)
8952                 return rc1;
8953         if (rc2)
8954                 return rc2;
8955         if (rc3)
8956                 return rc3;
8957         if (inacc)
8958                 return -EIO;
8959
8960         return 0;
8961 }
8962
8963 static int lfs_project(int argc, char **argv)
8964 {
8965         int ret = 0, err = 0, c, i;
8966         struct project_handle_control phc = { 0 };
8967         enum lfs_project_ops_t op;
8968
8969         phc.newline = true;
8970         phc.assign_projid = false;
8971         /* default action */
8972         op = LFS_PROJECT_LIST;
8973
8974         while ((c = getopt(argc, argv, "p:cCsdkr0")) != -1) {
8975                 switch (c) {
8976                 case 'c':
8977                         if (op != LFS_PROJECT_LIST) {
8978                                 fprintf(stderr,
8979                                         "%s: cannot specify '-c' '-C' '-s' together\n",
8980                                         progname);
8981                                 return CMD_HELP;
8982                         }
8983
8984                         op = LFS_PROJECT_CHECK;
8985                         break;
8986                 case 'C':
8987                         if (op != LFS_PROJECT_LIST) {
8988                                 fprintf(stderr,
8989                                         "%s: cannot specify '-c' '-C' '-s' together\n",
8990                                         progname);
8991                                 return CMD_HELP;
8992                         }
8993
8994                         op = LFS_PROJECT_CLEAR;
8995                         break;
8996                 case 's':
8997                         if (op != LFS_PROJECT_LIST) {
8998                                 fprintf(stderr,
8999                                         "%s: cannot specify '-c' '-C' '-s' together\n",
9000                                         progname);
9001                                 return CMD_HELP;
9002                         }
9003
9004                         phc.set_inherit = true;
9005                         op = LFS_PROJECT_SET;
9006                         break;
9007                 case 'd':
9008                         phc.dironly = true;
9009                         break;
9010                 case 'k':
9011                         phc.keep_projid = true;
9012                         break;
9013                 case 'r':
9014                         phc.recursive = true;
9015                         break;
9016                 case 'p':
9017                         if (str2quotaid(&phc.projid, optarg)) {
9018                                 fprintf(stderr,
9019                                         "Invalid project ID: %s\n",
9020                                         optarg);
9021                                 return CMD_HELP;
9022                         }
9023
9024                         phc.assign_projid = true;
9025
9026                         break;
9027                 case '0':
9028                         phc.newline = false;
9029                         break;
9030                 default:
9031                         fprintf(stderr, "%s: invalid option '%c'\n",
9032                                 progname, optopt);
9033                         return CMD_HELP;
9034                 }
9035         }
9036
9037         if (phc.assign_projid && op == LFS_PROJECT_LIST) {
9038                 op = LFS_PROJECT_SET;
9039                 phc.set_projid = true;
9040         } else if (phc.assign_projid && op == LFS_PROJECT_SET) {
9041                 phc.set_projid = true;
9042         }
9043
9044         switch (op) {
9045         case LFS_PROJECT_CHECK:
9046                 if (phc.keep_projid) {
9047                         fprintf(stderr,
9048                                 "%s: '-k' is useless together with '-c'\n",
9049                                 progname);
9050                         return CMD_HELP;
9051                 }
9052                 break;
9053         case LFS_PROJECT_CLEAR:
9054                 if (!phc.newline) {
9055                         fprintf(stderr,
9056                                 "%s: '-0' is useless together with '-C'\n",
9057                                 progname);
9058                         return CMD_HELP;
9059                 }
9060                 if (phc.assign_projid) {
9061                         fprintf(stderr,
9062                                 "%s: '-p' is useless together with '-C'\n",
9063                                 progname);
9064                         return CMD_HELP;
9065                 }
9066                 break;
9067         case LFS_PROJECT_SET:
9068                 if (!phc.newline) {
9069                         fprintf(stderr,
9070                                 "%s: '-0' is useless together with '-s'\n",
9071                                 progname);
9072                         return CMD_HELP;
9073                 }
9074                 if (phc.keep_projid) {
9075                         fprintf(stderr,
9076                                 "%s: '-k' is useless together with '-s'\n",
9077                                 progname);
9078                         return CMD_HELP;
9079                 }
9080                 break;
9081         default:
9082                 if (!phc.newline) {
9083                         fprintf(stderr,
9084                                 "%s: '-0' is useless for list operations\n",
9085                                 progname);
9086                         return CMD_HELP;
9087                 }
9088                 break;
9089         }
9090
9091         argv += optind;
9092         argc -= optind;
9093         if (argc == 0) {
9094                 fprintf(stderr, "%s: missing file or directory target(s)\n",
9095                         progname);
9096                 return CMD_HELP;
9097         }
9098
9099         for (i = 0; i < argc; i++) {
9100                 switch (op) {
9101                 case LFS_PROJECT_CHECK:
9102                         err = lfs_project_check(argv[i], &phc);
9103                         break;
9104                 case LFS_PROJECT_LIST:
9105                         err = lfs_project_list(argv[i], &phc);
9106                         break;
9107                 case LFS_PROJECT_CLEAR:
9108                         err = lfs_project_clear(argv[i], &phc);
9109                         break;
9110                 case LFS_PROJECT_SET:
9111                         err = lfs_project_set(argv[i], &phc);
9112                         break;
9113                 default:
9114                         break;
9115                 }
9116                 if (err && !ret)
9117                         ret = err;
9118         }
9119
9120         return ret;
9121 }
9122
9123 static int lfs_quota(int argc, char **argv)
9124 {
9125         int c;
9126         char *mnt, *name = NULL;
9127         struct if_quotactl *qctl;
9128         char *obd_uuid;
9129         int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
9130         __u32 valid = QC_GENERAL, idx = 0;
9131         bool human_readable = false;
9132         bool show_default = false;
9133         int qtype;
9134         bool show_pools = false;
9135         struct option long_opts[] = {
9136         { .val = LFS_POOL_OPT, .name = "pool", .has_arg = optional_argument },
9137         { .name = NULL } };
9138         char **poollist = NULL;
9139         char *buf = NULL;
9140         int poolcount, i;
9141
9142         qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1);
9143         if (!qctl)
9144                 return -ENOMEM;
9145
9146         qctl->qc_cmd = LUSTRE_Q_GETQUOTA;
9147         qctl->qc_type = ALLQUOTA;
9148         obd_uuid = (char *)qctl->obd_uuid.uuid;
9149
9150         while ((c = getopt_long(argc, argv, "gGi:I:o:pPqtuUvh",
9151                 long_opts, NULL)) != -1) {
9152                 switch (c) {
9153                 case 'U':
9154                         show_default = true;
9155                 case 'u':
9156                         qtype = USRQUOTA;
9157                         goto quota_type;
9158                 case 'G':
9159                         show_default = true;
9160                 case 'g':
9161                         qtype = GRPQUOTA;
9162                         goto quota_type;
9163                 case 'P':
9164                         show_default = true;
9165                 case 'p':
9166                         qtype = PRJQUOTA;
9167 quota_type:
9168                         if (qctl->qc_type != ALLQUOTA) {
9169                                 fprintf(stderr,
9170                                         "%s quota: only one of -u, -g, or -p may be specified\n",
9171                                         progname);
9172                                 rc = CMD_HELP;
9173                                 goto out;
9174                         }
9175                         qctl->qc_type = qtype;
9176                         break;
9177                 case 't':
9178                         qctl->qc_cmd = LUSTRE_Q_GETINFO;
9179                         break;
9180                 case 'o':
9181                         valid = qctl->qc_valid = QC_UUID;
9182                         snprintf(obd_uuid, sizeof(*obd_uuid), "%s", optarg);
9183                         break;
9184                 case 'i':
9185                         valid = qctl->qc_valid = QC_MDTIDX;
9186                         idx = qctl->qc_idx = atoi(optarg);
9187                         if (idx == 0 && *optarg != '0') {
9188                                 fprintf(stderr,
9189                                         "%s quota: invalid MDT index '%s'\n",
9190                                         progname, optarg);
9191                                 rc = CMD_HELP;
9192                                 goto out;
9193                         }
9194                         break;
9195                 case 'I':
9196                         valid = qctl->qc_valid = QC_OSTIDX;
9197                         idx = qctl->qc_idx = atoi(optarg);
9198                         if (idx == 0 && *optarg != '0') {
9199                                 fprintf(stderr,
9200                                         "%s quota: invalid OST index '%s'\n",
9201                                         progname, optarg);
9202                                 rc = CMD_HELP;
9203                                 goto out;
9204                         }
9205                         break;
9206                 case 'v':
9207                         verbose = 1;
9208                         break;
9209                 case 'q':
9210                         quiet = 1;
9211                         break;
9212                 case 'h':
9213                         human_readable = true;
9214                         break;
9215                 case LFS_POOL_OPT:
9216                         if ((!optarg) && (argv[optind] != NULL) &&
9217                                 (argv[optind][0] != '-') &&
9218                                 (argv[optind][0] != '/')) {
9219                                 optarg = argv[optind++];
9220                                 if (lfs_verify_poolarg(optarg)) {
9221                                         rc = -EINVAL;
9222                                         goto out;
9223                                 }
9224                                 strncpy(qctl->qc_poolname, optarg,
9225                                         LOV_MAXPOOLNAME);
9226                                 if (qctl->qc_cmd == LUSTRE_Q_GETINFO)
9227                                         qctl->qc_cmd = LUSTRE_Q_GETINFOPOOL;
9228                                 else
9229                                         qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
9230                                 break;
9231                         }
9232
9233                         /* optarg is NULL */
9234                         show_pools = true;
9235                         qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
9236                         break;
9237                 default:
9238                         fprintf(stderr, "%s quota: unrecognized option '%s'\n",
9239                                 progname, argv[optind - 1]);
9240                         rc = CMD_HELP;
9241                         goto out;
9242                 }
9243         }
9244
9245         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
9246         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
9247              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
9248              qctl->qc_type == ALLQUOTA &&
9249              optind == argc - 1 && !show_default) {
9250                 qctl->qc_idx = idx;
9251
9252                 for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) {
9253                         qctl->qc_type = qtype;
9254                         qctl->qc_valid = valid;
9255                         if (qtype == USRQUOTA) {
9256                                 qctl->qc_id = geteuid();
9257                                 rc = uid2name(&name, qctl->qc_id);
9258                         } else {
9259                                 qctl->qc_id = getegid();
9260                                 rc = gid2name(&name, qctl->qc_id);
9261                                 memset(&qctl->qc_dqblk, 0,
9262                                        sizeof(qctl->qc_dqblk));
9263                         }
9264                         if (rc)
9265                                 name = "<unknown>";
9266                         mnt = argv[optind];
9267                         rc1 = get_print_quota(mnt, name, qctl, verbose, quiet,
9268                                               human_readable, show_default);
9269                         if (rc1 && !rc)
9270                                 rc = rc1;
9271                 }
9272                 goto out;
9273         /* lfs quota -u username /path/to/lustre/mount */
9274         } else if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
9275                    qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
9276                 /* options should be followed by u/g-name and mntpoint */
9277                 if ((!show_default && optind + 2 != argc) ||
9278                     (show_default && optind + 1 != argc) ||
9279                     qctl->qc_type == ALLQUOTA) {
9280                         fprintf(stderr,
9281                                 "%s quota: name and mount point must be specified\n",
9282                                 progname);
9283                         rc = CMD_HELP;
9284                         goto out;
9285                 }
9286
9287                 if (!show_default) {
9288                         name = argv[optind++];
9289                         switch (qctl->qc_type) {
9290                         case USRQUOTA:
9291                                 rc = name2uid(&qctl->qc_id, name);
9292                                 break;
9293                         case GRPQUOTA:
9294                                 rc = name2gid(&qctl->qc_id, name);
9295                                 break;
9296                         case PRJQUOTA:
9297                                 rc = name2projid(&qctl->qc_id, name);
9298                                 break;
9299                         default:
9300                                 rc = -ENOTSUP;
9301                                 break;
9302                         }
9303                 } else {
9304                         qctl->qc_valid = QC_GENERAL;
9305                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ?
9306                                         LUSTRE_Q_GETDEFAULT_POOL :
9307                                         LUSTRE_Q_GETDEFAULT;
9308                         qctl->qc_id = 0;
9309                 }
9310
9311                 if (rc) {
9312                         if (str2quotaid(&qctl->qc_id, name)) {
9313                                 fprintf(stderr, "%s quota: invalid id '%s'\n",
9314                                         progname, name);
9315                                 rc = CMD_HELP;
9316                                 goto out;
9317                         }
9318                 }
9319         } else if (optind + 1 != argc || qctl->qc_type == ALLQUOTA) {
9320                 fprintf(stderr, "%s quota: missing quota info argument(s)\n",
9321                         progname);
9322                 rc = CMD_HELP;
9323                 goto out;
9324         }
9325
9326         mnt = argv[optind];
9327         if (show_pools) {
9328                 char *p;
9329
9330                 i = 0;
9331                 rc = llapi_get_poolbuf(mnt, &buf, &poollist, &poolcount);
9332                 if (rc)
9333                         goto out;
9334
9335                 for (i = 0; i < poolcount; i++) {
9336                         p = memchr(poollist[i], '.', MAXNAMLEN);
9337                         if (!p) {
9338                                 fprintf(stderr, "bad string format %.*s\n",
9339                                         MAXNAMLEN, poollist[i]);
9340                                 rc = -EINVAL;
9341                                 goto out;
9342                         }
9343                         p++;
9344                         printf("Quotas for pool: %s\n", p);
9345                         strncpy(qctl->qc_poolname, p, LOV_MAXPOOLNAME);
9346                         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
9347                                              human_readable, show_default);
9348                         if (rc)
9349                                 break;
9350                 }
9351                 goto out;
9352         }
9353
9354         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
9355                              human_readable, show_default);
9356 out:
9357         free(buf);
9358         free(qctl);
9359         return rc;
9360 }
9361 #endif /* HAVE_SYS_QUOTA_H! */
9362
9363 static int flushctx_ioctl(char *mp)
9364 {
9365         int fd, rc;
9366
9367         fd = open(mp, O_RDONLY);
9368         if (fd == -1) {
9369                 fprintf(stderr, "flushctx: error open %s: %s\n",
9370                         mp, strerror(errno));
9371                 return -1;
9372         }
9373
9374         rc = ioctl(fd, LL_IOC_FLUSHCTX);
9375         if (rc == -1)
9376                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
9377                         mp, strerror(errno));
9378
9379         close(fd);
9380         return rc;
9381 }
9382
9383 static int lfs_flushctx(int argc, char **argv)
9384 {
9385         int     kdestroy = 0, reap = 0, c;
9386         char    mntdir[PATH_MAX] = {'\0'};
9387         int     index = 0;
9388         int     rc = 0;
9389
9390         while ((c = getopt(argc, argv, "kr")) != -1) {
9391                 switch (c) {
9392                 case 'k':
9393                         kdestroy = 1;
9394                         break;
9395                 case 'r':
9396                         reap = 1;
9397                         break;
9398                 default:
9399                         fprintf(stderr,
9400                                 "error: %s: option '-%c' unrecognized\n",
9401                                 argv[0], c);
9402                         return CMD_HELP;
9403                 }
9404         }
9405
9406         if (kdestroy) {
9407                 rc = system("kdestroy > /dev/null");
9408                 if (rc) {
9409                         rc = WEXITSTATUS(rc);
9410                         fprintf(stderr,
9411                                 "error destroying tickets: %d, continuing\n",
9412                                 rc);
9413                 }
9414         }
9415
9416         if (optind >= argc) {
9417                 /* flush for all mounted lustre fs. */
9418                 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
9419                         /* Check if we have a mount point */
9420                         if (mntdir[0] == '\0')
9421                                 continue;
9422
9423                         if (flushctx_ioctl(mntdir))
9424                                 rc = -1;
9425
9426                         mntdir[0] = '\0'; /* avoid matching in next loop */
9427                 }
9428         } else {
9429                 /* flush fs as specified */
9430                 while (optind < argc) {
9431                         if (flushctx_ioctl(argv[optind++]))
9432                                 rc = -1;
9433                 }
9434         }
9435
9436         if (reap) {
9437                 rc = system("keyctl reap > /dev/null");
9438                 if (rc != 0) {
9439                         rc = WEXITSTATUS(rc);
9440                         fprintf(stderr, "error reaping keyring: %d\n", rc);
9441                 }
9442         }
9443
9444         return rc;
9445 }
9446
9447 static int lfs_changelog(int argc, char **argv)
9448 {
9449         void *changelog_priv;
9450         struct changelog_rec *rec;
9451         long long startrec = 0, endrec = 0;
9452         char *mdd;
9453         struct option long_opts[] = {
9454                 { .val = 'f', .name = "follow", .has_arg = no_argument },
9455                 { .name = NULL } };
9456         char short_opts[] = "f";
9457         int rc, follow = 0;
9458
9459         while ((rc = getopt_long(argc, argv, short_opts,
9460                 long_opts, NULL)) != -1) {
9461                 switch (rc) {
9462                 case 'f':
9463                         follow++;
9464                         break;
9465                 default:
9466                         fprintf(stderr,
9467                                 "%s changelog: unrecognized option '%s'\n",
9468                                 progname, argv[optind - 1]);
9469                         return CMD_HELP;
9470                 }
9471         }
9472         if (optind >= argc) {
9473                 fprintf(stderr, "%s changelog: mdtname must be specified\n",
9474                         progname);
9475                 return CMD_HELP;
9476         }
9477
9478         mdd = argv[optind++];
9479         if (argc > optind) {
9480                 errno = 0;
9481                 startrec = strtoll(argv[optind++], NULL, 10);
9482                 if (errno != 0 || startrec < 0) {
9483                         fprintf(stderr,
9484                                 "%s changelog: bad startrec\n",
9485                                 progname);
9486                         return CMD_HELP;
9487                 }
9488         }
9489
9490         if (argc > optind) {
9491                 errno = 0;
9492                 endrec = strtoll(argv[optind++], NULL, 10);
9493                 if (errno != 0 || endrec < 0) {
9494                         fprintf(stderr,
9495                                 "%s changelog: bad endrec\n",
9496                                 progname);
9497                         return CMD_HELP;
9498                 }
9499         }
9500
9501         rc = llapi_changelog_start(&changelog_priv,
9502                                    CHANGELOG_FLAG_BLOCK |
9503                                    CHANGELOG_FLAG_JOBID |
9504                                    CHANGELOG_FLAG_EXTRA_FLAGS |
9505                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
9506                                    mdd, startrec);
9507         if (rc < 0) {
9508                 fprintf(stderr, "%s changelog: cannot start changelog: %s\n",
9509                         progname, strerror(errno = -rc));
9510                 return rc;
9511         }
9512
9513         rc = llapi_changelog_set_xflags(changelog_priv,
9514                                         CHANGELOG_EXTRA_FLAG_UIDGID |
9515                                         CHANGELOG_EXTRA_FLAG_NID |
9516                                         CHANGELOG_EXTRA_FLAG_OMODE |
9517                                         CHANGELOG_EXTRA_FLAG_XATTR);
9518         if (rc < 0) {
9519                 fprintf(stderr,
9520                         "%s changelog: cannot set xflags for changelog: %s\n",
9521                         progname, strerror(errno = -rc));
9522                 return rc;
9523         }
9524
9525         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
9526                 time_t secs;
9527                 struct tm ts;
9528
9529                 if (endrec && rec->cr_index > endrec) {
9530                         llapi_changelog_free(&rec);
9531                         break;
9532                 }
9533                 if (rec->cr_index < startrec) {
9534                         llapi_changelog_free(&rec);
9535                         continue;
9536                 }
9537
9538                 secs = rec->cr_time >> 30;
9539                 gmtime_r(&secs, &ts);
9540                 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
9541                        "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
9542                        changelog_type2str(rec->cr_type),
9543                        ts.tm_hour, ts.tm_min, ts.tm_sec,
9544                        (int)(rec->cr_time & ((1 << 30) - 1)),
9545                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
9546                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
9547
9548                 if (rec->cr_flags & CLF_JOBID) {
9549                         struct changelog_ext_jobid *jid =
9550                                 changelog_rec_jobid(rec);
9551
9552                         if (jid->cr_jobid[0] != '\0')
9553                                 printf(" j=%s", jid->cr_jobid);
9554                 }
9555
9556                 if (rec->cr_flags & CLF_EXTRA_FLAGS) {
9557                         struct changelog_ext_extra_flags *ef =
9558                                 changelog_rec_extra_flags(rec);
9559
9560                         printf(" ef=0x%llx",
9561                                (unsigned long long)ef->cr_extra_flags);
9562
9563                         if (ef->cr_extra_flags & CLFE_UIDGID) {
9564                                 struct changelog_ext_uidgid *uidgid =
9565                                         changelog_rec_uidgid(rec);
9566
9567                                 printf(" u=%llu:%llu",
9568                                        (unsigned long long)uidgid->cr_uid,
9569                                        (unsigned long long)uidgid->cr_gid);
9570                         }
9571                         if (ef->cr_extra_flags & CLFE_NID) {
9572                                 struct changelog_ext_nid *nid =
9573                                         changelog_rec_nid(rec);
9574
9575                                 printf(" nid=%s",
9576                                        libcfs_nid2str(nid->cr_nid));
9577                         }
9578
9579                         if (ef->cr_extra_flags & CLFE_OPEN) {
9580                                 struct changelog_ext_openmode *omd =
9581                                         changelog_rec_openmode(rec);
9582                                 char mode[] = "---";
9583
9584                                 /* exec mode must be exclusive */
9585                                 if (omd->cr_openflags & MDS_FMODE_EXEC) {
9586                                         mode[2] = 'x';
9587                                 } else {
9588                                         if (omd->cr_openflags & MDS_FMODE_READ)
9589                                                 mode[0] = 'r';
9590                                         if (omd->cr_openflags &
9591                                             (MDS_FMODE_WRITE |
9592                                              MDS_OPEN_TRUNC |
9593                                              MDS_OPEN_APPEND))
9594                                                 mode[1] = 'w';
9595                                 }
9596
9597                                 if (strcmp(mode, "---") != 0)
9598                                         printf(" m=%s", mode);
9599                         }
9600
9601                         if (ef->cr_extra_flags & CLFE_XATTR) {
9602                                 struct changelog_ext_xattr *xattr =
9603                                         changelog_rec_xattr(rec);
9604
9605                                 if (xattr->cr_xattr[0] != '\0')
9606                                         printf(" x=%s", xattr->cr_xattr);
9607                         }
9608                 }
9609
9610                 if (!fid_is_zero(&rec->cr_pfid))
9611                         printf(" p="DFID, PFID(&rec->cr_pfid));
9612                 if (rec->cr_namelen)
9613                         printf(" %.*s", rec->cr_namelen,
9614                                changelog_rec_name(rec));
9615
9616                 if (rec->cr_flags & CLF_RENAME) {
9617                         struct changelog_ext_rename *rnm =
9618                                 changelog_rec_rename(rec);
9619
9620                         if (!fid_is_zero(&rnm->cr_sfid))
9621                                 printf(" s="DFID" sp="DFID" %.*s",
9622                                        PFID(&rnm->cr_sfid),
9623                                        PFID(&rnm->cr_spfid),
9624                                        (int)changelog_rec_snamelen(rec),
9625                                        changelog_rec_sname(rec));
9626                 }
9627                 printf("\n");
9628
9629                 llapi_changelog_free(&rec);
9630         }
9631
9632         llapi_changelog_fini(&changelog_priv);
9633
9634         if (rc < 0)
9635                 fprintf(stderr, "%s changelog: cannot access changelog: %s\n",
9636                         progname, strerror(errno = -rc));
9637
9638         return (rc == 1 ? 0 : rc);
9639 }
9640
9641 static int lfs_changelog_clear(int argc, char **argv)
9642 {
9643         long long endrec;
9644         int rc;
9645
9646         if (argc != 4)
9647                 return CMD_HELP;
9648
9649         errno = 0;
9650         endrec = strtoll(argv[3], NULL, 10);
9651         if (errno != 0 || endrec < 0) {
9652                 fprintf(stderr,
9653                         "%s: bad endrec '%s'\n",
9654                         argv[0], argv[3]);
9655                 return CMD_HELP;
9656         }
9657
9658         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
9659
9660         if (rc == -EINVAL)
9661                 fprintf(stderr, "%s: record out of range: %llu\n",
9662                         argv[0], endrec);
9663         else if (rc == -ENOENT)
9664                 fprintf(stderr, "%s: no changelog user: %s\n",
9665                         argv[0], argv[2]);
9666         else if (rc)
9667                 fprintf(stderr, "%s error: %s\n", argv[0],
9668                         strerror(-rc));
9669
9670         if (rc)
9671                 errno = -rc;
9672
9673         return rc;
9674 }
9675
9676 static void rstripc(char *str, int c)
9677 {
9678         char *end = str + strlen(str);
9679
9680         for (; str < end && end[-1] == c; --end)
9681                 end[-1] = '\0';
9682 }
9683
9684 /* Helper function to lfs_fid2path. To print out only the file names and
9685  * not the full path. Do not call OBD_IOC_FID2PATH for every file. Instead
9686  * read the trusted.link xattr and loop over all the records to get all the
9687  * file names.
9688  */
9689 static int lfs_fid2path_prn_name(char *mnt_dir, char *path_buf,
9690                                  bool print_linkno, bool print_fid, char *ptr,
9691                                  const char *fid_str, int linktmp)
9692 {
9693         char buf[65536]; /* BUFFER_SIZE 65536 */
9694         char full_path[PATH_MAX * 2 + 2];
9695         struct link_ea_header *leh;
9696         struct link_ea_entry *lee;
9697         ssize_t size;
9698         int reclen, i, rc = 0;
9699
9700         /* Generate full_path */
9701         snprintf(full_path, sizeof(full_path) - 1, "%s/%s", mnt_dir, path_buf);
9702
9703         size = getxattr(full_path, "trusted.link", buf, sizeof(buf));
9704         if (size < 0) {
9705                 fprintf(stderr, "%s: failed to read %s xattr: %s\n", path_buf,
9706                         "trusted.link", strerror(errno));
9707                 rc = -errno;
9708                 goto fail;
9709         }
9710
9711         leh = (struct link_ea_header *)buf;
9712
9713         if (leh->leh_magic == __swab32(LINK_EA_MAGIC))
9714                 leh->leh_reccount = __swab32(leh->leh_reccount);
9715
9716         lee = (struct link_ea_entry *)(leh + 1);
9717
9718         for (i = 0; i < leh->leh_reccount; i++) {
9719                 reclen = (lee->lee_reclen[0] << 8) | lee->lee_reclen[1];
9720
9721                 /* handle -n -l case */
9722                 if (print_linkno) {
9723                         ptr = strrchr(path_buf, '/');
9724                         if (!ptr)
9725                                 ptr = path_buf;
9726                         else
9727                                 ptr = ptr + 1;
9728
9729                         if (strcmp(ptr, lee->lee_name) == 0) {
9730                                 if (print_fid)
9731                                         printf("%s ", fid_str);
9732
9733                                 printf("%d ", linktmp);
9734                                 printf("%s\n", lee->lee_name);
9735                                 break;
9736                         }
9737                 } else {
9738                         if (print_fid)
9739                                 printf("%s ", fid_str);
9740                         printf("%s\n", lee->lee_name);
9741                 }
9742
9743                 /* Get next record */
9744                 lee = (struct link_ea_entry *)((char *)lee + reclen);
9745         }
9746 fail:
9747         return rc;
9748 }
9749
9750 static int lfs_fid2path(int argc, char **argv)
9751 {
9752         struct option long_opts[] = {
9753                 { .val = '0',   .name = "print0",       .has_arg = no_argument },
9754                 { .val = 'c',   .name = "cur",  .has_arg = no_argument },
9755                 { .val = 'c',   .name = "current",      .has_arg = no_argument },
9756                 { .val = 'c',   .name = "print-link",   .has_arg = no_argument },
9757                 { .val = 'f',   .name = "print-fid",    .has_arg = no_argument },
9758                 { .val = 'l',   .name = "link", .has_arg = required_argument },
9759                 { .val = 'n',   .name = "name", .has_arg = no_argument },
9760                 { .name = NULL } };
9761         char short_opts[] = "0cfl:pr:n";
9762         bool print_only_fname = false;
9763         bool print_linkno = false;
9764         bool print_link = false;
9765         bool print_fid = false;
9766         bool print_mnt_dir;
9767         char mnt_dir[PATH_MAX] = "";
9768         int mnt_fd = -1;
9769         char *path_or_fsname;
9770         long long recno = -1;
9771         int linkno = -1;
9772         char *endptr = NULL;
9773         char link_separator = '\n';
9774         int rc = 0;
9775         int c;
9776         int i;
9777
9778         while ((c = getopt_long(argc, argv, short_opts,long_opts, NULL)) !=
9779                 -1) {
9780                 switch (c) {
9781                 case '0':
9782                         link_separator = '\0';
9783                         break;
9784                 case 'c':
9785                         print_link = true;
9786                         break;
9787                 case 'f':
9788                         print_fid = true;
9789                         break;
9790                 case 'l':
9791                         errno = 0;
9792                         linkno = strtol(optarg, &endptr, 10);
9793                         if (errno != 0 || *endptr != '\0' || linkno < 0) {
9794                                 fprintf(stderr,
9795                                         "%s fid2path: invalid linkno '%s'\n",
9796                                         progname, optarg);
9797                                 return CMD_HELP;
9798                         }
9799                         print_linkno = true;
9800                         break;
9801                 case 'n':
9802                         /* Bypass the full parent path if true
9803                          * only print the final filename */
9804                         print_only_fname = true;
9805                         break;
9806                 case 'r':
9807                         /* recno is something to do with changelogs
9808                          * that was never implemented. We just pass it
9809                          * through for the MDT to ignore.
9810                          */
9811                         errno = 0;
9812                         recno = strtoll(optarg, &endptr, 10);
9813                         if (errno != 0 || *endptr != '\0' || recno < 0) {
9814                                 fprintf(stderr,
9815                                         "%s fid2path: invalid recno '%s'\n",
9816                                         progname, optarg);
9817                                 return CMD_HELP;
9818                         }
9819                         break;
9820                 default:
9821                         fprintf(stderr,
9822                                 "%s fid2path: unrecognized option '%s'\n",
9823                                 progname, argv[optind - 1]);
9824                         return CMD_HELP;
9825                 }
9826         }
9827
9828         if (argc - optind < 2) {
9829                 fprintf(stderr,
9830                         "Usage: %s fid2path FSNAME|ROOT FID...\n",
9831                         progname);
9832                 return CMD_HELP;
9833         }
9834
9835         path_or_fsname = argv[optind];
9836
9837         if (*path_or_fsname == '/') {
9838                 print_mnt_dir = true;
9839                 rc = llapi_search_mounts(path_or_fsname, 0, mnt_dir, NULL);
9840         } else {
9841                 print_mnt_dir = false;
9842                 rc = llapi_search_rootpath(mnt_dir, path_or_fsname);
9843         }
9844
9845         if (rc < 0) {
9846                 fprintf(stderr,
9847                         "%s fid2path: cannot resolve mount point for '%s': %s\n",
9848                         progname, path_or_fsname, strerror(-rc));
9849                 goto out;
9850         }
9851
9852         mnt_fd = open(mnt_dir, O_RDONLY | O_DIRECTORY);
9853         if (mnt_fd < 0) {
9854                 fprintf(stderr,
9855                         "%s fid2path: cannot open mount point for '%s': %s\n",
9856                         progname, path_or_fsname, strerror(-rc));
9857                 goto out;
9858         }
9859
9860         /* Strip trailing slashes from mnt_dir. */
9861         rstripc(mnt_dir + 1, '/');
9862
9863         for (i = optind + 1; i < argc; i++) {
9864                 const char *fid_str = argv[i];
9865                 struct lu_fid fid;
9866                 char *ptr = NULL;
9867                 int rc2;
9868
9869                 rc2 = llapi_fid_parse(fid_str, &fid, NULL);
9870                 if (rc2 < 0) {
9871                         fprintf(stderr,
9872                                 "%s fid2path: invalid FID '%s'\n",
9873                                 progname, fid_str);
9874                         if (rc == 0)
9875                                 rc = rc2;
9876
9877                         continue;
9878                 }
9879
9880                 int linktmp = (linkno >= 0) ? linkno : 0;
9881
9882                 while (1) {
9883                         int oldtmp = linktmp;
9884                         long long rectmp = recno;
9885                         char path_buf[PATH_MAX];
9886
9887                         rc2 = llapi_fid2path_at(mnt_fd, &fid, path_buf,
9888                                                 sizeof(path_buf), &rectmp,
9889                                                 &linktmp);
9890                         if (rc2 < 0) {
9891                                 fprintf(stderr,
9892                                         "%s fid2path: cannot find %s %s: %s\n",
9893                                         progname, path_or_fsname, fid_str,
9894                                         strerror(-rc2));
9895                                 if (rc == 0)
9896                                         rc = rc2;
9897                                 break;
9898                         }
9899
9900                         if (print_only_fname && !print_link) {
9901                                 /* '-n' is passed as option here.
9902                                  * For all other cases of -c fall back
9903                                  * to default(else) path as to get the link
9904                                  * count associated with the file name call
9905                                  * to OBD_IOC_FID2PATH is required
9906                                  */
9907                                 rc = lfs_fid2path_prn_name(mnt_dir,
9908                                                            path_buf,
9909                                                            print_linkno,
9910                                                            print_fid, ptr,
9911                                                            fid_str, linktmp);
9912                                 /* llapi_fid2path_at() is already called once
9913                                  * in this case. No need to call it again.
9914                                  * Break out as we have all the filenames.
9915                                  */
9916                                 break;
9917                         }
9918
9919                         if (print_fid)
9920                                 printf("%s ", fid_str);
9921
9922                         if (print_link)
9923                                 printf("%d ", linktmp);
9924
9925                         /* You may think this looks wrong or weird (and it is!)
9926                          * but we are actually trying to preserve the old quirky
9927                          * behaviors (enforced by our old quirky tests!) that
9928                          * make lfs so much fun to work on:
9929                          *
9930                          *   lustre 0x200000007:0x1:0x0 => "/"
9931                          *   /mnt/lustre 0x200000007:0x1:0x0 => "/mnt/lustre//"
9932                          *
9933                          * Note that llapi_fid2path() returns "" for the root
9934                          * FID. */
9935                         if (!print_only_fname) {
9936                                 printf("%s%s%s%c",
9937                                        print_mnt_dir ? mnt_dir : "",
9938                                        (print_mnt_dir || *path_buf == '\0') ?
9939                                        "/" : "", path_buf, link_separator);
9940                         } else {
9941                                 ptr = strrchr(path_buf, '/');
9942                                 if (!ptr)
9943                                         printf("%s\n", path_buf);
9944                                 else
9945                                         printf("%s\n", ptr + 1);
9946                         }
9947
9948                         if (linkno >= 0)
9949                                 /* specified linkno */
9950                                 break;
9951
9952                         if (oldtmp == linktmp)
9953                                 /* no more links */
9954                                 break;
9955                 }
9956         }
9957 out:
9958         if (!(mnt_fd < 0))
9959                 close(mnt_fd);
9960
9961         return rc;
9962 }
9963
9964 static int lfs_path2fid(int argc, char **argv)
9965 {
9966         struct option long_opts[] = {
9967                 { .val = 'p', .name = "parents", .has_arg = no_argument },
9968                 { .name = NULL } };
9969         char            **path;
9970         const char        short_opts[] = "p";
9971         const char       *sep = "";
9972         struct lu_fid     fid;
9973         int               rc = 0;
9974         bool              show_parents = false;
9975
9976         while ((rc = getopt_long(argc, argv, short_opts,
9977                                  long_opts, NULL)) != -1) {
9978                 switch (rc) {
9979                 case 'p':
9980                         show_parents = true;
9981                         break;
9982                 default:
9983                         fprintf(stderr,
9984                                 "%s path2fid: unrecognized option '%s'\n",
9985                                 progname, argv[optind - 1]);
9986                         return CMD_HELP;
9987                 }
9988         }
9989
9990         if (optind > argc - 1) {
9991                 fprintf(stderr, "%s path2fid: FILE... must be specified\n",
9992                         progname);
9993                 return CMD_HELP;
9994         } else if (optind < argc - 1) {
9995                 sep = ": ";
9996         }
9997
9998         rc = 0;
9999         for (path = argv + optind; optind < argc; path++, optind++) {
10000                 int err = 0;
10001
10002                 if (!show_parents) {
10003                         err = llapi_path2fid(*path, &fid);
10004                         if (!err)
10005                                 printf("%s%s"DFID"\n",
10006                                        *sep != '\0' ? *path : "", sep,
10007                                        PFID(&fid));
10008                 } else {
10009                         char            name[NAME_MAX + 1];
10010                         unsigned int    linkno = 0;
10011
10012                         while ((err = llapi_path2parent(*path, linkno, &fid,
10013                                                 name, sizeof(name))) == 0) {
10014                                 if (*sep != '\0' && linkno == 0)
10015                                         printf("%s%s", *path, sep);
10016
10017                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
10018                                        PFID(&fid), name);
10019                                 linkno++;
10020                         }
10021
10022                         /* err == -ENODATA is end-of-loop */
10023                         if (linkno > 0 && err == -ENODATA) {
10024                                 printf("\n");
10025                                 err = 0;
10026                         }
10027                 }
10028
10029                 if (err) {
10030                         fprintf(stderr,
10031                                 "%s path2fid: cannot get %sfid for '%s': %s\n",
10032                                 progname, show_parents ? "parent " : "", *path,
10033                                 strerror(-err));
10034                         if (rc == 0) {
10035                                 rc = err;
10036                                 errno = -err;
10037                         }
10038                 }
10039         }
10040
10041         return rc;
10042 }
10043
10044 #define MAX_ERRNO       4095
10045 #define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO)
10046
10047 static int lfs_rmfid_and_show_errors(int rootfd, struct fid_array *fa)
10048 {
10049         int rc, rc2, k;
10050
10051         rc = llapi_rmfid_at(rootfd, fa);
10052         if (rc < 0) {
10053                 fprintf(stderr, "%s rmfid: cannot remove FIDs: %s\n",
10054                         progname, strerror(-rc));
10055                 return rc;
10056         }
10057
10058         for (k = 0; k < fa->fa_nr; k++) {
10059                 rc2 = (__s32)fa->fa_fids[k].f_ver;
10060                 if (!IS_ERR_VALUE(rc2))
10061                         continue;
10062
10063                 if (rc == 0)
10064                         rc = rc2;
10065
10066                 fa->fa_fids[k].f_ver = 0;
10067                 fprintf(stderr, "%s rmfid: cannot remove "DFID": %s\n",
10068                         progname, PFID(&fa->fa_fids[k]), strerror(-rc2));
10069         }
10070
10071         return rc;
10072 }
10073
10074 static int lfs_rmfid(int argc, char **argv)
10075 {
10076         int rc = 0, rc2, rc3 = 0, nr;
10077         struct fid_array *fa;
10078         const char *device;
10079         char *fidstr;
10080         int rootfd;
10081
10082         /* Interactive mode: Adjust optind */
10083         if (!optind)
10084                 optind++;
10085
10086         device = argv[optind++];
10087
10088         if (optind > argc - 1) {
10089                 fprintf(stderr, "%s rmfid: missing dirname\n", progname);
10090                 return CMD_HELP;
10091         }
10092
10093         nr = argc - optind;
10094
10095         rc = llapi_root_path_open(device, &rootfd);
10096         if (rc < 0) {
10097                 fprintf(stderr,
10098                         "%s rmfid: error opening device/fsname '%s': %s\n",
10099                         progname, device, strerror(-rc));
10100                 return -rc;
10101         }
10102
10103         fa = malloc(offsetof(struct fid_array, fa_fids[nr + 1]));
10104         if (!fa) {
10105                 fprintf(stderr, "%s rmfid: error allocating %zd bytes: %s\n",
10106                         progname, offsetof(struct fid_array, fa_fids[nr + 1]),
10107                         strerror(errno));
10108                 return -ENOMEM;
10109         }
10110
10111         fa->fa_nr = 0;
10112         rc = 0;
10113         while (optind < argc) {
10114                 char *origfidstr;
10115                 int found;
10116
10117                 origfidstr = fidstr = argv[optind++];
10118                 while (*fidstr == '[')
10119                         fidstr++;
10120                 found = sscanf(fidstr, SFID, RFID(&fa->fa_fids[fa->fa_nr]));
10121                 if (found != 3) {
10122                         fprintf(stderr, "lfs rmfid: '%s': Wrong FID format\n",
10123                                 origfidstr);
10124                         if (!rc3)
10125                                 rc3 = -EINVAL; /* Invalid argument */
10126                         continue;
10127                 }
10128                 fa->fa_nr++;
10129                 if (fa->fa_nr == OBD_MAX_FIDS_IN_ARRAY) {
10130                         /* start another batch */
10131                         rc2 = lfs_rmfid_and_show_errors(rootfd, fa);
10132                         if (rc2 && !rc)
10133                                 rc = rc2;
10134                         if (rc3)
10135                                 rc = rc3;
10136                         fa->fa_nr = 0;
10137                 }
10138         }
10139         if (fa->fa_nr) {
10140                 rc2 = lfs_rmfid_and_show_errors(rootfd, fa);
10141                 if (rc2 && !rc)
10142                         rc = rc2;
10143                 if (rc3)
10144                         rc = rc3;
10145         }
10146
10147         if (fa) {
10148                 free(fa);
10149                 fa = NULL;
10150         }
10151
10152         close(rootfd);
10153         return rc;
10154 }
10155
10156 static int lfs_data_version(int argc, char **argv)
10157 {
10158         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
10159         __u64 data_version;
10160         char *path;
10161         int fd;
10162         int rc;
10163         int c;
10164
10165         if (argc < 2) {
10166                 fprintf(stderr, "%s: FILE must be specified\n",
10167                         progname);
10168                 return CMD_HELP;
10169         }
10170
10171         while ((c = getopt(argc, argv, "hnrw")) != -1) {
10172                 switch (c) {
10173                 case 'n':
10174                         data_version_flags = 0;
10175                         break;
10176                 case 'r':
10177                         data_version_flags |= LL_DV_RD_FLUSH;
10178                         break;
10179                 case 'w':
10180                         data_version_flags |= LL_DV_WR_FLUSH;
10181                         break;
10182                 default:
10183                         fprintf(stderr,
10184                                 "%s data_version: unrecognized option '%s'\n",
10185                                 progname, argv[optind - 1]);
10186                         fallthrough;
10187                 case 'h':
10188                         return CMD_HELP;
10189                 }
10190         }
10191         if (optind == argc) {
10192                 fprintf(stderr, "%s data_version: FILE must be specified\n",
10193                         progname);
10194                 return CMD_HELP;
10195         }
10196
10197         path = argv[optind];
10198         fd = open(path, O_RDONLY);
10199         if (fd < 0) {
10200                 rc = -errno;
10201                 fprintf(stderr, "%s data_version: cannot open file '%s': %s\n",
10202                         progname, path, strerror(-rc));
10203                 return rc;
10204         }
10205
10206         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
10207         if (rc < 0)
10208                 fprintf(stderr,
10209                         "%s data_version: cannot get version for '%s': %s\n",
10210                         progname, path, strerror(-rc));
10211         else
10212                 printf("%ju" "\n", (uintmax_t)data_version);
10213
10214         close(fd);
10215         return rc;
10216 }
10217
10218 static int lfs_hsm_state(int argc, char **argv)
10219 {
10220         int rc = 0;
10221         int i = 1;
10222         char *path;
10223         struct hsm_user_state hus;
10224
10225         if (argc < 2)
10226                 return CMD_HELP;
10227
10228         do {
10229                 int rc2;
10230                 path = argv[i];
10231
10232                 rc2 = llapi_hsm_state_get(path, &hus);
10233                 if (rc2) {
10234                         fprintf(stderr,
10235                                 "%s %s: get HSM state for '%s' failed: %s\n",
10236                                 progname, argv[0], path, strerror(-rc2));
10237                         if (!rc)
10238                                 rc = rc2;
10239                         continue;
10240                 }
10241
10242                 /* Display path name and status flags */
10243                 printf("%s: (0x%08x)", path, hus.hus_states);
10244
10245                 if (hus.hus_states & HS_RELEASED)
10246                         printf(" released");
10247                 if (hus.hus_states & HS_EXISTS)
10248                         printf(" exists");
10249                 if (hus.hus_states & HS_DIRTY)
10250                         printf(" dirty");
10251                 if (hus.hus_states & HS_ARCHIVED)
10252                         printf(" archived");
10253                 /* Display user-settable flags */
10254                 if (hus.hus_states & HS_NORELEASE)
10255                         printf(" never_release");
10256                 if (hus.hus_states & HS_NOARCHIVE)
10257                         printf(" never_archive");
10258                 if (hus.hus_states & HS_LOST)
10259                         printf(" lost_from_hsm");
10260
10261                 if (hus.hus_archive_id != 0)
10262                         printf(", archive_id:%d", hus.hus_archive_id);
10263                 printf("\n");
10264
10265         } while (++i < argc);
10266
10267         return rc;
10268 }
10269
10270 #define LFS_HSM_SET   0
10271 #define LFS_HSM_CLEAR 1
10272
10273 /**
10274  * Generic function to set or clear HSM flags.
10275  * Used by hsm_set and hsm_clear.
10276  *
10277  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
10278  */
10279 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
10280 {
10281         struct option long_opts[] = {
10282         { .val = 'A',   .name = "archived",     .has_arg = no_argument },
10283         { .val = 'a',   .name = "noarchive",    .has_arg = no_argument },
10284         { .val = 'd',   .name = "dirty",        .has_arg = no_argument },
10285         { .val = 'e',   .name = "exists",       .has_arg = no_argument },
10286         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10287         { .val = 'i',   .name = "archive-id",   .has_arg = required_argument },
10288         { .val = 'l',   .name = "lost",         .has_arg = no_argument },
10289         { .val = 'r',   .name = "norelease",    .has_arg = no_argument },
10290         { .name = NULL } };
10291         __u64 mask = 0;
10292         int c, rc = 0;
10293         char *path;
10294         __u32 archive_id = 0;
10295         char *end = NULL;
10296
10297         if (argc < 3)
10298                 return CMD_HELP;
10299
10300         while ((c = getopt_long(argc, argv, "aAdehi:lr",
10301                                 long_opts, NULL)) != -1) {
10302                 switch (c) {
10303                 case 'l':
10304                         mask |= HS_LOST;
10305                         break;
10306                 case 'a':
10307                         mask |= HS_NOARCHIVE;
10308                         break;
10309                 case 'A':
10310                         mask |= HS_ARCHIVED;
10311                         break;
10312                 case 'r':
10313                         mask |= HS_NORELEASE;
10314                         break;
10315                 case 'd':
10316                         mask |= HS_DIRTY;
10317                         break;
10318                 case 'e':
10319                         mask |= HS_EXISTS;
10320                         break;
10321                 case 'i':
10322                         errno = 0;
10323                         archive_id = strtol(optarg, &end, 10);
10324                         if (errno != 0 || *end != '\0' || archive_id < 0) {
10325                                 fprintf(stderr,
10326                                         "%s: invalid archive_id: '%s'\n",
10327                                         progname, end);
10328                                 return CMD_HELP;
10329                         }
10330                         break;
10331                 default:
10332                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10333                                 progname, argv[optind - 1]);
10334                         fallthrough;
10335                 case 'h':
10336                         return CMD_HELP;
10337                 }
10338         }
10339
10340         /* User should have specified a flag */
10341         if (mask == 0)
10342                 return CMD_HELP;
10343
10344         while (optind < argc) {
10345                 int rc2;
10346                 path = argv[optind];
10347
10348                 /* If mode == 0, this means we apply the mask. */
10349                 if (mode == LFS_HSM_SET)
10350                         rc2 = llapi_hsm_state_set(path, mask, 0, archive_id);
10351                 else
10352                         rc2 = llapi_hsm_state_set(path, 0, mask, 0);
10353
10354                 if (rc2) {
10355                         fprintf(stderr,
10356                                 "%s %s: change hsm flags for '%s' failed: %s\n",
10357                                 progname, argv[0], path, strerror(-rc2));
10358                         if (!rc)
10359                                 rc = rc2;
10360                 }
10361                 optind++;
10362         }
10363
10364         return rc;
10365 }
10366
10367 static int lfs_hsm_action(int argc, char **argv)
10368 {
10369         struct hsm_current_action hca;
10370         struct hsm_extent he;
10371         enum hsm_user_action hua;
10372         enum hsm_progress_states hps;
10373         int rc = 0;
10374         int i = 1;
10375         char *path;
10376
10377         if (argc < 2)
10378                 return CMD_HELP;
10379
10380         do {
10381                 int rc2;
10382                 path = argv[i];
10383
10384                 rc2 = llapi_hsm_current_action(path, &hca);
10385                 if (rc2) {
10386                         fprintf(stderr,
10387                                 "%s %s: get hsm action for '%s' failed: %s\n",
10388                                 progname, argv[0], path, strerror(-rc2));
10389
10390                         if (!rc)
10391                                 rc = rc2;
10392                         continue;
10393                 }
10394                 he = hca.hca_location;
10395                 hua = hca.hca_action;
10396                 hps = hca.hca_state;
10397
10398                 printf("%s: %s", path, hsm_user_action2name(hua));
10399
10400                 /* Skip file without action */
10401                 if (hca.hca_action == HUA_NONE) {
10402                         printf("\n");
10403                         continue;
10404                 }
10405
10406                 printf(" %s ", hsm_progress_state2name(hps));
10407
10408                 if ((hps == HPS_RUNNING) &&
10409                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
10410                         printf("(%llu bytes moved)\n",
10411                                (unsigned long long)he.length);
10412                 else if ((he.offset + he.length) == LUSTRE_EOF)
10413                         printf("(from %llu to EOF)\n",
10414                                (unsigned long long)he.offset);
10415                 else
10416                         printf("(from %llu to %llu)\n",
10417                                (unsigned long long)he.offset,
10418                                (unsigned long long)(he.offset + he.length));
10419
10420         } while (++i < argc);
10421
10422         return rc;
10423 }
10424
10425 static int lfs_hsm_set(int argc, char **argv)
10426 {
10427         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
10428 }
10429
10430 static int lfs_hsm_clear(int argc, char **argv)
10431 {
10432         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
10433 }
10434
10435 /**
10436  * Check file state and return its fid, to be used by lfs_hsm_request().
10437  *
10438  * \param[in]     file      Path to file to check
10439  * \param[in,out] fid       Pointer to allocated lu_fid struct.
10440  * \param[in,out] last_dev  Pointer to last device id used.
10441  *
10442  * \return 0 on success.
10443  */
10444 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
10445                                 dev_t *last_dev)
10446 {
10447         struct stat     st;
10448         int             rc;
10449
10450         rc = lstat(file, &st);
10451         if (rc) {
10452                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
10453                 return -errno;
10454         }
10455         /*
10456          * Checking for regular file as archiving as posix copytool
10457          * rejects archiving files other than regular files
10458          */
10459         if (!S_ISREG(st.st_mode)) {
10460                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
10461                 return CMD_HELP;
10462         }
10463         /* A request should be ... */
10464         if (*last_dev != st.st_dev && *last_dev != 0) {
10465                 fprintf(stderr,
10466                         "All files should be on the same filesystem: %s\n",
10467                         file);
10468                 return -EINVAL;
10469         }
10470         *last_dev = st.st_dev;
10471
10472         rc = llapi_path2fid(file, fid);
10473         if (rc) {
10474                 fprintf(stderr, "Cannot read FID of %s: %s\n",
10475                         file, strerror(-rc));
10476                 return rc;
10477         }
10478         return 0;
10479 }
10480
10481 /* Fill an HSM HUR item with a given file name.
10482  *
10483  * If mntpath is set, then the filename is actually a FID, and no
10484  * lookup on the filesystem will be performed.
10485  *
10486  * \param[in]  hur         the user request to fill
10487  * \param[in]  idx         index of the item inside the HUR to fill
10488  * \param[in]  mntpath     mountpoint of Lustre
10489  * \param[in]  fname       filename (if mtnpath is NULL)
10490  *                         or FID (if mntpath is set)
10491  * \param[in]  last_dev    pointer to last device id used
10492  *
10493  * \retval 0 on success
10494  * \retval CMD_HELP or a negative errno on error
10495  */
10496 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
10497                          const char *mntpath, const char *fname,
10498                          dev_t *last_dev)
10499 {
10500         struct hsm_user_item *hui = &hur->hur_user_item[idx];
10501         int rc;
10502
10503         hui->hui_extent.length = -1;
10504
10505         if (mntpath) {
10506                 rc = llapi_fid_parse(fname, &hui->hui_fid, NULL);
10507                 if (rc)
10508                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
10509                                 fname);
10510         } else {
10511                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
10512         }
10513
10514         if (rc == 0)
10515                 hur->hur_request.hr_itemcount++;
10516
10517         return rc;
10518 }
10519
10520 static int lfs_hsm_request(int argc, char **argv, int action)
10521 {
10522         struct option long_opts[] = {
10523         { .val = 'a',   .name = "archive",      .has_arg = required_argument },
10524         { .val = 'D',   .name = "data",         .has_arg = required_argument },
10525         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10526         { .val = 'l',   .name = "filelist",     .has_arg = required_argument },
10527         { .val = 'm',   .name = "mntpath",      .has_arg = required_argument },
10528         { .name = NULL } };
10529         dev_t last_dev = 0;
10530         struct hsm_user_request *hur, *oldhur;
10531         int c, i;
10532         size_t len;
10533         int nbfile;
10534         char *line = NULL;
10535         char *filelist = NULL;
10536         char fullpath[PATH_MAX];
10537         char *opaque = NULL;
10538         int opaque_len = 0;
10539         int archive_id = 0;
10540         FILE *fp;
10541         int nbfile_alloc = 0;
10542         char *some_file = NULL;
10543         char *mntpath = NULL;
10544         int rc;
10545
10546         if (argc < 2) {
10547                 rc = CMD_HELP;
10548                 goto out_cmd_help;
10549         }
10550
10551         while ((c = getopt_long(argc, argv, "a:D:hl:m:",
10552                                 long_opts, NULL)) != -1) {
10553                 switch (c) {
10554                 case 'l':
10555                         filelist = optarg;
10556                         break;
10557                 case 'D':
10558                         opaque = optarg;
10559                         break;
10560                 case 'a':
10561                         if (action != HUA_ARCHIVE &&
10562                             action != HUA_REMOVE) {
10563                                 fprintf(stderr,
10564                                         "error: -a is supported only when archiving or removing\n");
10565                                 rc = CMD_HELP;
10566                                 goto out_cmd_help;
10567                         }
10568                         archive_id = atoi(optarg);
10569                         break;
10570                 case 'm':
10571                         if (!some_file) {
10572                                 mntpath = optarg;
10573                                 some_file = strdup(optarg);
10574                         }
10575                         break;
10576                 default:
10577                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10578                                 progname, argv[optind - 1]);
10579                         fallthrough;
10580                 case 'h':
10581                         rc = CMD_HELP;
10582                         goto out_cmd_help;
10583                 }
10584         }
10585
10586         /* All remaining args are files, so we have at least nbfile */
10587         nbfile = argc - optind;
10588
10589         if ((nbfile == 0) && (!filelist)) {
10590                 rc = errno;
10591                 goto out_errno;
10592         }
10593
10594         if (opaque)
10595                 opaque_len = strlen(opaque);
10596
10597         /*
10598          * Alloc the request structure with enough place to store all files
10599          * from command line.
10600          */
10601         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
10602         if (!hur) {
10603                 fprintf(stderr, "Cannot create the request: %s\n",
10604                         strerror(errno));
10605                 rc = errno;
10606                 goto out_errno;
10607         }
10608         nbfile_alloc = nbfile;
10609
10610         hur->hur_request.hr_action = action;
10611         hur->hur_request.hr_archive_id = archive_id;
10612         hur->hur_request.hr_flags = 0;
10613
10614         /* All remaining args are files, add them */
10615         if (nbfile != 0 && some_file == NULL)
10616                 some_file = strdup(argv[optind]);
10617
10618         for (i = 0; i < nbfile; i++) {
10619                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
10620                                    &last_dev);
10621                 if (rc)
10622                         goto out_hur;
10623         }
10624
10625         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
10626
10627         /* If a filelist was specified, read the filelist from it. */
10628         if (filelist) {
10629                 fp = fopen(filelist, "r");
10630                 if (!fp) {
10631                         fprintf(stderr, "Cannot read the file list %s: %s\n",
10632                                 filelist, strerror(errno));
10633                         rc = -errno;
10634                         goto out_hur;
10635                 }
10636
10637                 while ((rc = getline(&line, &len, fp)) != -1) {
10638                         /*
10639                          * If allocated buffer was too small, get something
10640                          * larger
10641                          */
10642                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
10643                                 ssize_t size;
10644
10645                                 nbfile_alloc = nbfile_alloc * 2 + 1;
10646                                 oldhur = hur;
10647                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
10648                                                                    opaque_len);
10649                                 if (!hur) {
10650                                         fprintf(stderr,
10651                                                 "hsm: cannot allocate the request: %s\n",
10652                                                 strerror(errno));
10653                                         hur = oldhur;
10654                                         rc = -errno;
10655                                         fclose(fp);
10656                                         goto out_hur;
10657                                 }
10658                                 size = hur_len(oldhur);
10659                                 if (size < 0) {
10660                                         fprintf(stderr,
10661                                                 "hsm: cannot allocate %u files + %u bytes data\n",
10662                                                 oldhur->hur_request.hr_itemcount,
10663                                                 oldhur->hur_request.hr_data_len);
10664                                         free(hur);
10665                                         hur = oldhur;
10666                                         rc = -E2BIG;
10667                                         fclose(fp);
10668                                         goto out_hur;
10669                                 }
10670                                 memcpy(hur, oldhur, size);
10671                                 free(oldhur);
10672                         }
10673
10674                         /* Chop CR */
10675                         if (line[strlen(line) - 1] == '\n')
10676                                 line[strlen(line) - 1] = '\0';
10677
10678                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
10679                                            mntpath, line, &last_dev);
10680                         if (rc) {
10681                                 fclose(fp);
10682                                 goto out_hur;
10683                         }
10684
10685                         if (!some_file) {
10686                                 some_file = line;
10687                                 line = NULL;
10688                         }
10689                 }
10690
10691                 rc = fclose(fp);
10692                 free(line);
10693         }
10694
10695         /* If a --data was used, add it to the request */
10696         hur->hur_request.hr_data_len = opaque_len;
10697         if (opaque)
10698                 memcpy(hur_data(hur), opaque, opaque_len);
10699
10700         /* Send the HSM request */
10701         if (realpath(some_file, fullpath) == NULL) {
10702                 fprintf(stderr, "Could not find path '%s': %s\n",
10703                         some_file, strerror(errno));
10704         }
10705         rc = llapi_hsm_request(fullpath, hur);
10706         if (rc)
10707                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
10708                         some_file, strerror(-rc));
10709
10710 out_hur:
10711         free(hur);
10712 out_errno:
10713         free(some_file);
10714 out_cmd_help:
10715         return rc;
10716 }
10717
10718 static int lfs_hsm_archive(int argc, char **argv)
10719 {
10720         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
10721 }
10722
10723 static int lfs_hsm_restore(int argc, char **argv)
10724 {
10725         return lfs_hsm_request(argc, argv, HUA_RESTORE);
10726 }
10727
10728 static int lfs_hsm_release(int argc, char **argv)
10729 {
10730         return lfs_hsm_request(argc, argv, HUA_RELEASE);
10731 }
10732
10733 static int lfs_hsm_remove(int argc, char **argv)
10734 {
10735         return lfs_hsm_request(argc, argv, HUA_REMOVE);
10736 }
10737
10738 static int lfs_hsm_cancel(int argc, char **argv)
10739 {
10740         return lfs_hsm_request(argc, argv, HUA_CANCEL);
10741 }
10742
10743 static int lfs_swap_layouts(int argc, char **argv)
10744 {
10745         int noxtime = 0;
10746
10747         if (argc == 4 && !strcmp(argv[1], "-n"))
10748                 noxtime = 1;
10749         else if (argc != 3)
10750                 return CMD_HELP;
10751
10752         return llapi_swap_layouts(argv[1+noxtime], argv[2+noxtime],
10753                                   0, 0, noxtime ? 0 :
10754                                   (SWAP_LAYOUTS_KEEP_MTIME |
10755                                   SWAP_LAYOUTS_KEEP_ATIME));
10756 }
10757
10758 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
10759
10760 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
10761
10762 int lfs_get_mode(const char *string)
10763 {
10764         enum lock_mode_user mode;
10765
10766         for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
10767                 if (lock_mode_names[mode] == NULL)
10768                         continue;
10769                 if (strcasecmp(string, lock_mode_names[mode]) == 0)
10770                         return mode;
10771         }
10772
10773         return -EINVAL;
10774 }
10775
10776 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
10777 {
10778         enum lu_ladvise_type advice;
10779
10780         for (advice = 0;
10781              advice < ARRAY_SIZE(ladvise_names); advice++) {
10782                 if (ladvise_names[advice] == NULL)
10783                         continue;
10784                 if (strcmp(string, ladvise_names[advice]) == 0)
10785                         return advice;
10786         }
10787
10788         return LU_LADVISE_INVALID;
10789 }
10790
10791 static int lfs_ladvise(int argc, char **argv)
10792 {
10793         struct option long_opts[] = {
10794         { .val = 'a',   .name = "advice",       .has_arg = required_argument },
10795         { .val = 'b',   .name = "background",   .has_arg = no_argument },
10796         { .val = 'e',   .name = "end",          .has_arg = required_argument },
10797         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10798         { .val = 'l',   .name = "length",       .has_arg = required_argument },
10799         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
10800         { .val = 's',   .name = "start",        .has_arg = required_argument },
10801         { .val = 'u',   .name = "unset",        .has_arg = no_argument },
10802         { .name = NULL } };
10803         struct llapi_lu_ladvise advice;
10804         enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
10805         unsigned long long start = 0;
10806         unsigned long long end = LUSTRE_EOF;
10807         unsigned long long length = 0;
10808         unsigned long long size_units;
10809         unsigned long long flags = 0;
10810         int c, fd, rc = 0;
10811         const char *path;
10812         int mode = 0;
10813
10814         optind = 0;
10815         while ((c = getopt_long(argc, argv, "a:be:hl:m:s:u",
10816                                 long_opts, NULL)) != -1) {
10817                 switch (c) {
10818                 case 'a':
10819                         advice_type = lfs_get_ladvice(optarg);
10820                         if (advice_type == LU_LADVISE_INVALID) {
10821                                 fprintf(stderr,
10822                                         "%s: invalid advice type '%s'\n",
10823                                         progname, optarg);
10824                                 fprintf(stderr, "Valid types:");
10825
10826                                 for (advice_type = 0;
10827                                      advice_type < ARRAY_SIZE(ladvise_names);
10828                                      advice_type++) {
10829                                         if (ladvise_names[advice_type] == NULL)
10830                                                 continue;
10831                                         fprintf(stderr, " %s",
10832                                                 ladvise_names[advice_type]);
10833                                 }
10834                                 fprintf(stderr, "\n");
10835
10836                                 return CMD_HELP;
10837                         }
10838                         break;
10839                 case 'b':
10840                         flags |= LF_ASYNC;
10841                         break;
10842                 case 'u':
10843                         flags |= LF_UNSET;
10844                         break;
10845                 case 'e':
10846                         size_units = 1;
10847                         rc = llapi_parse_size(optarg, &end,
10848                                               &size_units, 0);
10849                         if (rc) {
10850                                 fprintf(stderr, "%s: bad end offset '%s'\n",
10851                                         argv[0], optarg);
10852                                 return CMD_HELP;
10853                         }
10854                         break;
10855                 case 's':
10856                         size_units = 1;
10857                         rc = llapi_parse_size(optarg, &start,
10858                                               &size_units, 0);
10859                         if (rc) {
10860                                 fprintf(stderr,
10861                                         "%s: bad start offset '%s'\n",
10862                                         argv[0], optarg);
10863                                 return CMD_HELP;
10864                         }
10865                         break;
10866                 case 'l':
10867                         size_units = 1;
10868                         rc = llapi_parse_size(optarg, &length,
10869                                               &size_units, 0);
10870                         if (rc) {
10871                                 fprintf(stderr, "%s: bad length '%s'\n",
10872                                         argv[0], optarg);
10873                                 return CMD_HELP;
10874                         }
10875                         break;
10876                 case 'm':
10877                         mode = lfs_get_mode(optarg);
10878                         if (mode < 0) {
10879                                 fprintf(stderr,
10880                                         "%s: bad mode '%s', valid modes are READ or WRITE\n",
10881                                         argv[0], optarg);
10882                                 return CMD_HELP;
10883                         }
10884                         break;
10885                 default:
10886                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10887                                 progname, argv[optind - 1]);
10888                         fallthrough;
10889                 case 'h':
10890                         return CMD_HELP;
10891                 }
10892         }
10893
10894         if (advice_type == LU_LADVISE_INVALID) {
10895                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
10896                 fprintf(stderr, "Valid types:");
10897                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
10898                      advice_type++) {
10899                         if (ladvise_names[advice_type] == NULL)
10900                                 continue;
10901                         fprintf(stderr, " %s", ladvise_names[advice_type]);
10902                 }
10903                 fprintf(stderr, "\n");
10904                 return CMD_HELP;
10905         }
10906
10907         if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
10908                 fprintf(stderr,
10909                         "%s: Lock no expand advice is a per file descriptor advice, so when called from lfs, it does nothing.\n",
10910                         argv[0]);
10911                 return CMD_HELP;
10912         }
10913
10914         if (argc <= optind) {
10915                 fprintf(stderr, "%s: please give one or more file names\n",
10916                         argv[0]);
10917                 return CMD_HELP;
10918         }
10919
10920         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
10921                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
10922                         argv[0]);
10923                 return CMD_HELP;
10924         }
10925
10926         if (end == LUSTRE_EOF && length != 0)
10927                 end = start + length;
10928
10929         if (end <= start) {
10930                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
10931                         argv[0], start, end);
10932                 return CMD_HELP;
10933         }
10934
10935         if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
10936                 fprintf(stderr, "%s: mode is only valid with lockahead\n",
10937                         argv[0]);
10938                 return CMD_HELP;
10939         }
10940
10941         if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
10942                 fprintf(stderr, "%s: mode is required with lockahead\n",
10943                         argv[0]);
10944                 return CMD_HELP;
10945         }
10946
10947         while (optind < argc) {
10948                 int rc2;
10949
10950                 path = argv[optind++];
10951
10952                 fd = open(path, O_RDONLY);
10953                 if (fd < 0) {
10954                         rc2 = -errno;
10955                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
10956                                 argv[0], path, strerror(-rc2));
10957                         if (!rc)
10958                                 rc = rc2;
10959                         continue;
10960                 }
10961
10962                 advice.lla_start = start;
10963                 advice.lla_end = end;
10964                 advice.lla_advice = advice_type;
10965                 advice.lla_value1 = 0;
10966                 advice.lla_value2 = 0;
10967                 advice.lla_value3 = 0;
10968                 advice.lla_value4 = 0;
10969                 if (advice_type == LU_LADVISE_LOCKAHEAD) {
10970                         advice.lla_lockahead_mode = mode;
10971                         advice.lla_peradvice_flags = flags;
10972                 }
10973
10974                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
10975                 close(fd);
10976                 if (rc2 < 0) {
10977                         fprintf(stderr,
10978                                 "%s: cannot give advice '%s' to file '%s': %s\n",
10979                                 argv[0], ladvise_names[advice_type],
10980                                 path, strerror(errno));
10981
10982                         if (!rc)
10983                                 rc = rc2;
10984                         continue;
10985                 }
10986         }
10987
10988         return rc;
10989 }
10990
10991 static const char *const heat_names[] = LU_HEAT_NAMES;
10992
10993 static int lfs_heat_get(int argc, char **argv)
10994 {
10995         struct lu_heat *heat;
10996         int rc = 0, rc2;
10997         char *path;
10998         int fd;
10999         int i;
11000
11001         if (argc <= 1)
11002                 return CMD_HELP;
11003
11004         heat = calloc(sizeof(*heat) + sizeof(__u64) * OBD_HEAT_COUNT, 1);
11005         if (!heat) {
11006                 fprintf(stderr, "%s: memory allocation failed\n", argv[0]);
11007                 return -ENOMEM;
11008         }
11009
11010         optind = 1;
11011         while (optind < argc) {
11012                 path = argv[optind++];
11013
11014                 fd = open(path, O_RDONLY);
11015                 if (fd < 0) {
11016                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
11017                                 argv[0], path, strerror(errno));
11018                         rc2 = -errno;
11019                         goto next;
11020                 }
11021
11022                 heat->lh_count = OBD_HEAT_COUNT;
11023                 rc2 = llapi_heat_get(fd, heat);
11024                 close(fd);
11025                 if (rc2 < 0) {
11026                         fprintf(stderr,
11027                                 "%s: cannot get heat of file '%s': %s\n",
11028                                 argv[0], path, strerror(errno));
11029                         goto next;
11030                 }
11031
11032                 printf("flags: %x\n", heat->lh_flags);
11033                 for (i = 0; i < heat->lh_count; i++)
11034                         printf("%s: %llu\n", heat_names[i],
11035                                (unsigned long long)heat->lh_heat[i]);
11036 next:
11037                 if (rc == 0 && rc2 < 0)
11038                         rc = rc2;
11039         }
11040
11041         free(heat);
11042         return rc;
11043 }
11044
11045 static int lfs_heat_set(int argc, char **argv)
11046 {
11047         struct option long_opts[] = {
11048         { .val = 'c',   .name = "clear",        .has_arg = no_argument },
11049         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11050         { .val = 'o',   .name = "off",          .has_arg = no_argument },
11051         { .val = 'O',   .name = "on",           .has_arg = no_argument },
11052         { .name = NULL } };
11053         enum lu_heat_flag flags = 0;
11054         int rc = 0, rc2;
11055         char *path;
11056         int fd;
11057         int c;
11058
11059         if (argc <= 1)
11060                 return CMD_HELP;
11061
11062         optind = 0;
11063         while ((c = getopt_long(argc, argv, "choO", long_opts, NULL)) != -1) {
11064                 switch (c) {
11065                 case 'c':
11066                         flags |= LU_HEAT_FLAG_CLEAR;
11067                         break;
11068                 case 'o':
11069                         flags |= LU_HEAT_FLAG_CLEAR;
11070                         flags |= LU_HEAT_FLAG_OFF;
11071                         break;
11072                 case 'O':
11073                         flags &= ~LU_HEAT_FLAG_OFF;
11074                         break;
11075                 default:
11076                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11077                                 progname, argv[optind - 1]);
11078                         fallthrough;
11079                 case 'h':
11080                         return CMD_HELP;
11081                 }
11082         }
11083
11084         if (argc <= optind) {
11085                 fprintf(stderr, "%s: please give one or more file names\n",
11086                         argv[0]);
11087                 return CMD_HELP;
11088         }
11089
11090         while (optind < argc) {
11091                 path = argv[optind++];
11092
11093                 fd = open(path, O_RDONLY);
11094                 if (fd < 0) {
11095                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
11096                                 argv[0], path, strerror(errno));
11097                         rc2 = -errno;
11098                         goto next;
11099                 }
11100
11101                 rc2 = llapi_heat_set(fd, flags);
11102                 close(fd);
11103                 if (rc2 < 0) {
11104                         fprintf(stderr,
11105                                 "%s: cannot setflags heat of file '%s': %s\n",
11106                                 argv[0], path, strerror(errno));
11107                         goto next;
11108                 }
11109 next:
11110                 if (rc == 0 && rc2 < 0)
11111                         rc = rc2;
11112         }
11113         return rc;
11114 }
11115
11116 /**
11117  * The input string contains a comma delimited list of component ids and
11118  * ranges, for example "1,2-4,7".
11119  */
11120 static int parse_mirror_ids(__u16 *ids, int size, char *arg)
11121 {
11122         bool end_of_loop = false;
11123         char *ptr = NULL;
11124         int nr = 0;
11125         int rc;
11126
11127         if (!arg)
11128                 return -EINVAL;
11129
11130         while (!end_of_loop) {
11131                 int start_index;
11132                 int end_index;
11133                 int i;
11134                 char *endptr = NULL;
11135
11136                 rc = -EINVAL;
11137                 ptr = strchrnul(arg, ',');
11138                 end_of_loop = *ptr == '\0';
11139                 *ptr = '\0';
11140
11141                 start_index = strtol(arg, &endptr, 0);
11142                 if (endptr == arg) /* no data at all */
11143                         break;
11144                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
11145                         break;
11146                 if (start_index < 0)
11147                         break;
11148
11149                 end_index = start_index;
11150                 if (*endptr == '-') {
11151                         end_index = strtol(endptr + 1, &endptr, 0);
11152                         if (*endptr != '\0')
11153                                 break;
11154                         if (end_index < start_index)
11155                                 break;
11156                 }
11157
11158                 for (i = start_index; i <= end_index && size > 0; i++) {
11159                         int j;
11160
11161                         /* remove duplicate */
11162                         for (j = 0; j < nr; j++) {
11163                                 if (ids[j] == i)
11164                                         break;
11165                         }
11166                         if (j == nr) { /* no duplicate */
11167                                 ids[nr++] = i;
11168                                 --size;
11169                         }
11170                 }
11171
11172                 if (size == 0 && i < end_index)
11173                         break;
11174
11175                 *ptr = ',';
11176                 arg = ++ptr;
11177                 rc = 0;
11178         }
11179         if (!end_of_loop && ptr)
11180                 *ptr = ',';
11181
11182         return rc < 0 ? rc : nr;
11183 }
11184
11185 /**
11186  * struct verify_mirror_id - Mirror id to be verified.
11187  * @mirror_id:   A specified mirror id.
11188  * @is_valid_id: @mirror_id is valid or not in the mirrored file.
11189  */
11190 struct verify_mirror_id {
11191         __u16 mirror_id;
11192         bool is_valid_id;
11193 };
11194
11195 /**
11196  * compare_mirror_ids() - Compare mirror ids.
11197  * @layout: Mirror component list.
11198  * @cbdata: Callback data in verify_mirror_id structure.
11199  *
11200  * This is a callback function called by llapi_layout_comp_iterate()
11201  * to compare the specified mirror id with the one in the current
11202  * component of @layout. If they are the same, then the specified
11203  * mirror id is valid.
11204  *
11205  * Return: a negative error code on failure or
11206  *         LLAPI_LAYOUT_ITER_CONT: Proceed iteration
11207  *         LLAPI_LAYOUT_ITER_STOP: Stop iteration
11208  */
11209 static inline
11210 int compare_mirror_ids(struct llapi_layout *layout, void *cbdata)
11211 {
11212         struct verify_mirror_id *mirror_id_cbdata =
11213                                  (struct verify_mirror_id *)cbdata;
11214         uint32_t mirror_id;
11215         int rc = 0;
11216
11217         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
11218         if (rc < 0) {
11219                 rc = -errno;
11220                 fprintf(stderr,
11221                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
11222                         progname, strerror(errno));
11223                 return rc;
11224         }
11225
11226         if (mirror_id_cbdata->mirror_id == mirror_id) {
11227                 mirror_id_cbdata->is_valid_id = true;
11228                 return LLAPI_LAYOUT_ITER_STOP;
11229         }
11230
11231         return LLAPI_LAYOUT_ITER_CONT;
11232 }
11233
11234 /**
11235  * verify_mirror_ids() - Verify specified mirror ids.
11236  * @fname:      Mirrored file name.
11237  * @mirror_ids: Specified mirror ids to be verified.
11238  * @ids_nr:     Number of specified mirror ids.
11239  *
11240  * This function verifies that specified @mirror_ids are valid
11241  * in the mirrored file @fname.
11242  *
11243  * Return: 0 on success or a negative error code on failure.
11244  */
11245 static inline
11246 int verify_mirror_ids(const char *fname, __u16 *mirror_ids, int ids_nr)
11247 {
11248         struct llapi_layout *layout = NULL;
11249         struct verify_mirror_id mirror_id_cbdata = { 0 };
11250         struct stat stbuf;
11251         uint32_t flr_state;
11252         int i;
11253         int fd;
11254         int rc = 0;
11255         int rc2 = 0;
11256
11257         if (ids_nr <= 0)
11258                 return -EINVAL;
11259
11260         if (stat(fname, &stbuf) < 0) {
11261                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
11262                         progname, fname, strerror(errno));
11263                 rc = -errno;
11264                 goto error;
11265         }
11266
11267         if (!S_ISREG(stbuf.st_mode)) {
11268                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
11269                         progname, fname);
11270                 rc = -EINVAL;
11271                 goto error;
11272         }
11273
11274         fd = open(fname, O_DIRECT | O_RDONLY);
11275         if (fd < 0) {
11276                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
11277                         progname, fname, strerror(errno));
11278                 rc = -errno;
11279                 goto error;
11280         }
11281
11282         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
11283         if (rc < 0) {
11284                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
11285                         progname, fname, strerror(errno));
11286                 goto close_fd;
11287         }
11288
11289         layout = llapi_layout_get_by_fd(fd, 0);
11290         if (!layout) {
11291                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
11292                         progname, fname, strerror(errno));
11293                 rc = -errno;
11294                 llapi_lease_release(fd);
11295                 goto close_fd;
11296         }
11297
11298         rc = llapi_layout_flags_get(layout, &flr_state);
11299         if (rc < 0) {
11300                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
11301                         progname, fname, strerror(errno));
11302                 rc = -errno;
11303                 goto free_layout;
11304         }
11305
11306         flr_state &= LCM_FL_FLR_MASK;
11307         switch (flr_state) {
11308         case LCM_FL_NONE:
11309                 rc = -EINVAL;
11310                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
11311                         progname, fname, llapi_layout_flags_string(flr_state));
11312                 goto free_layout;
11313         default:
11314                 break;
11315         }
11316
11317         rc2 = 0;
11318         for (i = 0; i < ids_nr; i++) {
11319                 mirror_id_cbdata.mirror_id = mirror_ids[i];
11320                 mirror_id_cbdata.is_valid_id = false;
11321
11322                 rc = llapi_layout_comp_iterate(layout, compare_mirror_ids,
11323                                                &mirror_id_cbdata);
11324                 if (rc < 0) {
11325                         rc = -errno;
11326                         fprintf(stderr,
11327                                 "%s: '%s' failed to verify mirror id: %u.\n",
11328                                 progname, fname, mirror_ids[i]);
11329                         goto free_layout;
11330                 }
11331
11332                 if (!mirror_id_cbdata.is_valid_id) {
11333                         rc2 = -EINVAL;
11334                         fprintf(stderr,
11335                                 "%s: '%s' invalid specified mirror id: %u.\n",
11336                                 progname, fname, mirror_ids[i]);
11337                 }
11338         }
11339         rc = rc2;
11340
11341 free_layout:
11342         llapi_layout_free(layout);
11343         llapi_lease_release(fd);
11344 close_fd:
11345         close(fd);
11346 error:
11347         return rc;
11348 }
11349
11350 static inline
11351 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
11352                            __u16 *mirror_ids, int ids_nr,
11353                            long stats_interval_sec, long bandwidth_bytes_sec)
11354 {
11355         struct llapi_resync_comp comp_array[1024] = { { 0 } };
11356         struct llapi_layout *layout;
11357         struct stat stbuf;
11358         uint32_t flr_state;
11359         uint64_t start;
11360         uint64_t end;
11361         int comp_size = 0;
11362         int idx;
11363         int fd;
11364         int rc;
11365         int rc2;
11366
11367         if (stat(fname, &stbuf) < 0) {
11368                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
11369                         progname, fname, strerror(errno));
11370                 rc = -errno;
11371                 goto error;
11372         }
11373         if (!S_ISREG(stbuf.st_mode)) {
11374                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
11375                         progname, fname);
11376                 rc = -EINVAL;
11377                 goto error;
11378         }
11379
11380         /* Allow mirror resync even without the key on encrypted files */
11381         fd = open(fname, O_DIRECT | O_RDWR | O_CIPHERTEXT);
11382         if (fd < 0) {
11383                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
11384                         progname, fname, strerror(errno));
11385                 rc = -errno;
11386                 goto error;
11387         }
11388
11389         layout = llapi_layout_get_by_fd(fd, 0);
11390         if (!layout) {
11391                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
11392                         progname, fname, strerror(errno));
11393                 rc = -errno;
11394                 goto close_fd;
11395         }
11396
11397         rc = llapi_layout_flags_get(layout, &flr_state);
11398         if (rc) {
11399                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
11400                         progname, fname, strerror(errno));
11401                 rc = -errno;
11402                 goto free_layout;
11403         }
11404
11405         flr_state &= LCM_FL_FLR_MASK;
11406         if (flr_state == LCM_FL_NONE) {
11407                 rc = -EINVAL;
11408                 fprintf(stderr, "%s: '%s' is not a FLR file.\n",
11409                         progname, fname);
11410                 goto free_layout;
11411         }
11412
11413         /* get stale component info */
11414         comp_size = llapi_mirror_find_stale(layout, comp_array,
11415                                             ARRAY_SIZE(comp_array),
11416                                             mirror_ids, ids_nr);
11417         if (comp_size <= 0) {
11418                 rc = comp_size;
11419                 goto free_layout;
11420         }
11421
11422         ioc->lil_mode = LL_LEASE_WRLCK;
11423         ioc->lil_flags = LL_LEASE_RESYNC;
11424         rc = llapi_lease_set(fd, ioc);
11425         if (rc < 0) {
11426                 if (rc == -EALREADY)
11427                         rc = 0;
11428                 else
11429                         fprintf(stderr,
11430                             "%s: '%s' llapi_lease_get_ext resync failed: %s.\n",
11431                                 progname, fname, strerror(-rc));
11432                 goto free_layout;
11433         }
11434
11435         /* get the read range [start, end) */
11436         start = comp_array[0].lrc_start;
11437         end = comp_array[0].lrc_end;
11438         for (idx = 1; idx < comp_size; idx++) {
11439                 if (comp_array[idx].lrc_start < start)
11440                         start = comp_array[idx].lrc_start;
11441                 if (end < comp_array[idx].lrc_end)
11442                         end = comp_array[idx].lrc_end;
11443         }
11444
11445         rc = llapi_lease_check(fd);
11446         if (rc != LL_LEASE_WRLCK) {
11447                 fprintf(stderr, "%s: '%s' lost lease lock.\n",
11448                         progname, fname);
11449                 goto free_layout;
11450         }
11451
11452         rc = llapi_mirror_resync_many_params(fd, layout, comp_array, comp_size,
11453                                              start, end, stats_interval_sec,
11454                                              bandwidth_bytes_sec);
11455         if (rc < 0)
11456                 fprintf(stderr, "%s: '%s' llapi_mirror_resync_many: %s.\n",
11457                         progname, fname, strerror(-rc));
11458
11459         rc2 = migrate_set_timestamps(fd, &stbuf);
11460         if (rc2 < 0) {
11461                 fprintf(stderr, "%s: '%s' cannot set timestamps: %s\n",
11462                         progname, fname, strerror(-rc2));
11463                 if (!rc)
11464                         rc = rc2;
11465                 goto free_layout;
11466         }
11467
11468         /* need to do the lease unlock even resync fails */
11469         ioc->lil_mode = LL_LEASE_UNLCK;
11470         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
11471         ioc->lil_count = 0;
11472         for (idx = 0; idx < comp_size; idx++) {
11473                 if (comp_array[idx].lrc_synced) {
11474                         ioc->lil_ids[ioc->lil_count] = comp_array[idx].lrc_id;
11475                         ioc->lil_count++;
11476                 }
11477         }
11478
11479         rc2 = llapi_lease_set(fd, ioc);
11480         /**
11481          * llapi_lease_set returns lease mode when it request to unlock
11482          * the lease lock.
11483          */
11484         if (rc2 <= 0) {
11485                 /* rc2 == 0 means lost lease lock */
11486                 if (rc2 == 0 && rc == 0)
11487                         rc = -EBUSY;
11488                 else
11489                         rc = rc2;
11490                 fprintf(stderr, "%s: resync file '%s' failed: %s.\n",
11491                         progname, fname,
11492                         rc2 == 0 ? "lost lease lock" : strerror(-rc2));
11493
11494                 llapi_lease_release(fd);
11495                 goto free_layout;
11496         }
11497
11498 free_layout:
11499         llapi_layout_free(layout);
11500 close_fd:
11501         close(fd);
11502 error:
11503         return rc;
11504 }
11505
11506 static inline int lfs_mirror_resync(int argc, char **argv)
11507 {
11508         struct option long_opts[] = {
11509         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11510         { .val = 'o',   .name = "only",         .has_arg = required_argument },
11511         { .val = 'W',   .name = "bandwidth",    .has_arg = required_argument },
11512         { .val = LFS_STATS_OPT,
11513                         .name = "stats",        .has_arg = no_argument},
11514         { .val = LFS_STATS_INTERVAL_OPT,
11515                         .name = "stats-interval",
11516                                                 .has_arg = required_argument},
11517         { .name = NULL } };
11518         struct ll_ioc_lease *ioc = NULL;
11519         __u16 mirror_ids[128] = { 0 };
11520         unsigned int stats_interval_sec = 0;
11521         unsigned long long bandwidth_bytes_sec = 0;
11522         unsigned long long bandwidth_unit = ONE_MB;
11523         int ids_nr = 0;
11524         int c;
11525         int rc = 0;
11526
11527         while ((c = getopt_long(argc, argv, "ho:W:", long_opts, NULL)) >= 0) {
11528                 char *end;
11529                 switch (c) {
11530                 case 'o':
11531                         rc = parse_mirror_ids(mirror_ids,
11532                                         sizeof(mirror_ids) / sizeof(__u16),
11533                                         optarg);
11534                         if (rc < 0) {
11535                                 fprintf(stderr,
11536                                         "%s: bad mirror ids '%s'.\n",
11537                                         argv[0], optarg);
11538                                 goto error;
11539                         }
11540                         ids_nr = rc;
11541                         break;
11542                 case 'W':
11543                         if (llapi_parse_size(optarg, &bandwidth_bytes_sec,
11544                                              &bandwidth_unit, 0) < 0) {
11545                                 fprintf(stderr,
11546                                         "error: %s: bad value for bandwidth '%s'\n",
11547                                         argv[0], optarg);
11548                                 goto error;
11549                         }
11550                         break;
11551                 case LFS_STATS_OPT:
11552                         stats_interval_sec = 5;
11553                         break;
11554                 case LFS_STATS_INTERVAL_OPT:
11555                         stats_interval_sec = strtol(optarg, &end, 0);
11556                         break;
11557                 default:
11558                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11559                                 progname, argv[optind - 1]);
11560                         fallthrough;
11561                 case 'h':
11562                         rc = CMD_HELP;
11563                         goto error;
11564                 }
11565         }
11566
11567         if (argc == optind) {
11568                 fprintf(stderr, "%s: no file name given.\n", argv[0]);
11569                 rc = CMD_HELP;
11570                 goto error;
11571         }
11572
11573         if (ids_nr > 0 && argc > optind + 1) {
11574                 fprintf(stderr,
11575                     "%s: option '--only' cannot be used upon multiple files.\n",
11576                         argv[0]);
11577                 rc = CMD_HELP;
11578                 goto error;
11579         }
11580
11581         if (ids_nr > 0) {
11582                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
11583                 if (rc < 0)
11584                         goto error;
11585         }
11586
11587         /* set the lease on the file */
11588         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
11589         if (!ioc) {
11590                 fprintf(stderr, "%s: cannot alloc id array for ioc: %s.\n",
11591                         argv[0], strerror(errno));
11592                 rc = -errno;
11593                 goto error;
11594         }
11595
11596         for (; optind < argc; optind++) {
11597                 rc = lfs_mirror_resync_file(argv[optind], ioc,
11598                                             mirror_ids, ids_nr,
11599                                             stats_interval_sec,
11600                                             bandwidth_bytes_sec);
11601                 /* ignore previous file's error, continue with next file */
11602
11603                 /* reset ioc */
11604                 memset(ioc, 0, sizeof(*ioc) + sizeof(__u32) * 4096);
11605         }
11606
11607         free(ioc);
11608 error:
11609         return rc;
11610 }
11611
11612 static inline int verify_mirror_id_by_fd(int fd, __u16 mirror_id)
11613 {
11614         struct llapi_layout *layout;
11615         int rc;
11616
11617         layout = llapi_layout_get_by_fd(fd, 0);
11618         if (!layout) {
11619                 fprintf(stderr, "could not get layout.\n");
11620                 return  -EINVAL;
11621         }
11622
11623         rc = llapi_layout_comp_iterate(layout, find_mirror_id, &mirror_id);
11624         if (rc < 0) {
11625                 fprintf(stderr, "failed to iterate layout\n");
11626                 llapi_layout_free(layout);
11627
11628                 return rc;
11629         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
11630                 fprintf(stderr, "does not find mirror with ID %u\n", mirror_id);
11631                 llapi_layout_free(layout);
11632
11633                 return -EINVAL;
11634         }
11635         llapi_layout_free(layout);
11636
11637         return 0;
11638 }
11639
11640 /**
11641  * Check whether two files are the same file
11642  * \retval      0  same file
11643  * \retval      1  not the same file
11644  * \retval      <0 error code
11645  */
11646 static inline int check_same_file(int fd, const char *f2)
11647 {
11648         struct stat stbuf1;
11649         struct stat stbuf2;
11650
11651         if (fstat(fd, &stbuf1) < 0)
11652                 return -errno;
11653
11654         if (stat(f2, &stbuf2) < 0)
11655                 return 1;
11656
11657         if (stbuf1.st_rdev == stbuf2.st_rdev &&
11658             stbuf1.st_ino == stbuf2.st_ino)
11659                 return 0;
11660
11661         return 1;
11662 }
11663
11664 static inline int lfs_mirror_read(int argc, char **argv)
11665 {
11666         int rc = CMD_HELP;
11667         __u16 mirror_id = 0;
11668         const char *outfile = NULL;
11669         char *fname;
11670         int fd = 0;
11671         int outfd;
11672         int c;
11673         void *buf;
11674         const size_t buflen = 4 << 20;
11675         off_t pos;
11676         struct option long_opts[] = {
11677         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11678         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
11679         { .val = 'o',   .name = "outfile",      .has_arg = required_argument },
11680         { .name = NULL } };
11681
11682         while ((c = getopt_long(argc, argv, "hN:o:", long_opts, NULL)) >= 0) {
11683                 char *end;
11684
11685                 switch (c) {
11686                 case 'N': {
11687                         unsigned long int id;
11688
11689                         errno = 0;
11690                         id = strtoul(optarg, &end, 0);
11691                         if (errno != 0 || *end != '\0' || id == 0 ||
11692                             id > UINT16_MAX) {
11693                                 fprintf(stderr,
11694                                         "%s %s: invalid mirror ID '%s'\n",
11695                                         progname, argv[0], optarg);
11696                                 return rc;
11697                         }
11698
11699                         mirror_id = (__u16)id;
11700                         break;
11701                 }
11702                 case 'o':
11703                         outfile = optarg;
11704                         break;
11705                 default:
11706                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11707                                 progname, argv[optind - 1]);
11708                         fallthrough;
11709                 case 'h':
11710                         return CMD_HELP;
11711                 }
11712         }
11713
11714         if (argc == optind) {
11715                 fprintf(stderr, "%s %s: no mirrored file provided\n",
11716                         progname, argv[0]);
11717                 return rc;
11718         } else if (argc > optind + 1) {
11719                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
11720                 return rc;
11721         }
11722
11723         if (mirror_id == 0) {
11724                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
11725                         progname, argv[0]);
11726                 return rc;
11727         }
11728
11729         /* open mirror file */
11730         fname = argv[optind];
11731         fd = open(fname, O_DIRECT | O_RDONLY);
11732         if (fd < 0) {
11733                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
11734                         progname, argv[0], fname, strerror(errno));
11735                 return rc;
11736         }
11737
11738         /* verify mirror id */
11739         rc = verify_mirror_id_by_fd(fd, mirror_id);
11740         if (rc) {
11741                 fprintf(stderr,
11742                         "%s %s: cannot find mirror with ID %u in '%s'\n",
11743                         progname, argv[0], mirror_id, fname);
11744                 goto close_fd;
11745         }
11746
11747         /* open output file - O_EXCL ensures output is not the same as input */
11748         if (outfile) {
11749                 outfd = open(outfile, O_EXCL | O_WRONLY | O_CREAT, 0644);
11750                 if (outfd < 0) {
11751                         fprintf(stderr, "%s %s: cannot create file '%s': %s\n",
11752                                 progname, argv[0], outfile, strerror(errno));
11753                         rc = -errno;
11754                         goto close_fd;
11755                 }
11756         } else {
11757                 outfd = STDOUT_FILENO;
11758         }
11759
11760         /* allocate buffer */
11761         rc = posix_memalign(&buf, sysconf(_SC_PAGESIZE), buflen);
11762         if (rc) {
11763                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
11764                                 progname, argv[0], rc);
11765                 goto close_outfd;
11766         }
11767
11768         pos = 0;
11769         while (1) {
11770                 ssize_t bytes_read;
11771                 ssize_t written = 0;
11772
11773                 bytes_read = llapi_mirror_read(fd, mirror_id, buf, buflen, pos);
11774                 if (bytes_read < 0) {
11775                         rc = bytes_read;
11776                         fprintf(stderr,
11777                                 "%s %s: fail to read data from mirror %u: %s\n",
11778                                 progname, argv[0], mirror_id, strerror(-rc));
11779                         goto free_buf;
11780                 }
11781
11782                 /* EOF reached */
11783                 if (bytes_read == 0)
11784                         break;
11785
11786                 while (written < bytes_read) {
11787                         ssize_t written2;
11788
11789                         written2 = write(outfd, buf + written,
11790                                          bytes_read - written);
11791                         if (written2 < 0) {
11792                                 fprintf(stderr,
11793                                         "%s %s: fail to write %s: %s\n",
11794                                         progname, argv[0], outfile ? : "STDOUT",
11795                                         strerror(errno));
11796                                 rc = -errno;
11797                                 goto free_buf;
11798                         }
11799                         written += written2;
11800                 }
11801
11802                 if (written != bytes_read) {
11803                         fprintf(stderr,
11804                 "%s %s: written %ld bytes does not match with %ld read.\n",
11805                                 progname, argv[0], written, bytes_read);
11806                         rc = -EIO;
11807                         goto free_buf;
11808                 }
11809
11810                 pos += bytes_read;
11811         }
11812
11813         fsync(outfd);
11814         rc = 0;
11815
11816 free_buf:
11817         free(buf);
11818 close_outfd:
11819         if (outfile)
11820                 close(outfd);
11821 close_fd:
11822         close(fd);
11823
11824         return rc;
11825 }
11826
11827 static inline int lfs_mirror_write(int argc, char **argv)
11828 {
11829         int rc = CMD_HELP;
11830         __u16 mirror_id = 0;
11831         const char *inputfile = NULL;
11832         char *fname;
11833         int fd = 0;
11834         int inputfd;
11835         int c;
11836         void *buf;
11837         const size_t buflen = 4 << 20;
11838         off_t pos;
11839         size_t page_size = sysconf(_SC_PAGESIZE);
11840         struct ll_ioc_lease_id ioc;
11841         struct option long_opts[] = {
11842         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11843         { .val = 'i',   .name = "inputfile",    .has_arg = required_argument },
11844         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
11845         { .name = NULL } };
11846
11847         while ((c = getopt_long(argc, argv, "hi:N:", long_opts, NULL)) >= 0) {
11848                 char *end;
11849
11850                 switch (c) {
11851                 case 'N': {
11852                         unsigned long int id;
11853
11854                         errno = 0;
11855                         id = strtoul(optarg, &end, 0);
11856                         if (errno != 0 || *end != '\0' || id == 0 ||
11857                             id > UINT16_MAX) {
11858                                 fprintf(stderr,
11859                                         "%s %s: invalid mirror ID '%s'\n",
11860                                         progname, argv[0], optarg);
11861                                 return rc;
11862                         }
11863
11864                         mirror_id = (__u16)id;
11865                         break;
11866                 }
11867                 case 'i':
11868                         inputfile = optarg;
11869                         break;
11870                 default:
11871                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11872                                 progname, argv[optind - 1]);
11873                         fallthrough;
11874                 case 'h':
11875                         return CMD_HELP;
11876                 }
11877         }
11878
11879         if (argc == optind) {
11880                 fprintf(stderr, "%s %s: no mirrored file provided\n",
11881                         progname, argv[0]);
11882                 return rc;
11883         } else if (argc > optind + 1) {
11884                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
11885                 return rc;
11886         }
11887
11888         if (mirror_id == 0) {
11889                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
11890                         progname, argv[0]);
11891                 return rc;
11892         }
11893
11894         /* open mirror file */
11895         fname = argv[optind];
11896         fd = open(fname, O_DIRECT | O_WRONLY);
11897         if (fd < 0) {
11898                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
11899                         progname, argv[0], fname, strerror(errno));
11900                 return rc;
11901         }
11902
11903         /* verify mirror id */
11904         rc = verify_mirror_id_by_fd(fd, mirror_id);
11905         if (rc) {
11906                 fprintf(stderr,
11907                         "%s %s: cannot find mirror with ID %u in '%s'\n",
11908                         progname, argv[0], mirror_id, fname);
11909                 goto close_fd;
11910         }
11911
11912         /* open input file */
11913         if (inputfile) {
11914                 rc = check_same_file(fd, inputfile);
11915                 if (rc == 0) {
11916                         fprintf(stderr,
11917                         "%s %s: input file cannot be the mirrored file '%s'\n",
11918                                 progname, argv[0], fname);
11919                         goto close_fd;
11920                 }
11921                 if (rc < 0)
11922                         goto close_fd;
11923
11924                 inputfd = open(inputfile, O_RDONLY, 0644);
11925                 if (inputfd < 0) {
11926                         fprintf(stderr, "%s %s: cannot open file '%s': %s\n",
11927                                 progname, argv[0], inputfile, strerror(errno));
11928                         rc = -errno;
11929                         goto close_fd;
11930                 }
11931         } else {
11932                 inputfd = STDIN_FILENO;
11933         }
11934
11935         /* allocate buffer */
11936         rc = posix_memalign(&buf, page_size, buflen);
11937         if (rc) {
11938                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
11939                         progname, argv[0], rc);
11940                 goto close_inputfd;
11941         }
11942
11943         /* prepare target mirror components instantiation */
11944         ioc.lil_mode = LL_LEASE_WRLCK;
11945         ioc.lil_flags = LL_LEASE_RESYNC;
11946         ioc.lil_mirror_id = mirror_id;
11947         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
11948         if (rc < 0) {
11949                 fprintf(stderr,
11950                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
11951                         progname, argv[0], fname, strerror(errno));
11952                 goto free_buf;
11953         }
11954
11955         pos = 0;
11956         while (1) {
11957                 ssize_t bytes_read;
11958                 ssize_t written;
11959                 size_t to_write;
11960
11961                 rc = llapi_lease_check(fd);
11962                 if (rc != LL_LEASE_WRLCK) {
11963                         fprintf(stderr, "%s %s: '%s' lost lease lock\n",
11964                                 progname, argv[0], fname);
11965                         goto free_buf;
11966                 }
11967
11968                 bytes_read = read(inputfd, buf, buflen);
11969                 if (bytes_read < 0) {
11970                         rc = bytes_read;
11971                         fprintf(stderr,
11972                                 "%s %s: fail to read data from '%s': %s\n",
11973                                 progname, argv[0], inputfile ? : "STDIN",
11974                                 strerror(errno));
11975                         rc = -errno;
11976                         goto free_buf;
11977                 }
11978
11979                 /* EOF reached */
11980                 if (bytes_read == 0)
11981                         break;
11982
11983                 /* round up to page align to make direct IO happy. */
11984                 to_write = (bytes_read + page_size - 1) & ~(page_size - 1);
11985
11986                 written = llapi_mirror_write(fd, mirror_id, buf, to_write,
11987                                              pos);
11988                 if (written < 0) {
11989                         rc = written;
11990                         fprintf(stderr,
11991                               "%s %s: fail to write to mirror %u: %s\n",
11992                                 progname, argv[0], mirror_id,
11993                                 strerror(-rc));
11994                         goto free_buf;
11995                 }
11996
11997                 pos += bytes_read;
11998         }
11999
12000         if (pos & (page_size - 1)) {
12001                 rc = llapi_mirror_truncate(fd, mirror_id, pos);
12002                 if (rc < 0)
12003                         goto free_buf;
12004         }
12005
12006         ioc.lil_mode = LL_LEASE_UNLCK;
12007         ioc.lil_flags = LL_LEASE_RESYNC_DONE;
12008         ioc.lil_count = 0;
12009         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
12010         if (rc <= 0) {
12011                 if (rc == 0)
12012                         rc = -EBUSY;
12013                 fprintf(stderr,
12014                         "%s %s: release lease lock of '%s' failed: %s\n",
12015                         progname, argv[0], fname, strerror(-rc));
12016                 goto free_buf;
12017         }
12018
12019         rc = 0;
12020
12021 free_buf:
12022         free(buf);
12023 close_inputfd:
12024         if (inputfile)
12025                 close(inputfd);
12026 close_fd:
12027         close(fd);
12028
12029         return rc;
12030 }
12031
12032 static inline int get_other_mirror_ids(int fd, __u16 *ids, __u16 exclude_id)
12033 {
12034         struct llapi_layout *layout;
12035         struct collect_ids_data cid = { .cid_ids = ids,
12036                                         .cid_count = 0,
12037                                         .cid_exclude = exclude_id, };
12038         int rc;
12039
12040         layout = llapi_layout_get_by_fd(fd, 0);
12041         if (!layout) {
12042                 fprintf(stderr, "could not get layout\n");
12043                 return -EINVAL;
12044         }
12045
12046         rc = llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
12047         if (rc < 0) {
12048                 fprintf(stderr, "failed to iterate layout\n");
12049                 llapi_layout_free(layout);
12050
12051                 return rc;
12052         }
12053         llapi_layout_free(layout);
12054
12055         return cid.cid_count;
12056 }
12057
12058 #ifndef MIRROR_ID_NEG
12059 #define MIRROR_ID_NEG         0x8000
12060 #endif
12061
12062 static inline int lfs_mirror_copy(int argc, char **argv)
12063 {
12064         int rc = CMD_HELP;
12065         __u16 read_mirror_id = 0;
12066         __u16 ids[128] = { 0 };
12067         int count = 0;
12068         struct llapi_layout *layout = NULL;
12069         struct llapi_resync_comp comp_array[1024] = { { 0 } };
12070         int comp_size = 0;
12071         char *fname;
12072         int fd = 0;
12073         int c;
12074         int i;
12075         ssize_t copied;
12076         struct ll_ioc_lease *ioc = NULL;
12077         struct ll_ioc_lease_id *resync_ioc;
12078         struct option long_opts[] = {
12079         { .val = 'h',   .name = "help",         .has_arg = no_argument },
12080         { .val = 'i',   .name = "read-mirror",  .has_arg = required_argument },
12081         { .val = 'o',   .name = "write-mirror", .has_arg = required_argument },
12082         { .name = NULL } };
12083         char cmd[PATH_MAX];
12084
12085         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12086         progname = cmd;
12087         while ((c = getopt_long(argc, argv, "hi:o:", long_opts, NULL)) >= 0) {
12088                 char *end;
12089
12090                 switch (c) {
12091                 case 'i': {
12092                         unsigned long int id;
12093
12094                         errno = 0;
12095                         id = strtoul(optarg, &end, 0);
12096                         if (errno != 0 || *end != '\0' || id == 0 ||
12097                             id > UINT16_MAX) {
12098                                 fprintf(stderr,
12099                                         "%s: invalid read mirror ID '%s'\n",
12100                                         progname, optarg);
12101                                 return rc;
12102                         }
12103
12104                         read_mirror_id = (__u16)id;
12105                         break;
12106                 }
12107                 case 'o':
12108                         if (!strcmp(optarg, "-1")) {
12109                                 /* specify all other mirrors */
12110                                 ids[0] = (__u16)-1;
12111                                 count = 1;
12112                         } else {
12113                                 count = parse_mirror_ids((__u16 *)ids,
12114                                                          ARRAY_SIZE(ids),
12115                                                          optarg);
12116                                 if (count < 0)
12117                                         return rc;
12118                         }
12119                         break;
12120                 default:
12121                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12122                                 progname, argv[optind - 1]);
12123                         fallthrough;
12124                 case 'h':
12125                         return CMD_HELP;
12126                 }
12127         }
12128
12129         if (argc == optind) {
12130                 fprintf(stderr, "%s %s: no mirrored file provided\n",
12131                         progname, argv[0]);
12132                 return rc;
12133         } else if (argc > optind + 1) {
12134                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
12135                 return rc;
12136         }
12137
12138         if (read_mirror_id == 0) {
12139                 fprintf(stderr,
12140                         "%s %s: no valid read mirror ID %d is provided\n",
12141                         progname, argv[0], read_mirror_id);
12142                 return rc;
12143         }
12144
12145         if (count == 0) {
12146                 fprintf(stderr,
12147                         "%s %s: no write mirror ID is provided\n",
12148                         progname, argv[0]);
12149                 return rc;
12150         }
12151
12152         for (i = 0; i < count; i++) {
12153                 if (read_mirror_id == ids[i]) {
12154                         fprintf(stderr,
12155                         "%s %s: read and write mirror ID cannot be the same\n",
12156                                 progname, argv[0]);
12157                         return rc;
12158                 }
12159         }
12160
12161         /* open mirror file */
12162         fname = argv[optind];
12163
12164         fd = open(fname, O_DIRECT | O_RDWR);
12165         if (fd < 0) {
12166                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
12167                         progname, argv[0], fname, strerror(errno));
12168                 return rc;
12169         }
12170
12171         /* write to all other mirrors */
12172         if (ids[0] == (__u16)-1) {
12173                 count = get_other_mirror_ids(fd, ids, read_mirror_id);
12174                 if (count <= 0) {
12175                         rc = count;
12176                         fprintf(stderr,
12177                         "%s %s: failed to get other mirror ids in '%s': %d\n",
12178                                 progname, argv[0], fname, rc);
12179                         goto close_fd;
12180                 }
12181         }
12182
12183         /* verify mirror id */
12184         rc = verify_mirror_id_by_fd(fd, read_mirror_id);
12185         if (rc) {
12186                 fprintf(stderr,
12187                         "%s %s: cannot find mirror with ID %u in '%s'\n",
12188                         progname, argv[0], read_mirror_id, fname);
12189                 goto close_fd;
12190         }
12191
12192         for (i = 0; i < count; i++) {
12193                 rc = verify_mirror_id_by_fd(fd, ids[i]);
12194                 if (rc) {
12195                         fprintf(stderr,
12196                         "%s %s: cannot find mirror with ID %u in '%s'\n",
12197                                 progname, argv[0], ids[i], fname);
12198                         goto close_fd;
12199                 }
12200         }
12201
12202         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
12203         if (!ioc) {
12204                 fprintf(stderr,
12205                         "%s %s: cannot alloc comp id array for ioc: %s\n",
12206                         progname, argv[0], strerror(errno));
12207                 rc = -errno;
12208                 goto close_fd;
12209         }
12210
12211         /* get stale component info */
12212         layout = llapi_layout_get_by_fd(fd, 0);
12213         if (!layout) {
12214                 fprintf(stderr, "%s %s: failed to get layout of '%s': %s\n",
12215                         progname, argv[0], fname, strerror(errno));
12216                 rc = -errno;
12217                 goto free_ioc;
12218         }
12219         comp_size = llapi_mirror_find_stale(layout, comp_array,
12220                                             ARRAY_SIZE(comp_array),
12221                                             ids, count);
12222         llapi_layout_free(layout);
12223         if (comp_size < 0) {
12224                 rc = comp_size;
12225                 goto free_ioc;
12226         }
12227
12228         /* prepare target mirror components instantiation */
12229         resync_ioc = (struct ll_ioc_lease_id *)ioc;
12230         resync_ioc->lil_mode = LL_LEASE_WRLCK;
12231         resync_ioc->lil_flags = LL_LEASE_RESYNC;
12232         if (count == 1)
12233                 resync_ioc->lil_mirror_id = ids[0];
12234         else
12235                 resync_ioc->lil_mirror_id = read_mirror_id | MIRROR_ID_NEG;
12236         rc = llapi_lease_set(fd, ioc);
12237         if (rc < 0) {
12238                 fprintf(stderr,
12239                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
12240                         progname, argv[0], fname, strerror(errno));
12241                 goto free_ioc;
12242         }
12243
12244         copied = llapi_mirror_copy_many(fd, read_mirror_id, ids, count);
12245         if (copied < 0) {
12246                 rc = copied;
12247                 fprintf(stderr, "%s %s: copy error: %d\n",
12248                         progname, argv[0], rc);
12249                 goto free_ioc;
12250         }
12251
12252         fprintf(stdout, "mirror copied successfully: ");
12253         for (i = 0; i < copied; i++)
12254                 fprintf(stdout, "%d ", ids[i]);
12255         fprintf(stdout, "\n");
12256
12257         ioc->lil_mode = LL_LEASE_UNLCK;
12258         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
12259         ioc->lil_count = 0;
12260         for (i = 0; i < comp_size; i++) {
12261                 int j;
12262
12263                 for (j = 0; j < copied; j++) {
12264                         if (comp_array[i].lrc_mirror_id != ids[j])
12265                                 continue;
12266
12267                         ioc->lil_ids[ioc->lil_count] = comp_array[i].lrc_id;
12268                         ioc->lil_count++;
12269                 }
12270         }
12271         rc = llapi_lease_set(fd, ioc);
12272         if (rc <= 0) {
12273                 if (rc == 0)
12274                         rc = -EBUSY;
12275                 fprintf(stderr,
12276                         "%s %s: release lease lock of '%s' failed: %s\n",
12277                         progname, argv[0], fname, strerror(errno));
12278                 goto free_ioc;
12279         }
12280
12281         rc = 0;
12282
12283 free_ioc:
12284         free(ioc);
12285 close_fd:
12286         close(fd);
12287
12288         return rc;
12289 }
12290
12291 /**
12292  * struct verify_chunk - Mirror chunk to be verified.
12293  * @chunk:        [start, end) of the chunk.
12294  * @mirror_count: Number of mirror ids in @mirror_id array.
12295  * @mirror_id:    Array of valid mirror ids that cover the chunk.
12296  */
12297 struct verify_chunk {
12298         struct lu_extent chunk;
12299         unsigned int mirror_count;
12300         __u16 mirror_id[LUSTRE_MIRROR_COUNT_MAX];
12301 };
12302
12303 /**
12304  * print_chunks() - Print chunk information.
12305  * @fname:       Mirrored file name.
12306  * @chunks:      Array of chunks.
12307  * @chunk_count: Number of chunks in @chunks array.
12308  *
12309  * This function prints [start, end) of each chunk in @chunks
12310  * for mirrored file @fname, and also prints the valid mirror ids
12311  * that cover the chunk.
12312  *
12313  * Return: void.
12314  */
12315 static inline
12316 void print_chunks(const char *fname, struct verify_chunk *chunks,
12317                   int chunk_count)
12318 {
12319         int i;
12320         int j;
12321
12322         fprintf(stdout, "Chunks to be verified in %s:\n", fname);
12323         for (i = 0; i < chunk_count; i++) {
12324                 fprintf(stdout, DEXT, PEXT(&chunks[i].chunk));
12325
12326                 if (chunks[i].mirror_count == 0)
12327                         fprintf(stdout, "\t[");
12328                 else {
12329                         fprintf(stdout, "\t[%u", chunks[i].mirror_id[0]);
12330                         for (j = 1; j < chunks[i].mirror_count; j++)
12331                                 fprintf(stdout, ", %u", chunks[i].mirror_id[j]);
12332                 }
12333                 fprintf(stdout, "]\t%u\n", chunks[i].mirror_count);
12334         }
12335         fprintf(stdout, "\n");
12336 }
12337
12338 /**
12339  * print_checksums() - Print CRC-32 checksum values.
12340  * @chunk: A chunk and its corresponding valid mirror ids.
12341  * @crc:   CRC-32 checksum values on the chunk for each valid mirror.
12342  *
12343  * This function prints CRC-32 checksum values on @chunk for
12344  * each valid mirror that covers it.
12345  *
12346  * Return: void.
12347  */
12348 static inline
12349 void print_checksums(struct verify_chunk *chunk, unsigned long *crc,
12350                      unsigned long long pos, unsigned long long len)
12351 {
12352         int i;
12353
12354         fprintf(stdout,
12355                 "CRC-32 checksum value for chunk "DEXT":\n", pos, pos + len);
12356         for (i = 0; i < chunk->mirror_count; i++)
12357                 fprintf(stdout, "Mirror %u:\t%#lx\n",
12358                         chunk->mirror_id[i], crc[i]);
12359         fprintf(stdout, "\n");
12360 }
12361
12362 /**
12363  * filter_mirror_id() - Filter specified mirror ids.
12364  * @chunks:      Array of chunks.
12365  * @chunk_count: Number of chunks in @chunks array.
12366  * @mirror_ids:  Specified mirror ids to be verified.
12367  * @ids_nr:      Number of specified mirror ids.
12368  *
12369  * This function scans valid mirror ids that cover each chunk in @chunks
12370  * and filters specified mirror ids.
12371  *
12372  * Return: void.
12373  */
12374 static inline
12375 void filter_mirror_id(struct verify_chunk *chunks, int chunk_count,
12376                       __u16 *mirror_ids, int ids_nr)
12377 {
12378         int i;
12379         int j;
12380         int k;
12381         __u16 valid_id[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
12382         unsigned int valid_count = 0;
12383
12384         for (i = 0; i < chunk_count; i++) {
12385                 if (chunks[i].mirror_count == 0)
12386                         continue;
12387
12388                 valid_count = 0;
12389                 for (j = 0; j < ids_nr; j++) {
12390                         for (k = 0; k < chunks[i].mirror_count; k++) {
12391                                 if (chunks[i].mirror_id[k] == mirror_ids[j]) {
12392                                         valid_id[valid_count] = mirror_ids[j];
12393                                         valid_count++;
12394                                         break;
12395                                 }
12396                         }
12397                 }
12398
12399                 memcpy(chunks[i].mirror_id, valid_id,
12400                        sizeof(__u16) * valid_count);
12401                 chunks[i].mirror_count = valid_count;
12402         }
12403 }
12404
12405 /**
12406  * lfs_mirror_prepare_chunk() - Find mirror chunks to be verified.
12407  * @layout:      Mirror component list.
12408  * @chunks:      Array of chunks.
12409  * @chunks_size: Array size of @chunks.
12410  *
12411  * This function scans the components in @layout from offset 0 to LUSTRE_EOF
12412  * to find out chunk segments and store them in @chunks array.
12413  *
12414  * The @mirror_id array in each element of @chunks will store the valid
12415  * mirror ids that cover the chunk. If a mirror component covering the
12416  * chunk has LCME_FL_STALE or LCME_FL_OFFLINE flag, then the mirror id
12417  * will not be stored into the @mirror_id array, and the chunk for that
12418  * mirror will not be verified.
12419  *
12420  * The @mirror_count in each element of @chunks will store the number of
12421  * mirror ids in @mirror_id array. If @mirror_count is 0, it indicates the
12422  * chunk is invalid in all of the mirrors. And if @mirror_count is 1, it
12423  * indicates the chunk is valid in only one mirror. In both cases, the
12424  * chunk will not be verified.
12425  *
12426  * Here is an example:
12427  *
12428  *  0      1M     2M     3M     4M           EOF
12429  *  +------+-------------+--------------------+
12430  *  |      |             |      S             |       mirror1
12431  *  +------+------+------+------+-------------+
12432  *  |             |   S  |   S  |             |       mirror2
12433  *  +-------------+------+------+-------------+
12434  *
12435  * prepared @chunks array will contain 5 elements:
12436  * (([0, 1M), [1, 2], 2),
12437  *  ([1M, 2M), [1, 2], 2),
12438  *  ([2M, 3M), [1], 1),
12439  *  ([3M, 4M], [], 0),
12440  *  ([4M, EOF), [2], 1))
12441  *
12442  * Return: the actual array size of @chunks on success
12443  *         or a negative error code on failure.
12444  */
12445 static inline
12446 int lfs_mirror_prepare_chunk(struct llapi_layout *layout,
12447                              struct verify_chunk *chunks,
12448                              size_t chunks_size)
12449 {
12450         uint64_t start;
12451         uint64_t end;
12452         uint32_t mirror_id;
12453         uint32_t flags;
12454         int idx = 0;
12455         int i = 0;
12456         int rc = 0;
12457
12458         memset(chunks, 0, sizeof(*chunks) * chunks_size);
12459
12460         while (1) {
12461                 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
12462                 if (rc < 0) {
12463                         fprintf(stderr,
12464                                 "%s: move to the first layout component: %s.\n",
12465                                 progname, strerror(errno));
12466                         goto error;
12467                 }
12468
12469                 i = 0;
12470                 rc = 0;
12471                 chunks[idx].chunk.e_end = LUSTRE_EOF;
12472                 while (rc == 0) {
12473                         rc = llapi_layout_comp_extent_get(layout, &start, &end);
12474                         if (rc < 0) {
12475                                 fprintf(stderr,
12476                                         "%s: llapi_layout_comp_extent_get failed: %s.\n",
12477                                         progname, strerror(errno));
12478                                 goto error;
12479                         }
12480
12481                         if (start > chunks[idx].chunk.e_start ||
12482                             end <= chunks[idx].chunk.e_start)
12483                                 goto next;
12484
12485                         if (end < chunks[idx].chunk.e_end)
12486                                 chunks[idx].chunk.e_end = end;
12487
12488                         rc = llapi_layout_comp_flags_get(layout, &flags);
12489                         if (rc < 0) {
12490                                 fprintf(stderr,
12491                                         "%s: llapi_layout_comp_flags_get failed: %s.\n",
12492                                         progname, strerror(errno));
12493                                 goto error;
12494                         }
12495
12496                         if (flags & LCME_FL_STALE || flags & LCME_FL_OFFLINE)
12497                                 goto next;
12498
12499                         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
12500                         if (rc < 0) {
12501                                 fprintf(stderr,
12502                                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
12503                                         progname, strerror(errno));
12504                                 goto error;
12505                         }
12506
12507                         if (i >= ARRAY_SIZE(chunks[idx].mirror_id)) {
12508                                 fprintf(stderr,
12509                                         "%s: mirror_id array is too small.\n",
12510                                         progname);
12511                                 rc = -EINVAL;
12512                                 goto error;
12513                         }
12514                         chunks[idx].mirror_id[i] = mirror_id;
12515                         i++;
12516
12517 next:
12518                         rc = llapi_layout_comp_use(layout,
12519                                                    LLAPI_LAYOUT_COMP_USE_NEXT);
12520                         if (rc < 0) {
12521                                 fprintf(stderr,
12522                                         "%s: move to the next layout component: %s.\n",
12523                                         progname, strerror(errno));
12524                                 goto error;
12525                         }
12526                 } /* loop through all components */
12527
12528                 chunks[idx].mirror_count = i;
12529
12530                 if (chunks[idx].chunk.e_end == LUSTRE_EOF)
12531                         break;
12532
12533                 idx++;
12534                 if (idx >= chunks_size) {
12535                         fprintf(stderr, "%s: chunks array is too small.\n",
12536                                 progname);
12537                         rc = -EINVAL;
12538                         goto error;
12539                 }
12540
12541                 chunks[idx].chunk.e_start = chunks[idx - 1].chunk.e_end;
12542         }
12543
12544 error:
12545         return rc < 0 ? rc : idx + 1;
12546 }
12547
12548 /**
12549  * lfs_mirror_verify_chunk() - Verify a chunk.
12550  * @fd:        File descriptor of the mirrored file.
12551  * @file_size: Size of the mirrored file.
12552  * @chunk:     A chunk and its corresponding valid mirror ids.
12553  * @verbose:   Verbose mode.
12554  *
12555  * This function verifies a @chunk contains exactly the same data
12556  * ammong the mirrors that cover it.
12557  *
12558  * If @verbose is specified, then the function will print where the
12559  * differences are if the data do not match. Otherwise, it will
12560  * just return an error in that case.
12561  *
12562  * Return: 0 on success or a negative error code on failure.
12563  */
12564 static inline
12565 int lfs_mirror_verify_chunk(int fd, size_t file_size,
12566                             struct verify_chunk *chunk, int verbose)
12567 {
12568         const size_t buflen = 4 * 1024 * 1024; /* 4M */
12569         void *buf;
12570         size_t page_size = sysconf(_SC_PAGESIZE);
12571         ssize_t bytes_read;
12572         ssize_t bytes_done;
12573         size_t count;
12574         off_t pos;
12575         unsigned long crc;
12576         unsigned long crc_array[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
12577         int i;
12578         int rc = 0;
12579
12580         if (file_size == 0)
12581                 return 0;
12582
12583         rc = posix_memalign(&buf, page_size, buflen);
12584         if (rc) /* error code is returned directly */
12585                 return -rc;
12586
12587         if (verbose > 1) {
12588                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
12589                         PEXT(&chunk->chunk));
12590                 for (i = 0; i < chunk->mirror_count; i++)
12591                         fprintf(stdout, " %u", chunk->mirror_id[i]);
12592                 fprintf(stdout, "\n");
12593         }
12594
12595         bytes_done = 0;
12596         count = MIN(chunk->chunk.e_end, file_size) - chunk->chunk.e_start;
12597         pos = chunk->chunk.e_start;
12598         while (bytes_done < count) {
12599                 /* compute initial CRC-32 checksum */
12600                 crc = crc32(0L, Z_NULL, 0);
12601                 memset(crc_array, 0, sizeof(crc_array));
12602
12603                 bytes_read = 0;
12604                 for (i = 0; i < chunk->mirror_count; i++) {
12605                         bytes_read = llapi_mirror_read(fd, chunk->mirror_id[i],
12606                                                        buf, buflen, pos);
12607                         if (bytes_read < 0) {
12608                                 rc = bytes_read;
12609                                 fprintf(stderr,
12610                                         "%s: failed to read data from mirror %u: %s.\n",
12611                                         progname, chunk->mirror_id[i],
12612                                         strerror(-rc));
12613                                 goto error;
12614                         }
12615
12616                         /* compute new CRC-32 checksum */
12617                         crc_array[i] = crc32(crc, buf, bytes_read);
12618                 }
12619
12620                 if (verbose)
12621                         print_checksums(chunk, crc_array, pos, buflen);
12622
12623                 /* compare CRC-32 checksum values */
12624                 for (i = 1; i < chunk->mirror_count; i++) {
12625                         if (crc_array[i] != crc_array[0]) {
12626                                 rc = -EINVAL;
12627
12628                                 fprintf(stderr,
12629                                         "%s: chunk "DEXT" has different checksum value on mirror %u:%lx and mirror %u:%lx.\n",
12630                                         progname, PEXT(&chunk->chunk),
12631                                         chunk->mirror_id[0], crc_array[0],
12632                                         chunk->mirror_id[i], crc_array[i]);
12633                                 print_checksums(chunk, crc_array, pos, buflen);
12634                         }
12635                 }
12636
12637                 pos += bytes_read;
12638                 bytes_done += bytes_read;
12639         }
12640
12641         if (verbose > 1 && rc == 0) {
12642                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
12643                         PEXT(&chunk->chunk));
12644                 for (i = 0; i < chunk->mirror_count; i++)
12645                         fprintf(stdout, " %u", chunk->mirror_id[i]);
12646                 fprintf(stdout, " PASS\n\n");
12647         }
12648
12649 error:
12650         free(buf);
12651         return rc;
12652 }
12653
12654 /**
12655  * lfs_mirror_verify_file() - Verify a mirrored file.
12656  * @fname:      Mirrored file name.
12657  * @mirror_ids: Specified mirror ids to be verified.
12658  * @ids_nr:     Number of specified mirror ids.
12659  * @verbose:    Verbose mode.
12660  *
12661  * This function verifies that each SYNC mirror of a mirrored file
12662  * specified by @fname contains exactly the same data.
12663  *
12664  * If @mirror_ids is specified, then the function will verify the
12665  * mirrors specified by @mirror_ids contain exactly the same data.
12666  *
12667  * If @verbose is specified, then the function will print where the
12668  * differences are if the data do not match. Otherwise, it will
12669  * just return an error in that case.
12670  *
12671  * Return: 0 on success or a negative error code on failure.
12672  */
12673 static inline
12674 int lfs_mirror_verify_file(const char *fname, __u16 *mirror_ids, int ids_nr,
12675                            int verbose)
12676 {
12677         struct verify_chunk chunks_array[1024] = { };
12678         struct llapi_layout *layout = NULL;
12679         struct stat stbuf;
12680         uint32_t flr_state;
12681         int fd;
12682         int chunk_count = 0;
12683         int idx = 0;
12684         int rc = 0;
12685         int rc1 = 0;
12686         int rc2 = 0;
12687
12688         if (stat(fname, &stbuf) < 0) {
12689                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
12690                         progname, fname, strerror(errno));
12691                 rc = -errno;
12692                 goto error;
12693         }
12694
12695         if (!S_ISREG(stbuf.st_mode)) {
12696                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
12697                         progname, fname);
12698                 rc = -EINVAL;
12699                 goto error;
12700         }
12701
12702         if (stbuf.st_size == 0) {
12703                 if (verbose)
12704                         fprintf(stdout, "%s: '%s' file size is 0.\n",
12705                                 progname, fname);
12706                 rc = 0;
12707                 goto error;
12708         }
12709
12710         /* Allow mirror verify even without the key on encrypted files */
12711         fd = open(fname, O_DIRECT | O_RDONLY | O_CIPHERTEXT);
12712         if (fd < 0) {
12713                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
12714                         progname, fname, strerror(errno));
12715                 rc = -errno;
12716                 goto error;
12717         }
12718
12719         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
12720         if (rc < 0) {
12721                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
12722                         progname, fname, strerror(errno));
12723                 goto close_fd;
12724         }
12725
12726         layout = llapi_layout_get_by_fd(fd, 0);
12727         if (!layout) {
12728                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
12729                         progname, fname, strerror(errno));
12730                 rc = -errno;
12731                 llapi_lease_release(fd);
12732                 goto close_fd;
12733         }
12734
12735         rc = llapi_layout_flags_get(layout, &flr_state);
12736         if (rc < 0) {
12737                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
12738                         progname, fname, strerror(errno));
12739                 rc = -errno;
12740                 goto free_layout;
12741         }
12742
12743         flr_state &= LCM_FL_FLR_MASK;
12744         switch (flr_state) {
12745         case LCM_FL_NONE:
12746                 rc = -EINVAL;
12747                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
12748                         progname, fname, llapi_layout_flags_string(flr_state));
12749                 goto free_layout;
12750         default:
12751                 break;
12752         }
12753
12754         /* find out mirror chunks to be verified */
12755         chunk_count = lfs_mirror_prepare_chunk(layout, chunks_array,
12756                                                ARRAY_SIZE(chunks_array));
12757         if (chunk_count < 0) {
12758                 rc = chunk_count;
12759                 goto free_layout;
12760         }
12761
12762         if (ids_nr > 0)
12763                 /* filter specified mirror ids */
12764                 filter_mirror_id(chunks_array, chunk_count, mirror_ids, ids_nr);
12765
12766         if (verbose > 2)
12767                 print_chunks(fname, chunks_array, chunk_count);
12768
12769         for (idx = 0; idx < chunk_count; idx++) {
12770                 if (chunks_array[idx].chunk.e_start >= stbuf.st_size) {
12771                         if (verbose)
12772                                 fprintf(stdout,
12773                                         "%s: '%s' chunk "DEXT" exceeds file size %#llx: skipped\n",
12774                                         progname, fname,
12775                                         PEXT(&chunks_array[idx].chunk),
12776                                         (unsigned long long)stbuf.st_size);
12777                         break;
12778                 }
12779
12780                 if (chunks_array[idx].mirror_count == 0) {
12781                         fprintf(stderr,
12782                                 "%s: '%s' chunk "DEXT" is invalid in all of the mirrors: ",
12783                                 progname, fname,
12784                                 PEXT(&chunks_array[idx].chunk));
12785                         if (verbose) {
12786                                 fprintf(stderr, "skipped\n");
12787                                 continue;
12788                         }
12789                         rc = -EINVAL;
12790                         fprintf(stderr, "failed\n");
12791                         goto free_layout;
12792                 }
12793
12794                 if (chunks_array[idx].mirror_count == 1) {
12795                         if (verbose)
12796                                 fprintf(stdout,
12797                                         "%s: '%s' chunk "DEXT" is only valid in mirror %u: skipped\n",
12798                                         progname, fname,
12799                                         PEXT(&chunks_array[idx].chunk),
12800                                         chunks_array[idx].mirror_id[0]);
12801                         continue;
12802                 }
12803
12804                 rc = llapi_lease_check(fd);
12805                 if (rc != LL_LEASE_RDLCK) {
12806                         fprintf(stderr, "%s: '%s' lost lease lock.\n",
12807                                 progname, fname);
12808                         goto free_layout;
12809                 }
12810
12811                 /* verify one chunk */
12812                 rc1 = lfs_mirror_verify_chunk(fd, stbuf.st_size,
12813                                               &chunks_array[idx], verbose);
12814                 if (rc1 < 0) {
12815                         rc2 = rc1;
12816                         if (!verbose) {
12817                                 rc = rc1;
12818                                 goto free_layout;
12819                         }
12820                 }
12821         }
12822
12823         if (rc2 < 0)
12824                 rc = rc2;
12825
12826 free_layout:
12827         llapi_layout_free(layout);
12828         llapi_lease_release(fd);
12829 close_fd:
12830         close(fd);
12831 error:
12832         return rc;
12833 }
12834
12835 /**
12836  * lfs_mirror_verify() - Parse and execute lfs mirror verify command.
12837  * @argc: The count of lfs mirror verify command line arguments.
12838  * @argv: Array of strings for lfs mirror verify command line arguments.
12839  *
12840  * This function parses lfs mirror verify command and verifies the
12841  * specified mirrored file(s).
12842  *
12843  * Return: 0 on success or a negative error code on failure.
12844  */
12845 static inline int lfs_mirror_verify(int argc, char **argv)
12846 {
12847         __u16 mirror_ids[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
12848         int ids_nr = 0;
12849         int c;
12850         int verbose = 0;
12851         int rc = 0;
12852         int rc1 = 0;
12853         char cmd[PATH_MAX];
12854
12855         struct option long_opts[] = {
12856         { .val = 'h',   .name = "help",         .has_arg = no_argument },
12857         { .val = 'o',   .name = "only",         .has_arg = required_argument },
12858         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
12859         { .name = NULL } };
12860
12861         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12862         progname = cmd;
12863         while ((c = getopt_long(argc, argv, "ho:v", long_opts, NULL)) >= 0) {
12864                 switch (c) {
12865                 case 'o':
12866                         rc = parse_mirror_ids(mirror_ids,
12867                                               ARRAY_SIZE(mirror_ids),
12868                                               optarg);
12869                         if (rc < 0) {
12870                                 fprintf(stderr,
12871                                         "%s: bad mirror ids '%s'.\n",
12872                                         progname, optarg);
12873                                 goto error;
12874                         }
12875                         ids_nr = rc;
12876                         if (ids_nr < 2) {
12877                                 fprintf(stderr,
12878                                         "%s: at least 2 mirror ids needed with '--only' option.\n",
12879                                         progname);
12880                                 rc = CMD_HELP;
12881                                 goto error;
12882                         }
12883                         break;
12884                 case 'v':
12885                         verbose++;
12886                         break;
12887                 default:
12888                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12889                                 progname, argv[optind - 1]);
12890                         fallthrough;
12891                 case 'h':
12892                         rc = CMD_HELP;
12893                         goto error;
12894                 }
12895         }
12896
12897         if (argc == optind) {
12898                 fprintf(stderr, "%s: no file name given.\n", progname);
12899                 rc = CMD_HELP;
12900                 goto error;
12901         }
12902
12903         if (ids_nr > 0 && argc > optind + 1) {
12904                 fprintf(stderr,
12905                         "%s: '--only' cannot be used upon multiple files.\n",
12906                         progname);
12907                 rc = CMD_HELP;
12908                 goto error;
12909         }
12910
12911         if (ids_nr > 0) {
12912                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
12913                 if (rc < 0)
12914                         goto error;
12915         }
12916
12917         rc = 0;
12918         for (; optind < argc; optind++) {
12919                 rc1 = lfs_mirror_verify_file(argv[optind], mirror_ids, ids_nr,
12920                                              verbose);
12921                 if (rc1 < 0)
12922                         rc = rc1;
12923         }
12924 error:
12925         return rc;
12926 }
12927
12928 /**
12929  * lfs_mirror() - Parse and execute lfs mirror commands.
12930  * @argc: The count of lfs mirror command line arguments.
12931  * @argv: Array of strings for lfs mirror command line arguments.
12932  *
12933  * This function parses lfs mirror commands and performs the
12934  * corresponding functions specified in mirror_cmdlist[].
12935  *
12936  * Return: 0 on success or an error code on failure.
12937  */
12938 static int lfs_mirror(int argc, char **argv)
12939 {
12940         char cmd[PATH_MAX];
12941         int rc = 0;
12942
12943         setlinebuf(stdout);
12944
12945         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12946         progname = cmd;
12947         program_invocation_short_name = cmd;
12948         rc = cfs_parser(argc, argv, mirror_cmdlist);
12949
12950         return rc < 0 ? -rc : rc;
12951 }
12952
12953 static void lustre_som_swab(struct lustre_som_attrs *attrs)
12954 {
12955 #if __BYTE_ORDER == __BIG_ENDIAN
12956         __swab16s(&attrs->lsa_valid);
12957         __swab64s(&attrs->lsa_size);
12958         __swab64s(&attrs->lsa_blocks);
12959 #endif
12960 }
12961
12962 enum lfs_som_type {
12963         LFS_SOM_SIZE = 0x1,
12964         LFS_SOM_BLOCKS = 0x2,
12965         LFS_SOM_FLAGS = 0x4,
12966         LFS_SOM_ATTR_ALL = LFS_SOM_SIZE | LFS_SOM_BLOCKS |
12967                            LFS_SOM_FLAGS,
12968 };
12969
12970 static int lfs_getsom(int argc, char **argv)
12971 {
12972         const char *path;
12973         struct lustre_som_attrs *attrs;
12974         char buf[sizeof(*attrs) + 64];
12975         enum lfs_som_type type = LFS_SOM_ATTR_ALL;
12976         int rc = 0, c;
12977
12978         while ((c = getopt(argc, argv, "bfhs")) != -1) {
12979                 switch (c) {
12980                 case 'b':
12981                         type = LFS_SOM_BLOCKS;
12982                         break;
12983                 case 'f':
12984                         type = LFS_SOM_FLAGS;
12985                         break;
12986                 case 's':
12987                         type = LFS_SOM_SIZE;
12988                         break;
12989                 default:
12990                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12991                                 progname, argv[optind - 1]);
12992                         fallthrough;
12993                 case 'h':
12994                         return CMD_HELP;
12995                 }
12996         }
12997
12998         argc -= optind;
12999         argv += optind;
13000
13001         if (argc != 1) {
13002                 fprintf(stderr, "%s: %s\n",
13003                         progname, argc == 0 ? "miss file target" :
13004                         "input more than 2 files");
13005                 return CMD_HELP;
13006         }
13007
13008         path = argv[0];
13009         attrs = (void *)buf;
13010         rc = lgetxattr(path, "trusted.som", attrs, sizeof(buf));
13011         if (rc < 0) {
13012                 rc = -errno;
13013                 fprintf(stderr, "%s failed to get som xattr: %s (%d)\n",
13014                         argv[0], strerror(errno), errno);
13015                 return rc;
13016         }
13017
13018         lustre_som_swab(attrs);
13019
13020         switch (type) {
13021         case LFS_SOM_ATTR_ALL:
13022                 printf("file: %s size: %llu blocks: %llu flags: %x\n",
13023                        path, (unsigned long long)attrs->lsa_size,
13024                        (unsigned long long)attrs->lsa_blocks,
13025                        attrs->lsa_valid);
13026                 break;
13027         case LFS_SOM_SIZE:
13028                 printf("%llu\n", (unsigned long long)attrs->lsa_size);
13029                 break;
13030         case LFS_SOM_BLOCKS:
13031                 printf("%llu\n", (unsigned long long)attrs->lsa_blocks);
13032                 break;
13033         case LFS_SOM_FLAGS:
13034                 printf("%x\n", attrs->lsa_valid);
13035                 break;
13036         default:
13037                 fprintf(stderr, "%s: unknown option\n", progname);
13038                 return CMD_HELP;
13039         }
13040
13041         return 0;
13042 }
13043
13044 static int lfs_pcc_attach(int argc, char **argv)
13045 {
13046         struct option long_opts[] = {
13047         { .val = 'h',   .name = "help", .has_arg = no_argument },
13048         { .val = 'i',   .name = "id",   .has_arg = required_argument },
13049         { .name = NULL } };
13050         int c;
13051         int rc = 0;
13052         __u32 archive_id = 0;
13053         const char *path;
13054         char *end;
13055         char fullpath[PATH_MAX];
13056         enum lu_pcc_type type = LU_PCC_READWRITE;
13057
13058         optind = 0;
13059         while ((c = getopt_long(argc, argv, "hi:",
13060                                 long_opts, NULL)) != -1) {
13061                 switch (c) {
13062                 case 'i':
13063                         errno = 0;
13064                         archive_id = strtoul(optarg, &end, 0);
13065                         if (errno != 0 || *end != '\0' ||
13066                             archive_id == 0 || archive_id > UINT32_MAX) {
13067                                 fprintf(stderr,
13068                                         "error: %s: bad archive ID '%s'\n",
13069                                         progname, optarg);
13070                                 return CMD_HELP;
13071                         }
13072                         break;
13073                 default:
13074                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13075                                 progname, argv[optind - 1]);
13076                         fallthrough;
13077                 case 'h':
13078                         return CMD_HELP;
13079                 }
13080         }
13081
13082         if (archive_id == 0) {
13083                 fprintf(stderr, "%s: must specify attach ID\n", argv[0]);
13084                 return CMD_HELP;
13085         }
13086
13087         if (argc <= optind) {
13088                 fprintf(stderr, "%s: must specify one or more file names\n",
13089                         argv[0]);
13090                 return CMD_HELP;
13091         }
13092
13093         while (optind < argc) {
13094                 int rc2;
13095
13096                 path = argv[optind++];
13097                 if (!realpath(path, fullpath)) {
13098                         fprintf(stderr, "%s: could not find path '%s': %s\n",
13099                                 argv[0], path, strerror(errno));
13100                         if (rc == 0)
13101                                 rc = -EINVAL;
13102                         continue;
13103                 }
13104
13105                 rc2 = llapi_pcc_attach(fullpath, archive_id, type);
13106                 if (rc2 < 0) {
13107                         fprintf(stderr,
13108                                 "%s: cannot attach '%s' to PCC with archive ID '%u': %s\n",
13109                                 argv[0], path, archive_id, strerror(-rc2));
13110                         if (rc == 0)
13111                                 rc = rc2;
13112                 }
13113         }
13114         return rc;
13115 }
13116
13117 static int lfs_pcc_attach_fid(int argc, char **argv)
13118 {
13119         struct option long_opts[] = {
13120         { .val = 'h',   .name = "help", .has_arg = no_argument },
13121         { .val = 'i',   .name = "id",   .has_arg = required_argument },
13122         { .val = 'm',   .name = "mnt",  .has_arg = required_argument },
13123         { .name = NULL } };
13124         int c;
13125         int rc = 0;
13126         __u32 archive_id = 0;
13127         char *end;
13128         const char *mntpath = NULL;
13129         const char *fidstr;
13130         enum lu_pcc_type type = LU_PCC_READWRITE;
13131
13132         optind = 0;
13133         while ((c = getopt_long(argc, argv, "hi:m:",
13134                                 long_opts, NULL)) != -1) {
13135                 switch (c) {
13136                 case 'i':
13137                         errno = 0;
13138                         archive_id = strtoul(optarg, &end, 0);
13139                         if (errno != 0 || *end != '\0' ||
13140                             archive_id > UINT32_MAX) {
13141                                 fprintf(stderr,
13142                                         "error: %s: bad archive ID '%s'\n",
13143                                         argv[0], optarg);
13144                                 return CMD_HELP;
13145                         }
13146                         break;
13147                 case 'm':
13148                         mntpath = optarg;
13149                         break;
13150                 default:
13151                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13152                                 progname, argv[optind - 1]);
13153                         fallthrough;
13154                 case 'h':
13155                         return CMD_HELP;
13156                 }
13157         }
13158
13159         if (archive_id == 0) {
13160                 fprintf(stderr, "%s: must specify an archive ID\n", argv[0]);
13161                 return CMD_HELP;
13162         }
13163
13164         if (!mntpath) {
13165                 fprintf(stderr, "%s: must specify Lustre mount point\n",
13166                         argv[0]);
13167                 return CMD_HELP;
13168         }
13169
13170         if (argc <= optind) {
13171                 fprintf(stderr, "%s: must specify one or more fids\n", argv[0]);
13172                 return CMD_HELP;
13173         }
13174
13175         while (optind < argc) {
13176                 int rc2;
13177
13178                 fidstr = argv[optind++];
13179
13180                 rc2 = llapi_pcc_attach_fid_str(mntpath, fidstr,
13181                                                archive_id, type);
13182                 if (rc2 < 0) {
13183                         fprintf(stderr,
13184                                 "%s: cannot attach '%s' on '%s' to PCC with archive ID '%u': %s\n",
13185                                 argv[0], fidstr, mntpath, archive_id,
13186                                 strerror(rc2));
13187                 }
13188                 if (rc == 0 && rc2 < 0)
13189                         rc = rc2;
13190         }
13191         return rc;
13192 }
13193
13194 static int lfs_pcc_detach(int argc, char **argv)
13195 {
13196         struct option long_opts[] = {
13197         { .val = 'h',   .name = "help", .has_arg = no_argument },
13198         { .val = 'k',   .name = "keep", .has_arg = no_argument },
13199         { .name = NULL } };
13200         int c;
13201         int rc = 0;
13202         const char *path;
13203         char fullpath[PATH_MAX];
13204         __u32 detach_opt = PCC_DETACH_OPT_UNCACHE;
13205
13206         optind = 0;
13207         while ((c = getopt_long(argc, argv, "hk",
13208                                 long_opts, NULL)) != -1) {
13209                 switch (c) {
13210                 case 'k':
13211                         detach_opt = PCC_DETACH_OPT_NONE;
13212                         break;
13213                 default:
13214                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13215                                 progname, argv[optind - 1]);
13216                         fallthrough;
13217                 case 'h':
13218                         return CMD_HELP;
13219                 }
13220         }
13221
13222         while (optind < argc) {
13223                 int rc2;
13224
13225                 path = argv[optind++];
13226                 if (!realpath(path, fullpath)) {
13227                         fprintf(stderr, "%s: could not find path '%s': %s\n",
13228                                 argv[0], path, strerror(errno));
13229                         if (rc == 0)
13230                                 rc = -EINVAL;
13231                         continue;
13232                 }
13233
13234                 rc2 = llapi_pcc_detach_file(fullpath, detach_opt);
13235                 if (rc2 < 0) {
13236                         rc2 = -errno;
13237                         fprintf(stderr,
13238                                 "%s: cannot detach '%s' from PCC: %s\n",
13239                                 argv[0], path, strerror(errno));
13240                         if (rc == 0)
13241                                 rc = rc2;
13242                 }
13243         }
13244         return rc;
13245 }
13246
13247 static int lfs_pcc_detach_fid(int argc, char **argv)
13248 {
13249         struct option long_opts[] = {
13250         { .val = 'h',   .name = "help", .has_arg = no_argument },
13251         { .val = 'k',   .name = "keep", .has_arg = no_argument },
13252         { .name = NULL } };
13253         int c;
13254         int rc = 0;
13255         const char *fid;
13256         const char *mntpath;
13257         __u32 detach_opt = PCC_DETACH_OPT_UNCACHE;
13258
13259         optind = 0;
13260         while ((c = getopt_long(argc, argv, "hk",
13261                                 long_opts, NULL)) != -1) {
13262                 switch (c) {
13263                 case 'k':
13264                         detach_opt = PCC_DETACH_OPT_NONE;
13265                         break;
13266                 default:
13267                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13268                                 progname, argv[optind - 1]);
13269                         fallthrough;
13270                 case 'h':
13271                         return CMD_HELP;
13272                 }
13273         }
13274
13275         mntpath = argv[optind++];
13276
13277         while (optind < argc) {
13278                 int rc2;
13279
13280                 fid = argv[optind++];
13281
13282                 rc2 = llapi_pcc_detach_fid_str(mntpath, fid, detach_opt);
13283                 if (rc2 < 0) {
13284                         fprintf(stderr,
13285                                 "%s: cannot detach '%s' on '%s' from PCC: %s\n",
13286                                 argv[0], fid, mntpath, strerror(-rc2));
13287                         if (rc == 0)
13288                                 rc = rc2;
13289                 }
13290         }
13291         return rc;
13292 }
13293
13294 static int lfs_pcc_state(int argc, char **argv)
13295 {
13296         int rc = 0;
13297         const char *path;
13298         char fullpath[PATH_MAX];
13299         struct lu_pcc_state state;
13300
13301         optind = 1;
13302
13303         if (argc <= 1) {
13304                 fprintf(stderr, "%s: must specify one or more file names\n",
13305                         progname);
13306                 return CMD_HELP;
13307         }
13308
13309         while (optind < argc) {
13310                 int rc2;
13311
13312                 path = argv[optind++];
13313                 if (!realpath(path, fullpath)) {
13314                         fprintf(stderr, "%s: could not find path '%s': %s\n",
13315                                 argv[0], path, strerror(errno));
13316                         if (rc == 0)
13317                                 rc = -EINVAL;
13318                         continue;
13319                 }
13320
13321                 rc2 = llapi_pcc_state_get(fullpath, &state);
13322                 if (rc2 < 0) {
13323                         if (rc == 0)
13324                                 rc = rc2;
13325                         fprintf(stderr,
13326                                 "%s: cannot get PCC state of '%s': %s\n",
13327                                 argv[0], path, strerror(-rc2));
13328                         continue;
13329                 }
13330
13331                 printf("file: %s", path);
13332                 printf(", type: %s", pcc_type2string(state.pccs_type));
13333                 if (state.pccs_type == LU_PCC_NONE &&
13334                     state.pccs_open_count == 0) {
13335                         printf("\n");
13336                         continue;
13337                 }
13338
13339                 printf(", PCC file: %s", state.pccs_path);
13340                 printf(", user number: %u", state.pccs_open_count);
13341                 printf(", flags: %x", state.pccs_flags);
13342                 printf("\n");
13343         }
13344         return rc;
13345 }
13346
13347 /**
13348  * lfs_pcc() - Parse and execute lfs pcc commands.
13349  * @argc: The count of lfs pcc command line arguments.
13350  * @argv: Array of strings for lfs pcc command line arguments.
13351  *
13352  * This function parses lfs pcc commands and performs the
13353  * corresponding functions specified in pcc_cmdlist[].
13354  *
13355  * Return: 0 on success or an error code on failure.
13356  */
13357 static int lfs_pcc(int argc, char **argv)
13358 {
13359         char cmd[PATH_MAX];
13360         int rc = 0;
13361
13362         setlinebuf(stdout);
13363
13364         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
13365         progname = cmd;
13366         program_invocation_short_name = cmd;
13367         rc = cfs_parser(argc, argv, pcc_cmdlist);
13368
13369         return rc < 0 ? -rc : rc;
13370 }
13371
13372 int main(int argc, char **argv)
13373 {
13374         int rc;
13375
13376         /* Ensure that liblustreapi constructor has run */
13377         if (!llapi_liblustreapi_initialized())
13378                 fprintf(stderr, "liblustreapi was not properly initialized\n");
13379
13380         setlinebuf(stdout);
13381         opterr = 0;
13382
13383         progname = program_invocation_short_name; /* Used in error messages */
13384         llapi_set_command_name(argv[1]);
13385         rc = cfs_parser(argc, argv, cmdlist);
13386         llapi_clear_command_name();
13387
13388         return rc < 0 ? -rc : rc;
13389 }