Whamcloud - gitweb
LU-17662 osd-zfs: Support for ZFS 2.2.3
[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 #include "callvpe.h"
82
83 #ifndef NSEC_PER_SEC
84 # define NSEC_PER_SEC 1000000000UL
85 #endif
86 #define ONE_MB 0x100000
87
88 /* all functions */
89 static int lfs_find(int argc, char **argv);
90 static int lfs_getstripe(int argc, char **argv);
91 static int lfs_getdirstripe(int argc, char **argv);
92 static int lfs_setdirstripe(int argc, char **argv);
93 static int lfs_rmentry(int argc, char **argv);
94 static int lfs_unlink_foreign(int argc, char **argv);
95 static int lfs_osts(int argc, char **argv);
96 static int lfs_mdts(int argc, char **argv);
97 static int lfs_df(int argc, char **argv);
98 static int lfs_getname(int argc, char **argv);
99 static int lfs_check(int argc, char **argv);
100 #ifdef HAVE_SYS_QUOTA_H
101 static int lfs_setquota(int argc, char **argv);
102 static int lfs_quota(int argc, char **argv);
103 static int lfs_project(int argc, char **argv);
104 #endif
105 static int lfs_flushctx(int argc, char **argv);
106 static int lfs_poollist(int argc, char **argv);
107 static int lfs_changelog(int argc, char **argv);
108 static int lfs_changelog_clear(int argc, char **argv);
109 static int lfs_fid2path(int argc, char **argv);
110 static int lfs_path2fid(int argc, char **argv);
111 static int lfs_rmfid(int argc, char **argv);
112 static int lfs_data_version(int argc, char **argv);
113 static int lfs_hsm_state(int argc, char **argv);
114 static int lfs_hsm_set(int argc, char **argv);
115 static int lfs_hsm_clear(int argc, char **argv);
116 static int lfs_hsm_action(int argc, char **argv);
117 static int lfs_hsm_archive(int argc, char **argv);
118 static int lfs_hsm_restore(int argc, char **argv);
119 static int lfs_hsm_release(int argc, char **argv);
120 static int lfs_hsm_remove(int argc, char **argv);
121 static int lfs_hsm_cancel(int argc, char **argv);
122 static int lfs_swap_layouts(int argc, char **argv);
123 static int lfs_mv(int argc, char **argv);
124 static int lfs_ladvise(int argc, char **argv);
125 static int lfs_getsom(int argc, char **argv);
126 static int lfs_heat_get(int argc, char **argv);
127 static int lfs_heat_set(int argc, char **argv);
128 static int lfs_mirror(int argc, char **argv);
129 static inline int lfs_mirror_resync(int argc, char **argv);
130 static inline int lfs_mirror_verify(int argc, char **argv);
131 static inline int lfs_mirror_read(int argc, char **argv);
132 static inline int lfs_mirror_write(int argc, char **argv);
133 static inline int lfs_mirror_copy(int argc, char **argv);
134 static int lfs_pcc_attach(int argc, char **argv);
135 static int lfs_pcc_attach_fid(int argc, char **argv);
136 static int lfs_pcc_detach(int argc, char **argv);
137 static int lfs_pcc_detach_fid(int argc, char **argv);
138 static int lfs_pcc_state(int argc, char **argv);
139 static int lfs_pcc(int argc, char **argv);
140
141 static int lfs_migrate_to_dom(int fd_src, int fd_dst, char *name,
142                               __u64 migration_flags,
143                               unsigned long long bandwidth_bytes_sec,
144                               long stats_interval_sec);
145
146 struct pool_to_id_cbdata {
147         const char *pool;
148         __u32 id;
149 };
150
151 static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata);
152 static int find_mirror_id_by_pool(struct llapi_layout *layout, void *cbdata);
153
154 enum setstripe_origin {
155         SO_SETSTRIPE,
156         SO_MIGRATE,
157         SO_MIGRATE_MDT,
158         SO_MIRROR_CREATE,
159         SO_MIRROR_EXTEND,
160         SO_MIRROR_SPLIT,
161         SO_MIRROR_DELETE,
162 };
163
164 static int lfs_setstripe_internal(int argc, char **argv,
165                                   enum setstripe_origin opc);
166
167 static inline int lfs_setstripe(int argc, char **argv)
168 {
169         return lfs_setstripe_internal(argc, argv, SO_SETSTRIPE);
170 }
171
172 static inline int lfs_setstripe_migrate(int argc, char **argv)
173 {
174         return lfs_setstripe_internal(argc, argv, SO_MIGRATE);
175 }
176
177 static inline int lfs_mirror_create(int argc, char **argv)
178 {
179         return lfs_setstripe_internal(argc, argv, SO_MIRROR_CREATE);
180 }
181
182 static inline int lfs_mirror_extend(int argc, char **argv)
183 {
184         return lfs_setstripe_internal(argc, argv, SO_MIRROR_EXTEND);
185 }
186
187 static inline int lfs_mirror_split(int argc, char **argv)
188 {
189         return lfs_setstripe_internal(argc, argv, SO_MIRROR_SPLIT);
190 }
191
192 static inline int lfs_mirror_delete(int argc, char **argv)
193 {
194         return lfs_setstripe_internal(argc, argv, SO_MIRROR_DELETE);
195 }
196
197 #define SSM_SETSTRIPE_OPT \
198         "[--component-add|--component-del|--delete|-d]\n"       \
199         "\t\t[--comp-set --comp-id|-I COMP_ID|--comp-flags=COMP_FLAGS]\n"       \
200         "\t\t[--component-end|-E END_OFFSET]\n"                 \
201         "\t\t[--copy=SOURCE_LAYOUT_FILE]|--yaml|-y YAML_TEMPLATE_FILE]\n"       \
202         "\t\t[--extension-size|--ext-size|-z EXT_SIZE]\n"       \
203         "\t\t[--help|-h]\n"                                     \
204         "\t\t[--foreign=FOREIGN_TYPE --xattr|-x LAYOUT]\n"      \
205         "\t\t[--layout|-L PATTERN] [--mode FILE_MODE]\n"        \
206         "\t\t[--mirror-count|-N[MIRROR_COUNT]]\n"               \
207         "\t\t[--ost|-o OST_INDEX[,OST_INDEX,...]]\n"            \
208         "\t\t[--overstripe-count|-C STRIPE_COUNT]\n"            \
209         "\t\t[--pool|-p POOL_NAME]\n"                           \
210         "\t\t[--stripe-count|-c STRIPE_COUNT]\n"                \
211         "\t\t[--stripe-index|-i START_OST_IDX]\n"               \
212         "\t\t[--stripe-size|-S STRIPE_SIZE]"
213
214 /* Setstripe and migrate share mostly the same parameters */
215 #define SSM_CMD_COMMON(cmd)             \
216         "Usage: " cmd                   \
217         " " SSM_SETSTRIPE_OPT "\n"
218
219 #define SETSTRIPE_USAGE                                                 \
220         SSM_CMD_COMMON("setstripe  ")                                   \
221         "\t\tFILENAME|DIRECTORY\n"
222
223 #define MIGRATE_USAGE                                                   \
224         SSM_CMD_COMMON("migrate  ")                                     \
225         "\t\t[--block|-b] [--non-block|-n]\n"                           \
226         "\t\t[--non-direct|-D] [--verbose|-v] FILENAME\n"               \
227
228 #define SETDIRSTRIPE_USAGE                                              \
229         "               [--mdt-count|-c stripe_count>\n"                \
230         "               [--help|-h] [--mdt-hash|-H mdt_hash]\n"         \
231         "               [--mdt-index|-i mdt_index[,mdt_index,...]\n"    \
232         "               [--mdt-overcount|-C stripe_count>\n"            \
233         "               [--default|-D] [--mode|-o mode]\n"              \
234         "               [--max-inherit|-X max_inherit]\n"               \
235         "               [--max-inherit-rr max_inherit_rr] <dir>\n"      \
236         "To create dir with a foreign (free format) layout :\n"         \
237         "setdirstripe|mkdir --foreign[=FOREIGN_TYPE] -x|-xattr STRING " \
238         "               [--mode|-o MODE] [--flags HEX] DIRECTORY\n"
239
240 /**
241  * command_t mirror_cmdlist - lfs mirror commands.
242  */
243 command_t mirror_cmdlist[] = {
244         { .pc_name = "create", .pc_func = lfs_mirror_create,
245           .pc_help = "Create a mirrored file.\n"
246                 "usage: lfs mirror create --mirror-count|-N[MIRROR_COUNT]\n"
247                 "           [SETSTRIPE_OPTIONS] ... FILENAME|DIRECTORY ...\n" },
248         { .pc_name = "delete", .pc_func = lfs_mirror_delete,
249           .pc_help = "Delete a mirror from a file.\n"
250         "usage: lfs mirror delete {--mirror-id <mirror_id> |\n"
251         "\t               --component-id|--comp-id|-I COMP_ID |\n"
252         "\t               -p <pool>} MIRRORED_FILE ...\n"
253         },
254         { .pc_name = "extend", .pc_func = lfs_mirror_extend,
255           .pc_help = "Extend a mirrored file.\n"
256                 "Usage: lfs mirror extend "
257                 "--mirror-count|-N[MIRROR_COUNT] [--no-verify]|\n"
258                 "\t\t[--stats|--stats-interval=STATS_INTERVAL]|\n"
259                 "\t\t[--bandwidth-limit|--W BANDWIDTH]\n"
260                 "\t\t[[-f VICTIM_FILE] |\n"
261                 "\t\t" SSM_SETSTRIPE_OPT "]"
262                 " FILENAME ...\n" },
263         { .pc_name = "split", .pc_func = lfs_mirror_split,
264           .pc_help = "Split a mirrored file.\n"
265         "usage: lfs mirror split {--mirror-id MIRROR_ID |\n"
266         "\t             --component-id|-I COMP_ID|-p POOL} [--destroy|-d]\n"
267         "\t             [-f NEW_FILE] MIRRORED_FILE ...\n" },
268         { .pc_name = "read", .pc_func = lfs_mirror_read,
269           .pc_help = "Read the content of a specified mirror of a file.\n"
270                 "usage: lfs mirror read {--mirror-id|-N MIRROR_ID}\n"
271                 "\t\t[--outfile|-o <output_file>] <mirrored_file>\n" },
272         { .pc_name = "write", .pc_func = lfs_mirror_write,
273           .pc_help = "Write to a specified mirror of a file.\n"
274                 "usage: lfs mirror write {--mirror-id|-N MIRROR_ID}\n"
275                 "\t\t[--inputfile|-i <input_file>] <mirrored_file>\n" },
276         { .pc_name = "copy", .pc_func = lfs_mirror_copy,
277           .pc_help = "Copy a specified mirror to other mirror(s) of a file.\n"
278                 "usage: lfs mirror copy {--read-mirror|-i MIRROR_ID0}\n"
279                 "\t\t{--write-mirror|-o MIRROR_ID1[,...]} <mirrored_file>\n" },
280         { .pc_name = "resync", .pc_func = lfs_mirror_resync,
281           .pc_help = "Resynchronizes out-of-sync mirrored file(s).\n"
282                 "usage: lfs mirror resync [--only MIRROR_ID[,...]>]|\n"
283                 "\t\t--stats|--stats-interval=<sec>|\n"
284                 "\t\t--W <bandwidth>|--bandwidth-limit=<bandwidth>\n"
285                 "\t\t<mirrored_file> [<mirrored_file2>...]\n" },
286         { .pc_name = "verify", .pc_func = lfs_mirror_verify,
287           .pc_help = "Verify mirrored file(s).\n"
288                 "usage: lfs mirror verify [--only MIRROR_ID[,...]]\n"
289                 "\t\t[--verbose|-v] <mirrored_file> [<mirrored_file2> ...]\n" },
290         { .pc_help = NULL }
291 };
292
293 /**
294  * command_t pcc_cmdlist - lfs pcc commands.
295  */
296 command_t pcc_cmdlist[] = {
297         { .pc_name = "attach", .pc_func = lfs_pcc_attach,
298           .pc_help = "Attach given files to the Persistent Client Cache.\n"
299                 "usage: lfs pcc attach <--id|-i NUM> <file> ...\n"
300                 "\t-i: archive id for RW-PCC\n" },
301         { .pc_name = "attach_fid", .pc_func = lfs_pcc_attach_fid,
302           .pc_help = "Attach given files into PCC by FID(s).\n"
303                 "usage: lfs pcc attach_id {--id|-i NUM} {--mnt|-m MOUNTPOINT} FID ...\n"
304                 "\t-i: archive id for RW-PCC\n"
305                 "\t-m: Lustre mount point\n" },
306         { .pc_name = "state", .pc_func = lfs_pcc_state,
307           .pc_help = "Display the PCC state for given files.\n"
308                 "usage: lfs pcc state <file> ...\n" },
309         { .pc_name = "detach", .pc_func = lfs_pcc_detach,
310           .pc_help = "Detach given files from the Persistent Client Cache.\n"
311                 "usage: lfs pcc detach <file> ...\n" },
312         { .pc_name = "detach_fid", .pc_func = lfs_pcc_detach_fid,
313           .pc_help = "Detach given files from PCC by FID(s).\n"
314                 "usage: lfs pcc detach_fid <mntpath> <fid>...\n" },
315         { .pc_help = NULL }
316 };
317
318 /* all available commands */
319 command_t cmdlist[] = {
320         {"setstripe", lfs_setstripe, 0,
321          "Create a file with specified striping/composite layout, or\n"
322          "set the default layout on an existing directory.\n"
323          SETSTRIPE_USAGE},
324         {"getstripe", lfs_getstripe, 0,
325          "List the layout pattern for a given file or files in a\n"
326          "directory or recursively for all files in a directory tree.\n"
327          "Usage: getstripe [--ost|-O OST_NAME] [--quiet|-q] [--verbose|-v]\n"
328          "                 [--stripe-count|-c] [--stripe-index|-i] [--fid|-F]\n"
329          "                 [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
330          "                 [--mdt-index|-m] [--recursive|-r] [--raw|-R]\n"
331          "                 [--layout|-L] [--generation|-g] [--yaml|-y]\n"
332          "                 [--help|-h] [--hex-idx]\n"
333          "                 [--component-id|-I[=COMP_ID]]\n"
334          "                 [--component-flags[=COMP_FLAGS]]\n"
335          "                 [--component-count]\n"
336          "                 [--extension-size|--ext-size|-z]\n"
337          "                 [--component-start[=[+-]START_OFFSET]]\n"
338          "                 [--component-end|-E[[+-]END_OFFSET]]\n"
339          "                 [[!] --mirror-index=[+-]MIRROR_INDEX |\n"
340          "                 [!] --mirror-id=[+-]MIRROR_ID] [--mirror-count|-N]\n"
341          "                 [--no-follow]\n"
342          "                 FILENAME|DIRECTORY"},
343         {"setdirstripe", lfs_setdirstripe, 0,
344          "Create striped directory on specified MDT, same as mkdir.\n"
345          "May be restricted to root or group users, depending on settings.\n"
346          "usage: setdirstripe [OPTION] <directory>\n"
347          SETDIRSTRIPE_USAGE},
348         {"getdirstripe", lfs_getdirstripe, 0,
349          "To list the layout pattern info for a given directory\n"
350          "or recursively for all directories in a directory tree.\n"
351          "usage: getdirstripe [--mdt-count|-c] [--mdt-index|-m|-i]\n"
352          "                    [--help|-h] [--hex-idx] [--mdt-hash|-H]\n"
353          "                    [--obd|-O UUID] [--recursive|-r] [--raw|-R]\n"
354          "                    [--yaml|-y] [--verbose|-v] [--default|-D]\n"
355          "                    [--max-inherit|-X]\n"
356          "                    [--max-inherit-rr] <dir> ..."},
357         {"mkdir", lfs_setdirstripe, 0,
358          "Create striped directory on specified MDT, same as setdirstripe.\n"
359          "usage: mkdir [OPTION] <directory>\n"
360          SETDIRSTRIPE_USAGE},
361         {"rm_entry", lfs_rmentry, 0,
362          "To remove the name entry of the remote directory. Note: This\n"
363          "command will only delete the name entry, i.e. the remote directory\n"
364          "will become inaccessable after this command. This can only be done\n"
365          "by the administrator\n"
366          "usage: rm_entry <dir>\n"},
367         {"rmentry", lfs_rmentry, 0, "remove a dir entry, same as 'rm_entry'\n"},
368         {"unlink_foreign", lfs_unlink_foreign, 0,
369          "To remove the foreign file/dir.\n"
370          "Note: This is for files/dirs prevented to be removed using\n"
371          "unlink/rmdir, but works also for regular ones\n"
372          "usage: unlink_foreign <foreign_dir/file> [<foreign_dir/file> ...]\n"},
373         {"pool_list", lfs_poollist, 0,
374          "List pools or pool OSTs\n"
375          "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
376         {"find", lfs_find, 0,
377          "find files matching given attributes recursively in directory tree.\n"
378          "usage: find <directory|filename> ...\n"
379          "     [[!] --atime|-A [+-]N[smhdwy]] [[!] --btime|-B [+-]N[smhdwy]]\n"
380          "     [[!] --ctime|-C [+-]N[smhdwy]] [[!] --mtime|-M [+-]N[smhdwy]]\n"
381          "     [[!] --attrs=[^]ATTR[,...]]\n"
382          "     [[!] --blocks|-b N] [[!] --component-count [+-]<comp_cnt>]\n"
383          "     [[!] --component-start [+-]N[kMGTPE]]\n"
384          "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
385          "     [[!] --component-flags {init,stale,prefer,prefrd,prefwr,offline,nosync,extension}]\n"
386          "     [[!] --extension-size|--ext-size|-z [+-]N[kMGT]]\n"
387          "     [[!] --foreign[=<foreign_type>]]\n"
388          "     [[!] --gid|-g|--group|-G <gid>|<gname>] [--help|-h]\n"
389          "     [[!] --layout|-L released,raid0,mdt] [--lazy|-l] [[!] --links [+-]n]\n"
390          "     [--maxdepth|-D N] [[!] --mdt-count|-T [+-]<stripes>]\n"
391          "     [[!] --mdt-hash|-H <[^][blm],[^]fnv_1a_64,all_char,crush,...>\n"
392          "     [[!] --mdt-index|--mdt|-m <uuid|index,...>]\n"
393          "     [[!] --mirror-count|-N [+-]<n>]\n"
394          "     [[!] --mirror-state <[^]state>]\n"
395          "     [[!] --name|-n <pattern>] [[!] --newer[XY] <reference>]\n"
396          "     [[!] --ost|-O <uuid|index,...>] [[!] --perm [/-]mode]\n"
397          "     [[!] --pool <pool>] [--print|-P] [--print0|-0] [--printf <format>]\n"
398          "     [[!] --projid <projid>] [[!] --size|-s [+-]N[bkMGTPE]]\n"
399          "     [[!] --stripe-count|-c [+-]<stripes>]\n"
400          "     [[!] --stripe-index|-i <index,...>]\n"
401          "     [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
402          "     [[!] --uid|-u|--user|-U <uid>|<uname>]\n"
403          "\t !: used before an option indicates 'NOT' requested attribute\n"
404          "\t -: used before a value indicates less than requested value\n"
405          "\t +: used before a value indicates more than requested value\n"
406          "\t ^: used before a flag indicates to exclude it\n"},
407         {"check", lfs_check, 0,
408          "Display the status of MGTs, MDTs or OSTs (as specified in the command)\n"
409          "or all the servers (MGTs, MDTs and OSTs) [for specified path only].\n"
410          "usage: check {mgts|osts|mdts|all} [path]"},
411         {"osts", lfs_osts, 0, "list OSTs connected to client "
412          "[for specified path only]\n" "usage: osts [path]"},
413         {"mdts", lfs_mdts, 0, "list MDTs connected to client "
414          "[for specified path only]\n" "usage: mdts [path]"},
415         {"df", lfs_df, 0,
416          "report filesystem disk space usage or inodes usage "
417          "of each MDS and all OSDs or a batch belonging to a specific pool.\n"
418          "Usage: df [--inodes|-i] [--human-readable|-h] [--lazy|-l]\n"
419          "          [--pool|-p <fsname>[.<pool>]] [path]"},
420         {"getname", lfs_getname, 0,
421          "list instances and specified mount points [for specified path only]\n"
422          "Usage: getname [--help|-h] [--instance|-i] [--fsname|-n] [path ...]"},
423 #ifdef HAVE_SYS_QUOTA_H
424         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
425          "usage: setquota [-t] {-u|-U|-g|-G|-p|-P ID} {-b|-B|-i|-I LIMIT} [--pool POOL] FILESYSTEM\n"
426          "       setquota {-u|-g|-p ID} {--default|--delete} FILESYSTEM\n"},
427         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
428          "usage: quota [-q] [-v] [-h] [-o OBD_UUID|-i MDT_IDX|-I OST_IDX]\n"
429          "             [{-u|-g|-p} UNAME|UID|GNAME|GID|PROJID]\n"
430          "             [--pool OST_POOL_NAME] FILESYSTEM\n"
431          "       quota -t {-u|-g|-p} [--pool OST_POOL_NAME] FILESYSTEM\n"
432          "       quota [-hqv] {-U|-G|-P} [--pool OST_POOL_NAME] FILESYSTEM\n"
433          "       quota -a {-u|-g|-p} [-s START_QID] [-e END_QID] FILESYSTEM"},
434         {"project", lfs_project, 0,
435          "Change or list project attribute for specified file or directory.\n"
436          "usage: project [-d|-r] <file|directory...>\n"
437          "         list project ID and flags on file(s) or directories\n"
438          "       project [-p id] [-s] [-r] <file|directory...>\n"
439          "         set project ID and/or inherit flag for specified file(s) or directories\n"
440          "       project -c [-d|-r [-p id] [-0]] <file|directory...>\n"
441          "         check project ID and flags on file(s) or directories, print outliers\n"
442          "       project -C [-d|-r] [-k] <file|directory...>\n"
443          "         clear the project inherit flag and ID on the file or directory\n"
444         },
445 #endif
446         {"flushctx", lfs_flushctx, 0,
447          "Flush security context for current user.\n"
448          "usage: flushctx [-k] [-r] [mountpoint...]"},
449         {"changelog", lfs_changelog, 0,
450          "Show the metadata changes on an MDT."
451          "\nusage: changelog <mdtname> [startrec [endrec]]"},
452         {"changelog_clear", lfs_changelog_clear, 0,
453          "Indicate that old changelog records up to <endrec> are no longer of "
454          "interest to consumer <id>, allowing the system to free up space.\n"
455          "An <endrec> of 0 means all records.\n"
456          "usage: changelog_clear <mdtname> <id> <endrec>"},
457         {"fid2path", lfs_fid2path, 0,
458          "Resolve the full path(s) for given FID(s). For a specific hardlink "
459          "specify link number <linkno>.\n"
460          "usage: fid2path [--print0|-0] [--print-fid|-f] [--print-link|-c] "
461          "[--link|-l <linkno>] [--name|-n] <fsname|root> <fid>..."},
462         {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
463          "usage: path2fid [--parents] <path> ..."},
464         {"rmfid", lfs_rmfid, 0, "Remove file(s) by FID(s)\n"
465          "usage: rmfid <fsname|rootpath> <fid> ..."},
466         {"data_version", lfs_data_version, 0, "Display file data version for "
467          "a given path.\n" "usage: data_version [-n|-r|-w] <path>"},
468         {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
469          "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
470         {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
471          "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
472          "[--archived] [--lost] [--archive-id NUM] <file> ..."},
473         {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
474          "files.\n"
475          "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
476          "[--archived] [--lost] <file> ..."},
477         {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
478          "given files.\n" "usage: hsm_action <file> ..."},
479         {"hsm_archive", lfs_hsm_archive, 0,
480          "Archive file to external storage.\n"
481          "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
482          "<file> ..."},
483         {"hsm_restore", lfs_hsm_restore, 0,
484          "Restore file from external storage.\n"
485          "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
486         {"hsm_release", lfs_hsm_release, 0,
487          "Release files from Lustre.\n"
488          "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
489         {"hsm_remove", lfs_hsm_remove, 0,
490          "Remove file copy from external storage.\n"
491          "usage: hsm_remove [--filelist FILELIST] [--data DATA] "
492          "[--archive NUM]\n"
493          "                  (FILE [FILE ...] | "
494          "--mntpath MOUNTPATH FID [FID ...])\n"
495          "\n"
496          "Note: To remove an archived copy of a file already deleted from a "
497          "Lustre FS, the\n"
498          "--mntpath option and a list of FIDs must be specified"
499         },
500         {"hsm_cancel", lfs_hsm_cancel, 0,
501          "Cancel requests related to specified files.\n"
502          "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
503         {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
504          "usage: swap_layouts <path1> <path2>"},
505         {"migrate", lfs_setstripe_migrate, 0,
506          "migrate directories and their inodes between MDTs.\n"
507          "usage: migrate [--mdt-count|-c STRIPE_COUNT]\n"
508          "               [--mdt-overcount|-C OVERSTRIPE_COUNT\n"
509          "               [--directory|-d] [--mdt-hash|-H HASH_TYPE]\n"
510          "               [--mdt-index|-m START_MDT_INDEX] [--verbose|-v]\n"
511          "               DIRECTORY\n"
512          "\n"
513          "migrate file objects from one OST layout to another\n"
514          "(may be not safe with concurent writes).\n"
515          MIGRATE_USAGE },
516         {"mv", lfs_mv, 0,
517          "To move directories between MDTs. This command is deprecated, "
518          "use \"migrate\" instead.\n"
519          "usage: mv <directory|filename> [--mdt-index|-m MDT_INDEX] "
520          "[--verbose|-v]\n"},
521         {"ladvise", lfs_ladvise, 0,
522          "Provide servers with advice about access patterns for a file.\n"
523          "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
524          "               [--background|-b] [--unset|-u]\n\n"
525          "               {--end|-e END[kMGT]|--length|-l LENGTH[kMGT]}\n"
526          "               {[--mode|-m [READ,WRITE]}\n"
527          "               <file> ...\n"},
528         {"mirror", lfs_mirror, mirror_cmdlist,
529          "lfs commands used to manage files with mirrored components:\n"
530          "lfs mirror create - create a mirrored file or directory\n"
531          "lfs mirror extend - add mirror(s) to an existing file\n"
532          "lfs mirror split  - split a mirror from an existing mirrored file\n"
533          "lfs mirror resync - resynchronize out-of-sync mirrored file(s)\n"
534          "lfs mirror read   - read a mirror content of a mirrored file\n"
535          "lfs mirror write  - write to a mirror of a mirrored file\n"
536          "lfs mirror copy   - copy a mirror to other mirror(s) of a file\n"
537          "lfs mirror verify - verify mirrored file(s)\n"},
538         {"getsom", lfs_getsom, 0, "To list the SOM info for a given file.\n"
539          "usage: getsom [-s] [-b] [-f] <path>\n"
540          "\t-s: Only show the size value of the SOM data for a given file\n"
541          "\t-b: Only show the blocks value of the SOM data for a given file\n"
542          "\t-f: Only show the flags value of the SOM data for a given file\n"},
543         {"heat_get", lfs_heat_get, 0,
544          "To get heat of files.\n"
545          "usage: heat_get <file> ...\n"},
546         {"heat_set", lfs_heat_set, 0,
547          "To set heat flags of files.\n"
548          "usage: heat_set [--clear|-c] [--off|-o] [--on|-O] <file> ...\n"
549          "\t--clear|-c: Clear file heat for given files\n"
550          "\t--off|-o:   Turn off file heat for given files\n"
551          "\t--on|-O:    Turn on file heat for given files\n"},
552         {"pcc", lfs_pcc, pcc_cmdlist,
553          "lfs commands used to interact with PCC features:\n"
554          "lfs pcc attach - attach given files to Persistent Client Cache\n"
555          "lfs pcc attach_fid - attach given files into PCC by FID(s)\n"
556          "lfs pcc state  - display the PCC state for given files\n"
557          "lfs pcc detach - detach given files from Persistent Client Cache\n"
558          "lfs pcc detach_fid - detach given files from PCC by FID(s)\n"},
559         { 0, 0, 0, NULL }
560 };
561
562 static int check_hashtype(const char *hashtype)
563 {
564         int type_num = atoi(hashtype);
565         int i;
566
567         /* numeric hash type */
568         if (hashtype && lmv_is_known_hash_type(type_num))
569                 return type_num;
570         /* string hash type */
571         for (i = LMV_HASH_TYPE_ALL_CHARS; i < ARRAY_SIZE(mdt_hash_name); i++)
572                 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
573                         return i;
574
575         return 0;
576 }
577
578 static uint32_t check_foreign_type_name(const char *foreign_type_name)
579 {
580         uint32_t i;
581
582         for (i = 0; i < LU_FOREIGN_TYPE_UNKNOWN; i++) {
583                 if (!lu_foreign_types[i].lft_name)
584                         break;
585                 if (strcmp(foreign_type_name,
586                            lu_foreign_types[i].lft_name) == 0)
587                         return lu_foreign_types[i].lft_type;
588         }
589
590         return LU_FOREIGN_TYPE_UNKNOWN;
591 }
592
593 static const char *error_loc = "syserror";
594
595 static int
596 migrate_open_files(const char *name, __u64 migration_flags,
597                    const struct llapi_stripe_param *param,
598                    struct llapi_layout *layout, int *fd_src_ptr,
599                    int *fd_dst_ptr)
600 {
601         int                      fd_src = -1;
602         int                      fd_dst = -1;
603         int                      rflags;
604         int                      mdt_index;
605         int                      random_value;
606         char                     parent[PATH_MAX];
607         char                     volatile_file[PATH_MAX];
608         char                    *ptr;
609         int                      rc;
610         struct stat              st;
611         struct stat              stv;
612
613         if (!param && !layout) {
614                 error_loc = "layout information";
615                 return -EINVAL;
616         }
617
618         /* search for file directory pathname */
619         if (strlen(name) > sizeof(parent) - 1) {
620                 error_loc = "source file name";
621                 return -ERANGE;
622         }
623
624         strncpy(parent, name, sizeof(parent));
625         ptr = strrchr(parent, '/');
626         if (!ptr) {
627                 if (!getcwd(parent, sizeof(parent))) {
628                         error_loc = "getcwd";
629                         return -errno;
630                 }
631         } else {
632                 if (ptr == parent) /* leading '/' */
633                         ptr = parent + 1;
634                 *ptr = '\0';
635         }
636
637         /* even if the file is only read, WR mode is nedeed to allow
638          * layout swap on fd
639          */
640         /* Allow migrating even without the key on encrypted files */
641         rflags = O_RDWR | O_NOATIME | O_CIPHERTEXT;
642         if (!(migration_flags & LLAPI_MIGRATION_NONDIRECT))
643                 rflags |= O_DIRECT;
644 source_open:
645         fd_src = open(name, rflags);
646         if (fd_src < 0) {
647                 /* If encrypted file without the key,
648                  * retry mirror extend in O_DIRECT.
649                  */
650                 if (errno == ENOKEY && !(rflags & O_DIRECT) &&
651                     migration_flags & LLAPI_MIGRATION_MIRROR) {
652                         rflags |= O_DIRECT;
653                         goto source_open;
654                 }
655                 rc = -errno;
656                 error_loc = "cannot open source file";
657                 return rc;
658         }
659
660         rc = llapi_file_fget_mdtidx(fd_src, &mdt_index);
661         if (rc < 0) {
662                 error_loc = "cannot get MDT index";
663                 goto out;
664         }
665
666         do {
667                 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW |
668                         /* Allow migrating without the key on encrypted files */
669                         O_CIPHERTEXT;
670                 mode_t open_mode = S_IRUSR | S_IWUSR;
671
672                 if (rflags & O_DIRECT)
673                         open_flags |= O_DIRECT;
674                 random_value = random();
675                 rc = snprintf(volatile_file, sizeof(volatile_file),
676                               "%s/%s:%.4X:%.4X:fd=%.2d", parent,
677                               LUSTRE_VOLATILE_HDR, mdt_index,
678                               random_value, fd_src);
679                 if (rc >= sizeof(volatile_file)) {
680                         rc = -ENAMETOOLONG;
681                         break;
682                 }
683
684                 /* create, open a volatile file, use caching (ie no directio) */
685                 if (layout) {
686                         /* Returns -1 and sets errno on error: */
687                         fd_dst = llapi_layout_file_open(volatile_file,
688                                                          open_flags, open_mode,
689                                                          layout);
690                         if (fd_dst < 0)
691                                 fd_dst = -errno;
692                 } else {
693                         /* Does the right thing on error: */
694                         fd_dst = llapi_file_open_param(volatile_file,
695                                                         open_flags,
696                                                         open_mode, param);
697                 }
698         } while (fd_dst < 0 && (rc = fd_dst) == -EEXIST);
699
700         if (rc < 0) {
701                 error_loc = "cannot create volatile file";
702                 goto out;
703         }
704
705         /*
706          * In case the MDT does not support creation of volatile files
707          * we should try to unlink it.
708          */
709         (void)unlink(volatile_file);
710
711         /*
712          * Not-owner (root?) special case.
713          * Need to set owner/group of volatile file like original.
714          * This will allow to pass related check during layout_swap.
715          */
716         rc = fstat(fd_src, &st);
717         if (rc != 0) {
718                 rc = -errno;
719                 error_loc = "cannot stat source file";
720                 goto out;
721         }
722
723         rc = fstat(fd_dst, &stv);
724         if (rc != 0) {
725                 rc = -errno;
726                 error_loc = "cannot stat volatile";
727                 goto out;
728         }
729
730         if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
731                 rc = fchown(fd_dst, st.st_uid, st.st_gid);
732                 if (rc != 0) {
733                         rc = -errno;
734                         error_loc = "cannot change ownwership of volatile";
735                         goto out;
736                 }
737         }
738
739 out:
740         if (rc < 0) {
741                 if (fd_src > 0)
742                         close(fd_src);
743                 if (fd_dst > 0)
744                         close(fd_dst);
745         } else {
746                 *fd_src_ptr = fd_src;
747                 *fd_dst_ptr = fd_dst;
748                 error_loc = NULL;
749         }
750         return rc;
751 }
752
753 static struct timespec timespec_sub(struct timespec *before,
754                                     struct timespec *after)
755 {
756         struct timespec ret;
757
758         ret.tv_sec = after->tv_sec - before->tv_sec;
759         if (after->tv_nsec < before->tv_nsec) {
760                 ret.tv_sec--;
761                 ret.tv_nsec = NSEC_PER_SEC + after->tv_nsec - before->tv_nsec;
762         } else {
763                 ret.tv_nsec = after->tv_nsec - before->tv_nsec;
764         }
765
766         return ret;
767 }
768
769 static void stats_log(struct timespec *now, struct timespec *start_time,
770                       ssize_t read_bytes, size_t write_bytes,
771                       off_t file_size_bytes)
772 {
773         struct timespec diff = timespec_sub(start_time, now);
774
775         if (file_size_bytes == 0)
776                 return;
777
778         if (diff.tv_sec == 0 && diff.tv_nsec == 0)
779                 return;
780
781         printf("- { seconds: %li, rmbps: %5.2g, wmbps: %5.2g, copied: %lu, size: %lu, pct: %lu%% }\n",
782                 diff.tv_sec,
783                 (double) read_bytes/((ONE_MB * diff.tv_sec) +
784                         ((ONE_MB * diff.tv_nsec)/NSEC_PER_SEC)),
785                 (double) write_bytes/((ONE_MB * diff.tv_sec) +
786                         ((ONE_MB * diff.tv_nsec)/NSEC_PER_SEC)),
787                 write_bytes/ONE_MB, file_size_bytes/ONE_MB,
788                 ((write_bytes*100)/file_size_bytes));
789 }
790
791 static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int),
792                              unsigned long long bandwidth_bytes_sec,
793                              long stats_interval_sec, off_t file_size_bytes)
794 {
795         struct llapi_layout *layout;
796         size_t buf_size = 64 * ONE_MB;
797         uint64_t stripe_size = ONE_MB;
798         void *buf = NULL;
799         off_t pos = 0;
800         off_t data_end = 0;
801         ssize_t page_size;
802         bool sparse;
803         int rc;
804         size_t write_bytes = 0;
805         ssize_t read_bytes = 0;
806         struct timespec start_time;
807         struct timespec now;
808         struct timespec last_bw_print;
809
810         layout = llapi_layout_get_by_fd(fd_src, 0);
811         if (layout) {
812                 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
813                 if (rc == 0) {
814                         /* We like big bufs */
815                         if (stripe_size > buf_size)
816                                 buf_size = stripe_size;
817                         else
818                                 /* Trim to stripe_size multiple */
819                                 buf_size -= buf_size % stripe_size;
820                 }
821
822                 llapi_layout_free(layout);
823         }
824
825         /* limit transfer size to what can be sent in one second */
826         if (bandwidth_bytes_sec && bandwidth_bytes_sec < buf_size)
827                 buf_size = (bandwidth_bytes_sec + stripe_size - 1) &
828                         ~(stripe_size - 1);
829
830         page_size = sysconf(_SC_PAGESIZE);
831         if (page_size < 0) {
832                 rc = -errno;
833                 return rc;
834         }
835
836         /* Use a page-aligned buffer for direct I/O */
837         rc = posix_memalign(&buf, page_size, buf_size);
838         if (rc != 0)
839                 return -rc;
840
841         sparse = llapi_file_is_sparse(fd_src);
842         if (sparse) {
843                 rc = ftruncate(fd_dst, pos);
844                 if (rc < 0) {
845                         rc = -errno;
846                         free(buf);
847                         return rc;
848                 }
849         }
850
851         clock_gettime(CLOCK_MONOTONIC, &start_time);
852         now = last_bw_print = start_time;
853
854         while (1) {
855                 off_t data_off;
856                 size_t to_read, to_write;
857                 ssize_t rsize;
858
859                 if (sparse && pos >= data_end) {
860                         size_t data_size;
861
862                         data_off = llapi_data_seek(fd_src, pos, &data_size);
863                         if (data_off < 0) {
864                                 /* Non-fatal, switch to full copy */
865                                 sparse = false;
866                                 continue;
867                         }
868                         /* hole at the end of file, truncate up to it */
869                         if (!data_size) {
870                                 rc = ftruncate(fd_dst, data_off);
871                                 if (rc < 0)
872                                         goto out;
873                         }
874                         pos = data_off & ~(page_size - 1);
875                         data_end = data_off + data_size;
876                         to_read = ((data_end - pos - 1) | (page_size - 1)) + 1;
877                         to_read = MIN(to_read, buf_size);
878                 } else {
879                         to_read = buf_size;
880                 }
881
882                 if (check_file) {
883                         rc = check_file(fd_src);
884                         if (rc < 0)
885                                 goto out;
886                 }
887
888                 rsize = pread(fd_src, buf, to_read, pos);
889                 read_bytes += rsize;
890                 if (rsize < 0) {
891                         rc = -errno;
892                         goto out;
893                 }
894                 /* EOF */
895                 if (rsize == 0)
896                         break;
897
898                 to_write = rsize;
899                 while (to_write > 0) {
900                         unsigned long long write_target;
901                         ssize_t written;
902                         struct timespec diff;
903
904                         written = pwrite(fd_dst, buf, to_write, pos);
905                         if (written < 0) {
906                                 rc = -errno;
907                                 goto out;
908                         }
909                         pos += written;
910                         to_write -= written;
911                         write_bytes += written;
912
913                         if (bandwidth_bytes_sec == 0)
914                                 continue;
915
916                         clock_gettime(CLOCK_MONOTONIC, &now);
917                         diff = timespec_sub(&start_time, &now);
918                         write_target = ((bandwidth_bytes_sec * diff.tv_sec) +
919                                 ((bandwidth_bytes_sec *
920                                 diff.tv_nsec)/NSEC_PER_SEC));
921
922                         if (write_target < write_bytes) {
923                                 unsigned long long excess;
924                                 struct timespec delay = { 0, 0 };
925
926                                 excess = write_bytes - write_target;
927
928                                 if (excess == 0)
929                                         continue;
930
931                                 delay.tv_sec = excess / bandwidth_bytes_sec;
932                                 delay.tv_nsec = (excess % bandwidth_bytes_sec) *
933                                         NSEC_PER_SEC / bandwidth_bytes_sec;
934
935                                 do {
936                                         rc = clock_nanosleep(CLOCK_MONOTONIC, 0,
937                                                              &delay, &delay);
938                                 } while (rc < 0 && errno == EINTR);
939
940                                 if (rc < 0) {
941                                         if (stats_interval_sec)
942                                                 fprintf(stderr,
943                                                         "error %s: delay for bandwidth control failed: %s\n",
944                                                         progname,
945                                                         strerror(-rc));
946                                         rc = 0;
947                                 }
948                         }
949                 }
950
951                 clock_gettime(CLOCK_MONOTONIC, &now);
952                 if (stats_interval_sec && (write_bytes != file_size_bytes) &&
953                         (now.tv_sec >= last_bw_print.tv_sec +
954                         stats_interval_sec)) {
955                         stats_log(&now, &start_time,
956                                   read_bytes, write_bytes,
957                                   file_size_bytes);
958                         last_bw_print = now;
959                 }
960
961                 if (rc || rsize < to_read)
962                         break;
963         }
964
965         /* Output at least one log, regardless of stats_interval */
966         if (stats_interval_sec) {
967                 clock_gettime(CLOCK_MONOTONIC, &now);
968                 stats_log(&now, &start_time, read_bytes, write_bytes,
969                           file_size_bytes);
970         }
971
972         rc = fsync(fd_dst);
973         if (rc < 0)
974                 rc = -errno;
975 out:
976         /* Try to avoid page cache pollution after migration. */
977         (void)posix_fadvise(fd_src, 0, 0, POSIX_FADV_DONTNEED);
978         (void)posix_fadvise(fd_dst, 0, 0, POSIX_FADV_DONTNEED);
979
980         free(buf);
981         return rc;
982 }
983
984 static int migrate_set_timestamps(int fd, const struct stat *st)
985 {
986         struct timeval tv[2] = {
987                 {.tv_sec = st->st_atime},
988                 {.tv_sec = st->st_mtime}
989         };
990
991         return futimes(fd, tv);
992 }
993
994 static int migrate_block(int fd_src, int fd_dst,
995                          unsigned long long bandwidth_bytes_sec,
996                          long stats_interval_sec)
997 {
998         struct stat st;
999         __u64   dv1;
1000         int     gid;
1001         int     rc;
1002         int     rc2;
1003
1004         do
1005                 gid = random();
1006         while (gid == 0);
1007
1008
1009         /* The grouplock blocks all concurrent accesses to the file. */
1010         rc = llapi_group_lock(fd_src, gid);
1011         if (rc < 0) {
1012                 error_loc = "cannot get group lock";
1013                 return rc;
1014         }
1015
1016         rc = fstat(fd_src, &st);
1017         if (rc < 0) {
1018                 error_loc = "cannot stat source file";
1019                 rc = -errno;
1020                 goto out_unlock;
1021         }
1022
1023         /*
1024          * LL_DV_RD_FLUSH should not be set, otherwise the servers will try to
1025          * get extent locks on the OST objects. This will conflict with our
1026          * extent group locks.
1027          */
1028         rc = llapi_get_data_version(fd_src, &dv1, 0);
1029         if (rc < 0) {
1030                 error_loc = "cannot get dataversion";
1031                 goto out_unlock;
1032         }
1033
1034         rc = migrate_copy_data(fd_src, fd_dst, NULL, bandwidth_bytes_sec,
1035                                stats_interval_sec, st.st_size);
1036         if (rc < 0) {
1037                 error_loc = "data copy failed";
1038                 goto out_unlock;
1039         }
1040
1041         /* Make sure we keep original atime/mtime values */
1042         rc = migrate_set_timestamps(fd_dst, &st);
1043         if (rc < 0) {
1044                 error_loc = "set target file timestamp failed";
1045                 goto out_unlock;
1046         }
1047
1048         /*
1049          * swap layouts
1050          * for a migration we need to check data version on file did
1051          * not change.
1052          *
1053          * Pass in gid=0 since we already own grouplock.
1054          */
1055         rc = llapi_fswap_layouts_grouplock(fd_src, fd_dst, dv1, 0, 0,
1056                                            SWAP_LAYOUTS_CHECK_DV1);
1057         if (rc == -EAGAIN) {
1058                 error_loc = "file changed";
1059                 goto out_unlock;
1060         } else if (rc < 0) {
1061                 error_loc = "cannot swap layout";
1062                 goto out_unlock;
1063         }
1064
1065 out_unlock:
1066         rc2 = llapi_group_unlock(fd_src, gid);
1067         if (rc2 < 0 && rc == 0) {
1068                 error_loc = "unlock group lock";
1069                 rc = rc2;
1070         }
1071
1072         return rc;
1073 }
1074
1075 /**
1076  * Internal helper for migrate_copy_data(). Check lease and report error if
1077  * need be.
1078  *
1079  * \param[in]  fd           File descriptor on which to check the lease.
1080  *
1081  * \retval 0       Migration can keep on going.
1082  * \retval -errno  Error occurred, abort migration.
1083  */
1084 static int check_lease(int fd)
1085 {
1086         int rc;
1087
1088         rc = llapi_lease_check(fd);
1089         if (rc > 0)
1090                 return 0; /* llapi_check_lease returns > 0 on success. */
1091
1092         return -EBUSY;
1093 }
1094
1095 static int migrate_nonblock(int fd_src, int fd_dst,
1096                             unsigned long long bandwidth_bytes_sec,
1097                             long stats_interval_sec,
1098                             __u64 *dv_src)
1099 {
1100         struct stat st;
1101         __u64 dv1;
1102         __u64 dv2;
1103         int rc;
1104
1105         rc = fstat(fd_src, &st);
1106         if (rc < 0) {
1107                 error_loc = "cannot stat source file";
1108                 return -errno;
1109         }
1110
1111         rc = llapi_get_data_version(fd_src, &dv1, LL_DV_RD_FLUSH);
1112         if (rc < 0) {
1113                 error_loc = "cannot get data version";
1114                 return rc;
1115         }
1116
1117         rc = migrate_copy_data(fd_src, fd_dst, check_lease,
1118                                bandwidth_bytes_sec,
1119                                stats_interval_sec, st.st_size);
1120         if (rc < 0) {
1121                 error_loc = "data copy failed";
1122                 return rc;
1123         }
1124
1125         rc = llapi_get_data_version(fd_src, &dv2, LL_DV_RD_FLUSH);
1126         if (rc != 0) {
1127                 error_loc = "cannot get data version";
1128                 return rc;
1129         }
1130
1131         if (dv_src)
1132                 *dv_src = dv2;
1133
1134         if (dv1 != dv2) {
1135                 rc = -EAGAIN;
1136                 error_loc = "source file changed";
1137                 return rc;
1138         }
1139
1140         /* Make sure we keep original atime/mtime values */
1141         rc = migrate_set_timestamps(fd_dst, &st);
1142         if (rc < 0) {
1143                 error_loc = "set target file timestamp failed";
1144                 return -errno;
1145         }
1146         return 0;
1147 }
1148
1149 static
1150 int lfs_layout_compid_by_pool(char *fname, const char *pool, int *comp_id)
1151 {
1152         struct pool_to_id_cbdata data = { .pool = pool };
1153         struct llapi_layout *layout = NULL;
1154         int rc;
1155
1156         layout = llapi_layout_get_by_path(fname, 0);
1157         if (!layout) {
1158                 fprintf(stderr,
1159                         "error %s: file '%s' couldn't get layout: rc=%d\n",
1160                         progname, fname, errno);
1161                 rc = -errno;
1162                 goto free_layout;
1163         }
1164         rc = llapi_layout_sanity(layout, false, true);
1165         if (rc < 0) {
1166                 llapi_layout_sanity_perror(errno);
1167                 goto free_layout;
1168         }
1169         rc = llapi_layout_comp_iterate(layout, find_comp_id_by_pool, &data);
1170         if (rc < 0)
1171                 goto free_layout;
1172
1173         *comp_id = data.id;
1174         rc = 0;
1175
1176 free_layout:
1177         if (layout)
1178                 llapi_layout_free(layout);
1179         return rc;
1180 }
1181
1182 static int lfs_component_set(char *fname, int comp_id, const char *pool,
1183                              __u32 flags, __u32 neg_flags)
1184 {
1185         __u32 ids[2];
1186         __u32 flags_array[2];
1187         size_t count = 0;
1188         int rc;
1189
1190         if (!comp_id) {
1191                 if (pool == NULL) {
1192                         fprintf(stderr,
1193                                 "error %s: neither component id nor pool is specified\n",
1194                                 progname);
1195                         return -EINVAL;
1196                 }
1197                 rc = lfs_layout_compid_by_pool(fname, pool, &comp_id);
1198                 if (rc)
1199                         return rc;
1200         }
1201
1202         if (flags) {
1203                 ids[count] = comp_id;
1204                 flags_array[count] = flags;
1205                 ++count;
1206         }
1207
1208         if (neg_flags) {
1209                 if (neg_flags & LCME_FL_STALE) {
1210                         fprintf(stderr,
1211                                 "%s: cannot clear 'stale' flags from component. Please use lfs-mirror-resync(1) instead\n",
1212                                 progname);
1213                         return -EINVAL;
1214                 }
1215
1216                 ids[count] = comp_id;
1217                 flags_array[count] = neg_flags | LCME_FL_NEG;
1218                 ++count;
1219         }
1220
1221         rc = llapi_layout_file_comp_set(fname, ids, flags_array, count);
1222         if (rc) {
1223                 if (errno == EUCLEAN) {
1224                         rc = -errno;
1225                         fprintf(stderr,
1226                                 "%s: cannot set 'stale' flag on component '%#x' of the last non-stale mirror of '%s'\n",
1227                                 progname, comp_id, fname);
1228                 } else {
1229                         fprintf(stderr,
1230                                 "%s: cannot change the flags of component '%#x' of file '%s': %x / ^(%x)\n",
1231                                 progname, comp_id, fname, flags, neg_flags);
1232                 }
1233         }
1234
1235         return rc;
1236 }
1237
1238 static int lfs_component_del(char *fname, __u32 comp_id,
1239                              __u32 flags, __u32 neg_flags)
1240 {
1241         int     rc = 0;
1242
1243         if (flags && neg_flags) {
1244                 fprintf(stderr,
1245                         "%s: cannot specify both positive and negative flags\n",
1246                         progname);
1247                 return -EINVAL;
1248         }
1249
1250         if (!flags && neg_flags)
1251                 flags = neg_flags | LCME_FL_NEG;
1252
1253         if (flags && comp_id) {
1254                 fprintf(stderr,
1255                         "%s: cannot specify component ID and flags at the same time\n",
1256                         progname);
1257                 return -EINVAL;
1258         }
1259
1260         if (!flags && !comp_id) {
1261                 fprintf(stderr,
1262                         "%s: neither flags nor component ID is specified\n",
1263                         progname);
1264                 return -EINVAL;
1265         }
1266
1267         if (flags) {
1268                 if (flags & ~LCME_KNOWN_FLAGS) {
1269                         fprintf(stderr,
1270                                 "%s setstripe: unknown flags %#x\n",
1271                                 progname, flags);
1272                         return -EINVAL;
1273                 }
1274         } else if (comp_id > LCME_ID_MAX) {
1275                 fprintf(stderr, "%s setstripe: invalid component id %u\n",
1276                         progname, comp_id);
1277                 return -EINVAL;
1278         }
1279
1280         rc = llapi_layout_file_comp_del(fname, comp_id, flags);
1281         if (rc)
1282                 fprintf(stderr,
1283                         "%s setstripe: cannot delete component %#x from '%s': %s\n",
1284                         progname, comp_id, fname, strerror(errno));
1285         return rc;
1286 }
1287
1288 static int lfs_component_add(char *fname, struct llapi_layout *layout)
1289 {
1290         int     rc;
1291
1292         if (!layout)
1293                 return -EINVAL;
1294
1295         rc = llapi_layout_file_comp_add(fname, layout);
1296         if (rc)
1297                 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
1298                         fname, strerror(errno));
1299         return rc;
1300 }
1301
1302 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
1303                                 struct llapi_layout *layout)
1304 {
1305         struct stat     st;
1306         int     fd;
1307
1308         if (!layout)
1309                 return -EINVAL;
1310
1311         fd = lstat(fname, &st);
1312         if (fd == 0 && S_ISDIR(st.st_mode))
1313                 open_flags = O_DIRECTORY | O_RDONLY;
1314
1315         fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
1316         if (fd < 0)
1317                 fprintf(stderr, "%s: cannot %s '%s': %s\n", progname,
1318                         S_ISDIR(st.st_mode) ?
1319                                 "set default composite layout for" :
1320                                 "create composite file",
1321                         fname, strerror(errno));
1322         return fd;
1323 }
1324
1325 static int lfs_migrate(char *name, __u64 migration_flags,
1326                         struct llapi_stripe_param *param,
1327                         struct llapi_layout *layout,
1328                         unsigned long long bandwidth_bytes_sec,
1329                         long stats_interval_sec)
1330 {
1331         struct llapi_layout *existing;
1332         uint64_t dom_new, dom_cur;
1333         __u64 dv_src = 0;
1334         __u64 dv_dst = 0;
1335         int fd_src = -1;
1336         int fd_dst = -1;
1337         int rc;
1338
1339         rc = migrate_open_files(name, migration_flags, param, layout,
1340                                 &fd_src, &fd_dst);
1341         if (rc < 0)
1342                 goto out;
1343
1344         rc = llapi_layout_dom_size(layout, &dom_new);
1345         if (rc) {
1346                 error_loc = "cannot get new layout DoM size";
1347                 goto out;
1348         }
1349         /* special case for migration to DOM layout*/
1350         existing = llapi_layout_get_by_fd(fd_src, 0);
1351         if (!existing) {
1352                 error_loc = "cannot get existing layout";
1353                 goto out;
1354         }
1355
1356         rc = llapi_layout_dom_size(existing, &dom_cur);
1357         if (rc) {
1358                 error_loc = "cannot get current layout DoM size";
1359                 goto out;
1360         }
1361
1362         /*
1363          * if file has DoM layout already then migration is possible to
1364          * the new layout with the same DoM component via swap layout,
1365          * if new layout used bigger DOM size, then mirroring is used
1366          */
1367         if (dom_new > dom_cur) {
1368                 rc = lfs_migrate_to_dom(fd_src, fd_dst, name,
1369                                         migration_flags,
1370                                         bandwidth_bytes_sec,
1371                                         stats_interval_sec);
1372                 if (rc)
1373                         error_loc = "cannot migrate to DOM layout";
1374                 goto out_closed;
1375         }
1376
1377         if (stats_interval_sec)
1378                 printf("%s:\n", name);
1379
1380         if (!(migration_flags & LLAPI_MIGRATION_NONBLOCK)) {
1381                 /*
1382                  * Blocking mode (forced if servers do not support file lease).
1383                  * It is also the default mode, since we cannot distinguish
1384                  * between a broken lease and a server that does not support
1385                  * atomic swap/close (LU-6785)
1386                  */
1387                 rc = migrate_block(fd_src, fd_dst, bandwidth_bytes_sec,
1388                                    stats_interval_sec);
1389                 goto out;
1390         }
1391
1392         rc = llapi_lease_acquire(fd_src, LL_LEASE_RDLCK);
1393         if (rc < 0) {
1394                 error_loc = "cannot get lease";
1395                 goto out;
1396         }
1397
1398         rc = migrate_nonblock(fd_src, fd_dst, bandwidth_bytes_sec,
1399                               stats_interval_sec, &dv_src);
1400         if (rc < 0) {
1401                 llapi_lease_release(fd_src);
1402                 goto out;
1403         }
1404
1405         rc = llapi_get_data_version(fd_dst, &dv_dst, LL_DV_RD_FLUSH);
1406         if (rc != 0) {
1407                 error_loc = "cannot get data version";
1408                 return rc;
1409         }
1410         /*
1411          * Atomically put lease, swap layouts and close.
1412          * for a migration we need to check data version on file did
1413          * not change.
1414          */
1415         rc = llapi_fswap_layouts(fd_src, fd_dst, dv_src, dv_dst,
1416                                  SWAP_LAYOUTS_CLOSE);
1417         if (rc < 0) {
1418                 error_loc = "cannot swap layout";
1419                 goto out;
1420         }
1421
1422 out:
1423         if (fd_src >= 0)
1424                 close(fd_src);
1425
1426         if (fd_dst >= 0)
1427                 close(fd_dst);
1428 out_closed:
1429         if (rc < 0)
1430                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1431                         progname, name, error_loc, strerror(-rc));
1432         else if (migration_flags & LLAPI_MIGRATION_VERBOSE)
1433                 printf("%s\n", name);
1434
1435         return rc;
1436 }
1437
1438 static int comp_str2flags(char *string, __u32 *flags, __u32 *neg_flags)
1439 {
1440         char *name;
1441         char *dup_string = NULL;
1442         int rc = 0;
1443
1444         *flags = 0;
1445         *neg_flags = 0;
1446
1447         if (!string || !string[0])
1448                 return -EINVAL;
1449
1450         dup_string = strdup(string);
1451         if (!dup_string) {
1452                 llapi_printf(LLAPI_MSG_ERROR,
1453                              "%s: insufficient memory\n",
1454                              progname);
1455                 return -ENOMEM;
1456         }
1457
1458         for (name = strtok(dup_string, ","); name; name = strtok(NULL, ",")) {
1459                 bool found = false;
1460                 int i;
1461
1462                 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1463                         __u32 comp_flag = comp_flags_table[i].cfn_flag;
1464                         const char *comp_name = comp_flags_table[i].cfn_name;
1465
1466                         if (strcmp(name, comp_name) == 0) {
1467                                 *flags |= comp_flag;
1468                                 found = true;
1469                         } else if (strncmp(name, "^", 1) == 0 &&
1470                                    strcmp(name + 1, comp_name) == 0) {
1471                                 *neg_flags |= comp_flag;
1472                                 found = true;
1473                         }
1474                 }
1475                 if (!found) {
1476                         llapi_printf(LLAPI_MSG_ERROR,
1477                                      "%s: component flag '%s' not supported\n",
1478                                      progname, name);
1479                         rc = -EINVAL;
1480                         goto out_free;
1481                 }
1482         }
1483
1484         if (!*flags && !*neg_flags)
1485                 rc = -EINVAL;
1486
1487         /* don't allow to set and exclude the same flag */
1488         if (*flags & *neg_flags)
1489                 rc = -EINVAL;
1490
1491 out_free:
1492         free(dup_string);
1493         return rc;
1494 }
1495
1496 static int mdthash_input(char *string, __u32 *inflags,
1497                          __u32 *exflags, __u32 *type)
1498 {
1499         char *name;
1500         struct mhf_list {
1501                 char *name;
1502                 __u32 flag;
1503         } mhflist[] = {
1504                 {"migrating", LMV_HASH_FLAG_MIGRATION},
1505                 {"bad_type", LMV_HASH_FLAG_BAD_TYPE},
1506                 {"badtype", LMV_HASH_FLAG_BAD_TYPE},
1507                 {"lost_lmv", LMV_HASH_FLAG_LOST_LMV},
1508                 {"lostlmv", LMV_HASH_FLAG_LOST_LMV},
1509         };
1510
1511         if (string == NULL)
1512                 return -EINVAL;
1513
1514         *inflags = 0;
1515         *exflags = 0;
1516         *type = 0;
1517         for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1518                 bool found = false;
1519                 int i;
1520
1521                 for (i = 0; i < ARRAY_SIZE(mhflist); i++) {
1522                         if (strcmp(name, mhflist[i].name) == 0 ||
1523                             name[0] == mhflist[i].name[0]) {
1524                                 *inflags |= mhflist[i].flag;
1525                                 found = true;
1526                         } else if (name[0] == '^' &&
1527                                    (strcmp(name + 1, mhflist[i].name) == 0 ||
1528                                     name[1] == mhflist[i].name[0])) {
1529                                 *exflags |= mhflist[i].flag;
1530                                 found = true;
1531                         }
1532                 }
1533                 if (!found) {
1534                         i = check_hashtype(name);
1535                         if (i > 0) {
1536                                 *type |= 1 << i;
1537                                 continue;
1538                         }
1539                         llapi_printf(LLAPI_MSG_ERROR,
1540                                      "%s: invalid mdt_hash value '%s'\n",
1541                                      progname, name);
1542                         return -EINVAL;
1543                 }
1544         }
1545
1546         /* don't allow to include and exclude the same flag */
1547         if (*inflags & *exflags) {
1548                 llapi_printf(LLAPI_MSG_ERROR,
1549                              "%s: include and exclude same flag '%s'\n",
1550                              progname, string);
1551                 return -EINVAL;
1552         }
1553
1554         return 0;
1555 }
1556
1557 static int mirror_str2state(char *string, __u16 *state, __u16 *neg_state)
1558 {
1559         if (!string)
1560                 return -EINVAL;
1561
1562         *state = 0;
1563         *neg_state = 0;
1564
1565         if (strncmp(string, "^", 1) == 0) {
1566                 *neg_state = llapi_layout_string_flags(string + 1);
1567                 if (*neg_state != 0)
1568                         return 0;
1569         } else {
1570                 *state = llapi_layout_string_flags(string);
1571                 if (*state != 0)
1572                         return 0;
1573         }
1574
1575         llapi_printf(LLAPI_MSG_ERROR,
1576                      "%s: mirrored file state '%s' not supported\n",
1577                      progname, string);
1578         return -EINVAL;
1579 }
1580
1581 /**
1582  * struct mirror_args - Command-line arguments for mirror(s).
1583  * @m_count:  Number of mirrors to be created with this layout.
1584  * @m_flags:  Mirror level flags, only 'prefer' is supported.
1585  * @m_layout: Mirror layout.
1586  * @m_file:   A victim file. Its layout will be split and used as a mirror.
1587  * @m_next:   Point to the next node of the list.
1588  *
1589  * Command-line arguments for mirror(s) will be parsed and stored in
1590  * a linked list that consists of this structure.
1591  */
1592 struct mirror_args {
1593         __u32                   m_count;
1594         __u32                   m_flags;
1595         struct llapi_layout     *m_layout;
1596         const char              *m_file;
1597         struct mirror_args      *m_next;
1598         bool                    m_inherit;
1599 };
1600
1601 /**
1602  * enum mirror_flags - Flags for extending a mirrored file.
1603  * @MF_NO_VERIFY: Indicates not to verify the mirror(s) from victim file(s)
1604  *             in case the victim file(s) contains the same data as the
1605  *             original mirrored file.
1606  * @MF_DESTROY: Indicates to delete the mirror from the mirrored file.
1607  * @MF_COMP_ID: specified component id instead of mirror id
1608  *
1609  * Flags for extending a mirrored file.
1610  */
1611 enum mirror_flags {
1612         MF_NO_VERIFY    = 0x1,
1613         MF_DESTROY      = 0x2,
1614         MF_COMP_ID      = 0x4,
1615         MF_COMP_POOL    = 0x8,
1616 };
1617
1618 /**
1619  * mirror_create_sanity_check() - Check mirror list.
1620  * @list:  A linked list that stores the mirror arguments.
1621  *
1622  * This function does a sanity check on @list for creating
1623  * a mirrored file.
1624  *
1625  * Return: 0 on success or a negative error code on failure.
1626  */
1627 static int mirror_create_sanity_check(const char *fname,
1628                                       struct mirror_args *list)
1629 {
1630         int rc = 0;
1631         bool has_m_file = false;
1632         char fsname[MAX_OBD_NAME + 1] = { 0 };
1633         bool has_m_layout = false;
1634
1635         if (!list)
1636                 return -EINVAL;
1637
1638         if (fname) {
1639                 rc = llapi_search_fsname(fname, fsname);
1640                 if (rc) {
1641                         fprintf(stderr,
1642                                 "error: %s: file '%s' has no fsname\n",
1643                                         progname, fname);
1644                         return rc;
1645                 }
1646         }
1647
1648         while (list) {
1649                 if (list->m_file) {
1650                         has_m_file = true;
1651                         llapi_layout_free(list->m_layout);
1652
1653                         list->m_layout =
1654                                 llapi_layout_get_by_path(list->m_file, 0);
1655                         if (!list->m_layout) {
1656                                 fprintf(stderr,
1657                                         "error: %s: file '%s' has no layout\n",
1658                                         progname, list->m_file);
1659                                 return -ENODATA;
1660                         }
1661                 } else {
1662                         has_m_layout = true;
1663                         if (!list->m_layout) {
1664                                 fprintf(stderr, "error: %s: no mirror layout\n",
1665                                         progname);
1666                                 return -EINVAL;
1667                         }
1668                 }
1669                 rc = llapi_layout_v2_sanity(list->m_layout, false, true,
1670                                             fsname);
1671                 if (rc) {
1672                         llapi_layout_sanity_perror(rc);
1673                         return rc;
1674                 }
1675
1676                 list = list->m_next;
1677         }
1678
1679         if (has_m_file && has_m_layout) {
1680                 fprintf(stderr,
1681                         "error: %s: -f <victim_file> option should not be specified with setstripe options\n",
1682                         progname);
1683                 return -EINVAL;
1684         }
1685
1686         return 0;
1687 }
1688
1689 static int mirror_set_flags(struct llapi_layout *layout, void *cbdata)
1690 {
1691         __u32 mirror_flags = *(__u32 *)cbdata;
1692         uint32_t flags;
1693         int rc;
1694
1695         rc = llapi_layout_comp_flags_get(layout, &flags);
1696         if (rc < 0)
1697                 return rc;
1698
1699         if (!flags) {
1700                 rc = llapi_layout_comp_flags_set(layout, mirror_flags);
1701                 if (rc)
1702                         return rc;
1703         }
1704
1705         return LLAPI_LAYOUT_ITER_CONT;
1706 }
1707
1708 /**
1709  * mirror_create() - Create a mirrored file.
1710  * @fname:        The file to be created.
1711  * @mirror_list:  A linked list that stores the mirror arguments.
1712  *
1713  * This function creates a mirrored file @fname with the mirror(s)
1714  * from @mirror_list.
1715  *
1716  * Return: 0 on success or a negative error code on failure.
1717  */
1718 static int mirror_create(char *fname, struct mirror_args *mirror_list)
1719 {
1720         struct llapi_layout *layout = NULL;
1721         struct mirror_args *cur_mirror = NULL;
1722         uint16_t mirror_count = 0;
1723         int i = 0;
1724         int rc = 0;
1725
1726         rc = mirror_create_sanity_check(fname, mirror_list);
1727         if (rc)
1728                 return rc;
1729
1730         cur_mirror = mirror_list;
1731         while (cur_mirror) {
1732                 rc = llapi_layout_comp_iterate(cur_mirror->m_layout,
1733                                                mirror_set_flags,
1734                                                &cur_mirror->m_flags);
1735                 if (rc) {
1736                         rc = -errno;
1737                         fprintf(stderr, "%s: failed to set mirror flags\n",
1738                                 progname);
1739                         goto error;
1740                 }
1741
1742                 for (i = 0; i < cur_mirror->m_count; i++) {
1743                         rc = llapi_layout_merge(&layout, cur_mirror->m_layout);
1744                         if (rc) {
1745                                 rc = -errno;
1746                                 fprintf(stderr,
1747                                         "error: %s: merge layout failed: %s\n",
1748                                         progname, strerror(errno));
1749                                 goto error;
1750                         }
1751                 }
1752                 mirror_count += cur_mirror->m_count;
1753                 cur_mirror = cur_mirror->m_next;
1754         }
1755
1756         if (!layout) {
1757                 fprintf(stderr, "error: %s: layout is NULL\n", progname);
1758                 return -EINVAL;
1759         }
1760
1761         rc = llapi_layout_mirror_count_set(layout, mirror_count);
1762         if (rc) {
1763                 rc = -errno;
1764                 fprintf(stderr, "error: %s: set mirror count failed: %s\n",
1765                         progname, strerror(errno));
1766                 goto error;
1767         }
1768
1769         rc = lfs_component_create(fname, O_CREAT | O_WRONLY, 0666,
1770                                   layout);
1771         if (rc >= 0) {
1772                 close(rc);
1773                 rc = 0;
1774         }
1775
1776 error:
1777         llapi_layout_free(layout);
1778         return rc;
1779 }
1780
1781 /**
1782  * Compare files and check lease on @fd.
1783  *
1784  * \retval bytes number of bytes are the same
1785  */
1786 static ssize_t mirror_file_compare(int fd_src, int fd_dst)
1787 {
1788         const size_t buflen = 4 * 1024 * 1024; /* 4M */
1789         void *buf;
1790         ssize_t bytes_done = 0;
1791         ssize_t bytes_read = 0;
1792
1793         buf = malloc(buflen * 2);
1794         if (!buf)
1795                 return -ENOMEM;
1796
1797         while (1) {
1798                 if (!llapi_lease_check(fd_src)) {
1799                         bytes_done = -EBUSY;
1800                         break;
1801                 }
1802
1803                 bytes_read = read(fd_src, buf, buflen);
1804                 if (bytes_read <= 0)
1805                         break;
1806
1807                 if (bytes_read != read(fd_dst, buf + buflen, buflen))
1808                         break;
1809
1810                 /*
1811                  * XXX: should compute the checksum on each buffer and then
1812                  * compare checksum to avoid cache collision
1813                  */
1814                 if (memcmp(buf, buf + buflen, bytes_read))
1815                         break;
1816
1817                 bytes_done += bytes_read;
1818         }
1819
1820         free(buf);
1821
1822         return bytes_done;
1823 }
1824
1825 static int mirror_extend_file(const char *fname, const char *victim_file,
1826                               enum mirror_flags mirror_flags)
1827 {
1828         int fd = -1;
1829         int fdv = -1;
1830         struct stat stbuf;
1831         struct stat stbuf_v;
1832         struct ll_ioc_lease *data = NULL;
1833         int rc;
1834
1835         fd = open(fname, O_RDWR);
1836         if (fd < 0) {
1837                 error_loc = "open source file";
1838                 rc = -errno;
1839                 goto out;
1840         }
1841
1842         fdv = open(victim_file, O_RDWR);
1843         if (fdv < 0) {
1844                 error_loc = "open target file";
1845                 rc = -errno;
1846                 goto out;
1847         }
1848
1849         if (fstat(fd, &stbuf) || fstat(fdv, &stbuf_v)) {
1850                 error_loc = "stat source or target file";
1851                 rc = -errno;
1852                 goto out;
1853         }
1854
1855         if (stbuf.st_dev != stbuf_v.st_dev) {
1856                 error_loc = "stat source and target file";
1857                 rc = -EXDEV;
1858                 goto out;
1859         }
1860
1861         /* mirrors should be of the same size */
1862         if (stbuf.st_size != stbuf_v.st_size) {
1863                 error_loc = "file sizes don't match";
1864                 rc = -EINVAL;
1865                 goto out;
1866         }
1867
1868         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1869         if (rc < 0) {
1870                 error_loc = "cannot get lease";
1871                 goto out;
1872         }
1873
1874         if (!(mirror_flags & MF_NO_VERIFY)) {
1875                 ssize_t ret;
1876                 /* mirrors should have the same contents */
1877                 ret = mirror_file_compare(fd, fdv);
1878                 if (ret != stbuf.st_size) {
1879                         error_loc = "file busy or contents don't match";
1880                         rc = ret < 0 ? ret : -EINVAL;
1881                         goto out;
1882                 }
1883         }
1884
1885         /* Get rid of caching pages from clients */
1886         rc = llapi_file_flush(fd);
1887         if (rc < 0) {
1888                 error_loc = "cannot get data version";
1889                 goto out;
1890         }
1891
1892         rc = llapi_file_flush(fdv);
1893         if (rc < 0) {
1894                 error_loc = "cannot get data version";
1895                 goto out;
1896         }
1897
1898         rc = migrate_set_timestamps(fd, &stbuf);
1899         if (rc < 0) {
1900                 error_loc = "cannot set source file timestamp";
1901                 goto out;
1902         }
1903
1904         /* Atomically put lease, merge layouts and close. */
1905         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
1906         if (!data) {
1907                 error_loc = "memory allocation";
1908                 goto out;
1909         }
1910         data->lil_mode = LL_LEASE_UNLCK;
1911         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
1912         data->lil_count = 1;
1913         data->lil_ids[0] = fdv;
1914         rc = llapi_lease_set(fd, data);
1915         if (rc < 0) {
1916                 error_loc = "cannot merge layout";
1917                 goto out;
1918         } else if (rc == 0) {
1919                 rc = -EBUSY;
1920                 error_loc = "lost lease lock";
1921                 goto out;
1922         }
1923         rc = 0;
1924
1925 out:
1926         if (data)
1927                 free(data);
1928         if (fd >= 0)
1929                 close(fd);
1930         if (fdv >= 0)
1931                 close(fdv);
1932         if (!rc)
1933                 (void) unlink(victim_file);
1934         if (rc < 0)
1935                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1936                         progname, fname, error_loc, strerror(-rc));
1937         return rc;
1938 }
1939
1940 static int mirror_extend_layout(char *name, struct llapi_layout *m_layout,
1941                                 bool inherit, uint32_t flags,
1942                                 unsigned long long bandwidth_bytes_sec,
1943                                 long stats_interval_sec)
1944 {
1945         struct llapi_layout *f_layout = NULL;
1946         struct ll_ioc_lease *data = NULL;
1947         int fd_src = -1;
1948         int fd_dst = -1;
1949         struct stat st;
1950         int rc = 0;
1951
1952         if (inherit) {
1953                 f_layout = llapi_layout_get_by_path(name, 0);
1954                 if (!f_layout) {
1955                         rc = -EINVAL;
1956                         fprintf(stderr, "%s: cannot get layout\n", progname);
1957                         goto out;
1958                 }
1959                 rc = llapi_layout_get_last_init_comp(f_layout);
1960                 if (rc) {
1961                         fprintf(stderr, "%s: cannot get the last init comp\n",
1962                                 progname);
1963                         goto out;
1964                 }
1965                 rc = llapi_layout_mirror_inherit(f_layout, m_layout);
1966                 if (rc) {
1967                         fprintf(stderr,
1968                                 "%s: cannot inherit from the last init comp\n",
1969                                 progname);
1970                         goto out;
1971                 }
1972         }
1973
1974         llapi_layout_comp_flags_set(m_layout, flags);
1975         rc = migrate_open_files(name,
1976                              LLAPI_MIGRATION_NONDIRECT | LLAPI_MIGRATION_MIRROR,
1977                              NULL, m_layout, &fd_src, &fd_dst);
1978         if (rc < 0)
1979                 goto out;
1980
1981         rc = llapi_lease_acquire(fd_src, LL_LEASE_RDLCK);
1982         if (rc < 0) {
1983                 error_loc = "cannot get lease";
1984                 goto out;
1985         }
1986
1987         rc = fstat(fd_src, &st);
1988         if (rc < 0) {
1989                 error_loc = "cannot stat source file";
1990                 goto out;
1991         }
1992
1993         if (stats_interval_sec)
1994                 printf("%s:\n", name);
1995
1996         rc = migrate_nonblock(fd_src, fd_dst, bandwidth_bytes_sec,
1997                               stats_interval_sec, NULL);
1998         if (rc < 0) {
1999                 llapi_lease_release(fd_src);
2000                 goto out;
2001         }
2002
2003         rc = migrate_set_timestamps(fd_src, &st);
2004         if (rc < 0) {
2005                 error_loc = "cannot set source file timestamp";
2006                 goto out;
2007         }
2008
2009         /* Atomically put lease, merge layouts and close. */
2010         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
2011         if (!data) {
2012                 error_loc = "memory allocation";
2013                 goto out;
2014         }
2015         data->lil_mode = LL_LEASE_UNLCK;
2016         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
2017         data->lil_count = 1;
2018         data->lil_ids[0] = fd_dst;
2019         rc = llapi_lease_set(fd_src, data);
2020         if (rc < 0) {
2021                 error_loc = "cannot merge layout";
2022                 goto out;
2023         } else if (rc == 0) {
2024                 rc = -EBUSY;
2025                 error_loc = "lost lease lock";
2026                 goto out;
2027         }
2028         rc = 0;
2029
2030 out:
2031         if (data)
2032                 free(data);
2033         if (fd_src >= 0)
2034                 close(fd_src);
2035         if (fd_dst >= 0)
2036                 close(fd_dst);
2037         if (rc < 0)
2038                 fprintf(stderr, "error: %s: %s: %s: %s\n",
2039                         progname, name, error_loc, strerror(-rc));
2040         return rc;
2041 }
2042
2043 static int mirror_extend(char *fname, struct mirror_args *mirror_list,
2044                          enum mirror_flags mirror_flags,
2045                          unsigned long long bandwidth_bytes_sec,
2046                          long stats_interval_sec)
2047 {
2048         int rc = 0;
2049
2050         while (mirror_list) {
2051                 if (mirror_list->m_file) {
2052                         rc = mirror_extend_file(fname, mirror_list->m_file,
2053                                                 mirror_flags);
2054                 } else {
2055                         __u32 mirror_count = mirror_list->m_count;
2056
2057                         while (mirror_count > 0) {
2058                                 rc = mirror_extend_layout(fname,
2059                                                         mirror_list->m_layout,
2060                                                         mirror_list->m_inherit,
2061                                                         mirror_list->m_flags,
2062                                                         bandwidth_bytes_sec,
2063                                                         stats_interval_sec);
2064                                 if (rc)
2065                                         break;
2066
2067                                 --mirror_count;
2068                         }
2069                 }
2070                 if (rc)
2071                         break;
2072
2073                 mirror_list = mirror_list->m_next;
2074         }
2075
2076         return rc;
2077 }
2078
2079 static int find_mirror_id(struct llapi_layout *layout, void *cbdata)
2080 {
2081         uint32_t id;
2082         int rc;
2083
2084         rc = llapi_layout_mirror_id_get(layout, &id);
2085         if (rc < 0)
2086                 return rc;
2087
2088         if ((__u16)id == *(__u16 *)cbdata)
2089                 return LLAPI_LAYOUT_ITER_STOP;
2090
2091         return LLAPI_LAYOUT_ITER_CONT;
2092 }
2093
2094 static int find_comp_id(struct llapi_layout *layout, void *cbdata)
2095 {
2096         uint32_t id;
2097         int rc;
2098
2099         rc = llapi_layout_comp_id_get(layout, &id);
2100         if (rc < 0)
2101                 return rc;
2102
2103         if (id == *(__u32 *)cbdata)
2104                 return LLAPI_LAYOUT_ITER_STOP;
2105
2106         return LLAPI_LAYOUT_ITER_CONT;
2107 }
2108
2109 static int find_mirror_id_by_pool(struct llapi_layout *layout, void *cbdata)
2110 {
2111         char buf[LOV_MAXPOOLNAME + 1];
2112         struct pool_to_id_cbdata *d = (void *)cbdata;
2113         uint32_t id;
2114         int rc;
2115
2116         rc = llapi_layout_pool_name_get(layout, buf, sizeof(buf));
2117         if (rc < 0)
2118                 return rc;
2119         if (strcmp(d->pool, buf))
2120                 return LLAPI_LAYOUT_ITER_CONT;
2121
2122         rc = llapi_layout_mirror_id_get(layout, &id);
2123         if (rc < 0)
2124                 return rc;
2125         d->id = id;
2126
2127         return LLAPI_LAYOUT_ITER_STOP;
2128 }
2129
2130 static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata)
2131 {
2132         char buf[LOV_MAXPOOLNAME + 1];
2133         struct pool_to_id_cbdata *d = (void *)cbdata;
2134         uint32_t id;
2135         int rc;
2136
2137         rc = llapi_layout_pool_name_get(layout, buf, sizeof(buf));
2138         if (rc < 0)
2139                 return rc;
2140         if (strcmp(d->pool, buf))
2141                 return LLAPI_LAYOUT_ITER_CONT;
2142
2143         rc = llapi_layout_comp_id_get(layout, &id);
2144         if (rc < 0)
2145                 return rc;
2146         d->id = id;
2147
2148         return LLAPI_LAYOUT_ITER_STOP;
2149 }
2150
2151 struct collect_ids_data {
2152         __u16   *cid_ids;
2153         int     cid_count;
2154         __u16   cid_exclude;
2155 };
2156
2157 static int collect_mirror_id(struct llapi_layout *layout, void *cbdata)
2158 {
2159         struct collect_ids_data *cid = cbdata;
2160         uint32_t id;
2161         int rc;
2162
2163         rc = llapi_layout_mirror_id_get(layout, &id);
2164         if (rc < 0)
2165                 return rc;
2166
2167         if ((__u16)id != cid->cid_exclude) {
2168                 int i;
2169
2170                 for (i = 0; i < cid->cid_count; i++) {
2171                         /* already collected the mirror id */
2172                         if (id == cid->cid_ids[i])
2173                                 return LLAPI_LAYOUT_ITER_CONT;
2174                 }
2175                 cid->cid_ids[cid->cid_count] = id;
2176                 cid->cid_count++;
2177         }
2178
2179         return LLAPI_LAYOUT_ITER_CONT;
2180 }
2181
2182 /**
2183  * last_non_stale_mirror() - Check if a mirror is the last non-stale mirror.
2184  * @mirror_id: Mirror id to be checked.
2185  * @layout:    Mirror component list.
2186  *
2187  * This function checks if a mirror with specified @mirror_id is the last
2188  * non-stale mirror of a layout @layout.
2189  *
2190  * Return: true or false.
2191  */
2192 static inline
2193 bool last_non_stale_mirror(__u16 mirror_id, struct llapi_layout *layout)
2194 {
2195         __u16 mirror_ids[128] = { 0 };
2196         struct collect_ids_data cid = { .cid_ids = mirror_ids,
2197                                         .cid_count = 0,
2198                                         .cid_exclude = mirror_id, };
2199         int i;
2200
2201         llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
2202
2203         for (i = 0; i < cid.cid_count; i++) {
2204                 struct llapi_resync_comp comp_array[1024] = { { 0 } };
2205                 int comp_size = 0;
2206
2207                 comp_size = llapi_mirror_find_stale(layout, comp_array,
2208                                                     ARRAY_SIZE(comp_array),
2209                                                     &mirror_ids[i], 1);
2210                 if (comp_size == 0)
2211                         return false;
2212         }
2213
2214         return true;
2215 }
2216
2217 static int mirror_split(const char *fname, __u32 id, const char *pool,
2218                         enum mirror_flags mflags, const char *victim_file)
2219 {
2220         struct llapi_layout *layout;
2221         char parent[PATH_MAX];
2222         char victim[PATH_MAX];
2223         int flags = O_CREAT | O_EXCL | O_LOV_DELAY_CREATE | O_NOFOLLOW;
2224         char *ptr;
2225         struct ll_ioc_lease *data;
2226         uint16_t mirror_count;
2227         __u32 mirror_id;
2228         int mdt_index;
2229         int fd, fdv;
2230         bool purge = true; /* delete mirror by setting fdv=fd */
2231         bool is_encrypted;
2232         int rc;
2233
2234         if (victim_file && (strcmp(fname, victim_file) == 0)) {
2235                 fprintf(stderr,
2236                         "error %s: the source file '%s' and -f file are the same\n",
2237                         progname, fname);
2238                 return -EINVAL;
2239         }
2240
2241         /* check fname contains mirror with mirror_id/comp_id */
2242         layout = llapi_layout_get_by_path(fname, 0);
2243         if (!layout) {
2244                 fprintf(stderr,
2245                         "error %s: file '%s' couldn't get layout\n",
2246                         progname, fname);
2247                 return -EINVAL;
2248         }
2249
2250         rc = llapi_layout_sanity(layout, false, true);
2251         if (rc) {
2252                 llapi_layout_sanity_perror(rc);
2253                 goto free_layout;
2254         }
2255
2256         rc = llapi_layout_mirror_count_get(layout, &mirror_count);
2257         if (rc) {
2258                 fprintf(stderr,
2259                         "error %s: file '%s' couldn't get mirror count\n",
2260                         progname, fname);
2261                 goto free_layout;
2262         }
2263         if (mirror_count < 2) {
2264                 fprintf(stderr,
2265                         "error %s: file '%s' has %d component, cannot split\n",
2266                         progname, fname, mirror_count);
2267                 goto free_layout;
2268         }
2269
2270         if (mflags & MF_COMP_POOL) {
2271                 struct pool_to_id_cbdata data = { .pool = pool };
2272
2273                 rc = llapi_layout_comp_iterate(layout, find_mirror_id_by_pool,
2274                                                &data);
2275                 mirror_id = data.id;
2276         } else if (mflags & MF_COMP_ID) {
2277                 rc = llapi_layout_comp_iterate(layout, find_comp_id, &id);
2278                 mirror_id = mirror_id_of(id);
2279         } else {
2280                 rc = llapi_layout_comp_iterate(layout, find_mirror_id, &id);
2281                 mirror_id = id;
2282         }
2283         if (rc < 0) {
2284                 fprintf(stderr, "error %s: failed to iterate layout of '%s'\n",
2285                         progname, fname);
2286                 goto free_layout;
2287         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
2288                 if (mflags & MF_COMP_POOL) {
2289                         fprintf(stderr,
2290                                 "error %s: file '%s' does not contain mirror with pool '%s'\n",
2291                                 progname, fname, pool);
2292                         goto free_layout;
2293                 } else if (mflags & MF_COMP_ID) {
2294                         fprintf(stderr,
2295                                 "error %s: file '%s' does not contain mirror with comp-id %u\n",
2296                                 progname, fname, id);
2297                         goto free_layout;
2298                 } else {
2299                         fprintf(stderr,
2300                                 "error %s: file '%s' does not contain mirror with id %u\n",
2301                                 progname, fname, id);
2302                         goto free_layout;
2303                 }
2304         }
2305
2306         if (last_non_stale_mirror(mirror_id, layout)) {
2307                 rc = -EUCLEAN;
2308                 fprintf(stderr,
2309                         "%s: cannot destroy the last non-stale mirror of file '%s'\n",
2310                         progname, fname);
2311                 goto free_layout;
2312         }
2313
2314         if (!victim_file && mflags & MF_DESTROY)
2315                 /* Allow mirror split even without the key on encrypted files,
2316                  * and in this case of a 'split -d', open file with O_DIRECT
2317                  * (no IOs will be done).
2318                  */
2319                 fd = open(fname, O_RDWR | O_DIRECT | O_CIPHERTEXT);
2320         else
2321                 fd = open(fname, O_RDWR);
2322
2323         if (fd < 0) {
2324                 fprintf(stderr,
2325                         "error %s: open file '%s' failed: %s\n",
2326                         progname, fname, strerror(errno));
2327                 goto free_layout;
2328         }
2329
2330         /* get victim file directory pathname */
2331         if (strlen(fname) > sizeof(parent) - 1) {
2332                 fprintf(stderr, "error %s: file name of '%s' too long\n",
2333                         progname, fname);
2334                 rc = -ERANGE;
2335                 goto close_fd;
2336         }
2337         strncpy(parent, fname, sizeof(parent));
2338         ptr = strrchr(parent, '/');
2339         if (!ptr) {
2340                 if (!getcwd(parent, sizeof(parent))) {
2341                         fprintf(stderr, "error %s: getcwd failed: %s\n",
2342                                 progname, strerror(errno));
2343                         rc = -errno;
2344                         goto close_fd;
2345                 }
2346         } else {
2347                 if (ptr == parent)
2348                         ptr = parent + 1;
2349                 *ptr = '\0';
2350         }
2351
2352         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
2353         if (rc < 0) {
2354                 fprintf(stderr, "%s: cannot get MDT index of '%s'\n",
2355                         progname, fname);
2356                 goto close_fd;
2357         }
2358
2359         rc = llapi_file_is_encrypted(fd);
2360         if (rc < 0) {
2361                 fprintf(stderr, "%s: cannot get flags of '%s': %d\n",
2362                         progname, fname, rc);
2363                 goto close_fd;
2364         }
2365         is_encrypted = rc;
2366
2367 again:
2368         if (!victim_file) {
2369                 /* use a temp file to store the splitted layout */
2370                 if (mflags & MF_DESTROY) {
2371                         char file_path[PATH_MAX];
2372                         unsigned int rnumber;
2373                         int open_flags;
2374
2375                         if (last_non_stale_mirror(mirror_id, layout)) {
2376                                 rc = -EUCLEAN;
2377                                 fprintf(stderr,
2378                                         "%s: cannot destroy the last non-stale mirror of file '%s'\n",
2379                                         progname, fname);
2380                                 goto close_fd;
2381                         }
2382
2383                         if (purge) {
2384                                 /* don't use volatile file for mirror destroy */
2385                                 fdv = fd;
2386                         } else {
2387                                 /**
2388                                  * try the old way to delete mirror using
2389                                  * volatile file.
2390                                  */
2391                                 do {
2392                                         rnumber = random();
2393                                         rc = snprintf(file_path,
2394                                                       sizeof(file_path),
2395                                                       "%s/" LUSTRE_VOLATILE_HDR ":%.4X:%.4X:fd=%.2d",
2396                                                       parent, mdt_index,
2397                                                       rnumber, fd);
2398                                         if (rc < 0 ||
2399                                             rc >= sizeof(file_path)) {
2400                                                 fdv = -ENAMETOOLONG;
2401                                                 break;
2402                                         }
2403
2404                                         open_flags = O_RDWR |
2405                                              (O_LOV_DELAY_CREATE & ~O_ACCMODE) |
2406                                              O_CREAT | O_EXCL | O_NOFOLLOW |
2407                                              /* O_DIRECT for mirror split -d */
2408                                              O_DIRECT |
2409                                              /* Allow split without the key */
2410                                              O_CIPHERTEXT;
2411                                         fdv = open(file_path, open_flags,
2412                                                    S_IRUSR | S_IWUSR);
2413                                         if (fdv < 0)
2414                                                 rc = -errno;
2415                                 } while (fdv < 0 && rc == -EEXIST);
2416                         }
2417                 } else {
2418                         if (is_encrypted) {
2419                                 rc = -1;
2420                                 fprintf(stderr,
2421                                         "error %s: not permitted on encrypted file '%s': %d\n",
2422                                         progname, fname, rc);
2423                                 goto close_fd;
2424                         }
2425
2426                         snprintf(victim, sizeof(victim), "%s.mirror~%u",
2427                                  fname, mirror_id);
2428                         fdv = open(victim, flags, S_IRUSR | S_IWUSR);
2429                 }
2430         } else {
2431                 /* user specified victim file */
2432                 if (is_encrypted) {
2433                         rc = -1;
2434                         fprintf(stderr,
2435                                 "error %s: not permitted on encrypted file '%s': %d\n",
2436                                 progname, fname, rc);
2437                         goto close_fd;
2438                 }
2439                 fdv = open(victim_file, flags, S_IRUSR | S_IWUSR);
2440         }
2441
2442         if (fdv < 0) {
2443                 fprintf(stderr,
2444                         "error %s: create victim file failed: %s\n",
2445                         progname, strerror(errno));
2446                 goto close_fd;
2447         }
2448
2449         /* get lease lock of fname */
2450         rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
2451         if (rc < 0) {
2452                 fprintf(stderr,
2453                         "error %s: cannot get lease of file '%s': %d\n",
2454                         progname, fname, rc);
2455                 goto close_victim;
2456         }
2457
2458         /* Atomatically put lease, split layouts and close. */
2459         data = malloc(offsetof(typeof(*data), lil_ids[2]));
2460         if (!data) {
2461                 rc = -ENOMEM;
2462                 goto close_victim;
2463         }
2464
2465         data->lil_mode = LL_LEASE_UNLCK;
2466         data->lil_flags = LL_LEASE_LAYOUT_SPLIT;
2467         data->lil_count = 2;
2468         data->lil_ids[0] = fdv;
2469         data->lil_ids[1] = mirror_id;
2470         rc = llapi_lease_set(fd, data);
2471         if (rc <= 0) {
2472                 if ((rc == -EINVAL || rc == -EBUSY) && purge) {
2473                         /* could be old MDS which prohibit fd==fdv */
2474                         purge = false;
2475                         goto again;
2476
2477                 }
2478                 if (rc == 0) /* lost lease lock */
2479                         rc = -EBUSY;
2480                 fprintf(stderr,
2481                         "error %s: cannot split '%s': %s\n",
2482                         progname, fname, strerror(-rc));
2483         } else {
2484                 rc = 0;
2485         }
2486         free(data);
2487
2488 close_victim:
2489         if (!purge)
2490                 close(fdv);
2491 close_fd:
2492         close(fd);
2493 free_layout:
2494         llapi_layout_free(layout);
2495         return rc;
2496 }
2497
2498 static inline
2499 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
2500                            __u16 *mirror_ids, int ids_nr,
2501                            long stats_interval_sec, long bandwidth_bytes_sec);
2502
2503
2504 static int lfs_migrate_to_dom(int fd_src, int fd_dst, char *name,
2505                               __u64 migration_flags,
2506                               unsigned long long bandwidth_bytes_sec,
2507                               long stats_interval_sec)
2508 {
2509         struct ll_ioc_lease *data = NULL;
2510         int rc;
2511
2512         rc = llapi_lease_acquire(fd_src, LL_LEASE_RDLCK);
2513         if (rc < 0) {
2514                 error_loc = "cannot get lease";
2515                 goto out_close;
2516         }
2517
2518         if (stats_interval_sec)
2519                 printf("%s:\n", name);
2520
2521         rc = migrate_nonblock(fd_src, fd_dst, bandwidth_bytes_sec,
2522                               stats_interval_sec, NULL);
2523         if (rc < 0)
2524                 goto out_release;
2525
2526         /* Atomically put lease, merge layouts, resync and close. */
2527         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
2528         if (!data) {
2529                 error_loc = "memory allocation";
2530                 goto out_release;
2531         }
2532         data->lil_mode = LL_LEASE_UNLCK;
2533         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
2534         data->lil_count = 1;
2535         data->lil_ids[0] = fd_dst;
2536         rc = llapi_lease_set(fd_src, data);
2537         if (rc < 0) {
2538                 error_loc = "cannot merge layout";
2539                 goto out_close;
2540         } else if (rc == 0) {
2541                 rc = -EBUSY;
2542                 error_loc = "lost lease lock";
2543                 goto out_close;
2544         }
2545         close(fd_src);
2546         close(fd_dst);
2547
2548         rc = lfs_mirror_resync_file(name, data, NULL, 0,
2549                                     stats_interval_sec,
2550                                     bandwidth_bytes_sec);
2551         if (rc) {
2552                 error_loc = "cannot resync file";
2553                 goto out;
2554         }
2555
2556         /* delete first mirror now */
2557         rc = mirror_split(name, 1, NULL, MF_DESTROY, NULL);
2558         if (rc < 0)
2559                 error_loc = "cannot delete old layout";
2560         goto out;
2561
2562 out_release:
2563         llapi_lease_release(fd_src);
2564 out_close:
2565         close(fd_src);
2566         close(fd_dst);
2567 out:
2568         if (rc < 0)
2569                 fprintf(stderr, "error: %s: %s: %s: %s\n",
2570                         progname, name, error_loc, strerror(-rc));
2571         else if (migration_flags & LLAPI_MIGRATION_VERBOSE)
2572                 printf("%s\n", name);
2573         if (data)
2574                 free(data);
2575         return rc;
2576 }
2577
2578 /**
2579  * Parse a string containing an target index list into an array of integers.
2580  *
2581  * The input string contains a comma delimited list of individual
2582  * indices and ranges, for example "1,2-4,7". Add the indices into the
2583  * \a tgts array and remove duplicates.
2584  *
2585  * \param[out] tgts             array to store indices in
2586  * \param[in] size              size of \a tgts array
2587  * \param[in] offset            starting index in \a tgts
2588  * \param[in] arg               string containing OST index list
2589  * \param[out] duplicates       tell caller list contains duplicates
2590  *
2591  * \retval positive    number of indices in \a tgts
2592  * \retval -EINVAL     unable to parse \a arg
2593  */
2594 static int parse_targets(__u32 *tgts, int size, int offset, char *arg,
2595                          bool *duplicates)
2596 {
2597         int rc;
2598         int nr = offset;
2599         int slots = size - offset;
2600         char *ptr = NULL;
2601         bool end_of_loop;
2602
2603         if (!arg)
2604                 return -EINVAL;
2605
2606         end_of_loop = false;
2607         while (!end_of_loop) {
2608                 int start_index = 0;
2609                 int end_index = 0;
2610                 int i;
2611                 char *endptr = NULL;
2612
2613                 rc = -EINVAL;
2614
2615                 ptr = strchrnul(arg, ',');
2616
2617                 end_of_loop = *ptr == '\0';
2618                 *ptr = '\0';
2619
2620                 errno = 0;
2621                 start_index = strtol(arg, &endptr, 0);
2622                 if (endptr == arg) /* no data at all */
2623                         break;
2624                 if (errno != 0 || start_index < -1 ||
2625                     (*endptr != '-' && *endptr != '\0'))
2626                         break;
2627
2628                 end_index = start_index;
2629                 if (*endptr == '-') {
2630                         errno = 0;
2631                         end_index = strtol(endptr + 1, &endptr, 0);
2632                         if (errno != 0 || *endptr != '\0' || end_index < -1)
2633                                 break;
2634                         if (end_index < start_index)
2635                                 break;
2636                 }
2637
2638                 for (i = start_index; i <= end_index && slots > 0; i++) {
2639                         int j;
2640
2641                         /* note presence of duplicates */
2642                         for (j = 0; j < offset; j++) {
2643                                 if (tgts[j] == i)
2644                                         *duplicates = true;
2645                         }
2646
2647                         j = offset;
2648
2649                         if (j == offset) { /* check complete */
2650                                 tgts[nr++] = i;
2651                                 --slots;
2652                         }
2653                 }
2654
2655                 if (slots == 0 && i < end_index)
2656                         break;
2657
2658                 *ptr = ',';
2659                 arg = ++ptr;
2660                 offset = nr;
2661                 rc = 0;
2662         }
2663         if (!end_of_loop && ptr)
2664                 *ptr = ',';
2665
2666         return rc < 0 ? rc : nr;
2667 }
2668
2669 struct lfs_setstripe_args {
2670         unsigned long long       lsa_comp_end;
2671         unsigned long long       lsa_stripe_size;
2672         unsigned long long       lsa_extension_size;
2673         long long                lsa_stripe_count;
2674         long long                lsa_stripe_off;
2675         __u32                    lsa_comp_flags;
2676         __u32                    lsa_comp_neg_flags;
2677         unsigned long long       lsa_pattern;
2678         unsigned int             lsa_mirror_count;
2679         int                      lsa_nr_tgts;
2680         bool                     lsa_first_comp;
2681         bool                     lsa_extension_comp;
2682         __u32                   *lsa_tgts;
2683         char                    *lsa_pool_name;
2684 };
2685
2686 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
2687 {
2688         unsigned int mirror_count = lsa->lsa_mirror_count;
2689         bool first_comp = lsa->lsa_first_comp;
2690
2691         memset(lsa, 0, sizeof(*lsa));
2692
2693         lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
2694         lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
2695         lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2696         lsa->lsa_pattern = LLAPI_LAYOUT_RAID0;
2697         lsa->lsa_pool_name = NULL;
2698
2699         lsa->lsa_mirror_count = mirror_count;
2700         lsa->lsa_first_comp = first_comp;
2701 }
2702
2703 /**
2704  * setstripe_args_init_inherit() - Initialize and inherit stripe options.
2705  * @lsa: Stripe options to be initialized and inherited.
2706  *
2707  * This function initializes stripe options in @lsa and inherit
2708  * stripe_size, stripe_count and OST pool_name options.
2709  *
2710  * Return: void.
2711  */
2712 static inline void setstripe_args_init_inherit(struct lfs_setstripe_args *lsa)
2713 {
2714         unsigned long long stripe_size;
2715         long long stripe_count;
2716         char *pool_name = NULL;
2717
2718         stripe_size = lsa->lsa_stripe_size;
2719         stripe_count = lsa->lsa_stripe_count;
2720         pool_name = lsa->lsa_pool_name;
2721
2722         setstripe_args_init(lsa);
2723
2724         lsa->lsa_stripe_size = stripe_size;
2725         lsa->lsa_stripe_count = stripe_count;
2726         lsa->lsa_pool_name = pool_name;
2727 }
2728
2729 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
2730 {
2731         return (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT ||
2732                 lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ||
2733                 lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
2734                 lsa->lsa_pattern != LLAPI_LAYOUT_RAID0 ||
2735                 lsa->lsa_comp_end != 0);
2736 }
2737
2738 static int lsa_args_stripe_count_check(struct lfs_setstripe_args *lsa)
2739 {
2740         if (lsa->lsa_nr_tgts) {
2741                 if (lsa->lsa_nr_tgts < 0 ||
2742                     lsa->lsa_nr_tgts >= LOV_MAX_STRIPE_COUNT) {
2743                         fprintf(stderr, "Invalid nr_tgts(%d)\n",
2744                                 lsa->lsa_nr_tgts);
2745                         errno = EINVAL;
2746                         return -1;
2747                 }
2748
2749                 if (lsa->lsa_stripe_count > 0 &&
2750                     lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
2751                     lsa->lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
2752                     lsa->lsa_nr_tgts != lsa->lsa_stripe_count) {
2753                         fprintf(stderr, "stripe_count(%lld) != nr_tgts(%d)\n",
2754                                 lsa->lsa_stripe_count,
2755                                 lsa->lsa_nr_tgts);
2756                         errno = EINVAL;
2757                         return -1;
2758                 }
2759         }
2760
2761         return 0;
2762
2763 }
2764
2765 /**
2766  * comp_args_to_layout() - Create or extend a composite layout.
2767  * @composite:       Pointer to the composite layout.
2768  * @lsa:             Stripe options for the new component.
2769  *
2770  * This function creates or extends a composite layout by adding a new
2771  * component with stripe options from @lsa.
2772  *
2773  * When modified, adjust llapi_stripe_param_verify() if needed as well.
2774  *
2775  * Return: 0 on success or an error code on failure.
2776  */
2777 static int comp_args_to_layout(struct llapi_layout **composite,
2778                                struct lfs_setstripe_args *lsa,
2779                                bool set_extent)
2780 {
2781         struct llapi_layout *layout = *composite;
2782         uint64_t prev_end = 0;
2783         uint64_t size;
2784         int i = 0, rc;
2785
2786 new_comp:
2787         if (!layout) {
2788                 layout = llapi_layout_alloc();
2789                 if (!layout) {
2790                         fprintf(stderr, "Alloc llapi_layout failed. %s\n",
2791                                 strerror(errno));
2792                         errno = ENOMEM;
2793                         return -1;
2794                 }
2795                 *composite = layout;
2796                 lsa->lsa_first_comp = true;
2797         } else {
2798                 uint64_t start;
2799
2800                 /*
2801                  * Get current component extent, current component
2802                  * must be the tail component.
2803                  */
2804                 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
2805                 if (rc) {
2806                         fprintf(stderr, "Get comp extent failed. %s\n",
2807                                 strerror(errno));
2808                         return rc;
2809                 }
2810
2811                 if (lsa->lsa_first_comp) {
2812                         prev_end = 0;
2813                         rc = llapi_layout_add_first_comp(layout);
2814                 } else {
2815                         rc = llapi_layout_comp_add(layout);
2816                 }
2817                 if (rc) {
2818                         fprintf(stderr, "Add component failed. %s\n",
2819                                 strerror(errno));
2820                         return rc;
2821                 }
2822         }
2823
2824         rc = llapi_layout_comp_flags_set(layout, lsa->lsa_comp_flags);
2825         if (rc) {
2826                 fprintf(stderr, "Set flags 0x%x failed: %s\n",
2827                         lsa->lsa_comp_flags, strerror(errno));
2828                 return rc;
2829         }
2830
2831         if (set_extent) {
2832                 uint64_t comp_end = lsa->lsa_comp_end;
2833
2834                 /*
2835                  * The extendable component is 0-length, so it can be removed
2836                  * if there is insufficient space to extend it.
2837                  */
2838                 if (lsa->lsa_extension_comp)
2839                         comp_end = prev_end;
2840
2841                 rc = llapi_layout_comp_extent_set(layout, prev_end,
2842                                                   comp_end);
2843                 if (rc) {
2844                         fprintf(stderr, "Set extent [%lu, %lu) failed. %s\n",
2845                                 prev_end, comp_end, strerror(errno));
2846                         return rc;
2847                 }
2848         }
2849         /* reset lsa_first_comp */
2850         lsa->lsa_first_comp = false;
2851
2852         /* Data-on-MDT component setting */
2853         if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
2854                 /* Yaml support */
2855                 if (lsa->lsa_stripe_count == 0)
2856                         lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
2857                 if (lsa->lsa_stripe_size == lsa->lsa_comp_end)
2858                         lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
2859                 if (lsa->lsa_stripe_off == -1 ||
2860                     lsa->lsa_stripe_off == 0)
2861                         lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2862                 /*
2863                  * In case of Data-on-MDT patterns the only extra option
2864                  * applicable is stripe size option.
2865                  */
2866                 if (lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
2867                         fprintf(stderr,
2868                                 "Option 'stripe-count' can't be specified with Data-on-MDT component: %lld\n",
2869                                 lsa->lsa_stripe_count);
2870                         errno = EINVAL;
2871                         return -1;
2872                 }
2873                 if (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT &&
2874                     lsa->lsa_stripe_size != lsa->lsa_comp_end - prev_end) {
2875                         fprintf(stderr,
2876                                 "Option 'stripe-size' can't be specified with Data-on-MDT component: %llu\n",
2877                                 lsa->lsa_stripe_size);
2878                         errno = EINVAL;
2879                         return -1;
2880                 }
2881                 if (lsa->lsa_nr_tgts != 0) {
2882                         fprintf(stderr,
2883                                 "Option 'ost-list' can't be specified with Data-on-MDT component: '%i'\n",
2884                                 lsa->lsa_nr_tgts);
2885                         errno = EINVAL;
2886                         return -1;
2887                 }
2888                 if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
2889                         fprintf(stderr,
2890                                 "Option 'stripe-offset' can't be specified with Data-on-MDT component: %lld\n",
2891                                 lsa->lsa_stripe_off);
2892                         errno = EINVAL;
2893                         return -1;
2894                 }
2895                 if (lsa->lsa_pool_name != 0) {
2896                         fprintf(stderr,
2897                                 "Option 'pool' can't be specified with Data-on-MDT component: '%s'\n",
2898                                 lsa->lsa_pool_name);
2899                         errno = EINVAL;
2900                         return -1;
2901                 }
2902
2903                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
2904                 if (rc) {
2905                         fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
2906                                 lsa->lsa_pattern,
2907                                 strerror(errno));
2908                         return rc;
2909                 }
2910                 /* Data-on-MDT component has always single stripe up to end */
2911                 lsa->lsa_stripe_size = lsa->lsa_comp_end;
2912         } else if (lsa->lsa_pattern == LLAPI_LAYOUT_OVERSTRIPING) {
2913                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
2914                 if (rc) {
2915                         fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
2916                                 lsa->lsa_pattern,
2917                                 strerror(errno));
2918                         return rc;
2919                 }
2920         }
2921
2922         size = lsa->lsa_comp_flags & LCME_FL_EXTENSION ?
2923                 lsa->lsa_extension_size : lsa->lsa_stripe_size;
2924
2925         if (lsa->lsa_comp_flags & LCME_FL_EXTENSION)
2926                 rc = llapi_layout_extension_size_set(layout, size);
2927         else
2928                 rc = llapi_layout_stripe_size_set(layout, size);
2929
2930         if (rc) {
2931                 fprintf(stderr, "Set stripe size %lu failed: %s\n",
2932                         size, strerror(errno));
2933                 return rc;
2934         }
2935
2936         rc = llapi_layout_stripe_count_set(layout, lsa->lsa_stripe_count);
2937         if (rc) {
2938                 fprintf(stderr, "Set stripe count %lld failed: %s\n",
2939                         lsa->lsa_stripe_count, strerror(errno));
2940                 return rc;
2941         }
2942
2943         if (lsa->lsa_pool_name) {
2944                 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
2945                 if (rc) {
2946                         fprintf(stderr, "Set pool name: %s failed. %s\n",
2947                                 lsa->lsa_pool_name, strerror(errno));
2948                         return rc;
2949                 }
2950         } else {
2951                 rc = llapi_layout_pool_name_set(layout, "");
2952                 if (rc) {
2953                         fprintf(stderr, "Clear pool name failed: %s\n",
2954                                 strerror(errno));
2955                         return rc;
2956                 }
2957         }
2958
2959         rc = lsa_args_stripe_count_check(lsa);
2960         if (rc)
2961                 return rc;
2962
2963         if (lsa->lsa_nr_tgts > 0) {
2964                 bool found = false;
2965
2966                 for (i = 0; i < lsa->lsa_nr_tgts; i++) {
2967                         rc = llapi_layout_ost_index_set(layout, i,
2968                                                         lsa->lsa_tgts[i]);
2969                         if (rc)
2970                                 break;
2971
2972                         /* Make sure stripe offset is in OST list. */
2973                         if (lsa->lsa_tgts[i] == lsa->lsa_stripe_off)
2974                                 found = true;
2975                 }
2976                 if (!found) {
2977                         fprintf(stderr, "Invalid stripe offset '%lld', not in the target list",
2978                                 lsa->lsa_stripe_off);
2979                         errno = EINVAL;
2980                         return -1;
2981                 }
2982         } else if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT &&
2983                    lsa->lsa_stripe_off != -1) {
2984                 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
2985         }
2986         if (rc) {
2987                 fprintf(stderr, "Set ost index %d failed. %s\n",
2988                         i, strerror(errno));
2989                 return rc;
2990         }
2991
2992         /* Create the second, virtual component of extension space */
2993         if (lsa->lsa_extension_comp) {
2994                 lsa->lsa_comp_flags |= LCME_FL_EXTENSION;
2995                 lsa->lsa_extension_comp = false;
2996                 goto new_comp;
2997         }
2998
2999         return rc;
3000 }
3001
3002 static int build_component(struct llapi_layout **layout,
3003                            struct lfs_setstripe_args *lsa, bool set_extent)
3004 {
3005         int rc;
3006
3007         rc = comp_args_to_layout(layout, lsa, set_extent);
3008         if (rc)
3009                 return rc;
3010
3011         if (lsa->lsa_mirror_count > 0) {
3012                 rc = llapi_layout_mirror_count_set(*layout,
3013                                                    lsa->lsa_mirror_count);
3014                 if (rc)
3015                         return rc;
3016
3017                 rc = llapi_layout_flags_set(*layout, LCM_FL_RDONLY);
3018                 if (rc)
3019                         return rc;
3020                 lsa->lsa_mirror_count = 0;
3021         }
3022
3023         return rc;
3024 }
3025
3026 static int build_prev_component(struct llapi_layout **layout,
3027                                 struct lfs_setstripe_args *prev,
3028                                 struct lfs_setstripe_args *lsa,
3029                                 bool set_extent)
3030 {
3031         int extension = lsa->lsa_comp_flags & LCME_FL_EXTENSION;
3032         int rc;
3033
3034         if (prev->lsa_stripe_size) {
3035                 if (extension) {
3036                         prev->lsa_comp_end = lsa->lsa_comp_end;
3037                         prev->lsa_extension_size = lsa->lsa_extension_size;
3038                         prev->lsa_extension_comp = true;
3039                 }
3040
3041                 rc = build_component(layout, prev, true);
3042                 if (rc)
3043                         return rc;
3044         }
3045
3046         /*
3047          * Copy lsa to previous lsa;
3048          * if this is an extension component, make the previous invalid;
3049          */
3050         if (extension)
3051                 prev->lsa_stripe_size = 0;
3052         else
3053                 *prev = *lsa;
3054
3055         return 0;
3056 }
3057
3058 #ifndef LCME_TEMPLATE_FLAGS
3059 #define LCME_TEMPLATE_FLAGS     (LCME_FL_PREF_RW | LCME_FL_NOSYNC | \
3060                                  LCME_FL_EXTENSION)
3061 #endif
3062
3063 static int build_layout_from_yaml_node(struct cYAML *node,
3064                                        struct llapi_layout **layout,
3065                                        struct lfs_setstripe_args *lsa,
3066                                        struct lfs_setstripe_args *prevp)
3067 {
3068         struct lfs_setstripe_args prev = { 0 };
3069         __u32 *osts = lsa->lsa_tgts;
3070         char *string;
3071         int rc = 0;
3072
3073         if (!prevp)
3074                 prevp = &prev;
3075
3076         while (node) {
3077                 string = node->cy_string;
3078
3079                 if (node->cy_type == CYAML_TYPE_OBJECT) {
3080                         /* go deep to sub blocks */
3081                         if (string && !strncmp(string, "component", 9) &&
3082                             strncmp(string, "component0", 10) &&
3083                             strncmp(string, "components", 10)) {
3084                                 rc = build_prev_component(layout, prevp, lsa,
3085                                                           true);
3086                                 if (rc)
3087                                         return rc;
3088
3089                                 /* initialize lsa. */
3090                                 setstripe_args_init(lsa);
3091                                 lsa->lsa_first_comp = false;
3092                                 lsa->lsa_tgts = osts;
3093                         }
3094
3095                         rc = build_layout_from_yaml_node(node->cy_child, layout,
3096                                                          lsa, prevp);
3097                         if (rc)
3098                                 return rc;
3099                 } else {
3100                         if (!node->cy_string)
3101                                 return -EINVAL;
3102
3103                         /* skip leading lmm_ if present, to simplify parsing */
3104                         if (strncmp(string, "lmm_", 4) == 0)
3105                                 string += 4;
3106
3107                         if (node->cy_type == CYAML_TYPE_STRING) {
3108                                 if (!strcmp(string, "lcme_extent.e_end")) {
3109                                         if (!strcmp(node->cy_valuestring, "EOF") ||
3110                                             !strcmp(node->cy_valuestring, "eof"))
3111                                                 lsa->lsa_comp_end = LUSTRE_EOF;
3112                                 } else if (!strcmp(string, "pool")) {
3113                                         lsa->lsa_pool_name = node->cy_valuestring;
3114                                 } else if (!strcmp(string, "pattern")) {
3115                                         if (!strcmp(node->cy_valuestring, "mdt"))
3116                                                 lsa->lsa_pattern = LLAPI_LAYOUT_MDT;
3117                                         if (!strcmp(node->cy_valuestring,
3118                                                     "raid0,overstriped"))
3119                                                 lsa->lsa_pattern =
3120                                                         LLAPI_LAYOUT_OVERSTRIPING;
3121                                 } else if (!strcmp(string, "lcme_flags")) {
3122                                         rc = comp_str2flags(node->cy_valuestring,
3123                                                             &lsa->lsa_comp_flags,
3124                                                             &lsa->lsa_comp_neg_flags);
3125                                         if (rc)
3126                                                 return rc;
3127                                         /*
3128                                          * Only template flags have meaning in
3129                                          * the layout for a new file
3130                                          */
3131                                         lsa->lsa_comp_flags &= LCME_TEMPLATE_FLAGS;
3132                                 }
3133                         } else if (node->cy_type == CYAML_TYPE_NUMBER) {
3134                                 if (!strcmp(string, "lcm_mirror_count")) {
3135                                         lsa->lsa_mirror_count = node->cy_valueint;
3136                                 } else if (!strcmp(string, "lcme_extent.e_start")) {
3137                                         if (node->cy_valueint == 0)
3138                                                 lsa->lsa_first_comp = true;
3139                                 } else if (!strcmp(string, "lcme_extent.e_end")) {
3140                                         if (node->cy_valueint == -1)
3141                                                 lsa->lsa_comp_end = LUSTRE_EOF;
3142                                         else
3143                                                 lsa->lsa_comp_end = node->cy_valueint;
3144                                 } else if (!strcmp(string, "stripe_count")) {
3145                                         lsa->lsa_stripe_count = node->cy_valueint;
3146                                 } else if (!strcmp(string, "stripe_size")) {
3147                                         lsa->lsa_stripe_size = node->cy_valueint;
3148                                 } else if (!strcmp(string, "extension_size")) {
3149                                         lsa->lsa_extension_size = node->cy_valueint;
3150                                         lsa->lsa_extension_comp = true;
3151                                 } else if (!strcmp(string, "stripe_offset")) {
3152                                         lsa->lsa_stripe_off = node->cy_valueint;
3153                                 } else if (!strcmp(string, "l_ost_idx")) {
3154                                         osts[lsa->lsa_nr_tgts] = node->cy_valueint;
3155                                         lsa->lsa_nr_tgts++;
3156                                 }
3157                         }
3158                 }
3159                 node = node->cy_next;
3160         }
3161
3162         if (prevp == &prev) {
3163                 rc = build_prev_component(layout, prevp, lsa, true);
3164                 if (rc)
3165                         return rc;
3166
3167                 if (!(lsa->lsa_comp_flags & LCME_FL_EXTENSION))
3168                         rc = build_component(layout, lsa, *layout != NULL);
3169         }
3170
3171         return rc;
3172 }
3173
3174 static int lfs_comp_create_from_yaml(char *template,
3175                                      struct llapi_layout **layout,
3176                                      struct lfs_setstripe_args *lsa,
3177                                      __u32 *osts)
3178 {
3179         struct cYAML *tree = NULL, *err_rc = NULL;
3180         int rc = 0;
3181
3182         tree = cYAML_build_tree(template, NULL, 0, &err_rc, false);
3183         if (!tree) {
3184                 fprintf(stderr, "%s: cannot parse YAML file %s\n",
3185                         progname, template);
3186                 cYAML_build_error(-EINVAL, -1, "yaml", "from comp yaml",
3187                                   "can't parse", &err_rc);
3188                 cYAML_print_tree2file(stderr, err_rc);
3189                 cYAML_free_tree(err_rc);
3190                 rc = -EINVAL;
3191                 goto err;
3192         }
3193
3194         /* initialize lsa for plain file */
3195         setstripe_args_init(lsa);
3196         lsa->lsa_tgts = osts;
3197
3198         rc = build_layout_from_yaml_node(tree, layout, lsa, NULL);
3199         if (rc) {
3200                 fprintf(stderr, "%s: cannot build layout from YAML file %s.\n",
3201                         progname, template);
3202                 goto err;
3203         }
3204         /* clean clean lsa */
3205         setstripe_args_init(lsa);
3206
3207 err:
3208         if (tree)
3209                 cYAML_free_tree(tree);
3210         return rc;
3211 }
3212
3213 /**
3214  * Get the extension size from the next (SEL) component and extend the
3215  * current component on it. The start of the next component is to be
3216  * adjusted as well.
3217  *
3218  * \param[in] layout    the current layout
3219  * \param[in] start     the start of the current component
3220  * \param[in,out] end   the end of the current component
3221  * \param[in] offset    the offset to adjust the end position to instead of
3222  *                      extension size
3223  *
3224  * \retval 0            - extended successfully
3225  * \retval < 0          - error
3226  */
3227 static int layout_extend_comp(struct llapi_layout *layout,
3228                               uint64_t start, uint64_t *end,
3229                               uint64_t offset)
3230 {
3231         uint64_t size, next_start, next_end;
3232         int rc;
3233
3234         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
3235         if (rc < 0) {
3236                 fprintf(stderr,
3237                         "%s setstripe: cannot move component cursor: %s\n",
3238                         progname, strerror(errno));
3239                 return rc;
3240         }
3241
3242         /*
3243          * Even if the @size will not be used below, this will fail if
3244          * this is not a SEL component - a good confirmation we are
3245          * working on right components.
3246          */
3247         rc = llapi_layout_extension_size_get(layout, &size);
3248         if (rc < 0) {
3249                 fprintf(stderr,
3250                         "%s setstripe: cannot get component ext size: %s\n",
3251                         progname, strerror(errno));
3252                 return rc;
3253         }
3254
3255         rc = llapi_layout_comp_extent_get(layout, &next_start, &next_end);
3256         if (rc) {
3257                 fprintf(stderr, "%s setstripe: cannot get extent: %s\n",
3258                         progname, strerror(errno));
3259                 return rc;
3260         }
3261
3262         next_start += offset ?: size;
3263         rc = llapi_layout_comp_extent_set(layout, next_start, next_end);
3264         if (rc) {
3265                 fprintf(stderr, "%s setstripe: cannot set extent: %s\n",
3266                         progname, strerror(errno));
3267                 return rc;
3268         }
3269
3270         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_PREV);
3271         if (rc < 0) {
3272                 fprintf(stderr,
3273                         "%s setstripe: cannot move component cursor: %s\n",
3274                         progname, strerror(errno));
3275                 return rc;
3276         }
3277
3278         *end += offset ?: size;
3279         rc = llapi_layout_comp_extent_set(layout, start, *end);
3280         if (rc) {
3281                 fprintf(stderr, "%s setstripe: cannot set extent: %s\n",
3282                         progname, strerror(errno));
3283                 return rc;
3284         }
3285
3286         return 0;
3287 }
3288
3289 /**
3290  * In 'lfs setstripe --component-add' mode, we need to fetch the extent
3291  * end of the last component in the existing file, and adjust the
3292  * first extent start of the components to be added accordingly.
3293  *
3294  * In the create mode, we need to check if the first component is an extendable
3295  * SEL component and extend its length to the extension size (first component
3296  * of the PFL file is initialised at the create time, cannot be 0-lenght.
3297  */
3298 static int layout_adjust_first_extent(char *fname, struct llapi_layout *layout,
3299                                       bool comp_add)
3300 {
3301         struct llapi_layout *head;
3302         uint64_t start = 0, prev_end = 0;
3303         uint64_t end;
3304         int rc, ret = 0;
3305
3306         if (!layout || !(comp_add || llapi_layout_is_composite(layout)))
3307                 return 0;
3308
3309         errno = 0;
3310         while (comp_add) {
3311                 head = llapi_layout_get_by_path(fname, 0);
3312                 if (!head) {
3313                         fprintf(stderr,
3314                                 "%s setstripe: cannot read layout from '%s': %s\n",
3315                                 progname, fname, strerror(errno));
3316                         return -EINVAL;
3317                 } else if (errno == ENODATA) {
3318                         /*
3319                          * file without LOVEA, this component-add will be turned
3320                          * into a component-create.
3321                          */
3322                         llapi_layout_free(head);
3323                         ret = -ENODATA;
3324
3325                         /*
3326                          * the new layout will be added to an empty one, it
3327                          * still needs to be adjusted below
3328                          */
3329                         comp_add = 0;
3330                         break;
3331                 } else if (!llapi_layout_is_composite(head)) {
3332                         fprintf(stderr,
3333                                 "%s setstripe: '%s' not a composite file\n",
3334                                 progname, fname);
3335                         llapi_layout_free(head);
3336                         return -EINVAL;
3337                 }
3338
3339                 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
3340                 if (rc) {
3341                         fprintf(stderr,
3342                                 "%s setstripe: cannot get prev extent: %s\n",
3343                                 progname, strerror(errno));
3344                         llapi_layout_free(head);
3345                         return rc;
3346                 }
3347
3348                 llapi_layout_free(head);
3349                 break;
3350         }
3351
3352         /* Make sure we use the first component of the layout to be added. */
3353         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
3354         if (rc < 0) {
3355                 fprintf(stderr,
3356                         "%s setstripe: cannot move component cursor: %s\n",
3357                         progname, strerror(errno));
3358                 return rc;
3359         }
3360
3361         rc = llapi_layout_comp_extent_get(layout, &start, &end);
3362         if (rc) {
3363                 fprintf(stderr, "%s setstripe: cannot get extent: %s\n",
3364                         progname, strerror(errno));
3365                 return rc;
3366         }
3367
3368         if (start == 0 && end == 0) {
3369                 rc = layout_extend_comp(layout, start, &end,
3370                                         comp_add ? prev_end : 0);
3371                 if (rc)
3372                         return rc;
3373         }
3374
3375         if (start > prev_end || end < prev_end) {
3376                 fprintf(stderr,
3377                         "%s setstripe: first extent [%lu, %lu) not adjacent with extent end %lu\n",
3378                         progname, start, end, prev_end);
3379                 return -EINVAL;
3380         }
3381
3382         rc = llapi_layout_comp_extent_set(layout, prev_end, end);
3383         if (rc) {
3384                 fprintf(stderr,
3385                         "%s setstripe: cannot set component extent [%lu, %lu): %s\n",
3386                         progname, prev_end, end, strerror(errno));
3387                 return rc;
3388         }
3389
3390         return ret;
3391 }
3392
3393 static int mirror_adjust_first_extents(struct mirror_args *list)
3394 {
3395         int rc = 0;
3396
3397         if (!list)
3398                 return 0;
3399
3400         while (list) {
3401                 rc = layout_adjust_first_extent(NULL, list->m_layout, false);
3402                 if (rc)
3403                         break;
3404                 list = list->m_next;
3405         }
3406
3407         return rc;
3408 }
3409
3410 static inline bool arg_is_eof(char *arg)
3411 {
3412         return !strncmp(arg, "-1", strlen("-1")) ||
3413                !strncmp(arg, "EOF", strlen("EOF")) ||
3414                !strncmp(arg, "eof", strlen("eof"));
3415 }
3416
3417 /**
3418  * lfs_mirror_alloc() - Allocate a mirror argument structure.
3419  *
3420  * Return: Valid mirror_args pointer on success and
3421  *         NULL if memory allocation fails.
3422  */
3423 static struct mirror_args *lfs_mirror_alloc(void)
3424 {
3425         struct mirror_args *mirror = NULL;
3426
3427         while (1) {
3428                 mirror = calloc(1, sizeof(*mirror));
3429                 if (mirror) {
3430                         mirror->m_inherit = false;
3431                         break;
3432                 }
3433
3434                 sleep(1);
3435         }
3436
3437         return mirror;
3438 }
3439
3440 /**
3441  * lfs_mirror_free() - Free memory allocated for a mirror argument
3442  *                     structure.
3443  * @mirror: Previously allocated mirror argument structure by
3444  *          lfs_mirror_alloc().
3445  *
3446  * Free memory allocated for @mirror.
3447  *
3448  * Return: void.
3449  */
3450 static void lfs_mirror_free(struct mirror_args *mirror)
3451 {
3452         if (mirror->m_layout)
3453                 llapi_layout_free(mirror->m_layout);
3454         free(mirror);
3455 }
3456
3457 /**
3458  * lfs_mirror_list_free() - Free memory allocated for a mirror list.
3459  * @mirror_list: Previously allocated mirror list.
3460  *
3461  * Free memory allocated for @mirror_list.
3462  *
3463  * Return: void.
3464  */
3465 static void lfs_mirror_list_free(struct mirror_args *mirror_list)
3466 {
3467         struct mirror_args *next_mirror = NULL;
3468
3469         while (mirror_list) {
3470                 next_mirror = mirror_list->m_next;
3471                 lfs_mirror_free(mirror_list);
3472                 mirror_list = next_mirror;
3473         }
3474 }
3475
3476 enum {
3477         LFS_SETQUOTA_DELETE = (CHAR_MAX + 1),
3478         LFS_POOL_OPT,
3479         LFS_COMP_COUNT_OPT,
3480         LFS_COMP_START_OPT,
3481         LFS_COMP_FLAGS_OPT,
3482         LFS_COMP_DEL_OPT,
3483         LFS_COMP_SET_OPT,
3484         LFS_COMP_ADD_OPT,
3485         LFS_COMP_NO_VERIFY_OPT,
3486         LFS_PROJID_OPT,
3487         LFS_LAYOUT_FLAGS_OPT, /* used for mirror and foreign flags */
3488         LFS_MIRROR_ID_OPT,
3489         LFS_MIRROR_STATE_OPT,
3490         LFS_LAYOUT_COPY,
3491         LFS_MIRROR_INDEX_OPT,
3492         LFS_LAYOUT_FOREIGN_OPT,
3493         LFS_MODE_OPT,
3494         LFS_NEWERXY_OPT,
3495         LFS_INHERIT_RR_OPT,
3496         LFS_FIND_PERM,
3497         LFS_PRINTF_OPT,
3498         LFS_NO_FOLLOW_OPT,
3499         LFS_HEX_IDX_OPT,
3500         LFS_STATS_OPT,
3501         LFS_STATS_INTERVAL_OPT,
3502         LFS_LINKS_OPT,
3503         LFS_ATTRS_OPT,
3504         LFS_XATTRS_MATCH_OPT
3505 };
3506
3507 #ifndef LCME_USER_MIRROR_FLAGS
3508 /* The mirror flags can be set by users at creation time. */
3509 #define LCME_USER_MIRROR_FLAGS  (LCME_FL_PREF_RW)
3510 #endif
3511
3512 /* functions */
3513 static int lfs_setstripe_internal(int argc, char **argv,
3514                                   enum setstripe_origin opc)
3515 {
3516         struct lfs_setstripe_args        lsa = { 0 };
3517         struct llapi_stripe_param       *param = NULL;
3518         struct find_param                migrate_mdt_param = {
3519                 .fp_max_depth = -1,
3520                 .fp_mdt_index = -1,
3521         };
3522         char                            *fname;
3523         int                              result = 0;
3524         int                              result2 = 0;
3525         char                            *end;
3526         int                              c;
3527         int                              delete = 0;
3528         unsigned long long               size_units = 1;
3529         bool                             migrate_mode = false;
3530         bool                             migrate_mdt_mode = false;
3531         bool                             setstripe_mode = false;
3532         bool                             migration_block = false;
3533         __u64                            migration_flags = 0;
3534         __u32                            tgts[LOV_MAX_STRIPE_COUNT] = { 0 };
3535         int                              comp_del = 0, comp_set = 0;
3536         int                              comp_add = 0;
3537         __u32                            comp_id = 0;
3538         struct llapi_layout             *layout = NULL;
3539         struct llapi_layout             **lpp = &layout;
3540         bool                             mirror_mode = false;
3541         bool                             has_m_file = false;
3542         __u32                            mirror_count = 0;
3543         enum mirror_flags                mirror_flags = 0;
3544         struct mirror_args              *mirror_list = NULL;
3545         struct mirror_args              *new_mirror = NULL;
3546         struct mirror_args              *last_mirror = NULL;
3547         __u16                            mirror_id = 0;
3548         char                             cmd[PATH_MAX];
3549         bool from_yaml = false;
3550         bool from_copy = false;
3551         char *template = NULL;
3552         bool foreign_mode = false;
3553         char *xattr = NULL;
3554         bool overstriped = false;
3555         uint32_t type = LU_FOREIGN_TYPE_NONE, flags = 0;
3556         char *mode_opt = NULL;
3557         mode_t previous_umask = 0;
3558         mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
3559         unsigned long long bandwidth_bytes_sec = 0;
3560         unsigned long long bandwidth_unit = ONE_MB;
3561         long stats_interval_sec = 0;
3562
3563         struct option long_opts[] = {
3564 /* find { .val = '0',   .name = "null",         .has_arg = no_argument }, */
3565 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
3566         /* --block is only valid in migrate mode */
3567         { .val = 'b',   .name = "block",        .has_arg = no_argument },
3568 /* find { .val = 'B',   .name = "btime",        .has_arg = required_argument }*/
3569         { .val = LFS_COMP_ADD_OPT,
3570                         .name = "comp-add",     .has_arg = no_argument },
3571         { .val = LFS_COMP_ADD_OPT,
3572                         .name = "component-add", .has_arg = no_argument },
3573         { .val = LFS_COMP_DEL_OPT,
3574                         .name = "comp-del",     .has_arg = no_argument },
3575         { .val = LFS_COMP_DEL_OPT,
3576                         .name = "component-del", .has_arg = no_argument },
3577         { .val = LFS_COMP_FLAGS_OPT,
3578                         .name = "comp-flags",   .has_arg = required_argument },
3579         { .val = LFS_COMP_FLAGS_OPT,
3580                         .name = "component-flags",
3581                                                 .has_arg = required_argument },
3582         { .val = LFS_COMP_SET_OPT,
3583                         .name = "comp-set",     .has_arg = no_argument },
3584         { .val = LFS_COMP_SET_OPT,
3585                         .name = "component-set",
3586                                                 .has_arg = no_argument},
3587         { .val = LFS_COMP_NO_VERIFY_OPT,
3588                         .name = "no-verify",    .has_arg = no_argument},
3589         { .val = LFS_LAYOUT_FLAGS_OPT,
3590                         .name = "flags",        .has_arg = required_argument},
3591         { .val = LFS_LAYOUT_FOREIGN_OPT,
3592                         .name = "foreign",      .has_arg = optional_argument},
3593         { .val = LFS_MIRROR_ID_OPT,
3594                         .name = "mirror-id",    .has_arg = required_argument},
3595         { .val = LFS_MODE_OPT,
3596                         .name = "mode",         .has_arg = required_argument},
3597         { .val = LFS_LAYOUT_COPY,
3598                         .name = "copy",         .has_arg = required_argument},
3599         { .val = LFS_STATS_OPT,
3600                         .name = "stats",        .has_arg = no_argument},
3601         { .val = LFS_STATS_INTERVAL_OPT,
3602                         .name = "stats-interval",
3603                                                 .has_arg = required_argument},
3604         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument},
3605         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument},
3606         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument},
3607         { .val = 'C',   .name = "overstripe-count",
3608                                                 .has_arg = required_argument},
3609         { .val = 'C',   .name = "mdt-overcount",
3610                                                 .has_arg = required_argument},
3611         { .val = 'd',   .name = "delete",       .has_arg = no_argument},
3612         { .val = 'd',   .name = "destroy",      .has_arg = no_argument},
3613         /* used with "lfs migrate -m" */
3614         { .val = 'd',   .name = "directory",    .has_arg = no_argument},
3615         /* --non-direct is only valid in migrate mode */
3616         { .val = 'D',   .name = "non-direct",   .has_arg = no_argument },
3617         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument},
3618         { .val = 'E',   .name = "component-end",
3619                                                 .has_arg = required_argument},
3620         { .val = 'f',   .name = "file",         .has_arg = required_argument },
3621 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
3622 /* find { .val = 'g',   .name = "gid",          .has_arg = no_argument }, */
3623 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
3624         { .val = 'h',   .name = "help",         .has_arg = no_argument },
3625         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument},
3626         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument},
3627         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument},
3628         { .val = 'I',   .name = "comp-id",      .has_arg = required_argument},
3629         { .val = 'I',   .name = "component-id", .has_arg = required_argument},
3630 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
3631         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
3632         { .val = 'm',   .name = "mdt",          .has_arg = required_argument},
3633         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument},
3634         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument},
3635         /* --non-block is only valid in migrate mode */
3636         { .val = 'n',   .name = "non-block",    .has_arg = no_argument },
3637         { .val = 'N',   .name = "mirror-count", .has_arg = optional_argument},
3638         { .val = 'o',   .name = "ost",          .has_arg = required_argument },
3639 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3640         { .val = 'o',   .name = "ost-list",     .has_arg = required_argument },
3641         { .val = 'o',   .name = "ost_list",     .has_arg = required_argument },
3642 #endif
3643         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
3644 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
3645 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
3646 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
3647         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
3648         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
3649 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
3650 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
3651 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
3652 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
3653         /* --verbose is only valid in migrate mode */
3654         { .val = 'v',   .name = "verbose",      .has_arg = no_argument},
3655         { .val = 'W',   .name = "bandwidth",    .has_arg = required_argument },
3656         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
3657 /* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/
3658         { .val = 'y',   .name = "yaml",         .has_arg = required_argument },
3659         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument},
3660         { .val = 'z',   .name = "extension-size", .has_arg = required_argument},
3661         { .name = NULL } };
3662
3663         setstripe_args_init(&lsa);
3664
3665         migrate_mode = (opc == SO_MIGRATE);
3666         mirror_mode = (opc == SO_MIRROR_CREATE || opc == SO_MIRROR_EXTEND);
3667         setstripe_mode = (opc == SO_SETSTRIPE);
3668         if (opc == SO_MIRROR_DELETE) {
3669                 delete = 1;
3670                 mirror_flags = MF_DESTROY;
3671         }
3672
3673         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
3674         progname = cmd;
3675         while ((c = getopt_long(argc, argv,
3676                                 "bc:C:dDE:f:hH:i:I:m:N::no:p:L:s:S:vx:W:y:z:",
3677                                 long_opts, NULL)) >= 0) {
3678                 size_units = 1;
3679                 switch (c) {
3680                 case 0:
3681                         /* Long options. */
3682                         break;
3683                 case LFS_COMP_ADD_OPT:
3684                         comp_add = 1;
3685                         break;
3686                 case LFS_COMP_DEL_OPT:
3687                         comp_del = 1;
3688                         break;
3689                 case LFS_COMP_FLAGS_OPT:
3690                         result = comp_str2flags(optarg, &lsa.lsa_comp_flags,
3691                                                 &lsa.lsa_comp_neg_flags);
3692                         if (result != 0)
3693                                 goto usage_error;
3694                         if (mirror_mode && lsa.lsa_comp_neg_flags) {
3695                                 fprintf(stderr,
3696                                         "%s: inverted flags are not supported\n",
3697                                         progname);
3698                                 goto usage_error;
3699                         }
3700                         break;
3701                 case LFS_COMP_SET_OPT:
3702                         comp_set = 1;
3703                         break;
3704                 case LFS_COMP_NO_VERIFY_OPT:
3705                         mirror_flags |= MF_NO_VERIFY;
3706                         break;
3707                 case LFS_MIRROR_ID_OPT: {
3708                         unsigned long int id;
3709
3710                         errno = 0;
3711                         id = strtoul(optarg, &end, 0);
3712                         if (errno != 0 || *end != '\0' || id == 0 ||
3713                             id > UINT16_MAX) {
3714                                 fprintf(stderr,
3715                                         "%s %s: invalid mirror ID '%s'\n",
3716                                         progname, argv[0], optarg);
3717                                 goto usage_error;
3718                         }
3719
3720                         mirror_id = (__u16)id;
3721                         break;
3722                 }
3723                 case LFS_LAYOUT_FLAGS_OPT: {
3724                         uint32_t neg_flags;
3725
3726                         /* check for numeric flags (foreign and mirror cases) */
3727                         if (setstripe_mode && !mirror_mode && !last_mirror) {
3728                                 errno = 0;
3729                                 flags = strtoul(optarg, &end, 16);
3730                                 if (errno != 0 || *end != '\0' ||
3731                                     flags >= UINT32_MAX) {
3732                                         fprintf(stderr,
3733                                                 "%s %s: invalid hex flags '%s'\n",
3734                                                 progname, argv[0], optarg);
3735                                         return CMD_HELP;
3736                                 }
3737                                 if (!foreign_mode) {
3738                                         fprintf(stderr,
3739                                                 "%s %s: hex flags must be specified with --foreign option\n",
3740                                                 progname, argv[0]);
3741                                         return CMD_HELP;
3742                                 }
3743                                 break;
3744                         }
3745
3746                         if (!mirror_mode || !last_mirror) {
3747                                 fprintf(stderr,
3748                                         "error: %s: --flags must be specified with --mirror-count|-N option\n",
3749                                         progname);
3750                                 goto usage_error;
3751                         }
3752
3753                         result = comp_str2flags(optarg, &last_mirror->m_flags,
3754                                                 &neg_flags);
3755                         if (result != 0)
3756                                 goto usage_error;
3757
3758                         if (neg_flags) {
3759                                 fprintf(stderr,
3760                                         "%s: inverted flags are not supported\n",
3761                                         progname);
3762                                 result = -EINVAL;
3763                                 goto usage_error;
3764                         }
3765                         if (last_mirror->m_flags & ~LCME_USER_MIRROR_FLAGS) {
3766                                 fprintf(stderr,
3767                                         "%s: unsupported mirror flags: %s\n",
3768                                         progname, optarg);
3769                                 result = -EINVAL;
3770                                 goto error;
3771                         }
3772                         break;
3773                 }
3774                 case LFS_LAYOUT_FOREIGN_OPT:
3775                         if (optarg) {
3776                                 /* check pure numeric */
3777                                 type = strtoul(optarg, &end, 0);
3778                                 if (*end) {
3779                                         /* check name */
3780                                         type = check_foreign_type_name(optarg);
3781                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
3782                                                 fprintf(stderr,
3783                                                         "%s %s: unrecognized foreign type '%s'\n",
3784                                                         progname, argv[0],
3785                                                         optarg);
3786                                                 return CMD_HELP;
3787                                         }
3788                                 } else if (type >= UINT32_MAX) {
3789                                         fprintf(stderr,
3790                                                 "%s %s: invalid foreign type '%s'\n",
3791                                                 progname, argv[0], optarg);
3792                                         return CMD_HELP;
3793                                 }
3794                         }
3795                         foreign_mode = true;
3796                         break;
3797                 case LFS_MODE_OPT:
3798                         mode_opt = optarg;
3799                         if (mode_opt) {
3800                                 mode = strtoul(mode_opt, &end, 8);
3801                                 if (*end != '\0') {
3802                                         fprintf(stderr,
3803                                                 "%s %s: bad mode '%s'\n",
3804                                                 progname, argv[0], mode_opt);
3805                                         return CMD_HELP;
3806                                 }
3807                                 previous_umask = umask(0);
3808                         }
3809                         break;
3810                 case LFS_LAYOUT_COPY:
3811                         from_copy = true;
3812                         template = optarg;
3813                         break;
3814                 case LFS_STATS_OPT:
3815                         stats_interval_sec = 5;
3816                         break;
3817                 case LFS_STATS_INTERVAL_OPT:
3818                         stats_interval_sec = strtol(optarg, &end, 0);
3819                         if (stats_interval_sec == 0 && errno) {
3820                                 fprintf(stderr,
3821                                         "%s %s: invalid stats interval %s\n",
3822                                         progname, argv[0], optarg);
3823                                 goto usage_error;
3824                         }
3825                         break;
3826                 case 'b':
3827                         if (!migrate_mode) {
3828                                 fprintf(stderr,
3829                                         "%s %s: -b|--block valid only for migrate command\n",
3830                                         progname, argv[0]);
3831                                 goto usage_error;
3832                         }
3833                         migration_block = true;
3834                         break;
3835                 case 'C':
3836                         if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) {
3837                                 fprintf(stderr,
3838                                         "%s %s: -C|--overstripe-count incompatible with DoM layout\n",
3839                                         progname, argv[0]);
3840                                 goto usage_error;
3841                         }
3842                         if (migrate_mode)
3843                                 overstriped = true;
3844                         else
3845                                 lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
3846                         fallthrough;
3847                 case 'c':
3848                         errno = 0;
3849                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
3850                         if (errno != 0 || *end != '\0'|| optarg == end ||
3851                             lsa.lsa_stripe_count < -1 ||
3852                             lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
3853                                 fprintf(stderr,
3854                                         "%s %s: invalid stripe count '%s'\n",
3855                                         progname, argv[0], optarg);
3856                                 goto usage_error;
3857                         }
3858
3859                         if (lsa.lsa_stripe_count == -1)
3860                                 lsa.lsa_stripe_count = LLAPI_LAYOUT_WIDE;
3861                         break;
3862                 case 'd':
3863                         if (migrate_mode) {
3864                                 migrate_mdt_param.fp_max_depth = 1;
3865                         } else {
3866                                 /* delete the default striping pattern */
3867                                 delete = 1;
3868                                 if (opc == SO_MIRROR_SPLIT) {
3869                                         if (has_m_file) {
3870                                                 fprintf(stderr,
3871                                                       "%s %s: -d cannot used with -f\n",
3872                                                         progname, argv[0]);
3873                                                 goto usage_error;
3874                                         }
3875                                         mirror_flags |= MF_DESTROY;
3876                                 }
3877                         }
3878                         break;
3879                 case 'D':
3880                         if (!migrate_mode) {
3881                                 fprintf(stderr,
3882                                         "%s %s: -D|--non-direct is valid only for migrate command\n",
3883                                         progname, argv[0]);
3884                                 goto usage_error;
3885                         }
3886                         migration_flags |= LLAPI_MIGRATION_NONDIRECT;
3887                         break;
3888                 case 'E':
3889                         if (lsa.lsa_comp_end != 0) {
3890                                 result = comp_args_to_layout(lpp, &lsa, true);
3891                                 if (result) {
3892                                         fprintf(stderr, "%s: invalid layout\n",
3893                                                 progname);
3894                                         goto usage_error;
3895                                 }
3896
3897                                 setstripe_args_init_inherit(&lsa);
3898                         }
3899
3900                         if (arg_is_eof(optarg)) {
3901                                 lsa.lsa_comp_end = LUSTRE_EOF;
3902                         } else {
3903                                 result = llapi_parse_size(optarg,
3904                                                           &lsa.lsa_comp_end,
3905                                                           &size_units, 0);
3906                                 /* assume units of KB if too small */
3907                                 if (lsa.lsa_comp_end < 4096)
3908                                         lsa.lsa_comp_end *= 1024;
3909                                 if (result ||
3910                                     lsa.lsa_comp_end & (LOV_MIN_STRIPE_SIZE - 1)) {
3911                                         fprintf(stderr,
3912                                                 "%s %s: invalid component end '%s'\n",
3913                                                 progname, argv[0], optarg);
3914                                         goto usage_error;
3915                                 }
3916                         }
3917                         break;
3918                 case 'H':
3919                         if (!migrate_mode) {
3920                                 fprintf(stderr,
3921                                         "--mdt-hash is valid only for migrate command\n");
3922                                 return CMD_HELP;
3923                         }
3924
3925                         lsa.lsa_pattern = check_hashtype(optarg);
3926                         if (lsa.lsa_pattern == 0) {
3927                                 fprintf(stderr,
3928                                         "%s %s: bad stripe hash type '%s'\n",
3929                                         progname, argv[0], optarg);
3930                                 return CMD_HELP;
3931                         }
3932                         break;
3933                 case 'i':
3934                         errno = 0;
3935                         lsa.lsa_stripe_off = strtol(optarg, &end, 0);
3936                         if (errno != 0 || *end != '\0' || optarg == end ||
3937                             lsa.lsa_stripe_off < -1 ||
3938                             lsa.lsa_stripe_off > LOV_V1_INSANE_STRIPE_COUNT) {
3939                                 fprintf(stderr,
3940                                         "%s %s: invalid stripe offset '%s'\n",
3941                                         progname, argv[0], optarg);
3942                                 goto usage_error;
3943                         }
3944                         if (lsa.lsa_stripe_off == -1)
3945                                 lsa.lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
3946                         break;
3947                 case 'I':
3948                         comp_id = strtoul(optarg, &end, 0);
3949                         if (*end != '\0' || comp_id == 0 ||
3950                             comp_id > LCME_ID_MAX) {
3951                                 fprintf(stderr,
3952                                         "%s %s: invalid component ID '%s'\n",
3953                                         progname, argv[0], optarg);
3954                                 goto usage_error;
3955                         }
3956                         break;
3957                 case 'f':
3958                         if (opc != SO_MIRROR_EXTEND && opc != SO_MIRROR_SPLIT) {
3959                                 fprintf(stderr,
3960                                         "error: %s: invalid option: %s\n",
3961                                         progname, argv[optopt + 1]);
3962                                 goto usage_error;
3963                         }
3964                         if (opc == SO_MIRROR_EXTEND) {
3965                                 if (!last_mirror) {
3966                                         fprintf(stderr,
3967                                 "error: %s: '-N' must exist in front of '%s'\n",
3968                                                 progname, argv[optopt + 1]);
3969                                         goto usage_error;
3970                                 }
3971                                 last_mirror->m_file = optarg;
3972                                 last_mirror->m_count = 1;
3973                         } else {
3974                                 /* mirror split */
3975                                 if (!mirror_list)
3976                                         mirror_list = lfs_mirror_alloc();
3977                                 mirror_list->m_file = optarg;
3978                         }
3979                         has_m_file = true;
3980                         break;
3981                 case 'L':
3982                         if (strcmp(argv[optind - 1], "mdt") == 0) {
3983                                 /* Can be only the first component */
3984                                 if (layout) {
3985                                         result = -EINVAL;
3986                                         fprintf(stderr,
3987                                                 "error: 'mdt' layout can be only the first one\n");
3988                                         goto error;
3989                                 }
3990                                 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
3991                                         result = -EFBIG;
3992                                         fprintf(stderr,
3993                                                 "error: 'mdt' layout size is too big\n");
3994                                         goto error;
3995                                 }
3996                                 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
3997                                 lsa.lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
3998                         } else if (strcmp(argv[optind - 1], "raid0") != 0) {
3999                                 result = -EINVAL;
4000                                 fprintf(stderr,
4001                                         "error: layout '%s' is unknown, supported layouts are: 'mdt', 'raid0'\n",
4002                                         argv[optind]);
4003                                 goto error;
4004                         }
4005                         break;
4006                 case 'm':
4007                         if (!migrate_mode) {
4008                                 fprintf(stderr,
4009                                         "%s %s: -m|--mdt-index is valid only for migrate command\n",
4010                                         progname, argv[0]);
4011                                 goto usage_error;
4012                         }
4013                         migrate_mdt_mode = true;
4014                         lsa.lsa_nr_tgts = parse_targets(tgts,
4015                                                         sizeof(tgts) / sizeof(__u32),
4016                                                         lsa.lsa_nr_tgts, optarg,
4017                                                         &overstriped);
4018                         if (lsa.lsa_nr_tgts < 0) {
4019                                 fprintf(stderr,
4020                                         "%s: invalid MDT target(s) '%s'\n",
4021                                         progname, optarg);
4022                                 goto usage_error;
4023                         }
4024
4025                         lsa.lsa_tgts = tgts;
4026                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4027                                 lsa.lsa_stripe_off = tgts[0];
4028                         break;
4029                 case 'n':
4030                         if (!migrate_mode) {
4031                                 fprintf(stderr,
4032                                         "%s %s: -n|--non-block valid only for migrate command\n",
4033                                         progname, argv[0]);
4034                                 goto usage_error;
4035                         }
4036                         migration_flags |= LLAPI_MIGRATION_NONBLOCK;
4037                         break;
4038                 case 'N':
4039                         if (opc == SO_SETSTRIPE) {
4040                                 opc = SO_MIRROR_CREATE;
4041                                 mirror_mode = true;
4042                         }
4043                         mirror_count = 1;
4044                         if (optarg) {
4045                                 errno = 0;
4046                                 mirror_count = strtoul(optarg, &end, 0);
4047                                 if (errno != 0 || *end != '\0' ||
4048                                     mirror_count == 0 ||
4049                                     mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
4050                                         fprintf(stderr,
4051                                                 "error: %s: bad mirror count: %s\n",
4052                                                 progname, optarg);
4053                                         result = -EINVAL;
4054                                         goto error;
4055                                 }
4056                         }
4057
4058                         new_mirror = lfs_mirror_alloc();
4059                         new_mirror->m_count = mirror_count;
4060
4061                         if (!mirror_list)
4062                                 mirror_list = new_mirror;
4063
4064                         if (last_mirror) {
4065                                 /* wrap up last mirror */
4066                                 if (!setstripe_args_specified(&lsa))
4067                                         last_mirror->m_inherit = true;
4068                                 if (lsa.lsa_comp_end == 0)
4069                                         lsa.lsa_comp_end = LUSTRE_EOF;
4070
4071                                 result = comp_args_to_layout(lpp, &lsa, true);
4072                                 if (result) {
4073                                         lfs_mirror_free(new_mirror);
4074                                         goto error;
4075                                 }
4076
4077                                 setstripe_args_init_inherit(&lsa);
4078
4079                                 last_mirror->m_next = new_mirror;
4080                         }
4081
4082                         last_mirror = new_mirror;
4083                         lpp = &last_mirror->m_layout;
4084                         break;
4085                 case 'o':
4086 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
4087                         if (strcmp(argv[optind - 1], "--ost-list") == 0)
4088                                 fprintf(stderr,
4089                                         "warning: '--ost-list' is deprecated, use '--ost' instead\n");
4090 #endif
4091                         if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) {
4092                                 fprintf(stderr,
4093                                         "%s %s: -o|--ost incompatible with DoM layout\n",
4094                                         progname, argv[0]);
4095                                 goto usage_error;
4096                         }
4097                         /*
4098                          * -o allows overstriping, and must note it because
4099                          * parse_targets is shared with MDT striping, which
4100                          * does not allow duplicates
4101                          */
4102                         lsa.lsa_nr_tgts = parse_targets(tgts,
4103                                                 sizeof(tgts) / sizeof(__u32),
4104                                                 lsa.lsa_nr_tgts, optarg,
4105                                                 &overstriped);
4106                         if (lsa.lsa_nr_tgts < 0) {
4107                                 fprintf(stderr,
4108                                         "%s %s: invalid OST target(s) '%s'\n",
4109                                         progname, argv[0], optarg);
4110                                 goto usage_error;
4111                         }
4112
4113                         if (overstriped)
4114                                 lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
4115
4116                         lsa.lsa_tgts = tgts;
4117                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4118                                 lsa.lsa_stripe_off = tgts[0];
4119                         break;
4120                 case 'p':
4121                         if (!optarg)
4122                                 goto usage_error;
4123
4124                         if (optarg[0] == '\0' || lov_pool_is_inherited(optarg))
4125                                 lsa.lsa_pool_name = NULL;
4126                         else
4127                                 lsa.lsa_pool_name = optarg;
4128                         break;
4129                 case 'S':
4130                         result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
4131                                                   &size_units, 0);
4132                         /* assume units of KB if too small to be valid */
4133                         if (lsa.lsa_stripe_size < 4096)
4134                                 lsa.lsa_stripe_size *= 1024;
4135                         if (result ||
4136                             lsa.lsa_stripe_size & (LOV_MIN_STRIPE_SIZE - 1)) {
4137                                 fprintf(stderr,
4138                                         "%s %s: invalid stripe size '%s'\n",
4139                                         progname, argv[0], optarg);
4140                                 goto usage_error;
4141                         }
4142                         break;
4143                 case 'v':
4144                         if (!migrate_mode) {
4145                                 fprintf(stderr,
4146                                         "%s %s: -v|--verbose valid only for migrate command\n",
4147                                         progname, argv[0]);
4148                                 goto usage_error;
4149                         }
4150                         migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
4151                         migration_flags = LLAPI_MIGRATION_VERBOSE;
4152                         break;
4153                 case 'x':
4154                         xattr = optarg;
4155                         break;
4156                 case 'W':
4157                         if (!migrate_mode && !mirror_mode) {
4158                                 fprintf(stderr,
4159                                         "--bandwidth is valid only for migrate and mirror mode\n");
4160                                 goto error;
4161                         }
4162                         if (llapi_parse_size(optarg, &bandwidth_bytes_sec,
4163                                              &bandwidth_unit, 0) < 0) {
4164                                 fprintf(stderr,
4165                                         "error: %s: bad value for bandwidth '%s'\n",
4166                                         argv[0], optarg);
4167                                 goto error;
4168                         }
4169                         break;
4170                 case 'y':
4171                         from_yaml = true;
4172                         template = optarg;
4173                         break;
4174                 case 'z':
4175                         result = llapi_parse_size(optarg,
4176                                                   &lsa.lsa_extension_size,
4177                                                   &size_units, 0);
4178                         if (result) {
4179                                 fprintf(stderr,
4180                                         "%s %s: invalid extension size '%s'\n",
4181                                         progname, argv[0], optarg);
4182                                 goto usage_error;
4183                         }
4184
4185                         lsa.lsa_extension_comp = true;
4186                         break;
4187                 default:
4188                         fprintf(stderr, "%s: unrecognized option '%s'\n",
4189                                 progname, argv[optind - 1]);
4190                 case 'h':
4191                         goto usage_error;
4192                 }
4193         }
4194
4195         fname = argv[optind];
4196
4197         if (optind == argc) {
4198                 fprintf(stderr, "%s %s: FILE must be specified\n",
4199                         progname, argv[0]);
4200                 goto usage_error;
4201         }
4202
4203         /* lfs migrate $filename should keep the file's layout by default */
4204         if (migrate_mode && !layout && !from_yaml &&
4205             !setstripe_args_specified(&lsa) && !lsa.lsa_pool_name)
4206                 from_copy = true;
4207
4208         if (xattr && !foreign_mode) {
4209                 /*
4210                  * only print a warning as this is harmless and will be ignored
4211                  */
4212                 fprintf(stderr,
4213                         "%s %s: xattr has been specified for non-foreign layout\n",
4214                         progname, argv[0]);
4215         } else if (foreign_mode && !xattr) {
4216                 fprintf(stderr,
4217                         "%s %s: xattr must be provided in foreign mode\n",
4218                         progname, argv[0]);
4219                 goto usage_error;
4220         }
4221
4222         if (foreign_mode && (!setstripe_mode || comp_add | comp_del ||
4223             comp_set || comp_id || delete || from_copy ||
4224             setstripe_args_specified(&lsa) || lsa.lsa_nr_tgts ||
4225             lsa.lsa_tgts)) {
4226                 fprintf(stderr,
4227                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
4228                         progname, argv[0]);
4229                 return CMD_HELP;
4230         }
4231
4232         if (mirror_mode && mirror_count == 0) {
4233                 fprintf(stderr,
4234                         "error: %s: --mirror-count|-N option is required\n",
4235                         progname);
4236                 result = -EINVAL;
4237                 goto error;
4238         }
4239
4240         if (mirror_mode) {
4241                 if (!setstripe_args_specified(&lsa))
4242                         last_mirror->m_inherit = true;
4243                 if (lsa.lsa_comp_end == 0)
4244                         lsa.lsa_comp_end = LUSTRE_EOF;
4245         }
4246
4247         if (lsa.lsa_comp_end != 0) {
4248                 result = comp_args_to_layout(lpp, &lsa, true);
4249                 if (result) {
4250                         fprintf(stderr, "error: %s: invalid layout\n",
4251                                 progname);
4252                         result = -EINVAL;
4253                         goto error;
4254                 }
4255         }
4256
4257         if (mirror_flags & MF_NO_VERIFY) {
4258                 if (opc != SO_MIRROR_EXTEND) {
4259                         fprintf(stderr,
4260                                 "error: %s: --no-verify is valid only for lfs mirror extend command\n",
4261                                 progname);
4262                         result = -EINVAL;
4263                         goto error;
4264                 } else if (!has_m_file) {
4265                         fprintf(stderr,
4266                                 "error: %s: --no-verify must be specified with -f <victim_file> option\n",
4267                                 progname);
4268                         result = -EINVAL;
4269                         goto error;
4270                 }
4271         }
4272
4273         if (comp_set && !comp_id && !lsa.lsa_pool_name) {
4274                 fprintf(stderr,
4275                         "%s %s: --component-set doesn't have component-id set\n",
4276                         progname, argv[0]);
4277                 goto usage_error;
4278         }
4279
4280         if ((delete + comp_set + comp_del + comp_add) > 1) {
4281                 fprintf(stderr,
4282                         "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
4283                         progname, argv[0]);
4284                 goto usage_error;
4285         }
4286
4287         if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
4288                        lsa.lsa_comp_flags != 0 || layout != NULL)) {
4289                 fprintf(stderr,
4290                         "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
4291                         progname, argv[0]);
4292                 goto usage_error;
4293         }
4294
4295         if ((comp_set || comp_del) &&
4296             (setstripe_args_specified(&lsa) || layout != NULL)) {
4297                 fprintf(stderr,
4298                         "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
4299                         progname, argv[0]);
4300                 goto usage_error;
4301         }
4302
4303         if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
4304                 fprintf(stderr,
4305                         "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
4306                         progname, argv[0]);
4307                 goto usage_error;
4308         }
4309
4310         if (comp_add || comp_del) {
4311                 struct stat st;
4312
4313                 result = lstat(fname, &st);
4314                 if (result == 0 && S_ISDIR(st.st_mode)) {
4315                         fprintf(stderr,
4316                                 "%s setstripe: cannot use --component-add or --component-del for directory\n",
4317                                 progname);
4318                         goto usage_error;
4319                 }
4320
4321                 if (mirror_mode) {
4322                         fprintf(stderr,
4323                                 "error: %s: can't use --component-add or --component-del for mirror operation\n",
4324                                 progname);
4325                         goto usage_error;
4326                 }
4327         }
4328
4329         if (comp_add) {
4330                 if (!layout) {
4331                         fprintf(stderr,
4332                                 "%s %s: option -E must be specified with --component-add\n",
4333                                 progname, argv[0]);
4334                         goto usage_error;
4335                 }
4336         }
4337
4338         if (from_yaml && from_copy) {
4339                 fprintf(stderr,
4340                         "%s: can't specify --yaml and --copy together\n",
4341                         progname);
4342                 goto error;
4343         }
4344
4345         if ((from_yaml || from_copy) &&
4346             (setstripe_args_specified(&lsa) || layout != NULL)) {
4347                 fprintf(stderr,
4348                         "error: %s: can't specify --yaml or --copy with -c, -S, -i, -o, -p or -E options.\n",
4349                         argv[0]);
4350                 goto error;
4351         }
4352
4353         if ((migration_flags & LLAPI_MIGRATION_NONBLOCK) && migration_block) {
4354                 fprintf(stderr,
4355                         "%s %s: options --non-block and --block are mutually exclusive\n",
4356                         progname, argv[0]);
4357                 goto usage_error;
4358         }
4359
4360         if (!comp_del && !comp_set && opc != SO_MIRROR_SPLIT &&
4361             opc != SO_MIRROR_DELETE && comp_id != 0) {
4362                 fprintf(stderr,
4363                         "%s: option -I can only be used with --component-del or --component-set or lfs mirror split\n",
4364                         progname);
4365                 goto usage_error;
4366         }
4367
4368         if (migrate_mdt_mode) {
4369                 struct lmv_user_md *lmu;
4370
4371                 /* initialize migrate mdt parameters */
4372                 lmu = calloc(1, lmv_user_md_size(lsa.lsa_nr_tgts,
4373                                                  LMV_USER_MAGIC_SPECIFIC));
4374                 if (!lmu) {
4375                         fprintf(stderr,
4376                                 "%s %s: cannot allocate memory for lmv_user_md: %s\n",
4377                                 progname, argv[0], strerror(ENOMEM));
4378                         result = -ENOMEM;
4379                         goto error;
4380                 }
4381                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
4382                         lmu->lum_stripe_count = lsa.lsa_stripe_count;
4383                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT) {
4384                         fprintf(stderr,
4385                                 "%s %s: migrate should specify MDT index\n",
4386                                 progname, argv[0]);
4387                         free(lmu);
4388                         goto usage_error;
4389                 }
4390                 lmu->lum_stripe_offset = lsa.lsa_stripe_off;
4391
4392                 if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
4393                         lmu->lum_hash_type = lsa.lsa_pattern;
4394                 else
4395                         lmu->lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
4396
4397                 if (overstriped)
4398                         lmu->lum_hash_type |= LMV_HASH_FLAG_OVERSTRIPED;
4399
4400                 if (lsa.lsa_pool_name) {
4401                         strncpy(lmu->lum_pool_name, lsa.lsa_pool_name,
4402                                 sizeof(lmu->lum_pool_name) - 1);
4403                         lmu->lum_pool_name[sizeof(lmu->lum_pool_name) - 1] = 0;
4404                 }
4405                 if (lsa.lsa_nr_tgts > 1) {
4406                         int i;
4407
4408                         if (lsa.lsa_stripe_count > 0 &&
4409                             lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
4410                             lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
4411                                 fprintf(stderr,
4412                                         "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
4413                                         progname, lsa.lsa_stripe_count,
4414                                         lsa.lsa_nr_tgts);
4415                                 free(lmu);
4416                                 goto usage_error;
4417                         }
4418
4419                         lmu->lum_magic = LMV_USER_MAGIC_SPECIFIC;
4420                         lmu->lum_stripe_count = lsa.lsa_nr_tgts;
4421                         for (i = 0; i < lsa.lsa_nr_tgts; i++)
4422                                 lmu->lum_objects[i].lum_mds = lsa.lsa_tgts[i];
4423                 } else {
4424                         lmu->lum_magic = LMV_USER_MAGIC;
4425                 }
4426
4427                 migrate_mdt_param.fp_lmv_md = lmu;
4428                 migrate_mdt_param.fp_migrate = 1;
4429         } else if (!layout) {
4430                 if (lsa_args_stripe_count_check(&lsa))
4431                         goto usage_error;
4432
4433                 /* initialize stripe parameters */
4434                 param = calloc(1, offsetof(typeof(*param),
4435                                lsp_osts[lsa.lsa_nr_tgts]));
4436                 if (!param) {
4437                         fprintf(stderr,
4438                                 "%s %s: cannot allocate memory for parameters: %s\n",
4439                                 progname, argv[0], strerror(ENOMEM));
4440                         result = -ENOMEM;
4441                         goto error;
4442                 }
4443
4444                 if (lsa.lsa_stripe_size != LLAPI_LAYOUT_DEFAULT)
4445                         param->lsp_stripe_size = lsa.lsa_stripe_size;
4446                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
4447                         if (lsa.lsa_stripe_count == LLAPI_LAYOUT_WIDE)
4448                                 param->lsp_stripe_count = -1;
4449                         else
4450                                 param->lsp_stripe_count = lsa.lsa_stripe_count;
4451                 }
4452                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4453                         param->lsp_stripe_offset = -1;
4454                 else
4455                         param->lsp_stripe_offset = lsa.lsa_stripe_off;
4456                 param->lsp_stripe_pattern =
4457                                 llapi_pattern_to_lov(lsa.lsa_pattern);
4458                 if (param->lsp_stripe_pattern == EINVAL) {
4459                         fprintf(stderr, "error: %s: invalid stripe pattern\n",
4460                                 argv[0]);
4461                         free(param);
4462                         goto usage_error;
4463                 }
4464                 param->lsp_pool = lsa.lsa_pool_name;
4465                 param->lsp_is_specific = false;
4466
4467                 if (lsa.lsa_nr_tgts > 0) {
4468                         param->lsp_is_specific = true;
4469                         param->lsp_stripe_count = lsa.lsa_nr_tgts;
4470                         memcpy(param->lsp_osts, tgts,
4471                                sizeof(*tgts) * lsa.lsa_nr_tgts);
4472                 }
4473         }
4474
4475         if (from_yaml) {
4476                 /* generate a layout from a YAML template */
4477                 result = lfs_comp_create_from_yaml(template, &layout,
4478                                                    &lsa, tgts);
4479                 if (result) {
4480                         fprintf(stderr,
4481                                 "error: %s: can't create composite layout from template file %s\n",
4482                                 argv[0], template);
4483                         goto error;
4484                 }
4485         }
4486
4487         if (layout != NULL || mirror_list != NULL) {
4488                 if (mirror_list)
4489                         result = mirror_adjust_first_extents(mirror_list);
4490                 else
4491                         result = layout_adjust_first_extent(fname, layout,
4492                                                             comp_add);
4493                 if (result == -ENODATA)
4494                         comp_add = 0;
4495                 else if (result != 0) {
4496                         fprintf(stderr, "error: %s: invalid layout\n",
4497                                 progname);
4498                         goto error;
4499                 }
4500         }
4501
4502         for (fname = argv[optind]; (optind < argc) && (fname != NULL);
4503              fname = argv[++optind]) {
4504                 if (from_copy) {
4505                         layout = llapi_layout_get_by_path(template ?: fname, 0);
4506                         if (!layout) {
4507                                 fprintf(stderr,
4508                                         "%s: can't create composite layout from file %s: %s\n",
4509                                         progname, template ?: fname,
4510                                         strerror(errno));
4511                                 result = -errno;
4512                                 goto error;
4513                         }
4514                 }
4515
4516                 if (migrate_mdt_mode) {
4517                         result = llapi_migrate_mdt(fname, &migrate_mdt_param);
4518                 } else if (migrate_mode) {
4519                         if (from_copy) {
4520                                 /*
4521                                  * Strip the source layout of specific
4522                                  * OST object/index values.
4523                                  */
4524                                 result = llapi_layout_ost_index_reset(layout);
4525                                 if (result) {
4526                                         fprintf(stderr,
4527                                                 "%s: set default ost index failed: %s\n",
4528                                                 progname, strerror(errno));
4529                                         result = -errno;
4530                                         goto error;
4531                                 }
4532                         }
4533
4534                         result = lfs_migrate(fname, migration_flags, param,
4535                                              layout, bandwidth_bytes_sec,
4536                                              stats_interval_sec);
4537                 } else if (comp_set != 0) {
4538                         result = lfs_component_set(fname, comp_id,
4539                                                    lsa.lsa_pool_name,
4540                                                    lsa.lsa_comp_flags,
4541                                                    lsa.lsa_comp_neg_flags);
4542                 } else if (comp_del != 0) {
4543                         result = lfs_component_del(fname, comp_id,
4544                                                    lsa.lsa_comp_flags,
4545                                                    lsa.lsa_comp_neg_flags);
4546                 } else if (comp_add != 0) {
4547                         result = lfs_component_add(fname, layout);
4548                 } else if (opc == SO_MIRROR_CREATE) {
4549                         result = mirror_create(fname, mirror_list);
4550                 } else if (opc == SO_MIRROR_EXTEND) {
4551                         result = mirror_extend(fname, mirror_list,
4552                                                mirror_flags,
4553                                                bandwidth_bytes_sec,
4554                                                stats_interval_sec);
4555                 } else if (opc == SO_MIRROR_SPLIT || opc == SO_MIRROR_DELETE) {
4556                         if (!mirror_id && !comp_id && !lsa.lsa_pool_name) {
4557                                 fprintf(stderr,
4558                                         "%s: no mirror id, component id, or pool name specified to delete from '%s'\n",
4559                                         progname, fname);
4560                                 goto usage_error;
4561                         }
4562                         if (lsa.lsa_pool_name)
4563                                 mirror_flags |= MF_COMP_POOL;
4564                         else if (mirror_id != 0)
4565                                 comp_id = mirror_id;
4566                         else
4567                                 mirror_flags |= MF_COMP_ID;
4568                         if (has_m_file && !strcmp(fname, mirror_list->m_file)) {
4569                                 fprintf(stderr,
4570                                         "%s: the file specified by -f cannot be same as the source file '%s'\n",
4571                                         progname, fname);
4572                                 goto usage_error;
4573                         }
4574                         result = mirror_split(fname, comp_id, lsa.lsa_pool_name,
4575                                               mirror_flags,
4576                                               has_m_file ? mirror_list->m_file :
4577                                               NULL);
4578                 } else if (layout) {
4579                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
4580                                                       mode, layout);
4581                         if (result >= 0) {
4582                                 close(result);
4583                                 result = 0;
4584                         }
4585                 } else if (foreign_mode) {
4586                         result = llapi_file_create_foreign(fname, mode, type,
4587                                                            flags, xattr);
4588                         if (result >= 0) {
4589                                 close(result);
4590                                 result = 0;
4591                         }
4592                 } else {
4593                         result = llapi_file_open_param(fname,
4594                                                        O_CREAT | O_WRONLY,
4595                                                        mode, param);
4596                         if (result >= 0) {
4597                                 close(result);
4598                                 result = 0;
4599                         }
4600                 }
4601                 if (result) {
4602                         /* Save the first error encountered. */
4603                         if (result2 == 0)
4604                                 result2 = result;
4605                         continue;
4606                 }
4607         }
4608
4609         if (mode_opt)
4610                 umask(previous_umask);
4611
4612         free(param);
4613         free(migrate_mdt_param.fp_lmv_md);
4614         llapi_layout_free(layout);
4615         lfs_mirror_list_free(mirror_list);
4616         return result2;
4617 usage_error:
4618         result = CMD_HELP;
4619 error:
4620         llapi_layout_free(layout);
4621         lfs_mirror_list_free(mirror_list);
4622         return result;
4623 }
4624
4625 static int lfs_poollist(int argc, char **argv)
4626 {
4627         if (argc != 2)
4628                 return CMD_HELP;
4629
4630         return llapi_poollist(argv[1]);
4631 }
4632
4633 #define FP_DEFAULT_TIME_MARGIN (24 * 60 * 60)
4634 static int set_time(struct find_param *param, time_t *time, time_t *set,
4635                     char *str)
4636 {
4637         long long t = 0;
4638         int sign = 0;
4639         char *endptr = "AD";
4640         char *timebuf;
4641
4642         if (str[0] == '+')
4643                 sign = 1;
4644         else if (str[0] == '-')
4645                 sign = -1;
4646
4647         if (sign)
4648                 str++;
4649
4650         for (timebuf = str; *endptr && *(endptr + 1); timebuf = endptr + 1) {
4651                 long long val = strtoll(timebuf, &endptr, 0);
4652                 int unit = 1;
4653
4654                 switch (*endptr) {
4655                 case  'y':
4656                         unit *= 52; /* 52 weeks + 1 day below */
4657                         fallthrough;
4658                 case  'w':
4659                         unit *= 7;
4660                         if (param->fp_time_margin == FP_DEFAULT_TIME_MARGIN)
4661                                 param->fp_time_margin *= (1 + unit / 52);
4662                         unit += (*endptr == 'y'); /* +1 day for 365 days/year */
4663                         fallthrough;
4664                 case '\0': /* days are default unit if none used */
4665                         fallthrough;
4666                 case  'd':
4667                         unit *= 24;
4668                         fallthrough;
4669                 case  'h':
4670                         unit *= 60;
4671                         fallthrough;
4672                 case  'm':
4673                         unit *= 60;
4674                         fallthrough;
4675                 case  's':
4676                         break;
4677                         /* don't need to multiply by 1 for seconds */
4678                 default:
4679                         fprintf(stderr,
4680                                 "%s find: bad time string '%s': %s\n",
4681                                 progname, timebuf, strerror(EINVAL));
4682                         return INT_MAX;
4683                 }
4684
4685                 if (param->fp_time_margin == 0 ||
4686                     (*endptr && unit < param->fp_time_margin))
4687                         param->fp_time_margin = unit;
4688
4689                 t += val * unit;
4690         }
4691         if (*time < t) {
4692                 if (sign != 0)
4693                         str--;
4694                 fprintf(stderr, "%s find: bad time '%s': too large\n",
4695                         progname, str);
4696                 return INT_MAX;
4697         }
4698
4699         *set = *time - t;
4700
4701         return sign;
4702 }
4703
4704 static int str2quotaid(__u32 *id, const char *arg)
4705 {
4706         unsigned long int projid_tmp = 0;
4707         char *endptr = NULL;
4708
4709         projid_tmp = strtoul(arg, &endptr, 10);
4710         if (*endptr != '\0')
4711                 return -EINVAL;
4712         /* UINT32_MAX is not allowed - see projid_valid()/INVALID_PROJID */
4713         if (projid_tmp >= UINT32_MAX)
4714                 return -ERANGE;
4715
4716         *id = projid_tmp;
4717         return 0;
4718 }
4719
4720 static int name2uid(unsigned int *id, const char *name)
4721 {
4722         struct passwd *passwd;
4723
4724         passwd = getpwnam(name);
4725         if (!passwd)
4726                 return -ENOENT;
4727         *id = passwd->pw_uid;
4728
4729         return 0;
4730 }
4731
4732 static int name2gid(unsigned int *id, const char *name)
4733 {
4734         struct group *group;
4735
4736         group = getgrnam(name);
4737         if (!group)
4738                 return -ENOENT;
4739         *id = group->gr_gid;
4740
4741         return 0;
4742 }
4743
4744 static inline int name2projid(unsigned int *id, const char *name)
4745 {
4746         return -ENOTSUP;
4747 }
4748
4749 static int uid2name(char **name, unsigned int id)
4750 {
4751         struct passwd *passwd;
4752
4753         passwd = getpwuid(id);
4754         if (!passwd)
4755                 return -ENOENT;
4756         *name = passwd->pw_name;
4757
4758         return 0;
4759 }
4760
4761 static inline int gid2name(char **name, unsigned int id)
4762 {
4763         struct group *group;
4764
4765         group = getgrgid(id);
4766         if (!group)
4767                 return -ENOENT;
4768         *name = group->gr_name;
4769
4770         return 0;
4771 }
4772
4773 static int name2layout(__u32 *layout, char *name)
4774 {
4775         char *ptr, *layout_name;
4776
4777         *layout = 0;
4778         for (ptr = name; ; ptr = NULL) {
4779                 layout_name = strtok(ptr, ",");
4780                 if (!layout_name)
4781                         break;
4782                 if (strcmp(layout_name, "released") == 0)
4783                         *layout |= LOV_PATTERN_F_RELEASED;
4784                 else if (strcmp(layout_name, "raid0") == 0)
4785                         *layout |= LOV_PATTERN_RAID0;
4786                 else if (strcmp(layout_name, "mdt") == 0)
4787                         *layout |= LOV_PATTERN_MDT;
4788                 else if (strcmp(layout_name, "overstriping") == 0)
4789                         *layout |= LOV_PATTERN_OVERSTRIPING;
4790                 else if (strcmp(layout_name, "foreign") == 0)
4791                         *layout |= LOV_PATTERN_FOREIGN;
4792                 else
4793                         return -1;
4794         }
4795         return 0;
4796 }
4797
4798 static int name2attrs(char *name, __u64 *attrs, __u64 *neg_attrs)
4799 {
4800         char *ptr, *attr_name = name;
4801         struct attrs_name *ap;
4802         int islongopt = 0; /* 1 true; 0 not known yet; -1 false. */
4803
4804         *attrs = 0;
4805         *neg_attrs = 0;
4806
4807         if (strchr(name, ','))
4808                 islongopt = 1;
4809
4810         for (ptr = name; ; ptr = NULL) {
4811                 if (islongopt != -1)
4812                         attr_name = strtok(ptr, ",");
4813                 else
4814                         attr_name = attr_name + 1;
4815                 if (!attr_name || *attr_name == '\0')
4816                         break;
4817
4818                 for (ap = (struct attrs_name *)attrs_array;
4819                      ap->an_attr != 0;
4820                      ap++) {
4821                         if (islongopt != -1 &&
4822                             strcmp(attr_name, ap->an_name) == 0) {
4823                                 *attrs |= ap->an_attr;
4824                                 islongopt = 1;
4825                                 break;
4826                         } else if (islongopt != -1 && attr_name[0] == '^' &&
4827                                    strcmp(attr_name + 1, ap->an_name) == 0) {
4828                                 *neg_attrs |= ap->an_attr;
4829                                 islongopt = 1;
4830                                 break;
4831                         } else if (islongopt != 1 &&
4832                                    *attr_name == ap->an_shortname) {
4833                                 *attrs |= ap->an_attr;
4834                                 islongopt = -1;
4835                                 break;
4836                         } else if (islongopt != 1 && *attr_name == '^' &&
4837                                    attr_name[1] == ap->an_shortname) {
4838                                 *neg_attrs |= ap->an_attr;
4839                                 islongopt = -1;
4840                                 attr_name++;
4841                                 break;
4842                         }
4843                 }
4844
4845                 if (ap->an_attr == 0) {
4846                         /* provided attr is unknown */
4847                         fprintf(stderr, "error: bad attribute name '%s'\n",
4848                                 attr_name);
4849                         return -1;
4850                 }
4851         }
4852         return 0;
4853 }
4854
4855 /**
4856  * xattr_match_info_append() - add the supplied name and value regex patterns
4857  *     to the supplied xattr_match_info struct.
4858  *
4859  * Return: 0 for success, nonzero if any errors encountered.
4860  */
4861 int xattr_match_info_append(struct xattr_match_info *xmi, bool exclude,
4862                             char *name_pattern, char *value_pattern)
4863 {
4864         int flags = REG_EXTENDED;
4865         char *err_buf;
4866         int err_len;
4867         void *nptr;
4868         int ret;
4869         int n;
4870
4871         if (xmi->xattr_name_buf == NULL) {
4872                 xmi->xattr_name_buf = malloc(XATTR_LIST_MAX);
4873                 if (xmi->xattr_name_buf == NULL)
4874                         goto err_out;
4875         }
4876
4877         if (xmi->xattr_value_buf == NULL) {
4878                 /*
4879                  * an xattr value need not be null-terminated, so allocate an
4880                  * extra byte to append a '\0', since regexec() expects a null-
4881                  * terminated string.
4882                  */
4883                 xmi->xattr_value_buf = malloc(XATTR_SIZE_MAX + 1);
4884                 if (xmi->xattr_value_buf == NULL)
4885                         goto err_out;
4886         }
4887
4888         n = ++xmi->xattr_regex_count;
4889
4890         nptr = realloc(xmi->xattr_regex_matched, n * sizeof(bool));
4891         if (nptr == NULL)
4892                 goto err_out;
4893         xmi->xattr_regex_matched = nptr;
4894
4895         nptr = realloc(xmi->xattr_regex_exclude, n * sizeof(bool));
4896         if (nptr == NULL)
4897                 goto err_out;
4898         xmi->xattr_regex_exclude = nptr;
4899
4900         nptr = realloc(xmi->xattr_regex_name, n * sizeof(regex_t *));
4901         if (nptr == NULL)
4902                 goto err_out;
4903         xmi->xattr_regex_name = nptr;
4904
4905         nptr = realloc(xmi->xattr_regex_value, n * sizeof(regex_t *));
4906         if (nptr == NULL)
4907                 goto err_out;
4908         xmi->xattr_regex_value = nptr;
4909
4910         n--;
4911
4912         xmi->xattr_regex_exclude[n] = exclude;
4913
4914         xmi->xattr_regex_name[n] = malloc(sizeof(regex_t));
4915         if (xmi->xattr_regex_name[n] == NULL)
4916                 goto err_out;
4917
4918         ret = regcomp(xmi->xattr_regex_name[n], name_pattern, flags);
4919         if (ret) {
4920                 err_len = regerror(ret, xmi->xattr_regex_name[n], NULL, 0);
4921                 err_buf = malloc(err_len);
4922                 if (err_buf == NULL)
4923                         goto err_out;
4924
4925                 regerror(ret, xmi->xattr_regex_name[n], err_buf, err_len);
4926                 fprintf(stderr, "%s: %s: %s\n",
4927                         progname, name_pattern, err_buf);
4928                 free(err_buf);
4929                 return ret;
4930         }
4931
4932         if (value_pattern && value_pattern[0] != '\0') {
4933                 xmi->xattr_regex_value[n] = malloc(sizeof(regex_t));
4934                 ret = regcomp(xmi->xattr_regex_value[n], value_pattern, flags);
4935                 if (ret) {
4936                         err_len = regerror(ret, xmi->xattr_regex_value[n],
4937                                            NULL, 0);
4938                         err_buf = malloc(err_len);
4939                         if (err_buf == NULL)
4940                                 goto err_out;
4941
4942                         regerror(ret, xmi->xattr_regex_value[n], err_buf,
4943                                  err_len);
4944                         fprintf(stderr, "%s: %s: %s\n",
4945                                 progname, value_pattern, err_buf);
4946                         free(err_buf);
4947                         return ret;
4948                 }
4949         } else {
4950                 xmi->xattr_regex_value[n] = NULL;
4951         }
4952
4953         return 0;
4954
4955 err_out:
4956         fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM));
4957         return -ENOMEM;
4958 }
4959
4960 void xattr_match_info_free(struct xattr_match_info *xmi)
4961 {
4962         int i;
4963
4964         free(xmi->xattr_regex_exclude);
4965         xmi->xattr_regex_exclude = NULL;
4966
4967         free(xmi->xattr_regex_matched);
4968         xmi->xattr_regex_matched = NULL;
4969
4970         for (i = 0; i < xmi->xattr_regex_count; i++) {
4971                 if (xmi->xattr_regex_name[i]) {
4972                         regfree(xmi->xattr_regex_name[i]);
4973                         free(xmi->xattr_regex_name[i]);
4974                 }
4975
4976                 if (xmi->xattr_regex_value[i]) {
4977                         regfree(xmi->xattr_regex_value[i]);
4978                         free(xmi->xattr_regex_value[i]);
4979                 }
4980         }
4981
4982         xmi->xattr_regex_count = 0;
4983
4984         free(xmi->xattr_regex_name);
4985         xmi->xattr_regex_name = NULL;
4986
4987         free(xmi->xattr_regex_value);
4988         xmi->xattr_regex_value = NULL;
4989
4990         free(xmi->xattr_name_buf);
4991         xmi->xattr_name_buf = NULL;
4992
4993         free(xmi->xattr_value_buf);
4994         xmi->xattr_value_buf = NULL;
4995 }
4996
4997 /**
4998  * compile_xattr_match_regex() - Compile regexes for matching xattr names and
4999  * values, returning an error if either fails to compile.
5000  *
5001  * The argument should be in the form "NAME=VALUE". The first '=' found
5002  * is assumed to be the separator between the name regex and the value regex.
5003  *
5004  * VALUE may be empty. If it is empty, it is not compiled and left NULL.
5005  * NAME must not be empty.
5006  *
5007  * Return: 0 if argument string is succesfully processed, nonzero if any
5008  *         errors encountered.
5009  */
5010 static int compile_xattr_match_regex(char *optarg, bool exclude,
5011                                      struct find_param *param)
5012 {
5013         char *sep;
5014
5015         sep = strchr(optarg, '=');
5016         if (sep)
5017                 *sep = '\0';
5018
5019         /* error if no NAME pattern specified */
5020         if (*optarg == '\0') {
5021                 fprintf(stderr, "%s: must specify xattr pattern\n", progname);
5022                 return CMD_HELP;
5023         }
5024
5025         /* if first -xattr option seen */
5026         if (param->fp_xattr_match_info == NULL) {
5027                 param->fp_xattr_match_info = calloc(1,
5028                                         sizeof(struct xattr_match_info));
5029                 if (param->fp_xattr_match_info == NULL) {
5030                         fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM));
5031                         return -ENOMEM;
5032                 }
5033         }
5034
5035         /*
5036          * if '=' was not provided, or if there is no value after the '=',
5037          * then pass NULL to xattr_match_info_append() so that no VALUE regex
5038          * is compiled.
5039          */
5040         if (sep) {
5041                 sep++;
5042                 if (*sep == '\0')
5043                         sep = NULL;
5044         }
5045
5046         return xattr_match_info_append(param->fp_xattr_match_info, exclude,
5047                                        optarg, sep);
5048 }
5049
5050 static int parse_symbolic(const char *input, mode_t *outmode, const char **end)
5051 {
5052         int loop;
5053         int user, group, other;
5054         int who, all;
5055         char c, op;
5056         mode_t perm;
5057         mode_t usermask;
5058         mode_t previous_flags;
5059
5060         user = group = other = 0;
5061         all = 0;
5062         loop = 1;
5063         perm = 0;
5064         previous_flags = 0;
5065         *end = input;
5066         usermask = 0;
5067
5068         while (loop) {
5069                 switch (*input) {
5070                 case 'u':
5071                         user = 1;
5072                         break;
5073                 case 'g':
5074                         group = 1;
5075                         break;
5076                 case 'o':
5077                         other = 1;
5078                         break;
5079                 case 'a':
5080                         user = group = other = 1;
5081                         all = 1;
5082                         break;
5083                 default:
5084                         loop = 0;
5085                 }
5086
5087                 if (loop)
5088                         input++;
5089         }
5090
5091         who = user || group || other;
5092         if (!who) {
5093                 /* get the umask */
5094                 usermask = umask(0022);
5095                 umask(usermask);
5096                 usermask &= 07777;
5097         }
5098
5099         if (*input == '-' || *input == '+' || *input == '=')
5100                 op = *input++;
5101         else
5102                 /* operation is required */
5103                 return -1;
5104
5105         /* get the flags in *outmode */
5106         switch (*input) {
5107         case 'u':
5108                 previous_flags = (*outmode & 0700);
5109                 perm |= user  ? previous_flags : 0;
5110                 perm |= group ? (previous_flags >> 3) : 0;
5111                 perm |= other ? (previous_flags >> 6) : 0;
5112                 input++;
5113                 goto write_perm;
5114         case 'g':
5115                 previous_flags = (*outmode & 0070);
5116                 perm |= user  ? (previous_flags << 3) : 0;
5117                 perm |= group ? previous_flags : 0;
5118                 perm |= other ? (previous_flags >> 3) : 0;
5119                 input++;
5120                 goto write_perm;
5121         case 'o':
5122                 previous_flags = (*outmode & 0007);
5123                 perm |= user  ? (previous_flags << 6) : 0;
5124                 perm |= group ? (previous_flags << 3) : 0;
5125                 perm |= other ? previous_flags : 0;
5126                 input++;
5127                 goto write_perm;
5128         default:
5129                 break;
5130         }
5131
5132         /* this part is optional,
5133          * if empty perm = 0 and *outmode is not modified
5134          */
5135         loop = 1;
5136         while (loop) {
5137                 c = *input;
5138                 switch (c) {
5139                 case 'r':
5140                         perm |= user  ? 0400 : 0;
5141                         perm |= group ? 0040 : 0;
5142                         perm |= other ? 0004 : 0;
5143                         /* set read permission for uog except for umask's
5144                          * permissions
5145                          */
5146                         perm |= who   ? 0 : (0444 & ~usermask);
5147                         break;
5148                 case 'w':
5149                         perm |= user  ? 0200 : 0;
5150                         perm |= group ? 0020 : 0;
5151                         perm |= other ? 0002 : 0;
5152                         /* set write permission for uog except for umask'
5153                          * permissions
5154                          */
5155                         perm |= who   ? 0 : (0222 & ~usermask);
5156                         break;
5157                 case 'x':
5158                         perm |= user  ? 0100 : 0;
5159                         perm |= group ? 0010 : 0;
5160                         perm |= other ? 0001 : 0;
5161                         /* set execute permission for uog except for umask'
5162                          * permissions
5163                          */
5164                         perm |= who   ? 0 : (0111 & ~usermask);
5165                         break;
5166                 case 'X':
5167                         /*
5168                          * Adds execute permission to 'u', 'g' and/or 'g' if
5169                          * specified and either 'u', 'g' or 'o' already has
5170                          * execute permissions.
5171                          */
5172                         if ((*outmode & 0111) != 0) {
5173                                 perm |= user  ? 0100 : 0;
5174                                 perm |= group ? 0010 : 0;
5175                                 perm |= other ? 0001 : 0;
5176                                 perm |= !who  ? 0111 : 0;
5177                         }
5178                         break;
5179                 case 's':
5180                         /* s is ignored if o is given, but it's not an error */
5181                         if (other && !group && !user)
5182                                 break;
5183                         perm |= user  ? S_ISUID : 0;
5184                         perm |= group ? S_ISGID : 0;
5185                         break;
5186                 case 't':
5187                         /* 't' should be used when 'a' is given
5188                          * or who is empty
5189                          */
5190                         perm |= (!who || all) ? S_ISVTX : 0;
5191                         /* using ugo with t is not an error */
5192                         break;
5193                 default:
5194                         loop = 0;
5195                         break;
5196                 }
5197                 if (loop)
5198                         input++;
5199         }
5200
5201 write_perm:
5202         /* uog flags should be only one character long */
5203         if (previous_flags && (*input != '\0' && *input != ','))
5204                 return -1;
5205
5206         switch (op) {
5207         case '-':
5208                 /* remove the flags from outmode */
5209                 *outmode &= ~perm;
5210                 break;
5211         case '+':
5212                 /* add the flags to outmode */
5213                 *outmode |= perm;
5214                 break;
5215         case '=':
5216                 /* set the flags of outmode to perm */
5217                 if (perm != 0)
5218                         *outmode = perm;
5219                 break;
5220         }
5221
5222         *end = input;
5223         return 0;
5224 }
5225
5226 static int str2mode_t(const char *input, mode_t *outmode)
5227 {
5228         int ret;
5229         const char *iter;
5230
5231         ret = 0;
5232
5233         if (*input >= '0' && *input <= '7') {
5234                 /* parse octal representation */
5235                 char *end;
5236
5237                 iter = input;
5238
5239                 /* look for invalid digits in octal representation */
5240                 while (isdigit(*iter))
5241                         if (*iter++ > '7')
5242                                 return -1;
5243
5244                 errno = 0;
5245                 *outmode = strtoul(input, &end, 8);
5246
5247                 if (errno != 0 || *outmode > 07777) {
5248                         *outmode = 0;
5249                         ret = -1;
5250                 }
5251
5252         } else if (*input == '8' || *input == '9') {
5253                 /* error: invalid octal number */
5254                 ret = -1;
5255         } else {
5256                 /* parse coma seperated list of symbolic representation */
5257                 int rc;
5258                 const char *end;
5259
5260                 *outmode = 0;
5261                 rc = 0;
5262                 end = NULL;
5263
5264                 do {
5265                         rc = parse_symbolic(input, outmode, &end);
5266                         if (rc)
5267                                 return -1;
5268
5269                         input = end+1;
5270                 } while (*end == ',');
5271
5272                 if (*end != '\0')
5273                         ret = -1;
5274         }
5275         return ret;
5276 }
5277
5278 static int lfs_find(int argc, char **argv)
5279 {
5280         int c, rc;
5281         int ret = 0;
5282         time_t t;
5283         struct find_param param = {
5284                 .fp_max_depth = -1,
5285                 .fp_quiet = 1,
5286                 .fp_time_margin = FP_DEFAULT_TIME_MARGIN,
5287         };
5288         struct option long_opts[] = {
5289         { .val = 'A',   .name = "atime",        .has_arg = required_argument },
5290         { .val = LFS_ATTRS_OPT,
5291                         .name = "attrs",        .has_arg = required_argument },
5292         { .val = 'b',   .name = "blocks",       .has_arg = required_argument },
5293         { .val = 'B',   .name = "btime",        .has_arg = required_argument },
5294         { .val = 'B',   .name = "Btime",        .has_arg = required_argument },
5295         { .val = LFS_COMP_COUNT_OPT,
5296                         .name = "comp-count",   .has_arg = required_argument },
5297         { .val = LFS_COMP_COUNT_OPT,
5298                         .name = "component-count",
5299                                                 .has_arg = required_argument },
5300         { .val = LFS_COMP_FLAGS_OPT,
5301                         .name = "comp-flags",   .has_arg = required_argument },
5302         { .val = LFS_COMP_FLAGS_OPT,
5303                         .name = "component-flags",
5304                                                 .has_arg = required_argument },
5305         { .val = LFS_COMP_START_OPT,
5306                         .name = "comp-start",   .has_arg = required_argument },
5307         { .val = LFS_COMP_START_OPT,
5308                         .name = "component-start",
5309                                                 .has_arg = required_argument },
5310         { .val = LFS_MIRROR_STATE_OPT,
5311                         .name = "mirror-state", .has_arg = required_argument },
5312         { .val = LFS_NEWERXY_OPT,
5313                         .name = "newer",        .has_arg = required_argument},
5314         { .val = LFS_NEWERXY_OPT,
5315                         .name = "neweraa",      .has_arg = required_argument},
5316         { .val = LFS_NEWERXY_OPT,
5317                         .name = "neweram",      .has_arg = required_argument},
5318         { .val = LFS_NEWERXY_OPT,
5319                         .name = "newerac",      .has_arg = required_argument},
5320         { .val = LFS_NEWERXY_OPT,
5321                         .name = "newerab",      .has_arg = required_argument},
5322         { .val = LFS_NEWERXY_OPT,
5323                         .name = "newerma",      .has_arg = required_argument},
5324         { .val = LFS_NEWERXY_OPT,
5325                         .name = "newermm",      .has_arg = required_argument},
5326         { .val = LFS_NEWERXY_OPT,
5327                         .name = "newermc",      .has_arg = required_argument},
5328         { .val = LFS_NEWERXY_OPT,
5329                         .name = "newermb",      .has_arg = required_argument},
5330         { .val = LFS_NEWERXY_OPT,
5331                         .name = "newerca",      .has_arg = required_argument},
5332         { .val = LFS_NEWERXY_OPT,
5333                         .name = "newercm",      .has_arg = required_argument},
5334         { .val = LFS_NEWERXY_OPT,
5335                         .name = "newercc",      .has_arg = required_argument},
5336         { .val = LFS_NEWERXY_OPT,
5337                         .name = "newercb",      .has_arg = required_argument},
5338         { .val = LFS_NEWERXY_OPT,
5339                         .name = "newerba",      .has_arg = required_argument},
5340         { .val = LFS_NEWERXY_OPT,
5341                         .name = "newerbm",      .has_arg = required_argument},
5342         { .val = LFS_NEWERXY_OPT,
5343                         .name = "newerbc",      .has_arg = required_argument},
5344         { .val = LFS_NEWERXY_OPT,
5345                         .name = "newerbb",      .has_arg = required_argument},
5346         { .val = LFS_NEWERXY_OPT,
5347                         .name = "newerBa",      .has_arg = required_argument},
5348         { .val = LFS_NEWERXY_OPT,
5349                         .name = "newerBm",      .has_arg = required_argument},
5350         { .val = LFS_NEWERXY_OPT,
5351                         .name = "newerBc",      .has_arg = required_argument},
5352         { .val = LFS_NEWERXY_OPT,
5353                         .name = "newerBB",      .has_arg = required_argument},
5354         { .val = LFS_NEWERXY_OPT,
5355                         .name = "newerat",      .has_arg = required_argument},
5356         { .val = LFS_NEWERXY_OPT,
5357                         .name = "newermt",      .has_arg = required_argument},
5358         { .val = LFS_NEWERXY_OPT,
5359                         .name = "newerct",      .has_arg = required_argument},
5360         { .val = LFS_NEWERXY_OPT,
5361                         .name = "newerbt",      .has_arg = required_argument},
5362         { .val = LFS_NEWERXY_OPT,
5363                         .name = "newerBt",      .has_arg = required_argument},
5364         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument },
5365         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument },
5366         { .val = 'C',   .name = "ctime",        .has_arg = required_argument },
5367 /* getstripe { .val = 'd', .name = "directory", .has_arg = no_argument }, */
5368         { .val = 'D',   .name = "maxdepth",     .has_arg = required_argument },
5369         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument },
5370         { .val = 'E',   .name = "component-end",
5371                                                 .has_arg = required_argument },
5372 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
5373         { .val = LFS_LAYOUT_FOREIGN_OPT,
5374                         .name = "foreign",      .has_arg = optional_argument},
5375         { .val = 'g',   .name = "gid",          .has_arg = required_argument },
5376         { .val = 'G',   .name = "group",        .has_arg = required_argument },
5377         { .val = 'h',   .name = "help",         .has_arg = no_argument },
5378         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
5379         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument },
5380         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument },
5381 /* getstripe { .val = 'I', .name = "comp-id",   .has_arg = required_argument }*/
5382         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
5383         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
5384         { .val = LFS_LINKS_OPT,
5385                         .name = "links",        .has_arg = required_argument },
5386         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
5387         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
5388         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument },
5389         { .val = 'M',   .name = "mtime",        .has_arg = required_argument },
5390         { .val = 'n',   .name = "name",         .has_arg = required_argument },
5391         { .val = 'N',   .name = "mirror-count", .has_arg = required_argument },
5392 /* find { .val = 'o'    .name = "or", .has_arg = no_argument }, like find(1) */
5393         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
5394         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
5395         { .val = LFS_FIND_PERM,
5396                         .name = "perm",         .has_arg = required_argument },
5397         /* no short option for pool yet, can be 'p' after 2.18 */
5398         { .val = LFS_POOL_OPT,
5399                         .name = "pool",         .has_arg = required_argument },
5400         { .val = '0',   .name = "print0",       .has_arg = no_argument },
5401         { .val = 'P',   .name = "print",        .has_arg = no_argument },
5402         { .val = LFS_PRINTF_OPT,
5403                         .name = "printf",       .has_arg = required_argument },
5404         { .val = LFS_PROJID_OPT,
5405                         .name = "projid",       .has_arg = required_argument },
5406 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
5407 /* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
5408 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
5409         { .val = 's',   .name = "size",         .has_arg = required_argument },
5410         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
5411         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
5412         { .val = 't',   .name = "type",         .has_arg = required_argument },
5413         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
5414         { .val = 'u',   .name = "uid",          .has_arg = required_argument },
5415         { .val = 'U',   .name = "user",         .has_arg = required_argument },
5416 /* getstripe { .val = 'v', .name = "verbose",   .has_arg = no_argument }, */
5417 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }, */
5418         { .val = LFS_XATTRS_MATCH_OPT,
5419                         .name = "xattr",        .has_arg = required_argument },
5420         { .val = 'z',   .name = "extension-size",
5421                                                 .has_arg = required_argument },
5422         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument },
5423         { .name = NULL } };
5424         int prev_optind = optind;
5425         int optidx = 0;
5426         int pathstart = -1;
5427         int pathend = -1;
5428         int neg_opt = 0;
5429         time_t *xtime;
5430         int *xsign;
5431         int isoption;
5432         char *endptr;
5433
5434         time(&t);
5435
5436         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
5437         while ((c = getopt_long_only(argc, argv,
5438                 "-0A:b:B:c:C:D:E:g:G:hH:i:lL:m:M:n:N:O:Ppqrs:S:t:T:u:U:z:",
5439                 long_opts, &optidx)) >= 0) {
5440                 xtime = NULL;
5441                 xsign = NULL;
5442                 if (neg_opt)
5443                         --neg_opt;
5444                 /* '!' is part of option */
5445                 /*
5446                  * when getopt_long_only() finds a string which is not
5447                  * an option nor a known option argument it returns 1
5448                  * in that case if we already have found pathstart and pathend
5449                  * (i.e. we have the list of pathnames),
5450                  * the only supported value is "!"
5451                  */
5452                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
5453                 if (!isoption && pathend != -1) {
5454                         fprintf(stderr,
5455                                 "err: %s: filename|dirname must either precede options or follow options\n",
5456                                 argv[0]);
5457                         ret = CMD_HELP;
5458                         goto err;
5459                 }
5460                 if (!isoption && pathstart == -1)
5461                         pathstart = prev_optind;
5462                 if (isoption && pathstart != -1 && pathend == -1)
5463                         pathend = prev_optind;
5464
5465                 prev_optind = optind;
5466
5467                 switch (c) {
5468                 case 0:
5469                         /* Long options. */
5470                         break;
5471                 case 1:
5472                         /*
5473                          * unknown; opt is "!" or path component,
5474                          * checking done above.
5475                          */
5476                         if (strcmp(optarg, "!") == 0)
5477                                 neg_opt = 2;
5478                         break;
5479                 case 'A':
5480                         xtime = &param.fp_atime;
5481                         xsign = &param.fp_asign;
5482                         param.fp_exclude_atime = !!neg_opt;
5483                         /* no break, this falls through to 'B' for btime */
5484                         fallthrough;
5485                 case 'B':
5486                         if (c == 'B') {
5487                                 xtime = &param.fp_btime;
5488                                 xsign = &param.fp_bsign;
5489                                 param.fp_exclude_btime = !!neg_opt;
5490                         }
5491                         /* no break, this falls through to 'C' for ctime */
5492                         fallthrough;
5493                 case 'C':
5494                         if (c == 'C') {
5495                                 xtime = &param.fp_ctime;
5496                                 xsign = &param.fp_csign;
5497                                 param.fp_exclude_ctime = !!neg_opt;
5498                         }
5499                         /* no break, this falls through to 'M' for mtime */
5500                         fallthrough;
5501                 case 'M':
5502                         if (c == 'M') {
5503                                 xtime = &param.fp_mtime;
5504                                 xsign = &param.fp_msign;
5505                                 param.fp_exclude_mtime = !!neg_opt;
5506                         }
5507                         rc = set_time(&param, &t, xtime, optarg);
5508                         if (rc == INT_MAX) {
5509                                 ret = -1;
5510                                 goto err;
5511                         }
5512                         if (rc)
5513                                 *xsign = rc;
5514                         break;
5515                 case LFS_ATTRS_OPT:
5516                         ret = name2attrs(optarg, &param.fp_attrs,
5517                                          &param.fp_neg_attrs);
5518                         if (ret)
5519                                 goto err;
5520                         param.fp_exclude_attrs = !!neg_opt;
5521                         break;
5522                 case 'b':
5523                         if (optarg[0] == '+') {
5524                                 param.fp_blocks_sign = -1;
5525                                 optarg++;
5526                         } else if (optarg[0] == '-') {
5527                                 param.fp_blocks_sign =  1;
5528                                 optarg++;
5529                         }
5530
5531                         param.fp_blocks_units = 512;
5532                         ret = llapi_parse_size(optarg, &param.fp_blocks,
5533                                                &param.fp_blocks_units, 0);
5534                         if (ret) {
5535                                 fprintf(stderr, "error: bad blocks '%s'\n",
5536                                         optarg);
5537                                 goto err;
5538                         }
5539                         param.fp_check_blocks = 1;
5540                         param.fp_exclude_blocks = !!neg_opt;
5541                         break;
5542                 case LFS_COMP_COUNT_OPT:
5543                         if (optarg[0] == '+') {
5544                                 param.fp_comp_count_sign = -1;
5545                                 optarg++;
5546                         } else if (optarg[0] == '-') {
5547                                 param.fp_comp_count_sign =  1;
5548                                 optarg++;
5549                         }
5550
5551                         errno = 0;
5552                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
5553                         if (errno != 0 || *endptr != '\0' ||
5554                             param.fp_comp_count > UINT32_MAX) {
5555                                 fprintf(stderr,
5556                                         "error: bad component count '%s'\n",
5557                                         optarg);
5558                                 goto err;
5559                         }
5560                         param.fp_check_comp_count = 1;
5561                         param.fp_exclude_comp_count = !!neg_opt;
5562                         break;
5563                 case LFS_COMP_FLAGS_OPT:
5564                         rc = comp_str2flags(optarg, &param.fp_comp_flags,
5565                                             &param.fp_comp_neg_flags);
5566                         if (rc) {
5567                                 fprintf(stderr,
5568                                         "error: bad component flags '%s'\n",
5569                                         optarg);
5570                                 goto err;
5571                         }
5572                         param.fp_check_comp_flags = 1;
5573                         if (neg_opt) {
5574                                 __u32 flags = param.fp_comp_neg_flags;
5575
5576                                 param.fp_comp_neg_flags = param.fp_comp_flags;
5577                                 param.fp_comp_flags = flags;
5578                         }
5579                         break;
5580                 case LFS_COMP_START_OPT:
5581                         if (optarg[0] == '+') {
5582                                 param.fp_comp_start_sign = -1;
5583                                 optarg++;
5584                         } else if (optarg[0] == '-') {
5585                                 param.fp_comp_start_sign =  1;
5586                                 optarg++;
5587                         }
5588
5589                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
5590                                               &param.fp_comp_start_units, 0);
5591                         if (rc) {
5592                                 fprintf(stderr,
5593                                         "error: bad component start '%s'\n",
5594                                         optarg);
5595                                 goto err;
5596                         }
5597                         param.fp_check_comp_start = 1;
5598                         param.fp_exclude_comp_start = !!neg_opt;
5599                         break;
5600                 case LFS_MIRROR_STATE_OPT:
5601                         rc = mirror_str2state(optarg, &param.fp_mirror_state,
5602                                               &param.fp_mirror_neg_state);
5603                         if (rc) {
5604                                 fprintf(stderr,
5605                                         "error: bad mirrored file state '%s'\n",
5606                                         optarg);
5607                                 goto err;
5608                         }
5609                         param.fp_check_mirror_state = 1;
5610                         if (neg_opt) {
5611                                 __u16 state = param.fp_mirror_neg_state;
5612
5613                                 param.fp_mirror_neg_state =
5614                                         param.fp_mirror_state;
5615                                 param.fp_mirror_state = state;
5616                         }
5617                         break;
5618                 case 'c':
5619                         if (optarg[0] == '+') {
5620                                 param.fp_stripe_count_sign = -1;
5621                                 optarg++;
5622                         } else if (optarg[0] == '-') {
5623                                 param.fp_stripe_count_sign =  1;
5624                                 optarg++;
5625                         }
5626
5627                         errno = 0;
5628                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
5629                         if (errno != 0 || *endptr != '\0' ||
5630                             param.fp_stripe_count > LOV_MAX_STRIPE_COUNT) {
5631                                 fprintf(stderr,
5632                                         "error: bad stripe_count '%s'\n",
5633                                         optarg);
5634                                 ret = -1;
5635                                 goto err;
5636                         }
5637                         param.fp_check_stripe_count = 1;
5638                         param.fp_exclude_stripe_count = !!neg_opt;
5639                         break;
5640                 case 'D':
5641                         errno = 0;
5642                         param.fp_max_depth = strtol(optarg, 0, 0);
5643                         if (errno != 0 || param.fp_max_depth < 0) {
5644                                 fprintf(stderr,
5645                                         "error: bad maxdepth '%s'\n",
5646                                         optarg);
5647                                 ret = -1;
5648                                 goto err;
5649                         }
5650                         break;
5651                 case 'E':
5652                         if (optarg[0] == '+') {
5653                                 param.fp_comp_end_sign = -1;
5654                                 optarg++;
5655                         } else if (optarg[0] == '-') {
5656                                 param.fp_comp_end_sign =  1;
5657                                 optarg++;
5658                         }
5659
5660                         if (arg_is_eof(optarg)) {
5661                                 param.fp_comp_end = LUSTRE_EOF;
5662                                 param.fp_comp_end_units = 1;
5663                                 rc = 0;
5664                         } else {
5665                                 rc = llapi_parse_size(optarg,
5666                                                 &param.fp_comp_end,
5667                                                 &param.fp_comp_end_units, 0);
5668                                 /* assume units of KB if too small */
5669                                 if (param.fp_comp_end < 4096)
5670                                         param.fp_comp_end *= 1024;
5671                         }
5672                         if (rc) {
5673                                 fprintf(stderr,
5674                                         "error: bad component end '%s'\n",
5675                                         optarg);
5676                                 goto err;
5677                         }
5678                         param.fp_check_comp_end = 1;
5679                         param.fp_exclude_comp_end = !!neg_opt;
5680                         break;
5681                 case LFS_LAYOUT_FOREIGN_OPT: {
5682                         /* all types by default */
5683                         uint32_t type = LU_FOREIGN_TYPE_UNKNOWN;
5684
5685                         if (optarg) {
5686                                 /* check pure numeric */
5687                                 type = strtoul(optarg, &endptr, 0);
5688                                 if (*endptr) {
5689                                         /* check name */
5690                                         type = check_foreign_type_name(optarg);
5691                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
5692                                                 fprintf(stderr,
5693                                                         "%s %s: unknown foreign type '%s'\n",
5694                                                         progname, argv[0],
5695                                                         optarg);
5696                                                 return CMD_HELP;
5697                                         }
5698                                 } else if (type >= UINT32_MAX) {
5699                                         fprintf(stderr,
5700                                                 "%s %s: invalid foreign type '%s'\n",
5701                                                 progname, argv[0], optarg);
5702                                         return CMD_HELP;
5703                                 }
5704                         }
5705                         param.fp_foreign_type = type;
5706                         param.fp_check_foreign = 1;
5707                         param.fp_exclude_foreign = !!neg_opt;
5708                         break;
5709                 }
5710                 case LFS_NEWERXY_OPT: {
5711                         char x = 'm';
5712                         char y = 'm';
5713                         int xidx;
5714                         int negidx;
5715                         time_t *newery;
5716                         time_t ref = time(NULL);
5717
5718                         /* no need to check bad options, they won't get here */
5719                         if (strlen(long_opts[optidx].name) == 7) {
5720                                 x = long_opts[optidx].name[5];
5721                                 y = long_opts[optidx].name[6];
5722                         }
5723
5724                         if (y == 't') {
5725                                 static const char *const fmts[] = {
5726                                         "%Y-%m-%d %H:%M:%S",
5727                                         "%Y-%m-%d %H:%M",
5728                                         "%Y-%m-%d",
5729                                         "%H:%M:%S", /* sometime today */
5730                                         "%H:%M",
5731                                         "@%s",
5732                                         "%s",
5733                                         NULL };
5734                                 struct tm tm;
5735                                 bool found = false;
5736                                 int i;
5737
5738                                 for (i = 0; fmts[i] != NULL; i++) {
5739                                         char *ptr;
5740
5741                                         /* Init for times relative to today */
5742                                         if (strncmp(fmts[i], "%H", 2) == 0) {
5743                                                 localtime_r(&ref, &tm);
5744                                         } else {
5745                                                 memset(&tm, 0, sizeof(tm));
5746                                                 tm.tm_isdst = -1;
5747                                         }
5748                                         ptr = strptime(optarg, fmts[i], &tm);
5749                                         /* Skip spaces */
5750                                         while (ptr && isspace(*ptr))
5751                                                 ptr++;
5752                                         if (ptr == optarg + strlen(optarg)) {
5753                                                 found = true;
5754                                                 break;
5755                                         }
5756                                 }
5757
5758                                 if (!found) {
5759                                         fprintf(stderr,
5760                                                 "%s: invalid time '%s'\n",
5761                                                 progname, optarg);
5762                                         fprintf(stderr,
5763                                                 "supported formats are:\n  ");
5764                                         for (i = 0; fmts[i] != NULL; i++)
5765                                                 fprintf(stderr, "'%s', ",
5766                                                         fmts[i]);
5767                                         fprintf(stderr, "\n");
5768                                         ret = -EINVAL;
5769                                         goto err;
5770                                 }
5771
5772                                 ref = mktime(&tm);
5773                         } else if (y == 'b' || y == 'B') {
5774                                 lstatx_t stx;
5775
5776                                 rc = llapi_get_lum_file(optarg, NULL, &stx,
5777                                                         NULL, 0);
5778                                 if (rc || !(stx.stx_mask & STATX_BTIME)) {
5779                                         if (!(stx.stx_mask & STATX_BTIME))
5780                                                 ret = -EOPNOTSUPP;
5781                                         else
5782                                                 ret = -errno;
5783                                         fprintf(stderr,
5784                                                 "%s: get btime failed '%s': %s\n",
5785                                                 progname, optarg,
5786                                                 strerror(-ret));
5787                                         goto err;
5788                                 }
5789
5790                                 ref = stx.stx_btime.tv_sec;
5791                         } else {
5792                                 struct stat statbuf;
5793
5794                                 if (stat(optarg, &statbuf) < 0) {
5795                                         fprintf(stderr,
5796                                                 "%s: cannot stat file '%s': %s\n",
5797                                                 progname, optarg,
5798                                                 strerror(errno));
5799                                         ret = -errno;
5800                                         goto err;
5801                                 }
5802
5803                                 switch (y) {
5804                                 case 'a':
5805                                         ref = statbuf.st_atime;
5806                                         break;
5807                                 case 'm':
5808                                         ref = statbuf.st_mtime;
5809                                         break;
5810                                 case 'c':
5811                                         ref = statbuf.st_ctime;
5812                                         break;
5813                                 default:
5814                                         fprintf(stderr,
5815                                                 "%s: invalid Y argument: '%c'\n",
5816                                                 progname, x);
5817                                         ret = -EINVAL;
5818                                         goto err;
5819                                 }
5820                         }
5821
5822                         switch (x) {
5823                         case 'a':
5824                                 xidx = NEWERXY_ATIME;
5825                                 break;
5826                         case 'm':
5827                                 xidx = NEWERXY_MTIME;
5828                                 break;
5829                         case 'c':
5830                                 xidx = NEWERXY_CTIME;
5831                                 break;
5832                         case 'b':
5833                         case 'B':
5834                                 xidx = NEWERXY_BTIME;
5835                                 break;
5836                         default:
5837                                 fprintf(stderr,
5838                                         "%s: invalid X argument: '%c'\n",
5839                                         progname, x);
5840                                 ret = -EINVAL;
5841                                 goto err;
5842                         }
5843
5844                         negidx = !!neg_opt;
5845                         newery = &param.fp_newery[xidx][negidx];
5846
5847                         if (*newery == 0) {
5848                                 *newery = ref;
5849                         } else {
5850                                 if (negidx)
5851                                         *newery = *newery > ref ? ref : *newery;
5852                                 else
5853                                         *newery = *newery > ref ? *newery : ref;
5854                         }
5855                         param.fp_newerxy = 1;
5856                         break;
5857                 }
5858                 case 'g':
5859                 case 'G':
5860                         rc = name2gid(&param.fp_gid, optarg);
5861                         if (rc) {
5862                                 if (str2quotaid(&param.fp_gid, optarg)) {
5863                                         fprintf(stderr,
5864                                                 "Group/GID: %s cannot be found.\n",
5865                                                 optarg);
5866                                         ret = -1;
5867                                         goto err;
5868                                 }
5869                         }
5870                         param.fp_exclude_gid = !!neg_opt;
5871                         param.fp_check_gid = 1;
5872                         break;
5873                 case 'H':
5874                         rc = mdthash_input(optarg, &param.fp_hash_inflags,
5875                                            &param.fp_hash_exflags,
5876                                            &param.fp_hash_type);
5877                         if (rc) {
5878                                 ret = -1;
5879                                 goto err;
5880                         }
5881                         if (param.fp_hash_inflags || param.fp_hash_exflags)
5882                                 param.fp_check_hash_flag = 1;
5883                         param.fp_exclude_hash_type = !!neg_opt;
5884                         break;
5885                 case 'l':
5886                         param.fp_lazy = 1;
5887                         break;
5888                 case 'L':
5889                         ret = name2layout(&param.fp_layout, optarg);
5890                         if (ret)
5891                                 goto err;
5892                         param.fp_exclude_layout = !!neg_opt;
5893                         param.fp_check_layout = 1;
5894                         break;
5895                 case LFS_LINKS_OPT:
5896                         if (optarg[0] == '+') {
5897                                 param.fp_nlink_sign = -1;
5898                                 optarg++;
5899                         } else if (optarg[0] == '-') {
5900                                 param.fp_nlink_sign =  1;
5901                                 optarg++;
5902                         }
5903                         errno = 0;
5904                         param.fp_nlink = strtoul(optarg, &endptr, 0);
5905                         if (errno != 0 || *endptr != '\0' || !param.fp_nlink) {
5906                                 fprintf(stderr, "error: bad link count '%s'\n",
5907                                         optarg);
5908                                 ret = -1;
5909                                 goto err;
5910                         }
5911                         param.fp_exclude_nlink = !!neg_opt;
5912                         break;
5913                 case 'u':
5914                 case 'U':
5915                         rc = name2uid(&param.fp_uid, optarg);
5916                         if (rc) {
5917                                 if (str2quotaid(&param.fp_uid, optarg)) {
5918                                         fprintf(stderr,
5919                                                 "User/UID: %s cannot be found.\n",
5920                                                 optarg);
5921                                         ret = -1;
5922                                         goto err;
5923                                 }
5924                         }
5925                         param.fp_exclude_uid = !!neg_opt;
5926                         param.fp_check_uid = 1;
5927                         break;
5928                 case 'n':
5929                         param.fp_pattern = (char *)optarg;
5930                         param.fp_exclude_pattern = !!neg_opt;
5931                         break;
5932                 case 'N':
5933                         if (optarg[0] == '+') {
5934                                 param.fp_mirror_count_sign = -1;
5935                                 optarg++;
5936                         } else if (optarg[0] == '-') {
5937                                 param.fp_mirror_count_sign =  1;
5938                                 optarg++;
5939                         }
5940
5941                         errno = 0;
5942                         param.fp_mirror_count = strtoul(optarg, &endptr, 0);
5943                         if (errno != 0 || *endptr != '\0' ||
5944                             param.fp_mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
5945                                 fprintf(stderr,
5946                                         "error: bad mirror count '%s'\n",
5947                                         optarg);
5948                                 goto err;
5949                         }
5950                         param.fp_check_mirror_count = 1;
5951                         param.fp_exclude_mirror_count = !!neg_opt;
5952                         break;
5953                 case 'm':
5954                 case 'i':
5955                 case 'O': {
5956                         char *buf, *token, *next, *p;
5957                         int len = 1;
5958                         void *tmp;
5959
5960                         buf = strdup(optarg);
5961                         if (!buf) {
5962                                 ret = -ENOMEM;
5963                                 goto err;
5964                         }
5965
5966                         param.fp_exclude_obd = !!neg_opt;
5967
5968                         token = buf;
5969                         while (token && *token) {
5970                                 token = strchr(token, ',');
5971                                 if (token) {
5972                                         len++;
5973                                         token++;
5974                                 }
5975                         }
5976                         if (c == 'm') {
5977                                 param.fp_exclude_mdt = !!neg_opt;
5978                                 param.fp_num_alloc_mdts += len;
5979                                 tmp = realloc(param.fp_mdt_uuid,
5980                                               param.fp_num_alloc_mdts *
5981                                               sizeof(*param.fp_mdt_uuid));
5982                                 if (!tmp) {
5983                                         ret = -ENOMEM;
5984                                         goto err_free;
5985                                 }
5986
5987                                 param.fp_mdt_uuid = tmp;
5988                         } else {
5989                                 param.fp_exclude_obd = !!neg_opt;
5990                                 param.fp_num_alloc_obds += len;
5991                                 tmp = realloc(param.fp_obd_uuid,
5992                                               param.fp_num_alloc_obds *
5993                                               sizeof(*param.fp_obd_uuid));
5994                                 if (!tmp) {
5995                                         ret = -ENOMEM;
5996                                         goto err_free;
5997                                 }
5998
5999                                 param.fp_obd_uuid = tmp;
6000                         }
6001                         for (token = buf; token && *token; token = next) {
6002                                 struct obd_uuid *puuid;
6003
6004                                 if (c == 'm') {
6005                                         puuid =
6006                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
6007                                 } else {
6008                                         puuid =
6009                                         &param.fp_obd_uuid[param.fp_num_obds++];
6010                                 }
6011                                 p = strchr(token, ',');
6012                                 next = 0;
6013                                 if (p) {
6014                                         *p = 0;
6015                                         next = p+1;
6016                                 }
6017
6018                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
6019                                         ret = -E2BIG;
6020                                         goto err_free;
6021                                 }
6022
6023                                 strncpy(puuid->uuid, token,
6024                                         sizeof(puuid->uuid));
6025                         }
6026 err_free:
6027                         if (buf)
6028                                 free(buf);
6029                         break;
6030                 }
6031 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 18, 53, 0)
6032                 case 'p':
6033 #endif
6034                 case LFS_POOL_OPT:
6035                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
6036                                 fprintf(stderr,
6037                                         "Pool name %s is too long (max %d)\n",
6038                                         optarg, LOV_MAXPOOLNAME);
6039                                 ret = -1;
6040                                 goto err;
6041                         }
6042                         /*
6043                          * We do check for empty pool because empty pool
6044                          * is used to find V1 LOV attributes
6045                          */
6046                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
6047                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
6048                         param.fp_exclude_pool = !!neg_opt;
6049                         param.fp_check_pool = 1;
6050                         break;
6051                 case '0':
6052                         param.fp_zero_end = 1;
6053                         break;
6054                 case 'P': /* we always print, this option is a no-op */
6055                         break;
6056                 case LFS_PRINTF_OPT:
6057                         param.fp_format_printf_str = strdup(optarg);
6058                         break;
6059                 case LFS_PROJID_OPT:
6060                         rc = name2projid(&param.fp_projid, optarg);
6061                         if (rc) {
6062                                 if (str2quotaid(&param.fp_projid, optarg)) {
6063                                         fprintf(stderr,
6064                                                 "Invalid project ID: %s\n",
6065                                                 optarg);
6066                                         ret = -1;
6067                                         goto err;
6068                                 }
6069                         }
6070                         param.fp_exclude_projid = !!neg_opt;
6071                         param.fp_check_projid = 1;
6072                         break;
6073                 case 's':
6074                         if (optarg[0] == '+') {
6075                                 param.fp_size_sign = -1;
6076                                 optarg++;
6077                         } else if (optarg[0] == '-') {
6078                                 param.fp_size_sign =  1;
6079                                 optarg++;
6080                         }
6081
6082                         param.fp_size_units = 512;
6083                         ret = llapi_parse_size(optarg, &param.fp_size,
6084                                                &param.fp_size_units, 0);
6085                         if (ret) {
6086                                 fprintf(stderr, "error: bad file size '%s'\n",
6087                                         optarg);
6088                                 goto err;
6089                         }
6090                         param.fp_check_size = 1;
6091                         param.fp_exclude_size = !!neg_opt;
6092                         break;
6093                 case 'S':
6094                         if (optarg[0] == '+') {
6095                                 param.fp_stripe_size_sign = -1;
6096                                 optarg++;
6097                         } else if (optarg[0] == '-') {
6098                                 param.fp_stripe_size_sign =  1;
6099                                 optarg++;
6100                         }
6101
6102                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
6103                                                &param.fp_stripe_size_units, 0);
6104                         /* assume units of KB if too small to be valid */
6105                         if (param.fp_stripe_size < 4096)
6106                                 param.fp_stripe_size *= 1024;
6107                         if (ret) {
6108                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
6109                                         optarg);
6110                                 goto err;
6111                         }
6112                         param.fp_check_stripe_size = 1;
6113                         param.fp_exclude_stripe_size = !!neg_opt;
6114                         break;
6115                 case 't':
6116                         param.fp_exclude_type = !!neg_opt;
6117                         switch (optarg[0]) {
6118                         case 'b':
6119                                 param.fp_type = S_IFBLK;
6120                                 break;
6121                         case 'c':
6122                                 param.fp_type = S_IFCHR;
6123                                 break;
6124                         case 'd':
6125                                 param.fp_type = S_IFDIR;
6126                                 break;
6127                         case 'f':
6128                                 param.fp_type = S_IFREG;
6129                                 break;
6130                         case 'l':
6131                                 param.fp_type = S_IFLNK;
6132                                 break;
6133                         case 'p':
6134                                 param.fp_type = S_IFIFO;
6135                                 break;
6136                         case 's':
6137                                 param.fp_type = S_IFSOCK;
6138                                 break;
6139                         default:
6140                                 fprintf(stderr, "%s: bad type '%s'\n",
6141                                         progname, optarg);
6142                                 ret = CMD_HELP;
6143                                 goto err;
6144                         }
6145                         break;
6146                 case LFS_FIND_PERM:
6147                         param.fp_exclude_perm = !!neg_opt;
6148                         param.fp_perm_sign = LFS_FIND_PERM_EXACT;
6149                         if (*optarg == '/') {
6150                                 param.fp_perm_sign = LFS_FIND_PERM_ANY;
6151                                 optarg++;
6152                         } else if (*optarg == '-') {
6153                                 param.fp_perm_sign = LFS_FIND_PERM_ALL;
6154                                 optarg++;
6155                         }
6156
6157                         if (str2mode_t(optarg, &param.fp_perm)) {
6158                                 fprintf(stderr, "error: invalid mode '%s'\n",
6159                                         optarg);
6160                                 ret = -1;
6161                                 goto err;
6162                         }
6163                         break;
6164                 case 'T':
6165                         if (optarg[0] == '+') {
6166                                 param.fp_mdt_count_sign = -1;
6167                                 optarg++;
6168                         } else if (optarg[0] == '-') {
6169                                 param.fp_mdt_count_sign =  1;
6170                                 optarg++;
6171                         }
6172
6173                         errno = 0;
6174                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
6175                         if (errno != 0 || *endptr != '\0' ||
6176                             param.fp_mdt_count >= UINT32_MAX) {
6177                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
6178                                         optarg);
6179                                 ret = -1;
6180                                 goto err;
6181                         }
6182                         param.fp_check_mdt_count = 1;
6183                         param.fp_exclude_mdt_count = !!neg_opt;
6184                         break;
6185                 case LFS_XATTRS_MATCH_OPT:
6186                         ret = compile_xattr_match_regex(optarg, neg_opt,
6187                                                         &param);
6188                         if (ret)
6189                                 goto err;
6190                         break;
6191                 case 'z':
6192                         if (optarg[0] == '+') {
6193                                 param.fp_ext_size_sign = -1;
6194                                 optarg++;
6195                         } else if (optarg[0] == '-') {
6196                                 param.fp_ext_size_sign =  1;
6197                                 optarg++;
6198                         }
6199
6200                         ret = llapi_parse_size(optarg, &param.fp_ext_size,
6201                                                &param.fp_ext_size_units, 0);
6202                         if (ret) {
6203                                 fprintf(stderr, "error: bad ext-size '%s'\n",
6204                                         optarg);
6205                                 goto err;
6206                         }
6207                         param.fp_ext_size /= SEL_UNIT_SIZE;
6208                         param.fp_ext_size_units /= SEL_UNIT_SIZE;
6209                         param.fp_check_ext_size = 1;
6210                         param.fp_exclude_ext_size = !!neg_opt;
6211                         break;
6212                 default:
6213                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6214                                 progname, argv[optind - 1]);
6215                 case 'h':
6216                         ret = CMD_HELP;
6217                         goto err;
6218                 }
6219         }
6220         if (!param.fp_verbose)
6221                 param.fp_verbose = VERBOSE_DEFAULT;
6222
6223         if (pathstart == -1) {
6224                 fprintf(stderr, "error: %s: no filename|pathname\n",
6225                         argv[0]);
6226                 ret = CMD_HELP;
6227                 goto err;
6228         } else if (pathend == -1) {
6229                 /* no options */
6230                 pathend = argc;
6231         }
6232
6233         do {
6234                 rc = llapi_find(argv[pathstart], &param);
6235                 if (rc) {
6236                         if (!ret)
6237                                 ret = rc;
6238
6239                         fprintf(stderr, "%s: failed for '%s': %s\n",
6240                                 progname, argv[pathstart], strerror(-rc));
6241                 }
6242         } while (++pathstart < pathend);
6243
6244 err:
6245         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
6246                 free(param.fp_obd_uuid);
6247
6248         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
6249                 free(param.fp_mdt_uuid);
6250
6251         if (param.fp_format_printf_str)
6252                 free(param.fp_format_printf_str);
6253
6254         if (param.fp_xattr_match_info) {
6255                 xattr_match_info_free(param.fp_xattr_match_info);
6256                 free(param.fp_xattr_match_info);
6257                 param.fp_xattr_match_info = NULL;
6258         }
6259
6260         return ret;
6261 }
6262
6263 static int lfs_getstripe_internal(int argc, char **argv,
6264                                   struct find_param *param)
6265 {
6266         struct option long_opts[] = {
6267 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
6268 /* find { .val = 'b',   .name = "blocks",       .has_arg = required_argument }*/
6269 /* find { .val = 'B',   .name = "btime",        .has_arg = required_argument }*/
6270 /* find { .val = 'B',   .name = "Btime",        .has_arg = required_argument }*/
6271         { .val = LFS_COMP_COUNT_OPT,
6272                         .name = "comp-count",   .has_arg = no_argument },
6273         { .val = LFS_COMP_COUNT_OPT,
6274                 .name = "component-count",      .has_arg = no_argument },
6275         { .val = LFS_COMP_FLAGS_OPT,
6276                         .name = "comp-flags",   .has_arg = optional_argument },
6277         { .val = LFS_COMP_FLAGS_OPT,
6278                 .name = "component-flags",      .has_arg = optional_argument },
6279         { .val = LFS_COMP_START_OPT,
6280                         .name = "comp-start",   .has_arg = optional_argument },
6281         { .val = LFS_COMP_START_OPT,
6282                 .name = "component-start",      .has_arg = optional_argument },
6283         { .val = 'c',   .name = "stripe-count", .has_arg = no_argument },
6284         { .val = 'c',   .name = "stripe_count", .has_arg = no_argument },
6285 /* find { .val = 'C',   .name = "ctime",        .has_arg = required_argument }*/
6286         { .val = 'd',   .name = "directory",    .has_arg = no_argument },
6287         { .val = 'D',   .name = "default",      .has_arg = no_argument },
6288         { .val = 'E',   .name = "comp-end",     .has_arg = optional_argument },
6289         { .val = 'E',   .name = "component-end", .has_arg = optional_argument },
6290         { .val = 'F',   .name = "fid",          .has_arg = no_argument },
6291         { .val = 'g',   .name = "generation",   .has_arg = no_argument },
6292 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
6293         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6294         { .val = LFS_HEX_IDX_OPT,
6295                         .name = "hex-idx",      .has_arg = no_argument },
6296 /* dirstripe { .val = 'H', .name = "mdt-hash",  .has_arg = required_argument }*/
6297         { .val = 'i',   .name = "stripe-index", .has_arg = no_argument },
6298         { .val = 'i',   .name = "stripe_index", .has_arg = no_argument },
6299         { .val = 'I',   .name = "comp-id",      .has_arg = optional_argument },
6300         { .val = 'I',   .name = "component-id", .has_arg = optional_argument },
6301 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
6302         { .val = 'L',   .name = "layout",       .has_arg = no_argument },
6303         { .val = 'm',   .name = "mdt",          .has_arg = no_argument },
6304         { .val = 'm',   .name = "mdt-index",    .has_arg = no_argument },
6305         { .val = 'm',   .name = "mdt_index",    .has_arg = no_argument },
6306 /* find { .val = 'M',   .name = "mtime",        .has_arg = required_argument }*/
6307 /* find { .val = 'n',   .name = "name",         .has_arg = required_argument }*/
6308         { .val = 'N',   .name = "mirror-count", .has_arg = no_argument },
6309         { .val = LFS_MIRROR_INDEX_OPT,
6310                         .name = "mirror-index", .has_arg = required_argument },
6311         { .val = LFS_MIRROR_ID_OPT,
6312                         .name = "mirror-id",    .has_arg = required_argument },
6313         { .val = LFS_NO_FOLLOW_OPT,
6314                         .name = "no-follow",    .has_arg = no_argument },
6315         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
6316         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
6317         { .val = 'p',   .name = "pool",         .has_arg = no_argument },
6318 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
6319         { .val = 'q',   .name = "quiet",        .has_arg = no_argument },
6320         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
6321         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
6322         { .val = 'S',   .name = "stripe-size",  .has_arg = no_argument },
6323         { .val = 'S',   .name = "stripe_size",  .has_arg = no_argument },
6324 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
6325 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
6326 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
6327 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
6328         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
6329 /* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/
6330 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }*/
6331         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
6332         { .val = 'z',   .name = "extension-size", .has_arg = no_argument },
6333         { .val = 'z',   .name = "ext-size",     .has_arg = no_argument },
6334         { .name = NULL } };
6335         int c, rc = 0;
6336         int neg_opt = 0;
6337         int pathstart = -1, pathend = -1;
6338         int isoption;
6339         char *end, *tmp;
6340
6341         while ((c = getopt_long(argc, argv,
6342                         "-cdDE::FghiI::LmMNoO:pqrRsSvyz",
6343                         long_opts, NULL)) != -1) {
6344                 if (neg_opt)
6345                         --neg_opt;
6346
6347                 /* '!' is part of option */
6348                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
6349                 if (!isoption && pathend != -1) {
6350                         fprintf(stderr,
6351                                 "error: %s: filename|dirname must either precede options or follow options\n",
6352                                 argv[0]);
6353                         return CMD_HELP;
6354                 }
6355                 if (!isoption && pathstart == -1)
6356                         pathstart = optind - 1;
6357                 if (isoption && pathstart != -1 && pathend == -1)
6358                         pathend = optind - 2;
6359
6360                 switch (c) {
6361                 case 1:
6362                         /* unknown: opt is "!" */
6363                         if (strcmp(optarg, "!") == 0)
6364                                 neg_opt = 2;
6365                         break;
6366                 case 'c':
6367                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6368                                 param->fp_verbose |= VERBOSE_COUNT;
6369                                 param->fp_max_depth = 0;
6370                         }
6371                         break;
6372                 case LFS_COMP_COUNT_OPT:
6373                         param->fp_verbose |= VERBOSE_COMP_COUNT;
6374                         param->fp_max_depth = 0;
6375                         break;
6376                 case LFS_COMP_FLAGS_OPT:
6377                         if (optarg) {
6378                                 rc = comp_str2flags(optarg,
6379                                                     &param->fp_comp_flags,
6380                                                     &param->fp_comp_neg_flags);
6381                                 if (rc != 0) {
6382                                         fprintf(stderr,
6383                                                 "error: %s bad component flags '%s'.\n",
6384                                                 argv[0], optarg);
6385                                         return CMD_HELP;
6386                                 }
6387                                 param->fp_check_comp_flags = 1;
6388                         } else {
6389                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
6390                                 param->fp_max_depth = 0;
6391                         }
6392                         break;
6393                 case LFS_COMP_START_OPT:
6394                         if (optarg) {
6395                                 tmp = optarg;
6396                                 if (tmp[0] == '+') {
6397                                         param->fp_comp_start_sign = -1;
6398                                         tmp++;
6399                                 } else if (tmp[0] == '-') {
6400                                         param->fp_comp_start_sign = 1;
6401                                         tmp++;
6402                                 }
6403                                 rc = llapi_parse_size(tmp,
6404                                                 &param->fp_comp_start,
6405                                                 &param->fp_comp_start_units, 0);
6406                                 if (rc != 0) {
6407                                         fprintf(stderr,
6408                                                 "error: %s bad component start '%s'.\n",
6409                                                 argv[0], tmp);
6410                                         return CMD_HELP;
6411                                 }
6412                                 param->fp_check_comp_start = 1;
6413                         } else {
6414                                 param->fp_verbose |= VERBOSE_COMP_START;
6415                                 param->fp_max_depth = 0;
6416                         }
6417                         break;
6418                 case LFS_MIRROR_INDEX_OPT: {
6419                         unsigned long int mirror_index;
6420
6421                         if (optarg[0] == '+') {
6422                                 param->fp_mirror_index_sign = -1;
6423                                 optarg++;
6424                         } else if (optarg[0] == '-') {
6425                                 param->fp_mirror_index_sign = 1;
6426                                 optarg++;
6427                         }
6428
6429                         errno = 0;
6430                         mirror_index = strtoul(optarg, &end, 0);
6431                         if (errno != 0 || *end != '\0' ||
6432                             mirror_index > UINT16_MAX || (mirror_index == 0 &&
6433                             param->fp_mirror_index_sign == 0 && neg_opt == 0)) {
6434                                 fprintf(stderr,
6435                                         "%s %s: invalid mirror index '%s'\n",
6436                                         progname, argv[0], optarg);
6437                                 return CMD_HELP;
6438                         }
6439
6440                         param->fp_mirror_index = (__u16)mirror_index;
6441
6442                         if (param->fp_mirror_id != 0) {
6443                                 fprintf(stderr,
6444                                         "%s %s: can't specify both mirror index and mirror ID\n",
6445                                         progname, argv[0]);
6446                                 return CMD_HELP;
6447                         }
6448                         param->fp_check_mirror_index = 1;
6449                         param->fp_exclude_mirror_index = !!neg_opt;
6450                         break;
6451                 }
6452                 case LFS_MIRROR_ID_OPT: {
6453                         unsigned long int mirror_id;
6454
6455                         if (optarg[0] == '+') {
6456                                 param->fp_mirror_id_sign = -1;
6457                                 optarg++;
6458                         } else if (optarg[0] == '-') {
6459                                 param->fp_mirror_id_sign = 1;
6460                                 optarg++;
6461                         }
6462
6463                         errno = 0;
6464                         mirror_id = strtoul(optarg, &end, 0);
6465                         if (errno != 0 || *end != '\0' ||
6466                             mirror_id > UINT16_MAX || (mirror_id == 0 &&
6467                             param->fp_mirror_id_sign == 0 && neg_opt == 0)) {
6468                                 fprintf(stderr,
6469                                         "%s %s: invalid mirror ID '%s'\n",
6470                                         progname, argv[0], optarg);
6471                                 return CMD_HELP;
6472                         }
6473
6474                         param->fp_mirror_id = (__u16)mirror_id;
6475
6476                         if (param->fp_mirror_index != 0) {
6477                                 fprintf(stderr,
6478                                         "%s %s: can't specify both mirror index and mirror ID\n",
6479                                         progname, argv[0]);
6480                                 return CMD_HELP;
6481                         }
6482                         param->fp_check_mirror_id = 1;
6483                         param->fp_exclude_mirror_id = !!neg_opt;
6484                         break;
6485                 }
6486                 case LFS_NO_FOLLOW_OPT:
6487                         param->fp_no_follow = true;
6488                         break;
6489                 case LFS_HEX_IDX_OPT:
6490                         param->fp_hex_idx = true;
6491                         break;
6492                 case 'd':
6493                         param->fp_max_depth = 0;
6494                         break;
6495                 case 'D':
6496                         param->fp_get_default_lmv = 1;
6497                         break;
6498                 case 'E':
6499                         if (optarg) {
6500                                 tmp = optarg;
6501                                 if (tmp[0] == '+') {
6502                                         param->fp_comp_end_sign = -1;
6503                                         tmp++;
6504                                 } else if (tmp[0] == '-') {
6505                                         param->fp_comp_end_sign = 1;
6506                                         tmp++;
6507                                 }
6508
6509                                 if (arg_is_eof(tmp)) {
6510                                         param->fp_comp_end = LUSTRE_EOF;
6511                                         param->fp_comp_end_units = 1;
6512                                         rc = 0;
6513                                 } else {
6514                                         rc = llapi_parse_size(tmp,
6515                                                 &param->fp_comp_end,
6516                                                 &param->fp_comp_end_units, 0);
6517                                         /* assume units of KB if too small */
6518                                         if (param->fp_comp_end < 4096)
6519                                                 param->fp_comp_end *= 1024;
6520                                 }
6521                                 if (rc != 0) {
6522                                         fprintf(stderr,
6523                                                 "error: %s bad component end '%s'.\n",
6524                                                 argv[0], tmp);
6525                                         return CMD_HELP;
6526                                 }
6527                                 param->fp_check_comp_end = 1;
6528                         } else {
6529                                 param->fp_verbose |= VERBOSE_COMP_END;
6530                                 param->fp_max_depth = 0;
6531                         }
6532                         break;
6533                 case 'F':
6534                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6535                                 param->fp_verbose |= VERBOSE_DFID;
6536                                 param->fp_max_depth = 0;
6537                         }
6538                         break;
6539                 case 'g':
6540                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6541                                 param->fp_verbose |= VERBOSE_GENERATION;
6542                                 param->fp_max_depth = 0;
6543                         }
6544                         break;
6545                 case 'i':
6546                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6547                                 param->fp_verbose |= VERBOSE_STRIPE_OFFSET;
6548                                 param->fp_max_depth = 0;
6549                         }
6550                         break;
6551                 case 'I':
6552                         if (optarg) {
6553                                 param->fp_comp_id = strtoul(optarg, &end, 0);
6554                                 if (*end != '\0' || param->fp_comp_id == 0 ||
6555                                     param->fp_comp_id > LCME_ID_MAX) {
6556                                         fprintf(stderr,
6557                                                 "error: %s bad component id '%s'\n",
6558                                                 argv[0], optarg);
6559                                         return CMD_HELP;
6560                                 }
6561                                 param->fp_check_comp_id = 1;
6562                         } else {
6563                                 param->fp_max_depth = 0;
6564                                 param->fp_verbose |= VERBOSE_COMP_ID;
6565                         }
6566                         break;
6567                 case 'L':
6568                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6569                                 param->fp_verbose |= VERBOSE_PATTERN;
6570                                 param->fp_max_depth = 0;
6571                         }
6572                         break;
6573 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6574                 case 'M':
6575                         fprintf(stderr,
6576                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
6577 #endif
6578                 case 'm':
6579                         if (!(param->fp_verbose & VERBOSE_DETAIL))
6580                                 param->fp_max_depth = 0;
6581                         param->fp_verbose |= VERBOSE_MDTINDEX;
6582                         break;
6583                 case 'N':
6584                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6585                                 param->fp_verbose |= VERBOSE_MIRROR_COUNT;
6586                                 param->fp_max_depth = 0;
6587                         }
6588                         break;
6589                 case 'O':
6590                         if (param->fp_obd_uuid) {
6591                                 fprintf(stderr,
6592                                         "error: %s: only one obduuid allowed",
6593                                         argv[0]);
6594                                 return CMD_HELP;
6595                         }
6596                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
6597                         break;
6598                 case 'p':
6599                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6600                                 param->fp_verbose |= VERBOSE_POOL;
6601                                 param->fp_max_depth = 0;
6602                         }
6603                         break;
6604                 case 'q':
6605                         param->fp_quiet++;
6606                         break;
6607                 case 'r':
6608                         param->fp_recursive = 1;
6609                         break;
6610                 case 'R':
6611                         param->fp_raw = 1;
6612                         break;
6613                 case 'S':
6614                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6615                                 param->fp_verbose |= VERBOSE_STRIPE_SIZE;
6616                                 param->fp_max_depth = 0;
6617                         }
6618                         break;
6619                 case 'v':
6620                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
6621                         break;
6622                 case 'y':
6623                         param->fp_yaml = 1;
6624                         break;
6625                 case 'z':
6626                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6627                                 param->fp_verbose |= VERBOSE_EXT_SIZE;
6628                                 param->fp_max_depth = 0;
6629                         }
6630                         break;
6631                 default:
6632                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6633                                 progname, argv[optind - 1]);
6634                 case 'h':
6635                         return CMD_HELP;
6636                 }
6637         }
6638
6639         if (pathstart == -1) {
6640                 fprintf(stderr, "error: %s: no filename|pathname\n",
6641                                 argv[0]);
6642                 return CMD_HELP;
6643         } else if (pathend == -1) {
6644                 /* no options */
6645                 pathend = argc;
6646         }
6647
6648         if (pathend > argc)
6649                 return CMD_HELP;
6650
6651         if (param->fp_recursive)
6652                 param->fp_max_depth = -1;
6653         else if (param->fp_verbose & VERBOSE_DETAIL)
6654                 param->fp_max_depth = 1;
6655
6656         if (!param->fp_verbose)
6657                 param->fp_verbose = VERBOSE_DEFAULT;
6658         if (param->fp_quiet)
6659                 param->fp_verbose = VERBOSE_OBJID;
6660
6661         do {
6662                 int rc2;
6663
6664                 rc2 = llapi_getstripe(argv[pathstart], param);
6665                 if (rc2) {
6666                         fprintf(stderr, "%s: %s for '%s' failed: %s\n",
6667                                 progname, argv[0], argv[pathstart],
6668                                 strerror(-rc2));
6669                         if (!rc)
6670                                 rc = rc2;
6671                 }
6672         } while (++pathstart < pathend);
6673
6674         return rc;
6675 }
6676
6677 static int lfs_tgts(int argc, char **argv)
6678 {
6679         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
6680         struct find_param param;
6681         int index = 0, rc = 0;
6682
6683         if (argc > 2)
6684                 return CMD_HELP;
6685
6686         if (argc == 2 && !realpath(argv[1], path)) {
6687                 rc = -errno;
6688                 fprintf(stderr, "error: invalid path '%s': %s\n",
6689                         argv[1], strerror(-rc));
6690                 return rc;
6691         }
6692
6693         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
6694                 /* Check if we have a mount point */
6695                 if (mntdir[0] == '\0')
6696                         continue;
6697
6698                 memset(&param, 0, sizeof(param));
6699                 if (!strcmp(argv[0], "mdts"))
6700                         param.fp_get_lmv = 1;
6701
6702                 rc = llapi_ostlist(mntdir, &param);
6703                 if (rc) {
6704                         fprintf(stderr, "error: %s: failed on %s\n",
6705                                 argv[0], mntdir);
6706                 }
6707                 if (path[0] != '\0')
6708                         break;
6709                 memset(mntdir, 0, PATH_MAX);
6710         }
6711
6712         return rc;
6713 }
6714
6715 static int lfs_getstripe(int argc, char **argv)
6716 {
6717         struct find_param param = { 0 };
6718
6719         param.fp_max_depth = 1;
6720         return lfs_getstripe_internal(argc, argv, &param);
6721 }
6722
6723 /* functions */
6724 static int lfs_getdirstripe(int argc, char **argv)
6725 {
6726         struct find_param param = { 0 };
6727         struct option long_opts[] = {
6728         { .val = 'c',   .name = "mdt-count",     .has_arg = no_argument },
6729         { .val = 'D',   .name = "default",       .has_arg = no_argument },
6730         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6731         { .val = 'H',   .name = "mdt-hash",      .has_arg = no_argument },
6732         { .val = LFS_HEX_IDX_OPT,
6733                         .name = "hex-idx",       .has_arg = no_argument },
6734         { .val = 'i',   .name = "mdt-index",     .has_arg = no_argument },
6735         { .val = 'm',   .name = "mdt-index",     .has_arg = no_argument },
6736         { .val = 'O',   .name = "obd",           .has_arg = required_argument },
6737         { .val = 'r',   .name = "recursive",     .has_arg = no_argument },
6738         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
6739         { .val = 'T',   .name = "mdt-count",     .has_arg = no_argument },
6740         { .val = 'v',   .name = "verbose",       .has_arg = no_argument },
6741         { .val = 'X',   .name = "max-inherit",   .has_arg = no_argument },
6742         { .val = LFS_INHERIT_RR_OPT,
6743                         .name = "max-inherit-rr", .has_arg = no_argument },
6744         { .val = 'y',   .name = "yaml",          .has_arg = no_argument },
6745         { .name = NULL } };
6746         int c, rc = 0;
6747
6748         param.fp_get_lmv = 1;
6749
6750         while ((c = getopt_long(argc, argv,
6751                                 "cDhHimO:rRtTvXy", long_opts, NULL)) != -1) {
6752                 switch (c) {
6753                 case 'c':
6754                 case 'T':
6755                         param.fp_verbose |= VERBOSE_COUNT;
6756                         break;
6757                 case 'D':
6758                         param.fp_get_default_lmv = 1;
6759                         break;
6760 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6761                 case 't':
6762                         fprintf(stderr,
6763                                 "warning: '-t' deprecated, use '--mdt-hash' or '-H' instead\n");
6764                         fallthrough;
6765 #endif
6766                 case 'H':
6767                         param.fp_verbose |= VERBOSE_HASH_TYPE;
6768                         break;
6769                 case LFS_HEX_IDX_OPT:
6770                         param.fp_hex_idx = 1;
6771                         break;
6772                 case 'i':
6773                         fallthrough;
6774                 case 'm':
6775                         param.fp_verbose |= VERBOSE_STRIPE_OFFSET;
6776                         break;
6777                 case 'O':
6778                         if (param.fp_obd_uuid) {
6779                                 fprintf(stderr,
6780                                         "%s: only one obduuid allowed",
6781                                         progname);
6782                                 return CMD_HELP;
6783                         }
6784                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
6785                         break;
6786                 case 'r':
6787                         param.fp_recursive = 1;
6788                         break;
6789                 case 'R':
6790                         param.fp_raw = 1;
6791                         break;
6792                 case 'v':
6793                         param.fp_verbose |= VERBOSE_DEFAULT;
6794                         param.fp_verbose |= VERBOSE_DETAIL;
6795                         break;
6796                 case 'X':
6797                         param.fp_verbose |= VERBOSE_INHERIT;
6798                         break;
6799                 case LFS_INHERIT_RR_OPT:
6800                         param.fp_verbose |= VERBOSE_INHERIT_RR;
6801                         break;
6802                 case 'y':
6803                         param.fp_yaml = 1;
6804                         break;
6805                 default:
6806                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6807                                 progname, argv[optind - 1]);
6808                         fallthrough;
6809                 case 'h':
6810                         return CMD_HELP;
6811                 }
6812         }
6813
6814         if (optind >= argc)
6815                 return CMD_HELP;
6816
6817         if (param.fp_recursive)
6818                 param.fp_max_depth = -1;
6819
6820         if (!param.fp_verbose)
6821                 param.fp_verbose = VERBOSE_DEFAULT;
6822
6823         do {
6824                 int rc2;
6825
6826                 rc2 = llapi_getstripe(argv[optind], &param);
6827                 if (rc2) {
6828                         fprintf(stderr, "%s: %s for '%s' failed: %s\n",
6829                                 progname, argv[0], argv[optind],
6830                                 strerror(-rc2));
6831                         if (!rc)
6832                                 rc = rc2;
6833                 }
6834         } while (++optind < argc);
6835
6836         return rc;
6837 }
6838
6839 enum mntdf_flags {
6840         MNTDF_INODES    = 0x0001,
6841         MNTDF_COOKED    = 0x0002,
6842         MNTDF_LAZY      = 0x0004,
6843         MNTDF_VERBOSE   = 0x0008,
6844         MNTDF_SHOW      = 0x0010,
6845         MNTDF_DECIMAL   = 0x0020,
6846 };
6847
6848 #define COOK(value, base)                                       \
6849 ({                                                              \
6850         int radix = 0;                                          \
6851         while (value > base) {                                  \
6852                 value /= base;                                  \
6853                 radix++;                                        \
6854         }                                                       \
6855         radix;                                                  \
6856 })
6857 #define UUF     "%-20s"
6858 #define CSF     "%11s"
6859 #define CDF     "%11llu"
6860 #define HDF     "%8.1f%c"
6861 #define RSF     "%4s"
6862 #define RDF     "%3d%%"
6863
6864 static inline int obd_statfs_ratio(const struct obd_statfs *st, bool inodes)
6865 {
6866         double avail, used, ratio = 0;
6867
6868         if (inodes) {
6869                 avail = st->os_ffree;
6870                 used = st->os_files - st->os_ffree;
6871         } else {
6872                 avail = st->os_bavail;
6873                 used = st->os_blocks - st->os_bfree;
6874         }
6875         if (avail + used > 0)
6876                 ratio = used / (used + avail) * 100;
6877
6878         /* Round up to match df(1) usage percentage */
6879         return (ratio - (int)ratio) > 0 ? (int)(ratio + 1) : (int)ratio;
6880 }
6881
6882 /*
6883  * This is to identify various problem states for "lfs df" if .osn_err = true,
6884  * so only show flags reflecting those states by default. Informational states
6885  * are only shown with "-v" and use lower-case names to distinguish them.
6886  * UNUSED[12] were for "EROFS = 30" until 1.6 but are now available for use.
6887  */
6888 static struct obd_statfs_state_names {
6889         enum obd_statfs_state   osn_state;
6890         const char              osn_name;
6891         bool                    osn_err;
6892 } oss_names[] = {
6893         { .osn_state = OS_STATFS_DEGRADED,   .osn_name = 'D', .osn_err = true },
6894         { .osn_state = OS_STATFS_READONLY,   .osn_name = 'R', .osn_err = true },
6895         { .osn_state = OS_STATFS_NOCREATE,   .osn_name = 'N', .osn_err = true },
6896         { .osn_state = OS_STATFS_UNUSED1,    .osn_name = '?', .osn_err = true },
6897         { .osn_state = OS_STATFS_UNUSED2,    .osn_name = '?', .osn_err = true },
6898         { .osn_state = OS_STATFS_ENOSPC,     .osn_name = 'S', .osn_err = true },
6899         { .osn_state = OS_STATFS_ENOINO,     .osn_name = 'I', .osn_err = true },
6900         { .osn_state = OS_STATFS_SUM,        .osn_name = 'a', /* aggregate */ },
6901         { .osn_state = OS_STATFS_NONROT,     .osn_name = 'f', /* flash */     },
6902 };
6903
6904 static int showdf(char *mntdir, struct obd_statfs *stat,
6905                   char *uuid, enum mntdf_flags flags,
6906                   char *type, int index, int rc)
6907 {
6908         long long avail, used, total;
6909         int ratio = 0;
6910         char *suffix = flags & MNTDF_DECIMAL ? "kMGTPEZY" : "KMGTPEZY";
6911         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
6912         char tbuf[3 * sizeof(__u64)];
6913         char ubuf[3 * sizeof(__u64)];
6914         char abuf[3 * sizeof(__u64)];
6915         char rbuf[3 * sizeof(__u64)];
6916
6917         if (!uuid || !stat)
6918                 return -EINVAL;
6919
6920         switch (rc) {
6921         case 0:
6922                 if (flags & MNTDF_INODES) {
6923                         avail = stat->os_ffree;
6924                         used = stat->os_files - stat->os_ffree;
6925                         total = stat->os_files;
6926                 } else {
6927                         int shift = flags & MNTDF_COOKED ? 0 : 10;
6928
6929                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
6930                         used  = ((stat->os_blocks - stat->os_bfree) *
6931                                  stat->os_bsize) >> shift;
6932                         total = (stat->os_blocks * stat->os_bsize) >> shift;
6933                 }
6934
6935                 ratio = obd_statfs_ratio(stat, flags & MNTDF_INODES);
6936
6937                 if (flags & MNTDF_COOKED) {
6938                         int base = flags & MNTDF_DECIMAL ? 1000 : 1024;
6939                         double cook_val;
6940                         int i;
6941
6942                         cook_val = (double)total;
6943                         i = COOK(cook_val, base);
6944                         if (i > 0)
6945                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
6946                                          suffix[i - 1]);
6947                         else
6948                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
6949
6950                         cook_val = (double)used;
6951                         i = COOK(cook_val, base);
6952                         if (i > 0)
6953                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
6954                                          suffix[i - 1]);
6955                         else
6956                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
6957
6958                         cook_val = (double)avail;
6959                         i = COOK(cook_val, base);
6960                         if (i > 0)
6961                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
6962                                          suffix[i - 1]);
6963                         else
6964                                 snprintf(abuf, sizeof(abuf), CDF, avail);
6965                 } else {
6966                         snprintf(tbuf, sizeof(tbuf), CDF, total);
6967                         snprintf(ubuf, sizeof(tbuf), CDF, used);
6968                         snprintf(abuf, sizeof(tbuf), CDF, avail);
6969                 }
6970
6971                 sprintf(rbuf, RDF, ratio);
6972                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
6973                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
6974                 if (type)
6975                         printf("[%s:%d]", type, index);
6976
6977                 if (stat->os_state) {
6978                         uint32_t i;
6979
6980                         printf(" ");
6981                         for (i = 0; i < ARRAY_SIZE(oss_names); i++) {
6982                                 if (oss_names[i].osn_state & stat->os_state &&
6983                                     (oss_names[i].osn_err ||
6984                                      flags & MNTDF_VERBOSE))
6985                                         printf("%c", oss_names[i].osn_name);
6986                         }
6987                 }
6988
6989                 printf("\n");
6990                 break;
6991         case -ENODATA:
6992                 printf(UUF": inactive device\n", uuid);
6993                 break;
6994         default:
6995                 printf(UUF": %s\n", uuid, strerror(-rc));
6996                 break;
6997         }
6998
6999         return 0;
7000 }
7001
7002 struct ll_stat_type {
7003         int   st_op;
7004         char *st_name;
7005 };
7006
7007 #define LL_STATFS_MAX   LOV_MAX_STRIPE_COUNT
7008
7009 struct ll_statfs_data {
7010         int                     sd_index;
7011         struct obd_statfs       sd_st;
7012 };
7013
7014 struct ll_statfs_buf {
7015         int                     sb_count;
7016         struct ll_statfs_data   sb_buf[LL_STATFS_MAX];
7017 };
7018
7019 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags,
7020                  int ops, struct ll_statfs_buf *lsb)
7021 {
7022         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
7023         struct obd_uuid uuid_buf;
7024         char *poolname = NULL;
7025         struct ll_stat_type types[] = {
7026                 { .st_op = LL_STATFS_LMV,       .st_name = "MDT" },
7027                 { .st_op = LL_STATFS_LOV,       .st_name = "OST" },
7028                 { .st_name = NULL } };
7029         struct ll_stat_type *tp;
7030         __u64 ost_files = 0;
7031         __u64 ost_ffree = 0;
7032         __u32 index;
7033         __u32 type;
7034         int fd;
7035         int rc = 0;
7036         int rc2;
7037
7038         if (pool) {
7039                 poolname = strchr(pool, '.');
7040                 if (poolname) {
7041                         if (strncmp(fsname, pool, strlen(fsname))) {
7042                                 fprintf(stderr, "filesystem name incorrect\n");
7043                                 return -ENODEV;
7044                         }
7045                         poolname++;
7046                 } else
7047                         poolname = pool;
7048         }
7049
7050         fd = open(mntdir, O_RDONLY);
7051         if (fd < 0) {
7052                 rc = -errno;
7053                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
7054                         strerror(errno));
7055                 return rc;
7056         }
7057
7058         if (flags & MNTDF_SHOW) {
7059                 if (flags & MNTDF_INODES)
7060                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
7061                                "UUID", "Inodes", "IUsed", "IFree",
7062                                "IUse%", "Mounted on");
7063                 else
7064                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
7065                                "UUID",
7066                                flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
7067                                "Used", "Available", "Use%", "Mounted on");
7068         }
7069
7070         for (tp = types; tp->st_name != NULL; tp++) {
7071                 bool have_ost = false;
7072
7073                 if (!(tp->st_op & ops))
7074                         continue;
7075
7076                 for (index = 0; index < LOV_ALL_STRIPES &&
7077                      (!lsb || lsb->sb_count < LL_STATFS_MAX); index++) {
7078                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
7079                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
7080                         type = flags & MNTDF_LAZY ?
7081                                 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
7082                         rc2 = llapi_obd_fstatfs(fd, type, index,
7083                                                 &stat_buf, &uuid_buf);
7084                         if (rc2 == -ENODEV)
7085                                 break;
7086                         if (rc2 == -EAGAIN)
7087                                 continue;
7088                         if (rc2 == -ENODATA) { /* Inactive device, OK. */
7089                                 if (!(flags & MNTDF_VERBOSE))
7090                                         continue;
7091                         } else if (rc2 < 0 && rc == 0) {
7092                                 rc = rc2;
7093                         }
7094
7095                         /*
7096                          * If we have OSTs then don't report MDT block counts.
7097                          * For MDT-only filesystems the expectation is that all
7098                          * layouts have a DoM component.  For filesystems with
7099                          * OSTs, files are not necessarily going to store data
7100                          * on MDTs, and MDT space is limited to a fraction of
7101                          * OST space, so don't include it in the summary.
7102                          */
7103                         if (tp->st_op == LL_STATFS_LOV && !have_ost) {
7104                                 have_ost = true;
7105                                 sum.os_blocks = 0;
7106                                 sum.os_bfree = 0;
7107                                 sum.os_bavail = 0;
7108                         }
7109
7110                         if (poolname && tp->st_op == LL_STATFS_LOV &&
7111                             llapi_search_ost(fsname, poolname,
7112                                              obd_uuid2str(&uuid_buf)) != 1)
7113                                 continue;
7114
7115                         /*
7116                          * the llapi_obd_fstatfs() call may have returned with
7117                          * an error, but if it filled in uuid_buf we will at
7118                          * lease use that to print out a message for that OBD.
7119                          * If we didn't get anything in the uuid_buf, then fill
7120                          * it in so that we can print an error message.
7121                          */
7122                         if (uuid_buf.uuid[0] == '\0')
7123                                 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
7124                                          "%s%04x", tp->st_name, index);
7125                         if (!rc && lsb) {
7126                                 lsb->sb_buf[lsb->sb_count].sd_index = index;
7127                                 lsb->sb_buf[lsb->sb_count].sd_st = stat_buf;
7128                                 lsb->sb_count++;
7129                         }
7130                         if (flags & MNTDF_SHOW)
7131                                 showdf(mntdir, &stat_buf,
7132                                        obd_uuid2str(&uuid_buf), flags,
7133                                        tp->st_name, index, rc2);
7134
7135                         if (rc2)
7136                                 continue;
7137
7138                         if (tp->st_op == LL_STATFS_LMV) {
7139                                 sum.os_ffree += stat_buf.os_ffree;
7140                                 sum.os_files += stat_buf.os_files;
7141                         } else /* if (tp->st_op == LL_STATFS_LOV) */ {
7142                                 ost_files += stat_buf.os_files;
7143                                 ost_ffree += stat_buf.os_ffree;
7144                         }
7145                         sum.os_blocks += stat_buf.os_blocks *
7146                                          stat_buf.os_bsize;
7147                         sum.os_bfree  += stat_buf.os_bfree *
7148                                          stat_buf.os_bsize;
7149                         sum.os_bavail += stat_buf.os_bavail *
7150                                          stat_buf.os_bsize;
7151                 }
7152         }
7153
7154         close(fd);
7155
7156         /*
7157          * If we have _some_ OSTs, but don't have as many free objects on the
7158          * OST as inodes on the MDTs, reduce the reported number of inodes
7159          * to compensate, so that the "inodes in use" number is correct.
7160          * This should be kept in sync with ll_statfs_internal().
7161          */
7162         if (ost_files && ost_ffree < sum.os_ffree) {
7163                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
7164                 sum.os_ffree = ost_ffree;
7165         }
7166         if (flags & MNTDF_SHOW) {
7167                 printf("\n");
7168                 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
7169                 printf("\n");
7170         }
7171
7172         return rc;
7173 }
7174
7175 enum {
7176         LAYOUT_INHERIT_UNSET    = -2,
7177 };
7178
7179 /* functions */
7180 static int lfs_setdirstripe(int argc, char **argv)
7181 {
7182         char *dname;
7183         struct lfs_setstripe_args lsa = { 0 };
7184         struct llapi_stripe_param *param = NULL;
7185         __u32 mdts[LMV_MAX_STRIPE_COUNT] = { 0 };
7186         char *end;
7187         int c;
7188         char *mode_opt = NULL;
7189         bool default_stripe = false;
7190         bool delete = false;
7191         bool foreign_mode = false;
7192         bool mdt_count_set = false;
7193         bool overstriped = false;
7194         mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
7195         mode_t previous_mode = 0;
7196         char *xattr = NULL;
7197         __u32 type = LU_FOREIGN_TYPE_SYMLINK, flags = 0;
7198         int max_inherit = LAYOUT_INHERIT_UNSET;
7199         int max_inherit_rr = LAYOUT_INHERIT_UNSET;
7200         struct option long_opts[] = {
7201         { .val = 'c',   .name = "count",        .has_arg = required_argument },
7202         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
7203         { .val = 'C',   .name = "mdt-overcount", .has_arg = required_argument },
7204         { .val = 'd',   .name = "delete",       .has_arg = no_argument },
7205         { .val = 'D',   .name = "default",      .has_arg = no_argument },
7206         { .val = 'D',   .name = "default_stripe", .has_arg = no_argument },
7207         { .val = LFS_LAYOUT_FLAGS_OPT,
7208                         .name = "flags",        .has_arg = required_argument },
7209         { .val = LFS_LAYOUT_FOREIGN_OPT,
7210                         .name = "foreign",      .has_arg = optional_argument},
7211         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7212         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
7213 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 17, 53, 0)
7214         { .val = 'i',   .name = "mdt-index",    .has_arg = required_argument },
7215         { .val = 'i',   .name = "mdt",          .has_arg = required_argument },
7216 #else
7217 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
7218         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
7219         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
7220 #endif
7221 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7222         { .val = 'i',   .name = "index",        .has_arg = required_argument },
7223 #endif
7224         { .val = 'o',   .name = "mode",         .has_arg = required_argument },
7225 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7226         { .val = 't',   .name = "hash-type",    .has_arg = required_argument },
7227 #endif
7228         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
7229         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
7230         { .val = 'X',   .name = "max-inherit",  .has_arg = required_argument },
7231         { .val = LFS_INHERIT_RR_OPT,
7232                         .name = "max-inherit-rr", .has_arg = required_argument},
7233 /* setstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
7234 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }, */
7235         { .name = NULL } };
7236         int result = 0;
7237
7238         setstripe_args_init(&lsa);
7239
7240         while ((c = getopt_long(argc, argv, "c:C:dDi:hH:m:o:t:T:x:X:",
7241                                 long_opts, NULL)) >= 0) {
7242                 switch (c) {
7243                 case 0:
7244                         /* Long options. */
7245                         break;
7246                 case 'C':
7247                         overstriped = true;
7248                         fallthrough;
7249                 case 'c':
7250                         fallthrough;
7251                 case 'T':
7252                         errno = 0;
7253                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
7254                         if (errno != 0 || *end != '\0' ||
7255                             lsa.lsa_stripe_count < -1 ||
7256                             lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
7257                                 fprintf(stderr,
7258                                         "%s: invalid stripe count '%s'\n",
7259                                         progname, optarg);
7260                                 return CMD_HELP;
7261                         }
7262                         mdt_count_set = true;
7263                         break;
7264                 case 'd':
7265                         delete = true;
7266                         default_stripe = true;
7267                         break;
7268                 case 'D':
7269                         default_stripe = true;
7270                         break;
7271                 case LFS_LAYOUT_FOREIGN_OPT:
7272                         if (optarg) {
7273                                 /* check pure numeric */
7274                                 type = strtoul(optarg, &end, 0);
7275                                 if (*end) {
7276                                         /* check name */
7277                                         type = check_foreign_type_name(optarg);
7278                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
7279                                                 fprintf(stderr,
7280                                                         "%s %s: unknown foreign type '%s'\n",
7281                                                         progname, argv[0],
7282                                                         optarg);
7283                                                 return CMD_HELP;
7284                                         }
7285                                 } else if (type >= UINT32_MAX) {
7286                                         fprintf(stderr,
7287                                                 "%s %s: invalid foreign type '%s'\n",
7288                                                 progname, argv[0], optarg);
7289                                         return CMD_HELP;
7290                                 }
7291                         }
7292                         foreign_mode = true;
7293                         break;
7294                 case LFS_LAYOUT_FLAGS_OPT:
7295                         errno = 0;
7296                         flags = strtoul(optarg, &end, 16);
7297                         if (errno != 0 || *end != '\0' ||
7298                             flags >= UINT32_MAX) {
7299                                 fprintf(stderr,
7300                                         "%s %s: invalid hex flags '%s'\n",
7301                                         progname, argv[0], optarg);
7302                                 return CMD_HELP;
7303                         }
7304                         if (!foreign_mode) {
7305                                 fprintf(stderr,
7306                                         "%s %s: hex flags must be specified with --foreign option\n",
7307                                         progname, argv[0]);
7308                                 return CMD_HELP;
7309                         }
7310                         break;
7311 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7312                 case 't':
7313                         fprintf(stderr,
7314                                 "warning: '--hash-type' and '-t' deprecated, use '--mdt-hash' or '-H' instead\n");
7315                         fallthrough;
7316 #endif
7317                 case 'H':
7318                         lsa.lsa_pattern = check_hashtype(optarg);
7319                         if (lsa.lsa_pattern == 0) {
7320                                 fprintf(stderr,
7321                                         "%s %s: bad directory hash type '%s'\n",
7322                                         progname, argv[0], optarg);
7323                                 return CMD_HELP;
7324                         }
7325                         break;
7326                 case 'i':
7327 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 17, 53, 0)
7328                 case 'm':
7329 #endif
7330 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7331                         if (strcmp(argv[optind - 1], "--index") == 0)
7332                                 fprintf(stderr,
7333                                         "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
7334                                         progname, argv[0]);
7335 #endif
7336                         lsa.lsa_nr_tgts = parse_targets(mdts,
7337                                                 sizeof(mdts) / sizeof(__u32),
7338                                                 lsa.lsa_nr_tgts, optarg,
7339                                                 &overstriped);
7340                         if (lsa.lsa_nr_tgts < 0) {
7341                                 fprintf(stderr,
7342                                         "%s %s: invalid MDT target(s) '%s'\n",
7343                                         progname, argv[0], optarg);
7344                                 return CMD_HELP;
7345                         }
7346
7347                         lsa.lsa_tgts = mdts;
7348                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
7349                                 lsa.lsa_stripe_off = mdts[0];
7350                         break;
7351                 case 'o':
7352                         mode_opt = optarg;
7353                         break;
7354                 case 'x':
7355                         xattr = optarg;
7356                         break;
7357                 case 'X':
7358                         errno = 0;
7359                         max_inherit = strtol(optarg, &end, 10);
7360                         if (errno != 0 || *end != '\0' || max_inherit < -2) {
7361                                 fprintf(stderr,
7362                                         "%s %s: invalid max-inherit '%s'\n",
7363                                         progname, argv[0], optarg);
7364                                 return CMD_HELP;
7365                         }
7366                         if (max_inherit == 0) {
7367                                 max_inherit = LMV_INHERIT_NONE;
7368                         } else if (max_inherit == -1) {
7369                                 max_inherit = LMV_INHERIT_UNLIMITED;
7370                         } else if (max_inherit > LMV_INHERIT_MAX) {
7371                                 fprintf(stderr,
7372                                         "%s %s: max-inherit %d exceeds maximum %u\n",
7373                                         progname, argv[0], max_inherit,
7374                                         LMV_INHERIT_MAX);
7375                                 return CMD_HELP;
7376                         }
7377                         break;
7378                 case LFS_INHERIT_RR_OPT:
7379                         if (!default_stripe) {
7380                                 fprintf(stderr,
7381                                         "%s %s: '--max-inherit-rr' must be specified with '-D'\n",
7382                                         progname, argv[0]);
7383                                 return CMD_HELP;
7384                         }
7385                         errno = 0;
7386                         max_inherit_rr = strtol(optarg, &end, 10);
7387                         if (errno != 0 || *end != '\0' || max_inherit_rr < -2) {
7388                                 fprintf(stderr,
7389                                         "%s %s: invalid max-inherit-rr '%s'\n",
7390                                         progname, argv[0], optarg);
7391                                 return CMD_HELP;
7392                         }
7393                         if (max_inherit_rr == 0) {
7394                                 max_inherit_rr = LMV_INHERIT_RR_NONE;
7395                         } else if (max_inherit_rr == -1) {
7396                                 max_inherit_rr = LMV_INHERIT_RR_UNLIMITED;
7397                         } else if (max_inherit_rr > LMV_INHERIT_RR_MAX) {
7398                                 fprintf(stderr,
7399                                         "%s %s: max-inherit-rr %d exceeds maximum %u\n",
7400                                         progname, argv[0], max_inherit_rr,
7401                                         LMV_INHERIT_RR_MAX);
7402                                 return CMD_HELP;
7403                         }
7404                         break;
7405                 default:
7406                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7407                                 progname, argv[optind - 1]);
7408                         fallthrough;
7409                 case 'h':
7410                         return CMD_HELP;
7411                 }
7412         }
7413
7414         if (optind == argc) {
7415                 fprintf(stderr, "%s %s: DIR must be specified\n",
7416                         progname, argv[0]);
7417                 return CMD_HELP;
7418         }
7419
7420         if (xattr && !foreign_mode) {
7421                 /*
7422                  * only print a warning as this is armless and will be
7423                  * ignored
7424                  */
7425                 fprintf(stderr,
7426                         "%s %s: xattr has been specified for non-foreign layout\n",
7427                         progname, argv[0]);
7428         } else if (foreign_mode && !xattr) {
7429                 fprintf(stderr,
7430                         "%s %s: xattr must be provided in foreign mode\n",
7431                         progname, argv[0]);
7432                 return CMD_HELP;
7433         }
7434
7435         if (foreign_mode && (delete || default_stripe || lsa.lsa_nr_tgts ||
7436             lsa.lsa_tgts || setstripe_args_specified(&lsa))) {
7437                 fprintf(stderr,
7438                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
7439                         progname, argv[0]);
7440                 return CMD_HELP;
7441         }
7442
7443         if (!delete && lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT &&
7444             lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT && !foreign_mode) {
7445                 /* if no parameters set, create directory on least-used MDTs */
7446                 lsa.lsa_stripe_off = LMV_OFFSET_DEFAULT;
7447                 lsa.lsa_stripe_count = 1;
7448         }
7449
7450         if (delete &&
7451             (lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
7452              lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)) {
7453                 fprintf(stderr,
7454                         "%s %s: cannot specify -d with -c or -i options\n",
7455                         progname, argv[0]);
7456                 return CMD_HELP;
7457         }
7458
7459         if (mode_opt) {
7460                 mode = strtoul(mode_opt, &end, 8);
7461                 if (*end != '\0') {
7462                         fprintf(stderr,
7463                                 "%s %s: bad MODE '%s'\n",
7464                                 progname, argv[0], mode_opt);
7465                         return CMD_HELP;
7466                 }
7467                 previous_mode = umask(0);
7468         }
7469
7470         /* check max-inherit and warn user in some cases */
7471         if (default_stripe &&
7472             (lsa.lsa_stripe_count < 0 || lsa.lsa_stripe_count > 1)) {
7473                 if (max_inherit == LMV_INHERIT_UNLIMITED)
7474                         fprintf(stderr,
7475                         "%s %s: unrecommended max-inherit=-1 when default stripe-count=%lld\n",
7476                         progname, argv[0], lsa.lsa_stripe_count);
7477                 else if (max_inherit > LMV_INHERIT_DEFAULT_STRIPED + 2 &&
7478                          max_inherit != LMV_INHERIT_NONE)
7479                         fprintf(stderr,
7480                                 "%s %s: unrecommended max-inherit=%d when default stripe-count=%lld\n",
7481                                 progname, argv[0], max_inherit,
7482                                 lsa.lsa_stripe_count);
7483         }
7484
7485         if (default_stripe && lsa.lsa_nr_tgts > 1 && !mdt_count_set) {
7486                 fprintf(stderr,
7487                         "%s %s: trying to create unrecommended default striped directory layout,\n"
7488                         "       '-D -i x,y,z' will stripe every new directory across all MDTs,\n"
7489                         "       add -c with the number of MDTs to do this anyway\n",
7490                         progname, argv[0]);
7491                 return CMD_HELP;
7492         }
7493
7494         if (max_inherit_rr != LAYOUT_INHERIT_UNSET &&
7495             lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT &&
7496             lsa.lsa_stripe_off != LMV_OFFSET_DEFAULT) {
7497                 fprintf(stderr,
7498                         "%s %s: max-inherit-rr needs mdt-index=-1, not %lld\n",
7499                         progname, argv[0], lsa.lsa_stripe_off);
7500                 return CMD_HELP;
7501         }
7502
7503         /* foreign LMV/dir case */
7504         if (foreign_mode) {
7505                 if (argc > optind + 1) {
7506                         fprintf(stderr,
7507                                 "%s %s: cannot specify multiple foreign dirs\n",
7508                                 progname, argv[0]);
7509                         return CMD_HELP;
7510                 }
7511
7512                 dname = argv[optind];
7513                 result = llapi_dir_create_foreign(dname, mode, type, flags,
7514                                                   xattr);
7515                 if (result != 0)
7516                         fprintf(stderr,
7517                                 "%s mkdir: can't create foreign dir '%s': %s\n",
7518                                 progname, dname, strerror(-result));
7519                 return result;
7520         }
7521
7522         /*
7523          * initialize stripe parameters, in case param is converted to specific,
7524          * i.e, 'lfs mkdir -i -1 -c N', always allocate space for lsp_tgts.
7525          */
7526         param = calloc(1, offsetof(typeof(*param),
7527                        lsp_tgts[lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ?
7528                                 lsa.lsa_stripe_count : lsa.lsa_nr_tgts]));
7529         if (!param) {
7530                 fprintf(stderr,
7531                         "%s %s: cannot allocate memory for parameters: %s\n",
7532                         progname, argv[0], strerror(ENOMEM));
7533                 return CMD_HELP;
7534         }
7535
7536         /* if "lfs setdirstripe -D -i -1" is used, assume 1-stripe directory */
7537         if (default_stripe && lsa.lsa_stripe_off == LMV_OFFSET_DEFAULT &&
7538             (lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT ||
7539              lsa.lsa_stripe_count == 0))
7540                 lsa.lsa_stripe_count = 1;
7541         if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
7542                 param->lsp_stripe_count = lsa.lsa_stripe_count;
7543         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
7544                 param->lsp_stripe_offset = LMV_OFFSET_DEFAULT;
7545         else
7546                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
7547
7548         if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
7549                 param->lsp_stripe_pattern = lsa.lsa_pattern;
7550         else
7551                 param->lsp_stripe_pattern = LMV_HASH_TYPE_UNKNOWN;
7552
7553         if (overstriped) {
7554                 param->lsp_stripe_pattern |= LMV_HASH_FLAG_OVERSTRIPED;
7555                 max_inherit = LMV_INHERIT_DEFAULT_OVERSTRIPED;
7556         }
7557
7558         param->lsp_pool = lsa.lsa_pool_name;
7559         param->lsp_is_specific = false;
7560
7561         if (max_inherit == LAYOUT_INHERIT_UNSET) {
7562                 if (lsa.lsa_stripe_count == 0 || lsa.lsa_stripe_count == 1 ||
7563                     lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT)
7564                         max_inherit = LMV_INHERIT_DEFAULT_PLAIN;
7565                 else
7566                         max_inherit = LMV_INHERIT_DEFAULT_STRIPED;
7567         }
7568         param->lsp_max_inherit = max_inherit;
7569         if (default_stripe) {
7570
7571                 if (max_inherit_rr == LAYOUT_INHERIT_UNSET)
7572                         max_inherit_rr = LMV_INHERIT_RR_DEFAULT;
7573                 param->lsp_max_inherit_rr = max_inherit_rr;
7574         }
7575         if (strcmp(argv[0], "mkdir") == 0)
7576                 param->lsp_is_create = true;
7577         if (lsa.lsa_nr_tgts > 1) {
7578                 if (lsa.lsa_stripe_count > 0 &&
7579                     lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
7580                     lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
7581                         fprintf(stderr,
7582                                 "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
7583                                 argv[0], lsa.lsa_stripe_count,
7584                                 lsa.lsa_nr_tgts);
7585                         free(param);
7586                         return CMD_HELP;
7587                 }
7588
7589                 param->lsp_is_specific = true;
7590                 param->lsp_stripe_count = lsa.lsa_nr_tgts;
7591                 memcpy(param->lsp_tgts, mdts, sizeof(*mdts) * lsa.lsa_nr_tgts);
7592         }
7593
7594         dname = argv[optind];
7595         do {
7596                 if (default_stripe) {
7597                         result = llapi_dir_set_default_lmv(dname, param);
7598                         if (result)
7599                                 fprintf(stderr,
7600                                         "%s setdirstripe: cannot set default stripe on dir '%s': %s\n",
7601                                         progname, dname, strerror(-result));
7602                         continue;
7603                 }
7604
7605                 result = llapi_dir_create(dname, mode, param);
7606                 if (result)
7607                         fprintf(stderr,
7608                                 "%s setdirstripe: cannot create dir '%s': %s\n",
7609                                 progname, dname, strerror(-result));
7610         } while ((dname = argv[++optind]));
7611
7612         if (mode_opt)
7613                 umask(previous_mode);
7614
7615         free(param);
7616         return result;
7617 }
7618
7619 static int lfs_rmentry(int argc, char **argv)
7620 {
7621         char *dname;
7622         int index;
7623         int result = 0;
7624
7625         if (argc <= 1) {
7626                 fprintf(stderr, "error: %s: missing dirname\n",
7627                         argv[0]);
7628                 return CMD_HELP;
7629         }
7630
7631         index = 1;
7632         dname = argv[index];
7633         while (dname) {
7634                 int rc2;
7635
7636                 rc2 = llapi_direntry_remove(dname);
7637                 if (rc2) {
7638                         fprintf(stderr,
7639                                 "%s %s: remove dir entry '%s' failed: %s\n",
7640                                 progname, argv[0], dname, strerror(-rc2));
7641                         if (!result)
7642                                 result = rc2;
7643                 }
7644                 dname = argv[++index];
7645         }
7646         return result;
7647 }
7648
7649 static int lfs_unlink_foreign(int argc, char **argv)
7650 {
7651         char *name;
7652         int   index;
7653         int   result = 0;
7654
7655         if (argc <= 1) {
7656                 fprintf(stderr, "error: %s: missing pathname\n",
7657                         argv[0]);
7658                 return CMD_HELP;
7659         }
7660
7661         index = 1;
7662         name = argv[index];
7663         while (name != NULL) {
7664                 result = llapi_unlink_foreign(name);
7665                 if (result) {
7666                         fprintf(stderr,
7667                                 "error: %s: unlink foreign entry '%s' failed\n",
7668                                 argv[0], name);
7669                         break;
7670                 }
7671                 name = argv[++index];
7672         }
7673         return result;
7674 }
7675
7676 static int lfs_mv(int argc, char **argv)
7677 {
7678         struct lmv_user_md lmu = { LMV_USER_MAGIC };
7679         struct find_param param = {
7680                 .fp_max_depth = -1,
7681                 .fp_mdt_index = -1,
7682         };
7683         char *end;
7684         int c;
7685         int rc = 0;
7686         struct option long_opts[] = {
7687         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
7688         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
7689         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7690         { .name = NULL } };
7691
7692         while ((c = getopt_long(argc, argv, "m:M:v", long_opts, NULL)) != -1) {
7693                 switch (c) {
7694 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7695                 case 'M':
7696                         fprintf(stderr,
7697                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
7698 #endif
7699                 case 'm':
7700                         errno = 0;
7701                         lmu.lum_stripe_offset = strtoul(optarg, &end, 0);
7702                         if (errno != 0 || *end != '\0' ||
7703                             lmu.lum_stripe_offset >= UINT32_MAX) {
7704                                 fprintf(stderr, "%s mv: bad MDT index '%s'\n",
7705                                         progname, optarg);
7706                                 return CMD_HELP;
7707                         }
7708                         break;
7709                 case 'v':
7710                         param.fp_verbose = VERBOSE_DETAIL;
7711                         break;
7712                 default:
7713                         fprintf(stderr, "%s mv: unrecognized option '%s'\n",
7714                                 progname, argv[optind - 1]);
7715                         return CMD_HELP;
7716                 }
7717         }
7718
7719         if (lmu.lum_stripe_offset == LMV_OFFSET_DEFAULT) {
7720                 fprintf(stderr, "%s mv: MDT index must be specified\n",
7721                         progname);
7722                 return CMD_HELP;
7723         }
7724
7725         if (optind >= argc) {
7726                 fprintf(stderr, "%s mv: DIR must be specified\n", progname);
7727                 return CMD_HELP;
7728         }
7729
7730         lmu.lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
7731
7732         /* initialize migrate mdt parameters */
7733         param.fp_lmv_md = &lmu;
7734         param.fp_migrate = 1;
7735         rc = llapi_migrate_mdt(argv[optind], &param);
7736         if (rc != 0)
7737                 fprintf(stderr, "%s mv: cannot migrate '%s' to MDT%04x: %s\n",
7738                         progname, argv[optind], lmu.lum_stripe_offset,
7739                         strerror(-rc));
7740         return rc;
7741 }
7742
7743 static int lfs_osts(int argc, char **argv)
7744 {
7745         return lfs_tgts(argc, argv);
7746 }
7747
7748 static int lfs_mdts(int argc, char **argv)
7749 {
7750         return lfs_tgts(argc, argv);
7751 }
7752
7753 static int lfs_df(int argc, char **argv)
7754 {
7755         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
7756         enum mntdf_flags flags = MNTDF_SHOW;
7757         int ops = LL_STATFS_LMV | LL_STATFS_LOV;
7758         int c, rc = 0, rc1 = 0, index = 0, arg_idx = 0;
7759         char fsname[PATH_MAX] = "", *pool_name = NULL;
7760         struct option long_opts[] = {
7761         { .val = 'h',   .name = "human-readable", .has_arg = no_argument },
7762         { .val = 'H',   .name = "si",           .has_arg = no_argument },
7763         { .val = 'i',   .name = "inodes",       .has_arg = no_argument },
7764         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
7765         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
7766         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7767         { .name = NULL} };
7768
7769         while ((c = getopt_long(argc, argv, "hHilp:v", long_opts, NULL)) != -1) {
7770                 switch (c) {
7771                 case 'h':
7772                         flags = (flags & ~MNTDF_DECIMAL) | MNTDF_COOKED;
7773                         break;
7774                 case 'H':
7775                         flags |= MNTDF_COOKED | MNTDF_DECIMAL;
7776                         break;
7777                 case 'i':
7778                         flags |= MNTDF_INODES;
7779                         break;
7780                 case 'l':
7781                         flags |= MNTDF_LAZY;
7782                         break;
7783                 case 'p':
7784                         pool_name = optarg;
7785                         break;
7786                 case 'v':
7787                         flags |= MNTDF_VERBOSE;
7788                         break;
7789                 default:
7790                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7791                                 progname, argv[optind - 1]);
7792                         return CMD_HELP;
7793                 }
7794         }
7795
7796         /* Handle case where path is not specified */
7797         if (optind == argc) {
7798                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7799                         /* Check if we have a mount point */
7800                         if (mntdir[0] == '\0')
7801                                 continue;
7802
7803                         rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
7804                         if (rc || path[0] != '\0')
7805                                 break;
7806
7807                         fsname[0] = '\0'; /* avoid matching in next loop */
7808                         mntdir[0] = '\0'; /* avoid matching in next loop */
7809                         path[0] = '\0'; /* clean for next loop */
7810                 }
7811                 return rc;
7812         }
7813
7814         /* Loop through all the remaining arguments. These are Lustre FS
7815          * paths.
7816          */
7817         for (arg_idx = optind; arg_idx <= argc - 1; arg_idx++) {
7818                 bool valid = false;
7819
7820                 fsname[0] = '\0'; /* start clean */
7821                 mntdir[0] = '\0'; /* start clean */
7822                 path[0] = '\0';   /* start clean */
7823
7824                 /* path does not exists at all */
7825                 if (!realpath(argv[arg_idx], path)) {
7826                         rc = -errno;
7827                         fprintf(stderr, "error: invalid path '%s': %s\n",
7828                                 argv[arg_idx], strerror(-rc));
7829                         /* save first seen error */
7830                         if (!rc1)
7831                                 rc1 = rc;
7832
7833                         continue;
7834                 }
7835
7836                 /* path exists but may not be a Lustre filesystem */
7837                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7838                         /* Check if we have a mount point */
7839                         if (mntdir[0] == '\0')
7840                                 continue;
7841
7842                         rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
7843                         if (rc || path[0] != '\0') {
7844                                 valid = true;
7845
7846                                 /* save first seen error */
7847                                 if (!rc1)
7848                                         rc1 = rc;
7849                                 break;
7850                         }
7851                 }
7852
7853                 if (!valid) {
7854                         llapi_printf(LLAPI_MSG_ERROR,
7855                                      "%s:%s Not a Lustre filesystem\n",
7856                                      argv[0], argv[arg_idx]);
7857                         /* save first seen error */
7858                         if (!rc1)
7859                                 rc1 = -EOPNOTSUPP;
7860                 }
7861         }
7862
7863         return rc1;
7864 }
7865
7866 static int print_instance(const char *mntdir, char *buf, size_t buflen,
7867                           bool opt_instance, bool opt_fsname, bool opt_mntdir)
7868 {
7869         int rc = 0;
7870
7871         if (opt_fsname == opt_instance) { /* both true or both false */
7872                 rc = llapi_getname(mntdir, buf, buflen);
7873         } else if (opt_fsname) {
7874                 /*
7875                  * llapi_search_mounts() fills @buf with fsname, but that is not
7876                  * called if explicit paths are specified on the command-line
7877                  */
7878                 if (buf[0] == '\0')
7879                         rc = llapi_get_fsname(mntdir, buf, buflen);
7880         } else /* if (opt_instance) */ {
7881                 rc = llapi_get_instance(mntdir, buf, buflen);
7882         }
7883
7884         if (rc < 0) {
7885                 fprintf(stderr, "cannot get instance for '%s': %s\n",
7886                         mntdir, strerror(-rc));
7887                 return rc;
7888         }
7889
7890         if (opt_mntdir)
7891                 printf("%s %s\n", buf, mntdir);
7892         else
7893                 printf("%s\n", buf);
7894
7895         return 0;
7896 }
7897
7898 static int lfs_getname(int argc, char **argv)
7899 {
7900         struct option long_opts[] = {
7901         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7902         { .val = 'i',   .name = "instance",     .has_arg = no_argument },
7903         { .val = 'n',   .name = "fsname",       .has_arg = no_argument },
7904         { .name = NULL} };
7905         bool opt_instance = false, opt_fsname = false;
7906         char fsname[PATH_MAX] = "";
7907         int rc = 0, rc2, c;
7908
7909         while ((c = getopt_long(argc, argv, "hin", long_opts, NULL)) != -1) {
7910                 switch (c) {
7911                 case 'i':
7912                         opt_instance = true;
7913                         break;
7914                 case 'n':
7915                         opt_fsname = true;
7916                         break;
7917                 default:
7918                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7919                                 progname, argv[optind - 1]);
7920                         fallthrough;
7921                 case 'h':
7922                         return CMD_HELP;
7923                 }
7924         }
7925
7926         if (optind == argc) { /* no paths specified, get all paths. */
7927                 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "";
7928                 int index = 0;
7929
7930                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7931                         rc2 = print_instance(mntdir, fsname, sizeof(fsname),
7932                                              opt_instance, opt_fsname, true);
7933                         if (!rc)
7934                                 rc = rc2;
7935                         path[0] = fsname[0] = mntdir[0] = '\0';
7936                 }
7937         } else { /* paths specified, only attempt to search these. */
7938                 bool opt_mntdir;
7939
7940                 /* if only one path is given, print only requested info */
7941                 opt_mntdir = argc - optind > 1 || (opt_instance == opt_fsname);
7942
7943                 for (; optind < argc; optind++) {
7944                         rc2 = print_instance(argv[optind], fsname,
7945                                              sizeof(fsname), opt_instance,
7946                                              opt_fsname, opt_mntdir);
7947                         if (!rc)
7948                                 rc = rc2;
7949                         fsname[0] = '\0';
7950                 }
7951         }
7952
7953         return rc;
7954 }
7955
7956 static int lfs_check(int argc, char **argv)
7957 {
7958         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
7959         int num_types = 1;
7960         char *obd_types[3];
7961         char obd_type1[4];
7962         char obd_type2[4];
7963         char obd_type3[4];
7964         int rc;
7965
7966         if (argc < 2 || argc > 3) {
7967                 fprintf(stderr, "%s check: server type must be specified\n",
7968                         progname);
7969                 return CMD_HELP;
7970         }
7971
7972         obd_types[0] = obd_type1;
7973         obd_types[1] = obd_type2;
7974         obd_types[2] = obd_type3;
7975
7976         if (strcmp(argv[1], "osts") == 0) {
7977                 strcpy(obd_types[0], "osc");
7978         } else if (strcmp(argv[1], "mdts") == 0 ||
7979                    strcmp(argv[1], "mds") == 0) {
7980                 strcpy(obd_types[0], "mdc");
7981         } else if (strcmp(argv[1], "mgts") == 0) {
7982                 strcpy(obd_types[0], "mgc");
7983         } else if (strcmp(argv[1], "all") == 0 ||
7984                    strcmp(argv[1], "servers") == 0) {
7985                 num_types = 3;
7986                 strcpy(obd_types[0], "osc");
7987                 strcpy(obd_types[1], "mdc");
7988                 strcpy(obd_types[2], "mgc");
7989         } else {
7990                 fprintf(stderr, "%s check: unrecognized option '%s'\n",
7991                         progname, argv[1]);
7992                 return CMD_HELP;
7993         }
7994
7995         if (argc >= 3 && !realpath(argv[2], path)) {
7996                 rc = -errno;
7997                 fprintf(stderr, "error: invalid path '%s': %s\n",
7998                         argv[2], strerror(-rc));
7999                 return rc;
8000         }
8001
8002         rc = llapi_search_mounts(path, 0, mntdir, NULL);
8003         if (rc < 0 || mntdir[0] == '\0') {
8004                 fprintf(stderr,
8005                         "%s %s: cannot find mounted Lustre filesystem: %s\n",
8006                         progname, argv[0],
8007                         (rc < 0) ? strerror(-rc) : strerror(ENODEV));
8008                 return rc;
8009         }
8010
8011         rc = llapi_target_check(num_types, obd_types, path);
8012         if (rc)
8013                 fprintf(stderr, "%s %s: cannot check target '%s': %s\n",
8014                         progname, argv[0], argv[1], strerror(-rc));
8015
8016         return rc;
8017 }
8018
8019 #ifdef HAVE_SYS_QUOTA_H
8020 #define ADD_OVERFLOW(a, b) \
8021                      ((((a) + (b)) < (a)) ? \
8022                       ((a) = ULONG_MAX) : ((a) = (a) + (b)))
8023
8024 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
8025  * returns the value or ULONG_MAX on integer overflow or incorrect format
8026  * Notes:
8027  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
8028  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
8029  *        3. empty integer value is interpreted as 0
8030  */
8031 static unsigned long str2sec(const char *timestr)
8032 {
8033         const char spec[] = "smhdw";
8034         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
8035         unsigned long val = 0;
8036         char *tail;
8037
8038         if (strpbrk(timestr, spec) == NULL) {
8039                 /*
8040                  * no specifiers inside the time string,
8041                  * should treat it as an integer value
8042                  */
8043                 val = strtoul(timestr, &tail, 10);
8044                 return *tail ? ULONG_MAX : val;
8045         }
8046
8047         /* format string is XXwXXdXXhXXmXXs */
8048         while (*timestr) {
8049                 unsigned long v;
8050                 int ind;
8051                 char *ptr;
8052
8053                 v = strtoul(timestr, &tail, 10);
8054                 if (v == ULONG_MAX || *tail == '\0')
8055                         /*
8056                          * value too large (ULONG_MAX or more)
8057                          * or missing specifier
8058                          */
8059                         goto error;
8060
8061                 ptr = strchr(spec, *tail);
8062                 if (!ptr)
8063                         /* unknown specifier */
8064                         goto error;
8065
8066                 ind = ptr - spec;
8067
8068                 /* check if product will overflow the type */
8069                 if (!(v < ULONG_MAX / mult[ind]))
8070                         goto error;
8071
8072                 ADD_OVERFLOW(val, mult[ind] * v);
8073                 if (val == ULONG_MAX)
8074                         goto error;
8075
8076                 timestr = tail + 1;
8077         }
8078
8079         return val;
8080
8081 error:
8082         return ULONG_MAX;
8083 }
8084
8085 #define ARG2ULL(nr, str, def_units)                                     \
8086 do {                                                                    \
8087         unsigned long long limit, units = def_units;                    \
8088         int rc;                                                         \
8089                                                                         \
8090         rc = llapi_parse_size(str, &limit, &units, 1);                  \
8091         if (rc < 0) {                                                   \
8092                 fprintf(stderr, "%s: invalid limit '%s'\n",             \
8093                         progname, str);                                 \
8094                 return CMD_HELP;                                        \
8095         }                                                               \
8096         nr = limit;                                                     \
8097 } while (0)
8098
8099 static inline int has_times_option(int argc, char **argv)
8100 {
8101         int i;
8102
8103         for (i = 1; i < argc; i++)
8104                 if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--times"))
8105                         return 1;
8106
8107         return 0;
8108 }
8109
8110 static inline int lfs_verify_poolarg(char *pool)
8111 {
8112         if (strnlen(optarg, LOV_MAXPOOLNAME + 1) > LOV_MAXPOOLNAME) {
8113                 fprintf(stderr,
8114                         "Pool name '%.*s' is longer than %d\n",
8115                         LOV_MAXPOOLNAME, pool, LOV_MAXPOOLNAME);
8116                 return 1;
8117         }
8118         return 0;
8119 }
8120
8121 /* special grace time, only notify the user when its quota is over soft limit
8122  * but doesn't block new writes until the hard limit is reached.
8123  */
8124 #define NOTIFY_GRACE            "notify"
8125 #define NOTIFY_GRACE_TIME       LQUOTA_GRACE_MASK
8126
8127 #ifndef toqb
8128 static inline __u64 lustre_stoqb(size_t space)
8129 {
8130         return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
8131 }
8132 #else
8133 #define lustre_stoqb   toqb
8134 #endif
8135
8136 static int lfs_setquota_times(int argc, char **argv, struct if_quotactl *qctl)
8137 {
8138         int c, rc;
8139         char *mnt, *obd_type = (char *)qctl->obd_type;
8140         struct obd_dqblk *dqb = &qctl->qc_dqblk;
8141         struct obd_dqinfo *dqi = &qctl->qc_dqinfo;
8142         struct option long_opts[] = {
8143         { .val = 'b',   .name = "block-grace",  .has_arg = required_argument },
8144         { .val = 'g',   .name = "group",        .has_arg = no_argument },
8145         { .val = 'h',   .name = "help",         .has_arg = no_argument },
8146         { .val = 'i',   .name = "inode-grace",  .has_arg = required_argument },
8147         { .val = LFS_POOL_OPT, .name = "pool",  .has_arg = required_argument },
8148         { .val = 'p',   .name = "projid",       .has_arg = no_argument },
8149         { .val = 't',   .name = "times",        .has_arg = no_argument },
8150         { .val = 'u',   .name = "user",         .has_arg = no_argument },
8151         { .name = NULL } };
8152         int qtype;
8153
8154         qctl->qc_cmd  = LUSTRE_Q_SETINFO;
8155         qctl->qc_type = ALLQUOTA;
8156
8157         while ((c = getopt_long(argc, argv, "b:ghi:ptu",
8158                                 long_opts, NULL)) != -1) {
8159                 switch (c) {
8160                 case 'b':
8161                         if (strncmp(optarg, NOTIFY_GRACE,
8162                                     strlen(NOTIFY_GRACE)) == 0) {
8163                                 dqi->dqi_bgrace = NOTIFY_GRACE_TIME;
8164                         } else {
8165                                 dqi->dqi_bgrace = str2sec(optarg);
8166                                 if (dqi->dqi_bgrace >= NOTIFY_GRACE_TIME) {
8167                                         fprintf(stderr,
8168                                                 "%s: bad block-grace: %s\n",
8169                                                 progname, optarg);
8170                                         return CMD_HELP;
8171                                 }
8172                         }
8173                         dqb->dqb_valid |= QIF_BTIME;
8174                         break;
8175                 case 'g':
8176                         qtype = GRPQUOTA;
8177                         goto quota_type;
8178                 case 'i':
8179                         if (strncmp(optarg, NOTIFY_GRACE,
8180                                     strlen(NOTIFY_GRACE)) == 0) {
8181                                 dqi->dqi_igrace = NOTIFY_GRACE_TIME;
8182                         } else {
8183                                 dqi->dqi_igrace = str2sec(optarg);
8184                                 if (dqi->dqi_igrace >= NOTIFY_GRACE_TIME) {
8185                                         fprintf(stderr,
8186                                                 "%s: bad inode-grace: %s\n",
8187                                                 progname, optarg);
8188                                         return CMD_HELP;
8189                                 }
8190                         }
8191                         dqb->dqb_valid |= QIF_ITIME;
8192                         break;
8193                 case 'p':
8194                         qtype = PRJQUOTA;
8195                         goto quota_type;
8196                 case LFS_POOL_OPT:
8197                         if (lfs_verify_poolarg(optarg))
8198                                 return -1;
8199                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
8200                         qctl->qc_cmd  = LUSTRE_Q_SETINFOPOOL;
8201                         break;
8202                 case 't': /* Yes, of course! */
8203                         break;
8204                 case 'u':
8205                         qtype = USRQUOTA;
8206 quota_type:
8207                         if (qctl->qc_type != ALLQUOTA) {
8208                                 fprintf(stderr,
8209                                         "%s: -u/g/p cannot be used more than once\n",
8210                                         progname);
8211                                 return CMD_HELP;
8212                         }
8213                         qctl->qc_type = qtype;
8214                         break;
8215                 /* getopt prints error message for us when opterr != 0 */
8216                 default:
8217                         fprintf(stderr, "%s: unrecognized option '%s'\n",
8218                                 progname, argv[optind - 1]);
8219                         fallthrough;
8220                 case 'h':
8221                         return CMD_HELP;
8222                 }
8223         }
8224
8225         if (qctl->qc_type == ALLQUOTA) {
8226                 fprintf(stderr, "%s: neither -u, -g nor -p specified\n",
8227                         progname);
8228                 return CMD_HELP;
8229         }
8230
8231         if (optind != argc - 1) {
8232                 fprintf(stderr, "%s: unexpected parameter '%s'\n",
8233                         progname, argv[optind + 1]);
8234                 return CMD_HELP;
8235         }
8236
8237         mnt = argv[optind];
8238         rc = llapi_quotactl(mnt, qctl);
8239         if (rc) {
8240                 if (*obd_type)
8241                         fprintf(stderr, "%s %s ", obd_type,
8242                                 obd_uuid2str(&qctl->obd_uuid));
8243                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
8244                 return rc;
8245         }
8246
8247         return 0;
8248 }
8249
8250 static int lfs_reset_quota(char *mnt, struct if_quotactl *qctl)
8251 {
8252         struct if_quotactl tmp_qctl;
8253         int index, md_count, dt_count;
8254         int wait_phase = 0, wait_index = 0, wait_count = 0;
8255         int rc, rc2;
8256
8257         /* reset the quota ID, the existing quota setting will be returned */
8258         rc = llapi_quotactl(mnt, qctl);
8259         if (rc)
8260                 return rc;
8261
8262         /* sanity check */
8263         if ((qctl->qc_dqblk.dqb_valid & QIF_LIMITS) != QIF_LIMITS) {
8264                 fprintf(stderr,
8265                         "the existing quota settings are not returned!\n");
8266                 return -EINVAL;
8267         }
8268
8269         rc = llapi_get_obd_count(mnt, &md_count, 1);
8270         if (rc) {
8271                 fprintf(stderr, "can not get mdt count: %s\n", strerror(-rc));
8272                 return rc;
8273         }
8274
8275         rc = llapi_get_obd_count(mnt, &dt_count, 0);
8276         if (rc) {
8277                 fprintf(stderr, "can not get ost count: %s\n", strerror(-rc));
8278                 return rc;
8279         }
8280
8281         memset(&tmp_qctl, 0, sizeof(tmp_qctl));
8282         tmp_qctl.qc_type = qctl->qc_type;
8283         tmp_qctl.qc_id = qctl->qc_id;
8284         tmp_qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
8285
8286 retry:
8287         if (wait_phase == 0) {
8288                 for (index = wait_index; index < md_count; index++) {
8289                         tmp_qctl.qc_idx = index;
8290                         tmp_qctl.qc_valid = QC_MDTIDX;
8291                         rc = llapi_quotactl(mnt, &tmp_qctl);
8292                         if (rc == -ENODEV || rc == -ENODATA)
8293                                 continue;
8294                         if (rc) {
8295                                 fprintf(stderr, "quotactl mdt%d failed: %s\n",
8296                                         index, strerror(-rc));
8297                                 break;
8298                         }
8299                         /* check whether the md quota grant is reset */
8300                         if (tmp_qctl.qc_dqblk.dqb_valid & QIF_LIMITS &&
8301                             tmp_qctl.qc_dqblk.dqb_ihardlimit != 0)
8302                                 break;
8303                 }
8304
8305                 if (index < md_count) {
8306                         wait_phase = 0;
8307                         wait_index = index;
8308                         goto wait;
8309                 }
8310         } else {
8311                 for (index = wait_index; index < dt_count; index++) {
8312                         tmp_qctl.qc_idx = index;
8313                         tmp_qctl.qc_valid = QC_OSTIDX;
8314                         rc = llapi_quotactl(mnt, &tmp_qctl);
8315                         if (rc == -ENODEV || rc == -ENODATA)
8316                                 continue;
8317                         if (rc) {
8318                                 fprintf(stderr, "quotactl mdt%d failed: %s\n",
8319                                         index, strerror(-rc));
8320                                 break;
8321                         }
8322                         /* check whether the dt quota grant is reset */
8323                         if (tmp_qctl.qc_dqblk.dqb_valid & QIF_LIMITS &&
8324                             tmp_qctl.qc_dqblk.dqb_bhardlimit != 0)
8325                                 break;
8326                 }
8327
8328                 if (index < dt_count) {
8329                         wait_phase = 1;
8330                         wait_index = index;
8331                         goto wait;
8332                 }
8333         }
8334
8335         if (wait_phase == 0) {
8336                 wait_phase = 1;
8337                 goto retry;
8338         }
8339
8340         goto out;
8341
8342 wait:
8343         if (rc || wait_count > 30) {
8344                 fprintf(stderr, "fail to reset the quota ID %d on OBDs\n",
8345                         qctl->qc_id);
8346                 goto out;
8347         }
8348
8349         wait_count++;
8350         sleep(1);
8351         fprintf(stdout, "wait %d seconds for OBDs to reset the quota ID %u\n",
8352                 wait_count, qctl->qc_id);
8353         goto retry;
8354
8355
8356 out:
8357         /* restore the quota setting */
8358         if (qctl->qc_dqblk.dqb_isoftlimit == 0 &&
8359             qctl->qc_dqblk.dqb_ihardlimit == 0 &&
8360             qctl->qc_dqblk.dqb_bsoftlimit == 0 &&
8361             qctl->qc_dqblk.dqb_bhardlimit == 0)
8362                 return rc;
8363
8364         memcpy(&tmp_qctl, qctl, sizeof(tmp_qctl));
8365         tmp_qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
8366         rc2 = llapi_quotactl(mnt, &tmp_qctl);
8367         if (!rc2)
8368                 return rc;
8369
8370         fprintf(stderr,
8371                 "fail to restore the quota setting: %s, please restore it manually by\n  lfs setquota %s %d",
8372                 strerror(-rc2),
8373                 qctl->qc_type == USRQUOTA ? "-u" :
8374                                 (qctl->qc_type == GRPQUOTA ? "-g" : "-p"),
8375                 qctl->qc_id);
8376
8377         if (qctl->qc_dqblk.dqb_isoftlimit != 0)
8378                 fprintf(stderr, " -i %llu",
8379                         (unsigned long long)qctl->qc_dqblk.dqb_isoftlimit);
8380         if (qctl->qc_dqblk.dqb_ihardlimit != 0)
8381                 fprintf(stderr, " -I %llu",
8382                         (unsigned long long)qctl->qc_dqblk.dqb_ihardlimit);
8383         if (qctl->qc_dqblk.dqb_bsoftlimit != 0)
8384                 fprintf(stderr, " -b %llu",
8385                         (unsigned long long)qctl->qc_dqblk.dqb_bsoftlimit);
8386         if (qctl->qc_dqblk.dqb_bhardlimit != 0)
8387                 fprintf(stderr, " -B %llu",
8388                         (unsigned long long)qctl->qc_dqblk.dqb_bhardlimit);
8389
8390         fprintf(stderr, " %s\n", mnt);
8391         if (!rc)
8392                 rc = rc2;
8393
8394         return rc;
8395 }
8396
8397 #define BSLIMIT (1 << 0)
8398 #define BHLIMIT (1 << 1)
8399 #define ISLIMIT (1 << 2)
8400 #define IHLIMIT (1 << 3)
8401
8402 int lfs_setquota(int argc, char **argv)
8403 {
8404         int c, rc = 0;
8405         struct if_quotactl *qctl;
8406         char *mnt, *obd_type;
8407         struct obd_dqblk *dqb;
8408         struct option long_opts[] = {
8409         { .val = 'b',   .name = "block-softlimit",
8410                                                 .has_arg = required_argument },
8411         { .val = 'B',   .name = "block-hardlimit",
8412                                                 .has_arg = required_argument },
8413         { .val = 'd',   .name = "default",      .has_arg = no_argument },
8414         { .val = LFS_SETQUOTA_DELETE,
8415                         .name = "delete",       .has_arg = no_argument },
8416         { .val = 'g',   .name = "group",        .has_arg = required_argument },
8417         { .val = 'G',   .name = "default-grp",  .has_arg = no_argument },
8418         { .val = 'h',   .name = "help",         .has_arg = no_argument },
8419         { .val = 'i',   .name = "inode-softlimit",
8420                                                 .has_arg = required_argument },
8421         { .val = 'I',   .name = "inode-hardlimit",
8422                                                 .has_arg = required_argument },
8423         { .val = 'p',   .name = "projid",       .has_arg = required_argument },
8424         { .val = 'P',   .name = "default-prj",  .has_arg = no_argument },
8425         { .val = 'r',   .name = "reset",        .has_arg = no_argument },
8426         { .val = 'u',   .name = "user",         .has_arg = required_argument },
8427         { .val = 'U',   .name = "default-usr",  .has_arg = no_argument },
8428         { .val = LFS_POOL_OPT,
8429                         .name = "pool",         .has_arg = required_argument },
8430         { .name = NULL } };
8431         unsigned int limit_mask = 0;
8432         bool use_default = false;
8433         int qtype, qctl_len;
8434
8435         qctl_len = sizeof(*qctl) + LOV_MAXPOOLNAME + 1;
8436         qctl = malloc(qctl_len);
8437         if (!qctl)
8438                 return -ENOMEM;
8439
8440         memset(qctl, 0, qctl_len);
8441         obd_type = (char *)qctl->obd_type;
8442         dqb = &qctl->qc_dqblk;
8443
8444         if (has_times_option(argc, argv)) {
8445                 rc = lfs_setquota_times(argc, argv, qctl);
8446                 goto out;
8447         }
8448
8449         qctl->qc_cmd  = LUSTRE_Q_SETQUOTA;
8450         qctl->qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
8451                                    * so it can be used as a marker that qc_type
8452                                    * isn't reinitialized from command line
8453                                    */
8454         while ((c = getopt_long(argc, argv, "b:B:dDg:Ghi:I:p:Pru:U",
8455                 long_opts, NULL)) != -1) {
8456                 switch (c) {
8457                 case 'U':
8458                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8459                         qtype = USRQUOTA;
8460                         qctl->qc_id = 0;
8461                         goto quota_type_def;
8462                 case 'u':
8463                         qtype = USRQUOTA;
8464                         rc = name2uid(&qctl->qc_id, optarg);
8465                         goto quota_type;
8466                 case 'G':
8467                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8468                         qtype = GRPQUOTA;
8469                         qctl->qc_id = 0;
8470                         goto quota_type_def;
8471                 case 'g':
8472                         qtype = GRPQUOTA;
8473                         rc = name2gid(&qctl->qc_id, optarg);
8474                         goto quota_type;
8475                 case 'P':
8476                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8477                         qtype = PRJQUOTA;
8478                         qctl->qc_id = 0;
8479                         goto quota_type_def;
8480                 case 'p':
8481                         qtype = PRJQUOTA;
8482                         rc = name2projid(&qctl->qc_id, optarg);
8483 quota_type:
8484                         if (rc) {
8485                                 if (str2quotaid(&qctl->qc_id, optarg)) {
8486                                         fprintf(stderr,
8487                                                 "%s setquota: invalid id '%s'\n",
8488                                                 progname, optarg);
8489                                         rc = -1;
8490                                         goto out;
8491                                 }
8492                         }
8493
8494                         if (qctl->qc_id == 0) {
8495                                 fprintf(stderr,
8496                                         "%s setquota: can't set quota for root usr/group/project.\n",
8497                                         progname);
8498                                 rc = -1;
8499                                 goto out;
8500                         }
8501
8502 quota_type_def:
8503                         if (qctl->qc_type != ALLQUOTA) {
8504                                 fprintf(stderr,
8505                                         "%s setquota: only one of -u, -U, -g, -G, -p or -P may be specified\n",
8506                                         progname);
8507                                 rc = CMD_HELP;
8508                                 goto out;
8509                         }
8510                         qctl->qc_type = qtype;
8511                         break;
8512 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 22, 53, 0)
8513                 case 'd':
8514                         fprintf(stderr,
8515                                 "%s setquota: '-d' deprecated, use '-D' or '--default'\n",
8516                                 progname);
8517                         fallthrough;
8518 #endif
8519                 case 'D':
8520                         use_default = true;
8521                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8522                         break;
8523                 case LFS_SETQUOTA_DELETE:
8524                         qctl->qc_cmd = LUSTRE_Q_DELETEQID;
8525                         break;
8526                 case 'b':
8527                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
8528                         dqb->dqb_bsoftlimit >>= 10;
8529                         limit_mask |= BSLIMIT;
8530                         if (dqb->dqb_bsoftlimit &&
8531                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
8532                                 fprintf(stderr,
8533                                         "%s setquota: warning: block softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8534                                         progname,
8535                                         (unsigned long long)dqb->dqb_bsoftlimit,
8536                                         progname);
8537                         break;
8538                 case 'B':
8539                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
8540                         dqb->dqb_bhardlimit >>= 10;
8541                         limit_mask |= BHLIMIT;
8542                         if (dqb->dqb_bhardlimit &&
8543                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
8544                                 fprintf(stderr,
8545                                         "%s setquota: warning: block hardlimit '%llu' smaller than minimum qunit size\n"
8546                                         "See '%s help setquota' or Lustre manual for details\n",
8547                                         progname,
8548                                         (unsigned long long)dqb->dqb_bhardlimit,
8549                                         progname);
8550                         break;
8551                 case 'i':
8552                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
8553                         limit_mask |= ISLIMIT;
8554                         if (dqb->dqb_isoftlimit &&
8555                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
8556                                 fprintf(stderr,
8557                                         "%s setquota: warning: inode softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8558                                         progname,
8559                                         (unsigned long long)dqb->dqb_isoftlimit,
8560                                         progname);
8561                         break;
8562                 case 'I':
8563                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
8564                         limit_mask |= IHLIMIT;
8565                         if (dqb->dqb_ihardlimit &&
8566                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
8567                                 fprintf(stderr,
8568                                         "%s setquota: warning: inode hardlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8569                                         progname,
8570                                         (unsigned long long)dqb->dqb_ihardlimit,
8571                                         progname);
8572                         break;
8573                 case LFS_POOL_OPT:
8574                         if (lfs_verify_poolarg(optarg)) {
8575                                 rc = -1;
8576                                 goto out;
8577                         }
8578                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
8579                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_SETDEFAULT ?
8580                                                 LUSTRE_Q_SETDEFAULT_POOL :
8581                                                 LUSTRE_Q_SETQUOTAPOOL;
8582                         break;
8583                 case 'r':
8584                         qctl->qc_cmd = LUSTRE_Q_RESETQID;
8585                         break;
8586                 default:
8587                         fprintf(stderr,
8588                                 "%s setquota: unrecognized option '%s'\n",
8589                                 progname, argv[optind - 1]);
8590                         fallthrough;
8591                 case 'h':
8592                         rc = CMD_HELP;
8593                         goto out;
8594                 }
8595         }
8596
8597         if (qctl->qc_type == ALLQUOTA) {
8598                 fprintf(stderr,
8599                         "%s setquota: either -u or -g must be specified\n",
8600                         progname);
8601                 rc = CMD_HELP;
8602                 goto out;
8603         }
8604
8605         if (!use_default && qctl->qc_cmd != LUSTRE_Q_DELETEQID &&
8606             qctl->qc_cmd != LUSTRE_Q_RESETQID && limit_mask == 0) {
8607                 fprintf(stderr,
8608                         "%s setquota: at least one limit must be specified\n",
8609                         progname);
8610                 rc = CMD_HELP;
8611                 goto out;
8612         }
8613
8614         if ((use_default || qctl->qc_cmd == LUSTRE_Q_DELETEQID ||
8615              qctl->qc_cmd == LUSTRE_Q_RESETQID) && limit_mask != 0) {
8616                 fprintf(stderr,
8617                         "%s setquota: limits should not be specified when using default quota, deleting or resetting quota ID\n",
8618                         progname);
8619                 rc = CMD_HELP;
8620                 goto out;
8621         }
8622
8623         if (use_default && qctl->qc_id == 0) {
8624                 fprintf(stderr,
8625                         "%s setquota: can not set default quota for root user/group/project\n",
8626                         progname);
8627                 rc = CMD_HELP;
8628                 goto out;
8629         }
8630
8631         if ((qctl->qc_cmd == LUSTRE_Q_DELETEQID ||
8632              qctl->qc_cmd == LUSTRE_Q_RESETQID)  && qctl->qc_id == 0) {
8633                 fprintf(stderr,
8634                         "%s setquota: can not delete or reset root user/group/project\n",
8635                         progname);
8636                 rc = CMD_HELP;
8637                 goto out;
8638         }
8639
8640         if (optind != argc - 1) {
8641                 fprintf(stderr,
8642                         "%s setquota: filesystem not specified or unexpected argument '%s'\n",
8643                         progname, argv[optind]);
8644                 rc = CMD_HELP;
8645                 goto out;
8646         }
8647
8648         mnt = argv[optind];
8649
8650         if (use_default) {
8651                 dqb->dqb_bhardlimit = 0;
8652                 dqb->dqb_bsoftlimit = 0;
8653                 dqb->dqb_ihardlimit = 0;
8654                 dqb->dqb_isoftlimit = 0;
8655                 dqb->dqb_itime = 0;
8656                 dqb->dqb_btime = 0;
8657                 dqb->dqb_valid |= QIF_LIMITS | QIF_TIMES;
8658                 /* do not set inode limits for Pool Quotas */
8659                 if (qctl->qc_cmd  == LUSTRE_Q_SETDEFAULT_POOL)
8660                         dqb->dqb_valid ^= QIF_ILIMITS | QIF_ITIME;
8661         } else if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
8662                    (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
8663                 /* sigh, we can't just set blimits/ilimits */
8664                 struct if_quotactl *tmp_qctl;
8665
8666                 tmp_qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1);
8667                 if (!tmp_qctl)
8668                         goto out;
8669
8670                 if (qctl->qc_cmd == LUSTRE_Q_SETQUOTAPOOL) {
8671                         tmp_qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
8672                         strncpy(tmp_qctl->qc_poolname, qctl->qc_poolname,
8673                                 LOV_MAXPOOLNAME);
8674                 } else {
8675                         tmp_qctl->qc_cmd  = LUSTRE_Q_GETQUOTA;
8676                 }
8677                 tmp_qctl->qc_type = qctl->qc_type;
8678                 tmp_qctl->qc_id = qctl->qc_id;
8679
8680                 rc = llapi_quotactl(mnt, tmp_qctl);
8681                 if (rc < 0) {
8682                         free(tmp_qctl);
8683                         goto out;
8684                 }
8685
8686                 if (!(limit_mask & BHLIMIT))
8687                         dqb->dqb_bhardlimit = tmp_qctl->qc_dqblk.dqb_bhardlimit;
8688                 if (!(limit_mask & BSLIMIT))
8689                         dqb->dqb_bsoftlimit = tmp_qctl->qc_dqblk.dqb_bsoftlimit;
8690                 if (!(limit_mask & IHLIMIT))
8691                         dqb->dqb_ihardlimit = tmp_qctl->qc_dqblk.dqb_ihardlimit;
8692                 if (!(limit_mask & ISLIMIT))
8693                         dqb->dqb_isoftlimit = tmp_qctl->qc_dqblk.dqb_isoftlimit;
8694
8695                 /* Keep grace times if we have got no softlimit arguments */
8696                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
8697                         dqb->dqb_valid |= QIF_BTIME;
8698                         dqb->dqb_btime = tmp_qctl->qc_dqblk.dqb_btime;
8699                 }
8700
8701                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
8702                         dqb->dqb_valid |= QIF_ITIME;
8703                         dqb->dqb_itime = tmp_qctl->qc_dqblk.dqb_itime;
8704                 }
8705                 free(tmp_qctl);
8706         }
8707
8708         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
8709         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
8710
8711         if (qctl->qc_cmd == LUSTRE_Q_RESETQID)
8712                 rc = lfs_reset_quota(mnt, qctl);
8713         else
8714                 rc = llapi_quotactl(mnt, qctl);
8715
8716         if (rc) {
8717                 if (*obd_type)
8718                         fprintf(stderr,
8719                                 "%s setquota: cannot quotactl '%s' '%s': %s\n",
8720                                 progname, obd_type,
8721                                 obd_uuid2str(&qctl->obd_uuid), strerror(-rc));
8722                 else
8723                         fprintf(stderr,
8724                                 "%s setquota: quotactl failed: %s\n",
8725                                 progname, strerror(-rc));
8726         }
8727 out:
8728         if (rc)
8729                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
8730
8731         free(qctl);
8732         return rc;
8733 }
8734
8735 /* Converts seconds value into format string
8736  * result is returned in buf
8737  * Notes:
8738  *        1. result is in descenting order: 1w2d3h4m5s
8739  *        2. zero fields are not filled (except for p. 3): 5d1s
8740  *        3. zero seconds value is presented as "0s"
8741  */
8742 static char *__sec2str(time_t seconds, char *buf)
8743 {
8744         const char spec[] = "smhdw";
8745         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
8746         unsigned long c;
8747         char *tail = buf;
8748         int i;
8749
8750         for (i = ARRAY_SIZE(mult) - 1 ; i >= 0; i--) {
8751                 c = seconds / mult[i];
8752
8753                 if (c > 0 || (i == 0 && buf == tail))
8754                         tail += scnprintf(tail, 40-(tail-buf), "%lu%c", c,
8755                                           spec[i]);
8756
8757                 seconds %= mult[i];
8758         }
8759
8760         return tail;
8761 }
8762
8763 static void sec2str(time_t seconds, char *buf, int rc)
8764 {
8765         char *tail = buf;
8766
8767         if (rc)
8768                 *tail++ = '[';
8769
8770         tail = __sec2str(seconds, tail);
8771
8772         if (rc && tail - buf < 39) {
8773                 *tail++ = ']';
8774                 *tail++ = 0;
8775         }
8776 }
8777
8778 static void diff2str(time_t seconds, char *buf, time_t now)
8779 {
8780         buf[0] = 0;
8781         if (!seconds)
8782                 return;
8783         if (seconds <= now) {
8784                 strcpy(buf, "expired");
8785                 return;
8786         }
8787         __sec2str(seconds - now, buf);
8788 }
8789
8790 static void print_quota_title(char *name, struct if_quotactl *qctl,
8791                               bool human_readable, bool show_default)
8792 {
8793         if (show_default) {
8794                 printf("Disk default %s quota:\n", qtype_name(qctl->qc_type));
8795                 printf("%15s %8s%8s%8s %8s%8s%8s\n",
8796                        "Filesystem", "bquota", "blimit", "bgrace",
8797                        "iquota", "ilimit", "igrace");
8798         } else {
8799                 printf("Disk quotas for %s %s (%cid %u):\n",
8800                        qtype_name(qctl->qc_type), name,
8801                        *qtype_name(qctl->qc_type), qctl->qc_id);
8802                 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
8803                        "Filesystem", human_readable ? "used" : "kbytes",
8804                        "quota", "limit", "grace",
8805                        "files", "quota", "limit", "grace");
8806         }
8807 }
8808
8809 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
8810 {
8811         if (!h) {
8812                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
8813         } else {
8814                 if (num >> 40)
8815                         snprintf(buf, buflen, "%5.4gP",
8816                                  (double)num / ((__u64)1 << 40));
8817                 else if (num >> 30)
8818                         snprintf(buf, buflen, "%5.4gT",
8819                                  (double)num / (1 << 30));
8820                 else if (num >> 20)
8821                         snprintf(buf, buflen, "%5.4gG",
8822                                  (double)num / (1 << 20));
8823                 else if (num >> 10)
8824                         snprintf(buf, buflen, "%5.4gM",
8825                                  (double)num / (1 << 10));
8826                 else
8827                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
8828         }
8829 }
8830
8831 #ifdef HAVE_NATIVE_CLIENT
8832 /* In the current Lustre implementation, the grace time is either the time
8833  * or the timestamp to be used after some quota ID exceeds the soft limt,
8834  * 48 bits should be enough, its high 16 bits can be used as quota flags.
8835  */
8836 #define LQUOTA_GRACE_BITS       48
8837 #define LQUOTA_GRACE_MASK       ((1ULL << LQUOTA_GRACE_BITS) - 1)
8838 #define LQUOTA_GRACE_MAX        LQUOTA_GRACE_MASK
8839 #define LQUOTA_GRACE(t)         (t & LQUOTA_GRACE_MASK)
8840 #define LQUOTA_FLAG(t)          (t >> LQUOTA_GRACE_BITS)
8841 #define LQUOTA_GRACE_FLAG(t, f) ((__u64)t | (__u64)f << LQUOTA_GRACE_BITS)
8842 #endif
8843
8844 #define STRBUF_LEN      24
8845 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
8846                         int rc, bool h, bool show_default, bool show_qid)
8847 {
8848         char *name;
8849         time_t now;
8850
8851         time(&now);
8852
8853         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA ||
8854             qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
8855             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT ||
8856             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL) {
8857                 int bover = 0, iover = 0;
8858                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
8859                 char numbuf[3][STRBUF_LEN + 2]; /* 2 for brackets or wildcard */
8860                 char timebuf[40];
8861                 char strbuf[STRBUF_LEN];
8862
8863                 dqb->dqb_btime &= LQUOTA_GRACE_MASK;
8864                 dqb->dqb_itime &= LQUOTA_GRACE_MASK;
8865
8866                 if (dqb->dqb_bhardlimit &&
8867                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
8868                         bover = 1;
8869                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
8870                         if (dqb->dqb_btime > now)
8871                                 bover = 2;
8872                         else
8873                                 bover = 3;
8874                 }
8875
8876                 if (dqb->dqb_ihardlimit &&
8877                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
8878                         iover = 1;
8879                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
8880                         if (dqb->dqb_itime > now)
8881                                 iover = 2;
8882                         else
8883                                 iover = 3;
8884                 }
8885
8886                 if (show_qid) {
8887                         if (qctl->qc_type == USRQUOTA) {
8888                                 if (uid2name(&name, qctl->qc_id))
8889                                         printf("%10u", qctl->qc_id);
8890                                 else
8891                                         printf("%10s", name);
8892                         } else if (qctl->qc_type == GRPQUOTA) {
8893                                 if (gid2name(&name, qctl->qc_id))
8894                                         printf("%10u", qctl->qc_id);
8895                                 else
8896                                         printf("%10s", name);
8897                         } else {
8898                                 printf("%10u", qctl->qc_id);
8899                         }
8900                 } else {
8901                         if (strlen(mnt) > 15)
8902                                 printf("%s\n%15s", mnt, "");
8903                         else
8904                                 printf("%15s", mnt);
8905                 }
8906
8907                 if (show_default)
8908                         snprintf(timebuf, sizeof(timebuf), "%llu",
8909                                  (unsigned long long)dqb->dqb_btime);
8910                 else if (bover)
8911                         diff2str(dqb->dqb_btime, timebuf, now);
8912
8913                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
8914                            strbuf, sizeof(strbuf), h);
8915                 if (rc == -EREMOTEIO)
8916                         sprintf(numbuf[0], "%s*", strbuf);
8917                 else
8918                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
8919                                 "%s" : "[%s]", strbuf);
8920
8921                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
8922                 if (type == QC_GENERAL)
8923                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
8924                                 "%s" : "[%s]", strbuf);
8925                 else
8926                         sprintf(numbuf[1], "%s", "-");
8927
8928                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
8929                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
8930                         "%s" : "[%s]", strbuf);
8931
8932                 if (show_default)
8933                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
8934                 else
8935                         printf(" %7s%c %6s %7s %7s",
8936                                numbuf[0], bover ? '*' : ' ', numbuf[1],
8937                                numbuf[2], bover > 1 ? timebuf : "-");
8938
8939                 if (show_default)
8940                         snprintf(timebuf, sizeof(timebuf), "%llu",
8941                                  (unsigned long long)dqb->dqb_itime);
8942                 else if (iover)
8943                         diff2str(dqb->dqb_itime, timebuf, now);
8944
8945                 snprintf(numbuf[0], sizeof(numbuf),
8946                          (dqb->dqb_valid & QIF_INODES) ? "%ju" : "[%ju]",
8947                          (uintmax_t)dqb->dqb_curinodes);
8948
8949                 if (type == QC_GENERAL)
8950                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
8951                                 "%ju" : "[%ju]",
8952                                 (uintmax_t)dqb->dqb_isoftlimit);
8953                 else
8954                         sprintf(numbuf[1], "%s", "-");
8955
8956                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
8957                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
8958
8959                 if (show_default)
8960                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
8961                 else if (type != QC_OSTIDX)
8962                         printf(" %7s%c %6s %7s %7s",
8963                                numbuf[0], iover ? '*' : ' ', numbuf[1],
8964                                numbuf[2], iover > 1 ? timebuf : "-");
8965                 else
8966                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
8967                 printf("\n");
8968         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
8969                    qctl->qc_cmd == LUSTRE_Q_GETINFOPOOL ||
8970                    qctl->qc_cmd == Q_GETOINFO) {
8971                 char bgtimebuf[40];
8972                 char igtimebuf[40];
8973
8974                 if (qctl->qc_dqinfo.dqi_bgrace == NOTIFY_GRACE_TIME)
8975                         strncpy(bgtimebuf, NOTIFY_GRACE, 40);
8976                 else
8977                         sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
8978                 if (qctl->qc_dqinfo.dqi_igrace == NOTIFY_GRACE_TIME)
8979                         strncpy(igtimebuf, NOTIFY_GRACE, 40);
8980                 else
8981                         sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
8982
8983                 printf("Block grace time: %s; Inode grace time: %s\n",
8984                        bgtimebuf, igtimebuf);
8985         }
8986 }
8987
8988 static int tgt_name2index(const char *tgtname, unsigned int *idx)
8989 {
8990         char *dash, *endp;
8991
8992         /* format is "lustre-OST0001" */
8993         dash = memchr(tgtname, '-', LUSTRE_MAXFSNAME + 1);
8994         if (!dash) {
8995                 fprintf(stderr, "wrong tgtname format '%s'\n", tgtname);
8996                 return -EINVAL;
8997         }
8998         dash += 4;
8999
9000         *idx = strtoul(dash, &endp, 16);
9001         if (*idx > LOV_V1_INSANE_STRIPE_COUNT) {
9002                 fprintf(stderr, "wrong index %s\n", tgtname);
9003                 return -ERANGE;
9004         }
9005
9006         return 0;
9007 }
9008
9009 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
9010                            bool h, __u64 *total)
9011 {
9012         int rc = 0, rc1 = 0, count = 0, i = 0;
9013         char **list = NULL, *buffer = NULL;
9014         __u32 valid = qctl->qc_valid;
9015
9016         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL && is_mdt)
9017                 return 0;
9018
9019         /* Is it correct for the case OST0000, OST0002, OST0003 -
9020          * we will ask OST0001 that is absent and won't ask OST0003? */
9021         rc = llapi_get_obd_count(mnt, &count, is_mdt);
9022         if (rc) {
9023                 fprintf(stderr, "can not get %s count: %s\n",
9024                         is_mdt ? "mdt" : "ost", strerror(-rc));
9025                 return rc;
9026         }
9027
9028         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
9029                 char fname[PATH_MAX];
9030                 char fsname[LUSTRE_MAXFSNAME + 1];
9031                 int bufsize = sizeof(struct obd_uuid) * count;
9032
9033                 rc = llapi_search_fsname(mnt, fsname);
9034                 if (rc) {
9035                         fprintf(stderr, "cannot get fsname for mountpoint %s\n",
9036                                 mnt);
9037                         goto out;
9038                 }
9039                 buffer = malloc(bufsize + sizeof(*list) * count);
9040                 if (!buffer)
9041                         return -ENOMEM;
9042                 list = (char **)(buffer + bufsize);
9043                 snprintf(fname, PATH_MAX, "%s.%s", fsname, qctl->qc_poolname);
9044                 count = llapi_get_poolmembers(fname, list, count,
9045                                               buffer, bufsize);
9046                 if (count <= 0)
9047                         goto out;
9048         }
9049
9050         for (i = 0; i < count; i++) {
9051                 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
9052                         unsigned int index;
9053
9054                         if (tgt_name2index(list[i], &index))
9055                                 continue;
9056                         qctl->qc_idx = index;
9057                 } else {
9058                         qctl->qc_idx = i;
9059                 }
9060
9061                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
9062                 rc = llapi_quotactl(mnt, qctl);
9063                 if (rc) {
9064                         /* It is remote client case. */
9065                         if (rc == -EOPNOTSUPP) {
9066                                 rc = 0;
9067                                 goto out;
9068                         }
9069
9070                         /* no target for this index yet */
9071                         if (rc == -ENODEV) {
9072                                 rc = 0;
9073                                 continue;
9074                         }
9075
9076                         /* inactive target */
9077                         if (rc == -ENODATA) {
9078                                 char name[UUID_MAX+8];
9079
9080                                 snprintf(name, sizeof(name), "%s[inact]",
9081                                         obd_uuid2str(&qctl->obd_uuid));
9082                                 memset(&qctl->qc_dqinfo, 0,
9083                                        sizeof(qctl->qc_dqinfo));
9084                                 memset(&qctl->qc_dqblk, 0,
9085                                        sizeof(qctl->qc_dqblk));
9086                                 print_quota(name, qctl, qctl->qc_valid, 0, h,
9087                                             false, false);
9088                                 rc = 0;
9089                                 continue;
9090                         }
9091
9092                         if (!rc1)
9093                                 rc1 = rc;
9094                         fprintf(stderr, "quotactl %s%d failed.\n",
9095                                 is_mdt ? "mdt" : "ost", qctl->qc_idx);
9096                         continue;
9097                 }
9098
9099                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
9100                             qctl->qc_valid, 0, h, false, false);
9101                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
9102                                    qctl->qc_dqblk.dqb_bhardlimit;
9103         }
9104 out:
9105         if (buffer)
9106                 free(buffer);
9107         qctl->qc_valid = valid;
9108         return rc ? : rc1;
9109 }
9110
9111 static int print_one_quota(char *mnt, char *name, struct if_quotactl *qctl,
9112                            int verbose, int quiet, bool human_readable,
9113                            bool show_default, bool show_qid, int rc)
9114 {
9115         int rc1 = 0, rc2 = 0;
9116         char *obd_type = (char *)qctl->obd_type;
9117         char *obd_uuid = (char *)qctl->obd_uuid.uuid;
9118         __u64 total_ialloc = 0, total_balloc = 0;
9119         int inacc;
9120
9121         if (!show_default && qctl->qc_id == 0) {
9122                 qctl->qc_dqblk.dqb_bhardlimit = 0;
9123                 qctl->qc_dqblk.dqb_bsoftlimit = 0;
9124                 qctl->qc_dqblk.dqb_ihardlimit = 0;
9125                 qctl->qc_dqblk.dqb_isoftlimit = 0;
9126                 qctl->qc_dqblk.dqb_btime = 0;
9127                 qctl->qc_dqblk.dqb_itime = 0;
9128                 qctl->qc_dqblk.dqb_valid |= QIF_LIMITS | QIF_TIMES;
9129         }
9130
9131         if (qctl->qc_dqblk.dqb_valid & QIF_BTIME &&
9132             LQUOTA_FLAG(qctl->qc_dqblk.dqb_btime) & LQUOTA_FLAG_DEFAULT)
9133                 qctl->qc_dqblk.dqb_btime &= LQUOTA_GRACE_MASK;
9134
9135         if (qctl->qc_dqblk.dqb_valid & QIF_ITIME &&
9136             LQUOTA_FLAG(qctl->qc_dqblk.dqb_itime) & LQUOTA_FLAG_DEFAULT)
9137                 qctl->qc_dqblk.dqb_itime &= LQUOTA_GRACE_MASK;
9138
9139         if (!show_qid && (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
9140              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
9141              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL ||
9142              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) && !quiet)
9143                 print_quota_title(name, qctl, human_readable, show_default);
9144
9145         if (rc && *obd_type)
9146                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
9147
9148         if (qctl->qc_valid != QC_GENERAL)
9149                 mnt = "";
9150
9151         inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
9152                  qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
9153                 ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
9154                  (QIF_LIMITS|QIF_USAGE));
9155
9156         print_quota(mnt, qctl, QC_GENERAL, rc, human_readable, show_default,
9157                     show_qid);
9158
9159         if (!show_qid && !show_default && verbose &&
9160             qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO &&
9161             qctl->qc_cmd != LUSTRE_Q_GETINFOPOOL) {
9162                 char strbuf[STRBUF_LEN];
9163
9164                 rc1 = print_obd_quota(mnt, qctl, 1, human_readable,
9165                                       &total_ialloc);
9166                 rc2 = print_obd_quota(mnt, qctl, 0, human_readable,
9167                                       &total_balloc);
9168                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
9169                            human_readable);
9170                 printf("Total allocated inode limit: %ju, total allocated block limit: %s\n",
9171                        (uintmax_t)total_ialloc, strbuf);
9172         }
9173
9174         if (!show_qid && (rc || rc1 || rc2 || inacc))
9175                 printf("%d Some errors happened when getting quota info. Some devices may be not working or deactivated. The data in \"[]\" is inaccurate.\n", inacc);
9176
9177         if (rc)
9178                 return rc;
9179         if (rc1)
9180                 return rc1;
9181         if (rc2)
9182                 return rc2;
9183         if (inacc)
9184                 return -EIO;
9185
9186         return 0;
9187 }
9188
9189 static int iter_all_quota(char *mnt, struct if_quotactl *qctl, int quiet,
9190                           bool human_readable)
9191 {
9192         struct if_quotactl qctl_tmp, *qctl_iter;
9193         void *buffer = NULL;
9194         __u64 mark;
9195         __u64 cur, buflen = 0;
9196         int rc = 0;
9197
9198         memcpy(&qctl_tmp, qctl, sizeof(struct if_quotactl));
9199         qctl_tmp.qc_cmd = LUSTRE_Q_ITERQUOTA;
9200         rc = llapi_quotactl(mnt, &qctl_tmp);
9201         if (rc)
9202                 goto out;
9203
9204         buflen = qctl_tmp.qc_allquota_count * sizeof(struct if_quotactl);
9205         buffer = malloc(buflen);
9206         if (buffer == NULL) {
9207                 rc = -ENOMEM;
9208                 goto out;
9209         }
9210
9211         mark = qctl_tmp.qc_allquota_mark;
9212         memcpy(&qctl_tmp, qctl, sizeof(struct if_quotactl));
9213         qctl_tmp.qc_cmd = LUSTRE_Q_GETALLQUOTA;
9214         qctl_tmp.qc_allquota_buffer = (__u64)buffer;
9215         qctl_tmp.qc_allquota_buflen = buflen;
9216         qctl_tmp.qc_allquota_mark = mark;
9217         rc = llapi_quotactl(mnt, &qctl_tmp);
9218         if (rc)
9219                 goto out;
9220
9221         printf("Filesystem %s, Disk %s quotas\n", mnt,
9222                qtype_name(qctl->qc_type));
9223         printf("%10s%8s %7s%8s%8s%8s %7s%8s%8s\n", "quota_id",
9224                human_readable ? "used" : "kbytes", "quota", "limit", "grace",
9225                "files", "quota", "limit", "grace");
9226
9227         cur = 0;
9228         while (cur < buflen) {
9229                 if ((buflen - cur) < sizeof(struct if_quotactl)) {
9230                         rc = -EFAULT;
9231                         break;
9232                 }
9233
9234                 qctl_iter = buffer + cur;
9235                 qctl_iter->qc_cmd = LUSTRE_Q_GETQUOTA;
9236                 cur += sizeof(struct if_quotactl);
9237
9238                 /* Is no file created for this quota ID yet? */
9239                 if ((qctl_iter->qc_dqblk.dqb_valid & QIF_USAGE) != QIF_USAGE)
9240                         qctl_iter->qc_dqblk.dqb_valid |= QIF_USAGE;
9241
9242                 print_one_quota(mnt, NULL, qctl_iter, 0, quiet,
9243                                 human_readable, false, true, 0);
9244         }
9245
9246 out:
9247         if (buffer != NULL)
9248                 free(buffer);
9249
9250         if (rc)
9251                 fprintf(stderr, "get all quota failed %d\n", rc);
9252
9253         return rc;
9254 }
9255
9256 static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
9257                            int verbose, int quiet, bool human_readable,
9258                            bool show_default)
9259 {
9260         int rc;
9261
9262         rc = llapi_quotactl(mnt, qctl);
9263         if (rc < 0) {
9264                 switch (rc) {
9265                 case -ESRCH:
9266                         fprintf(stderr, "%s quotas are not enabled.\n",
9267                                 qtype_name(qctl->qc_type));
9268                         break;
9269                 case -EPERM:
9270                         fprintf(stderr, "Permission denied.\n");
9271                 case -ENODEV:
9272                 case -ENOENT:
9273                         /* We already got error message. */
9274                         break;
9275                 default:
9276                         fprintf(stderr, "Unexpected quotactl error: %s\n",
9277                                 strerror(-rc));
9278                 }
9279
9280                 return rc;
9281         }
9282
9283         return print_one_quota(mnt, name, qctl, verbose, quiet, human_readable,
9284                                show_default, false, rc);
9285 }
9286
9287 static int lfs_project(int argc, char **argv)
9288 {
9289         int ret = 0, err = 0, c, i;
9290         struct project_handle_control phc = { 0 };
9291         enum lfs_project_ops_t op;
9292
9293         phc.newline = true;
9294         phc.assign_projid = false;
9295         /* default action */
9296         op = LFS_PROJECT_LIST;
9297
9298         while ((c = getopt(argc, argv, "p:cCsdkr0")) != -1) {
9299                 switch (c) {
9300                 case 'c':
9301                         if (op != LFS_PROJECT_LIST) {
9302                                 fprintf(stderr,
9303                                         "%s: cannot specify '-c' '-C' '-s' together\n",
9304                                         progname);
9305                                 return CMD_HELP;
9306                         }
9307
9308                         op = LFS_PROJECT_CHECK;
9309                         break;
9310                 case 'C':
9311                         if (op != LFS_PROJECT_LIST) {
9312                                 fprintf(stderr,
9313                                         "%s: cannot specify '-c' '-C' '-s' together\n",
9314                                         progname);
9315                                 return CMD_HELP;
9316                         }
9317
9318                         op = LFS_PROJECT_CLEAR;
9319                         break;
9320                 case 's':
9321                         if (op != LFS_PROJECT_LIST) {
9322                                 fprintf(stderr,
9323                                         "%s: cannot specify '-c' '-C' '-s' together\n",
9324                                         progname);
9325                                 return CMD_HELP;
9326                         }
9327
9328                         phc.set_inherit = true;
9329                         op = LFS_PROJECT_SET;
9330                         break;
9331                 case 'd':
9332                         phc.dironly = true;
9333                         break;
9334                 case 'k':
9335                         phc.keep_projid = true;
9336                         break;
9337                 case 'r':
9338                         phc.recursive = true;
9339                         break;
9340                 case 'p':
9341                         if (str2quotaid(&phc.projid, optarg)) {
9342                                 fprintf(stderr,
9343                                         "Invalid project ID: %s\n",
9344                                         optarg);
9345                                 return CMD_HELP;
9346                         }
9347
9348                         phc.assign_projid = true;
9349
9350                         break;
9351                 case '0':
9352                         phc.newline = false;
9353                         break;
9354                 default:
9355                         fprintf(stderr, "%s: invalid option '%c'\n",
9356                                 progname, optopt);
9357                         return CMD_HELP;
9358                 }
9359         }
9360
9361         if (phc.assign_projid && op == LFS_PROJECT_LIST) {
9362                 op = LFS_PROJECT_SET;
9363                 phc.set_projid = true;
9364         } else if (phc.assign_projid && op == LFS_PROJECT_SET) {
9365                 phc.set_projid = true;
9366         }
9367
9368         switch (op) {
9369         case LFS_PROJECT_CHECK:
9370                 if (phc.keep_projid) {
9371                         fprintf(stderr,
9372                                 "%s: '-k' is useless together with '-c'\n",
9373                                 progname);
9374                         return CMD_HELP;
9375                 }
9376                 break;
9377         case LFS_PROJECT_CLEAR:
9378                 if (!phc.newline) {
9379                         fprintf(stderr,
9380                                 "%s: '-0' is useless together with '-C'\n",
9381                                 progname);
9382                         return CMD_HELP;
9383                 }
9384                 if (phc.assign_projid) {
9385                         fprintf(stderr,
9386                                 "%s: '-p' is useless together with '-C'\n",
9387                                 progname);
9388                         return CMD_HELP;
9389                 }
9390                 break;
9391         case LFS_PROJECT_SET:
9392                 if (!phc.newline) {
9393                         fprintf(stderr,
9394                                 "%s: '-0' is useless together with '-s'\n",
9395                                 progname);
9396                         return CMD_HELP;
9397                 }
9398                 if (phc.keep_projid) {
9399                         fprintf(stderr,
9400                                 "%s: '-k' is useless together with '-s'\n",
9401                                 progname);
9402                         return CMD_HELP;
9403                 }
9404                 break;
9405         default:
9406                 if (!phc.newline) {
9407                         fprintf(stderr,
9408                                 "%s: '-0' is useless for list operations\n",
9409                                 progname);
9410                         return CMD_HELP;
9411                 }
9412                 break;
9413         }
9414
9415         argv += optind;
9416         argc -= optind;
9417         if (argc == 0) {
9418                 fprintf(stderr, "%s: missing file or directory target(s)\n",
9419                         progname);
9420                 return CMD_HELP;
9421         }
9422
9423         for (i = 0; i < argc; i++) {
9424                 switch (op) {
9425                 case LFS_PROJECT_CHECK:
9426                         err = lfs_project_check(argv[i], &phc);
9427                         break;
9428                 case LFS_PROJECT_LIST:
9429                         err = lfs_project_list(argv[i], &phc);
9430                         break;
9431                 case LFS_PROJECT_CLEAR:
9432                         err = lfs_project_clear(argv[i], &phc);
9433                         break;
9434                 case LFS_PROJECT_SET:
9435                         err = lfs_project_set(argv[i], &phc);
9436                         break;
9437                 default:
9438                         break;
9439                 }
9440                 if (err && !ret)
9441                         ret = err;
9442         }
9443
9444         return ret;
9445 }
9446
9447 static int lfs_quota(int argc, char **argv)
9448 {
9449         int c;
9450         char *mnt, *name = NULL;
9451         struct if_quotactl *qctl;
9452         char *obd_uuid, *endp;
9453         int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
9454         __u32 valid = QC_GENERAL;
9455         long idx = 0;
9456         __u32 start_qid = 0, end_qid = 0;
9457         bool human_readable = false;
9458         bool show_default = false;
9459         int qtype;
9460         bool show_pools = false;
9461         struct option long_opts[] = {
9462         { .val = 'a',   .name = "all",          .has_arg = required_argument },
9463         { .val = 'e',   .name = "end-qid",      .has_arg = required_argument },
9464         { .val = 'g',   .name = "group",        .has_arg = required_argument },
9465         { .val = 'G',   .name = "default-grp",  .has_arg = no_argument },
9466         { .val = 'h',   .name = "human-readable", .has_arg = no_argument },
9467         /* It is unfortunate that '-i' was used for mdt-index, and '-I' for
9468          * ost-index, because '-i' is used for ost-index everywhere else.
9469          * These options have been this way since ancient days, but I suspect
9470          * that they are not often used. Prefer --ost and --mdt instead.
9471          */
9472         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
9473         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
9474         { .val = 'o',   .name = "ost-index",    .has_arg = required_argument },
9475         { .val = 'o',   .name = "ost",          .has_arg = required_argument },
9476         { .val = LFS_POOL_OPT, .name = "pool",  .has_arg = optional_argument },
9477         { .val = 'p',   .name = "projid",       .has_arg = required_argument },
9478         { .val = 'P',   .name = "default-prj",  .has_arg = no_argument },
9479         { .val = 'q',   .name = "quiet",        .has_arg = no_argument },
9480         { .val = 's',   .name = "start-qid",    .has_arg = required_argument },
9481         { .val = 't',   .name = "times",        .has_arg = no_argument },
9482         { .val = 'u',   .name = "user",         .has_arg = required_argument },
9483         { .val = 'U',   .name = "default-usr",  .has_arg = required_argument },
9484         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
9485         { .name = NULL } };
9486         char **poollist = NULL;
9487         char *buf = NULL;
9488         int poolcount, i;
9489
9490         qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1);
9491         if (!qctl)
9492                 return -ENOMEM;
9493
9494         qctl->qc_cmd = LUSTRE_Q_GETQUOTA;
9495         qctl->qc_type = ALLQUOTA;
9496         obd_uuid = (char *)qctl->obd_uuid.uuid;
9497
9498         while ((c = getopt_long(argc, argv, "ae:gGhi:I:m:o:pPqs:tuUv",
9499                 long_opts, NULL)) != -1) {
9500                 switch (c) {
9501                 case 'a':
9502                         qctl->qc_cmd = LUSTRE_Q_ITERQUOTA;
9503                         break;
9504                 case 'e':
9505                         if (optarg == NULL || *optarg == '\0') {
9506                                 fprintf(stderr,
9507                                         "%s quota: invalid start quota ID\n",
9508                                 progname);
9509                                 rc = CMD_HELP;
9510                                 goto out;
9511                         }
9512                         end_qid = strtoul(optarg, NULL, 0);
9513                         break;
9514                 case 'G':
9515                         show_default = true;
9516                         /* fallthrough */
9517                 case 'g':
9518                         qtype = GRPQUOTA;
9519                         goto quota_type;
9520                 case 'h':
9521                         human_readable = true;
9522                         break;
9523 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 22, 53, 0)
9524                 case 'i':
9525                         fprintf(stderr,
9526                                 "'-i' deprecated, use '--ost' or '--mdt'\n");
9527                         /* fallthrough */
9528 #endif
9529                 case 'm':
9530                         errno = 0;
9531                         idx = strtol(optarg, &endp, 0);
9532                         if (errno != 0 || idx > LOV_V1_INSANE_STRIPE_COUNT ||
9533                             idx < 0 || *endp != '\0') {
9534                                 fprintf(stderr,
9535                                         "%s quota: invalid MDT index '%s'\n",
9536                                         progname, optarg);
9537                                 rc = CMD_HELP;
9538                                 goto out;
9539                         }
9540                         valid = qctl->qc_valid = QC_MDTIDX;
9541                         qctl->qc_idx = idx;
9542                         break;
9543 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 22, 53, 0)
9544                 case 'I':
9545                         fprintf(stderr, "'-I' deprecated, use '--ost'\n");
9546                         /* fallthrough */
9547 #endif
9548                 case 'o':
9549                         errno = 0;
9550                         idx = strtol(optarg, &endp, 0);
9551                         /* simple digit, treat it as a numerical OST index */
9552                         if (*endp == '\0') {
9553                                 if (idx > LOV_V1_INSANE_STRIPE_COUNT ||
9554                                     idx < 0) {
9555                                         fprintf(stderr,
9556                                                 "%s quota: invalid OST index '%s'\n",
9557                                                 progname, optarg);
9558                                         rc = CMD_HELP;
9559                                         goto out;
9560                                 }
9561                                 valid = qctl->qc_valid = QC_OSTIDX;
9562                                 qctl->qc_idx = idx;
9563                                 break;
9564                         }
9565
9566                         /* need to also handle a UUID for compatibility */
9567                         valid = qctl->qc_valid = QC_UUID;
9568                         snprintf(obd_uuid, sizeof(*obd_uuid), "%s", optarg);
9569                         break;
9570                 case 'P':
9571                         show_default = true;
9572                         /* fallthrough */
9573                 case 'p':
9574                         qtype = PRJQUOTA;
9575                         goto quota_type;
9576                 case LFS_POOL_OPT:
9577                         if ((!optarg) && (argv[optind] != NULL) &&
9578                                 (argv[optind][0] != '-') &&
9579                                 (argv[optind][0] != '/')) {
9580                                 optarg = argv[optind++];
9581                                 if (lfs_verify_poolarg(optarg)) {
9582                                         rc = -EINVAL;
9583                                         goto out;
9584                                 }
9585                                 strncpy(qctl->qc_poolname, optarg,
9586                                         LOV_MAXPOOLNAME);
9587                                 if (qctl->qc_cmd == LUSTRE_Q_GETINFO)
9588                                         qctl->qc_cmd = LUSTRE_Q_GETINFOPOOL;
9589                                 else
9590                                         qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
9591                                 break;
9592                         }
9593
9594                         /* optarg is NULL */
9595                         show_pools = true;
9596                         qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
9597                         break;
9598                 case 'q':
9599                         quiet = 1;
9600                         break;
9601                 case 's':
9602                         if (optarg == NULL || *optarg == '\0') {
9603                                 fprintf(stderr,
9604                                         "%s quota: invalid start quota ID\n",
9605                                 progname);
9606                                 rc = CMD_HELP;
9607                                 goto out;
9608                         }
9609                         start_qid = strtoul(optarg, NULL, 0);
9610                         break;
9611                 case 't':
9612                         qctl->qc_cmd = LUSTRE_Q_GETINFO;
9613                         break;
9614                 case 'U':
9615                         show_default = true;
9616                         /* fallthrough */
9617                 case 'u':
9618                         qtype = USRQUOTA;
9619 quota_type:
9620                         if (qctl->qc_type != ALLQUOTA) {
9621                                 fprintf(stderr,
9622                                         "%s quota: only one of -u, -g, or -p may be specified\n",
9623                                         progname);
9624                                 rc = CMD_HELP;
9625                                 goto out;
9626                         }
9627                         qctl->qc_type = qtype;
9628                         break;
9629                 case 'v':
9630                         verbose = 1;
9631                         break;
9632                 default:
9633                         fprintf(stderr, "%s quota: unrecognized option '%s'\n",
9634                                 progname, argv[optind - 1]);
9635                         rc = CMD_HELP;
9636                         goto out;
9637                 }
9638         }
9639
9640         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
9641         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
9642              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
9643              qctl->qc_type == ALLQUOTA &&
9644              optind == argc - 1 && !show_default) {
9645                 qctl->qc_idx = idx;
9646
9647                 for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) {
9648                         qctl->qc_type = qtype;
9649                         qctl->qc_valid = valid;
9650                         if (qtype == USRQUOTA) {
9651                                 qctl->qc_id = geteuid();
9652                                 rc = uid2name(&name, qctl->qc_id);
9653                         } else {
9654                                 qctl->qc_id = getegid();
9655                                 rc = gid2name(&name, qctl->qc_id);
9656                                 memset(&qctl->qc_dqblk, 0,
9657                                        sizeof(qctl->qc_dqblk));
9658                         }
9659                         if (rc)
9660                                 name = "<unknown>";
9661                         mnt = argv[optind];
9662                         rc1 = get_print_quota(mnt, name, qctl, verbose, quiet,
9663                                               human_readable, show_default);
9664                         if (rc1 && !rc)
9665                                 rc = rc1;
9666                 }
9667                 goto out;
9668         /* lfs quota -u username /path/to/lustre/mount */
9669         } else if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
9670                    qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
9671                 /* options should be followed by u/g-name and mntpoint */
9672                 if ((!show_default && optind + 2 != argc) ||
9673                     (show_default && optind + 1 != argc) ||
9674                     qctl->qc_type == ALLQUOTA) {
9675                         fprintf(stderr,
9676                                 "%s quota: name and mount point must be specified\n",
9677                                 progname);
9678                         rc = CMD_HELP;
9679                         goto out;
9680                 }
9681
9682                 if (!show_default) {
9683                         name = argv[optind++];
9684                         switch (qctl->qc_type) {
9685                         case USRQUOTA:
9686                                 rc = name2uid(&qctl->qc_id, name);
9687                                 break;
9688                         case GRPQUOTA:
9689                                 rc = name2gid(&qctl->qc_id, name);
9690                                 break;
9691                         case PRJQUOTA:
9692                                 rc = name2projid(&qctl->qc_id, name);
9693                                 break;
9694                         default:
9695                                 rc = -ENOTSUP;
9696                                 break;
9697                         }
9698                 } else {
9699                         qctl->qc_valid = QC_GENERAL;
9700                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ?
9701                                         LUSTRE_Q_GETDEFAULT_POOL :
9702                                         LUSTRE_Q_GETDEFAULT;
9703                         qctl->qc_id = 0;
9704                 }
9705
9706                 if (rc) {
9707                         if (str2quotaid(&qctl->qc_id, name)) {
9708                                 fprintf(stderr, "%s quota: invalid id '%s'\n",
9709                                         progname, name);
9710                                 rc = CMD_HELP;
9711                                 goto out;
9712                         }
9713                 }
9714         } else if (qctl->qc_cmd == LUSTRE_Q_ITERQUOTA) {
9715                 if (optind + 1 != argc) {
9716                         fprintf(stderr,
9717                                 "%s quota: mount point must be specified\n",
9718                                 progname);
9719                         rc = CMD_HELP;
9720                         goto out;
9721                 }
9722
9723                 if (qctl->qc_type == ALLQUOTA) {
9724                         fprintf(stderr, "%s quota: no quota type to iterate\n",
9725                                 progname);
9726                         rc = CMD_HELP;
9727                         goto out;
9728                 }
9729
9730                 if (end_qid != 0 && start_qid > end_qid) {
9731                         fprintf(stderr,
9732                                 "%s quota: end qid is smaller than start qid\n",
9733                                 progname);
9734                         rc = CMD_HELP;
9735                         goto out;
9736                 }
9737
9738                 qctl->qc_allquota_qid_start = start_qid;
9739                 qctl->qc_allquota_qid_end = end_qid;
9740                 rc = iter_all_quota(argv[optind], qctl, quiet, human_readable);
9741                 goto out;
9742         } else if (optind + 1 != argc || qctl->qc_type == ALLQUOTA) {
9743                 fprintf(stderr, "%s quota: missing quota info argument(s)\n",
9744                         progname);
9745                 rc = CMD_HELP;
9746                 goto out;
9747         }
9748
9749         mnt = argv[optind];
9750         if (show_pools) {
9751                 char *p;
9752
9753                 i = 0;
9754                 rc = llapi_get_poolbuf(mnt, &buf, &poollist, &poolcount);
9755                 if (rc)
9756                         goto out;
9757
9758                 for (i = 0; i < poolcount; i++) {
9759                         p = memchr(poollist[i], '.', MAXNAMLEN);
9760                         if (!p) {
9761                                 fprintf(stderr, "bad string format %.*s\n",
9762                                         MAXNAMLEN, poollist[i]);
9763                                 rc = -EINVAL;
9764                                 goto out;
9765                         }
9766                         p++;
9767                         printf("Quotas for pool: %s\n", p);
9768                         strncpy(qctl->qc_poolname, p, LOV_MAXPOOLNAME);
9769                         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
9770                                              human_readable, show_default);
9771                         if (rc)
9772                                 break;
9773                 }
9774                 goto out;
9775         }
9776
9777         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
9778                              human_readable, show_default);
9779 out:
9780         free(buf);
9781         free(qctl);
9782         return rc;
9783 }
9784 #endif /* HAVE_SYS_QUOTA_H! */
9785
9786 static int flushctx_ioctl(char *mp)
9787 {
9788         int fd, rc;
9789
9790         fd = open(mp, O_RDONLY);
9791         if (fd == -1) {
9792                 fprintf(stderr, "flushctx: error open %s: %s\n",
9793                         mp, strerror(errno));
9794                 return -1;
9795         }
9796
9797         rc = ioctl(fd, LL_IOC_FLUSHCTX);
9798         if (rc == -1)
9799                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
9800                         mp, strerror(errno));
9801
9802         close(fd);
9803         return rc;
9804 }
9805
9806 static int lfs_flushctx(int argc, char **argv)
9807 {
9808         int kdestroy = 0, reap = 0, c;
9809         char **mnts = NULL, **mnt_ptr;
9810         int mnt_num = 1, index = 0, rc = 0, rc2;
9811         extern char **environ;
9812
9813         while ((c = getopt(argc, argv, "kr")) != -1) {
9814                 switch (c) {
9815                 case 'k':
9816                         kdestroy = 1;
9817                         break;
9818                 case 'r':
9819                         reap = 1;
9820                         break;
9821                 default:
9822                         fprintf(stderr,
9823                                 "error: %s: option '-%c' unrecognized\n",
9824                                 argv[0], c);
9825                         return CMD_HELP;
9826                 }
9827         }
9828
9829         if (optind >= argc) {
9830                 /* flush for all lustre mount points */
9831 again:
9832                 mnt_ptr = realloc(mnts, mnt_num * sizeof(char *));
9833                 if (!mnt_ptr) {
9834                         mnt_num--;
9835                         rc = -ENOMEM;
9836                         goto reap;
9837                 }
9838                 mnts = mnt_ptr;
9839                 mnts[mnt_num - 1] = (char *)calloc(PATH_MAX + 1, sizeof(char));
9840                 if (!mnts[mnt_num - 1]) {
9841                         rc = -ENOMEM;
9842                         goto reap;
9843                 }
9844 next:
9845                 if (!llapi_search_mounts(NULL, index++,
9846                                          mnts[mnt_num - 1], NULL)) {
9847
9848                         if (*mnts[mnt_num - 1] == '\0')
9849                                 goto next;
9850                         mnt_num++;
9851                         goto again;
9852                 } else {
9853                         *mnts[mnt_num - 1] = '\0';
9854                 }
9855
9856                 mnt_ptr = mnts;
9857                 index = 0;
9858         } else {
9859                 /* flush for mounts as specified on command line */
9860                 mnt_ptr = argv + optind;
9861                 mnt_num = argc - optind;
9862         }
9863
9864         for (index = 0; index < mnt_num; index++) {
9865                 /* Check if we have a mount point */
9866                 if (*mnt_ptr[index] == '\0')
9867                         continue;
9868
9869                 rc2 = flushctx_ioctl(mnt_ptr[index]);
9870                 if (rc2) {
9871                         rc2 = -errno;
9872                         fprintf(stderr,
9873                                 "error flushing contexts on mount point %s: %s\n",
9874                                 mnt_ptr[index], strerror(errno));
9875                         rc = rc ? rc : rc2;
9876                 }
9877         }
9878
9879 reap:
9880         if (reap) {
9881                 static char *args[] = { "keyctl", "reap", NULL };
9882
9883                 /* use callvpe to bypass the shell */
9884                 rc2 = callvpe("keyctl", args, environ);
9885                 if (rc2) {
9886                         rc2 = WEXITSTATUS(rc2);
9887                         fprintf(stderr, "error reaping keyring: %d\n", rc2);
9888                 }
9889         }
9890
9891         if (kdestroy) {
9892                 static char *args[] = { "kdestroy", NULL };
9893
9894                 /* use callvpe to bypass the shell */
9895                 rc2 = callvpe("kdestroy", args, environ);
9896                 if (rc2) {
9897                         rc2 = WEXITSTATUS(rc2);
9898                         fprintf(stderr, "error destroying tickets: %d\n", rc2);
9899                 }
9900         }
9901
9902         if (mnts) {
9903                 for (index = 0; index < mnt_num; index++)
9904                         free(mnts[index]);
9905                 free(mnts);
9906         }
9907         return rc;
9908 }
9909
9910 static int lfs_changelog(int argc, char **argv)
9911 {
9912         void *changelog_priv;
9913         struct changelog_rec *rec;
9914         long long startrec = 0, endrec = 0;
9915         char *mdd;
9916         struct option long_opts[] = {
9917                 { .val = 'f', .name = "follow", .has_arg = no_argument },
9918                 { .name = NULL } };
9919         char short_opts[] = "f";
9920         int rc, follow = 0;
9921
9922         while ((rc = getopt_long(argc, argv, short_opts,
9923                 long_opts, NULL)) != -1) {
9924                 switch (rc) {
9925                 case 'f':
9926                         follow++;
9927                         break;
9928                 default:
9929                         fprintf(stderr,
9930                                 "%s changelog: unrecognized option '%s'\n",
9931                                 progname, argv[optind - 1]);
9932                         return CMD_HELP;
9933                 }
9934         }
9935         if (optind >= argc) {
9936                 fprintf(stderr, "%s changelog: mdtname must be specified\n",
9937                         progname);
9938                 return CMD_HELP;
9939         }
9940
9941         mdd = argv[optind++];
9942         if (argc > optind) {
9943                 errno = 0;
9944                 startrec = strtoll(argv[optind++], NULL, 10);
9945                 if (errno != 0 || startrec < 0) {
9946                         fprintf(stderr,
9947                                 "%s changelog: bad startrec\n",
9948                                 progname);
9949                         return CMD_HELP;
9950                 }
9951         }
9952
9953         if (argc > optind) {
9954                 errno = 0;
9955                 endrec = strtoll(argv[optind++], NULL, 10);
9956                 if (errno != 0 || endrec < 0) {
9957                         fprintf(stderr,
9958                                 "%s changelog: bad endrec\n",
9959                                 progname);
9960                         return CMD_HELP;
9961                 }
9962         }
9963
9964         rc = llapi_changelog_start(&changelog_priv,
9965                                    CHANGELOG_FLAG_BLOCK |
9966                                    CHANGELOG_FLAG_JOBID |
9967                                    CHANGELOG_FLAG_EXTRA_FLAGS |
9968                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
9969                                    mdd, startrec);
9970         if (rc < 0) {
9971                 fprintf(stderr, "%s changelog: cannot start changelog: %s\n",
9972                         progname, strerror(errno = -rc));
9973                 return rc;
9974         }
9975
9976         rc = llapi_changelog_set_xflags(changelog_priv,
9977                                         CHANGELOG_EXTRA_FLAG_UIDGID |
9978                                         CHANGELOG_EXTRA_FLAG_NID |
9979                                         CHANGELOG_EXTRA_FLAG_OMODE |
9980                                         CHANGELOG_EXTRA_FLAG_XATTR);
9981         if (rc < 0) {
9982                 fprintf(stderr,
9983                         "%s changelog: cannot set xflags for changelog: %s\n",
9984                         progname, strerror(errno = -rc));
9985                 return rc;
9986         }
9987
9988         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
9989                 time_t secs;
9990                 struct tm ts;
9991
9992                 if (endrec && rec->cr_index > endrec) {
9993                         llapi_changelog_free(&rec);
9994                         break;
9995                 }
9996                 if (rec->cr_index < startrec) {
9997                         llapi_changelog_free(&rec);
9998                         continue;
9999                 }
10000
10001                 secs = rec->cr_time >> 30;
10002                 gmtime_r(&secs, &ts);
10003                 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
10004                        "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
10005                        changelog_type2str(rec->cr_type),
10006                        ts.tm_hour, ts.tm_min, ts.tm_sec,
10007                        (int)(rec->cr_time & ((1 << 30) - 1)),
10008                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
10009                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
10010
10011                 if (rec->cr_flags & CLF_JOBID) {
10012                         struct changelog_ext_jobid *jid =
10013                                 changelog_rec_jobid(rec);
10014
10015                         if (jid->cr_jobid[0] != '\0')
10016                                 printf(" j=%s", jid->cr_jobid);
10017                 }
10018
10019                 if (rec->cr_flags & CLF_EXTRA_FLAGS) {
10020                         struct changelog_ext_extra_flags *ef =
10021                                 changelog_rec_extra_flags(rec);
10022
10023                         printf(" ef=0x%llx",
10024                                (unsigned long long)ef->cr_extra_flags);
10025
10026                         if (ef->cr_extra_flags & CLFE_UIDGID) {
10027                                 struct changelog_ext_uidgid *uidgid =
10028                                         changelog_rec_uidgid(rec);
10029
10030                                 printf(" u=%llu:%llu",
10031                                        (unsigned long long)uidgid->cr_uid,
10032                                        (unsigned long long)uidgid->cr_gid);
10033                         }
10034                         if (ef->cr_extra_flags & CLFE_NID) {
10035                                 struct changelog_ext_nid *nid =
10036                                         changelog_rec_nid(rec);
10037
10038                                 printf(" nid=%s",
10039                                        libcfs_nid2str(nid->cr_nid));
10040                         }
10041
10042                         if (ef->cr_extra_flags & CLFE_OPEN) {
10043                                 struct changelog_ext_openmode *omd =
10044                                         changelog_rec_openmode(rec);
10045                                 char mode[] = "---";
10046
10047                                 /* exec mode must be exclusive */
10048                                 if (omd->cr_openflags & MDS_FMODE_EXEC) {
10049                                         mode[2] = 'x';
10050                                 } else {
10051                                         if (omd->cr_openflags & MDS_FMODE_READ)
10052                                                 mode[0] = 'r';
10053                                         if (omd->cr_openflags &
10054                                             (MDS_FMODE_WRITE |
10055                                              MDS_OPEN_TRUNC |
10056                                              MDS_OPEN_APPEND))
10057                                                 mode[1] = 'w';
10058                                 }
10059
10060                                 if (strcmp(mode, "---") != 0)
10061                                         printf(" m=%s", mode);
10062                         }
10063
10064                         if (ef->cr_extra_flags & CLFE_XATTR) {
10065                                 struct changelog_ext_xattr *xattr =
10066                                         changelog_rec_xattr(rec);
10067
10068                                 if (xattr->cr_xattr[0] != '\0')
10069                                         printf(" x=%s", xattr->cr_xattr);
10070                         }
10071                 }
10072
10073                 if (!fid_is_zero(&rec->cr_pfid))
10074                         printf(" p="DFID, PFID(&rec->cr_pfid));
10075                 if (rec->cr_namelen)
10076                         printf(" %.*s", rec->cr_namelen,
10077                                changelog_rec_name(rec));
10078
10079                 if (rec->cr_flags & CLF_RENAME) {
10080                         struct changelog_ext_rename *rnm =
10081                                 changelog_rec_rename(rec);
10082
10083                         if (!fid_is_zero(&rnm->cr_sfid))
10084                                 printf(" s="DFID" sp="DFID" %.*s",
10085                                        PFID(&rnm->cr_sfid),
10086                                        PFID(&rnm->cr_spfid),
10087                                        (int)changelog_rec_snamelen(rec),
10088                                        changelog_rec_sname(rec));
10089                 }
10090                 printf("\n");
10091
10092                 llapi_changelog_free(&rec);
10093         }
10094
10095         llapi_changelog_fini(&changelog_priv);
10096
10097         if (rc < 0)
10098                 fprintf(stderr, "%s changelog: cannot access changelog: %s\n",
10099                         progname, strerror(errno = -rc));
10100
10101         return (rc == 1 ? 0 : rc);
10102 }
10103
10104 static int lfs_changelog_clear(int argc, char **argv)
10105 {
10106         long long endrec;
10107         int rc;
10108
10109         if (argc != 4)
10110                 return CMD_HELP;
10111
10112         errno = 0;
10113         endrec = strtoll(argv[3], NULL, 10);
10114         if (errno != 0 || endrec < 0) {
10115                 fprintf(stderr,
10116                         "%s: bad endrec '%s'\n",
10117                         argv[0], argv[3]);
10118                 return CMD_HELP;
10119         }
10120
10121         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
10122
10123         if (rc == -EINVAL)
10124                 fprintf(stderr, "%s: record out of range: %llu\n",
10125                         argv[0], endrec);
10126         else if (rc == -ENOENT)
10127                 fprintf(stderr, "%s: no changelog user: %s\n",
10128                         argv[0], argv[2]);
10129         else if (rc)
10130                 fprintf(stderr, "%s error: %s\n", argv[0],
10131                         strerror(-rc));
10132
10133         if (rc)
10134                 errno = -rc;
10135
10136         return rc;
10137 }
10138
10139 static void rstripc(char *str, int c)
10140 {
10141         char *end = str + strlen(str);
10142
10143         for (; str < end && end[-1] == c; --end)
10144                 end[-1] = '\0';
10145 }
10146
10147 /* Helper function to lfs_fid2path. To print out only the file names and
10148  * not the full path. Do not call OBD_IOC_FID2PATH for every file. Instead
10149  * read the trusted.link xattr and loop over all the records to get all the
10150  * file names.
10151  */
10152 static int lfs_fid2path_prn_name(char *mnt_dir, char *path_buf,
10153                                  bool print_linkno, bool print_fid, char *ptr,
10154                                  const char *fid_str, int linktmp)
10155 {
10156         char buf[65536]; /* BUFFER_SIZE 65536 */
10157         char full_path[PATH_MAX * 2 + 2];
10158         struct link_ea_header *leh;
10159         struct link_ea_entry *lee;
10160         ssize_t size;
10161         int reclen, i, rc = 0;
10162
10163         /* Generate full_path */
10164         snprintf(full_path, sizeof(full_path) - 1, "%s/%s", mnt_dir, path_buf);
10165
10166         size = getxattr(full_path, "trusted.link", buf, sizeof(buf));
10167         if (size < 0) {
10168                 fprintf(stderr, "%s: failed to read %s xattr: %s\n", path_buf,
10169                         "trusted.link", strerror(errno));
10170                 rc = -errno;
10171                 goto fail;
10172         }
10173
10174         leh = (struct link_ea_header *)buf;
10175
10176         if (leh->leh_magic == __swab32(LINK_EA_MAGIC))
10177                 leh->leh_reccount = __swab32(leh->leh_reccount);
10178
10179         lee = (struct link_ea_entry *)(leh + 1);
10180
10181         for (i = 0; i < leh->leh_reccount; i++) {
10182                 reclen = (lee->lee_reclen[0] << 8) | lee->lee_reclen[1];
10183
10184                 /* handle -n -l case */
10185                 if (print_linkno) {
10186                         ptr = strrchr(path_buf, '/');
10187                         if (!ptr)
10188                                 ptr = path_buf;
10189                         else
10190                                 ptr = ptr + 1;
10191
10192                         if (strcmp(ptr, lee->lee_name) == 0) {
10193                                 if (print_fid)
10194                                         printf("%s ", fid_str);
10195
10196                                 printf("%d ", linktmp);
10197                                 printf("%s\n", lee->lee_name);
10198                                 break;
10199                         }
10200                 } else {
10201                         if (print_fid)
10202                                 printf("%s ", fid_str);
10203                         printf("%s\n", lee->lee_name);
10204                 }
10205
10206                 /* Get next record */
10207                 lee = (struct link_ea_entry *)((char *)lee + reclen);
10208         }
10209 fail:
10210         return rc;
10211 }
10212
10213 static int lfs_fid2path(int argc, char **argv)
10214 {
10215         struct option long_opts[] = {
10216                 { .val = '0',   .name = "print0",       .has_arg = no_argument },
10217                 { .val = 'c',   .name = "cur",  .has_arg = no_argument },
10218                 { .val = 'c',   .name = "current",      .has_arg = no_argument },
10219                 { .val = 'c',   .name = "print-link",   .has_arg = no_argument },
10220                 { .val = 'f',   .name = "print-fid",    .has_arg = no_argument },
10221                 { .val = 'l',   .name = "link", .has_arg = required_argument },
10222                 { .val = 'n',   .name = "name", .has_arg = no_argument },
10223                 { .name = NULL } };
10224         char short_opts[] = "0cfl:pr:n";
10225         bool print_only_fname = false;
10226         bool print_linkno = false;
10227         bool print_link = false;
10228         bool print_fid = false;
10229         bool print_mnt_dir;
10230         char mnt_dir[PATH_MAX] = "";
10231         int mnt_fd = -1;
10232         char *path_or_fsname;
10233         long long recno = -1;
10234         int linkno = -1;
10235         char *endptr = NULL;
10236         char link_separator = '\n';
10237         int rc = 0;
10238         int c;
10239         int i;
10240
10241         while ((c = getopt_long(argc, argv, short_opts,long_opts, NULL)) !=
10242                 -1) {
10243                 switch (c) {
10244                 case '0':
10245                         link_separator = '\0';
10246                         break;
10247                 case 'c':
10248                         print_link = true;
10249                         break;
10250                 case 'f':
10251                         print_fid = true;
10252                         break;
10253                 case 'l':
10254                         errno = 0;
10255                         linkno = strtol(optarg, &endptr, 10);
10256                         if (errno != 0 || *endptr != '\0' || linkno < 0) {
10257                                 fprintf(stderr,
10258                                         "%s fid2path: invalid linkno '%s'\n",
10259                                         progname, optarg);
10260                                 return CMD_HELP;
10261                         }
10262                         print_linkno = true;
10263                         break;
10264                 case 'n':
10265                         /* Bypass the full parent path if true
10266                          * only print the final filename */
10267                         print_only_fname = true;
10268                         break;
10269                 case 'r':
10270                         /* recno is something to do with changelogs
10271                          * that was never implemented. We just pass it
10272                          * through for the MDT to ignore.
10273                          */
10274                         errno = 0;
10275                         recno = strtoll(optarg, &endptr, 10);
10276                         if (errno != 0 || *endptr != '\0' || recno < 0) {
10277                                 fprintf(stderr,
10278                                         "%s fid2path: invalid recno '%s'\n",
10279                                         progname, optarg);
10280                                 return CMD_HELP;
10281                         }
10282                         break;
10283                 default:
10284                         fprintf(stderr,
10285                                 "%s fid2path: unrecognized option '%s'\n",
10286                                 progname, argv[optind - 1]);
10287                         return CMD_HELP;
10288                 }
10289         }
10290
10291         if (argc - optind < 2) {
10292                 fprintf(stderr,
10293                         "Usage: %s fid2path FSNAME|ROOT FID...\n",
10294                         progname);
10295                 return CMD_HELP;
10296         }
10297
10298         path_or_fsname = argv[optind];
10299
10300         if (*path_or_fsname == '/') {
10301                 print_mnt_dir = true;
10302                 rc = llapi_search_mounts(path_or_fsname, 0, mnt_dir, NULL);
10303         } else {
10304                 print_mnt_dir = false;
10305                 rc = llapi_search_rootpath(mnt_dir, path_or_fsname);
10306         }
10307
10308         if (rc < 0) {
10309                 fprintf(stderr,
10310                         "%s fid2path: cannot resolve mount point for '%s': %s\n",
10311                         progname, path_or_fsname, strerror(-rc));
10312                 goto out;
10313         }
10314
10315         mnt_fd = open(mnt_dir, O_RDONLY | O_DIRECTORY);
10316         if (mnt_fd < 0) {
10317                 fprintf(stderr,
10318                         "%s fid2path: cannot open mount point for '%s': %s\n",
10319                         progname, path_or_fsname, strerror(-rc));
10320                 goto out;
10321         }
10322
10323         /* Strip trailing slashes from mnt_dir. */
10324         rstripc(mnt_dir + 1, '/');
10325
10326         for (i = optind + 1; i < argc; i++) {
10327                 const char *fid_str = argv[i];
10328                 struct lu_fid fid;
10329                 char *ptr = NULL;
10330                 int rc2;
10331
10332                 rc2 = llapi_fid_parse(fid_str, &fid, NULL);
10333                 if (rc2 < 0) {
10334                         fprintf(stderr,
10335                                 "%s fid2path: invalid FID '%s'\n",
10336                                 progname, fid_str);
10337                         if (rc == 0)
10338                                 rc = rc2;
10339
10340                         continue;
10341                 }
10342
10343                 int linktmp = (linkno >= 0) ? linkno : 0;
10344
10345                 while (1) {
10346                         int oldtmp = linktmp;
10347                         long long rectmp = recno;
10348                         char path_buf[PATH_MAX];
10349
10350                         rc2 = llapi_fid2path_at(mnt_fd, &fid, path_buf,
10351                                                 sizeof(path_buf), &rectmp,
10352                                                 &linktmp);
10353                         if (rc2 < 0) {
10354                                 fprintf(stderr,
10355                                         "%s fid2path: cannot find %s %s: %s\n",
10356                                         progname, path_or_fsname, fid_str,
10357                                         strerror(-rc2));
10358                                 if (rc == 0)
10359                                         rc = rc2;
10360                                 break;
10361                         }
10362
10363                         if (print_only_fname && !print_link) {
10364                                 /* '-n' is passed as option here.
10365                                  * For all other cases of -c fall back
10366                                  * to default(else) path as to get the link
10367                                  * count associated with the file name call
10368                                  * to OBD_IOC_FID2PATH is required
10369                                  */
10370                                 rc = lfs_fid2path_prn_name(mnt_dir,
10371                                                            path_buf,
10372                                                            print_linkno,
10373                                                            print_fid, ptr,
10374                                                            fid_str, linktmp);
10375                                 /* llapi_fid2path_at() is already called once
10376                                  * in this case. No need to call it again.
10377                                  * Break out as we have all the filenames.
10378                                  */
10379                                 break;
10380                         }
10381
10382                         if (print_fid)
10383                                 printf("%s ", fid_str);
10384
10385                         if (print_link)
10386                                 printf("%d ", linktmp);
10387
10388                         /* You may think this looks wrong or weird (and it is!)
10389                          * but we are actually trying to preserve the old quirky
10390                          * behaviors (enforced by our old quirky tests!) that
10391                          * make lfs so much fun to work on:
10392                          *
10393                          *   lustre 0x200000007:0x1:0x0 => "/"
10394                          *   /mnt/lustre 0x200000007:0x1:0x0 => "/mnt/lustre//"
10395                          *
10396                          * Note that llapi_fid2path() returns "" for the root
10397                          * FID. */
10398                         if (!print_only_fname) {
10399                                 printf("%s%s%s%c",
10400                                        print_mnt_dir ? mnt_dir : "",
10401                                        (print_mnt_dir || *path_buf == '\0') ?
10402                                        "/" : "", path_buf, link_separator);
10403                         } else {
10404                                 ptr = strrchr(path_buf, '/');
10405                                 if (!ptr)
10406                                         printf("%s\n", path_buf);
10407                                 else
10408                                         printf("%s\n", ptr + 1);
10409                         }
10410
10411                         if (linkno >= 0)
10412                                 /* specified linkno */
10413                                 break;
10414
10415                         if (oldtmp == linktmp)
10416                                 /* no more links */
10417                                 break;
10418                 }
10419         }
10420 out:
10421         if (!(mnt_fd < 0))
10422                 close(mnt_fd);
10423
10424         return rc;
10425 }
10426
10427 static int lfs_path2fid(int argc, char **argv)
10428 {
10429         struct option long_opts[] = {
10430                 { .val = 'p', .name = "parents", .has_arg = no_argument },
10431                 { .name = NULL } };
10432         char            **path;
10433         const char        short_opts[] = "p";
10434         const char       *sep = "";
10435         struct lu_fid     fid;
10436         int               rc = 0;
10437         bool              show_parents = false;
10438
10439         while ((rc = getopt_long(argc, argv, short_opts,
10440                                  long_opts, NULL)) != -1) {
10441                 switch (rc) {
10442                 case 'p':
10443                         show_parents = true;
10444                         break;
10445                 default:
10446                         fprintf(stderr,
10447                                 "%s path2fid: unrecognized option '%s'\n",
10448                                 progname, argv[optind - 1]);
10449                         return CMD_HELP;
10450                 }
10451         }
10452
10453         if (optind > argc - 1) {
10454                 fprintf(stderr, "%s path2fid: FILE... must be specified\n",
10455                         progname);
10456                 return CMD_HELP;
10457         } else if (optind < argc - 1) {
10458                 sep = ": ";
10459         }
10460
10461         rc = 0;
10462         for (path = argv + optind; optind < argc; path++, optind++) {
10463                 int err = 0;
10464
10465                 if (!show_parents) {
10466                         err = llapi_path2fid(*path, &fid);
10467                         if (!err)
10468                                 printf("%s%s"DFID"\n",
10469                                        *sep != '\0' ? *path : "", sep,
10470                                        PFID(&fid));
10471                 } else {
10472                         char            name[NAME_MAX + 1];
10473                         unsigned int    linkno = 0;
10474
10475                         while ((err = llapi_path2parent(*path, linkno, &fid,
10476                                                 name, sizeof(name))) == 0) {
10477                                 if (*sep != '\0' && linkno == 0)
10478                                         printf("%s%s", *path, sep);
10479
10480                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
10481                                        PFID(&fid), name);
10482                                 linkno++;
10483                         }
10484
10485                         /* err == -ENODATA is end-of-loop */
10486                         if (linkno > 0 && err == -ENODATA) {
10487                                 printf("\n");
10488                                 err = 0;
10489                         }
10490                 }
10491
10492                 if (err) {
10493                         fprintf(stderr,
10494                                 "%s path2fid: cannot get %sfid for '%s': %s\n",
10495                                 progname, show_parents ? "parent " : "", *path,
10496                                 strerror(-err));
10497                         if (rc == 0) {
10498                                 rc = err;
10499                                 errno = -err;
10500                         }
10501                 }
10502         }
10503
10504         return rc;
10505 }
10506
10507 #define MAX_ERRNO       4095
10508 #define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO)
10509
10510 static int lfs_rmfid_and_show_errors(int rootfd, struct fid_array *fa)
10511 {
10512         int rc, rc2, k;
10513
10514         rc = llapi_rmfid_at(rootfd, fa);
10515         if (rc < 0) {
10516                 fprintf(stderr, "%s rmfid: cannot remove FIDs: %s\n",
10517                         progname, strerror(-rc));
10518                 return rc;
10519         }
10520
10521         for (k = 0; k < fa->fa_nr; k++) {
10522                 rc2 = (__s32)fa->fa_fids[k].f_ver;
10523                 if (!IS_ERR_VALUE(rc2))
10524                         continue;
10525
10526                 if (rc == 0)
10527                         rc = rc2;
10528
10529                 fa->fa_fids[k].f_ver = 0;
10530                 fprintf(stderr, "%s rmfid: cannot remove "DFID": %s\n",
10531                         progname, PFID(&fa->fa_fids[k]), strerror(-rc2));
10532         }
10533
10534         return rc;
10535 }
10536
10537 static int lfs_rmfid(int argc, char **argv)
10538 {
10539         int rc = 0, rc2, rc3 = 0, nr;
10540         struct fid_array *fa;
10541         const char *device;
10542         char *fidstr;
10543         int rootfd;
10544
10545         /* Interactive mode: Adjust optind */
10546         if (!optind)
10547                 optind++;
10548
10549         device = argv[optind++];
10550
10551         if (optind > argc - 1) {
10552                 fprintf(stderr, "%s rmfid: missing dirname\n", progname);
10553                 return CMD_HELP;
10554         }
10555
10556         nr = argc - optind;
10557
10558         rc = llapi_root_path_open(device, &rootfd);
10559         if (rc < 0) {
10560                 fprintf(stderr,
10561                         "%s rmfid: error opening device/fsname '%s': %s\n",
10562                         progname, device, strerror(-rc));
10563                 return -rc;
10564         }
10565
10566         fa = malloc(offsetof(struct fid_array, fa_fids[nr + 1]));
10567         if (!fa) {
10568                 rc = -errno ?: -ENOMEM;
10569                 fprintf(stderr, "%s rmfid: error allocating %zd bytes: %s\n",
10570                         progname, offsetof(struct fid_array, fa_fids[nr + 1]),
10571                         strerror(-rc));
10572                 goto out_close;
10573         }
10574
10575         fa->fa_nr = 0;
10576         rc = 0;
10577         while (optind < argc) {
10578                 char *origfidstr;
10579                 int found;
10580
10581                 origfidstr = fidstr = argv[optind++];
10582                 while (*fidstr == '[')
10583                         fidstr++;
10584                 found = sscanf(fidstr, SFID, RFID(&fa->fa_fids[fa->fa_nr]));
10585                 if (found != 3) {
10586                         fprintf(stderr, "lfs rmfid: '%s': Wrong FID format\n",
10587                                 origfidstr);
10588                         if (!rc3)
10589                                 rc3 = -EINVAL; /* Invalid argument */
10590                         continue;
10591                 }
10592                 fa->fa_nr++;
10593                 if (fa->fa_nr == OBD_MAX_FIDS_IN_ARRAY) {
10594                         /* start another batch */
10595                         rc2 = lfs_rmfid_and_show_errors(rootfd, fa);
10596                         if (rc2 && !rc)
10597                                 rc = rc2;
10598                         if (rc3)
10599                                 rc = rc3;
10600                         fa->fa_nr = 0;
10601                 }
10602         }
10603         if (fa->fa_nr) {
10604                 rc2 = lfs_rmfid_and_show_errors(rootfd, fa);
10605                 if (rc2 && !rc)
10606                         rc = rc2;
10607                 if (rc3)
10608                         rc = rc3;
10609         }
10610
10611         if (fa) {
10612                 free(fa);
10613                 fa = NULL;
10614         }
10615
10616 out_close:
10617         close(rootfd);
10618         return rc;
10619 }
10620
10621 static int lfs_data_version(int argc, char **argv)
10622 {
10623         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
10624         __u64 data_version;
10625         char *path;
10626         int fd;
10627         int rc;
10628         int c;
10629
10630         if (argc < 2) {
10631                 fprintf(stderr, "%s: FILE must be specified\n",
10632                         progname);
10633                 return CMD_HELP;
10634         }
10635
10636         while ((c = getopt(argc, argv, "hnrw")) != -1) {
10637                 switch (c) {
10638                 case 'n':
10639                         data_version_flags = 0;
10640                         break;
10641                 case 'r':
10642                         data_version_flags |= LL_DV_RD_FLUSH;
10643                         break;
10644                 case 'w':
10645                         data_version_flags |= LL_DV_WR_FLUSH;
10646                         break;
10647                 default:
10648                         fprintf(stderr,
10649                                 "%s data_version: unrecognized option '%s'\n",
10650                                 progname, argv[optind - 1]);
10651                         fallthrough;
10652                 case 'h':
10653                         return CMD_HELP;
10654                 }
10655         }
10656         if (optind == argc) {
10657                 fprintf(stderr, "%s data_version: FILE must be specified\n",
10658                         progname);
10659                 return CMD_HELP;
10660         }
10661
10662         path = argv[optind];
10663         fd = open(path, O_RDONLY);
10664         if (fd < 0) {
10665                 rc = -errno;
10666                 fprintf(stderr, "%s data_version: cannot open file '%s': %s\n",
10667                         progname, path, strerror(-rc));
10668                 return rc;
10669         }
10670
10671         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
10672         if (rc < 0)
10673                 fprintf(stderr,
10674                         "%s data_version: cannot get version for '%s': %s\n",
10675                         progname, path, strerror(-rc));
10676         else
10677                 printf("%ju" "\n", (uintmax_t)data_version);
10678
10679         close(fd);
10680         return rc;
10681 }
10682
10683 static int lfs_hsm_state(int argc, char **argv)
10684 {
10685         int rc = 0;
10686         int i = 1;
10687         char *path;
10688         struct hsm_user_state hus;
10689
10690         if (argc < 2)
10691                 return CMD_HELP;
10692
10693         do {
10694                 int rc2;
10695                 path = argv[i];
10696
10697                 rc2 = llapi_hsm_state_get(path, &hus);
10698                 if (rc2) {
10699                         fprintf(stderr,
10700                                 "%s %s: get HSM state for '%s' failed: %s\n",
10701                                 progname, argv[0], path, strerror(-rc2));
10702                         if (!rc)
10703                                 rc = rc2;
10704                         continue;
10705                 }
10706
10707                 /* Display path name and status flags */
10708                 printf("%s: (0x%08x)", path, hus.hus_states);
10709
10710                 if (hus.hus_states & HS_RELEASED)
10711                         printf(" released");
10712                 if (hus.hus_states & HS_EXISTS)
10713                         printf(" exists");
10714                 if (hus.hus_states & HS_DIRTY)
10715                         printf(" dirty");
10716                 if (hus.hus_states & HS_ARCHIVED)
10717                         printf(" archived");
10718                 /* Display user-settable flags */
10719                 if (hus.hus_states & HS_NORELEASE)
10720                         printf(" never_release");
10721                 if (hus.hus_states & HS_NOARCHIVE)
10722                         printf(" never_archive");
10723                 if (hus.hus_states & HS_LOST)
10724                         printf(" lost_from_hsm");
10725
10726                 if (hus.hus_archive_id != 0)
10727                         printf(", archive_id:%d", hus.hus_archive_id);
10728                 printf("\n");
10729
10730         } while (++i < argc);
10731
10732         return rc;
10733 }
10734
10735 #define LFS_HSM_SET   0
10736 #define LFS_HSM_CLEAR 1
10737
10738 /**
10739  * Generic function to set or clear HSM flags.
10740  * Used by hsm_set and hsm_clear.
10741  *
10742  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
10743  */
10744 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
10745 {
10746         struct option long_opts[] = {
10747         { .val = 'A',   .name = "archived",     .has_arg = no_argument },
10748         { .val = 'a',   .name = "noarchive",    .has_arg = no_argument },
10749         { .val = 'd',   .name = "dirty",        .has_arg = no_argument },
10750         { .val = 'e',   .name = "exists",       .has_arg = no_argument },
10751         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10752         { .val = 'i',   .name = "archive-id",   .has_arg = required_argument },
10753         { .val = 'l',   .name = "lost",         .has_arg = no_argument },
10754         { .val = 'r',   .name = "norelease",    .has_arg = no_argument },
10755         { .name = NULL } };
10756         __u64 mask = 0;
10757         int c, rc = 0;
10758         char *path;
10759         __u32 archive_id = 0;
10760         char *end = NULL;
10761
10762         if (argc < 3)
10763                 return CMD_HELP;
10764
10765         while ((c = getopt_long(argc, argv, "aAdehi:lr",
10766                                 long_opts, NULL)) != -1) {
10767                 switch (c) {
10768                 case 'l':
10769                         mask |= HS_LOST;
10770                         break;
10771                 case 'a':
10772                         mask |= HS_NOARCHIVE;
10773                         break;
10774                 case 'A':
10775                         mask |= HS_ARCHIVED;
10776                         break;
10777                 case 'r':
10778                         mask |= HS_NORELEASE;
10779                         break;
10780                 case 'd':
10781                         mask |= HS_DIRTY;
10782                         break;
10783                 case 'e':
10784                         mask |= HS_EXISTS;
10785                         break;
10786                 case 'i':
10787                         errno = 0;
10788                         archive_id = strtol(optarg, &end, 10);
10789                         if (errno != 0 || *end != '\0' || archive_id < 0) {
10790                                 fprintf(stderr,
10791                                         "%s: invalid archive_id: '%s'\n",
10792                                         progname, end);
10793                                 return CMD_HELP;
10794                         }
10795                         break;
10796                 default:
10797                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10798                                 progname, argv[optind - 1]);
10799                         fallthrough;
10800                 case 'h':
10801                         return CMD_HELP;
10802                 }
10803         }
10804
10805         /* User should have specified a flag */
10806         if (mask == 0)
10807                 return CMD_HELP;
10808
10809         while (optind < argc) {
10810                 int rc2;
10811                 path = argv[optind];
10812
10813                 /* If mode == 0, this means we apply the mask. */
10814                 if (mode == LFS_HSM_SET)
10815                         rc2 = llapi_hsm_state_set(path, mask, 0, archive_id);
10816                 else
10817                         rc2 = llapi_hsm_state_set(path, 0, mask, 0);
10818
10819                 if (rc2) {
10820                         fprintf(stderr,
10821                                 "%s %s: change hsm flags for '%s' failed: %s\n",
10822                                 progname, argv[0], path, strerror(-rc2));
10823                         if (!rc)
10824                                 rc = rc2;
10825                 }
10826                 optind++;
10827         }
10828
10829         return rc;
10830 }
10831
10832 static int lfs_hsm_action(int argc, char **argv)
10833 {
10834         struct hsm_current_action hca;
10835         struct hsm_extent he;
10836         enum hsm_user_action hua;
10837         enum hsm_progress_states hps;
10838         int rc = 0;
10839         int i = 1;
10840         char *path;
10841
10842         if (argc < 2)
10843                 return CMD_HELP;
10844
10845         do {
10846                 int rc2;
10847                 path = argv[i];
10848
10849                 rc2 = llapi_hsm_current_action(path, &hca);
10850                 if (rc2) {
10851                         fprintf(stderr,
10852                                 "%s %s: get hsm action for '%s' failed: %s\n",
10853                                 progname, argv[0], path, strerror(-rc2));
10854
10855                         if (!rc)
10856                                 rc = rc2;
10857                         continue;
10858                 }
10859                 he = hca.hca_location;
10860                 hua = hca.hca_action;
10861                 hps = hca.hca_state;
10862
10863                 printf("%s: %s", path, hsm_user_action2name(hua));
10864
10865                 /* Skip file without action */
10866                 if (hca.hca_action == HUA_NONE) {
10867                         printf("\n");
10868                         continue;
10869                 }
10870
10871                 printf(" %s ", hsm_progress_state2name(hps));
10872
10873                 if ((hps == HPS_RUNNING) &&
10874                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
10875                         printf("(%llu bytes moved)\n",
10876                                (unsigned long long)he.length);
10877                 else if ((he.offset + he.length) == LUSTRE_EOF)
10878                         printf("(from %llu to EOF)\n",
10879                                (unsigned long long)he.offset);
10880                 else
10881                         printf("(from %llu to %llu)\n",
10882                                (unsigned long long)he.offset,
10883                                (unsigned long long)(he.offset + he.length));
10884
10885         } while (++i < argc);
10886
10887         return rc;
10888 }
10889
10890 static int lfs_hsm_set(int argc, char **argv)
10891 {
10892         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
10893 }
10894
10895 static int lfs_hsm_clear(int argc, char **argv)
10896 {
10897         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
10898 }
10899
10900 /**
10901  * Check file state and return its fid, to be used by lfs_hsm_request().
10902  *
10903  * \param[in]     file      Path to file to check
10904  * \param[in,out] fid       Pointer to allocated lu_fid struct.
10905  * \param[in,out] last_dev  Pointer to last device id used.
10906  *
10907  * \return 0 on success.
10908  */
10909 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
10910                                 dev_t *last_dev)
10911 {
10912         struct stat     st;
10913         int             rc;
10914
10915         rc = lstat(file, &st);
10916         if (rc) {
10917                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
10918                 return -errno;
10919         }
10920         /*
10921          * Checking for regular file as archiving as posix copytool
10922          * rejects archiving files other than regular files
10923          */
10924         if (!S_ISREG(st.st_mode)) {
10925                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
10926                 return CMD_HELP;
10927         }
10928         /* A request should be ... */
10929         if (*last_dev != st.st_dev && *last_dev != 0) {
10930                 fprintf(stderr,
10931                         "All files should be on the same filesystem: %s\n",
10932                         file);
10933                 return -EINVAL;
10934         }
10935         *last_dev = st.st_dev;
10936
10937         rc = llapi_path2fid(file, fid);
10938         if (rc) {
10939                 fprintf(stderr, "Cannot read FID of %s: %s\n",
10940                         file, strerror(-rc));
10941                 return rc;
10942         }
10943         return 0;
10944 }
10945
10946 /* Fill an HSM HUR item with a given file name.
10947  *
10948  * If mntpath is set, then the filename is actually a FID, and no
10949  * lookup on the filesystem will be performed.
10950  *
10951  * \param[in]  hur         the user request to fill
10952  * \param[in]  idx         index of the item inside the HUR to fill
10953  * \param[in]  mntpath     mountpoint of Lustre
10954  * \param[in]  fname       filename (if mtnpath is NULL)
10955  *                         or FID (if mntpath is set)
10956  * \param[in]  last_dev    pointer to last device id used
10957  *
10958  * \retval 0 on success
10959  * \retval CMD_HELP or a negative errno on error
10960  */
10961 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
10962                          const char *mntpath, const char *fname,
10963                          dev_t *last_dev)
10964 {
10965         struct hsm_user_item *hui = &hur->hur_user_item[idx];
10966         int rc;
10967
10968         hui->hui_extent.length = -1;
10969
10970         if (mntpath) {
10971                 rc = llapi_fid_parse(fname, &hui->hui_fid, NULL);
10972                 if (rc)
10973                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
10974                                 fname);
10975         } else {
10976                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
10977         }
10978
10979         if (rc == 0)
10980                 hur->hur_request.hr_itemcount++;
10981
10982         return rc;
10983 }
10984
10985 static int lfs_hsm_request(int argc, char **argv, int action)
10986 {
10987         struct option long_opts[] = {
10988         { .val = 'a',   .name = "archive",      .has_arg = required_argument },
10989         { .val = 'D',   .name = "data",         .has_arg = required_argument },
10990         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10991         { .val = 'l',   .name = "filelist",     .has_arg = required_argument },
10992         { .val = 'm',   .name = "mntpath",      .has_arg = required_argument },
10993         { .name = NULL } };
10994         dev_t last_dev = 0;
10995         struct hsm_user_request *hur, *oldhur;
10996         int c, i;
10997         size_t len;
10998         int nbfile;
10999         char *line = NULL;
11000         char *filelist = NULL;
11001         char fullpath[PATH_MAX];
11002         char *opaque = NULL;
11003         int opaque_len = 0;
11004         int archive_id = 0;
11005         FILE *fp;
11006         int nbfile_alloc = 0;
11007         char *some_file = NULL;
11008         char *mntpath = NULL;
11009         int rc;
11010
11011         if (argc < 2) {
11012                 rc = CMD_HELP;
11013                 goto out_cmd_help;
11014         }
11015
11016         while ((c = getopt_long(argc, argv, "a:D:hl:m:",
11017                                 long_opts, NULL)) != -1) {
11018                 switch (c) {
11019                 case 'l':
11020                         filelist = optarg;
11021                         break;
11022                 case 'D':
11023                         opaque = optarg;
11024                         break;
11025                 case 'a':
11026                         if (action != HUA_ARCHIVE &&
11027                             action != HUA_REMOVE) {
11028                                 fprintf(stderr,
11029                                         "error: -a is supported only when archiving or removing\n");
11030                                 rc = CMD_HELP;
11031                                 goto out_cmd_help;
11032                         }
11033                         archive_id = atoi(optarg);
11034                         break;
11035                 case 'm':
11036                         if (!some_file) {
11037                                 mntpath = optarg;
11038                                 some_file = strdup(optarg);
11039                         }
11040                         break;
11041                 default:
11042                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11043                                 progname, argv[optind - 1]);
11044                         fallthrough;
11045                 case 'h':
11046                         rc = CMD_HELP;
11047                         goto out_cmd_help;
11048                 }
11049         }
11050
11051         /* All remaining args are files, so we have at least nbfile */
11052         nbfile = argc - optind;
11053
11054         if ((nbfile == 0) && (!filelist)) {
11055                 rc = errno;
11056                 goto out_errno;
11057         }
11058
11059         if (opaque)
11060                 opaque_len = strlen(opaque);
11061
11062         /*
11063          * Alloc the request structure with enough place to store all files
11064          * from command line.
11065          */
11066         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
11067         if (!hur) {
11068                 fprintf(stderr, "Cannot create the request: %s\n",
11069                         strerror(errno));
11070                 rc = errno;
11071                 goto out_errno;
11072         }
11073         nbfile_alloc = nbfile;
11074
11075         hur->hur_request.hr_action = action;
11076         hur->hur_request.hr_archive_id = archive_id;
11077         hur->hur_request.hr_flags = 0;
11078
11079         /* All remaining args are files, add them */
11080         if (nbfile != 0 && some_file == NULL)
11081                 some_file = strdup(argv[optind]);
11082
11083         for (i = 0; i < nbfile; i++) {
11084                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
11085                                    &last_dev);
11086                 if (rc)
11087                         goto out_hur;
11088         }
11089
11090         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
11091
11092         /* If a filelist was specified, read the filelist from it. */
11093         if (filelist) {
11094                 fp = fopen(filelist, "r");
11095                 if (!fp) {
11096                         fprintf(stderr, "Cannot read the file list %s: %s\n",
11097                                 filelist, strerror(errno));
11098                         rc = -errno;
11099                         goto out_hur;
11100                 }
11101
11102                 while ((rc = getline(&line, &len, fp)) != -1) {
11103                         /*
11104                          * If allocated buffer was too small, get something
11105                          * larger
11106                          */
11107                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
11108                                 ssize_t size;
11109
11110                                 nbfile_alloc = nbfile_alloc * 2 + 1;
11111                                 oldhur = hur;
11112                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
11113                                                                    opaque_len);
11114                                 if (!hur) {
11115                                         fprintf(stderr,
11116                                                 "hsm: cannot allocate the request: %s\n",
11117                                                 strerror(errno));
11118                                         hur = oldhur;
11119                                         rc = -errno;
11120                                         fclose(fp);
11121                                         goto out_hur;
11122                                 }
11123                                 size = hur_len(oldhur);
11124                                 if (size < 0) {
11125                                         fprintf(stderr,
11126                                                 "hsm: cannot allocate %u files + %u bytes data\n",
11127                                                 oldhur->hur_request.hr_itemcount,
11128                                                 oldhur->hur_request.hr_data_len);
11129                                         free(hur);
11130                                         hur = oldhur;
11131                                         rc = -E2BIG;
11132                                         fclose(fp);
11133                                         goto out_hur;
11134                                 }
11135                                 memcpy(hur, oldhur, size);
11136                                 free(oldhur);
11137                         }
11138
11139                         /* Chop CR */
11140                         if (line[strlen(line) - 1] == '\n')
11141                                 line[strlen(line) - 1] = '\0';
11142
11143                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
11144                                            mntpath, line, &last_dev);
11145                         if (rc) {
11146                                 fclose(fp);
11147                                 goto out_hur;
11148                         }
11149
11150                         if (!some_file) {
11151                                 some_file = line;
11152                                 line = NULL;
11153                         }
11154                 }
11155
11156                 rc = fclose(fp);
11157                 free(line);
11158         }
11159
11160         /* If a --data was used, add it to the request */
11161         hur->hur_request.hr_data_len = opaque_len;
11162         if (opaque)
11163                 memcpy(hur_data(hur), opaque, opaque_len);
11164
11165         /* Send the HSM request */
11166         if (realpath(some_file, fullpath) == NULL) {
11167                 fprintf(stderr, "Could not find path '%s': %s\n",
11168                         some_file, strerror(errno));
11169         }
11170         rc = llapi_hsm_request(fullpath, hur);
11171         if (rc)
11172                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
11173                         some_file, strerror(-rc));
11174
11175 out_hur:
11176         free(hur);
11177 out_errno:
11178         free(some_file);
11179 out_cmd_help:
11180         return rc;
11181 }
11182
11183 static int lfs_hsm_archive(int argc, char **argv)
11184 {
11185         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
11186 }
11187
11188 static int lfs_hsm_restore(int argc, char **argv)
11189 {
11190         return lfs_hsm_request(argc, argv, HUA_RESTORE);
11191 }
11192
11193 static int lfs_hsm_release(int argc, char **argv)
11194 {
11195         return lfs_hsm_request(argc, argv, HUA_RELEASE);
11196 }
11197
11198 static int lfs_hsm_remove(int argc, char **argv)
11199 {
11200         return lfs_hsm_request(argc, argv, HUA_REMOVE);
11201 }
11202
11203 static int lfs_hsm_cancel(int argc, char **argv)
11204 {
11205         return lfs_hsm_request(argc, argv, HUA_CANCEL);
11206 }
11207
11208 static int lfs_swap_layouts(int argc, char **argv)
11209 {
11210         int noxtime = 0;
11211
11212         if (argc == 4 && !strcmp(argv[1], "-n"))
11213                 noxtime = 1;
11214         else if (argc != 3)
11215                 return CMD_HELP;
11216
11217         return llapi_swap_layouts(argv[1+noxtime], argv[2+noxtime],
11218                                   0, 0, noxtime ? 0 :
11219                                   (SWAP_LAYOUTS_KEEP_MTIME |
11220                                   SWAP_LAYOUTS_KEEP_ATIME));
11221 }
11222
11223 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
11224
11225 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
11226
11227 static int lfs_get_mode(const char *string)
11228 {
11229         enum lock_mode_user mode;
11230
11231         for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
11232                 if (lock_mode_names[mode] == NULL)
11233                         continue;
11234                 if (strcasecmp(string, lock_mode_names[mode]) == 0)
11235                         return mode;
11236         }
11237
11238         return -EINVAL;
11239 }
11240
11241 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
11242 {
11243         enum lu_ladvise_type advice;
11244
11245         for (advice = 0;
11246              advice < ARRAY_SIZE(ladvise_names); advice++) {
11247                 if (ladvise_names[advice] == NULL)
11248                         continue;
11249                 if (strcmp(string, ladvise_names[advice]) == 0)
11250                         return advice;
11251         }
11252
11253         return LU_LADVISE_INVALID;
11254 }
11255
11256 static int lfs_ladvise(int argc, char **argv)
11257 {
11258         struct option long_opts[] = {
11259         { .val = 'a',   .name = "advice",       .has_arg = required_argument },
11260         { .val = 'b',   .name = "background",   .has_arg = no_argument },
11261         { .val = 'e',   .name = "end",          .has_arg = required_argument },
11262         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11263         { .val = 'l',   .name = "length",       .has_arg = required_argument },
11264         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
11265         { .val = 's',   .name = "start",        .has_arg = required_argument },
11266         { .val = 'u',   .name = "unset",        .has_arg = no_argument },
11267         { .name = NULL } };
11268         struct llapi_lu_ladvise advice;
11269         enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
11270         unsigned long long start = 0;
11271         unsigned long long end = LUSTRE_EOF;
11272         unsigned long long length = 0;
11273         unsigned long long size_units;
11274         unsigned long long flags = 0;
11275         int c, fd, rc = 0;
11276         const char *path;
11277         int mode = 0;
11278
11279         optind = 0;
11280         while ((c = getopt_long(argc, argv, "a:be:hl:m:s:u",
11281                                 long_opts, NULL)) != -1) {
11282                 switch (c) {
11283                 case 'a':
11284                         advice_type = lfs_get_ladvice(optarg);
11285                         if (advice_type == LU_LADVISE_INVALID) {
11286                                 fprintf(stderr,
11287                                         "%s: invalid advice type '%s'\n",
11288                                         progname, optarg);
11289                                 fprintf(stderr, "Valid types:");
11290
11291                                 for (advice_type = 0;
11292                                      advice_type < ARRAY_SIZE(ladvise_names);
11293                                      advice_type++) {
11294                                         if (ladvise_names[advice_type] == NULL)
11295                                                 continue;
11296                                         fprintf(stderr, " %s",
11297                                                 ladvise_names[advice_type]);
11298                                 }
11299                                 fprintf(stderr, "\n");
11300
11301                                 return CMD_HELP;
11302                         }
11303                         break;
11304                 case 'b':
11305                         flags |= LF_ASYNC;
11306                         break;
11307                 case 'u':
11308                         flags |= LF_UNSET;
11309                         break;
11310                 case 'e':
11311                         size_units = 1;
11312                         rc = llapi_parse_size(optarg, &end,
11313                                               &size_units, 0);
11314                         if (rc) {
11315                                 fprintf(stderr, "%s: bad end offset '%s'\n",
11316                                         argv[0], optarg);
11317                                 return CMD_HELP;
11318                         }
11319                         break;
11320                 case 's':
11321                         size_units = 1;
11322                         rc = llapi_parse_size(optarg, &start,
11323                                               &size_units, 0);
11324                         if (rc) {
11325                                 fprintf(stderr,
11326                                         "%s: bad start offset '%s'\n",
11327                                         argv[0], optarg);
11328                                 return CMD_HELP;
11329                         }
11330                         break;
11331                 case 'l':
11332                         size_units = 1;
11333                         rc = llapi_parse_size(optarg, &length,
11334                                               &size_units, 0);
11335                         if (rc) {
11336                                 fprintf(stderr, "%s: bad length '%s'\n",
11337                                         argv[0], optarg);
11338                                 return CMD_HELP;
11339                         }
11340                         break;
11341                 case 'm':
11342                         mode = lfs_get_mode(optarg);
11343                         if (mode < 0) {
11344                                 fprintf(stderr,
11345                                         "%s: bad mode '%s', valid modes are READ or WRITE\n",
11346                                         argv[0], optarg);
11347                                 return CMD_HELP;
11348                         }
11349                         break;
11350                 default:
11351                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11352                                 progname, argv[optind - 1]);
11353                         fallthrough;
11354                 case 'h':
11355                         return CMD_HELP;
11356                 }
11357         }
11358
11359         if (advice_type == LU_LADVISE_INVALID) {
11360                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
11361                 fprintf(stderr, "Valid types:");
11362                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
11363                      advice_type++) {
11364                         if (ladvise_names[advice_type] == NULL)
11365                                 continue;
11366                         fprintf(stderr, " %s", ladvise_names[advice_type]);
11367                 }
11368                 fprintf(stderr, "\n");
11369                 return CMD_HELP;
11370         }
11371
11372         if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
11373                 fprintf(stderr,
11374                         "%s: Lock no expand advice is a per file descriptor advice, so when called from lfs, it does nothing.\n",
11375                         argv[0]);
11376                 return CMD_HELP;
11377         }
11378
11379         if (argc <= optind) {
11380                 fprintf(stderr, "%s: please give one or more file names\n",
11381                         argv[0]);
11382                 return CMD_HELP;
11383         }
11384
11385         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
11386                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
11387                         argv[0]);
11388                 return CMD_HELP;
11389         }
11390
11391         if (end == LUSTRE_EOF && length != 0)
11392                 end = start + length;
11393
11394         if (end <= start) {
11395                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
11396                         argv[0], start, end);
11397                 return CMD_HELP;
11398         }
11399
11400         if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
11401                 fprintf(stderr, "%s: mode is only valid with lockahead\n",
11402                         argv[0]);
11403                 return CMD_HELP;
11404         }
11405
11406         if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
11407                 fprintf(stderr, "%s: mode is required with lockahead\n",
11408                         argv[0]);
11409                 return CMD_HELP;
11410         }
11411
11412         while (optind < argc) {
11413                 int rc2;
11414
11415                 path = argv[optind++];
11416
11417                 fd = open(path, O_RDONLY);
11418                 if (fd < 0) {
11419                         rc2 = -errno;
11420                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
11421                                 argv[0], path, strerror(-rc2));
11422                         if (!rc)
11423                                 rc = rc2;
11424                         continue;
11425                 }
11426
11427                 advice.lla_start = start;
11428                 advice.lla_end = end;
11429                 advice.lla_advice = advice_type;
11430                 advice.lla_value1 = 0;
11431                 advice.lla_value2 = 0;
11432                 advice.lla_value3 = 0;
11433                 advice.lla_value4 = 0;
11434                 if (advice_type == LU_LADVISE_LOCKAHEAD) {
11435                         advice.lla_lockahead_mode = mode;
11436                         advice.lla_peradvice_flags = flags;
11437                 }
11438
11439                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
11440                 close(fd);
11441                 if (rc2 < 0) {
11442                         fprintf(stderr,
11443                                 "%s: cannot give advice '%s' to file '%s': %s\n",
11444                                 argv[0], ladvise_names[advice_type],
11445                                 path, strerror(errno));
11446
11447                         if (!rc)
11448                                 rc = rc2;
11449                         continue;
11450                 }
11451         }
11452
11453         return rc;
11454 }
11455
11456 static const char *const heat_names[] = LU_HEAT_NAMES;
11457
11458 static int lfs_heat_get(int argc, char **argv)
11459 {
11460         struct lu_heat *heat;
11461         int rc = 0, rc2;
11462         char *path;
11463         int fd;
11464         int i;
11465
11466         if (argc <= 1)
11467                 return CMD_HELP;
11468
11469         heat = calloc(sizeof(*heat) + sizeof(__u64) * OBD_HEAT_COUNT, 1);
11470         if (!heat) {
11471                 fprintf(stderr, "%s: memory allocation failed\n", argv[0]);
11472                 return -ENOMEM;
11473         }
11474
11475         optind = 1;
11476         while (optind < argc) {
11477                 path = argv[optind++];
11478
11479                 fd = open(path, O_RDONLY);
11480                 if (fd < 0) {
11481                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
11482                                 argv[0], path, strerror(errno));
11483                         rc2 = -errno;
11484                         goto next;
11485                 }
11486
11487                 heat->lh_count = OBD_HEAT_COUNT;
11488                 rc2 = llapi_heat_get(fd, heat);
11489                 close(fd);
11490                 if (rc2 < 0) {
11491                         fprintf(stderr,
11492                                 "%s: cannot get heat of file '%s': %s\n",
11493                                 argv[0], path, strerror(errno));
11494                         goto next;
11495                 }
11496
11497                 printf("flags: %x\n", heat->lh_flags);
11498                 for (i = 0; i < heat->lh_count; i++)
11499                         printf("%s: %llu\n", heat_names[i],
11500                                (unsigned long long)heat->lh_heat[i]);
11501 next:
11502                 if (rc == 0 && rc2 < 0)
11503                         rc = rc2;
11504         }
11505
11506         free(heat);
11507         return rc;
11508 }
11509
11510 static int lfs_heat_set(int argc, char **argv)
11511 {
11512         struct option long_opts[] = {
11513         { .val = 'c',   .name = "clear",        .has_arg = no_argument },
11514         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11515         { .val = 'o',   .name = "off",          .has_arg = no_argument },
11516         { .val = 'O',   .name = "on",           .has_arg = no_argument },
11517         { .name = NULL } };
11518         enum lu_heat_flag flags = 0;
11519         int rc = 0, rc2;
11520         char *path;
11521         int fd;
11522         int c;
11523
11524         if (argc <= 1)
11525                 return CMD_HELP;
11526
11527         optind = 0;
11528         while ((c = getopt_long(argc, argv, "choO", long_opts, NULL)) != -1) {
11529                 switch (c) {
11530                 case 'c':
11531                         flags |= LU_HEAT_FLAG_CLEAR;
11532                         break;
11533                 case 'o':
11534                         flags |= LU_HEAT_FLAG_CLEAR;
11535                         flags |= LU_HEAT_FLAG_OFF;
11536                         break;
11537                 case 'O':
11538                         flags &= ~LU_HEAT_FLAG_OFF;
11539                         break;
11540                 default:
11541                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11542                                 progname, argv[optind - 1]);
11543                         fallthrough;
11544                 case 'h':
11545                         return CMD_HELP;
11546                 }
11547         }
11548
11549         if (argc <= optind) {
11550                 fprintf(stderr, "%s: please give one or more file names\n",
11551                         argv[0]);
11552                 return CMD_HELP;
11553         }
11554
11555         while (optind < argc) {
11556                 path = argv[optind++];
11557
11558                 fd = open(path, O_RDONLY);
11559                 if (fd < 0) {
11560                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
11561                                 argv[0], path, strerror(errno));
11562                         rc2 = -errno;
11563                         goto next;
11564                 }
11565
11566                 rc2 = llapi_heat_set(fd, flags);
11567                 close(fd);
11568                 if (rc2 < 0) {
11569                         fprintf(stderr,
11570                                 "%s: cannot setflags heat of file '%s': %s\n",
11571                                 argv[0], path, strerror(errno));
11572                         goto next;
11573                 }
11574 next:
11575                 if (rc == 0 && rc2 < 0)
11576                         rc = rc2;
11577         }
11578         return rc;
11579 }
11580
11581 /**
11582  * The input string contains a comma delimited list of component ids and
11583  * ranges, for example "1,2-4,7".
11584  */
11585 static int parse_mirror_ids(__u16 *ids, int size, char *arg)
11586 {
11587         bool end_of_loop = false;
11588         char *ptr = NULL;
11589         int nr = 0;
11590         int rc;
11591
11592         if (!arg)
11593                 return -EINVAL;
11594
11595         while (!end_of_loop) {
11596                 int start_index;
11597                 int end_index;
11598                 int i;
11599                 char *endptr = NULL;
11600
11601                 rc = -EINVAL;
11602                 ptr = strchrnul(arg, ',');
11603                 end_of_loop = *ptr == '\0';
11604                 *ptr = '\0';
11605
11606                 start_index = strtol(arg, &endptr, 0);
11607                 if (endptr == arg) /* no data at all */
11608                         break;
11609                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
11610                         break;
11611                 if (start_index < 0)
11612                         break;
11613
11614                 end_index = start_index;
11615                 if (*endptr == '-') {
11616                         end_index = strtol(endptr + 1, &endptr, 0);
11617                         if (*endptr != '\0')
11618                                 break;
11619                         if (end_index < start_index)
11620                                 break;
11621                 }
11622
11623                 for (i = start_index; i <= end_index && size > 0; i++) {
11624                         int j;
11625
11626                         /* remove duplicate */
11627                         for (j = 0; j < nr; j++) {
11628                                 if (ids[j] == i)
11629                                         break;
11630                         }
11631                         if (j == nr) { /* no duplicate */
11632                                 ids[nr++] = i;
11633                                 --size;
11634                         }
11635                 }
11636
11637                 if (size == 0 && i < end_index)
11638                         break;
11639
11640                 *ptr = ',';
11641                 arg = ++ptr;
11642                 rc = 0;
11643         }
11644         if (!end_of_loop && ptr)
11645                 *ptr = ',';
11646
11647         return rc < 0 ? rc : nr;
11648 }
11649
11650 /**
11651  * struct verify_mirror_id - Mirror id to be verified.
11652  * @mirror_id:   A specified mirror id.
11653  * @is_valid_id: @mirror_id is valid or not in the mirrored file.
11654  */
11655 struct verify_mirror_id {
11656         __u16 mirror_id;
11657         bool is_valid_id;
11658 };
11659
11660 /**
11661  * compare_mirror_ids() - Compare mirror ids.
11662  * @layout: Mirror component list.
11663  * @cbdata: Callback data in verify_mirror_id structure.
11664  *
11665  * This is a callback function called by llapi_layout_comp_iterate()
11666  * to compare the specified mirror id with the one in the current
11667  * component of @layout. If they are the same, then the specified
11668  * mirror id is valid.
11669  *
11670  * Return: a negative error code on failure or
11671  *         LLAPI_LAYOUT_ITER_CONT: Proceed iteration
11672  *         LLAPI_LAYOUT_ITER_STOP: Stop iteration
11673  */
11674 static inline
11675 int compare_mirror_ids(struct llapi_layout *layout, void *cbdata)
11676 {
11677         struct verify_mirror_id *mirror_id_cbdata =
11678                                  (struct verify_mirror_id *)cbdata;
11679         uint32_t mirror_id;
11680         int rc = 0;
11681
11682         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
11683         if (rc < 0) {
11684                 rc = -errno;
11685                 fprintf(stderr,
11686                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
11687                         progname, strerror(errno));
11688                 return rc;
11689         }
11690
11691         if (mirror_id_cbdata->mirror_id == mirror_id) {
11692                 mirror_id_cbdata->is_valid_id = true;
11693                 return LLAPI_LAYOUT_ITER_STOP;
11694         }
11695
11696         return LLAPI_LAYOUT_ITER_CONT;
11697 }
11698
11699 /**
11700  * verify_mirror_ids() - Verify specified mirror ids.
11701  * @fname:      Mirrored file name.
11702  * @mirror_ids: Specified mirror ids to be verified.
11703  * @ids_nr:     Number of specified mirror ids.
11704  *
11705  * This function verifies that specified @mirror_ids are valid
11706  * in the mirrored file @fname.
11707  *
11708  * Return: 0 on success or a negative error code on failure.
11709  */
11710 static inline
11711 int verify_mirror_ids(const char *fname, __u16 *mirror_ids, int ids_nr)
11712 {
11713         struct llapi_layout *layout = NULL;
11714         struct verify_mirror_id mirror_id_cbdata = { 0 };
11715         struct stat stbuf;
11716         uint32_t flr_state;
11717         int i;
11718         int fd;
11719         int rc = 0;
11720         int rc2 = 0;
11721
11722         if (ids_nr <= 0)
11723                 return -EINVAL;
11724
11725         if (stat(fname, &stbuf) < 0) {
11726                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
11727                         progname, fname, strerror(errno));
11728                 rc = -errno;
11729                 goto error;
11730         }
11731
11732         if (!S_ISREG(stbuf.st_mode)) {
11733                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
11734                         progname, fname);
11735                 rc = -EINVAL;
11736                 goto error;
11737         }
11738
11739         fd = open(fname, O_DIRECT | O_RDONLY);
11740         if (fd < 0) {
11741                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
11742                         progname, fname, strerror(errno));
11743                 rc = -errno;
11744                 goto error;
11745         }
11746
11747         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
11748         if (rc < 0) {
11749                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
11750                         progname, fname, strerror(errno));
11751                 goto close_fd;
11752         }
11753
11754         layout = llapi_layout_get_by_fd(fd, 0);
11755         if (!layout) {
11756                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
11757                         progname, fname, strerror(errno));
11758                 rc = -errno;
11759                 llapi_lease_release(fd);
11760                 goto close_fd;
11761         }
11762
11763         rc = llapi_layout_flags_get(layout, &flr_state);
11764         if (rc < 0) {
11765                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
11766                         progname, fname, strerror(errno));
11767                 rc = -errno;
11768                 goto free_layout;
11769         }
11770
11771         flr_state &= LCM_FL_FLR_MASK;
11772         switch (flr_state) {
11773         case LCM_FL_NONE:
11774                 rc = -EINVAL;
11775                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
11776                         progname, fname, llapi_layout_flags_string(flr_state));
11777                 goto free_layout;
11778         default:
11779                 break;
11780         }
11781
11782         rc2 = 0;
11783         for (i = 0; i < ids_nr; i++) {
11784                 mirror_id_cbdata.mirror_id = mirror_ids[i];
11785                 mirror_id_cbdata.is_valid_id = false;
11786
11787                 rc = llapi_layout_comp_iterate(layout, compare_mirror_ids,
11788                                                &mirror_id_cbdata);
11789                 if (rc < 0) {
11790                         rc = -errno;
11791                         fprintf(stderr,
11792                                 "%s: '%s' failed to verify mirror id: %u.\n",
11793                                 progname, fname, mirror_ids[i]);
11794                         goto free_layout;
11795                 }
11796
11797                 if (!mirror_id_cbdata.is_valid_id) {
11798                         rc2 = -EINVAL;
11799                         fprintf(stderr,
11800                                 "%s: '%s' invalid specified mirror id: %u.\n",
11801                                 progname, fname, mirror_ids[i]);
11802                 }
11803         }
11804         rc = rc2;
11805
11806 free_layout:
11807         llapi_layout_free(layout);
11808         llapi_lease_release(fd);
11809 close_fd:
11810         close(fd);
11811 error:
11812         return rc;
11813 }
11814
11815 static inline
11816 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
11817                            __u16 *mirror_ids, int ids_nr,
11818                            long stats_interval_sec, long bandwidth_bytes_sec)
11819 {
11820         struct llapi_resync_comp comp_array[1024] = { { 0 } };
11821         struct llapi_layout *layout;
11822         struct stat stbuf;
11823         uint32_t flr_state;
11824         uint64_t start;
11825         uint64_t end;
11826         int comp_size = 0;
11827         int idx;
11828         int fd;
11829         int rc;
11830         int rc2;
11831
11832         if (stat(fname, &stbuf) < 0) {
11833                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
11834                         progname, fname, strerror(errno));
11835                 rc = -errno;
11836                 goto error;
11837         }
11838         if (!S_ISREG(stbuf.st_mode)) {
11839                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
11840                         progname, fname);
11841                 rc = -EINVAL;
11842                 goto error;
11843         }
11844
11845         /* Allow mirror resync even without the key on encrypted files */
11846         fd = open(fname, O_DIRECT | O_RDWR | O_CIPHERTEXT);
11847         if (fd < 0) {
11848                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
11849                         progname, fname, strerror(errno));
11850                 rc = -errno;
11851                 goto error;
11852         }
11853
11854         layout = llapi_layout_get_by_fd(fd, 0);
11855         if (!layout) {
11856                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
11857                         progname, fname, strerror(errno));
11858                 rc = -errno;
11859                 goto close_fd;
11860         }
11861
11862         rc = llapi_layout_flags_get(layout, &flr_state);
11863         if (rc) {
11864                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
11865                         progname, fname, strerror(errno));
11866                 rc = -errno;
11867                 goto free_layout;
11868         }
11869
11870         flr_state &= LCM_FL_FLR_MASK;
11871         if (flr_state == LCM_FL_NONE) {
11872                 rc = -EINVAL;
11873                 fprintf(stderr, "%s: '%s' is not a FLR file.\n",
11874                         progname, fname);
11875                 goto free_layout;
11876         }
11877
11878         /* get stale component info */
11879         comp_size = llapi_mirror_find_stale(layout, comp_array,
11880                                             ARRAY_SIZE(comp_array),
11881                                             mirror_ids, ids_nr);
11882         if (comp_size <= 0) {
11883                 rc = comp_size;
11884                 goto free_layout;
11885         }
11886
11887         ioc->lil_mode = LL_LEASE_WRLCK;
11888         ioc->lil_flags = LL_LEASE_RESYNC;
11889         rc = llapi_lease_set(fd, ioc);
11890         if (rc < 0) {
11891                 if (rc == -EALREADY)
11892                         rc = 0;
11893                 else
11894                         fprintf(stderr,
11895                             "%s: '%s' llapi_lease_get_ext resync failed: %s.\n",
11896                                 progname, fname, strerror(-rc));
11897                 goto free_layout;
11898         }
11899
11900         /* get the read range [start, end) */
11901         start = comp_array[0].lrc_start;
11902         end = comp_array[0].lrc_end;
11903         for (idx = 1; idx < comp_size; idx++) {
11904                 if (comp_array[idx].lrc_start < start)
11905                         start = comp_array[idx].lrc_start;
11906                 if (end < comp_array[idx].lrc_end)
11907                         end = comp_array[idx].lrc_end;
11908         }
11909
11910         rc = llapi_lease_check(fd);
11911         if (rc != LL_LEASE_WRLCK) {
11912                 fprintf(stderr, "%s: '%s' lost lease lock.\n",
11913                         progname, fname);
11914                 goto free_layout;
11915         }
11916
11917         rc = llapi_mirror_resync_many_params(fd, layout, comp_array, comp_size,
11918                                              start, end, stats_interval_sec,
11919                                              bandwidth_bytes_sec);
11920         if (rc < 0)
11921                 fprintf(stderr, "%s: '%s' llapi_mirror_resync_many: %s.\n",
11922                         progname, fname, strerror(-rc));
11923
11924         rc2 = migrate_set_timestamps(fd, &stbuf);
11925         if (rc2 < 0) {
11926                 fprintf(stderr, "%s: '%s' cannot set timestamps: %s\n",
11927                         progname, fname, strerror(-rc2));
11928                 if (!rc)
11929                         rc = rc2;
11930                 goto free_layout;
11931         }
11932
11933         /* need to do the lease unlock even resync fails */
11934         ioc->lil_mode = LL_LEASE_UNLCK;
11935         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
11936         ioc->lil_count = 0;
11937         for (idx = 0; idx < comp_size; idx++) {
11938                 if (comp_array[idx].lrc_synced) {
11939                         ioc->lil_ids[ioc->lil_count] = comp_array[idx].lrc_id;
11940                         ioc->lil_count++;
11941                 }
11942         }
11943
11944         rc2 = llapi_lease_set(fd, ioc);
11945         /**
11946          * llapi_lease_set returns lease mode when it request to unlock
11947          * the lease lock.
11948          */
11949         if (rc2 <= 0) {
11950                 /* rc2 == 0 means lost lease lock */
11951                 if (rc2 == 0 && rc == 0)
11952                         rc = -EBUSY;
11953                 else
11954                         rc = rc2;
11955                 fprintf(stderr, "%s: resync file '%s' failed: %s.\n",
11956                         progname, fname,
11957                         rc2 == 0 ? "lost lease lock" : strerror(-rc2));
11958
11959                 llapi_lease_release(fd);
11960                 goto free_layout;
11961         }
11962
11963 free_layout:
11964         llapi_layout_free(layout);
11965 close_fd:
11966         close(fd);
11967 error:
11968         return rc;
11969 }
11970
11971 static inline int lfs_mirror_resync(int argc, char **argv)
11972 {
11973         struct option long_opts[] = {
11974         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11975         { .val = 'o',   .name = "only",         .has_arg = required_argument },
11976         { .val = 'W',   .name = "bandwidth",    .has_arg = required_argument },
11977         { .val = LFS_STATS_OPT,
11978                         .name = "stats",        .has_arg = no_argument},
11979         { .val = LFS_STATS_INTERVAL_OPT,
11980                         .name = "stats-interval",
11981                                                 .has_arg = required_argument},
11982         { .name = NULL } };
11983         struct ll_ioc_lease *ioc = NULL;
11984         __u16 mirror_ids[128] = { 0 };
11985         unsigned int stats_interval_sec = 0;
11986         unsigned long long bandwidth_bytes_sec = 0;
11987         unsigned long long bandwidth_unit = ONE_MB;
11988         int ids_nr = 0;
11989         int c;
11990         int rc = 0;
11991
11992         while ((c = getopt_long(argc, argv, "ho:W:", long_opts, NULL)) >= 0) {
11993                 char *end;
11994                 switch (c) {
11995                 case 'o':
11996                         rc = parse_mirror_ids(mirror_ids,
11997                                         sizeof(mirror_ids) / sizeof(__u16),
11998                                         optarg);
11999                         if (rc < 0) {
12000                                 fprintf(stderr,
12001                                         "%s: bad mirror ids '%s'.\n",
12002                                         argv[0], optarg);
12003                                 goto error;
12004                         }
12005                         ids_nr = rc;
12006                         break;
12007                 case 'W':
12008                         if (llapi_parse_size(optarg, &bandwidth_bytes_sec,
12009                                              &bandwidth_unit, 0) < 0) {
12010                                 fprintf(stderr,
12011                                         "error: %s: bad value for bandwidth '%s'\n",
12012                                         argv[0], optarg);
12013                                 goto error;
12014                         }
12015                         break;
12016                 case LFS_STATS_OPT:
12017                         stats_interval_sec = 5;
12018                         break;
12019                 case LFS_STATS_INTERVAL_OPT:
12020                         stats_interval_sec = strtol(optarg, &end, 0);
12021                         break;
12022                 default:
12023                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12024                                 progname, argv[optind - 1]);
12025                         fallthrough;
12026                 case 'h':
12027                         rc = CMD_HELP;
12028                         goto error;
12029                 }
12030         }
12031
12032         if (argc == optind) {
12033                 fprintf(stderr, "%s: no file name given.\n", argv[0]);
12034                 rc = CMD_HELP;
12035                 goto error;
12036         }
12037
12038         if (ids_nr > 0 && argc > optind + 1) {
12039                 fprintf(stderr,
12040                     "%s: option '--only' cannot be used upon multiple files.\n",
12041                         argv[0]);
12042                 rc = CMD_HELP;
12043                 goto error;
12044         }
12045
12046         if (ids_nr > 0) {
12047                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
12048                 if (rc < 0)
12049                         goto error;
12050         }
12051
12052         /* set the lease on the file */
12053         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
12054         if (!ioc) {
12055                 fprintf(stderr, "%s: cannot alloc id array for ioc: %s.\n",
12056                         argv[0], strerror(errno));
12057                 rc = -errno;
12058                 goto error;
12059         }
12060
12061         for (; optind < argc; optind++) {
12062                 rc = lfs_mirror_resync_file(argv[optind], ioc,
12063                                             mirror_ids, ids_nr,
12064                                             stats_interval_sec,
12065                                             bandwidth_bytes_sec);
12066                 /* ignore previous file's error, continue with next file */
12067
12068                 /* reset ioc */
12069                 memset(ioc, 0, sizeof(*ioc) + sizeof(__u32) * 4096);
12070         }
12071
12072         free(ioc);
12073 error:
12074         return rc;
12075 }
12076
12077 static inline int verify_mirror_id_by_fd(int fd, __u16 mirror_id)
12078 {
12079         struct llapi_layout *layout;
12080         int rc;
12081
12082         layout = llapi_layout_get_by_fd(fd, 0);
12083         if (!layout) {
12084                 fprintf(stderr, "could not get layout.\n");
12085                 return  -EINVAL;
12086         }
12087
12088         rc = llapi_layout_comp_iterate(layout, find_mirror_id, &mirror_id);
12089         if (rc < 0) {
12090                 fprintf(stderr, "failed to iterate layout\n");
12091                 llapi_layout_free(layout);
12092
12093                 return rc;
12094         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
12095                 fprintf(stderr, "does not find mirror with ID %u\n", mirror_id);
12096                 llapi_layout_free(layout);
12097
12098                 return -EINVAL;
12099         }
12100         llapi_layout_free(layout);
12101
12102         return 0;
12103 }
12104
12105 /**
12106  * Check whether two files are the same file
12107  * \retval      0  same file
12108  * \retval      1  not the same file
12109  * \retval      <0 error code
12110  */
12111 static inline int check_same_file(int fd, const char *f2)
12112 {
12113         struct stat stbuf1;
12114         struct stat stbuf2;
12115
12116         if (fstat(fd, &stbuf1) < 0)
12117                 return -errno;
12118
12119         if (stat(f2, &stbuf2) < 0)
12120                 return 1;
12121
12122         if (stbuf1.st_rdev == stbuf2.st_rdev &&
12123             stbuf1.st_ino == stbuf2.st_ino)
12124                 return 0;
12125
12126         return 1;
12127 }
12128
12129 static inline int lfs_mirror_read(int argc, char **argv)
12130 {
12131         int rc = CMD_HELP;
12132         __u16 mirror_id = 0;
12133         const char *outfile = NULL;
12134         char *fname;
12135         int fd = 0;
12136         int outfd;
12137         int c;
12138         void *buf;
12139         const size_t buflen = 4 << 20;
12140         ssize_t page_size;
12141         off_t pos;
12142         struct option long_opts[] = {
12143         { .val = 'h',   .name = "help",         .has_arg = no_argument },
12144         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
12145         { .val = 'o',   .name = "outfile",      .has_arg = required_argument },
12146         { .name = NULL } };
12147
12148         while ((c = getopt_long(argc, argv, "hN:o:", long_opts, NULL)) >= 0) {
12149                 char *end;
12150
12151                 switch (c) {
12152                 case 'N': {
12153                         unsigned long int id;
12154
12155                         errno = 0;
12156                         id = strtoul(optarg, &end, 0);
12157                         if (errno != 0 || *end != '\0' || id == 0 ||
12158                             id > UINT16_MAX) {
12159                                 fprintf(stderr,
12160                                         "%s %s: invalid mirror ID '%s'\n",
12161                                         progname, argv[0], optarg);
12162                                 return rc;
12163                         }
12164
12165                         mirror_id = (__u16)id;
12166                         break;
12167                 }
12168                 case 'o':
12169                         outfile = optarg;
12170                         break;
12171                 default:
12172                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12173                                 progname, argv[optind - 1]);
12174                         fallthrough;
12175                 case 'h':
12176                         return CMD_HELP;
12177                 }
12178         }
12179
12180         if (argc == optind) {
12181                 fprintf(stderr, "%s %s: no mirrored file provided\n",
12182                         progname, argv[0]);
12183                 return rc;
12184         } else if (argc > optind + 1) {
12185                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
12186                 return rc;
12187         }
12188
12189         if (mirror_id == 0) {
12190                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
12191                         progname, argv[0]);
12192                 return rc;
12193         }
12194
12195         /* open mirror file */
12196         fname = argv[optind];
12197         fd = open(fname, O_DIRECT | O_RDONLY);
12198         if (fd < 0) {
12199                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
12200                         progname, argv[0], fname, strerror(errno));
12201                 return rc;
12202         }
12203
12204         /* verify mirror id */
12205         rc = verify_mirror_id_by_fd(fd, mirror_id);
12206         if (rc) {
12207                 fprintf(stderr,
12208                         "%s %s: cannot find mirror with ID %u in '%s'\n",
12209                         progname, argv[0], mirror_id, fname);
12210                 goto close_fd;
12211         }
12212
12213         /* open output file - O_EXCL ensures output is not the same as input */
12214         if (outfile) {
12215                 outfd = open(outfile, O_EXCL | O_WRONLY | O_CREAT, 0644);
12216                 if (outfd < 0) {
12217                         fprintf(stderr, "%s %s: cannot create file '%s': %s\n",
12218                                 progname, argv[0], outfile, strerror(errno));
12219                         rc = -errno;
12220                         goto close_fd;
12221                 }
12222         } else {
12223                 outfd = STDOUT_FILENO;
12224         }
12225
12226         page_size = sysconf(_SC_PAGESIZE);
12227         if (page_size < 0) {
12228                 rc = -errno;
12229                 goto close_fd;
12230         }
12231
12232         /* allocate buffer */
12233         rc = posix_memalign(&buf, page_size, buflen);
12234         if (rc) {
12235                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
12236                                 progname, argv[0], rc);
12237                 goto close_outfd;
12238         }
12239
12240         pos = 0;
12241         while (1) {
12242                 ssize_t bytes_read;
12243                 ssize_t written = 0;
12244
12245                 bytes_read = llapi_mirror_read(fd, mirror_id, buf, buflen, pos);
12246                 if (bytes_read < 0) {
12247                         rc = bytes_read;
12248                         fprintf(stderr,
12249                                 "%s %s: fail to read data from mirror %u: %s\n",
12250                                 progname, argv[0], mirror_id, strerror(-rc));
12251                         goto free_buf;
12252                 }
12253
12254                 /* EOF reached */
12255                 if (bytes_read == 0)
12256                         break;
12257
12258                 while (written < bytes_read) {
12259                         ssize_t written2;
12260
12261                         written2 = write(outfd, buf + written,
12262                                          bytes_read - written);
12263                         if (written2 < 0) {
12264                                 fprintf(stderr,
12265                                         "%s %s: fail to write %s: %s\n",
12266                                         progname, argv[0], outfile ? : "STDOUT",
12267                                         strerror(errno));
12268                                 rc = -errno;
12269                                 goto free_buf;
12270                         }
12271                         written += written2;
12272                 }
12273
12274                 if (written != bytes_read) {
12275                         fprintf(stderr,
12276                 "%s %s: written %ld bytes does not match with %ld read.\n",
12277                                 progname, argv[0], written, bytes_read);
12278                         rc = -EIO;
12279                         goto free_buf;
12280                 }
12281
12282                 pos += bytes_read;
12283         }
12284
12285         fsync(outfd);
12286         rc = 0;
12287
12288 free_buf:
12289         free(buf);
12290 close_outfd:
12291         if (outfile)
12292                 close(outfd);
12293 close_fd:
12294         close(fd);
12295
12296         return rc;
12297 }
12298
12299 static inline int lfs_mirror_write(int argc, char **argv)
12300 {
12301         int rc = CMD_HELP;
12302         __u16 mirror_id = 0;
12303         const char *inputfile = NULL;
12304         char *fname;
12305         int fd = 0;
12306         int inputfd;
12307         int c;
12308         void *buf;
12309         const size_t buflen = 4 << 20;
12310         off_t pos;
12311         ssize_t page_size = sysconf(_SC_PAGESIZE);
12312         struct ll_ioc_lease_id ioc;
12313         struct option long_opts[] = {
12314         { .val = 'h',   .name = "help",         .has_arg = no_argument },
12315         { .val = 'i',   .name = "inputfile",    .has_arg = required_argument },
12316         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
12317         { .name = NULL } };
12318
12319         while ((c = getopt_long(argc, argv, "hi:N:", long_opts, NULL)) >= 0) {
12320                 char *end;
12321
12322                 switch (c) {
12323                 case 'N': {
12324                         unsigned long int id;
12325
12326                         errno = 0;
12327                         id = strtoul(optarg, &end, 0);
12328                         if (errno != 0 || *end != '\0' || id == 0 ||
12329                             id > UINT16_MAX) {
12330                                 fprintf(stderr,
12331                                         "%s %s: invalid mirror ID '%s'\n",
12332                                         progname, argv[0], optarg);
12333                                 return rc;
12334                         }
12335
12336                         mirror_id = (__u16)id;
12337                         break;
12338                 }
12339                 case 'i':
12340                         inputfile = optarg;
12341                         break;
12342                 default:
12343                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12344                                 progname, argv[optind - 1]);
12345                         fallthrough;
12346                 case 'h':
12347                         return CMD_HELP;
12348                 }
12349         }
12350
12351         if (argc == optind) {
12352                 fprintf(stderr, "%s %s: no mirrored file provided\n",
12353                         progname, argv[0]);
12354                 return rc;
12355         } else if (argc > optind + 1) {
12356                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
12357                 return rc;
12358         }
12359
12360         if (mirror_id == 0) {
12361                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
12362                         progname, argv[0]);
12363                 return rc;
12364         }
12365
12366         /* open mirror file */
12367         fname = argv[optind];
12368         fd = open(fname, O_DIRECT | O_WRONLY);
12369         if (fd < 0) {
12370                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
12371                         progname, argv[0], fname, strerror(errno));
12372                 return rc;
12373         }
12374
12375         /* verify mirror id */
12376         rc = verify_mirror_id_by_fd(fd, mirror_id);
12377         if (rc) {
12378                 fprintf(stderr,
12379                         "%s %s: cannot find mirror with ID %u in '%s'\n",
12380                         progname, argv[0], mirror_id, fname);
12381                 goto close_fd;
12382         }
12383
12384         /* open input file */
12385         if (inputfile) {
12386                 rc = check_same_file(fd, inputfile);
12387                 if (rc == 0) {
12388                         fprintf(stderr,
12389                         "%s %s: input file cannot be the mirrored file '%s'\n",
12390                                 progname, argv[0], fname);
12391                         goto close_fd;
12392                 }
12393                 if (rc < 0)
12394                         goto close_fd;
12395
12396                 inputfd = open(inputfile, O_RDONLY, 0644);
12397                 if (inputfd < 0) {
12398                         fprintf(stderr, "%s %s: cannot open file '%s': %s\n",
12399                                 progname, argv[0], inputfile, strerror(errno));
12400                         rc = -errno;
12401                         goto close_fd;
12402                 }
12403         } else {
12404                 inputfd = STDIN_FILENO;
12405         }
12406
12407         /* allocate buffer */
12408         rc = posix_memalign(&buf, page_size, buflen);
12409         if (rc) {
12410                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
12411                         progname, argv[0], rc);
12412                 goto close_inputfd;
12413         }
12414
12415         /* prepare target mirror components instantiation */
12416         ioc.lil_mode = LL_LEASE_WRLCK;
12417         ioc.lil_flags = LL_LEASE_RESYNC;
12418         ioc.lil_mirror_id = mirror_id;
12419         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
12420         if (rc < 0) {
12421                 fprintf(stderr,
12422                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
12423                         progname, argv[0], fname, strerror(errno));
12424                 goto free_buf;
12425         }
12426
12427         pos = 0;
12428         while (1) {
12429                 ssize_t bytes_read;
12430                 ssize_t written;
12431                 size_t to_write;
12432
12433                 rc = llapi_lease_check(fd);
12434                 if (rc != LL_LEASE_WRLCK) {
12435                         fprintf(stderr, "%s %s: '%s' lost lease lock\n",
12436                                 progname, argv[0], fname);
12437                         goto free_buf;
12438                 }
12439
12440                 bytes_read = read(inputfd, buf, buflen);
12441                 if (bytes_read < 0) {
12442                         rc = bytes_read;
12443                         fprintf(stderr,
12444                                 "%s %s: fail to read data from '%s': %s\n",
12445                                 progname, argv[0], inputfile ? : "STDIN",
12446                                 strerror(errno));
12447                         rc = -errno;
12448                         goto free_buf;
12449                 }
12450
12451                 /* EOF reached */
12452                 if (bytes_read == 0)
12453                         break;
12454
12455                 /* round up to page align to make direct IO happy. */
12456                 to_write = (bytes_read + page_size - 1) & ~(page_size - 1);
12457
12458                 written = llapi_mirror_write(fd, mirror_id, buf, to_write,
12459                                              pos);
12460                 if (written < 0) {
12461                         rc = written;
12462                         fprintf(stderr,
12463                               "%s %s: fail to write to mirror %u: %s\n",
12464                                 progname, argv[0], mirror_id,
12465                                 strerror(-rc));
12466                         goto free_buf;
12467                 }
12468
12469                 pos += bytes_read;
12470         }
12471
12472         if (pos & (page_size - 1)) {
12473                 rc = llapi_mirror_truncate(fd, mirror_id, pos);
12474                 if (rc < 0)
12475                         goto free_buf;
12476         }
12477
12478         ioc.lil_mode = LL_LEASE_UNLCK;
12479         ioc.lil_flags = LL_LEASE_RESYNC_DONE;
12480         ioc.lil_count = 0;
12481         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
12482         if (rc <= 0) {
12483                 if (rc == 0)
12484                         rc = -EBUSY;
12485                 fprintf(stderr,
12486                         "%s %s: release lease lock of '%s' failed: %s\n",
12487                         progname, argv[0], fname, strerror(-rc));
12488                 goto free_buf;
12489         }
12490
12491         rc = 0;
12492
12493 free_buf:
12494         free(buf);
12495 close_inputfd:
12496         if (inputfile)
12497                 close(inputfd);
12498 close_fd:
12499         close(fd);
12500
12501         return rc;
12502 }
12503
12504 static inline int get_other_mirror_ids(int fd, __u16 *ids, __u16 exclude_id)
12505 {
12506         struct llapi_layout *layout;
12507         struct collect_ids_data cid = { .cid_ids = ids,
12508                                         .cid_count = 0,
12509                                         .cid_exclude = exclude_id, };
12510         int rc;
12511
12512         layout = llapi_layout_get_by_fd(fd, 0);
12513         if (!layout) {
12514                 fprintf(stderr, "could not get layout\n");
12515                 return -EINVAL;
12516         }
12517
12518         rc = llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
12519         if (rc < 0) {
12520                 fprintf(stderr, "failed to iterate layout\n");
12521                 llapi_layout_free(layout);
12522
12523                 return rc;
12524         }
12525         llapi_layout_free(layout);
12526
12527         return cid.cid_count;
12528 }
12529
12530 #ifndef MIRROR_ID_NEG
12531 #define MIRROR_ID_NEG         0x8000
12532 #endif
12533
12534 static inline int lfs_mirror_copy(int argc, char **argv)
12535 {
12536         int rc = CMD_HELP;
12537         __u16 read_mirror_id = 0;
12538         __u16 ids[128] = { 0 };
12539         int count = 0;
12540         struct llapi_layout *layout = NULL;
12541         struct llapi_resync_comp comp_array[1024] = { { 0 } };
12542         int comp_size = 0;
12543         char *fname;
12544         int fd = 0;
12545         int c;
12546         int i;
12547         ssize_t copied;
12548         struct ll_ioc_lease *ioc = NULL;
12549         struct ll_ioc_lease_id *resync_ioc;
12550         struct option long_opts[] = {
12551         { .val = 'h',   .name = "help",         .has_arg = no_argument },
12552         { .val = 'i',   .name = "read-mirror",  .has_arg = required_argument },
12553         { .val = 'o',   .name = "write-mirror", .has_arg = required_argument },
12554         { .name = NULL } };
12555         char cmd[PATH_MAX];
12556
12557         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12558         progname = cmd;
12559         while ((c = getopt_long(argc, argv, "hi:o:", long_opts, NULL)) >= 0) {
12560                 char *end;
12561
12562                 switch (c) {
12563                 case 'i': {
12564                         unsigned long int id;
12565
12566                         errno = 0;
12567                         id = strtoul(optarg, &end, 0);
12568                         if (errno != 0 || *end != '\0' || id == 0 ||
12569                             id > UINT16_MAX) {
12570                                 fprintf(stderr,
12571                                         "%s: invalid read mirror ID '%s'\n",
12572                                         progname, optarg);
12573                                 return rc;
12574                         }
12575
12576                         read_mirror_id = (__u16)id;
12577                         break;
12578                 }
12579                 case 'o':
12580                         if (!strcmp(optarg, "-1")) {
12581                                 /* specify all other mirrors */
12582                                 ids[0] = (__u16)-1;
12583                                 count = 1;
12584                         } else {
12585                                 count = parse_mirror_ids((__u16 *)ids,
12586                                                          ARRAY_SIZE(ids),
12587                                                          optarg);
12588                                 if (count < 0)
12589                                         return rc;
12590                         }
12591                         break;
12592                 default:
12593                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12594                                 progname, argv[optind - 1]);
12595                         fallthrough;
12596                 case 'h':
12597                         return CMD_HELP;
12598                 }
12599         }
12600
12601         if (argc == optind) {
12602                 fprintf(stderr, "%s %s: no mirrored file provided\n",
12603                         progname, argv[0]);
12604                 return rc;
12605         } else if (argc > optind + 1) {
12606                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
12607                 return rc;
12608         }
12609
12610         if (read_mirror_id == 0) {
12611                 fprintf(stderr,
12612                         "%s %s: no valid read mirror ID %d is provided\n",
12613                         progname, argv[0], read_mirror_id);
12614                 return rc;
12615         }
12616
12617         if (count == 0) {
12618                 fprintf(stderr,
12619                         "%s %s: no write mirror ID is provided\n",
12620                         progname, argv[0]);
12621                 return rc;
12622         }
12623
12624         for (i = 0; i < count; i++) {
12625                 if (read_mirror_id == ids[i]) {
12626                         fprintf(stderr,
12627                         "%s %s: read and write mirror ID cannot be the same\n",
12628                                 progname, argv[0]);
12629                         return rc;
12630                 }
12631         }
12632
12633         /* open mirror file */
12634         fname = argv[optind];
12635
12636         fd = open(fname, O_DIRECT | O_RDWR);
12637         if (fd < 0) {
12638                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
12639                         progname, argv[0], fname, strerror(errno));
12640                 return rc;
12641         }
12642
12643         /* write to all other mirrors */
12644         if (ids[0] == (__u16)-1) {
12645                 count = get_other_mirror_ids(fd, ids, read_mirror_id);
12646                 if (count <= 0) {
12647                         rc = count;
12648                         fprintf(stderr,
12649                         "%s %s: failed to get other mirror ids in '%s': %d\n",
12650                                 progname, argv[0], fname, rc);
12651                         goto close_fd;
12652                 }
12653         }
12654
12655         /* verify mirror id */
12656         rc = verify_mirror_id_by_fd(fd, read_mirror_id);
12657         if (rc) {
12658                 fprintf(stderr,
12659                         "%s %s: cannot find mirror with ID %u in '%s'\n",
12660                         progname, argv[0], read_mirror_id, fname);
12661                 goto close_fd;
12662         }
12663
12664         for (i = 0; i < count; i++) {
12665                 rc = verify_mirror_id_by_fd(fd, ids[i]);
12666                 if (rc) {
12667                         fprintf(stderr,
12668                         "%s %s: cannot find mirror with ID %u in '%s'\n",
12669                                 progname, argv[0], ids[i], fname);
12670                         goto close_fd;
12671                 }
12672         }
12673
12674         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
12675         if (!ioc) {
12676                 fprintf(stderr,
12677                         "%s %s: cannot alloc comp id array for ioc: %s\n",
12678                         progname, argv[0], strerror(errno));
12679                 rc = -errno;
12680                 goto close_fd;
12681         }
12682
12683         /* get stale component info */
12684         layout = llapi_layout_get_by_fd(fd, 0);
12685         if (!layout) {
12686                 fprintf(stderr, "%s %s: failed to get layout of '%s': %s\n",
12687                         progname, argv[0], fname, strerror(errno));
12688                 rc = -errno;
12689                 goto free_ioc;
12690         }
12691         comp_size = llapi_mirror_find_stale(layout, comp_array,
12692                                             ARRAY_SIZE(comp_array),
12693                                             ids, count);
12694         llapi_layout_free(layout);
12695         if (comp_size < 0) {
12696                 rc = comp_size;
12697                 goto free_ioc;
12698         }
12699
12700         /* prepare target mirror components instantiation */
12701         resync_ioc = (struct ll_ioc_lease_id *)ioc;
12702         resync_ioc->lil_mode = LL_LEASE_WRLCK;
12703         resync_ioc->lil_flags = LL_LEASE_RESYNC;
12704         if (count == 1)
12705                 resync_ioc->lil_mirror_id = ids[0];
12706         else
12707                 resync_ioc->lil_mirror_id = read_mirror_id | MIRROR_ID_NEG;
12708         rc = llapi_lease_set(fd, ioc);
12709         if (rc < 0) {
12710                 fprintf(stderr,
12711                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
12712                         progname, argv[0], fname, strerror(errno));
12713                 goto free_ioc;
12714         }
12715
12716         copied = llapi_mirror_copy_many(fd, read_mirror_id, ids, count);
12717         if (copied < 0) {
12718                 rc = copied;
12719                 fprintf(stderr, "%s %s: copy error: %d\n",
12720                         progname, argv[0], rc);
12721                 goto free_ioc;
12722         }
12723
12724         fprintf(stdout, "mirror copied successfully: ");
12725         for (i = 0; i < copied; i++)
12726                 fprintf(stdout, "%d ", ids[i]);
12727         fprintf(stdout, "\n");
12728
12729         ioc->lil_mode = LL_LEASE_UNLCK;
12730         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
12731         ioc->lil_count = 0;
12732         for (i = 0; i < comp_size; i++) {
12733                 int j;
12734
12735                 for (j = 0; j < copied; j++) {
12736                         if (comp_array[i].lrc_mirror_id != ids[j])
12737                                 continue;
12738
12739                         ioc->lil_ids[ioc->lil_count] = comp_array[i].lrc_id;
12740                         ioc->lil_count++;
12741                 }
12742         }
12743         rc = llapi_lease_set(fd, ioc);
12744         if (rc <= 0) {
12745                 if (rc == 0)
12746                         rc = -EBUSY;
12747                 fprintf(stderr,
12748                         "%s %s: release lease lock of '%s' failed: %s\n",
12749                         progname, argv[0], fname, strerror(errno));
12750                 goto free_ioc;
12751         }
12752
12753         rc = 0;
12754
12755 free_ioc:
12756         free(ioc);
12757 close_fd:
12758         close(fd);
12759
12760         return rc;
12761 }
12762
12763 /**
12764  * struct verify_chunk - Mirror chunk to be verified.
12765  * @chunk:        [start, end) of the chunk.
12766  * @mirror_count: Number of mirror ids in @mirror_id array.
12767  * @mirror_id:    Array of valid mirror ids that cover the chunk.
12768  */
12769 struct verify_chunk {
12770         struct lu_extent chunk;
12771         unsigned int mirror_count;
12772         __u16 mirror_id[LUSTRE_MIRROR_COUNT_MAX];
12773 };
12774
12775 /**
12776  * print_chunks() - Print chunk information.
12777  * @fname:       Mirrored file name.
12778  * @chunks:      Array of chunks.
12779  * @chunk_count: Number of chunks in @chunks array.
12780  *
12781  * This function prints [start, end) of each chunk in @chunks
12782  * for mirrored file @fname, and also prints the valid mirror ids
12783  * that cover the chunk.
12784  *
12785  * Return: void.
12786  */
12787 static inline
12788 void print_chunks(const char *fname, struct verify_chunk *chunks,
12789                   int chunk_count)
12790 {
12791         int i;
12792         int j;
12793
12794         fprintf(stdout, "Chunks to be verified in %s:\n", fname);
12795         for (i = 0; i < chunk_count; i++) {
12796                 fprintf(stdout, DEXT, PEXT(&chunks[i].chunk));
12797
12798                 if (chunks[i].mirror_count == 0)
12799                         fprintf(stdout, "\t[");
12800                 else {
12801                         fprintf(stdout, "\t[%u", chunks[i].mirror_id[0]);
12802                         for (j = 1; j < chunks[i].mirror_count; j++)
12803                                 fprintf(stdout, ", %u", chunks[i].mirror_id[j]);
12804                 }
12805                 fprintf(stdout, "]\t%u\n", chunks[i].mirror_count);
12806         }
12807         fprintf(stdout, "\n");
12808 }
12809
12810 /**
12811  * print_checksums() - Print CRC-32 checksum values.
12812  * @chunk: A chunk and its corresponding valid mirror ids.
12813  * @crc:   CRC-32 checksum values on the chunk for each valid mirror.
12814  *
12815  * This function prints CRC-32 checksum values on @chunk for
12816  * each valid mirror that covers it.
12817  *
12818  * Return: void.
12819  */
12820 static inline
12821 void print_checksums(struct verify_chunk *chunk, unsigned long *crc,
12822                      unsigned long long pos, unsigned long long len)
12823 {
12824         int i;
12825
12826         fprintf(stdout,
12827                 "CRC-32 checksum value for chunk "DEXT":\n", pos, pos + len);
12828         for (i = 0; i < chunk->mirror_count; i++)
12829                 fprintf(stdout, "Mirror %u:\t%#lx\n",
12830                         chunk->mirror_id[i], crc[i]);
12831         fprintf(stdout, "\n");
12832 }
12833
12834 /**
12835  * filter_mirror_id() - Filter specified mirror ids.
12836  * @chunks:      Array of chunks.
12837  * @chunk_count: Number of chunks in @chunks array.
12838  * @mirror_ids:  Specified mirror ids to be verified.
12839  * @ids_nr:      Number of specified mirror ids.
12840  *
12841  * This function scans valid mirror ids that cover each chunk in @chunks
12842  * and filters specified mirror ids.
12843  *
12844  * Return: void.
12845  */
12846 static inline
12847 void filter_mirror_id(struct verify_chunk *chunks, int chunk_count,
12848                       __u16 *mirror_ids, int ids_nr)
12849 {
12850         int i;
12851         int j;
12852         int k;
12853         __u16 valid_id[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
12854         unsigned int valid_count = 0;
12855
12856         for (i = 0; i < chunk_count; i++) {
12857                 if (chunks[i].mirror_count == 0)
12858                         continue;
12859
12860                 valid_count = 0;
12861                 for (j = 0; j < ids_nr; j++) {
12862                         for (k = 0; k < chunks[i].mirror_count; k++) {
12863                                 if (chunks[i].mirror_id[k] == mirror_ids[j]) {
12864                                         valid_id[valid_count] = mirror_ids[j];
12865                                         valid_count++;
12866                                         break;
12867                                 }
12868                         }
12869                 }
12870
12871                 memcpy(chunks[i].mirror_id, valid_id,
12872                        sizeof(__u16) * valid_count);
12873                 chunks[i].mirror_count = valid_count;
12874         }
12875 }
12876
12877 /**
12878  * lfs_mirror_prepare_chunk() - Find mirror chunks to be verified.
12879  * @layout:      Mirror component list.
12880  * @chunks:      Array of chunks.
12881  * @chunks_size: Array size of @chunks.
12882  *
12883  * This function scans the components in @layout from offset 0 to LUSTRE_EOF
12884  * to find out chunk segments and store them in @chunks array.
12885  *
12886  * The @mirror_id array in each element of @chunks will store the valid
12887  * mirror ids that cover the chunk. If a mirror component covering the
12888  * chunk has LCME_FL_STALE or LCME_FL_OFFLINE flag, then the mirror id
12889  * will not be stored into the @mirror_id array, and the chunk for that
12890  * mirror will not be verified.
12891  *
12892  * The @mirror_count in each element of @chunks will store the number of
12893  * mirror ids in @mirror_id array. If @mirror_count is 0, it indicates the
12894  * chunk is invalid in all of the mirrors. And if @mirror_count is 1, it
12895  * indicates the chunk is valid in only one mirror. In both cases, the
12896  * chunk will not be verified.
12897  *
12898  * Here is an example:
12899  *
12900  *  0      1M     2M     3M     4M           EOF
12901  *  +------+-------------+--------------------+
12902  *  |      |             |      S             |       mirror1
12903  *  +------+------+------+------+-------------+
12904  *  |             |   S  |   S  |             |       mirror2
12905  *  +-------------+------+------+-------------+
12906  *
12907  * prepared @chunks array will contain 5 elements:
12908  * (([0, 1M), [1, 2], 2),
12909  *  ([1M, 2M), [1, 2], 2),
12910  *  ([2M, 3M), [1], 1),
12911  *  ([3M, 4M], [], 0),
12912  *  ([4M, EOF), [2], 1))
12913  *
12914  * Return: the actual array size of @chunks on success
12915  *         or a negative error code on failure.
12916  */
12917 static inline
12918 int lfs_mirror_prepare_chunk(struct llapi_layout *layout,
12919                              struct verify_chunk *chunks,
12920                              size_t chunks_size)
12921 {
12922         uint64_t start;
12923         uint64_t end;
12924         uint32_t mirror_id;
12925         uint32_t flags;
12926         int idx = 0;
12927         int i = 0;
12928         int rc = 0;
12929
12930         memset(chunks, 0, sizeof(*chunks) * chunks_size);
12931
12932         while (1) {
12933                 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
12934                 if (rc < 0) {
12935                         fprintf(stderr,
12936                                 "%s: move to the first layout component: %s.\n",
12937                                 progname, strerror(errno));
12938                         goto error;
12939                 }
12940
12941                 i = 0;
12942                 rc = 0;
12943                 chunks[idx].chunk.e_end = LUSTRE_EOF;
12944                 while (rc == 0) {
12945                         rc = llapi_layout_comp_extent_get(layout, &start, &end);
12946                         if (rc < 0) {
12947                                 fprintf(stderr,
12948                                         "%s: llapi_layout_comp_extent_get failed: %s.\n",
12949                                         progname, strerror(errno));
12950                                 goto error;
12951                         }
12952
12953                         if (start > chunks[idx].chunk.e_start ||
12954                             end <= chunks[idx].chunk.e_start)
12955                                 goto next;
12956
12957                         if (end < chunks[idx].chunk.e_end)
12958                                 chunks[idx].chunk.e_end = end;
12959
12960                         rc = llapi_layout_comp_flags_get(layout, &flags);
12961                         if (rc < 0) {
12962                                 fprintf(stderr,
12963                                         "%s: llapi_layout_comp_flags_get failed: %s.\n",
12964                                         progname, strerror(errno));
12965                                 goto error;
12966                         }
12967
12968                         if (flags & LCME_FL_STALE || flags & LCME_FL_OFFLINE)
12969                                 goto next;
12970
12971                         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
12972                         if (rc < 0) {
12973                                 fprintf(stderr,
12974                                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
12975                                         progname, strerror(errno));
12976                                 goto error;
12977                         }
12978
12979                         if (i >= ARRAY_SIZE(chunks[idx].mirror_id)) {
12980                                 fprintf(stderr,
12981                                         "%s: mirror_id array is too small.\n",
12982                                         progname);
12983                                 rc = -EINVAL;
12984                                 goto error;
12985                         }
12986                         chunks[idx].mirror_id[i] = mirror_id;
12987                         i++;
12988
12989 next:
12990                         rc = llapi_layout_comp_use(layout,
12991                                                    LLAPI_LAYOUT_COMP_USE_NEXT);
12992                         if (rc < 0) {
12993                                 fprintf(stderr,
12994                                         "%s: move to the next layout component: %s.\n",
12995                                         progname, strerror(errno));
12996                                 goto error;
12997                         }
12998                 } /* loop through all components */
12999
13000                 chunks[idx].mirror_count = i;
13001
13002                 if (chunks[idx].chunk.e_end == LUSTRE_EOF)
13003                         break;
13004
13005                 idx++;
13006                 if (idx >= chunks_size) {
13007                         fprintf(stderr, "%s: chunks array is too small.\n",
13008                                 progname);
13009                         rc = -EINVAL;
13010                         goto error;
13011                 }
13012
13013                 chunks[idx].chunk.e_start = chunks[idx - 1].chunk.e_end;
13014         }
13015
13016 error:
13017         return rc < 0 ? rc : idx + 1;
13018 }
13019
13020 /**
13021  * lfs_mirror_verify_chunk() - Verify a chunk.
13022  * @fd:        File descriptor of the mirrored file.
13023  * @file_size: Size of the mirrored file.
13024  * @chunk:     A chunk and its corresponding valid mirror ids.
13025  * @verbose:   Verbose mode.
13026  *
13027  * This function verifies a @chunk contains exactly the same data
13028  * ammong the mirrors that cover it.
13029  *
13030  * If @verbose is specified, then the function will print where the
13031  * differences are if the data do not match. Otherwise, it will
13032  * just return an error in that case.
13033  *
13034  * Return: 0 on success or a negative error code on failure.
13035  */
13036 static inline
13037 int lfs_mirror_verify_chunk(int fd, size_t file_size,
13038                             struct verify_chunk *chunk, int verbose)
13039 {
13040         const size_t buflen = 4 * 1024 * 1024; /* 4M */
13041         void *buf;
13042         size_t page_size;
13043         ssize_t bytes_read;
13044         ssize_t bytes_done;
13045         size_t count;
13046         off_t pos;
13047         unsigned long crc;
13048         unsigned long crc_array[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
13049         int i;
13050         int rc = 0;
13051
13052         if (file_size == 0)
13053                 return 0;
13054
13055         page_size = sysconf(_SC_PAGESIZE);
13056         if (page_size < 0) {
13057                 rc = -errno;
13058                 return rc;
13059         }
13060
13061         rc = posix_memalign(&buf, page_size, buflen);
13062         if (rc) /* error code is returned directly */
13063                 return -rc;
13064
13065         if (verbose > 1) {
13066                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
13067                         PEXT(&chunk->chunk));
13068                 for (i = 0; i < chunk->mirror_count; i++)
13069                         fprintf(stdout, " %u", chunk->mirror_id[i]);
13070                 fprintf(stdout, "\n");
13071         }
13072
13073         bytes_done = 0;
13074         count = MIN(chunk->chunk.e_end, file_size) - chunk->chunk.e_start;
13075         pos = chunk->chunk.e_start;
13076         while (bytes_done < count) {
13077                 /* compute initial CRC-32 checksum */
13078                 crc = crc32(0L, Z_NULL, 0);
13079                 memset(crc_array, 0, sizeof(crc_array));
13080
13081                 bytes_read = 0;
13082                 for (i = 0; i < chunk->mirror_count; i++) {
13083                         bytes_read = llapi_mirror_read(fd, chunk->mirror_id[i],
13084                                                        buf, buflen, pos);
13085                         if (bytes_read < 0) {
13086                                 rc = bytes_read;
13087                                 fprintf(stderr,
13088                                         "%s: failed to read data from mirror %u: %s.\n",
13089                                         progname, chunk->mirror_id[i],
13090                                         strerror(-rc));
13091                                 goto error;
13092                         }
13093
13094                         /* compute new CRC-32 checksum */
13095                         crc_array[i] = crc32(crc, buf, bytes_read);
13096                 }
13097
13098                 if (verbose)
13099                         print_checksums(chunk, crc_array, pos, buflen);
13100
13101                 /* compare CRC-32 checksum values */
13102                 for (i = 1; i < chunk->mirror_count; i++) {
13103                         if (crc_array[i] != crc_array[0]) {
13104                                 rc = -EINVAL;
13105
13106                                 fprintf(stderr,
13107                                         "%s: chunk "DEXT" has different checksum value on mirror %u:%lx and mirror %u:%lx.\n",
13108                                         progname, PEXT(&chunk->chunk),
13109                                         chunk->mirror_id[0], crc_array[0],
13110                                         chunk->mirror_id[i], crc_array[i]);
13111                                 print_checksums(chunk, crc_array, pos, buflen);
13112                         }
13113                 }
13114
13115                 pos += bytes_read;
13116                 bytes_done += bytes_read;
13117         }
13118
13119         if (verbose > 1 && rc == 0) {
13120                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
13121                         PEXT(&chunk->chunk));
13122                 for (i = 0; i < chunk->mirror_count; i++)
13123                         fprintf(stdout, " %u", chunk->mirror_id[i]);
13124                 fprintf(stdout, " PASS\n\n");
13125         }
13126
13127 error:
13128         free(buf);
13129         return rc;
13130 }
13131
13132 /**
13133  * lfs_mirror_verify_file() - Verify a mirrored file.
13134  * @fname:      Mirrored file name.
13135  * @mirror_ids: Specified mirror ids to be verified.
13136  * @ids_nr:     Number of specified mirror ids.
13137  * @verbose:    Verbose mode.
13138  *
13139  * This function verifies that each SYNC mirror of a mirrored file
13140  * specified by @fname contains exactly the same data.
13141  *
13142  * If @mirror_ids is specified, then the function will verify the
13143  * mirrors specified by @mirror_ids contain exactly the same data.
13144  *
13145  * If @verbose is specified, then the function will print where the
13146  * differences are if the data do not match. Otherwise, it will
13147  * just return an error in that case.
13148  *
13149  * Return: 0 on success or a negative error code on failure.
13150  */
13151 static inline
13152 int lfs_mirror_verify_file(const char *fname, __u16 *mirror_ids, int ids_nr,
13153                            int verbose)
13154 {
13155         struct verify_chunk chunks_array[1024] = { };
13156         struct llapi_layout *layout = NULL;
13157         struct stat stbuf;
13158         uint32_t flr_state;
13159         int fd;
13160         int chunk_count = 0;
13161         int idx = 0;
13162         int rc = 0;
13163         int rc1 = 0;
13164         int rc2 = 0;
13165
13166         if (stat(fname, &stbuf) < 0) {
13167                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
13168                         progname, fname, strerror(errno));
13169                 rc = -errno;
13170                 goto error;
13171         }
13172
13173         if (!S_ISREG(stbuf.st_mode)) {
13174                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
13175                         progname, fname);
13176                 rc = -EINVAL;
13177                 goto error;
13178         }
13179
13180         if (stbuf.st_size == 0) {
13181                 if (verbose)
13182                         fprintf(stdout, "%s: '%s' file size is 0.\n",
13183                                 progname, fname);
13184                 rc = 0;
13185                 goto error;
13186         }
13187
13188         /* Allow mirror verify even without the key on encrypted files */
13189         fd = open(fname, O_DIRECT | O_RDONLY | O_CIPHERTEXT);
13190         if (fd < 0) {
13191                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
13192                         progname, fname, strerror(errno));
13193                 rc = -errno;
13194                 goto error;
13195         }
13196
13197         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
13198         if (rc < 0) {
13199                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
13200                         progname, fname, strerror(errno));
13201                 goto close_fd;
13202         }
13203
13204         layout = llapi_layout_get_by_fd(fd, 0);
13205         if (!layout) {
13206                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
13207                         progname, fname, strerror(errno));
13208                 rc = -errno;
13209                 llapi_lease_release(fd);
13210                 goto close_fd;
13211         }
13212
13213         rc = llapi_layout_flags_get(layout, &flr_state);
13214         if (rc < 0) {
13215                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
13216                         progname, fname, strerror(errno));
13217                 rc = -errno;
13218                 goto free_layout;
13219         }
13220
13221         flr_state &= LCM_FL_FLR_MASK;
13222         switch (flr_state) {
13223         case LCM_FL_NONE:
13224                 rc = -EINVAL;
13225                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
13226                         progname, fname, llapi_layout_flags_string(flr_state));
13227                 goto free_layout;
13228         default:
13229                 break;
13230         }
13231
13232         /* find out mirror chunks to be verified */
13233         chunk_count = lfs_mirror_prepare_chunk(layout, chunks_array,
13234                                                ARRAY_SIZE(chunks_array));
13235         if (chunk_count < 0) {
13236                 rc = chunk_count;
13237                 goto free_layout;
13238         }
13239
13240         if (ids_nr > 0)
13241                 /* filter specified mirror ids */
13242                 filter_mirror_id(chunks_array, chunk_count, mirror_ids, ids_nr);
13243
13244         if (verbose > 2)
13245                 print_chunks(fname, chunks_array, chunk_count);
13246
13247         for (idx = 0; idx < chunk_count; idx++) {
13248                 if (chunks_array[idx].chunk.e_start >= stbuf.st_size) {
13249                         if (verbose)
13250                                 fprintf(stdout,
13251                                         "%s: '%s' chunk "DEXT" exceeds file size %#llx: skipped\n",
13252                                         progname, fname,
13253                                         PEXT(&chunks_array[idx].chunk),
13254                                         (unsigned long long)stbuf.st_size);
13255                         break;
13256                 }
13257
13258                 if (chunks_array[idx].mirror_count == 0) {
13259                         fprintf(stderr,
13260                                 "%s: '%s' chunk "DEXT" is invalid in all of the mirrors: ",
13261                                 progname, fname,
13262                                 PEXT(&chunks_array[idx].chunk));
13263                         if (verbose) {
13264                                 fprintf(stderr, "skipped\n");
13265                                 continue;
13266                         }
13267                         rc = -EINVAL;
13268                         fprintf(stderr, "failed\n");
13269                         goto free_layout;
13270                 }
13271
13272                 if (chunks_array[idx].mirror_count == 1) {
13273                         if (verbose)
13274                                 fprintf(stdout,
13275                                         "%s: '%s' chunk "DEXT" is only valid in mirror %u: skipped\n",
13276                                         progname, fname,
13277                                         PEXT(&chunks_array[idx].chunk),
13278                                         chunks_array[idx].mirror_id[0]);
13279                         continue;
13280                 }
13281
13282                 rc = llapi_lease_check(fd);
13283                 if (rc != LL_LEASE_RDLCK) {
13284                         fprintf(stderr, "%s: '%s' lost lease lock.\n",
13285                                 progname, fname);
13286                         goto free_layout;
13287                 }
13288
13289                 /* verify one chunk */
13290                 rc1 = lfs_mirror_verify_chunk(fd, stbuf.st_size,
13291                                               &chunks_array[idx], verbose);
13292                 if (rc1 < 0) {
13293                         rc2 = rc1;
13294                         if (!verbose) {
13295                                 rc = rc1;
13296                                 goto free_layout;
13297                         }
13298                 }
13299         }
13300
13301         if (rc2 < 0)
13302                 rc = rc2;
13303
13304 free_layout:
13305         llapi_layout_free(layout);
13306         llapi_lease_release(fd);
13307 close_fd:
13308         close(fd);
13309 error:
13310         return rc;
13311 }
13312
13313 /**
13314  * lfs_mirror_verify() - Parse and execute lfs mirror verify command.
13315  * @argc: The count of lfs mirror verify command line arguments.
13316  * @argv: Array of strings for lfs mirror verify command line arguments.
13317  *
13318  * This function parses lfs mirror verify command and verifies the
13319  * specified mirrored file(s).
13320  *
13321  * Return: 0 on success or a negative error code on failure.
13322  */
13323 static inline int lfs_mirror_verify(int argc, char **argv)
13324 {
13325         __u16 mirror_ids[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
13326         int ids_nr = 0;
13327         int c;
13328         int verbose = 0;
13329         int rc = 0;
13330         int rc1 = 0;
13331         char cmd[PATH_MAX];
13332
13333         struct option long_opts[] = {
13334         { .val = 'h',   .name = "help",         .has_arg = no_argument },
13335         { .val = 'o',   .name = "only",         .has_arg = required_argument },
13336         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
13337         { .name = NULL } };
13338
13339         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
13340         progname = cmd;
13341         while ((c = getopt_long(argc, argv, "ho:v", long_opts, NULL)) >= 0) {
13342                 switch (c) {
13343                 case 'o':
13344                         rc = parse_mirror_ids(mirror_ids,
13345                                               ARRAY_SIZE(mirror_ids),
13346                                               optarg);
13347                         if (rc < 0) {
13348                                 fprintf(stderr,
13349                                         "%s: bad mirror ids '%s'.\n",
13350                                         progname, optarg);
13351                                 goto error;
13352                         }
13353                         ids_nr = rc;
13354                         if (ids_nr < 2) {
13355                                 fprintf(stderr,
13356                                         "%s: at least 2 mirror ids needed with '--only' option.\n",
13357                                         progname);
13358                                 rc = CMD_HELP;
13359                                 goto error;
13360                         }
13361                         break;
13362                 case 'v':
13363                         verbose++;
13364                         break;
13365                 default:
13366                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13367                                 progname, argv[optind - 1]);
13368                         fallthrough;
13369                 case 'h':
13370                         rc = CMD_HELP;
13371                         goto error;
13372                 }
13373         }
13374
13375         if (argc == optind) {
13376                 fprintf(stderr, "%s: no file name given.\n", progname);
13377                 rc = CMD_HELP;
13378                 goto error;
13379         }
13380
13381         if (ids_nr > 0 && argc > optind + 1) {
13382                 fprintf(stderr,
13383                         "%s: '--only' cannot be used upon multiple files.\n",
13384                         progname);
13385                 rc = CMD_HELP;
13386                 goto error;
13387         }
13388
13389         if (ids_nr > 0) {
13390                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
13391                 if (rc < 0)
13392                         goto error;
13393         }
13394
13395         rc = 0;
13396         for (; optind < argc; optind++) {
13397                 rc1 = lfs_mirror_verify_file(argv[optind], mirror_ids, ids_nr,
13398                                              verbose);
13399                 if (rc1 < 0)
13400                         rc = rc1;
13401         }
13402 error:
13403         return rc;
13404 }
13405
13406 /**
13407  * lfs_mirror() - Parse and execute lfs mirror commands.
13408  * @argc: The count of lfs mirror command line arguments.
13409  * @argv: Array of strings for lfs mirror command line arguments.
13410  *
13411  * This function parses lfs mirror commands and performs the
13412  * corresponding functions specified in mirror_cmdlist[].
13413  *
13414  * Return: 0 on success or an error code on failure.
13415  */
13416 static int lfs_mirror(int argc, char **argv)
13417 {
13418         char cmd[PATH_MAX];
13419         int rc = 0;
13420
13421         setlinebuf(stdout);
13422
13423         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
13424         progname = cmd;
13425         program_invocation_short_name = cmd;
13426         rc = cfs_parser(argc, argv, mirror_cmdlist);
13427
13428         return rc < 0 ? -rc : rc;
13429 }
13430
13431 static void lustre_som_swab(struct lustre_som_attrs *attrs)
13432 {
13433 #if __BYTE_ORDER == __BIG_ENDIAN
13434         __swab16s(&attrs->lsa_valid);
13435         __swab64s(&attrs->lsa_size);
13436         __swab64s(&attrs->lsa_blocks);
13437 #endif
13438 }
13439
13440 enum lfs_som_type {
13441         LFS_SOM_SIZE = 0x1,
13442         LFS_SOM_BLOCKS = 0x2,
13443         LFS_SOM_FLAGS = 0x4,
13444         LFS_SOM_ATTR_ALL = LFS_SOM_SIZE | LFS_SOM_BLOCKS |
13445                            LFS_SOM_FLAGS,
13446 };
13447
13448 static int lfs_getsom(int argc, char **argv)
13449 {
13450         const char *path;
13451         struct lustre_som_attrs *attrs;
13452         char buf[sizeof(*attrs) + 64];
13453         enum lfs_som_type type = LFS_SOM_ATTR_ALL;
13454         int rc = 0, c;
13455
13456         while ((c = getopt(argc, argv, "bfhs")) != -1) {
13457                 switch (c) {
13458                 case 'b':
13459                         type = LFS_SOM_BLOCKS;
13460                         break;
13461                 case 'f':
13462                         type = LFS_SOM_FLAGS;
13463                         break;
13464                 case 's':
13465                         type = LFS_SOM_SIZE;
13466                         break;
13467                 default:
13468                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13469                                 progname, argv[optind - 1]);
13470                         fallthrough;
13471                 case 'h':
13472                         return CMD_HELP;
13473                 }
13474         }
13475
13476         argc -= optind;
13477         argv += optind;
13478
13479         if (argc != 1) {
13480                 fprintf(stderr, "%s: %s\n",
13481                         progname, argc == 0 ? "miss file target" :
13482                         "input more than 2 files");
13483                 return CMD_HELP;
13484         }
13485
13486         path = argv[0];
13487         attrs = (void *)buf;
13488         rc = lgetxattr(path, "trusted.som", attrs, sizeof(buf));
13489         if (rc < 0) {
13490                 rc = -errno;
13491                 fprintf(stderr, "%s failed to get som xattr: %s (%d)\n",
13492                         argv[0], strerror(errno), errno);
13493                 return rc;
13494         }
13495
13496         lustre_som_swab(attrs);
13497
13498         switch (type) {
13499         case LFS_SOM_ATTR_ALL:
13500                 printf("file: %s size: %llu blocks: %llu flags: %x\n",
13501                        path, (unsigned long long)attrs->lsa_size,
13502                        (unsigned long long)attrs->lsa_blocks,
13503                        attrs->lsa_valid);
13504                 break;
13505         case LFS_SOM_SIZE:
13506                 printf("%llu\n", (unsigned long long)attrs->lsa_size);
13507                 break;
13508         case LFS_SOM_BLOCKS:
13509                 printf("%llu\n", (unsigned long long)attrs->lsa_blocks);
13510                 break;
13511         case LFS_SOM_FLAGS:
13512                 printf("%x\n", attrs->lsa_valid);
13513                 break;
13514         default:
13515                 fprintf(stderr, "%s: unknown option\n", progname);
13516                 return CMD_HELP;
13517         }
13518
13519         return 0;
13520 }
13521
13522 static int lfs_pcc_attach(int argc, char **argv)
13523 {
13524         struct option long_opts[] = {
13525         { .val = 'h',   .name = "help", .has_arg = no_argument },
13526         { .val = 'i',   .name = "id",   .has_arg = required_argument },
13527         { .val = 'r',   .name = "readonly",     .has_arg = no_argument },
13528         { .name = NULL } };
13529         int c;
13530         int rc = 0;
13531         __u32 attach_id = 0;
13532         const char *path;
13533         char *end;
13534         char fullpath[PATH_MAX];
13535         enum lu_pcc_type type = LU_PCC_READWRITE;
13536
13537         optind = 0;
13538         while ((c = getopt_long(argc, argv, "hi:r",
13539                                 long_opts, NULL)) != -1) {
13540                 switch (c) {
13541                 case 'i':
13542                         errno = 0;
13543                         attach_id = strtoul(optarg, &end, 0);
13544                         if (errno != 0 || *end != '\0' ||
13545                             attach_id == 0 || attach_id > UINT32_MAX) {
13546                                 fprintf(stderr,
13547                                         "error: %s: bad archive ID '%s'\n",
13548                                         progname, optarg);
13549                                 return CMD_HELP;
13550                         }
13551                         break;
13552                 case 'r':
13553                         type = LU_PCC_READONLY;
13554                         break;
13555                 case '?':
13556                         return CMD_HELP;
13557                 default:
13558                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13559                                 progname, argv[optind - 1]);
13560                         fallthrough;
13561                 case 'h':
13562                         return CMD_HELP;
13563                 }
13564         }
13565
13566         if (attach_id == 0) {
13567                 fprintf(stderr, "%s: must specify attach ID\n", argv[0]);
13568                 return CMD_HELP;
13569         }
13570
13571         if (argc <= optind) {
13572                 fprintf(stderr, "%s: must specify one or more file names\n",
13573                         argv[0]);
13574                 return CMD_HELP;
13575         }
13576
13577         while (optind < argc) {
13578                 int rc2;
13579
13580                 path = argv[optind++];
13581                 if (!realpath(path, fullpath)) {
13582                         fprintf(stderr, "%s: could not find path '%s': %s\n",
13583                                 argv[0], path, strerror(errno));
13584                         if (rc == 0)
13585                                 rc = -EINVAL;
13586                         continue;
13587                 }
13588
13589                 rc2 = llapi_pcc_attach(fullpath, attach_id, type);
13590                 if (rc2 < 0) {
13591                         fprintf(stderr,
13592                                 "%s: cannot attach '%s' to PCC with attach ID '%u': %s\n",
13593                                 argv[0], path, attach_id, strerror(-rc2));
13594                         if (rc == 0)
13595                                 rc = rc2;
13596                 }
13597         }
13598         return rc;
13599 }
13600
13601 static int lfs_pcc_attach_fid(int argc, char **argv)
13602 {
13603         struct option long_opts[] = {
13604         { .val = 'h',   .name = "help",         .has_arg = no_argument },
13605         { .val = 'i',   .name = "id",           .has_arg = required_argument },
13606         { .val = 'r',   .name = "readonly",     .has_arg = no_argument },
13607         { .val = 'm',   .name = "mnt",          .has_arg = required_argument },
13608         { .name = NULL } };
13609         int c;
13610         int rc = 0;
13611         __u32 attach_id = 0;
13612         char *end;
13613         const char *mntpath = NULL;
13614         const char *fidstr;
13615         enum lu_pcc_type type = LU_PCC_READWRITE;
13616
13617         optind = 0;
13618         while ((c = getopt_long(argc, argv, "hi:m:r",
13619                                 long_opts, NULL)) != -1) {
13620                 switch (c) {
13621                 case 'i':
13622                         errno = 0;
13623                         attach_id = strtoul(optarg, &end, 0);
13624                         if (errno != 0 || *end != '\0' ||
13625                             attach_id > UINT32_MAX) {
13626                                 fprintf(stderr,
13627                                         "error: %s: bad attach ID '%s'\n",
13628                                         argv[0], optarg);
13629                                 return CMD_HELP;
13630                         }
13631                         break;
13632                 case 'r':
13633                         type = LU_PCC_READONLY;
13634                         break;
13635                 case 'm':
13636                         mntpath = optarg;
13637                         break;
13638                 default:
13639                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13640                                 progname, argv[optind - 1]);
13641                         fallthrough;
13642                 case 'h':
13643                         return CMD_HELP;
13644                 }
13645         }
13646
13647         if (attach_id == 0) {
13648                 fprintf(stderr, "%s: must specify an archive ID\n", argv[0]);
13649                 return CMD_HELP;
13650         }
13651
13652         if (!mntpath) {
13653                 fprintf(stderr, "%s: must specify Lustre mount point\n",
13654                         argv[0]);
13655                 return CMD_HELP;
13656         }
13657
13658         if (argc <= optind) {
13659                 fprintf(stderr, "%s: must specify one or more fids\n", argv[0]);
13660                 return CMD_HELP;
13661         }
13662
13663         while (optind < argc) {
13664                 int rc2;
13665
13666                 fidstr = argv[optind++];
13667
13668                 rc2 = llapi_pcc_attach_fid_str(mntpath, fidstr,
13669                                                attach_id, type);
13670                 if (rc2 < 0) {
13671                         fprintf(stderr,
13672                                 "%s: cannot attach '%s' on '%s' to PCC with attach ID '%u': %s\n",
13673                                 argv[0], fidstr, mntpath, attach_id,
13674                                 strerror(rc2));
13675                 }
13676                 if (rc == 0 && rc2 < 0)
13677                         rc = rc2;
13678         }
13679         return rc;
13680 }
13681
13682 static int lfs_pcc_detach(int argc, char **argv)
13683 {
13684         struct option long_opts[] = {
13685         { .val = 'h',   .name = "help", .has_arg = no_argument },
13686         { .val = 'k',   .name = "keep", .has_arg = no_argument },
13687         { .name = NULL } };
13688         int c;
13689         int rc = 0;
13690         const char *path;
13691         char fullpath[PATH_MAX];
13692         __u32 detach_opt = PCC_DETACH_OPT_UNCACHE;
13693
13694         optind = 0;
13695         while ((c = getopt_long(argc, argv, "hk",
13696                                 long_opts, NULL)) != -1) {
13697                 switch (c) {
13698                 case 'k':
13699                         detach_opt = PCC_DETACH_OPT_NONE;
13700                         break;
13701                 default:
13702                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13703                                 progname, argv[optind - 1]);
13704                         fallthrough;
13705                 case 'h':
13706                         return CMD_HELP;
13707                 }
13708         }
13709
13710         while (optind < argc) {
13711                 int rc2;
13712
13713                 path = argv[optind++];
13714                 if (!realpath(path, fullpath)) {
13715                         fprintf(stderr, "%s: could not find path '%s': %s\n",
13716                                 argv[0], path, strerror(errno));
13717                         if (rc == 0)
13718                                 rc = -EINVAL;
13719                         continue;
13720                 }
13721
13722                 rc2 = llapi_pcc_detach_file(fullpath, detach_opt);
13723                 if (rc2 < 0) {
13724                         rc2 = -errno;
13725                         fprintf(stderr,
13726                                 "%s: cannot detach '%s' from PCC: %s\n",
13727                                 argv[0], path, strerror(errno));
13728                         if (rc == 0)
13729                                 rc = rc2;
13730                 }
13731         }
13732         return rc;
13733 }
13734
13735 static int lfs_pcc_detach_fid(int argc, char **argv)
13736 {
13737         struct option long_opts[] = {
13738         { .val = 'h',   .name = "help", .has_arg = no_argument },
13739         { .val = 'k',   .name = "keep", .has_arg = no_argument },
13740         { .name = NULL } };
13741         int c;
13742         int rc = 0;
13743         const char *fid;
13744         const char *mntpath;
13745         __u32 detach_opt = PCC_DETACH_OPT_UNCACHE;
13746
13747         optind = 0;
13748         while ((c = getopt_long(argc, argv, "hk",
13749                                 long_opts, NULL)) != -1) {
13750                 switch (c) {
13751                 case 'k':
13752                         detach_opt = PCC_DETACH_OPT_NONE;
13753                         break;
13754                 default:
13755                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13756                                 progname, argv[optind - 1]);
13757                         fallthrough;
13758                 case 'h':
13759                         return CMD_HELP;
13760                 }
13761         }
13762
13763         mntpath = argv[optind++];
13764
13765         while (optind < argc) {
13766                 int rc2;
13767
13768                 fid = argv[optind++];
13769
13770                 rc2 = llapi_pcc_detach_fid_str(mntpath, fid, detach_opt);
13771                 if (rc2 < 0) {
13772                         fprintf(stderr,
13773                                 "%s: cannot detach '%s' on '%s' from PCC: %s\n",
13774                                 argv[0], fid, mntpath, strerror(-rc2));
13775                         if (rc == 0)
13776                                 rc = rc2;
13777                 }
13778         }
13779         return rc;
13780 }
13781
13782 static int lfs_pcc_state(int argc, char **argv)
13783 {
13784         int rc = 0;
13785         const char *path;
13786         char fullpath[PATH_MAX];
13787         struct lu_pcc_state state;
13788
13789         optind = 1;
13790
13791         if (argc <= 1) {
13792                 fprintf(stderr, "%s: must specify one or more file names\n",
13793                         progname);
13794                 return CMD_HELP;
13795         }
13796
13797         while (optind < argc) {
13798                 int rc2;
13799
13800                 path = argv[optind++];
13801                 if (!realpath(path, fullpath)) {
13802                         fprintf(stderr, "%s: could not find path '%s': %s\n",
13803                                 argv[0], path, strerror(errno));
13804                         if (rc == 0)
13805                                 rc = -EINVAL;
13806                         continue;
13807                 }
13808
13809                 rc2 = llapi_pcc_state_get(fullpath, &state);
13810                 if (rc2 < 0) {
13811                         if (rc == 0)
13812                                 rc = rc2;
13813                         fprintf(stderr,
13814                                 "%s: cannot get PCC state of '%s': %s\n",
13815                                 argv[0], path, strerror(-rc2));
13816                         continue;
13817                 }
13818
13819                 printf("file: %s", path);
13820                 printf(", type: %s", pcc_type2string(state.pccs_type));
13821                 if (state.pccs_type == LU_PCC_NONE &&
13822                     state.pccs_open_count == 0) {
13823                         printf("\n");
13824                         continue;
13825                 }
13826
13827                 printf(", PCC file: %s", state.pccs_path);
13828                 printf(", user number: %u", state.pccs_open_count);
13829                 printf(", flags: %x", state.pccs_flags);
13830                 printf("\n");
13831         }
13832         return rc;
13833 }
13834
13835 /**
13836  * lfs_pcc() - Parse and execute lfs pcc commands.
13837  * @argc: The count of lfs pcc command line arguments.
13838  * @argv: Array of strings for lfs pcc command line arguments.
13839  *
13840  * This function parses lfs pcc commands and performs the
13841  * corresponding functions specified in pcc_cmdlist[].
13842  *
13843  * Return: 0 on success or an error code on failure.
13844  */
13845 static int lfs_pcc(int argc, char **argv)
13846 {
13847         char cmd[PATH_MAX];
13848         int rc = 0;
13849
13850         setlinebuf(stdout);
13851
13852         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
13853         progname = cmd;
13854         program_invocation_short_name = cmd;
13855         rc = cfs_parser(argc, argv, pcc_cmdlist);
13856
13857         return rc < 0 ? -rc : rc;
13858 }
13859
13860 int main(int argc, char **argv)
13861 {
13862         int rc;
13863
13864         /* Ensure that liblustreapi constructor has run */
13865         if (!llapi_liblustreapi_initialized())
13866                 fprintf(stderr, "liblustreapi was not properly initialized\n");
13867
13868         setlinebuf(stdout);
13869         opterr = 0;
13870
13871         progname = program_invocation_short_name; /* Used in error messages */
13872         llapi_set_command_name(argv[1]);
13873         rc = cfs_parser(argc, argv, cmdlist);
13874         llapi_clear_command_name();
13875
13876         return rc < 0 ? -rc : rc;
13877 }