Whamcloud - gitweb
LU-17667 tests: Handle more than 1 IP returned by 'ip' cmd
[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][-D] {-u|-U|-g|-G|-p|-P} {-b|-B|-i|-I LIMIT} [--pool POOL] FILESYSTEM\n"
426          "       setquota {-u|-g|-p} --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 [-q] [-v] [h] {-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_set(layout, 0,
4525                                                 LLAPI_LAYOUT_DEFAULT);
4526                                 if (result) {
4527                                         fprintf(stderr,
4528                                                 "%s: set default ost index failed: %s\n",
4529                                                 progname, strerror(errno));
4530                                         result = -errno;
4531                                         goto error;
4532                                 }
4533                         }
4534
4535                         result = lfs_migrate(fname, migration_flags, param,
4536                                              layout, bandwidth_bytes_sec,
4537                                              stats_interval_sec);
4538                 } else if (comp_set != 0) {
4539                         result = lfs_component_set(fname, comp_id,
4540                                                    lsa.lsa_pool_name,
4541                                                    lsa.lsa_comp_flags,
4542                                                    lsa.lsa_comp_neg_flags);
4543                 } else if (comp_del != 0) {
4544                         result = lfs_component_del(fname, comp_id,
4545                                                    lsa.lsa_comp_flags,
4546                                                    lsa.lsa_comp_neg_flags);
4547                 } else if (comp_add != 0) {
4548                         result = lfs_component_add(fname, layout);
4549                 } else if (opc == SO_MIRROR_CREATE) {
4550                         result = mirror_create(fname, mirror_list);
4551                 } else if (opc == SO_MIRROR_EXTEND) {
4552                         result = mirror_extend(fname, mirror_list,
4553                                                mirror_flags,
4554                                                bandwidth_bytes_sec,
4555                                                stats_interval_sec);
4556                 } else if (opc == SO_MIRROR_SPLIT || opc == SO_MIRROR_DELETE) {
4557                         if (!mirror_id && !comp_id && !lsa.lsa_pool_name) {
4558                                 fprintf(stderr,
4559                                         "%s: no mirror id, component id, or pool name specified to delete from '%s'\n",
4560                                         progname, fname);
4561                                 goto usage_error;
4562                         }
4563                         if (lsa.lsa_pool_name)
4564                                 mirror_flags |= MF_COMP_POOL;
4565                         else if (mirror_id != 0)
4566                                 comp_id = mirror_id;
4567                         else
4568                                 mirror_flags |= MF_COMP_ID;
4569                         if (has_m_file && !strcmp(fname, mirror_list->m_file)) {
4570                                 fprintf(stderr,
4571                                         "%s: the file specified by -f cannot be same as the source file '%s'\n",
4572                                         progname, fname);
4573                                 goto usage_error;
4574                         }
4575                         result = mirror_split(fname, comp_id, lsa.lsa_pool_name,
4576                                               mirror_flags,
4577                                               has_m_file ? mirror_list->m_file :
4578                                               NULL);
4579                 } else if (layout) {
4580                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
4581                                                       mode, layout);
4582                         if (result >= 0) {
4583                                 close(result);
4584                                 result = 0;
4585                         }
4586                 } else if (foreign_mode) {
4587                         result = llapi_file_create_foreign(fname, mode, type,
4588                                                            flags, xattr);
4589                         if (result >= 0) {
4590                                 close(result);
4591                                 result = 0;
4592                         }
4593                 } else {
4594                         result = llapi_file_open_param(fname,
4595                                                        O_CREAT | O_WRONLY,
4596                                                        mode, param);
4597                         if (result >= 0) {
4598                                 close(result);
4599                                 result = 0;
4600                         }
4601                 }
4602                 if (result) {
4603                         /* Save the first error encountered. */
4604                         if (result2 == 0)
4605                                 result2 = result;
4606                         continue;
4607                 }
4608         }
4609
4610         if (mode_opt)
4611                 umask(previous_umask);
4612
4613         free(param);
4614         free(migrate_mdt_param.fp_lmv_md);
4615         llapi_layout_free(layout);
4616         lfs_mirror_list_free(mirror_list);
4617         return result2;
4618 usage_error:
4619         result = CMD_HELP;
4620 error:
4621         llapi_layout_free(layout);
4622         lfs_mirror_list_free(mirror_list);
4623         return result;
4624 }
4625
4626 static int lfs_poollist(int argc, char **argv)
4627 {
4628         if (argc != 2)
4629                 return CMD_HELP;
4630
4631         return llapi_poollist(argv[1]);
4632 }
4633
4634 #define FP_DEFAULT_TIME_MARGIN (24 * 60 * 60)
4635 static int set_time(struct find_param *param, time_t *time, time_t *set,
4636                     char *str)
4637 {
4638         long long t = 0;
4639         int sign = 0;
4640         char *endptr = "AD";
4641         char *timebuf;
4642
4643         if (str[0] == '+')
4644                 sign = 1;
4645         else if (str[0] == '-')
4646                 sign = -1;
4647
4648         if (sign)
4649                 str++;
4650
4651         for (timebuf = str; *endptr && *(endptr + 1); timebuf = endptr + 1) {
4652                 long long val = strtoll(timebuf, &endptr, 0);
4653                 int unit = 1;
4654
4655                 switch (*endptr) {
4656                 case  'y':
4657                         unit *= 52; /* 52 weeks + 1 day below */
4658                         fallthrough;
4659                 case  'w':
4660                         unit *= 7;
4661                         if (param->fp_time_margin == FP_DEFAULT_TIME_MARGIN)
4662                                 param->fp_time_margin *= (1 + unit / 52);
4663                         unit += (*endptr == 'y'); /* +1 day for 365 days/year */
4664                         fallthrough;
4665                 case '\0': /* days are default unit if none used */
4666                         fallthrough;
4667                 case  'd':
4668                         unit *= 24;
4669                         fallthrough;
4670                 case  'h':
4671                         unit *= 60;
4672                         fallthrough;
4673                 case  'm':
4674                         unit *= 60;
4675                         fallthrough;
4676                 case  's':
4677                         break;
4678                         /* don't need to multiply by 1 for seconds */
4679                 default:
4680                         fprintf(stderr,
4681                                 "%s find: bad time string '%s': %s\n",
4682                                 progname, timebuf, strerror(EINVAL));
4683                         return INT_MAX;
4684                 }
4685
4686                 if (param->fp_time_margin == 0 ||
4687                     (*endptr && unit < param->fp_time_margin))
4688                         param->fp_time_margin = unit;
4689
4690                 t += val * unit;
4691         }
4692         if (*time < t) {
4693                 if (sign != 0)
4694                         str--;
4695                 fprintf(stderr, "%s find: bad time '%s': too large\n",
4696                         progname, str);
4697                 return INT_MAX;
4698         }
4699
4700         *set = *time - t;
4701
4702         return sign;
4703 }
4704
4705 static int str2quotaid(__u32 *id, const char *arg)
4706 {
4707         unsigned long int projid_tmp = 0;
4708         char *endptr = NULL;
4709
4710         projid_tmp = strtoul(arg, &endptr, 10);
4711         if (*endptr != '\0')
4712                 return -EINVAL;
4713         /* UINT32_MAX is not allowed - see projid_valid()/INVALID_PROJID */
4714         if (projid_tmp >= UINT32_MAX)
4715                 return -ERANGE;
4716
4717         *id = projid_tmp;
4718         return 0;
4719 }
4720
4721 static int name2uid(unsigned int *id, const char *name)
4722 {
4723         struct passwd *passwd;
4724
4725         passwd = getpwnam(name);
4726         if (!passwd)
4727                 return -ENOENT;
4728         *id = passwd->pw_uid;
4729
4730         return 0;
4731 }
4732
4733 static int name2gid(unsigned int *id, const char *name)
4734 {
4735         struct group *group;
4736
4737         group = getgrnam(name);
4738         if (!group)
4739                 return -ENOENT;
4740         *id = group->gr_gid;
4741
4742         return 0;
4743 }
4744
4745 static inline int name2projid(unsigned int *id, const char *name)
4746 {
4747         return -ENOTSUP;
4748 }
4749
4750 static int uid2name(char **name, unsigned int id)
4751 {
4752         struct passwd *passwd;
4753
4754         passwd = getpwuid(id);
4755         if (!passwd)
4756                 return -ENOENT;
4757         *name = passwd->pw_name;
4758
4759         return 0;
4760 }
4761
4762 static inline int gid2name(char **name, unsigned int id)
4763 {
4764         struct group *group;
4765
4766         group = getgrgid(id);
4767         if (!group)
4768                 return -ENOENT;
4769         *name = group->gr_name;
4770
4771         return 0;
4772 }
4773
4774 static int name2layout(__u32 *layout, char *name)
4775 {
4776         char *ptr, *layout_name;
4777
4778         *layout = 0;
4779         for (ptr = name; ; ptr = NULL) {
4780                 layout_name = strtok(ptr, ",");
4781                 if (!layout_name)
4782                         break;
4783                 if (strcmp(layout_name, "released") == 0)
4784                         *layout |= LOV_PATTERN_F_RELEASED;
4785                 else if (strcmp(layout_name, "raid0") == 0)
4786                         *layout |= LOV_PATTERN_RAID0;
4787                 else if (strcmp(layout_name, "mdt") == 0)
4788                         *layout |= LOV_PATTERN_MDT;
4789                 else if (strcmp(layout_name, "overstriping") == 0)
4790                         *layout |= LOV_PATTERN_OVERSTRIPING;
4791                 else if (strcmp(layout_name, "foreign") == 0)
4792                         *layout |= LOV_PATTERN_FOREIGN;
4793                 else
4794                         return -1;
4795         }
4796         return 0;
4797 }
4798
4799 static int name2attrs(char *name, __u64 *attrs, __u64 *neg_attrs)
4800 {
4801         char *ptr, *attr_name = name;
4802         struct attrs_name *ap;
4803         int islongopt = 0; /* 1 true; 0 not known yet; -1 false. */
4804
4805         *attrs = 0;
4806         *neg_attrs = 0;
4807
4808         if (strchr(name, ','))
4809                 islongopt = 1;
4810
4811         for (ptr = name; ; ptr = NULL) {
4812                 if (islongopt != -1)
4813                         attr_name = strtok(ptr, ",");
4814                 else
4815                         attr_name = attr_name + 1;
4816                 if (!attr_name || *attr_name == '\0')
4817                         break;
4818
4819                 for (ap = (struct attrs_name *)attrs_array;
4820                      ap->an_attr != 0;
4821                      ap++) {
4822                         if (islongopt != -1 &&
4823                             strcmp(attr_name, ap->an_name) == 0) {
4824                                 *attrs |= ap->an_attr;
4825                                 islongopt = 1;
4826                                 break;
4827                         } else if (islongopt != -1 && attr_name[0] == '^' &&
4828                                    strcmp(attr_name + 1, ap->an_name) == 0) {
4829                                 *neg_attrs |= ap->an_attr;
4830                                 islongopt = 1;
4831                                 break;
4832                         } else if (islongopt != 1 &&
4833                                    *attr_name == ap->an_shortname) {
4834                                 *attrs |= ap->an_attr;
4835                                 islongopt = -1;
4836                                 break;
4837                         } else if (islongopt != 1 && *attr_name == '^' &&
4838                                    attr_name[1] == ap->an_shortname) {
4839                                 *neg_attrs |= ap->an_attr;
4840                                 islongopt = -1;
4841                                 attr_name++;
4842                                 break;
4843                         }
4844                 }
4845
4846                 if (ap->an_attr == 0) {
4847                         /* provided attr is unknown */
4848                         fprintf(stderr, "error: bad attribute name '%s'\n",
4849                                 attr_name);
4850                         return -1;
4851                 }
4852         }
4853         return 0;
4854 }
4855
4856 /**
4857  * xattr_match_info_append() - add the supplied name and value regex patterns
4858  *     to the supplied xattr_match_info struct.
4859  *
4860  * Return: 0 for success, nonzero if any errors encountered.
4861  */
4862 int xattr_match_info_append(struct xattr_match_info *xmi, bool exclude,
4863                             char *name_pattern, char *value_pattern)
4864 {
4865         int flags = REG_EXTENDED;
4866         char *err_buf;
4867         int err_len;
4868         void *nptr;
4869         int ret;
4870         int n;
4871
4872         if (xmi->xattr_name_buf == NULL) {
4873                 xmi->xattr_name_buf = malloc(XATTR_LIST_MAX);
4874                 if (xmi->xattr_name_buf == NULL)
4875                         goto err_out;
4876         }
4877
4878         if (xmi->xattr_value_buf == NULL) {
4879                 /*
4880                  * an xattr value need not be null-terminated, so allocate an
4881                  * extra byte to append a '\0', since regexec() expects a null-
4882                  * terminated string.
4883                  */
4884                 xmi->xattr_value_buf = malloc(XATTR_SIZE_MAX + 1);
4885                 if (xmi->xattr_value_buf == NULL)
4886                         goto err_out;
4887         }
4888
4889         n = ++xmi->xattr_regex_count;
4890
4891         nptr = realloc(xmi->xattr_regex_matched, n * sizeof(bool));
4892         if (nptr == NULL)
4893                 goto err_out;
4894         xmi->xattr_regex_matched = nptr;
4895
4896         nptr = realloc(xmi->xattr_regex_exclude, n * sizeof(bool));
4897         if (nptr == NULL)
4898                 goto err_out;
4899         xmi->xattr_regex_exclude = nptr;
4900
4901         nptr = realloc(xmi->xattr_regex_name, n * sizeof(regex_t *));
4902         if (nptr == NULL)
4903                 goto err_out;
4904         xmi->xattr_regex_name = nptr;
4905
4906         nptr = realloc(xmi->xattr_regex_value, n * sizeof(regex_t *));
4907         if (nptr == NULL)
4908                 goto err_out;
4909         xmi->xattr_regex_value = nptr;
4910
4911         n--;
4912
4913         xmi->xattr_regex_exclude[n] = exclude;
4914
4915         xmi->xattr_regex_name[n] = malloc(sizeof(regex_t));
4916         if (xmi->xattr_regex_name[n] == NULL)
4917                 goto err_out;
4918
4919         ret = regcomp(xmi->xattr_regex_name[n], name_pattern, flags);
4920         if (ret) {
4921                 err_len = regerror(ret, xmi->xattr_regex_name[n], NULL, 0);
4922                 err_buf = malloc(err_len);
4923                 if (err_buf == NULL)
4924                         goto err_out;
4925
4926                 regerror(ret, xmi->xattr_regex_name[n], err_buf, err_len);
4927                 fprintf(stderr, "%s: %s: %s\n",
4928                         progname, name_pattern, err_buf);
4929                 free(err_buf);
4930                 return ret;
4931         }
4932
4933         if (value_pattern && value_pattern[0] != '\0') {
4934                 xmi->xattr_regex_value[n] = malloc(sizeof(regex_t));
4935                 ret = regcomp(xmi->xattr_regex_value[n], value_pattern, flags);
4936                 if (ret) {
4937                         err_len = regerror(ret, xmi->xattr_regex_value[n],
4938                                            NULL, 0);
4939                         err_buf = malloc(err_len);
4940                         if (err_buf == NULL)
4941                                 goto err_out;
4942
4943                         regerror(ret, xmi->xattr_regex_value[n], err_buf,
4944                                  err_len);
4945                         fprintf(stderr, "%s: %s: %s\n",
4946                                 progname, value_pattern, err_buf);
4947                         free(err_buf);
4948                         return ret;
4949                 }
4950         } else {
4951                 xmi->xattr_regex_value[n] = NULL;
4952         }
4953
4954         return 0;
4955
4956 err_out:
4957         fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM));
4958         return -ENOMEM;
4959 }
4960
4961 void xattr_match_info_free(struct xattr_match_info *xmi)
4962 {
4963         int i;
4964
4965         free(xmi->xattr_regex_exclude);
4966         xmi->xattr_regex_exclude = NULL;
4967
4968         free(xmi->xattr_regex_matched);
4969         xmi->xattr_regex_matched = NULL;
4970
4971         for (i = 0; i < xmi->xattr_regex_count; i++) {
4972                 if (xmi->xattr_regex_name[i]) {
4973                         regfree(xmi->xattr_regex_name[i]);
4974                         free(xmi->xattr_regex_name[i]);
4975                 }
4976
4977                 if (xmi->xattr_regex_value[i]) {
4978                         regfree(xmi->xattr_regex_value[i]);
4979                         free(xmi->xattr_regex_value[i]);
4980                 }
4981         }
4982
4983         xmi->xattr_regex_count = 0;
4984
4985         free(xmi->xattr_regex_name);
4986         xmi->xattr_regex_name = NULL;
4987
4988         free(xmi->xattr_regex_value);
4989         xmi->xattr_regex_value = NULL;
4990
4991         free(xmi->xattr_name_buf);
4992         xmi->xattr_name_buf = NULL;
4993
4994         free(xmi->xattr_value_buf);
4995         xmi->xattr_value_buf = NULL;
4996 }
4997
4998 /**
4999  * compile_xattr_match_regex() - Compile regexes for matching xattr names and
5000  * values, returning an error if either fails to compile.
5001  *
5002  * The argument should be in the form "NAME=VALUE". The first '=' found
5003  * is assumed to be the separator between the name regex and the value regex.
5004  *
5005  * VALUE may be empty. If it is empty, it is not compiled and left NULL.
5006  * NAME must not be empty.
5007  *
5008  * Return: 0 if argument string is succesfully processed, nonzero if any
5009  *         errors encountered.
5010  */
5011 static int compile_xattr_match_regex(char *optarg, bool exclude,
5012                                      struct find_param *param)
5013 {
5014         char *sep;
5015
5016         sep = strchr(optarg, '=');
5017         if (sep)
5018                 *sep = '\0';
5019
5020         /* error if no NAME pattern specified */
5021         if (*optarg == '\0') {
5022                 fprintf(stderr, "%s: must specify xattr pattern\n", progname);
5023                 return CMD_HELP;
5024         }
5025
5026         /* if first -xattr option seen */
5027         if (param->fp_xattr_match_info == NULL) {
5028                 param->fp_xattr_match_info = calloc(1,
5029                                         sizeof(struct xattr_match_info));
5030                 if (param->fp_xattr_match_info == NULL) {
5031                         fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM));
5032                         return -ENOMEM;
5033                 }
5034         }
5035
5036         /*
5037          * if '=' was not provided, or if there is no value after the '=',
5038          * then pass NULL to xattr_match_info_append() so that no VALUE regex
5039          * is compiled.
5040          */
5041         if (sep) {
5042                 sep++;
5043                 if (*sep == '\0')
5044                         sep = NULL;
5045         }
5046
5047         return xattr_match_info_append(param->fp_xattr_match_info, exclude,
5048                                        optarg, sep);
5049 }
5050
5051 static int parse_symbolic(const char *input, mode_t *outmode, const char **end)
5052 {
5053         int loop;
5054         int user, group, other;
5055         int who, all;
5056         char c, op;
5057         mode_t perm;
5058         mode_t usermask;
5059         mode_t previous_flags;
5060
5061         user = group = other = 0;
5062         all = 0;
5063         loop = 1;
5064         perm = 0;
5065         previous_flags = 0;
5066         *end = input;
5067         usermask = 0;
5068
5069         while (loop) {
5070                 switch (*input) {
5071                 case 'u':
5072                         user = 1;
5073                         break;
5074                 case 'g':
5075                         group = 1;
5076                         break;
5077                 case 'o':
5078                         other = 1;
5079                         break;
5080                 case 'a':
5081                         user = group = other = 1;
5082                         all = 1;
5083                         break;
5084                 default:
5085                         loop = 0;
5086                 }
5087
5088                 if (loop)
5089                         input++;
5090         }
5091
5092         who = user || group || other;
5093         if (!who) {
5094                 /* get the umask */
5095                 usermask = umask(0022);
5096                 umask(usermask);
5097                 usermask &= 07777;
5098         }
5099
5100         if (*input == '-' || *input == '+' || *input == '=')
5101                 op = *input++;
5102         else
5103                 /* operation is required */
5104                 return -1;
5105
5106         /* get the flags in *outmode */
5107         switch (*input) {
5108         case 'u':
5109                 previous_flags = (*outmode & 0700);
5110                 perm |= user  ? previous_flags : 0;
5111                 perm |= group ? (previous_flags >> 3) : 0;
5112                 perm |= other ? (previous_flags >> 6) : 0;
5113                 input++;
5114                 goto write_perm;
5115         case 'g':
5116                 previous_flags = (*outmode & 0070);
5117                 perm |= user  ? (previous_flags << 3) : 0;
5118                 perm |= group ? previous_flags : 0;
5119                 perm |= other ? (previous_flags >> 3) : 0;
5120                 input++;
5121                 goto write_perm;
5122         case 'o':
5123                 previous_flags = (*outmode & 0007);
5124                 perm |= user  ? (previous_flags << 6) : 0;
5125                 perm |= group ? (previous_flags << 3) : 0;
5126                 perm |= other ? previous_flags : 0;
5127                 input++;
5128                 goto write_perm;
5129         default:
5130                 break;
5131         }
5132
5133         /* this part is optional,
5134          * if empty perm = 0 and *outmode is not modified
5135          */
5136         loop = 1;
5137         while (loop) {
5138                 c = *input;
5139                 switch (c) {
5140                 case 'r':
5141                         perm |= user  ? 0400 : 0;
5142                         perm |= group ? 0040 : 0;
5143                         perm |= other ? 0004 : 0;
5144                         /* set read permission for uog except for umask's
5145                          * permissions
5146                          */
5147                         perm |= who   ? 0 : (0444 & ~usermask);
5148                         break;
5149                 case 'w':
5150                         perm |= user  ? 0200 : 0;
5151                         perm |= group ? 0020 : 0;
5152                         perm |= other ? 0002 : 0;
5153                         /* set write permission for uog except for umask'
5154                          * permissions
5155                          */
5156                         perm |= who   ? 0 : (0222 & ~usermask);
5157                         break;
5158                 case 'x':
5159                         perm |= user  ? 0100 : 0;
5160                         perm |= group ? 0010 : 0;
5161                         perm |= other ? 0001 : 0;
5162                         /* set execute permission for uog except for umask'
5163                          * permissions
5164                          */
5165                         perm |= who   ? 0 : (0111 & ~usermask);
5166                         break;
5167                 case 'X':
5168                         /*
5169                          * Adds execute permission to 'u', 'g' and/or 'g' if
5170                          * specified and either 'u', 'g' or 'o' already has
5171                          * execute permissions.
5172                          */
5173                         if ((*outmode & 0111) != 0) {
5174                                 perm |= user  ? 0100 : 0;
5175                                 perm |= group ? 0010 : 0;
5176                                 perm |= other ? 0001 : 0;
5177                                 perm |= !who  ? 0111 : 0;
5178                         }
5179                         break;
5180                 case 's':
5181                         /* s is ignored if o is given, but it's not an error */
5182                         if (other && !group && !user)
5183                                 break;
5184                         perm |= user  ? S_ISUID : 0;
5185                         perm |= group ? S_ISGID : 0;
5186                         break;
5187                 case 't':
5188                         /* 't' should be used when 'a' is given
5189                          * or who is empty
5190                          */
5191                         perm |= (!who || all) ? S_ISVTX : 0;
5192                         /* using ugo with t is not an error */
5193                         break;
5194                 default:
5195                         loop = 0;
5196                         break;
5197                 }
5198                 if (loop)
5199                         input++;
5200         }
5201
5202 write_perm:
5203         /* uog flags should be only one character long */
5204         if (previous_flags && (*input != '\0' && *input != ','))
5205                 return -1;
5206
5207         switch (op) {
5208         case '-':
5209                 /* remove the flags from outmode */
5210                 *outmode &= ~perm;
5211                 break;
5212         case '+':
5213                 /* add the flags to outmode */
5214                 *outmode |= perm;
5215                 break;
5216         case '=':
5217                 /* set the flags of outmode to perm */
5218                 if (perm != 0)
5219                         *outmode = perm;
5220                 break;
5221         }
5222
5223         *end = input;
5224         return 0;
5225 }
5226
5227 static int str2mode_t(const char *input, mode_t *outmode)
5228 {
5229         int ret;
5230         const char *iter;
5231
5232         ret = 0;
5233
5234         if (*input >= '0' && *input <= '7') {
5235                 /* parse octal representation */
5236                 char *end;
5237
5238                 iter = input;
5239
5240                 /* look for invalid digits in octal representation */
5241                 while (isdigit(*iter))
5242                         if (*iter++ > '7')
5243                                 return -1;
5244
5245                 errno = 0;
5246                 *outmode = strtoul(input, &end, 8);
5247
5248                 if (errno != 0 || *outmode > 07777) {
5249                         *outmode = 0;
5250                         ret = -1;
5251                 }
5252
5253         } else if (*input == '8' || *input == '9') {
5254                 /* error: invalid octal number */
5255                 ret = -1;
5256         } else {
5257                 /* parse coma seperated list of symbolic representation */
5258                 int rc;
5259                 const char *end;
5260
5261                 *outmode = 0;
5262                 rc = 0;
5263                 end = NULL;
5264
5265                 do {
5266                         rc = parse_symbolic(input, outmode, &end);
5267                         if (rc)
5268                                 return -1;
5269
5270                         input = end+1;
5271                 } while (*end == ',');
5272
5273                 if (*end != '\0')
5274                         ret = -1;
5275         }
5276         return ret;
5277 }
5278
5279 static int lfs_find(int argc, char **argv)
5280 {
5281         int c, rc;
5282         int ret = 0;
5283         time_t t;
5284         struct find_param param = {
5285                 .fp_max_depth = -1,
5286                 .fp_quiet = 1,
5287                 .fp_time_margin = FP_DEFAULT_TIME_MARGIN,
5288         };
5289         struct option long_opts[] = {
5290         { .val = 'A',   .name = "atime",        .has_arg = required_argument },
5291         { .val = LFS_ATTRS_OPT,
5292                         .name = "attrs",        .has_arg = required_argument },
5293         { .val = 'b',   .name = "blocks",       .has_arg = required_argument },
5294         { .val = 'B',   .name = "btime",        .has_arg = required_argument },
5295         { .val = 'B',   .name = "Btime",        .has_arg = required_argument },
5296         { .val = LFS_COMP_COUNT_OPT,
5297                         .name = "comp-count",   .has_arg = required_argument },
5298         { .val = LFS_COMP_COUNT_OPT,
5299                         .name = "component-count",
5300                                                 .has_arg = required_argument },
5301         { .val = LFS_COMP_FLAGS_OPT,
5302                         .name = "comp-flags",   .has_arg = required_argument },
5303         { .val = LFS_COMP_FLAGS_OPT,
5304                         .name = "component-flags",
5305                                                 .has_arg = required_argument },
5306         { .val = LFS_COMP_START_OPT,
5307                         .name = "comp-start",   .has_arg = required_argument },
5308         { .val = LFS_COMP_START_OPT,
5309                         .name = "component-start",
5310                                                 .has_arg = required_argument },
5311         { .val = LFS_MIRROR_STATE_OPT,
5312                         .name = "mirror-state", .has_arg = required_argument },
5313         { .val = LFS_NEWERXY_OPT,
5314                         .name = "newer",        .has_arg = required_argument},
5315         { .val = LFS_NEWERXY_OPT,
5316                         .name = "neweraa",      .has_arg = required_argument},
5317         { .val = LFS_NEWERXY_OPT,
5318                         .name = "neweram",      .has_arg = required_argument},
5319         { .val = LFS_NEWERXY_OPT,
5320                         .name = "newerac",      .has_arg = required_argument},
5321         { .val = LFS_NEWERXY_OPT,
5322                         .name = "newerab",      .has_arg = required_argument},
5323         { .val = LFS_NEWERXY_OPT,
5324                         .name = "newerma",      .has_arg = required_argument},
5325         { .val = LFS_NEWERXY_OPT,
5326                         .name = "newermm",      .has_arg = required_argument},
5327         { .val = LFS_NEWERXY_OPT,
5328                         .name = "newermc",      .has_arg = required_argument},
5329         { .val = LFS_NEWERXY_OPT,
5330                         .name = "newermb",      .has_arg = required_argument},
5331         { .val = LFS_NEWERXY_OPT,
5332                         .name = "newerca",      .has_arg = required_argument},
5333         { .val = LFS_NEWERXY_OPT,
5334                         .name = "newercm",      .has_arg = required_argument},
5335         { .val = LFS_NEWERXY_OPT,
5336                         .name = "newercc",      .has_arg = required_argument},
5337         { .val = LFS_NEWERXY_OPT,
5338                         .name = "newercb",      .has_arg = required_argument},
5339         { .val = LFS_NEWERXY_OPT,
5340                         .name = "newerba",      .has_arg = required_argument},
5341         { .val = LFS_NEWERXY_OPT,
5342                         .name = "newerbm",      .has_arg = required_argument},
5343         { .val = LFS_NEWERXY_OPT,
5344                         .name = "newerbc",      .has_arg = required_argument},
5345         { .val = LFS_NEWERXY_OPT,
5346                         .name = "newerbb",      .has_arg = required_argument},
5347         { .val = LFS_NEWERXY_OPT,
5348                         .name = "newerBa",      .has_arg = required_argument},
5349         { .val = LFS_NEWERXY_OPT,
5350                         .name = "newerBm",      .has_arg = required_argument},
5351         { .val = LFS_NEWERXY_OPT,
5352                         .name = "newerBc",      .has_arg = required_argument},
5353         { .val = LFS_NEWERXY_OPT,
5354                         .name = "newerBB",      .has_arg = required_argument},
5355         { .val = LFS_NEWERXY_OPT,
5356                         .name = "newerat",      .has_arg = required_argument},
5357         { .val = LFS_NEWERXY_OPT,
5358                         .name = "newermt",      .has_arg = required_argument},
5359         { .val = LFS_NEWERXY_OPT,
5360                         .name = "newerct",      .has_arg = required_argument},
5361         { .val = LFS_NEWERXY_OPT,
5362                         .name = "newerbt",      .has_arg = required_argument},
5363         { .val = LFS_NEWERXY_OPT,
5364                         .name = "newerBt",      .has_arg = required_argument},
5365         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument },
5366         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument },
5367         { .val = 'C',   .name = "ctime",        .has_arg = required_argument },
5368 /* getstripe { .val = 'd', .name = "directory", .has_arg = no_argument }, */
5369         { .val = 'D',   .name = "maxdepth",     .has_arg = required_argument },
5370         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument },
5371         { .val = 'E',   .name = "component-end",
5372                                                 .has_arg = required_argument },
5373 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
5374         { .val = LFS_LAYOUT_FOREIGN_OPT,
5375                         .name = "foreign",      .has_arg = optional_argument},
5376         { .val = 'g',   .name = "gid",          .has_arg = required_argument },
5377         { .val = 'G',   .name = "group",        .has_arg = required_argument },
5378         { .val = 'h',   .name = "help",         .has_arg = no_argument },
5379         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
5380         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument },
5381         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument },
5382 /* getstripe { .val = 'I', .name = "comp-id",   .has_arg = required_argument }*/
5383         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
5384         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
5385         { .val = LFS_LINKS_OPT,
5386                         .name = "links",        .has_arg = required_argument },
5387         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
5388         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
5389         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument },
5390         { .val = 'M',   .name = "mtime",        .has_arg = required_argument },
5391         { .val = 'n',   .name = "name",         .has_arg = required_argument },
5392         { .val = 'N',   .name = "mirror-count", .has_arg = required_argument },
5393 /* find { .val = 'o'    .name = "or", .has_arg = no_argument }, like find(1) */
5394         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
5395         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
5396         { .val = LFS_FIND_PERM,
5397                         .name = "perm",         .has_arg = required_argument },
5398         /* no short option for pool yet, can be 'p' after 2.18 */
5399         { .val = LFS_POOL_OPT,
5400                         .name = "pool",         .has_arg = required_argument },
5401         { .val = '0',   .name = "print0",       .has_arg = no_argument },
5402         { .val = 'P',   .name = "print",        .has_arg = no_argument },
5403         { .val = LFS_PRINTF_OPT,
5404                         .name = "printf",       .has_arg = required_argument },
5405         { .val = LFS_PROJID_OPT,
5406                         .name = "projid",       .has_arg = required_argument },
5407 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
5408 /* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
5409 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
5410         { .val = 's',   .name = "size",         .has_arg = required_argument },
5411         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
5412         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
5413         { .val = 't',   .name = "type",         .has_arg = required_argument },
5414         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
5415         { .val = 'u',   .name = "uid",          .has_arg = required_argument },
5416         { .val = 'U',   .name = "user",         .has_arg = required_argument },
5417 /* getstripe { .val = 'v', .name = "verbose",   .has_arg = no_argument }, */
5418 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }, */
5419         { .val = LFS_XATTRS_MATCH_OPT,
5420                         .name = "xattr",        .has_arg = required_argument },
5421         { .val = 'z',   .name = "extension-size",
5422                                                 .has_arg = required_argument },
5423         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument },
5424         { .name = NULL } };
5425         int prev_optind = optind;
5426         int optidx = 0;
5427         int pathstart = -1;
5428         int pathend = -1;
5429         int neg_opt = 0;
5430         time_t *xtime;
5431         int *xsign;
5432         int isoption;
5433         char *endptr;
5434
5435         time(&t);
5436
5437         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
5438         while ((c = getopt_long_only(argc, argv,
5439                 "-0A:b:B:c:C:D:E:g:G:hH:i:lL:m:M:n:N:O:Ppqrs:S:t:T:u:U:z:",
5440                 long_opts, &optidx)) >= 0) {
5441                 xtime = NULL;
5442                 xsign = NULL;
5443                 if (neg_opt)
5444                         --neg_opt;
5445                 /* '!' is part of option */
5446                 /*
5447                  * when getopt_long_only() finds a string which is not
5448                  * an option nor a known option argument it returns 1
5449                  * in that case if we already have found pathstart and pathend
5450                  * (i.e. we have the list of pathnames),
5451                  * the only supported value is "!"
5452                  */
5453                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
5454                 if (!isoption && pathend != -1) {
5455                         fprintf(stderr,
5456                                 "err: %s: filename|dirname must either precede options or follow options\n",
5457                                 argv[0]);
5458                         ret = CMD_HELP;
5459                         goto err;
5460                 }
5461                 if (!isoption && pathstart == -1)
5462                         pathstart = prev_optind;
5463                 if (isoption && pathstart != -1 && pathend == -1)
5464                         pathend = prev_optind;
5465
5466                 prev_optind = optind;
5467
5468                 switch (c) {
5469                 case 0:
5470                         /* Long options. */
5471                         break;
5472                 case 1:
5473                         /*
5474                          * unknown; opt is "!" or path component,
5475                          * checking done above.
5476                          */
5477                         if (strcmp(optarg, "!") == 0)
5478                                 neg_opt = 2;
5479                         break;
5480                 case 'A':
5481                         xtime = &param.fp_atime;
5482                         xsign = &param.fp_asign;
5483                         param.fp_exclude_atime = !!neg_opt;
5484                         /* no break, this falls through to 'B' for btime */
5485                         fallthrough;
5486                 case 'B':
5487                         if (c == 'B') {
5488                                 xtime = &param.fp_btime;
5489                                 xsign = &param.fp_bsign;
5490                                 param.fp_exclude_btime = !!neg_opt;
5491                         }
5492                         /* no break, this falls through to 'C' for ctime */
5493                         fallthrough;
5494                 case 'C':
5495                         if (c == 'C') {
5496                                 xtime = &param.fp_ctime;
5497                                 xsign = &param.fp_csign;
5498                                 param.fp_exclude_ctime = !!neg_opt;
5499                         }
5500                         /* no break, this falls through to 'M' for mtime */
5501                         fallthrough;
5502                 case 'M':
5503                         if (c == 'M') {
5504                                 xtime = &param.fp_mtime;
5505                                 xsign = &param.fp_msign;
5506                                 param.fp_exclude_mtime = !!neg_opt;
5507                         }
5508                         rc = set_time(&param, &t, xtime, optarg);
5509                         if (rc == INT_MAX) {
5510                                 ret = -1;
5511                                 goto err;
5512                         }
5513                         if (rc)
5514                                 *xsign = rc;
5515                         break;
5516                 case LFS_ATTRS_OPT:
5517                         ret = name2attrs(optarg, &param.fp_attrs,
5518                                          &param.fp_neg_attrs);
5519                         if (ret)
5520                                 goto err;
5521                         param.fp_exclude_attrs = !!neg_opt;
5522                         break;
5523                 case 'b':
5524                         if (optarg[0] == '+') {
5525                                 param.fp_blocks_sign = -1;
5526                                 optarg++;
5527                         } else if (optarg[0] == '-') {
5528                                 param.fp_blocks_sign =  1;
5529                                 optarg++;
5530                         }
5531
5532                         param.fp_blocks_units = 512;
5533                         ret = llapi_parse_size(optarg, &param.fp_blocks,
5534                                                &param.fp_blocks_units, 0);
5535                         if (ret) {
5536                                 fprintf(stderr, "error: bad blocks '%s'\n",
5537                                         optarg);
5538                                 goto err;
5539                         }
5540                         param.fp_check_blocks = 1;
5541                         param.fp_exclude_blocks = !!neg_opt;
5542                         break;
5543                 case LFS_COMP_COUNT_OPT:
5544                         if (optarg[0] == '+') {
5545                                 param.fp_comp_count_sign = -1;
5546                                 optarg++;
5547                         } else if (optarg[0] == '-') {
5548                                 param.fp_comp_count_sign =  1;
5549                                 optarg++;
5550                         }
5551
5552                         errno = 0;
5553                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
5554                         if (errno != 0 || *endptr != '\0' ||
5555                             param.fp_comp_count > UINT32_MAX) {
5556                                 fprintf(stderr,
5557                                         "error: bad component count '%s'\n",
5558                                         optarg);
5559                                 goto err;
5560                         }
5561                         param.fp_check_comp_count = 1;
5562                         param.fp_exclude_comp_count = !!neg_opt;
5563                         break;
5564                 case LFS_COMP_FLAGS_OPT:
5565                         rc = comp_str2flags(optarg, &param.fp_comp_flags,
5566                                             &param.fp_comp_neg_flags);
5567                         if (rc) {
5568                                 fprintf(stderr,
5569                                         "error: bad component flags '%s'\n",
5570                                         optarg);
5571                                 goto err;
5572                         }
5573                         param.fp_check_comp_flags = 1;
5574                         if (neg_opt) {
5575                                 __u32 flags = param.fp_comp_neg_flags;
5576
5577                                 param.fp_comp_neg_flags = param.fp_comp_flags;
5578                                 param.fp_comp_flags = flags;
5579                         }
5580                         break;
5581                 case LFS_COMP_START_OPT:
5582                         if (optarg[0] == '+') {
5583                                 param.fp_comp_start_sign = -1;
5584                                 optarg++;
5585                         } else if (optarg[0] == '-') {
5586                                 param.fp_comp_start_sign =  1;
5587                                 optarg++;
5588                         }
5589
5590                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
5591                                               &param.fp_comp_start_units, 0);
5592                         if (rc) {
5593                                 fprintf(stderr,
5594                                         "error: bad component start '%s'\n",
5595                                         optarg);
5596                                 goto err;
5597                         }
5598                         param.fp_check_comp_start = 1;
5599                         param.fp_exclude_comp_start = !!neg_opt;
5600                         break;
5601                 case LFS_MIRROR_STATE_OPT:
5602                         rc = mirror_str2state(optarg, &param.fp_mirror_state,
5603                                               &param.fp_mirror_neg_state);
5604                         if (rc) {
5605                                 fprintf(stderr,
5606                                         "error: bad mirrored file state '%s'\n",
5607                                         optarg);
5608                                 goto err;
5609                         }
5610                         param.fp_check_mirror_state = 1;
5611                         if (neg_opt) {
5612                                 __u16 state = param.fp_mirror_neg_state;
5613
5614                                 param.fp_mirror_neg_state =
5615                                         param.fp_mirror_state;
5616                                 param.fp_mirror_state = state;
5617                         }
5618                         break;
5619                 case 'c':
5620                         if (optarg[0] == '+') {
5621                                 param.fp_stripe_count_sign = -1;
5622                                 optarg++;
5623                         } else if (optarg[0] == '-') {
5624                                 param.fp_stripe_count_sign =  1;
5625                                 optarg++;
5626                         }
5627
5628                         errno = 0;
5629                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
5630                         if (errno != 0 || *endptr != '\0' ||
5631                             param.fp_stripe_count > LOV_MAX_STRIPE_COUNT) {
5632                                 fprintf(stderr,
5633                                         "error: bad stripe_count '%s'\n",
5634                                         optarg);
5635                                 ret = -1;
5636                                 goto err;
5637                         }
5638                         param.fp_check_stripe_count = 1;
5639                         param.fp_exclude_stripe_count = !!neg_opt;
5640                         break;
5641                 case 'D':
5642                         errno = 0;
5643                         param.fp_max_depth = strtol(optarg, 0, 0);
5644                         if (errno != 0 || param.fp_max_depth < 0) {
5645                                 fprintf(stderr,
5646                                         "error: bad maxdepth '%s'\n",
5647                                         optarg);
5648                                 ret = -1;
5649                                 goto err;
5650                         }
5651                         break;
5652                 case 'E':
5653                         if (optarg[0] == '+') {
5654                                 param.fp_comp_end_sign = -1;
5655                                 optarg++;
5656                         } else if (optarg[0] == '-') {
5657                                 param.fp_comp_end_sign =  1;
5658                                 optarg++;
5659                         }
5660
5661                         if (arg_is_eof(optarg)) {
5662                                 param.fp_comp_end = LUSTRE_EOF;
5663                                 param.fp_comp_end_units = 1;
5664                                 rc = 0;
5665                         } else {
5666                                 rc = llapi_parse_size(optarg,
5667                                                 &param.fp_comp_end,
5668                                                 &param.fp_comp_end_units, 0);
5669                                 /* assume units of KB if too small */
5670                                 if (param.fp_comp_end < 4096)
5671                                         param.fp_comp_end *= 1024;
5672                         }
5673                         if (rc) {
5674                                 fprintf(stderr,
5675                                         "error: bad component end '%s'\n",
5676                                         optarg);
5677                                 goto err;
5678                         }
5679                         param.fp_check_comp_end = 1;
5680                         param.fp_exclude_comp_end = !!neg_opt;
5681                         break;
5682                 case LFS_LAYOUT_FOREIGN_OPT: {
5683                         /* all types by default */
5684                         uint32_t type = LU_FOREIGN_TYPE_UNKNOWN;
5685
5686                         if (optarg) {
5687                                 /* check pure numeric */
5688                                 type = strtoul(optarg, &endptr, 0);
5689                                 if (*endptr) {
5690                                         /* check name */
5691                                         type = check_foreign_type_name(optarg);
5692                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
5693                                                 fprintf(stderr,
5694                                                         "%s %s: unknown foreign type '%s'\n",
5695                                                         progname, argv[0],
5696                                                         optarg);
5697                                                 return CMD_HELP;
5698                                         }
5699                                 } else if (type >= UINT32_MAX) {
5700                                         fprintf(stderr,
5701                                                 "%s %s: invalid foreign type '%s'\n",
5702                                                 progname, argv[0], optarg);
5703                                         return CMD_HELP;
5704                                 }
5705                         }
5706                         param.fp_foreign_type = type;
5707                         param.fp_check_foreign = 1;
5708                         param.fp_exclude_foreign = !!neg_opt;
5709                         break;
5710                 }
5711                 case LFS_NEWERXY_OPT: {
5712                         char x = 'm';
5713                         char y = 'm';
5714                         int xidx;
5715                         int negidx;
5716                         time_t *newery;
5717                         time_t ref = time(NULL);
5718
5719                         /* no need to check bad options, they won't get here */
5720                         if (strlen(long_opts[optidx].name) == 7) {
5721                                 x = long_opts[optidx].name[5];
5722                                 y = long_opts[optidx].name[6];
5723                         }
5724
5725                         if (y == 't') {
5726                                 static const char *const fmts[] = {
5727                                         "%Y-%m-%d %H:%M:%S",
5728                                         "%Y-%m-%d %H:%M",
5729                                         "%Y-%m-%d",
5730                                         "%H:%M:%S", /* sometime today */
5731                                         "%H:%M",
5732                                         "@%s",
5733                                         "%s",
5734                                         NULL };
5735                                 struct tm tm;
5736                                 bool found = false;
5737                                 int i;
5738
5739                                 for (i = 0; fmts[i] != NULL; i++) {
5740                                         char *ptr;
5741
5742                                         /* Init for times relative to today */
5743                                         if (strncmp(fmts[i], "%H", 2) == 0) {
5744                                                 localtime_r(&ref, &tm);
5745                                         } else {
5746                                                 memset(&tm, 0, sizeof(tm));
5747                                                 tm.tm_isdst = -1;
5748                                         }
5749                                         ptr = strptime(optarg, fmts[i], &tm);
5750                                         /* Skip spaces */
5751                                         while (ptr && isspace(*ptr))
5752                                                 ptr++;
5753                                         if (ptr == optarg + strlen(optarg)) {
5754                                                 found = true;
5755                                                 break;
5756                                         }
5757                                 }
5758
5759                                 if (!found) {
5760                                         fprintf(stderr,
5761                                                 "%s: invalid time '%s'\n",
5762                                                 progname, optarg);
5763                                         fprintf(stderr,
5764                                                 "supported formats are:\n  ");
5765                                         for (i = 0; fmts[i] != NULL; i++)
5766                                                 fprintf(stderr, "'%s', ",
5767                                                         fmts[i]);
5768                                         fprintf(stderr, "\n");
5769                                         ret = -EINVAL;
5770                                         goto err;
5771                                 }
5772
5773                                 ref = mktime(&tm);
5774                         } else if (y == 'b' || y == 'B') {
5775                                 lstatx_t stx;
5776
5777                                 rc = llapi_get_lum_file(optarg, NULL, &stx,
5778                                                         NULL, 0);
5779                                 if (rc || !(stx.stx_mask & STATX_BTIME)) {
5780                                         if (!(stx.stx_mask & STATX_BTIME))
5781                                                 ret = -EOPNOTSUPP;
5782                                         else
5783                                                 ret = -errno;
5784                                         fprintf(stderr,
5785                                                 "%s: get btime failed '%s': %s\n",
5786                                                 progname, optarg,
5787                                                 strerror(-ret));
5788                                         goto err;
5789                                 }
5790
5791                                 ref = stx.stx_btime.tv_sec;
5792                         } else {
5793                                 struct stat statbuf;
5794
5795                                 if (stat(optarg, &statbuf) < 0) {
5796                                         fprintf(stderr,
5797                                                 "%s: cannot stat file '%s': %s\n",
5798                                                 progname, optarg,
5799                                                 strerror(errno));
5800                                         ret = -errno;
5801                                         goto err;
5802                                 }
5803
5804                                 switch (y) {
5805                                 case 'a':
5806                                         ref = statbuf.st_atime;
5807                                         break;
5808                                 case 'm':
5809                                         ref = statbuf.st_mtime;
5810                                         break;
5811                                 case 'c':
5812                                         ref = statbuf.st_ctime;
5813                                         break;
5814                                 default:
5815                                         fprintf(stderr,
5816                                                 "%s: invalid Y argument: '%c'\n",
5817                                                 progname, x);
5818                                         ret = -EINVAL;
5819                                         goto err;
5820                                 }
5821                         }
5822
5823                         switch (x) {
5824                         case 'a':
5825                                 xidx = NEWERXY_ATIME;
5826                                 break;
5827                         case 'm':
5828                                 xidx = NEWERXY_MTIME;
5829                                 break;
5830                         case 'c':
5831                                 xidx = NEWERXY_CTIME;
5832                                 break;
5833                         case 'b':
5834                         case 'B':
5835                                 xidx = NEWERXY_BTIME;
5836                                 break;
5837                         default:
5838                                 fprintf(stderr,
5839                                         "%s: invalid X argument: '%c'\n",
5840                                         progname, x);
5841                                 ret = -EINVAL;
5842                                 goto err;
5843                         }
5844
5845                         negidx = !!neg_opt;
5846                         newery = &param.fp_newery[xidx][negidx];
5847
5848                         if (*newery == 0) {
5849                                 *newery = ref;
5850                         } else {
5851                                 if (negidx)
5852                                         *newery = *newery > ref ? ref : *newery;
5853                                 else
5854                                         *newery = *newery > ref ? *newery : ref;
5855                         }
5856                         param.fp_newerxy = 1;
5857                         break;
5858                 }
5859                 case 'g':
5860                 case 'G':
5861                         rc = name2gid(&param.fp_gid, optarg);
5862                         if (rc) {
5863                                 if (str2quotaid(&param.fp_gid, optarg)) {
5864                                         fprintf(stderr,
5865                                                 "Group/GID: %s cannot be found.\n",
5866                                                 optarg);
5867                                         ret = -1;
5868                                         goto err;
5869                                 }
5870                         }
5871                         param.fp_exclude_gid = !!neg_opt;
5872                         param.fp_check_gid = 1;
5873                         break;
5874                 case 'H':
5875                         rc = mdthash_input(optarg, &param.fp_hash_inflags,
5876                                            &param.fp_hash_exflags,
5877                                            &param.fp_hash_type);
5878                         if (rc) {
5879                                 ret = -1;
5880                                 goto err;
5881                         }
5882                         if (param.fp_hash_inflags || param.fp_hash_exflags)
5883                                 param.fp_check_hash_flag = 1;
5884                         param.fp_exclude_hash_type = !!neg_opt;
5885                         break;
5886                 case 'l':
5887                         param.fp_lazy = 1;
5888                         break;
5889                 case 'L':
5890                         ret = name2layout(&param.fp_layout, optarg);
5891                         if (ret)
5892                                 goto err;
5893                         param.fp_exclude_layout = !!neg_opt;
5894                         param.fp_check_layout = 1;
5895                         break;
5896                 case LFS_LINKS_OPT:
5897                         if (optarg[0] == '+') {
5898                                 param.fp_nlink_sign = -1;
5899                                 optarg++;
5900                         } else if (optarg[0] == '-') {
5901                                 param.fp_nlink_sign =  1;
5902                                 optarg++;
5903                         }
5904                         errno = 0;
5905                         param.fp_nlink = strtoul(optarg, &endptr, 0);
5906                         if (errno != 0 || *endptr != '\0' || !param.fp_nlink) {
5907                                 fprintf(stderr, "error: bad link count '%s'\n",
5908                                         optarg);
5909                                 ret = -1;
5910                                 goto err;
5911                         }
5912                         param.fp_exclude_nlink = !!neg_opt;
5913                         break;
5914                 case 'u':
5915                 case 'U':
5916                         rc = name2uid(&param.fp_uid, optarg);
5917                         if (rc) {
5918                                 if (str2quotaid(&param.fp_uid, optarg)) {
5919                                         fprintf(stderr,
5920                                                 "User/UID: %s cannot be found.\n",
5921                                                 optarg);
5922                                         ret = -1;
5923                                         goto err;
5924                                 }
5925                         }
5926                         param.fp_exclude_uid = !!neg_opt;
5927                         param.fp_check_uid = 1;
5928                         break;
5929                 case 'n':
5930                         param.fp_pattern = (char *)optarg;
5931                         param.fp_exclude_pattern = !!neg_opt;
5932                         break;
5933                 case 'N':
5934                         if (optarg[0] == '+') {
5935                                 param.fp_mirror_count_sign = -1;
5936                                 optarg++;
5937                         } else if (optarg[0] == '-') {
5938                                 param.fp_mirror_count_sign =  1;
5939                                 optarg++;
5940                         }
5941
5942                         errno = 0;
5943                         param.fp_mirror_count = strtoul(optarg, &endptr, 0);
5944                         if (errno != 0 || *endptr != '\0' ||
5945                             param.fp_mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
5946                                 fprintf(stderr,
5947                                         "error: bad mirror count '%s'\n",
5948                                         optarg);
5949                                 goto err;
5950                         }
5951                         param.fp_check_mirror_count = 1;
5952                         param.fp_exclude_mirror_count = !!neg_opt;
5953                         break;
5954                 case 'm':
5955                 case 'i':
5956                 case 'O': {
5957                         char *buf, *token, *next, *p;
5958                         int len = 1;
5959                         void *tmp;
5960
5961                         buf = strdup(optarg);
5962                         if (!buf) {
5963                                 ret = -ENOMEM;
5964                                 goto err;
5965                         }
5966
5967                         param.fp_exclude_obd = !!neg_opt;
5968
5969                         token = buf;
5970                         while (token && *token) {
5971                                 token = strchr(token, ',');
5972                                 if (token) {
5973                                         len++;
5974                                         token++;
5975                                 }
5976                         }
5977                         if (c == 'm') {
5978                                 param.fp_exclude_mdt = !!neg_opt;
5979                                 param.fp_num_alloc_mdts += len;
5980                                 tmp = realloc(param.fp_mdt_uuid,
5981                                               param.fp_num_alloc_mdts *
5982                                               sizeof(*param.fp_mdt_uuid));
5983                                 if (!tmp) {
5984                                         ret = -ENOMEM;
5985                                         goto err_free;
5986                                 }
5987
5988                                 param.fp_mdt_uuid = tmp;
5989                         } else {
5990                                 param.fp_exclude_obd = !!neg_opt;
5991                                 param.fp_num_alloc_obds += len;
5992                                 tmp = realloc(param.fp_obd_uuid,
5993                                               param.fp_num_alloc_obds *
5994                                               sizeof(*param.fp_obd_uuid));
5995                                 if (!tmp) {
5996                                         ret = -ENOMEM;
5997                                         goto err_free;
5998                                 }
5999
6000                                 param.fp_obd_uuid = tmp;
6001                         }
6002                         for (token = buf; token && *token; token = next) {
6003                                 struct obd_uuid *puuid;
6004
6005                                 if (c == 'm') {
6006                                         puuid =
6007                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
6008                                 } else {
6009                                         puuid =
6010                                         &param.fp_obd_uuid[param.fp_num_obds++];
6011                                 }
6012                                 p = strchr(token, ',');
6013                                 next = 0;
6014                                 if (p) {
6015                                         *p = 0;
6016                                         next = p+1;
6017                                 }
6018
6019                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
6020                                         ret = -E2BIG;
6021                                         goto err_free;
6022                                 }
6023
6024                                 strncpy(puuid->uuid, token,
6025                                         sizeof(puuid->uuid));
6026                         }
6027 err_free:
6028                         if (buf)
6029                                 free(buf);
6030                         break;
6031                 }
6032 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 18, 53, 0)
6033                 case 'p':
6034 #endif
6035                 case LFS_POOL_OPT:
6036                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
6037                                 fprintf(stderr,
6038                                         "Pool name %s is too long (max %d)\n",
6039                                         optarg, LOV_MAXPOOLNAME);
6040                                 ret = -1;
6041                                 goto err;
6042                         }
6043                         /*
6044                          * We do check for empty pool because empty pool
6045                          * is used to find V1 LOV attributes
6046                          */
6047                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
6048                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
6049                         param.fp_exclude_pool = !!neg_opt;
6050                         param.fp_check_pool = 1;
6051                         break;
6052                 case '0':
6053                         param.fp_zero_end = 1;
6054                         break;
6055                 case 'P': /* we always print, this option is a no-op */
6056                         break;
6057                 case LFS_PRINTF_OPT:
6058                         param.fp_format_printf_str = strdup(optarg);
6059                         break;
6060                 case LFS_PROJID_OPT:
6061                         rc = name2projid(&param.fp_projid, optarg);
6062                         if (rc) {
6063                                 if (str2quotaid(&param.fp_projid, optarg)) {
6064                                         fprintf(stderr,
6065                                                 "Invalid project ID: %s\n",
6066                                                 optarg);
6067                                         ret = -1;
6068                                         goto err;
6069                                 }
6070                         }
6071                         param.fp_exclude_projid = !!neg_opt;
6072                         param.fp_check_projid = 1;
6073                         break;
6074                 case 's':
6075                         if (optarg[0] == '+') {
6076                                 param.fp_size_sign = -1;
6077                                 optarg++;
6078                         } else if (optarg[0] == '-') {
6079                                 param.fp_size_sign =  1;
6080                                 optarg++;
6081                         }
6082
6083                         param.fp_size_units = 512;
6084                         ret = llapi_parse_size(optarg, &param.fp_size,
6085                                                &param.fp_size_units, 0);
6086                         if (ret) {
6087                                 fprintf(stderr, "error: bad file size '%s'\n",
6088                                         optarg);
6089                                 goto err;
6090                         }
6091                         param.fp_check_size = 1;
6092                         param.fp_exclude_size = !!neg_opt;
6093                         break;
6094                 case 'S':
6095                         if (optarg[0] == '+') {
6096                                 param.fp_stripe_size_sign = -1;
6097                                 optarg++;
6098                         } else if (optarg[0] == '-') {
6099                                 param.fp_stripe_size_sign =  1;
6100                                 optarg++;
6101                         }
6102
6103                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
6104                                                &param.fp_stripe_size_units, 0);
6105                         /* assume units of KB if too small to be valid */
6106                         if (param.fp_stripe_size < 4096)
6107                                 param.fp_stripe_size *= 1024;
6108                         if (ret) {
6109                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
6110                                         optarg);
6111                                 goto err;
6112                         }
6113                         param.fp_check_stripe_size = 1;
6114                         param.fp_exclude_stripe_size = !!neg_opt;
6115                         break;
6116                 case 't':
6117                         param.fp_exclude_type = !!neg_opt;
6118                         switch (optarg[0]) {
6119                         case 'b':
6120                                 param.fp_type = S_IFBLK;
6121                                 break;
6122                         case 'c':
6123                                 param.fp_type = S_IFCHR;
6124                                 break;
6125                         case 'd':
6126                                 param.fp_type = S_IFDIR;
6127                                 break;
6128                         case 'f':
6129                                 param.fp_type = S_IFREG;
6130                                 break;
6131                         case 'l':
6132                                 param.fp_type = S_IFLNK;
6133                                 break;
6134                         case 'p':
6135                                 param.fp_type = S_IFIFO;
6136                                 break;
6137                         case 's':
6138                                 param.fp_type = S_IFSOCK;
6139                                 break;
6140                         default:
6141                                 fprintf(stderr, "%s: bad type '%s'\n",
6142                                         progname, optarg);
6143                                 ret = CMD_HELP;
6144                                 goto err;
6145                         }
6146                         break;
6147                 case LFS_FIND_PERM:
6148                         param.fp_exclude_perm = !!neg_opt;
6149                         param.fp_perm_sign = LFS_FIND_PERM_EXACT;
6150                         if (*optarg == '/') {
6151                                 param.fp_perm_sign = LFS_FIND_PERM_ANY;
6152                                 optarg++;
6153                         } else if (*optarg == '-') {
6154                                 param.fp_perm_sign = LFS_FIND_PERM_ALL;
6155                                 optarg++;
6156                         }
6157
6158                         if (str2mode_t(optarg, &param.fp_perm)) {
6159                                 fprintf(stderr, "error: invalid mode '%s'\n",
6160                                         optarg);
6161                                 ret = -1;
6162                                 goto err;
6163                         }
6164                         break;
6165                 case 'T':
6166                         if (optarg[0] == '+') {
6167                                 param.fp_mdt_count_sign = -1;
6168                                 optarg++;
6169                         } else if (optarg[0] == '-') {
6170                                 param.fp_mdt_count_sign =  1;
6171                                 optarg++;
6172                         }
6173
6174                         errno = 0;
6175                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
6176                         if (errno != 0 || *endptr != '\0' ||
6177                             param.fp_mdt_count >= UINT32_MAX) {
6178                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
6179                                         optarg);
6180                                 ret = -1;
6181                                 goto err;
6182                         }
6183                         param.fp_check_mdt_count = 1;
6184                         param.fp_exclude_mdt_count = !!neg_opt;
6185                         break;
6186                 case LFS_XATTRS_MATCH_OPT:
6187                         ret = compile_xattr_match_regex(optarg, neg_opt,
6188                                                         &param);
6189                         if (ret)
6190                                 goto err;
6191                         break;
6192                 case 'z':
6193                         if (optarg[0] == '+') {
6194                                 param.fp_ext_size_sign = -1;
6195                                 optarg++;
6196                         } else if (optarg[0] == '-') {
6197                                 param.fp_ext_size_sign =  1;
6198                                 optarg++;
6199                         }
6200
6201                         ret = llapi_parse_size(optarg, &param.fp_ext_size,
6202                                                &param.fp_ext_size_units, 0);
6203                         if (ret) {
6204                                 fprintf(stderr, "error: bad ext-size '%s'\n",
6205                                         optarg);
6206                                 goto err;
6207                         }
6208                         param.fp_ext_size /= SEL_UNIT_SIZE;
6209                         param.fp_ext_size_units /= SEL_UNIT_SIZE;
6210                         param.fp_check_ext_size = 1;
6211                         param.fp_exclude_ext_size = !!neg_opt;
6212                         break;
6213                 default:
6214                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6215                                 progname, argv[optind - 1]);
6216                 case 'h':
6217                         ret = CMD_HELP;
6218                         goto err;
6219                 }
6220         }
6221         if (!param.fp_verbose)
6222                 param.fp_verbose = VERBOSE_DEFAULT;
6223
6224         if (pathstart == -1) {
6225                 fprintf(stderr, "error: %s: no filename|pathname\n",
6226                         argv[0]);
6227                 ret = CMD_HELP;
6228                 goto err;
6229         } else if (pathend == -1) {
6230                 /* no options */
6231                 pathend = argc;
6232         }
6233
6234         do {
6235                 rc = llapi_find(argv[pathstart], &param);
6236                 if (rc) {
6237                         if (!ret)
6238                                 ret = rc;
6239
6240                         fprintf(stderr, "%s: failed for '%s': %s\n",
6241                                 progname, argv[pathstart], strerror(-rc));
6242                 }
6243         } while (++pathstart < pathend);
6244
6245 err:
6246         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
6247                 free(param.fp_obd_uuid);
6248
6249         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
6250                 free(param.fp_mdt_uuid);
6251
6252         if (param.fp_format_printf_str)
6253                 free(param.fp_format_printf_str);
6254
6255         if (param.fp_xattr_match_info) {
6256                 xattr_match_info_free(param.fp_xattr_match_info);
6257                 free(param.fp_xattr_match_info);
6258                 param.fp_xattr_match_info = NULL;
6259         }
6260
6261         return ret;
6262 }
6263
6264 static int lfs_getstripe_internal(int argc, char **argv,
6265                                   struct find_param *param)
6266 {
6267         struct option long_opts[] = {
6268 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
6269 /* find { .val = 'b',   .name = "blocks",       .has_arg = required_argument }*/
6270 /* find { .val = 'B',   .name = "btime",        .has_arg = required_argument }*/
6271 /* find { .val = 'B',   .name = "Btime",        .has_arg = required_argument }*/
6272         { .val = LFS_COMP_COUNT_OPT,
6273                         .name = "comp-count",   .has_arg = no_argument },
6274         { .val = LFS_COMP_COUNT_OPT,
6275                 .name = "component-count",      .has_arg = no_argument },
6276         { .val = LFS_COMP_FLAGS_OPT,
6277                         .name = "comp-flags",   .has_arg = optional_argument },
6278         { .val = LFS_COMP_FLAGS_OPT,
6279                 .name = "component-flags",      .has_arg = optional_argument },
6280         { .val = LFS_COMP_START_OPT,
6281                         .name = "comp-start",   .has_arg = optional_argument },
6282         { .val = LFS_COMP_START_OPT,
6283                 .name = "component-start",      .has_arg = optional_argument },
6284         { .val = 'c',   .name = "stripe-count", .has_arg = no_argument },
6285         { .val = 'c',   .name = "stripe_count", .has_arg = no_argument },
6286 /* find { .val = 'C',   .name = "ctime",        .has_arg = required_argument }*/
6287         { .val = 'd',   .name = "directory",    .has_arg = no_argument },
6288         { .val = 'D',   .name = "default",      .has_arg = no_argument },
6289         { .val = 'E',   .name = "comp-end",     .has_arg = optional_argument },
6290         { .val = 'E',   .name = "component-end", .has_arg = optional_argument },
6291         { .val = 'F',   .name = "fid",          .has_arg = no_argument },
6292         { .val = 'g',   .name = "generation",   .has_arg = no_argument },
6293 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
6294         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6295         { .val = LFS_HEX_IDX_OPT,
6296                         .name = "hex-idx",      .has_arg = no_argument },
6297 /* dirstripe { .val = 'H', .name = "mdt-hash",  .has_arg = required_argument }*/
6298         { .val = 'i',   .name = "stripe-index", .has_arg = no_argument },
6299         { .val = 'i',   .name = "stripe_index", .has_arg = no_argument },
6300         { .val = 'I',   .name = "comp-id",      .has_arg = optional_argument },
6301         { .val = 'I',   .name = "component-id", .has_arg = optional_argument },
6302 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
6303         { .val = 'L',   .name = "layout",       .has_arg = no_argument },
6304         { .val = 'm',   .name = "mdt",          .has_arg = no_argument },
6305         { .val = 'm',   .name = "mdt-index",    .has_arg = no_argument },
6306         { .val = 'm',   .name = "mdt_index",    .has_arg = no_argument },
6307 /* find { .val = 'M',   .name = "mtime",        .has_arg = required_argument }*/
6308 /* find { .val = 'n',   .name = "name",         .has_arg = required_argument }*/
6309         { .val = 'N',   .name = "mirror-count", .has_arg = no_argument },
6310         { .val = LFS_MIRROR_INDEX_OPT,
6311                         .name = "mirror-index", .has_arg = required_argument },
6312         { .val = LFS_MIRROR_ID_OPT,
6313                         .name = "mirror-id",    .has_arg = required_argument },
6314         { .val = LFS_NO_FOLLOW_OPT,
6315                         .name = "no-follow",    .has_arg = no_argument },
6316         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
6317         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
6318         { .val = 'p',   .name = "pool",         .has_arg = no_argument },
6319 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
6320         { .val = 'q',   .name = "quiet",        .has_arg = no_argument },
6321         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
6322         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
6323         { .val = 'S',   .name = "stripe-size",  .has_arg = no_argument },
6324         { .val = 'S',   .name = "stripe_size",  .has_arg = no_argument },
6325 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
6326 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
6327 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
6328 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
6329         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
6330 /* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/
6331 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }*/
6332         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
6333         { .val = 'z',   .name = "extension-size", .has_arg = no_argument },
6334         { .val = 'z',   .name = "ext-size",     .has_arg = no_argument },
6335         { .name = NULL } };
6336         int c, rc = 0;
6337         int neg_opt = 0;
6338         int pathstart = -1, pathend = -1;
6339         int isoption;
6340         char *end, *tmp;
6341
6342         while ((c = getopt_long(argc, argv,
6343                         "-cdDE::FghiI::LmMNoO:pqrRsSvyz",
6344                         long_opts, NULL)) != -1) {
6345                 if (neg_opt)
6346                         --neg_opt;
6347
6348                 /* '!' is part of option */
6349                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
6350                 if (!isoption && pathend != -1) {
6351                         fprintf(stderr,
6352                                 "error: %s: filename|dirname must either precede options or follow options\n",
6353                                 argv[0]);
6354                         return CMD_HELP;
6355                 }
6356                 if (!isoption && pathstart == -1)
6357                         pathstart = optind - 1;
6358                 if (isoption && pathstart != -1 && pathend == -1)
6359                         pathend = optind - 2;
6360
6361                 switch (c) {
6362                 case 1:
6363                         /* unknown: opt is "!" */
6364                         if (strcmp(optarg, "!") == 0)
6365                                 neg_opt = 2;
6366                         break;
6367                 case 'c':
6368                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6369                                 param->fp_verbose |= VERBOSE_COUNT;
6370                                 param->fp_max_depth = 0;
6371                         }
6372                         break;
6373                 case LFS_COMP_COUNT_OPT:
6374                         param->fp_verbose |= VERBOSE_COMP_COUNT;
6375                         param->fp_max_depth = 0;
6376                         break;
6377                 case LFS_COMP_FLAGS_OPT:
6378                         if (optarg) {
6379                                 rc = comp_str2flags(optarg,
6380                                                     &param->fp_comp_flags,
6381                                                     &param->fp_comp_neg_flags);
6382                                 if (rc != 0) {
6383                                         fprintf(stderr,
6384                                                 "error: %s bad component flags '%s'.\n",
6385                                                 argv[0], optarg);
6386                                         return CMD_HELP;
6387                                 }
6388                                 param->fp_check_comp_flags = 1;
6389                         } else {
6390                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
6391                                 param->fp_max_depth = 0;
6392                         }
6393                         break;
6394                 case LFS_COMP_START_OPT:
6395                         if (optarg) {
6396                                 tmp = optarg;
6397                                 if (tmp[0] == '+') {
6398                                         param->fp_comp_start_sign = -1;
6399                                         tmp++;
6400                                 } else if (tmp[0] == '-') {
6401                                         param->fp_comp_start_sign = 1;
6402                                         tmp++;
6403                                 }
6404                                 rc = llapi_parse_size(tmp,
6405                                                 &param->fp_comp_start,
6406                                                 &param->fp_comp_start_units, 0);
6407                                 if (rc != 0) {
6408                                         fprintf(stderr,
6409                                                 "error: %s bad component start '%s'.\n",
6410                                                 argv[0], tmp);
6411                                         return CMD_HELP;
6412                                 }
6413                                 param->fp_check_comp_start = 1;
6414                         } else {
6415                                 param->fp_verbose |= VERBOSE_COMP_START;
6416                                 param->fp_max_depth = 0;
6417                         }
6418                         break;
6419                 case LFS_MIRROR_INDEX_OPT: {
6420                         unsigned long int mirror_index;
6421
6422                         if (optarg[0] == '+') {
6423                                 param->fp_mirror_index_sign = -1;
6424                                 optarg++;
6425                         } else if (optarg[0] == '-') {
6426                                 param->fp_mirror_index_sign = 1;
6427                                 optarg++;
6428                         }
6429
6430                         errno = 0;
6431                         mirror_index = strtoul(optarg, &end, 0);
6432                         if (errno != 0 || *end != '\0' ||
6433                             mirror_index > UINT16_MAX || (mirror_index == 0 &&
6434                             param->fp_mirror_index_sign == 0 && neg_opt == 0)) {
6435                                 fprintf(stderr,
6436                                         "%s %s: invalid mirror index '%s'\n",
6437                                         progname, argv[0], optarg);
6438                                 return CMD_HELP;
6439                         }
6440
6441                         param->fp_mirror_index = (__u16)mirror_index;
6442
6443                         if (param->fp_mirror_id != 0) {
6444                                 fprintf(stderr,
6445                                         "%s %s: can't specify both mirror index and mirror ID\n",
6446                                         progname, argv[0]);
6447                                 return CMD_HELP;
6448                         }
6449                         param->fp_check_mirror_index = 1;
6450                         param->fp_exclude_mirror_index = !!neg_opt;
6451                         break;
6452                 }
6453                 case LFS_MIRROR_ID_OPT: {
6454                         unsigned long int mirror_id;
6455
6456                         if (optarg[0] == '+') {
6457                                 param->fp_mirror_id_sign = -1;
6458                                 optarg++;
6459                         } else if (optarg[0] == '-') {
6460                                 param->fp_mirror_id_sign = 1;
6461                                 optarg++;
6462                         }
6463
6464                         errno = 0;
6465                         mirror_id = strtoul(optarg, &end, 0);
6466                         if (errno != 0 || *end != '\0' ||
6467                             mirror_id > UINT16_MAX || (mirror_id == 0 &&
6468                             param->fp_mirror_id_sign == 0 && neg_opt == 0)) {
6469                                 fprintf(stderr,
6470                                         "%s %s: invalid mirror ID '%s'\n",
6471                                         progname, argv[0], optarg);
6472                                 return CMD_HELP;
6473                         }
6474
6475                         param->fp_mirror_id = (__u16)mirror_id;
6476
6477                         if (param->fp_mirror_index != 0) {
6478                                 fprintf(stderr,
6479                                         "%s %s: can't specify both mirror index and mirror ID\n",
6480                                         progname, argv[0]);
6481                                 return CMD_HELP;
6482                         }
6483                         param->fp_check_mirror_id = 1;
6484                         param->fp_exclude_mirror_id = !!neg_opt;
6485                         break;
6486                 }
6487                 case LFS_NO_FOLLOW_OPT:
6488                         param->fp_no_follow = true;
6489                         break;
6490                 case LFS_HEX_IDX_OPT:
6491                         param->fp_hex_idx = true;
6492                         break;
6493                 case 'd':
6494                         param->fp_max_depth = 0;
6495                         break;
6496                 case 'D':
6497                         param->fp_get_default_lmv = 1;
6498                         break;
6499                 case 'E':
6500                         if (optarg) {
6501                                 tmp = optarg;
6502                                 if (tmp[0] == '+') {
6503                                         param->fp_comp_end_sign = -1;
6504                                         tmp++;
6505                                 } else if (tmp[0] == '-') {
6506                                         param->fp_comp_end_sign = 1;
6507                                         tmp++;
6508                                 }
6509
6510                                 if (arg_is_eof(tmp)) {
6511                                         param->fp_comp_end = LUSTRE_EOF;
6512                                         param->fp_comp_end_units = 1;
6513                                         rc = 0;
6514                                 } else {
6515                                         rc = llapi_parse_size(tmp,
6516                                                 &param->fp_comp_end,
6517                                                 &param->fp_comp_end_units, 0);
6518                                         /* assume units of KB if too small */
6519                                         if (param->fp_comp_end < 4096)
6520                                                 param->fp_comp_end *= 1024;
6521                                 }
6522                                 if (rc != 0) {
6523                                         fprintf(stderr,
6524                                                 "error: %s bad component end '%s'.\n",
6525                                                 argv[0], tmp);
6526                                         return CMD_HELP;
6527                                 }
6528                                 param->fp_check_comp_end = 1;
6529                         } else {
6530                                 param->fp_verbose |= VERBOSE_COMP_END;
6531                                 param->fp_max_depth = 0;
6532                         }
6533                         break;
6534                 case 'F':
6535                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6536                                 param->fp_verbose |= VERBOSE_DFID;
6537                                 param->fp_max_depth = 0;
6538                         }
6539                         break;
6540                 case 'g':
6541                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6542                                 param->fp_verbose |= VERBOSE_GENERATION;
6543                                 param->fp_max_depth = 0;
6544                         }
6545                         break;
6546                 case 'i':
6547                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6548                                 param->fp_verbose |= VERBOSE_STRIPE_OFFSET;
6549                                 param->fp_max_depth = 0;
6550                         }
6551                         break;
6552                 case 'I':
6553                         if (optarg) {
6554                                 param->fp_comp_id = strtoul(optarg, &end, 0);
6555                                 if (*end != '\0' || param->fp_comp_id == 0 ||
6556                                     param->fp_comp_id > LCME_ID_MAX) {
6557                                         fprintf(stderr,
6558                                                 "error: %s bad component id '%s'\n",
6559                                                 argv[0], optarg);
6560                                         return CMD_HELP;
6561                                 }
6562                                 param->fp_check_comp_id = 1;
6563                         } else {
6564                                 param->fp_max_depth = 0;
6565                                 param->fp_verbose |= VERBOSE_COMP_ID;
6566                         }
6567                         break;
6568                 case 'L':
6569                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6570                                 param->fp_verbose |= VERBOSE_PATTERN;
6571                                 param->fp_max_depth = 0;
6572                         }
6573                         break;
6574 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6575                 case 'M':
6576                         fprintf(stderr,
6577                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
6578 #endif
6579                 case 'm':
6580                         if (!(param->fp_verbose & VERBOSE_DETAIL))
6581                                 param->fp_max_depth = 0;
6582                         param->fp_verbose |= VERBOSE_MDTINDEX;
6583                         break;
6584                 case 'N':
6585                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6586                                 param->fp_verbose |= VERBOSE_MIRROR_COUNT;
6587                                 param->fp_max_depth = 0;
6588                         }
6589                         break;
6590                 case 'O':
6591                         if (param->fp_obd_uuid) {
6592                                 fprintf(stderr,
6593                                         "error: %s: only one obduuid allowed",
6594                                         argv[0]);
6595                                 return CMD_HELP;
6596                         }
6597                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
6598                         break;
6599                 case 'p':
6600                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6601                                 param->fp_verbose |= VERBOSE_POOL;
6602                                 param->fp_max_depth = 0;
6603                         }
6604                         break;
6605                 case 'q':
6606                         param->fp_quiet++;
6607                         break;
6608                 case 'r':
6609                         param->fp_recursive = 1;
6610                         break;
6611                 case 'R':
6612                         param->fp_raw = 1;
6613                         break;
6614                 case 'S':
6615                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6616                                 param->fp_verbose |= VERBOSE_STRIPE_SIZE;
6617                                 param->fp_max_depth = 0;
6618                         }
6619                         break;
6620                 case 'v':
6621                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
6622                         break;
6623                 case 'y':
6624                         param->fp_yaml = 1;
6625                         break;
6626                 case 'z':
6627                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6628                                 param->fp_verbose |= VERBOSE_EXT_SIZE;
6629                                 param->fp_max_depth = 0;
6630                         }
6631                         break;
6632                 default:
6633                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6634                                 progname, argv[optind - 1]);
6635                 case 'h':
6636                         return CMD_HELP;
6637                 }
6638         }
6639
6640         if (pathstart == -1) {
6641                 fprintf(stderr, "error: %s: no filename|pathname\n",
6642                                 argv[0]);
6643                 return CMD_HELP;
6644         } else if (pathend == -1) {
6645                 /* no options */
6646                 pathend = argc;
6647         }
6648
6649         if (pathend > argc)
6650                 return CMD_HELP;
6651
6652         if (param->fp_recursive)
6653                 param->fp_max_depth = -1;
6654         else if (param->fp_verbose & VERBOSE_DETAIL)
6655                 param->fp_max_depth = 1;
6656
6657         if (!param->fp_verbose)
6658                 param->fp_verbose = VERBOSE_DEFAULT;
6659         if (param->fp_quiet)
6660                 param->fp_verbose = VERBOSE_OBJID;
6661
6662         do {
6663                 int rc2;
6664
6665                 rc2 = llapi_getstripe(argv[pathstart], param);
6666                 if (rc2) {
6667                         fprintf(stderr, "%s: %s for '%s' failed: %s\n",
6668                                 progname, argv[0], argv[pathstart],
6669                                 strerror(-rc2));
6670                         if (!rc)
6671                                 rc = rc2;
6672                 }
6673         } while (++pathstart < pathend);
6674
6675         return rc;
6676 }
6677
6678 static int lfs_tgts(int argc, char **argv)
6679 {
6680         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
6681         struct find_param param;
6682         int index = 0, rc = 0;
6683
6684         if (argc > 2)
6685                 return CMD_HELP;
6686
6687         if (argc == 2 && !realpath(argv[1], path)) {
6688                 rc = -errno;
6689                 fprintf(stderr, "error: invalid path '%s': %s\n",
6690                         argv[1], strerror(-rc));
6691                 return rc;
6692         }
6693
6694         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
6695                 /* Check if we have a mount point */
6696                 if (mntdir[0] == '\0')
6697                         continue;
6698
6699                 memset(&param, 0, sizeof(param));
6700                 if (!strcmp(argv[0], "mdts"))
6701                         param.fp_get_lmv = 1;
6702
6703                 rc = llapi_ostlist(mntdir, &param);
6704                 if (rc) {
6705                         fprintf(stderr, "error: %s: failed on %s\n",
6706                                 argv[0], mntdir);
6707                 }
6708                 if (path[0] != '\0')
6709                         break;
6710                 memset(mntdir, 0, PATH_MAX);
6711         }
6712
6713         return rc;
6714 }
6715
6716 static int lfs_getstripe(int argc, char **argv)
6717 {
6718         struct find_param param = { 0 };
6719
6720         param.fp_max_depth = 1;
6721         return lfs_getstripe_internal(argc, argv, &param);
6722 }
6723
6724 /* functions */
6725 static int lfs_getdirstripe(int argc, char **argv)
6726 {
6727         struct find_param param = { 0 };
6728         struct option long_opts[] = {
6729         { .val = 'c',   .name = "mdt-count",     .has_arg = no_argument },
6730         { .val = 'D',   .name = "default",       .has_arg = no_argument },
6731         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6732         { .val = 'H',   .name = "mdt-hash",      .has_arg = no_argument },
6733         { .val = LFS_HEX_IDX_OPT,
6734                         .name = "hex-idx",       .has_arg = no_argument },
6735         { .val = 'i',   .name = "mdt-index",     .has_arg = no_argument },
6736         { .val = 'm',   .name = "mdt-index",     .has_arg = no_argument },
6737         { .val = 'O',   .name = "obd",           .has_arg = required_argument },
6738         { .val = 'r',   .name = "recursive",     .has_arg = no_argument },
6739         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
6740         { .val = 'T',   .name = "mdt-count",     .has_arg = no_argument },
6741         { .val = 'v',   .name = "verbose",       .has_arg = no_argument },
6742         { .val = 'X',   .name = "max-inherit",   .has_arg = no_argument },
6743         { .val = LFS_INHERIT_RR_OPT,
6744                         .name = "max-inherit-rr", .has_arg = no_argument },
6745         { .val = 'y',   .name = "yaml",          .has_arg = no_argument },
6746         { .name = NULL } };
6747         int c, rc = 0;
6748
6749         param.fp_get_lmv = 1;
6750
6751         while ((c = getopt_long(argc, argv,
6752                                 "cDhHimO:rRtTvXy", long_opts, NULL)) != -1) {
6753                 switch (c) {
6754                 case 'c':
6755                 case 'T':
6756                         param.fp_verbose |= VERBOSE_COUNT;
6757                         break;
6758                 case 'D':
6759                         param.fp_get_default_lmv = 1;
6760                         break;
6761 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6762                 case 't':
6763                         fprintf(stderr,
6764                                 "warning: '-t' deprecated, use '--mdt-hash' or '-H' instead\n");
6765                         fallthrough;
6766 #endif
6767                 case 'H':
6768                         param.fp_verbose |= VERBOSE_HASH_TYPE;
6769                         break;
6770                 case LFS_HEX_IDX_OPT:
6771                         param.fp_hex_idx = 1;
6772                         break;
6773                 case 'i':
6774                         fallthrough;
6775                 case 'm':
6776                         param.fp_verbose |= VERBOSE_STRIPE_OFFSET;
6777                         break;
6778                 case 'O':
6779                         if (param.fp_obd_uuid) {
6780                                 fprintf(stderr,
6781                                         "%s: only one obduuid allowed",
6782                                         progname);
6783                                 return CMD_HELP;
6784                         }
6785                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
6786                         break;
6787                 case 'r':
6788                         param.fp_recursive = 1;
6789                         break;
6790                 case 'R':
6791                         param.fp_raw = 1;
6792                         break;
6793                 case 'v':
6794                         param.fp_verbose |= VERBOSE_DEFAULT;
6795                         param.fp_verbose |= VERBOSE_DETAIL;
6796                         break;
6797                 case 'X':
6798                         param.fp_verbose |= VERBOSE_INHERIT;
6799                         break;
6800                 case LFS_INHERIT_RR_OPT:
6801                         param.fp_verbose |= VERBOSE_INHERIT_RR;
6802                         break;
6803                 case 'y':
6804                         param.fp_yaml = 1;
6805                         break;
6806                 default:
6807                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6808                                 progname, argv[optind - 1]);
6809                         fallthrough;
6810                 case 'h':
6811                         return CMD_HELP;
6812                 }
6813         }
6814
6815         if (optind >= argc)
6816                 return CMD_HELP;
6817
6818         if (param.fp_recursive)
6819                 param.fp_max_depth = -1;
6820
6821         if (!param.fp_verbose)
6822                 param.fp_verbose = VERBOSE_DEFAULT;
6823
6824         do {
6825                 int rc2;
6826
6827                 rc2 = llapi_getstripe(argv[optind], &param);
6828                 if (rc2) {
6829                         fprintf(stderr, "%s: %s for '%s' failed: %s\n",
6830                                 progname, argv[0], argv[optind],
6831                                 strerror(-rc2));
6832                         if (!rc)
6833                                 rc = rc2;
6834                 }
6835         } while (++optind < argc);
6836
6837         return rc;
6838 }
6839
6840 enum mntdf_flags {
6841         MNTDF_INODES    = 0x0001,
6842         MNTDF_COOKED    = 0x0002,
6843         MNTDF_LAZY      = 0x0004,
6844         MNTDF_VERBOSE   = 0x0008,
6845         MNTDF_SHOW      = 0x0010,
6846         MNTDF_DECIMAL   = 0x0020,
6847 };
6848
6849 #define COOK(value, base)                                       \
6850 ({                                                              \
6851         int radix = 0;                                          \
6852         while (value > base) {                                  \
6853                 value /= base;                                  \
6854                 radix++;                                        \
6855         }                                                       \
6856         radix;                                                  \
6857 })
6858 #define UUF     "%-20s"
6859 #define CSF     "%11s"
6860 #define CDF     "%11llu"
6861 #define HDF     "%8.1f%c"
6862 #define RSF     "%4s"
6863 #define RDF     "%3d%%"
6864
6865 static inline int obd_statfs_ratio(const struct obd_statfs *st, bool inodes)
6866 {
6867         double avail, used, ratio = 0;
6868
6869         if (inodes) {
6870                 avail = st->os_ffree;
6871                 used = st->os_files - st->os_ffree;
6872         } else {
6873                 avail = st->os_bavail;
6874                 used = st->os_blocks - st->os_bfree;
6875         }
6876         if (avail + used > 0)
6877                 ratio = used / (used + avail) * 100;
6878
6879         /* Round up to match df(1) usage percentage */
6880         return (ratio - (int)ratio) > 0 ? (int)(ratio + 1) : (int)ratio;
6881 }
6882
6883 /*
6884  * This is to identify various problem states for "lfs df" if .osn_err = true,
6885  * so only show flags reflecting those states by default. Informational states
6886  * are only shown with "-v" and use lower-case names to distinguish them.
6887  * UNUSED[12] were for "EROFS = 30" until 1.6 but are now available for use.
6888  */
6889 static struct obd_statfs_state_names {
6890         enum obd_statfs_state   osn_state;
6891         const char              osn_name;
6892         bool                    osn_err;
6893 } oss_names[] = {
6894         { .osn_state = OS_STATFS_DEGRADED,   .osn_name = 'D', .osn_err = true },
6895         { .osn_state = OS_STATFS_READONLY,   .osn_name = 'R', .osn_err = true },
6896         { .osn_state = OS_STATFS_NOCREATE,   .osn_name = 'N', .osn_err = true },
6897         { .osn_state = OS_STATFS_UNUSED1,    .osn_name = '?', .osn_err = true },
6898         { .osn_state = OS_STATFS_UNUSED2,    .osn_name = '?', .osn_err = true },
6899         { .osn_state = OS_STATFS_ENOSPC,     .osn_name = 'S', .osn_err = true },
6900         { .osn_state = OS_STATFS_ENOINO,     .osn_name = 'I', .osn_err = true },
6901         { .osn_state = OS_STATFS_SUM,        .osn_name = 'a', /* aggregate */ },
6902         { .osn_state = OS_STATFS_NONROT,     .osn_name = 'f', /* flash */     },
6903 };
6904
6905 static int showdf(char *mntdir, struct obd_statfs *stat,
6906                   char *uuid, enum mntdf_flags flags,
6907                   char *type, int index, int rc)
6908 {
6909         long long avail, used, total;
6910         int ratio = 0;
6911         char *suffix = flags & MNTDF_DECIMAL ? "kMGTPEZY" : "KMGTPEZY";
6912         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
6913         char tbuf[3 * sizeof(__u64)];
6914         char ubuf[3 * sizeof(__u64)];
6915         char abuf[3 * sizeof(__u64)];
6916         char rbuf[3 * sizeof(__u64)];
6917
6918         if (!uuid || !stat)
6919                 return -EINVAL;
6920
6921         switch (rc) {
6922         case 0:
6923                 if (flags & MNTDF_INODES) {
6924                         avail = stat->os_ffree;
6925                         used = stat->os_files - stat->os_ffree;
6926                         total = stat->os_files;
6927                 } else {
6928                         int shift = flags & MNTDF_COOKED ? 0 : 10;
6929
6930                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
6931                         used  = ((stat->os_blocks - stat->os_bfree) *
6932                                  stat->os_bsize) >> shift;
6933                         total = (stat->os_blocks * stat->os_bsize) >> shift;
6934                 }
6935
6936                 ratio = obd_statfs_ratio(stat, flags & MNTDF_INODES);
6937
6938                 if (flags & MNTDF_COOKED) {
6939                         int base = flags & MNTDF_DECIMAL ? 1000 : 1024;
6940                         double cook_val;
6941                         int i;
6942
6943                         cook_val = (double)total;
6944                         i = COOK(cook_val, base);
6945                         if (i > 0)
6946                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
6947                                          suffix[i - 1]);
6948                         else
6949                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
6950
6951                         cook_val = (double)used;
6952                         i = COOK(cook_val, base);
6953                         if (i > 0)
6954                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
6955                                          suffix[i - 1]);
6956                         else
6957                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
6958
6959                         cook_val = (double)avail;
6960                         i = COOK(cook_val, base);
6961                         if (i > 0)
6962                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
6963                                          suffix[i - 1]);
6964                         else
6965                                 snprintf(abuf, sizeof(abuf), CDF, avail);
6966                 } else {
6967                         snprintf(tbuf, sizeof(tbuf), CDF, total);
6968                         snprintf(ubuf, sizeof(tbuf), CDF, used);
6969                         snprintf(abuf, sizeof(tbuf), CDF, avail);
6970                 }
6971
6972                 sprintf(rbuf, RDF, ratio);
6973                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
6974                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
6975                 if (type)
6976                         printf("[%s:%d]", type, index);
6977
6978                 if (stat->os_state) {
6979                         uint32_t i;
6980
6981                         printf(" ");
6982                         for (i = 0; i < ARRAY_SIZE(oss_names); i++) {
6983                                 if (oss_names[i].osn_state & stat->os_state &&
6984                                     (oss_names[i].osn_err ||
6985                                      flags & MNTDF_VERBOSE))
6986                                         printf("%c", oss_names[i].osn_name);
6987                         }
6988                 }
6989
6990                 printf("\n");
6991                 break;
6992         case -ENODATA:
6993                 printf(UUF": inactive device\n", uuid);
6994                 break;
6995         default:
6996                 printf(UUF": %s\n", uuid, strerror(-rc));
6997                 break;
6998         }
6999
7000         return 0;
7001 }
7002
7003 struct ll_stat_type {
7004         int   st_op;
7005         char *st_name;
7006 };
7007
7008 #define LL_STATFS_MAX   LOV_MAX_STRIPE_COUNT
7009
7010 struct ll_statfs_data {
7011         int                     sd_index;
7012         struct obd_statfs       sd_st;
7013 };
7014
7015 struct ll_statfs_buf {
7016         int                     sb_count;
7017         struct ll_statfs_data   sb_buf[LL_STATFS_MAX];
7018 };
7019
7020 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags,
7021                  int ops, struct ll_statfs_buf *lsb)
7022 {
7023         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
7024         struct obd_uuid uuid_buf;
7025         char *poolname = NULL;
7026         struct ll_stat_type types[] = {
7027                 { .st_op = LL_STATFS_LMV,       .st_name = "MDT" },
7028                 { .st_op = LL_STATFS_LOV,       .st_name = "OST" },
7029                 { .st_name = NULL } };
7030         struct ll_stat_type *tp;
7031         __u64 ost_files = 0;
7032         __u64 ost_ffree = 0;
7033         __u32 index;
7034         __u32 type;
7035         int fd;
7036         int rc = 0;
7037         int rc2;
7038
7039         if (pool) {
7040                 poolname = strchr(pool, '.');
7041                 if (poolname) {
7042                         if (strncmp(fsname, pool, strlen(fsname))) {
7043                                 fprintf(stderr, "filesystem name incorrect\n");
7044                                 return -ENODEV;
7045                         }
7046                         poolname++;
7047                 } else
7048                         poolname = pool;
7049         }
7050
7051         fd = open(mntdir, O_RDONLY);
7052         if (fd < 0) {
7053                 rc = -errno;
7054                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
7055                         strerror(errno));
7056                 return rc;
7057         }
7058
7059         if (flags & MNTDF_SHOW) {
7060                 if (flags & MNTDF_INODES)
7061                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
7062                                "UUID", "Inodes", "IUsed", "IFree",
7063                                "IUse%", "Mounted on");
7064                 else
7065                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
7066                                "UUID",
7067                                flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
7068                                "Used", "Available", "Use%", "Mounted on");
7069         }
7070
7071         for (tp = types; tp->st_name != NULL; tp++) {
7072                 bool have_ost = false;
7073
7074                 if (!(tp->st_op & ops))
7075                         continue;
7076
7077                 for (index = 0; index < LOV_ALL_STRIPES &&
7078                      (!lsb || lsb->sb_count < LL_STATFS_MAX); index++) {
7079                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
7080                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
7081                         type = flags & MNTDF_LAZY ?
7082                                 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
7083                         rc2 = llapi_obd_fstatfs(fd, type, index,
7084                                                 &stat_buf, &uuid_buf);
7085                         if (rc2 == -ENODEV)
7086                                 break;
7087                         if (rc2 == -EAGAIN)
7088                                 continue;
7089                         if (rc2 == -ENODATA) { /* Inactive device, OK. */
7090                                 if (!(flags & MNTDF_VERBOSE))
7091                                         continue;
7092                         } else if (rc2 < 0 && rc == 0) {
7093                                 rc = rc2;
7094                         }
7095
7096                         /*
7097                          * If we have OSTs then don't report MDT block counts.
7098                          * For MDT-only filesystems the expectation is that all
7099                          * layouts have a DoM component.  For filesystems with
7100                          * OSTs, files are not necessarily going to store data
7101                          * on MDTs, and MDT space is limited to a fraction of
7102                          * OST space, so don't include it in the summary.
7103                          */
7104                         if (tp->st_op == LL_STATFS_LOV && !have_ost) {
7105                                 have_ost = true;
7106                                 sum.os_blocks = 0;
7107                                 sum.os_bfree = 0;
7108                                 sum.os_bavail = 0;
7109                         }
7110
7111                         if (poolname && tp->st_op == LL_STATFS_LOV &&
7112                             llapi_search_ost(fsname, poolname,
7113                                              obd_uuid2str(&uuid_buf)) != 1)
7114                                 continue;
7115
7116                         /*
7117                          * the llapi_obd_fstatfs() call may have returned with
7118                          * an error, but if it filled in uuid_buf we will at
7119                          * lease use that to print out a message for that OBD.
7120                          * If we didn't get anything in the uuid_buf, then fill
7121                          * it in so that we can print an error message.
7122                          */
7123                         if (uuid_buf.uuid[0] == '\0')
7124                                 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
7125                                          "%s%04x", tp->st_name, index);
7126                         if (!rc && lsb) {
7127                                 lsb->sb_buf[lsb->sb_count].sd_index = index;
7128                                 lsb->sb_buf[lsb->sb_count].sd_st = stat_buf;
7129                                 lsb->sb_count++;
7130                         }
7131                         if (flags & MNTDF_SHOW)
7132                                 showdf(mntdir, &stat_buf,
7133                                        obd_uuid2str(&uuid_buf), flags,
7134                                        tp->st_name, index, rc2);
7135
7136                         if (rc2)
7137                                 continue;
7138
7139                         if (tp->st_op == LL_STATFS_LMV) {
7140                                 sum.os_ffree += stat_buf.os_ffree;
7141                                 sum.os_files += stat_buf.os_files;
7142                         } else /* if (tp->st_op == LL_STATFS_LOV) */ {
7143                                 ost_files += stat_buf.os_files;
7144                                 ost_ffree += stat_buf.os_ffree;
7145                         }
7146                         sum.os_blocks += stat_buf.os_blocks *
7147                                          stat_buf.os_bsize;
7148                         sum.os_bfree  += stat_buf.os_bfree *
7149                                          stat_buf.os_bsize;
7150                         sum.os_bavail += stat_buf.os_bavail *
7151                                          stat_buf.os_bsize;
7152                 }
7153         }
7154
7155         close(fd);
7156
7157         /*
7158          * If we have _some_ OSTs, but don't have as many free objects on the
7159          * OST as inodes on the MDTs, reduce the reported number of inodes
7160          * to compensate, so that the "inodes in use" number is correct.
7161          * This should be kept in sync with ll_statfs_internal().
7162          */
7163         if (ost_files && ost_ffree < sum.os_ffree) {
7164                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
7165                 sum.os_ffree = ost_ffree;
7166         }
7167         if (flags & MNTDF_SHOW) {
7168                 printf("\n");
7169                 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
7170                 printf("\n");
7171         }
7172
7173         return rc;
7174 }
7175
7176 enum {
7177         LAYOUT_INHERIT_UNSET    = -2,
7178 };
7179
7180 /* functions */
7181 static int lfs_setdirstripe(int argc, char **argv)
7182 {
7183         char *dname;
7184         struct lfs_setstripe_args lsa = { 0 };
7185         struct llapi_stripe_param *param = NULL;
7186         __u32 mdts[LMV_MAX_STRIPE_COUNT] = { 0 };
7187         char *end;
7188         int c;
7189         char *mode_opt = NULL;
7190         bool default_stripe = false;
7191         bool delete = false;
7192         bool foreign_mode = false;
7193         bool mdt_count_set = false;
7194         bool overstriped = false;
7195         mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
7196         mode_t previous_mode = 0;
7197         char *xattr = NULL;
7198         __u32 type = LU_FOREIGN_TYPE_SYMLINK, flags = 0;
7199         int max_inherit = LAYOUT_INHERIT_UNSET;
7200         int max_inherit_rr = LAYOUT_INHERIT_UNSET;
7201         struct option long_opts[] = {
7202         { .val = 'c',   .name = "count",        .has_arg = required_argument },
7203         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
7204         { .val = 'C',   .name = "mdt-overcount", .has_arg = required_argument },
7205         { .val = 'd',   .name = "delete",       .has_arg = no_argument },
7206         { .val = 'D',   .name = "default",      .has_arg = no_argument },
7207         { .val = 'D',   .name = "default_stripe", .has_arg = no_argument },
7208         { .val = LFS_LAYOUT_FLAGS_OPT,
7209                         .name = "flags",        .has_arg = required_argument },
7210         { .val = LFS_LAYOUT_FOREIGN_OPT,
7211                         .name = "foreign",      .has_arg = optional_argument},
7212         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7213         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
7214 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 17, 53, 0)
7215         { .val = 'i',   .name = "mdt-index",    .has_arg = required_argument },
7216         { .val = 'i',   .name = "mdt",          .has_arg = required_argument },
7217 #else
7218 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
7219         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
7220         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
7221 #endif
7222 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7223         { .val = 'i',   .name = "index",        .has_arg = required_argument },
7224 #endif
7225         { .val = 'o',   .name = "mode",         .has_arg = required_argument },
7226 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7227         { .val = 't',   .name = "hash-type",    .has_arg = required_argument },
7228 #endif
7229         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
7230         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
7231         { .val = 'X',   .name = "max-inherit",  .has_arg = required_argument },
7232         { .val = LFS_INHERIT_RR_OPT,
7233                         .name = "max-inherit-rr", .has_arg = required_argument},
7234 /* setstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
7235 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }, */
7236         { .name = NULL } };
7237         int result = 0;
7238
7239         setstripe_args_init(&lsa);
7240
7241         while ((c = getopt_long(argc, argv, "c:C:dDi:hH:m:o:t:T:x:X:",
7242                                 long_opts, NULL)) >= 0) {
7243                 switch (c) {
7244                 case 0:
7245                         /* Long options. */
7246                         break;
7247                 case 'C':
7248                         overstriped = true;
7249                         fallthrough;
7250                 case 'c':
7251                         fallthrough;
7252                 case 'T':
7253                         errno = 0;
7254                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
7255                         if (errno != 0 || *end != '\0' ||
7256                             lsa.lsa_stripe_count < -1 ||
7257                             lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
7258                                 fprintf(stderr,
7259                                         "%s: invalid stripe count '%s'\n",
7260                                         progname, optarg);
7261                                 return CMD_HELP;
7262                         }
7263                         mdt_count_set = true;
7264                         break;
7265                 case 'd':
7266                         delete = true;
7267                         default_stripe = true;
7268                         break;
7269                 case 'D':
7270                         default_stripe = true;
7271                         break;
7272                 case LFS_LAYOUT_FOREIGN_OPT:
7273                         if (optarg) {
7274                                 /* check pure numeric */
7275                                 type = strtoul(optarg, &end, 0);
7276                                 if (*end) {
7277                                         /* check name */
7278                                         type = check_foreign_type_name(optarg);
7279                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
7280                                                 fprintf(stderr,
7281                                                         "%s %s: unknown foreign type '%s'\n",
7282                                                         progname, argv[0],
7283                                                         optarg);
7284                                                 return CMD_HELP;
7285                                         }
7286                                 } else if (type >= UINT32_MAX) {
7287                                         fprintf(stderr,
7288                                                 "%s %s: invalid foreign type '%s'\n",
7289                                                 progname, argv[0], optarg);
7290                                         return CMD_HELP;
7291                                 }
7292                         }
7293                         foreign_mode = true;
7294                         break;
7295                 case LFS_LAYOUT_FLAGS_OPT:
7296                         errno = 0;
7297                         flags = strtoul(optarg, &end, 16);
7298                         if (errno != 0 || *end != '\0' ||
7299                             flags >= UINT32_MAX) {
7300                                 fprintf(stderr,
7301                                         "%s %s: invalid hex flags '%s'\n",
7302                                         progname, argv[0], optarg);
7303                                 return CMD_HELP;
7304                         }
7305                         if (!foreign_mode) {
7306                                 fprintf(stderr,
7307                                         "%s %s: hex flags must be specified with --foreign option\n",
7308                                         progname, argv[0]);
7309                                 return CMD_HELP;
7310                         }
7311                         break;
7312 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7313                 case 't':
7314                         fprintf(stderr,
7315                                 "warning: '--hash-type' and '-t' deprecated, use '--mdt-hash' or '-H' instead\n");
7316                         fallthrough;
7317 #endif
7318                 case 'H':
7319                         lsa.lsa_pattern = check_hashtype(optarg);
7320                         if (lsa.lsa_pattern == 0) {
7321                                 fprintf(stderr,
7322                                         "%s %s: bad directory hash type '%s'\n",
7323                                         progname, argv[0], optarg);
7324                                 return CMD_HELP;
7325                         }
7326                         break;
7327                 case 'i':
7328 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 17, 53, 0)
7329                 case 'm':
7330 #endif
7331 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7332                         if (strcmp(argv[optind - 1], "--index") == 0)
7333                                 fprintf(stderr,
7334                                         "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
7335                                         progname, argv[0]);
7336 #endif
7337                         lsa.lsa_nr_tgts = parse_targets(mdts,
7338                                                 sizeof(mdts) / sizeof(__u32),
7339                                                 lsa.lsa_nr_tgts, optarg,
7340                                                 &overstriped);
7341                         if (lsa.lsa_nr_tgts < 0) {
7342                                 fprintf(stderr,
7343                                         "%s %s: invalid MDT target(s) '%s'\n",
7344                                         progname, argv[0], optarg);
7345                                 return CMD_HELP;
7346                         }
7347
7348                         lsa.lsa_tgts = mdts;
7349                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
7350                                 lsa.lsa_stripe_off = mdts[0];
7351                         break;
7352                 case 'o':
7353                         mode_opt = optarg;
7354                         break;
7355                 case 'x':
7356                         xattr = optarg;
7357                         break;
7358                 case 'X':
7359                         errno = 0;
7360                         max_inherit = strtol(optarg, &end, 10);
7361                         if (errno != 0 || *end != '\0' || max_inherit < -2) {
7362                                 fprintf(stderr,
7363                                         "%s %s: invalid max-inherit '%s'\n",
7364                                         progname, argv[0], optarg);
7365                                 return CMD_HELP;
7366                         }
7367                         if (max_inherit == 0) {
7368                                 max_inherit = LMV_INHERIT_NONE;
7369                         } else if (max_inherit == -1) {
7370                                 max_inherit = LMV_INHERIT_UNLIMITED;
7371                         } else if (max_inherit > LMV_INHERIT_MAX) {
7372                                 fprintf(stderr,
7373                                         "%s %s: max-inherit %d exceeds maximum %u\n",
7374                                         progname, argv[0], max_inherit,
7375                                         LMV_INHERIT_MAX);
7376                                 return CMD_HELP;
7377                         }
7378                         break;
7379                 case LFS_INHERIT_RR_OPT:
7380                         if (!default_stripe) {
7381                                 fprintf(stderr,
7382                                         "%s %s: '--max-inherit-rr' must be specified with '-D'\n",
7383                                         progname, argv[0]);
7384                                 return CMD_HELP;
7385                         }
7386                         errno = 0;
7387                         max_inherit_rr = strtol(optarg, &end, 10);
7388                         if (errno != 0 || *end != '\0' || max_inherit_rr < -2) {
7389                                 fprintf(stderr,
7390                                         "%s %s: invalid max-inherit-rr '%s'\n",
7391                                         progname, argv[0], optarg);
7392                                 return CMD_HELP;
7393                         }
7394                         if (max_inherit_rr == 0) {
7395                                 max_inherit_rr = LMV_INHERIT_RR_NONE;
7396                         } else if (max_inherit_rr == -1) {
7397                                 max_inherit_rr = LMV_INHERIT_RR_UNLIMITED;
7398                         } else if (max_inherit_rr > LMV_INHERIT_RR_MAX) {
7399                                 fprintf(stderr,
7400                                         "%s %s: max-inherit-rr %d exceeds maximum %u\n",
7401                                         progname, argv[0], max_inherit_rr,
7402                                         LMV_INHERIT_RR_MAX);
7403                                 return CMD_HELP;
7404                         }
7405                         break;
7406                 default:
7407                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7408                                 progname, argv[optind - 1]);
7409                         fallthrough;
7410                 case 'h':
7411                         return CMD_HELP;
7412                 }
7413         }
7414
7415         if (optind == argc) {
7416                 fprintf(stderr, "%s %s: DIR must be specified\n",
7417                         progname, argv[0]);
7418                 return CMD_HELP;
7419         }
7420
7421         if (xattr && !foreign_mode) {
7422                 /*
7423                  * only print a warning as this is armless and will be
7424                  * ignored
7425                  */
7426                 fprintf(stderr,
7427                         "%s %s: xattr has been specified for non-foreign layout\n",
7428                         progname, argv[0]);
7429         } else if (foreign_mode && !xattr) {
7430                 fprintf(stderr,
7431                         "%s %s: xattr must be provided in foreign mode\n",
7432                         progname, argv[0]);
7433                 return CMD_HELP;
7434         }
7435
7436         if (foreign_mode && (delete || default_stripe || lsa.lsa_nr_tgts ||
7437             lsa.lsa_tgts || setstripe_args_specified(&lsa))) {
7438                 fprintf(stderr,
7439                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
7440                         progname, argv[0]);
7441                 return CMD_HELP;
7442         }
7443
7444         if (!delete && lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT &&
7445             lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT && !foreign_mode) {
7446                 /* if no parameters set, create directory on least-used MDTs */
7447                 lsa.lsa_stripe_off = LMV_OFFSET_DEFAULT;
7448                 lsa.lsa_stripe_count = 1;
7449         }
7450
7451         if (delete &&
7452             (lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
7453              lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)) {
7454                 fprintf(stderr,
7455                         "%s %s: cannot specify -d with -c or -i options\n",
7456                         progname, argv[0]);
7457                 return CMD_HELP;
7458         }
7459
7460         if (mode_opt) {
7461                 mode = strtoul(mode_opt, &end, 8);
7462                 if (*end != '\0') {
7463                         fprintf(stderr,
7464                                 "%s %s: bad MODE '%s'\n",
7465                                 progname, argv[0], mode_opt);
7466                         return CMD_HELP;
7467                 }
7468                 previous_mode = umask(0);
7469         }
7470
7471         /* check max-inherit and warn user in some cases */
7472         if (default_stripe &&
7473             (lsa.lsa_stripe_count < 0 || lsa.lsa_stripe_count > 1)) {
7474                 if (max_inherit == LMV_INHERIT_UNLIMITED)
7475                         fprintf(stderr,
7476                         "%s %s: unrecommended max-inherit=-1 when default stripe-count=%lld\n",
7477                         progname, argv[0], lsa.lsa_stripe_count);
7478                 else if (max_inherit > LMV_INHERIT_DEFAULT_STRIPED + 2 &&
7479                          max_inherit != LMV_INHERIT_NONE)
7480                         fprintf(stderr,
7481                                 "%s %s: unrecommended max-inherit=%d when default stripe-count=%lld\n",
7482                                 progname, argv[0], max_inherit,
7483                                 lsa.lsa_stripe_count);
7484         }
7485
7486         if (default_stripe && lsa.lsa_nr_tgts > 1 && !mdt_count_set) {
7487                 fprintf(stderr,
7488                         "%s %s: trying to create unrecommended default striped directory layout,\n"
7489                         "       '-D -i x,y,z' will stripe every new directory across all MDTs,\n"
7490                         "       add -c with the number of MDTs to do this anyway\n",
7491                         progname, argv[0]);
7492                 return CMD_HELP;
7493         }
7494
7495         if (max_inherit_rr != LAYOUT_INHERIT_UNSET &&
7496             lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT &&
7497             lsa.lsa_stripe_off != LMV_OFFSET_DEFAULT) {
7498                 fprintf(stderr,
7499                         "%s %s: max-inherit-rr needs mdt-index=-1, not %lld\n",
7500                         progname, argv[0], lsa.lsa_stripe_off);
7501                 return CMD_HELP;
7502         }
7503
7504         /* foreign LMV/dir case */
7505         if (foreign_mode) {
7506                 if (argc > optind + 1) {
7507                         fprintf(stderr,
7508                                 "%s %s: cannot specify multiple foreign dirs\n",
7509                                 progname, argv[0]);
7510                         return CMD_HELP;
7511                 }
7512
7513                 dname = argv[optind];
7514                 result = llapi_dir_create_foreign(dname, mode, type, flags,
7515                                                   xattr);
7516                 if (result != 0)
7517                         fprintf(stderr,
7518                                 "%s mkdir: can't create foreign dir '%s': %s\n",
7519                                 progname, dname, strerror(-result));
7520                 return result;
7521         }
7522
7523         /*
7524          * initialize stripe parameters, in case param is converted to specific,
7525          * i.e, 'lfs mkdir -i -1 -c N', always allocate space for lsp_tgts.
7526          */
7527         param = calloc(1, offsetof(typeof(*param),
7528                        lsp_tgts[lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ?
7529                                 lsa.lsa_stripe_count : lsa.lsa_nr_tgts]));
7530         if (!param) {
7531                 fprintf(stderr,
7532                         "%s %s: cannot allocate memory for parameters: %s\n",
7533                         progname, argv[0], strerror(ENOMEM));
7534                 return CMD_HELP;
7535         }
7536
7537         /* if "lfs setdirstripe -D -i -1" is used, assume 1-stripe directory */
7538         if (default_stripe && lsa.lsa_stripe_off == LMV_OFFSET_DEFAULT &&
7539             (lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT ||
7540              lsa.lsa_stripe_count == 0))
7541                 lsa.lsa_stripe_count = 1;
7542         if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
7543                 param->lsp_stripe_count = lsa.lsa_stripe_count;
7544         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
7545                 param->lsp_stripe_offset = LMV_OFFSET_DEFAULT;
7546         else
7547                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
7548
7549         if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
7550                 param->lsp_stripe_pattern = lsa.lsa_pattern;
7551         else
7552                 param->lsp_stripe_pattern = LMV_HASH_TYPE_UNKNOWN;
7553
7554         if (overstriped) {
7555                 param->lsp_stripe_pattern |= LMV_HASH_FLAG_OVERSTRIPED;
7556                 max_inherit = LMV_INHERIT_DEFAULT_OVERSTRIPED;
7557         }
7558
7559         param->lsp_pool = lsa.lsa_pool_name;
7560         param->lsp_is_specific = false;
7561
7562         if (max_inherit == LAYOUT_INHERIT_UNSET) {
7563                 if (lsa.lsa_stripe_count == 0 || lsa.lsa_stripe_count == 1 ||
7564                     lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT)
7565                         max_inherit = LMV_INHERIT_DEFAULT_PLAIN;
7566                 else
7567                         max_inherit = LMV_INHERIT_DEFAULT_STRIPED;
7568         }
7569         param->lsp_max_inherit = max_inherit;
7570         if (default_stripe) {
7571
7572                 if (max_inherit_rr == LAYOUT_INHERIT_UNSET)
7573                         max_inherit_rr = LMV_INHERIT_RR_DEFAULT;
7574                 param->lsp_max_inherit_rr = max_inherit_rr;
7575         }
7576         if (strcmp(argv[0], "mkdir") == 0)
7577                 param->lsp_is_create = true;
7578         if (lsa.lsa_nr_tgts > 1) {
7579                 if (lsa.lsa_stripe_count > 0 &&
7580                     lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
7581                     lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
7582                         fprintf(stderr,
7583                                 "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
7584                                 argv[0], lsa.lsa_stripe_count,
7585                                 lsa.lsa_nr_tgts);
7586                         free(param);
7587                         return CMD_HELP;
7588                 }
7589
7590                 param->lsp_is_specific = true;
7591                 param->lsp_stripe_count = lsa.lsa_nr_tgts;
7592                 memcpy(param->lsp_tgts, mdts, sizeof(*mdts) * lsa.lsa_nr_tgts);
7593         }
7594
7595         dname = argv[optind];
7596         do {
7597                 if (default_stripe) {
7598                         result = llapi_dir_set_default_lmv(dname, param);
7599                         if (result)
7600                                 fprintf(stderr,
7601                                         "%s setdirstripe: cannot set default stripe on dir '%s': %s\n",
7602                                         progname, dname, strerror(-result));
7603                         continue;
7604                 }
7605
7606                 result = llapi_dir_create(dname, mode, param);
7607                 if (result)
7608                         fprintf(stderr,
7609                                 "%s setdirstripe: cannot create dir '%s': %s\n",
7610                                 progname, dname, strerror(-result));
7611         } while ((dname = argv[++optind]));
7612
7613         if (mode_opt)
7614                 umask(previous_mode);
7615
7616         free(param);
7617         return result;
7618 }
7619
7620 static int lfs_rmentry(int argc, char **argv)
7621 {
7622         char *dname;
7623         int index;
7624         int result = 0;
7625
7626         if (argc <= 1) {
7627                 fprintf(stderr, "error: %s: missing dirname\n",
7628                         argv[0]);
7629                 return CMD_HELP;
7630         }
7631
7632         index = 1;
7633         dname = argv[index];
7634         while (dname) {
7635                 int rc2;
7636
7637                 rc2 = llapi_direntry_remove(dname);
7638                 if (rc2) {
7639                         fprintf(stderr,
7640                                 "%s %s: remove dir entry '%s' failed: %s\n",
7641                                 progname, argv[0], dname, strerror(-rc2));
7642                         if (!result)
7643                                 result = rc2;
7644                 }
7645                 dname = argv[++index];
7646         }
7647         return result;
7648 }
7649
7650 static int lfs_unlink_foreign(int argc, char **argv)
7651 {
7652         char *name;
7653         int   index;
7654         int   result = 0;
7655
7656         if (argc <= 1) {
7657                 fprintf(stderr, "error: %s: missing pathname\n",
7658                         argv[0]);
7659                 return CMD_HELP;
7660         }
7661
7662         index = 1;
7663         name = argv[index];
7664         while (name != NULL) {
7665                 result = llapi_unlink_foreign(name);
7666                 if (result) {
7667                         fprintf(stderr,
7668                                 "error: %s: unlink foreign entry '%s' failed\n",
7669                                 argv[0], name);
7670                         break;
7671                 }
7672                 name = argv[++index];
7673         }
7674         return result;
7675 }
7676
7677 static int lfs_mv(int argc, char **argv)
7678 {
7679         struct lmv_user_md lmu = { LMV_USER_MAGIC };
7680         struct find_param param = {
7681                 .fp_max_depth = -1,
7682                 .fp_mdt_index = -1,
7683         };
7684         char *end;
7685         int c;
7686         int rc = 0;
7687         struct option long_opts[] = {
7688         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
7689         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
7690         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7691         { .name = NULL } };
7692
7693         while ((c = getopt_long(argc, argv, "m:M:v", long_opts, NULL)) != -1) {
7694                 switch (c) {
7695 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7696                 case 'M':
7697                         fprintf(stderr,
7698                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
7699 #endif
7700                 case 'm':
7701                         errno = 0;
7702                         lmu.lum_stripe_offset = strtoul(optarg, &end, 0);
7703                         if (errno != 0 || *end != '\0' ||
7704                             lmu.lum_stripe_offset >= UINT32_MAX) {
7705                                 fprintf(stderr, "%s mv: bad MDT index '%s'\n",
7706                                         progname, optarg);
7707                                 return CMD_HELP;
7708                         }
7709                         break;
7710                 case 'v':
7711                         param.fp_verbose = VERBOSE_DETAIL;
7712                         break;
7713                 default:
7714                         fprintf(stderr, "%s mv: unrecognized option '%s'\n",
7715                                 progname, argv[optind - 1]);
7716                         return CMD_HELP;
7717                 }
7718         }
7719
7720         if (lmu.lum_stripe_offset == LMV_OFFSET_DEFAULT) {
7721                 fprintf(stderr, "%s mv: MDT index must be specified\n",
7722                         progname);
7723                 return CMD_HELP;
7724         }
7725
7726         if (optind >= argc) {
7727                 fprintf(stderr, "%s mv: DIR must be specified\n", progname);
7728                 return CMD_HELP;
7729         }
7730
7731         lmu.lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
7732
7733         /* initialize migrate mdt parameters */
7734         param.fp_lmv_md = &lmu;
7735         param.fp_migrate = 1;
7736         rc = llapi_migrate_mdt(argv[optind], &param);
7737         if (rc != 0)
7738                 fprintf(stderr, "%s mv: cannot migrate '%s' to MDT%04x: %s\n",
7739                         progname, argv[optind], lmu.lum_stripe_offset,
7740                         strerror(-rc));
7741         return rc;
7742 }
7743
7744 static int lfs_osts(int argc, char **argv)
7745 {
7746         return lfs_tgts(argc, argv);
7747 }
7748
7749 static int lfs_mdts(int argc, char **argv)
7750 {
7751         return lfs_tgts(argc, argv);
7752 }
7753
7754 static int lfs_df(int argc, char **argv)
7755 {
7756         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
7757         enum mntdf_flags flags = MNTDF_SHOW;
7758         int ops = LL_STATFS_LMV | LL_STATFS_LOV;
7759         int c, rc = 0, rc1 = 0, index = 0, arg_idx = 0;
7760         char fsname[PATH_MAX] = "", *pool_name = NULL;
7761         struct option long_opts[] = {
7762         { .val = 'h',   .name = "human-readable", .has_arg = no_argument },
7763         { .val = 'H',   .name = "si",           .has_arg = no_argument },
7764         { .val = 'i',   .name = "inodes",       .has_arg = no_argument },
7765         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
7766         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
7767         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7768         { .name = NULL} };
7769
7770         while ((c = getopt_long(argc, argv, "hHilp:v", long_opts, NULL)) != -1) {
7771                 switch (c) {
7772                 case 'h':
7773                         flags = (flags & ~MNTDF_DECIMAL) | MNTDF_COOKED;
7774                         break;
7775                 case 'H':
7776                         flags |= MNTDF_COOKED | MNTDF_DECIMAL;
7777                         break;
7778                 case 'i':
7779                         flags |= MNTDF_INODES;
7780                         break;
7781                 case 'l':
7782                         flags |= MNTDF_LAZY;
7783                         break;
7784                 case 'p':
7785                         pool_name = optarg;
7786                         break;
7787                 case 'v':
7788                         flags |= MNTDF_VERBOSE;
7789                         break;
7790                 default:
7791                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7792                                 progname, argv[optind - 1]);
7793                         return CMD_HELP;
7794                 }
7795         }
7796
7797         /* Handle case where path is not specified */
7798         if (optind == argc) {
7799                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7800                         /* Check if we have a mount point */
7801                         if (mntdir[0] == '\0')
7802                                 continue;
7803
7804                         rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
7805                         if (rc || path[0] != '\0')
7806                                 break;
7807
7808                         fsname[0] = '\0'; /* avoid matching in next loop */
7809                         mntdir[0] = '\0'; /* avoid matching in next loop */
7810                         path[0] = '\0'; /* clean for next loop */
7811                 }
7812                 return rc;
7813         }
7814
7815         /* Loop through all the remaining arguments. These are Lustre FS
7816          * paths.
7817          */
7818         for (arg_idx = optind; arg_idx <= argc - 1; arg_idx++) {
7819                 bool valid = false;
7820
7821                 fsname[0] = '\0'; /* start clean */
7822                 mntdir[0] = '\0'; /* start clean */
7823                 path[0] = '\0';   /* start clean */
7824
7825                 /* path does not exists at all */
7826                 if (!realpath(argv[arg_idx], path)) {
7827                         rc = -errno;
7828                         fprintf(stderr, "error: invalid path '%s': %s\n",
7829                                 argv[arg_idx], strerror(-rc));
7830                         /* save first seen error */
7831                         if (!rc1)
7832                                 rc1 = rc;
7833
7834                         continue;
7835                 }
7836
7837                 /* path exists but may not be a Lustre filesystem */
7838                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7839                         /* Check if we have a mount point */
7840                         if (mntdir[0] == '\0')
7841                                 continue;
7842
7843                         rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
7844                         if (rc || path[0] != '\0') {
7845                                 valid = true;
7846
7847                                 /* save first seen error */
7848                                 if (!rc1)
7849                                         rc1 = rc;
7850                                 break;
7851                         }
7852                 }
7853
7854                 if (!valid) {
7855                         llapi_printf(LLAPI_MSG_ERROR,
7856                                      "%s:%s Not a Lustre filesystem\n",
7857                                      argv[0], argv[arg_idx]);
7858                         /* save first seen error */
7859                         if (!rc1)
7860                                 rc1 = -EOPNOTSUPP;
7861                 }
7862         }
7863
7864         return rc1;
7865 }
7866
7867 static int print_instance(const char *mntdir, char *buf, size_t buflen,
7868                           bool opt_instance, bool opt_fsname, bool opt_mntdir)
7869 {
7870         int rc = 0;
7871
7872         if (opt_fsname == opt_instance) { /* both true or both false */
7873                 rc = llapi_getname(mntdir, buf, buflen);
7874         } else if (opt_fsname) {
7875                 /*
7876                  * llapi_search_mounts() fills @buf with fsname, but that is not
7877                  * called if explicit paths are specified on the command-line
7878                  */
7879                 if (buf[0] == '\0')
7880                         rc = llapi_get_fsname(mntdir, buf, buflen);
7881         } else /* if (opt_instance) */ {
7882                 rc = llapi_get_instance(mntdir, buf, buflen);
7883         }
7884
7885         if (rc < 0) {
7886                 fprintf(stderr, "cannot get instance for '%s': %s\n",
7887                         mntdir, strerror(-rc));
7888                 return rc;
7889         }
7890
7891         if (opt_mntdir)
7892                 printf("%s %s\n", buf, mntdir);
7893         else
7894                 printf("%s\n", buf);
7895
7896         return 0;
7897 }
7898
7899 static int lfs_getname(int argc, char **argv)
7900 {
7901         struct option long_opts[] = {
7902         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7903         { .val = 'i',   .name = "instance",     .has_arg = no_argument },
7904         { .val = 'n',   .name = "fsname",       .has_arg = no_argument },
7905         { .name = NULL} };
7906         bool opt_instance = false, opt_fsname = false;
7907         char fsname[PATH_MAX] = "";
7908         int rc = 0, rc2, c;
7909
7910         while ((c = getopt_long(argc, argv, "hin", long_opts, NULL)) != -1) {
7911                 switch (c) {
7912                 case 'i':
7913                         opt_instance = true;
7914                         break;
7915                 case 'n':
7916                         opt_fsname = true;
7917                         break;
7918                 default:
7919                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7920                                 progname, argv[optind - 1]);
7921                         fallthrough;
7922                 case 'h':
7923                         return CMD_HELP;
7924                 }
7925         }
7926
7927         if (optind == argc) { /* no paths specified, get all paths. */
7928                 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "";
7929                 int index = 0;
7930
7931                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7932                         rc2 = print_instance(mntdir, fsname, sizeof(fsname),
7933                                              opt_instance, opt_fsname, true);
7934                         if (!rc)
7935                                 rc = rc2;
7936                         path[0] = fsname[0] = mntdir[0] = '\0';
7937                 }
7938         } else { /* paths specified, only attempt to search these. */
7939                 bool opt_mntdir;
7940
7941                 /* if only one path is given, print only requested info */
7942                 opt_mntdir = argc - optind > 1 || (opt_instance == opt_fsname);
7943
7944                 for (; optind < argc; optind++) {
7945                         rc2 = print_instance(argv[optind], fsname,
7946                                              sizeof(fsname), opt_instance,
7947                                              opt_fsname, opt_mntdir);
7948                         if (!rc)
7949                                 rc = rc2;
7950                         fsname[0] = '\0';
7951                 }
7952         }
7953
7954         return rc;
7955 }
7956
7957 static int lfs_check(int argc, char **argv)
7958 {
7959         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
7960         int num_types = 1;
7961         char *obd_types[3];
7962         char obd_type1[4];
7963         char obd_type2[4];
7964         char obd_type3[4];
7965         int rc;
7966
7967         if (argc < 2 || argc > 3) {
7968                 fprintf(stderr, "%s check: server type must be specified\n",
7969                         progname);
7970                 return CMD_HELP;
7971         }
7972
7973         obd_types[0] = obd_type1;
7974         obd_types[1] = obd_type2;
7975         obd_types[2] = obd_type3;
7976
7977         if (strcmp(argv[1], "osts") == 0) {
7978                 strcpy(obd_types[0], "osc");
7979         } else if (strcmp(argv[1], "mdts") == 0 ||
7980                    strcmp(argv[1], "mds") == 0) {
7981                 strcpy(obd_types[0], "mdc");
7982         } else if (strcmp(argv[1], "mgts") == 0) {
7983                 strcpy(obd_types[0], "mgc");
7984         } else if (strcmp(argv[1], "all") == 0 ||
7985                    strcmp(argv[1], "servers") == 0) {
7986                 num_types = 3;
7987                 strcpy(obd_types[0], "osc");
7988                 strcpy(obd_types[1], "mdc");
7989                 strcpy(obd_types[2], "mgc");
7990         } else {
7991                 fprintf(stderr, "%s check: unrecognized option '%s'\n",
7992                         progname, argv[1]);
7993                 return CMD_HELP;
7994         }
7995
7996         if (argc >= 3 && !realpath(argv[2], path)) {
7997                 rc = -errno;
7998                 fprintf(stderr, "error: invalid path '%s': %s\n",
7999                         argv[2], strerror(-rc));
8000                 return rc;
8001         }
8002
8003         rc = llapi_search_mounts(path, 0, mntdir, NULL);
8004         if (rc < 0 || mntdir[0] == '\0') {
8005                 fprintf(stderr,
8006                         "%s %s: cannot find mounted Lustre filesystem: %s\n",
8007                         progname, argv[0],
8008                         (rc < 0) ? strerror(-rc) : strerror(ENODEV));
8009                 return rc;
8010         }
8011
8012         rc = llapi_target_check(num_types, obd_types, path);
8013         if (rc)
8014                 fprintf(stderr, "%s %s: cannot check target '%s': %s\n",
8015                         progname, argv[0], argv[1], strerror(-rc));
8016
8017         return rc;
8018 }
8019
8020 #ifdef HAVE_SYS_QUOTA_H
8021 #define ADD_OVERFLOW(a, b) \
8022                      ((((a) + (b)) < (a)) ? \
8023                       ((a) = ULONG_MAX) : ((a) = (a) + (b)))
8024
8025 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
8026  * returns the value or ULONG_MAX on integer overflow or incorrect format
8027  * Notes:
8028  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
8029  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
8030  *        3. empty integer value is interpreted as 0
8031  */
8032 static unsigned long str2sec(const char *timestr)
8033 {
8034         const char spec[] = "smhdw";
8035         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
8036         unsigned long val = 0;
8037         char *tail;
8038
8039         if (strpbrk(timestr, spec) == NULL) {
8040                 /*
8041                  * no specifiers inside the time string,
8042                  * should treat it as an integer value
8043                  */
8044                 val = strtoul(timestr, &tail, 10);
8045                 return *tail ? ULONG_MAX : val;
8046         }
8047
8048         /* format string is XXwXXdXXhXXmXXs */
8049         while (*timestr) {
8050                 unsigned long v;
8051                 int ind;
8052                 char *ptr;
8053
8054                 v = strtoul(timestr, &tail, 10);
8055                 if (v == ULONG_MAX || *tail == '\0')
8056                         /*
8057                          * value too large (ULONG_MAX or more)
8058                          * or missing specifier
8059                          */
8060                         goto error;
8061
8062                 ptr = strchr(spec, *tail);
8063                 if (!ptr)
8064                         /* unknown specifier */
8065                         goto error;
8066
8067                 ind = ptr - spec;
8068
8069                 /* check if product will overflow the type */
8070                 if (!(v < ULONG_MAX / mult[ind]))
8071                         goto error;
8072
8073                 ADD_OVERFLOW(val, mult[ind] * v);
8074                 if (val == ULONG_MAX)
8075                         goto error;
8076
8077                 timestr = tail + 1;
8078         }
8079
8080         return val;
8081
8082 error:
8083         return ULONG_MAX;
8084 }
8085
8086 #define ARG2ULL(nr, str, def_units)                                     \
8087 do {                                                                    \
8088         unsigned long long limit, units = def_units;                    \
8089         int rc;                                                         \
8090                                                                         \
8091         rc = llapi_parse_size(str, &limit, &units, 1);                  \
8092         if (rc < 0) {                                                   \
8093                 fprintf(stderr, "%s: invalid limit '%s'\n",             \
8094                         progname, str);                                 \
8095                 return CMD_HELP;                                        \
8096         }                                                               \
8097         nr = limit;                                                     \
8098 } while (0)
8099
8100 static inline int has_times_option(int argc, char **argv)
8101 {
8102         int i;
8103
8104         for (i = 1; i < argc; i++)
8105                 if (!strcmp(argv[i], "-t"))
8106                         return 1;
8107
8108         return 0;
8109 }
8110
8111 static inline int lfs_verify_poolarg(char *pool)
8112 {
8113         if (strnlen(optarg, LOV_MAXPOOLNAME + 1) > LOV_MAXPOOLNAME) {
8114                 fprintf(stderr,
8115                         "Pool name '%.*s' is longer than %d\n",
8116                         LOV_MAXPOOLNAME, pool, LOV_MAXPOOLNAME);
8117                 return 1;
8118         }
8119         return 0;
8120 }
8121
8122 /* special grace time, only notify the user when its quota is over soft limit
8123  * but doesn't block new writes until the hard limit is reached.
8124  */
8125 #define NOTIFY_GRACE            "notify"
8126 #define NOTIFY_GRACE_TIME       LQUOTA_GRACE_MASK
8127
8128 #ifndef toqb
8129 static inline __u64 lustre_stoqb(size_t space)
8130 {
8131         return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
8132 }
8133 #else
8134 #define lustre_stoqb   toqb
8135 #endif
8136
8137 static int lfs_setquota_times(int argc, char **argv, struct if_quotactl *qctl)
8138 {
8139         int c, rc;
8140         char *mnt, *obd_type = (char *)qctl->obd_type;
8141         struct obd_dqblk *dqb = &qctl->qc_dqblk;
8142         struct obd_dqinfo *dqi = &qctl->qc_dqinfo;
8143         struct option long_opts[] = {
8144         { .val = 'b',   .name = "block-grace",  .has_arg = required_argument },
8145         { .val = 'g',   .name = "group",        .has_arg = no_argument },
8146         { .val = 'h',   .name = "help",         .has_arg = no_argument },
8147         { .val = 'i',   .name = "inode-grace",  .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         { .val = LFS_POOL_OPT,
8152                         .name = "pool",         .has_arg = required_argument },
8153         { .name = NULL } };
8154         int qtype;
8155
8156         qctl->qc_cmd  = LUSTRE_Q_SETINFO;
8157         qctl->qc_type = ALLQUOTA;
8158
8159         while ((c = getopt_long(argc, argv, "b:ghi:ptu",
8160                                 long_opts, NULL)) != -1) {
8161                 switch (c) {
8162                 case 'u':
8163                         qtype = USRQUOTA;
8164                         goto quota_type;
8165                 case 'g':
8166                         qtype = GRPQUOTA;
8167                         goto quota_type;
8168                 case 'p':
8169                         qtype = PRJQUOTA;
8170 quota_type:
8171                         if (qctl->qc_type != ALLQUOTA) {
8172                                 fprintf(stderr,
8173                                         "%s: -u/g/p cannot be used more than once\n",
8174                                         progname);
8175                                 return CMD_HELP;
8176                         }
8177                         qctl->qc_type = qtype;
8178                         break;
8179                 case 'b':
8180                         if (strncmp(optarg, NOTIFY_GRACE,
8181                                     strlen(NOTIFY_GRACE)) == 0) {
8182                                 dqi->dqi_bgrace = NOTIFY_GRACE_TIME;
8183                         } else {
8184                                 dqi->dqi_bgrace = str2sec(optarg);
8185                                 if (dqi->dqi_bgrace >= NOTIFY_GRACE_TIME) {
8186                                         fprintf(stderr,
8187                                                 "%s: bad block-grace: %s\n",
8188                                                 progname, optarg);
8189                                         return CMD_HELP;
8190                                 }
8191                         }
8192                         dqb->dqb_valid |= QIF_BTIME;
8193                         break;
8194                 case 'i':
8195                         if (strncmp(optarg, NOTIFY_GRACE,
8196                                     strlen(NOTIFY_GRACE)) == 0) {
8197                                 dqi->dqi_igrace = NOTIFY_GRACE_TIME;
8198                         } else {
8199                                 dqi->dqi_igrace = str2sec(optarg);
8200                                 if (dqi->dqi_igrace >= NOTIFY_GRACE_TIME) {
8201                                         fprintf(stderr,
8202                                                 "%s: bad inode-grace: %s\n",
8203                                                 progname, optarg);
8204                                         return CMD_HELP;
8205                                 }
8206                         }
8207                         dqb->dqb_valid |= QIF_ITIME;
8208                         break;
8209                 case 't': /* Yes, of course! */
8210                         break;
8211                 case LFS_POOL_OPT:
8212                         if (lfs_verify_poolarg(optarg))
8213                                 return -1;
8214                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
8215                         qctl->qc_cmd  = LUSTRE_Q_SETINFOPOOL;
8216                         break;
8217                 /* getopt prints error message for us when opterr != 0 */
8218                 default:
8219                         fprintf(stderr, "%s: unrecognized option '%s'\n",
8220                                 progname, argv[optind - 1]);
8221                         fallthrough;
8222                 case 'h':
8223                         return CMD_HELP;
8224                 }
8225         }
8226
8227         if (qctl->qc_type == ALLQUOTA) {
8228                 fprintf(stderr, "%s: neither -u, -g nor -p specified\n",
8229                         progname);
8230                 return CMD_HELP;
8231         }
8232
8233         if (optind != argc - 1) {
8234                 fprintf(stderr, "%s: unexpected parameter '%s'\n",
8235                         progname, argv[optind + 1]);
8236                 return CMD_HELP;
8237         }
8238
8239         mnt = argv[optind];
8240         rc = llapi_quotactl(mnt, qctl);
8241         if (rc) {
8242                 if (*obd_type)
8243                         fprintf(stderr, "%s %s ", obd_type,
8244                                 obd_uuid2str(&qctl->obd_uuid));
8245                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
8246                 return rc;
8247         }
8248
8249         return 0;
8250 }
8251
8252 static int lfs_reset_quota(char *mnt, struct if_quotactl *qctl)
8253 {
8254         struct if_quotactl tmp_qctl;
8255         int index, md_count, dt_count;
8256         int wait_phase = 0, wait_index = 0, wait_count = 0;
8257         int rc, rc2;
8258
8259         /* reset the quota ID, the existing quota setting will be returned */
8260         rc = llapi_quotactl(mnt, qctl);
8261         if (rc)
8262                 return rc;
8263
8264         /* sanity check */
8265         if ((qctl->qc_dqblk.dqb_valid & QIF_LIMITS) != QIF_LIMITS) {
8266                 fprintf(stderr,
8267                         "the existing quota settings are not returned!\n");
8268                 return -EINVAL;
8269         }
8270
8271         rc = llapi_get_obd_count(mnt, &md_count, 1);
8272         if (rc) {
8273                 fprintf(stderr, "can not get mdt count: %s\n", strerror(-rc));
8274                 return rc;
8275         }
8276
8277         rc = llapi_get_obd_count(mnt, &dt_count, 0);
8278         if (rc) {
8279                 fprintf(stderr, "can not get ost count: %s\n", strerror(-rc));
8280                 return rc;
8281         }
8282
8283         memset(&tmp_qctl, 0, sizeof(tmp_qctl));
8284         tmp_qctl.qc_type = qctl->qc_type;
8285         tmp_qctl.qc_id = qctl->qc_id;
8286         tmp_qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
8287
8288 retry:
8289         if (wait_phase == 0) {
8290                 for (index = wait_index; index < md_count; index++) {
8291                         tmp_qctl.qc_idx = index;
8292                         tmp_qctl.qc_valid = QC_MDTIDX;
8293                         rc = llapi_quotactl(mnt, &tmp_qctl);
8294                         if (rc == -ENODEV || rc == -ENODATA)
8295                                 continue;
8296                         if (rc) {
8297                                 fprintf(stderr, "quotactl mdt%d failed: %s\n",
8298                                         index, strerror(-rc));
8299                                 break;
8300                         }
8301                         /* check whether the md quota grant is reset */
8302                         if (tmp_qctl.qc_dqblk.dqb_valid & QIF_LIMITS &&
8303                             tmp_qctl.qc_dqblk.dqb_ihardlimit != 0)
8304                                 break;
8305                 }
8306
8307                 if (index < md_count) {
8308                         wait_phase = 0;
8309                         wait_index = index;
8310                         goto wait;
8311                 }
8312         } else {
8313                 for (index = wait_index; index < dt_count; index++) {
8314                         tmp_qctl.qc_idx = index;
8315                         tmp_qctl.qc_valid = QC_OSTIDX;
8316                         rc = llapi_quotactl(mnt, &tmp_qctl);
8317                         if (rc == -ENODEV || rc == -ENODATA)
8318                                 continue;
8319                         if (rc) {
8320                                 fprintf(stderr, "quotactl mdt%d failed: %s\n",
8321                                         index, strerror(-rc));
8322                                 break;
8323                         }
8324                         /* check whether the dt quota grant is reset */
8325                         if (tmp_qctl.qc_dqblk.dqb_valid & QIF_LIMITS &&
8326                             tmp_qctl.qc_dqblk.dqb_bhardlimit != 0)
8327                                 break;
8328                 }
8329
8330                 if (index < dt_count) {
8331                         wait_phase = 1;
8332                         wait_index = index;
8333                         goto wait;
8334                 }
8335         }
8336
8337         if (wait_phase == 0) {
8338                 wait_phase = 1;
8339                 goto retry;
8340         }
8341
8342         goto out;
8343
8344 wait:
8345         if (rc || wait_count > 30) {
8346                 fprintf(stderr, "fail to reset the quota ID %d on OBDs\n",
8347                         qctl->qc_id);
8348                 goto out;
8349         }
8350
8351         wait_count++;
8352         sleep(1);
8353         fprintf(stdout, "wait %d seconds for OBDs to reset the quota ID %u\n",
8354                 wait_count, qctl->qc_id);
8355         goto retry;
8356
8357
8358 out:
8359         /* restore the quota setting */
8360         if (qctl->qc_dqblk.dqb_isoftlimit == 0 &&
8361             qctl->qc_dqblk.dqb_ihardlimit == 0 &&
8362             qctl->qc_dqblk.dqb_bsoftlimit == 0 &&
8363             qctl->qc_dqblk.dqb_bhardlimit == 0)
8364                 return rc;
8365
8366         memcpy(&tmp_qctl, qctl, sizeof(tmp_qctl));
8367         tmp_qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
8368         rc2 = llapi_quotactl(mnt, &tmp_qctl);
8369         if (!rc2)
8370                 return rc;
8371
8372         fprintf(stderr,
8373                 "fail to restore the quota setting: %s, please restore it manually by\n  lfs setquota %s %d",
8374                 strerror(-rc2),
8375                 qctl->qc_type == USRQUOTA ? "-u" :
8376                                 (qctl->qc_type == GRPQUOTA ? "-g" : "-p"),
8377                 qctl->qc_id);
8378
8379         if (qctl->qc_dqblk.dqb_isoftlimit != 0)
8380                 fprintf(stderr, " -i %llu",
8381                         (unsigned long long)qctl->qc_dqblk.dqb_isoftlimit);
8382         if (qctl->qc_dqblk.dqb_ihardlimit != 0)
8383                 fprintf(stderr, " -I %llu",
8384                         (unsigned long long)qctl->qc_dqblk.dqb_ihardlimit);
8385         if (qctl->qc_dqblk.dqb_bsoftlimit != 0)
8386                 fprintf(stderr, " -b %llu",
8387                         (unsigned long long)qctl->qc_dqblk.dqb_bsoftlimit);
8388         if (qctl->qc_dqblk.dqb_bhardlimit != 0)
8389                 fprintf(stderr, " -B %llu",
8390                         (unsigned long long)qctl->qc_dqblk.dqb_bhardlimit);
8391
8392         fprintf(stderr, " %s\n", mnt);
8393         if (!rc)
8394                 rc = rc2;
8395
8396         return rc;
8397 }
8398
8399 #define BSLIMIT (1 << 0)
8400 #define BHLIMIT (1 << 1)
8401 #define ISLIMIT (1 << 2)
8402 #define IHLIMIT (1 << 3)
8403
8404 int lfs_setquota(int argc, char **argv)
8405 {
8406         int c, rc = 0;
8407         struct if_quotactl *qctl;
8408         char *mnt, *obd_type;
8409         struct obd_dqblk *dqb;
8410         struct option long_opts[] = {
8411         { .val = 'b',   .name = "block-softlimit",
8412                                                 .has_arg = required_argument },
8413         { .val = 'B',   .name = "block-hardlimit",
8414                                                 .has_arg = required_argument },
8415         { .val = 'd',   .name = "default",      .has_arg = no_argument },
8416         { .val = LFS_SETQUOTA_DELETE,
8417                         .name = "delete",       .has_arg = no_argument },
8418         { .val = 'g',   .name = "group",        .has_arg = required_argument },
8419         { .val = 'G',   .name = "default-grp",  .has_arg = no_argument },
8420         { .val = 'h',   .name = "help",         .has_arg = no_argument },
8421         { .val = 'i',   .name = "inode-softlimit",
8422                                                 .has_arg = required_argument },
8423         { .val = 'I',   .name = "inode-hardlimit",
8424                                                 .has_arg = required_argument },
8425         { .val = 'p',   .name = "projid",       .has_arg = required_argument },
8426         { .val = 'P',   .name = "default-prj",  .has_arg = no_argument },
8427         { .val = 'r',   .name = "reset",        .has_arg = no_argument },
8428         { .val = 'u',   .name = "user",         .has_arg = required_argument },
8429         { .val = 'U',   .name = "default-usr",  .has_arg = no_argument },
8430         { .val = LFS_POOL_OPT,
8431                         .name = "pool",         .has_arg = required_argument },
8432         { .name = NULL } };
8433         unsigned int limit_mask = 0;
8434         bool use_default = false;
8435         int qtype, qctl_len;
8436
8437         qctl_len = sizeof(*qctl) + LOV_MAXPOOLNAME + 1;
8438         qctl = malloc(qctl_len);
8439         if (!qctl)
8440                 return -ENOMEM;
8441
8442         memset(qctl, 0, qctl_len);
8443         obd_type = (char *)qctl->obd_type;
8444         dqb = &qctl->qc_dqblk;
8445
8446         if (has_times_option(argc, argv)) {
8447                 rc = lfs_setquota_times(argc, argv, qctl);
8448                 goto out;
8449         }
8450
8451         qctl->qc_cmd  = LUSTRE_Q_SETQUOTA;
8452         qctl->qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
8453                                    * so it can be used as a marker that qc_type
8454                                    * isn't reinitialized from command line
8455                                    */
8456         while ((c = getopt_long(argc, argv, "b:B:dDg:Ghi:I:p:Pru:U",
8457                 long_opts, NULL)) != -1) {
8458                 switch (c) {
8459                 case 'U':
8460                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8461                         qtype = USRQUOTA;
8462                         qctl->qc_id = 0;
8463                         goto quota_type_def;
8464                 case 'u':
8465                         qtype = USRQUOTA;
8466                         rc = name2uid(&qctl->qc_id, optarg);
8467                         goto quota_type;
8468                 case 'G':
8469                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8470                         qtype = GRPQUOTA;
8471                         qctl->qc_id = 0;
8472                         goto quota_type_def;
8473                 case 'g':
8474                         qtype = GRPQUOTA;
8475                         rc = name2gid(&qctl->qc_id, optarg);
8476                         goto quota_type;
8477                 case 'P':
8478                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8479                         qtype = PRJQUOTA;
8480                         qctl->qc_id = 0;
8481                         goto quota_type_def;
8482                 case 'p':
8483                         qtype = PRJQUOTA;
8484                         rc = name2projid(&qctl->qc_id, optarg);
8485 quota_type:
8486                         if (rc) {
8487                                 if (str2quotaid(&qctl->qc_id, optarg)) {
8488                                         fprintf(stderr,
8489                                                 "%s setquota: invalid id '%s'\n",
8490                                                 progname, optarg);
8491                                         rc = -1;
8492                                         goto out;
8493                                 }
8494                         }
8495
8496                         if (qctl->qc_id == 0) {
8497                                 fprintf(stderr,
8498                                         "%s setquota: can't set quota for root usr/group/project.\n",
8499                                         progname);
8500                                 rc = -1;
8501                                 goto out;
8502                         }
8503
8504 quota_type_def:
8505                         if (qctl->qc_type != ALLQUOTA) {
8506                                 fprintf(stderr,
8507                                         "%s setquota: only one of -u, -U, -g, -G, -p or -P may be specified\n",
8508                                         progname);
8509                                 rc = CMD_HELP;
8510                                 goto out;
8511                         }
8512                         qctl->qc_type = qtype;
8513                         break;
8514 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
8515                 case 'd':
8516                         fprintf(stderr,
8517                                 "%s setquota: '-d' deprecated, use '-D' or '--default'\n",
8518                                 progname);
8519                         fallthrough;
8520 #endif
8521                 case 'D':
8522                         use_default = true;
8523                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8524                         break;
8525                 case LFS_SETQUOTA_DELETE:
8526                         qctl->qc_cmd = LUSTRE_Q_DELETEQID;
8527                         break;
8528                 case 'b':
8529                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
8530                         dqb->dqb_bsoftlimit >>= 10;
8531                         limit_mask |= BSLIMIT;
8532                         if (dqb->dqb_bsoftlimit &&
8533                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
8534                                 fprintf(stderr,
8535                                         "%s setquota: warning: block softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8536                                         progname,
8537                                         (unsigned long long)dqb->dqb_bsoftlimit,
8538                                         progname);
8539                         break;
8540                 case 'B':
8541                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
8542                         dqb->dqb_bhardlimit >>= 10;
8543                         limit_mask |= BHLIMIT;
8544                         if (dqb->dqb_bhardlimit &&
8545                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
8546                                 fprintf(stderr,
8547                                         "%s setquota: warning: block hardlimit '%llu' smaller than minimum qunit size\n"
8548                                         "See '%s help setquota' or Lustre manual for details\n",
8549                                         progname,
8550                                         (unsigned long long)dqb->dqb_bhardlimit,
8551                                         progname);
8552                         break;
8553                 case 'i':
8554                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
8555                         limit_mask |= ISLIMIT;
8556                         if (dqb->dqb_isoftlimit &&
8557                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
8558                                 fprintf(stderr,
8559                                         "%s setquota: warning: inode softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8560                                         progname,
8561                                         (unsigned long long)dqb->dqb_isoftlimit,
8562                                         progname);
8563                         break;
8564                 case 'I':
8565                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
8566                         limit_mask |= IHLIMIT;
8567                         if (dqb->dqb_ihardlimit &&
8568                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
8569                                 fprintf(stderr,
8570                                         "%s setquota: warning: inode hardlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8571                                         progname,
8572                                         (unsigned long long)dqb->dqb_ihardlimit,
8573                                         progname);
8574                         break;
8575                 case LFS_POOL_OPT:
8576                         if (lfs_verify_poolarg(optarg)) {
8577                                 rc = -1;
8578                                 goto out;
8579                         }
8580                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
8581                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_SETDEFAULT ?
8582                                                 LUSTRE_Q_SETDEFAULT_POOL :
8583                                                 LUSTRE_Q_SETQUOTAPOOL;
8584                         break;
8585                 case 'r':
8586                         qctl->qc_cmd = LUSTRE_Q_RESETQID;
8587                         break;
8588                 default:
8589                         fprintf(stderr,
8590                                 "%s setquota: unrecognized option '%s'\n",
8591                                 progname, argv[optind - 1]);
8592                         fallthrough;
8593                 case 'h':
8594                         rc = CMD_HELP;
8595                         goto out;
8596                 }
8597         }
8598
8599         if (qctl->qc_type == ALLQUOTA) {
8600                 fprintf(stderr,
8601                         "%s setquota: either -u or -g must be specified\n",
8602                         progname);
8603                 rc = CMD_HELP;
8604                 goto out;
8605         }
8606
8607         if (!use_default && qctl->qc_cmd != LUSTRE_Q_DELETEQID &&
8608             qctl->qc_cmd != LUSTRE_Q_RESETQID && limit_mask == 0) {
8609                 fprintf(stderr,
8610                         "%s setquota: at least one limit must be specified\n",
8611                         progname);
8612                 rc = CMD_HELP;
8613                 goto out;
8614         }
8615
8616         if ((use_default || qctl->qc_cmd == LUSTRE_Q_DELETEQID ||
8617              qctl->qc_cmd == LUSTRE_Q_RESETQID) && limit_mask != 0) {
8618                 fprintf(stderr,
8619                         "%s setquota: limits should not be specified when using default quota, deleting or resetting quota ID\n",
8620                         progname);
8621                 rc = CMD_HELP;
8622                 goto out;
8623         }
8624
8625         if (use_default && qctl->qc_id == 0) {
8626                 fprintf(stderr,
8627                         "%s setquota: can not set default quota for root user/group/project\n",
8628                         progname);
8629                 rc = CMD_HELP;
8630                 goto out;
8631         }
8632
8633         if ((qctl->qc_cmd == LUSTRE_Q_DELETEQID ||
8634              qctl->qc_cmd == LUSTRE_Q_RESETQID)  && qctl->qc_id == 0) {
8635                 fprintf(stderr,
8636                         "%s setquota: can not delete or reset root user/group/project\n",
8637                         progname);
8638                 rc = CMD_HELP;
8639                 goto out;
8640         }
8641
8642         if (optind != argc - 1) {
8643                 fprintf(stderr,
8644                         "%s setquota: filesystem not specified or unexpected argument '%s'\n",
8645                         progname, argv[optind]);
8646                 rc = CMD_HELP;
8647                 goto out;
8648         }
8649
8650         mnt = argv[optind];
8651
8652         if (use_default) {
8653                 dqb->dqb_bhardlimit = 0;
8654                 dqb->dqb_bsoftlimit = 0;
8655                 dqb->dqb_ihardlimit = 0;
8656                 dqb->dqb_isoftlimit = 0;
8657                 dqb->dqb_itime = 0;
8658                 dqb->dqb_btime = 0;
8659                 dqb->dqb_valid |= QIF_LIMITS | QIF_TIMES;
8660                 /* do not set inode limits for Pool Quotas */
8661                 if (qctl->qc_cmd  == LUSTRE_Q_SETDEFAULT_POOL)
8662                         dqb->dqb_valid ^= QIF_ILIMITS | QIF_ITIME;
8663         } else if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
8664                    (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
8665                 /* sigh, we can't just set blimits/ilimits */
8666                 struct if_quotactl *tmp_qctl;
8667
8668                 tmp_qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1);
8669                 if (!tmp_qctl)
8670                         goto out;
8671
8672                 if (qctl->qc_cmd == LUSTRE_Q_SETQUOTAPOOL) {
8673                         tmp_qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
8674                         strncpy(tmp_qctl->qc_poolname, qctl->qc_poolname,
8675                                 LOV_MAXPOOLNAME);
8676                 } else {
8677                         tmp_qctl->qc_cmd  = LUSTRE_Q_GETQUOTA;
8678                 }
8679                 tmp_qctl->qc_type = qctl->qc_type;
8680                 tmp_qctl->qc_id = qctl->qc_id;
8681
8682                 rc = llapi_quotactl(mnt, tmp_qctl);
8683                 if (rc < 0) {
8684                         free(tmp_qctl);
8685                         goto out;
8686                 }
8687
8688                 if (!(limit_mask & BHLIMIT))
8689                         dqb->dqb_bhardlimit = tmp_qctl->qc_dqblk.dqb_bhardlimit;
8690                 if (!(limit_mask & BSLIMIT))
8691                         dqb->dqb_bsoftlimit = tmp_qctl->qc_dqblk.dqb_bsoftlimit;
8692                 if (!(limit_mask & IHLIMIT))
8693                         dqb->dqb_ihardlimit = tmp_qctl->qc_dqblk.dqb_ihardlimit;
8694                 if (!(limit_mask & ISLIMIT))
8695                         dqb->dqb_isoftlimit = tmp_qctl->qc_dqblk.dqb_isoftlimit;
8696
8697                 /* Keep grace times if we have got no softlimit arguments */
8698                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
8699                         dqb->dqb_valid |= QIF_BTIME;
8700                         dqb->dqb_btime = tmp_qctl->qc_dqblk.dqb_btime;
8701                 }
8702
8703                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
8704                         dqb->dqb_valid |= QIF_ITIME;
8705                         dqb->dqb_itime = tmp_qctl->qc_dqblk.dqb_itime;
8706                 }
8707                 free(tmp_qctl);
8708         }
8709
8710         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
8711         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
8712
8713         if (qctl->qc_cmd == LUSTRE_Q_RESETQID)
8714                 rc = lfs_reset_quota(mnt, qctl);
8715         else
8716                 rc = llapi_quotactl(mnt, qctl);
8717
8718         if (rc) {
8719                 if (*obd_type)
8720                         fprintf(stderr,
8721                                 "%s setquota: cannot quotactl '%s' '%s': %s\n",
8722                                 progname, obd_type,
8723                                 obd_uuid2str(&qctl->obd_uuid), strerror(-rc));
8724                 else
8725                         fprintf(stderr,
8726                                 "%s setquota: quotactl failed: %s\n",
8727                                 progname, strerror(-rc));
8728         }
8729 out:
8730         if (rc)
8731                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
8732
8733         free(qctl);
8734         return rc;
8735 }
8736
8737 /* Converts seconds value into format string
8738  * result is returned in buf
8739  * Notes:
8740  *        1. result is in descenting order: 1w2d3h4m5s
8741  *        2. zero fields are not filled (except for p. 3): 5d1s
8742  *        3. zero seconds value is presented as "0s"
8743  */
8744 static char *__sec2str(time_t seconds, char *buf)
8745 {
8746         const char spec[] = "smhdw";
8747         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
8748         unsigned long c;
8749         char *tail = buf;
8750         int i;
8751
8752         for (i = ARRAY_SIZE(mult) - 1 ; i >= 0; i--) {
8753                 c = seconds / mult[i];
8754
8755                 if (c > 0 || (i == 0 && buf == tail))
8756                         tail += scnprintf(tail, 40-(tail-buf), "%lu%c", c,
8757                                           spec[i]);
8758
8759                 seconds %= mult[i];
8760         }
8761
8762         return tail;
8763 }
8764
8765 static void sec2str(time_t seconds, char *buf, int rc)
8766 {
8767         char *tail = buf;
8768
8769         if (rc)
8770                 *tail++ = '[';
8771
8772         tail = __sec2str(seconds, tail);
8773
8774         if (rc && tail - buf < 39) {
8775                 *tail++ = ']';
8776                 *tail++ = 0;
8777         }
8778 }
8779
8780 static void diff2str(time_t seconds, char *buf, time_t now)
8781 {
8782         buf[0] = 0;
8783         if (!seconds)
8784                 return;
8785         if (seconds <= now) {
8786                 strcpy(buf, "expired");
8787                 return;
8788         }
8789         __sec2str(seconds - now, buf);
8790 }
8791
8792 static void print_quota_title(char *name, struct if_quotactl *qctl,
8793                               bool human_readable, bool show_default)
8794 {
8795         if (show_default) {
8796                 printf("Disk default %s quota:\n", qtype_name(qctl->qc_type));
8797                 printf("%15s %8s%8s%8s %8s%8s%8s\n",
8798                        "Filesystem", "bquota", "blimit", "bgrace",
8799                        "iquota", "ilimit", "igrace");
8800         } else {
8801                 printf("Disk quotas for %s %s (%cid %u):\n",
8802                        qtype_name(qctl->qc_type), name,
8803                        *qtype_name(qctl->qc_type), qctl->qc_id);
8804                 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
8805                        "Filesystem", human_readable ? "used" : "kbytes",
8806                        "quota", "limit", "grace",
8807                        "files", "quota", "limit", "grace");
8808         }
8809 }
8810
8811 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
8812 {
8813         if (!h) {
8814                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
8815         } else {
8816                 if (num >> 40)
8817                         snprintf(buf, buflen, "%5.4gP",
8818                                  (double)num / ((__u64)1 << 40));
8819                 else if (num >> 30)
8820                         snprintf(buf, buflen, "%5.4gT",
8821                                  (double)num / (1 << 30));
8822                 else if (num >> 20)
8823                         snprintf(buf, buflen, "%5.4gG",
8824                                  (double)num / (1 << 20));
8825                 else if (num >> 10)
8826                         snprintf(buf, buflen, "%5.4gM",
8827                                  (double)num / (1 << 10));
8828                 else
8829                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
8830         }
8831 }
8832
8833 #ifdef HAVE_NATIVE_CLIENT
8834 /* In the current Lustre implementation, the grace time is either the time
8835  * or the timestamp to be used after some quota ID exceeds the soft limt,
8836  * 48 bits should be enough, its high 16 bits can be used as quota flags.
8837  */
8838 #define LQUOTA_GRACE_BITS       48
8839 #define LQUOTA_GRACE_MASK       ((1ULL << LQUOTA_GRACE_BITS) - 1)
8840 #define LQUOTA_GRACE_MAX        LQUOTA_GRACE_MASK
8841 #define LQUOTA_GRACE(t)         (t & LQUOTA_GRACE_MASK)
8842 #define LQUOTA_FLAG(t)          (t >> LQUOTA_GRACE_BITS)
8843 #define LQUOTA_GRACE_FLAG(t, f) ((__u64)t | (__u64)f << LQUOTA_GRACE_BITS)
8844 #endif
8845
8846 #define STRBUF_LEN      24
8847 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
8848                         int rc, bool h, bool show_default, bool show_qid)
8849 {
8850         char *name;
8851         time_t now;
8852
8853         time(&now);
8854
8855         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA ||
8856             qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
8857             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT ||
8858             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL) {
8859                 int bover = 0, iover = 0;
8860                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
8861                 char numbuf[3][STRBUF_LEN + 2]; /* 2 for brackets or wildcard */
8862                 char timebuf[40];
8863                 char strbuf[STRBUF_LEN];
8864
8865                 dqb->dqb_btime &= LQUOTA_GRACE_MASK;
8866                 dqb->dqb_itime &= LQUOTA_GRACE_MASK;
8867
8868                 if (dqb->dqb_bhardlimit &&
8869                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
8870                         bover = 1;
8871                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
8872                         if (dqb->dqb_btime > now)
8873                                 bover = 2;
8874                         else
8875                                 bover = 3;
8876                 }
8877
8878                 if (dqb->dqb_ihardlimit &&
8879                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
8880                         iover = 1;
8881                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
8882                         if (dqb->dqb_itime > now)
8883                                 iover = 2;
8884                         else
8885                                 iover = 3;
8886                 }
8887
8888                 if (show_qid) {
8889                         if (qctl->qc_type == USRQUOTA) {
8890                                 if (uid2name(&name, qctl->qc_id))
8891                                         printf("%10u", qctl->qc_id);
8892                                 else
8893                                         printf("%10s", name);
8894                         } else if (qctl->qc_type == GRPQUOTA) {
8895                                 if (gid2name(&name, qctl->qc_id))
8896                                         printf("%10u", qctl->qc_id);
8897                                 else
8898                                         printf("%10s", name);
8899                         } else {
8900                                 printf("%10u", qctl->qc_id);
8901                         }
8902                 } else {
8903                         if (strlen(mnt) > 15)
8904                                 printf("%s\n%15s", mnt, "");
8905                         else
8906                                 printf("%15s", mnt);
8907                 }
8908
8909                 if (show_default)
8910                         snprintf(timebuf, sizeof(timebuf), "%llu",
8911                                  (unsigned long long)dqb->dqb_btime);
8912                 else if (bover)
8913                         diff2str(dqb->dqb_btime, timebuf, now);
8914
8915                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
8916                            strbuf, sizeof(strbuf), h);
8917                 if (rc == -EREMOTEIO)
8918                         sprintf(numbuf[0], "%s*", strbuf);
8919                 else
8920                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
8921                                 "%s" : "[%s]", strbuf);
8922
8923                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
8924                 if (type == QC_GENERAL)
8925                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
8926                                 "%s" : "[%s]", strbuf);
8927                 else
8928                         sprintf(numbuf[1], "%s", "-");
8929
8930                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
8931                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
8932                         "%s" : "[%s]", strbuf);
8933
8934                 if (show_default)
8935                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
8936                 else
8937                         printf(" %7s%c %6s %7s %7s",
8938                                numbuf[0], bover ? '*' : ' ', numbuf[1],
8939                                numbuf[2], bover > 1 ? timebuf : "-");
8940
8941                 if (show_default)
8942                         snprintf(timebuf, sizeof(timebuf), "%llu",
8943                                  (unsigned long long)dqb->dqb_itime);
8944                 else if (iover)
8945                         diff2str(dqb->dqb_itime, timebuf, now);
8946
8947                 snprintf(numbuf[0], sizeof(numbuf),
8948                          (dqb->dqb_valid & QIF_INODES) ? "%ju" : "[%ju]",
8949                          (uintmax_t)dqb->dqb_curinodes);
8950
8951                 if (type == QC_GENERAL)
8952                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
8953                                 "%ju" : "[%ju]",
8954                                 (uintmax_t)dqb->dqb_isoftlimit);
8955                 else
8956                         sprintf(numbuf[1], "%s", "-");
8957
8958                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
8959                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
8960
8961                 if (show_default)
8962                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
8963                 else if (type != QC_OSTIDX)
8964                         printf(" %7s%c %6s %7s %7s",
8965                                numbuf[0], iover ? '*' : ' ', numbuf[1],
8966                                numbuf[2], iover > 1 ? timebuf : "-");
8967                 else
8968                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
8969                 printf("\n");
8970         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
8971                    qctl->qc_cmd == LUSTRE_Q_GETINFOPOOL ||
8972                    qctl->qc_cmd == Q_GETOINFO) {
8973                 char bgtimebuf[40];
8974                 char igtimebuf[40];
8975
8976                 if (qctl->qc_dqinfo.dqi_bgrace == NOTIFY_GRACE_TIME)
8977                         strncpy(bgtimebuf, NOTIFY_GRACE, 40);
8978                 else
8979                         sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
8980                 if (qctl->qc_dqinfo.dqi_igrace == NOTIFY_GRACE_TIME)
8981                         strncpy(igtimebuf, NOTIFY_GRACE, 40);
8982                 else
8983                         sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
8984
8985                 printf("Block grace time: %s; Inode grace time: %s\n",
8986                        bgtimebuf, igtimebuf);
8987         }
8988 }
8989
8990 static int tgt_name2index(const char *tgtname, unsigned int *idx)
8991 {
8992         char *dash, *endp;
8993
8994         /* format is "lustre-OST0001" */
8995         dash = memchr(tgtname, '-', LUSTRE_MAXFSNAME + 1);
8996         if (!dash) {
8997                 fprintf(stderr, "wrong tgtname format '%s'\n", tgtname);
8998                 return -EINVAL;
8999         }
9000         dash += 4;
9001
9002         *idx = strtoul(dash, &endp, 16);
9003         if (*idx > 0xffff) {
9004                 fprintf(stderr, "wrong index %s\n", tgtname);
9005                 return -ERANGE;
9006         }
9007
9008         return 0;
9009 }
9010
9011 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
9012                            bool h, __u64 *total)
9013 {
9014         int rc = 0, rc1 = 0, count = 0, i = 0;
9015         char **list = NULL, *buffer = NULL;
9016         __u32 valid = qctl->qc_valid;
9017
9018         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL && is_mdt)
9019                 return 0;
9020
9021         /* Is it correct for the case OST0000, OST0002, OST0003 -
9022          * we will ask OST0001 that is absent and won't ask OST0003? */
9023         rc = llapi_get_obd_count(mnt, &count, is_mdt);
9024         if (rc) {
9025                 fprintf(stderr, "can not get %s count: %s\n",
9026                         is_mdt ? "mdt" : "ost", strerror(-rc));
9027                 return rc;
9028         }
9029
9030         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
9031                 char fname[PATH_MAX];
9032                 char fsname[LUSTRE_MAXFSNAME + 1];
9033                 int bufsize = sizeof(struct obd_uuid) * count;
9034
9035                 rc = llapi_search_fsname(mnt, fsname);
9036                 if (rc) {
9037                         fprintf(stderr, "cannot get fsname for mountpoint %s\n",
9038                                 mnt);
9039                         goto out;
9040                 }
9041                 buffer = malloc(bufsize + sizeof(*list) * count);
9042                 if (!buffer)
9043                         return -ENOMEM;
9044                 list = (char **)(buffer + bufsize);
9045                 snprintf(fname, PATH_MAX, "%s.%s", fsname, qctl->qc_poolname);
9046                 count = llapi_get_poolmembers(fname, list, count,
9047                                               buffer, bufsize);
9048                 if (count <= 0)
9049                         goto out;
9050         }
9051
9052         for (i = 0; i < count; i++) {
9053                 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
9054                         unsigned int index;
9055
9056                         if (tgt_name2index(list[i], &index))
9057                                 continue;
9058                         qctl->qc_idx = index;
9059                 } else {
9060                         qctl->qc_idx = i;
9061                 }
9062
9063                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
9064                 rc = llapi_quotactl(mnt, qctl);
9065                 if (rc) {
9066                         /* It is remote client case. */
9067                         if (rc == -EOPNOTSUPP) {
9068                                 rc = 0;
9069                                 goto out;
9070                         }
9071
9072                         /* no target for this index yet */
9073                         if (rc == -ENODEV) {
9074                                 rc = 0;
9075                                 continue;
9076                         }
9077
9078                         /* inactive target */
9079                         if (rc == -ENODATA) {
9080                                 char name[UUID_MAX+8];
9081
9082                                 snprintf(name, sizeof(name), "%s[inact]",
9083                                         obd_uuid2str(&qctl->obd_uuid));
9084                                 memset(&qctl->qc_dqinfo, 0,
9085                                        sizeof(qctl->qc_dqinfo));
9086                                 memset(&qctl->qc_dqblk, 0,
9087                                        sizeof(qctl->qc_dqblk));
9088                                 print_quota(name, qctl, qctl->qc_valid, 0, h,
9089                                             false, false);
9090                                 rc = 0;
9091                                 continue;
9092                         }
9093
9094                         if (!rc1)
9095                                 rc1 = rc;
9096                         fprintf(stderr, "quotactl %s%d failed.\n",
9097                                 is_mdt ? "mdt" : "ost", qctl->qc_idx);
9098                         continue;
9099                 }
9100
9101                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
9102                             qctl->qc_valid, 0, h, false, false);
9103                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
9104                                    qctl->qc_dqblk.dqb_bhardlimit;
9105         }
9106 out:
9107         if (buffer)
9108                 free(buffer);
9109         qctl->qc_valid = valid;
9110         return rc ? : rc1;
9111 }
9112
9113 static int print_one_quota(char *mnt, char *name, struct if_quotactl *qctl,
9114                            int verbose, int quiet, bool human_readable,
9115                            bool show_default, bool show_qid, int rc)
9116 {
9117         int rc1 = 0, rc2 = 0;
9118         char *obd_type = (char *)qctl->obd_type;
9119         char *obd_uuid = (char *)qctl->obd_uuid.uuid;
9120         __u64 total_ialloc = 0, total_balloc = 0;
9121         bool use_default_for_blk = false;
9122         bool use_default_for_file = false;
9123         int inacc;
9124
9125         if (!show_default && qctl->qc_id == 0) {
9126                 qctl->qc_dqblk.dqb_bhardlimit = 0;
9127                 qctl->qc_dqblk.dqb_bsoftlimit = 0;
9128                 qctl->qc_dqblk.dqb_ihardlimit = 0;
9129                 qctl->qc_dqblk.dqb_isoftlimit = 0;
9130                 qctl->qc_dqblk.dqb_btime = 0;
9131                 qctl->qc_dqblk.dqb_itime = 0;
9132                 qctl->qc_dqblk.dqb_valid |= QIF_LIMITS | QIF_TIMES;
9133         }
9134
9135         if (qctl->qc_dqblk.dqb_valid & QIF_BTIME &&
9136             LQUOTA_FLAG(qctl->qc_dqblk.dqb_btime) & LQUOTA_FLAG_DEFAULT) {
9137                 use_default_for_blk = true;
9138                 qctl->qc_dqblk.dqb_btime &= LQUOTA_GRACE_MASK;
9139         }
9140
9141         if (qctl->qc_dqblk.dqb_valid & QIF_ITIME &&
9142             LQUOTA_FLAG(qctl->qc_dqblk.dqb_itime) & LQUOTA_FLAG_DEFAULT) {
9143                 use_default_for_file = true;
9144                 qctl->qc_dqblk.dqb_itime &= LQUOTA_GRACE_MASK;
9145         }
9146
9147         if (!show_qid && (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
9148              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
9149              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL ||
9150              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) && !quiet)
9151                 print_quota_title(name, qctl, human_readable, show_default);
9152
9153         if (rc && *obd_type)
9154                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
9155
9156         if (qctl->qc_valid != QC_GENERAL)
9157                 mnt = "";
9158
9159         inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
9160                  qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
9161                 ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
9162                  (QIF_LIMITS|QIF_USAGE));
9163
9164         print_quota(mnt, qctl, QC_GENERAL, rc, human_readable, show_default,
9165                     show_qid);
9166
9167         if (!show_qid && !show_default && verbose &&
9168             qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO &&
9169             qctl->qc_cmd != LUSTRE_Q_GETINFOPOOL) {
9170                 char strbuf[STRBUF_LEN];
9171
9172                 rc1 = print_obd_quota(mnt, qctl, 1, human_readable,
9173                                       &total_ialloc);
9174                 rc2 = print_obd_quota(mnt, qctl, 0, human_readable,
9175                                       &total_balloc);
9176                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
9177                            human_readable);
9178                 printf("Total allocated inode limit: %ju, total allocated block limit: %s\n",
9179                        (uintmax_t)total_ialloc, strbuf);
9180         }
9181
9182         if (use_default_for_blk)
9183                 printf("%cid %u is using default block quota setting\n",
9184                        *qtype_name(qctl->qc_type), qctl->qc_id);
9185
9186         if (use_default_for_file)
9187                 printf("%cid %u is using default file quota setting\n",
9188                        *qtype_name(qctl->qc_type), qctl->qc_id);
9189
9190         if (!show_qid && (rc || rc1 || rc2 || inacc))
9191                 printf("%d Some errors happened when getting quota info. Some devices may be not working or deactivated. The data in \"[]\" is inaccurate.\n", inacc);
9192
9193         if (rc)
9194                 return rc;
9195         if (rc1)
9196                 return rc1;
9197         if (rc2)
9198                 return rc2;
9199         if (inacc)
9200                 return -EIO;
9201
9202         return 0;
9203 }
9204
9205 static int iter_all_quota(char *mnt, struct if_quotactl *qctl, int quiet,
9206                           bool human_readable)
9207 {
9208         struct if_quotactl qctl_tmp, *qctl_iter;
9209         void *buffer = NULL;
9210         __u64 mark;
9211         __u64 cur, buflen = 0;
9212         int rc = 0;
9213
9214         memcpy(&qctl_tmp, qctl, sizeof(struct if_quotactl));
9215         qctl_tmp.qc_cmd = LUSTRE_Q_ITERQUOTA;
9216         rc = llapi_quotactl(mnt, &qctl_tmp);
9217         if (rc)
9218                 goto out;
9219
9220         buflen = qctl_tmp.qc_allquota_count * sizeof(struct if_quotactl);
9221         buffer = malloc(buflen);
9222         if (buffer == NULL) {
9223                 rc = -ENOMEM;
9224                 goto out;
9225         }
9226
9227         mark = qctl_tmp.qc_allquota_mark;
9228         memcpy(&qctl_tmp, qctl, sizeof(struct if_quotactl));
9229         qctl_tmp.qc_cmd = LUSTRE_Q_GETALLQUOTA;
9230         qctl_tmp.qc_allquota_buffer = (__u64)buffer;
9231         qctl_tmp.qc_allquota_buflen = buflen;
9232         qctl_tmp.qc_allquota_mark = mark;
9233         rc = llapi_quotactl(mnt, &qctl_tmp);
9234         if (rc)
9235                 goto out;
9236
9237         printf("Filesystem %s, Disk %s quotas\n", mnt,
9238                qtype_name(qctl->qc_type));
9239         printf("%10s%8s %7s%8s%8s%8s %7s%8s%8s\n", "quota_id",
9240                human_readable ? "used" : "kbytes", "quota", "limit", "grace",
9241                "files", "quota", "limit", "grace");
9242
9243         cur = 0;
9244         while (cur < buflen) {
9245                 if ((buflen - cur) < sizeof(struct if_quotactl)) {
9246                         rc = -EFAULT;
9247                         break;
9248                 }
9249
9250                 qctl_iter = buffer + cur;
9251                 qctl_iter->qc_cmd = LUSTRE_Q_GETQUOTA;
9252                 cur += sizeof(struct if_quotactl);
9253
9254                 /* Is no file created for this quota ID yet? */
9255                 if ((qctl_iter->qc_dqblk.dqb_valid & QIF_USAGE) != QIF_USAGE)
9256                         qctl_iter->qc_dqblk.dqb_valid |= QIF_USAGE;
9257
9258                 print_one_quota(mnt, NULL, qctl_iter, 0, quiet,
9259                                 human_readable, false, true, 0);
9260         }
9261
9262 out:
9263         if (buffer != NULL)
9264                 free(buffer);
9265
9266         if (rc)
9267                 fprintf(stderr, "get all quota failed %d\n", rc);
9268
9269         return rc;
9270 }
9271
9272 static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
9273                            int verbose, int quiet, bool human_readable,
9274                            bool show_default)
9275 {
9276         int rc;
9277
9278         rc = llapi_quotactl(mnt, qctl);
9279         if (rc < 0) {
9280                 switch (rc) {
9281                 case -ESRCH:
9282                         fprintf(stderr, "%s quotas are not enabled.\n",
9283                                 qtype_name(qctl->qc_type));
9284                         break;
9285                 case -EPERM:
9286                         fprintf(stderr, "Permission denied.\n");
9287                 case -ENODEV:
9288                 case -ENOENT:
9289                         /* We already got error message. */
9290                         break;
9291                 default:
9292                         fprintf(stderr, "Unexpected quotactl error: %s\n",
9293                                 strerror(-rc));
9294                 }
9295
9296                 return rc;
9297         }
9298
9299         return print_one_quota(mnt, name, qctl, verbose, quiet, human_readable,
9300                                show_default, false, rc);
9301 }
9302
9303 static int lfs_project(int argc, char **argv)
9304 {
9305         int ret = 0, err = 0, c, i;
9306         struct project_handle_control phc = { 0 };
9307         enum lfs_project_ops_t op;
9308
9309         phc.newline = true;
9310         phc.assign_projid = false;
9311         /* default action */
9312         op = LFS_PROJECT_LIST;
9313
9314         while ((c = getopt(argc, argv, "p:cCsdkr0")) != -1) {
9315                 switch (c) {
9316                 case 'c':
9317                         if (op != LFS_PROJECT_LIST) {
9318                                 fprintf(stderr,
9319                                         "%s: cannot specify '-c' '-C' '-s' together\n",
9320                                         progname);
9321                                 return CMD_HELP;
9322                         }
9323
9324                         op = LFS_PROJECT_CHECK;
9325                         break;
9326                 case 'C':
9327                         if (op != LFS_PROJECT_LIST) {
9328                                 fprintf(stderr,
9329                                         "%s: cannot specify '-c' '-C' '-s' together\n",
9330                                         progname);
9331                                 return CMD_HELP;
9332                         }
9333
9334                         op = LFS_PROJECT_CLEAR;
9335                         break;
9336                 case 's':
9337                         if (op != LFS_PROJECT_LIST) {
9338                                 fprintf(stderr,
9339                                         "%s: cannot specify '-c' '-C' '-s' together\n",
9340                                         progname);
9341                                 return CMD_HELP;
9342                         }
9343
9344                         phc.set_inherit = true;
9345                         op = LFS_PROJECT_SET;
9346                         break;
9347                 case 'd':
9348                         phc.dironly = true;
9349                         break;
9350                 case 'k':
9351                         phc.keep_projid = true;
9352                         break;
9353                 case 'r':
9354                         phc.recursive = true;
9355                         break;
9356                 case 'p':
9357                         if (str2quotaid(&phc.projid, optarg)) {
9358                                 fprintf(stderr,
9359                                         "Invalid project ID: %s\n",
9360                                         optarg);
9361                                 return CMD_HELP;
9362                         }
9363
9364                         phc.assign_projid = true;
9365
9366                         break;
9367                 case '0':
9368                         phc.newline = false;
9369                         break;
9370                 default:
9371                         fprintf(stderr, "%s: invalid option '%c'\n",
9372                                 progname, optopt);
9373                         return CMD_HELP;
9374                 }
9375         }
9376
9377         if (phc.assign_projid && op == LFS_PROJECT_LIST) {
9378                 op = LFS_PROJECT_SET;
9379                 phc.set_projid = true;
9380         } else if (phc.assign_projid && op == LFS_PROJECT_SET) {
9381                 phc.set_projid = true;
9382         }
9383
9384         switch (op) {
9385         case LFS_PROJECT_CHECK:
9386                 if (phc.keep_projid) {
9387                         fprintf(stderr,
9388                                 "%s: '-k' is useless together with '-c'\n",
9389                                 progname);
9390                         return CMD_HELP;
9391                 }
9392                 break;
9393         case LFS_PROJECT_CLEAR:
9394                 if (!phc.newline) {
9395                         fprintf(stderr,
9396                                 "%s: '-0' is useless together with '-C'\n",
9397                                 progname);
9398                         return CMD_HELP;
9399                 }
9400                 if (phc.assign_projid) {
9401                         fprintf(stderr,
9402                                 "%s: '-p' is useless together with '-C'\n",
9403                                 progname);
9404                         return CMD_HELP;
9405                 }
9406                 break;
9407         case LFS_PROJECT_SET:
9408                 if (!phc.newline) {
9409                         fprintf(stderr,
9410                                 "%s: '-0' is useless together with '-s'\n",
9411                                 progname);
9412                         return CMD_HELP;
9413                 }
9414                 if (phc.keep_projid) {
9415                         fprintf(stderr,
9416                                 "%s: '-k' is useless together with '-s'\n",
9417                                 progname);
9418                         return CMD_HELP;
9419                 }
9420                 break;
9421         default:
9422                 if (!phc.newline) {
9423                         fprintf(stderr,
9424                                 "%s: '-0' is useless for list operations\n",
9425                                 progname);
9426                         return CMD_HELP;
9427                 }
9428                 break;
9429         }
9430
9431         argv += optind;
9432         argc -= optind;
9433         if (argc == 0) {
9434                 fprintf(stderr, "%s: missing file or directory target(s)\n",
9435                         progname);
9436                 return CMD_HELP;
9437         }
9438
9439         for (i = 0; i < argc; i++) {
9440                 switch (op) {
9441                 case LFS_PROJECT_CHECK:
9442                         err = lfs_project_check(argv[i], &phc);
9443                         break;
9444                 case LFS_PROJECT_LIST:
9445                         err = lfs_project_list(argv[i], &phc);
9446                         break;
9447                 case LFS_PROJECT_CLEAR:
9448                         err = lfs_project_clear(argv[i], &phc);
9449                         break;
9450                 case LFS_PROJECT_SET:
9451                         err = lfs_project_set(argv[i], &phc);
9452                         break;
9453                 default:
9454                         break;
9455                 }
9456                 if (err && !ret)
9457                         ret = err;
9458         }
9459
9460         return ret;
9461 }
9462
9463 static int lfs_quota(int argc, char **argv)
9464 {
9465         int c;
9466         char *mnt, *name = NULL;
9467         struct if_quotactl *qctl;
9468         char *obd_uuid;
9469         int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
9470         __u32 valid = QC_GENERAL, idx = 0;
9471         __u32 start_qid = 0, end_qid = 0;
9472         bool human_readable = false;
9473         bool show_default = false;
9474         int qtype;
9475         bool show_pools = false;
9476         struct option long_opts[] = {
9477         { .val = LFS_POOL_OPT, .name = "pool", .has_arg = optional_argument },
9478         { .name = NULL } };
9479         char **poollist = NULL;
9480         char *buf = NULL;
9481         int poolcount, i;
9482
9483         qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1);
9484         if (!qctl)
9485                 return -ENOMEM;
9486
9487         qctl->qc_cmd = LUSTRE_Q_GETQUOTA;
9488         qctl->qc_type = ALLQUOTA;
9489         obd_uuid = (char *)qctl->obd_uuid.uuid;
9490
9491         while ((c = getopt_long(argc, argv, "ae:gGi:I:o:pPqs:tuUvh",
9492                 long_opts, NULL)) != -1) {
9493                 switch (c) {
9494                 case 'U':
9495                         show_default = true;
9496                 case 'u':
9497                         qtype = USRQUOTA;
9498                         goto quota_type;
9499                 case 'G':
9500                         show_default = true;
9501                 case 'g':
9502                         qtype = GRPQUOTA;
9503                         goto quota_type;
9504                 case 'P':
9505                         show_default = true;
9506                 case 'p':
9507                         qtype = PRJQUOTA;
9508 quota_type:
9509                         if (qctl->qc_type != ALLQUOTA) {
9510                                 fprintf(stderr,
9511                                         "%s quota: only one of -u, -g, or -p may be specified\n",
9512                                         progname);
9513                                 rc = CMD_HELP;
9514                                 goto out;
9515                         }
9516                         qctl->qc_type = qtype;
9517                         break;
9518                 case 'a':
9519                         qctl->qc_cmd = LUSTRE_Q_ITERQUOTA;
9520                         break;
9521                 case 't':
9522                         qctl->qc_cmd = LUSTRE_Q_GETINFO;
9523                         break;
9524                 case 'o':
9525                         valid = qctl->qc_valid = QC_UUID;
9526                         snprintf(obd_uuid, sizeof(*obd_uuid), "%s", optarg);
9527                         break;
9528                 case 'i':
9529                         valid = qctl->qc_valid = QC_MDTIDX;
9530                         idx = qctl->qc_idx = atoi(optarg);
9531                         if (idx == 0 && *optarg != '0') {
9532                                 fprintf(stderr,
9533                                         "%s quota: invalid MDT index '%s'\n",
9534                                         progname, optarg);
9535                                 rc = CMD_HELP;
9536                                 goto out;
9537                         }
9538                         break;
9539                 case 'I':
9540                         valid = qctl->qc_valid = QC_OSTIDX;
9541                         idx = qctl->qc_idx = atoi(optarg);
9542                         if (idx == 0 && *optarg != '0') {
9543                                 fprintf(stderr,
9544                                         "%s quota: invalid OST index '%s'\n",
9545                                         progname, optarg);
9546                                 rc = CMD_HELP;
9547                                 goto out;
9548                         }
9549                         break;
9550                 case 's':
9551                         start_qid = strtoul(optarg, NULL, 0);
9552                         break;
9553                 case 'e':
9554                         end_qid = strtoul(optarg, NULL, 0);
9555                         break;
9556                 case 'v':
9557                         verbose = 1;
9558                         break;
9559                 case 'q':
9560                         quiet = 1;
9561                         break;
9562                 case 'h':
9563                         human_readable = true;
9564                         break;
9565                 case LFS_POOL_OPT:
9566                         if ((!optarg) && (argv[optind] != NULL) &&
9567                                 (argv[optind][0] != '-') &&
9568                                 (argv[optind][0] != '/')) {
9569                                 optarg = argv[optind++];
9570                                 if (lfs_verify_poolarg(optarg)) {
9571                                         rc = -EINVAL;
9572                                         goto out;
9573                                 }
9574                                 strncpy(qctl->qc_poolname, optarg,
9575                                         LOV_MAXPOOLNAME);
9576                                 if (qctl->qc_cmd == LUSTRE_Q_GETINFO)
9577                                         qctl->qc_cmd = LUSTRE_Q_GETINFOPOOL;
9578                                 else
9579                                         qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
9580                                 break;
9581                         }
9582
9583                         /* optarg is NULL */
9584                         show_pools = true;
9585                         qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
9586                         break;
9587                 default:
9588                         fprintf(stderr, "%s quota: unrecognized option '%s'\n",
9589                                 progname, argv[optind - 1]);
9590                         rc = CMD_HELP;
9591                         goto out;
9592                 }
9593         }
9594
9595         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
9596         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
9597              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
9598              qctl->qc_type == ALLQUOTA &&
9599              optind == argc - 1 && !show_default) {
9600                 qctl->qc_idx = idx;
9601
9602                 for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) {
9603                         qctl->qc_type = qtype;
9604                         qctl->qc_valid = valid;
9605                         if (qtype == USRQUOTA) {
9606                                 qctl->qc_id = geteuid();
9607                                 rc = uid2name(&name, qctl->qc_id);
9608                         } else {
9609                                 qctl->qc_id = getegid();
9610                                 rc = gid2name(&name, qctl->qc_id);
9611                                 memset(&qctl->qc_dqblk, 0,
9612                                        sizeof(qctl->qc_dqblk));
9613                         }
9614                         if (rc)
9615                                 name = "<unknown>";
9616                         mnt = argv[optind];
9617                         rc1 = get_print_quota(mnt, name, qctl, verbose, quiet,
9618                                               human_readable, show_default);
9619                         if (rc1 && !rc)
9620                                 rc = rc1;
9621                 }
9622                 goto out;
9623         /* lfs quota -u username /path/to/lustre/mount */
9624         } else if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
9625                    qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
9626                 /* options should be followed by u/g-name and mntpoint */
9627                 if ((!show_default && optind + 2 != argc) ||
9628                     (show_default && optind + 1 != argc) ||
9629                     qctl->qc_type == ALLQUOTA) {
9630                         fprintf(stderr,
9631                                 "%s quota: name and mount point must be specified\n",
9632                                 progname);
9633                         rc = CMD_HELP;
9634                         goto out;
9635                 }
9636
9637                 if (!show_default) {
9638                         name = argv[optind++];
9639                         switch (qctl->qc_type) {
9640                         case USRQUOTA:
9641                                 rc = name2uid(&qctl->qc_id, name);
9642                                 break;
9643                         case GRPQUOTA:
9644                                 rc = name2gid(&qctl->qc_id, name);
9645                                 break;
9646                         case PRJQUOTA:
9647                                 rc = name2projid(&qctl->qc_id, name);
9648                                 break;
9649                         default:
9650                                 rc = -ENOTSUP;
9651                                 break;
9652                         }
9653                 } else {
9654                         qctl->qc_valid = QC_GENERAL;
9655                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ?
9656                                         LUSTRE_Q_GETDEFAULT_POOL :
9657                                         LUSTRE_Q_GETDEFAULT;
9658                         qctl->qc_id = 0;
9659                 }
9660
9661                 if (rc) {
9662                         if (str2quotaid(&qctl->qc_id, name)) {
9663                                 fprintf(stderr, "%s quota: invalid id '%s'\n",
9664                                         progname, name);
9665                                 rc = CMD_HELP;
9666                                 goto out;
9667                         }
9668                 }
9669         } else if (qctl->qc_cmd == LUSTRE_Q_ITERQUOTA) {
9670                 if (optind + 1 != argc) {
9671                         fprintf(stderr,
9672                                 "%s quota: mount point must be specified\n",
9673                                 progname);
9674                         rc = CMD_HELP;
9675                         goto out;
9676                 }
9677
9678                 if (qctl->qc_type == ALLQUOTA) {
9679                         fprintf(stderr, "%s quota: no quota type to iterate\n",
9680                                 progname);
9681                         rc = CMD_HELP;
9682                         goto out;
9683                 }
9684
9685                 if (end_qid != 0 && start_qid > end_qid) {
9686                         fprintf(stderr,
9687                                 "%s quota: end qid is smaller than start qid\n",
9688                                 progname);
9689                         rc = CMD_HELP;
9690                         goto out;
9691                 }
9692
9693                 qctl->qc_allquota_qid_start = start_qid;
9694                 qctl->qc_allquota_qid_end = end_qid;
9695                 rc = iter_all_quota(argv[optind], qctl, quiet, human_readable);
9696                 goto out;
9697         } else if (optind + 1 != argc || qctl->qc_type == ALLQUOTA) {
9698                 fprintf(stderr, "%s quota: missing quota info argument(s)\n",
9699                         progname);
9700                 rc = CMD_HELP;
9701                 goto out;
9702         }
9703
9704         mnt = argv[optind];
9705         if (show_pools) {
9706                 char *p;
9707
9708                 i = 0;
9709                 rc = llapi_get_poolbuf(mnt, &buf, &poollist, &poolcount);
9710                 if (rc)
9711                         goto out;
9712
9713                 for (i = 0; i < poolcount; i++) {
9714                         p = memchr(poollist[i], '.', MAXNAMLEN);
9715                         if (!p) {
9716                                 fprintf(stderr, "bad string format %.*s\n",
9717                                         MAXNAMLEN, poollist[i]);
9718                                 rc = -EINVAL;
9719                                 goto out;
9720                         }
9721                         p++;
9722                         printf("Quotas for pool: %s\n", p);
9723                         strncpy(qctl->qc_poolname, p, LOV_MAXPOOLNAME);
9724                         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
9725                                              human_readable, show_default);
9726                         if (rc)
9727                                 break;
9728                 }
9729                 goto out;
9730         }
9731
9732         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
9733                              human_readable, show_default);
9734 out:
9735         free(buf);
9736         free(qctl);
9737         return rc;
9738 }
9739 #endif /* HAVE_SYS_QUOTA_H! */
9740
9741 static int flushctx_ioctl(char *mp)
9742 {
9743         int fd, rc;
9744
9745         fd = open(mp, O_RDONLY);
9746         if (fd == -1) {
9747                 fprintf(stderr, "flushctx: error open %s: %s\n",
9748                         mp, strerror(errno));
9749                 return -1;
9750         }
9751
9752         rc = ioctl(fd, LL_IOC_FLUSHCTX);
9753         if (rc == -1)
9754                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
9755                         mp, strerror(errno));
9756
9757         close(fd);
9758         return rc;
9759 }
9760
9761 static int lfs_flushctx(int argc, char **argv)
9762 {
9763         int kdestroy = 0, reap = 0, c;
9764         char **mnts = NULL, **mnt_ptr;
9765         int mnt_num = 1, index = 0, rc = 0, rc2;
9766         extern char **environ;
9767
9768         while ((c = getopt(argc, argv, "kr")) != -1) {
9769                 switch (c) {
9770                 case 'k':
9771                         kdestroy = 1;
9772                         break;
9773                 case 'r':
9774                         reap = 1;
9775                         break;
9776                 default:
9777                         fprintf(stderr,
9778                                 "error: %s: option '-%c' unrecognized\n",
9779                                 argv[0], c);
9780                         return CMD_HELP;
9781                 }
9782         }
9783
9784         if (optind >= argc) {
9785                 /* flush for all lustre mount points */
9786 again:
9787                 mnt_ptr = realloc(mnts, mnt_num * sizeof(char *));
9788                 if (!mnt_ptr) {
9789                         mnt_num--;
9790                         rc = -ENOMEM;
9791                         goto reap;
9792                 }
9793                 mnts = mnt_ptr;
9794                 mnts[mnt_num - 1] = (char *)calloc(PATH_MAX + 1, sizeof(char));
9795                 if (!mnts[mnt_num - 1]) {
9796                         rc = -ENOMEM;
9797                         goto reap;
9798                 }
9799 next:
9800                 if (!llapi_search_mounts(NULL, index++,
9801                                          mnts[mnt_num - 1], NULL)) {
9802
9803                         if (*mnts[mnt_num - 1] == '\0')
9804                                 goto next;
9805                         mnt_num++;
9806                         goto again;
9807                 } else {
9808                         *mnts[mnt_num - 1] = '\0';
9809                 }
9810
9811                 mnt_ptr = mnts;
9812                 index = 0;
9813         } else {
9814                 /* flush for mounts as specified on command line */
9815                 mnt_ptr = argv + optind;
9816                 mnt_num = argc - optind;
9817         }
9818
9819         for (index = 0; index < mnt_num; index++) {
9820                 /* Check if we have a mount point */
9821                 if (*mnt_ptr[index] == '\0')
9822                         continue;
9823
9824                 rc2 = flushctx_ioctl(mnt_ptr[index]);
9825                 if (rc2) {
9826                         rc2 = -errno;
9827                         fprintf(stderr,
9828                                 "error flushing contexts on mount point %s: %s\n",
9829                                 mnt_ptr[index], strerror(errno));
9830                         rc = rc ? rc : rc2;
9831                 }
9832         }
9833
9834 reap:
9835         if (reap) {
9836                 static char *args[] = { "keyctl", "reap", NULL };
9837
9838                 /* use callvpe to bypass the shell */
9839                 rc2 = callvpe("keyctl", args, environ);
9840                 if (rc2) {
9841                         rc2 = WEXITSTATUS(rc2);
9842                         fprintf(stderr, "error reaping keyring: %d\n", rc2);
9843                 }
9844         }
9845
9846         if (kdestroy) {
9847                 static char *args[] = { "kdestroy", NULL };
9848
9849                 /* use callvpe to bypass the shell */
9850                 rc2 = callvpe("kdestroy", args, environ);
9851                 if (rc2) {
9852                         rc2 = WEXITSTATUS(rc2);
9853                         fprintf(stderr, "error destroying tickets: %d\n", rc2);
9854                 }
9855         }
9856
9857         if (mnts) {
9858                 for (index = 0; index < mnt_num; index++)
9859                         free(mnts[index]);
9860                 free(mnts);
9861         }
9862         return rc;
9863 }
9864
9865 static int lfs_changelog(int argc, char **argv)
9866 {
9867         void *changelog_priv;
9868         struct changelog_rec *rec;
9869         long long startrec = 0, endrec = 0;
9870         char *mdd;
9871         struct option long_opts[] = {
9872                 { .val = 'f', .name = "follow", .has_arg = no_argument },
9873                 { .name = NULL } };
9874         char short_opts[] = "f";
9875         int rc, follow = 0;
9876
9877         while ((rc = getopt_long(argc, argv, short_opts,
9878                 long_opts, NULL)) != -1) {
9879                 switch (rc) {
9880                 case 'f':
9881                         follow++;
9882                         break;
9883                 default:
9884                         fprintf(stderr,
9885                                 "%s changelog: unrecognized option '%s'\n",
9886                                 progname, argv[optind - 1]);
9887                         return CMD_HELP;
9888                 }
9889         }
9890         if (optind >= argc) {
9891                 fprintf(stderr, "%s changelog: mdtname must be specified\n",
9892                         progname);
9893                 return CMD_HELP;
9894         }
9895
9896         mdd = argv[optind++];
9897         if (argc > optind) {
9898                 errno = 0;
9899                 startrec = strtoll(argv[optind++], NULL, 10);
9900                 if (errno != 0 || startrec < 0) {
9901                         fprintf(stderr,
9902                                 "%s changelog: bad startrec\n",
9903                                 progname);
9904                         return CMD_HELP;
9905                 }
9906         }
9907
9908         if (argc > optind) {
9909                 errno = 0;
9910                 endrec = strtoll(argv[optind++], NULL, 10);
9911                 if (errno != 0 || endrec < 0) {
9912                         fprintf(stderr,
9913                                 "%s changelog: bad endrec\n",
9914                                 progname);
9915                         return CMD_HELP;
9916                 }
9917         }
9918
9919         rc = llapi_changelog_start(&changelog_priv,
9920                                    CHANGELOG_FLAG_BLOCK |
9921                                    CHANGELOG_FLAG_JOBID |
9922                                    CHANGELOG_FLAG_EXTRA_FLAGS |
9923                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
9924                                    mdd, startrec);
9925         if (rc < 0) {
9926                 fprintf(stderr, "%s changelog: cannot start changelog: %s\n",
9927                         progname, strerror(errno = -rc));
9928                 return rc;
9929         }
9930
9931         rc = llapi_changelog_set_xflags(changelog_priv,
9932                                         CHANGELOG_EXTRA_FLAG_UIDGID |
9933                                         CHANGELOG_EXTRA_FLAG_NID |
9934                                         CHANGELOG_EXTRA_FLAG_OMODE |
9935                                         CHANGELOG_EXTRA_FLAG_XATTR);
9936         if (rc < 0) {
9937                 fprintf(stderr,
9938                         "%s changelog: cannot set xflags for changelog: %s\n",
9939                         progname, strerror(errno = -rc));
9940                 return rc;
9941         }
9942
9943         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
9944                 time_t secs;
9945                 struct tm ts;
9946
9947                 if (endrec && rec->cr_index > endrec) {
9948                         llapi_changelog_free(&rec);
9949                         break;
9950                 }
9951                 if (rec->cr_index < startrec) {
9952                         llapi_changelog_free(&rec);
9953                         continue;
9954                 }
9955
9956                 secs = rec->cr_time >> 30;
9957                 gmtime_r(&secs, &ts);
9958                 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
9959                        "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
9960                        changelog_type2str(rec->cr_type),
9961                        ts.tm_hour, ts.tm_min, ts.tm_sec,
9962                        (int)(rec->cr_time & ((1 << 30) - 1)),
9963                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
9964                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
9965
9966                 if (rec->cr_flags & CLF_JOBID) {
9967                         struct changelog_ext_jobid *jid =
9968                                 changelog_rec_jobid(rec);
9969
9970                         if (jid->cr_jobid[0] != '\0')
9971                                 printf(" j=%s", jid->cr_jobid);
9972                 }
9973
9974                 if (rec->cr_flags & CLF_EXTRA_FLAGS) {
9975                         struct changelog_ext_extra_flags *ef =
9976                                 changelog_rec_extra_flags(rec);
9977
9978                         printf(" ef=0x%llx",
9979                                (unsigned long long)ef->cr_extra_flags);
9980
9981                         if (ef->cr_extra_flags & CLFE_UIDGID) {
9982                                 struct changelog_ext_uidgid *uidgid =
9983                                         changelog_rec_uidgid(rec);
9984
9985                                 printf(" u=%llu:%llu",
9986                                        (unsigned long long)uidgid->cr_uid,
9987                                        (unsigned long long)uidgid->cr_gid);
9988                         }
9989                         if (ef->cr_extra_flags & CLFE_NID) {
9990                                 struct changelog_ext_nid *nid =
9991                                         changelog_rec_nid(rec);
9992
9993                                 printf(" nid=%s",
9994                                        libcfs_nid2str(nid->cr_nid));
9995                         }
9996
9997                         if (ef->cr_extra_flags & CLFE_OPEN) {
9998                                 struct changelog_ext_openmode *omd =
9999                                         changelog_rec_openmode(rec);
10000                                 char mode[] = "---";
10001
10002                                 /* exec mode must be exclusive */
10003                                 if (omd->cr_openflags & MDS_FMODE_EXEC) {
10004                                         mode[2] = 'x';
10005                                 } else {
10006                                         if (omd->cr_openflags & MDS_FMODE_READ)
10007                                                 mode[0] = 'r';
10008                                         if (omd->cr_openflags &
10009                                             (MDS_FMODE_WRITE |
10010                                              MDS_OPEN_TRUNC |
10011                                              MDS_OPEN_APPEND))
10012                                                 mode[1] = 'w';
10013                                 }
10014
10015                                 if (strcmp(mode, "---") != 0)
10016                                         printf(" m=%s", mode);
10017                         }
10018
10019                         if (ef->cr_extra_flags & CLFE_XATTR) {
10020                                 struct changelog_ext_xattr *xattr =
10021                                         changelog_rec_xattr(rec);
10022
10023                                 if (xattr->cr_xattr[0] != '\0')
10024                                         printf(" x=%s", xattr->cr_xattr);
10025                         }
10026                 }
10027
10028                 if (!fid_is_zero(&rec->cr_pfid))
10029                         printf(" p="DFID, PFID(&rec->cr_pfid));
10030                 if (rec->cr_namelen)
10031                         printf(" %.*s", rec->cr_namelen,
10032                                changelog_rec_name(rec));
10033
10034                 if (rec->cr_flags & CLF_RENAME) {
10035                         struct changelog_ext_rename *rnm =
10036                                 changelog_rec_rename(rec);
10037
10038                         if (!fid_is_zero(&rnm->cr_sfid))
10039                                 printf(" s="DFID" sp="DFID" %.*s",
10040                                        PFID(&rnm->cr_sfid),
10041                                        PFID(&rnm->cr_spfid),
10042                                        (int)changelog_rec_snamelen(rec),
10043                                        changelog_rec_sname(rec));
10044                 }
10045                 printf("\n");
10046
10047                 llapi_changelog_free(&rec);
10048         }
10049
10050         llapi_changelog_fini(&changelog_priv);
10051
10052         if (rc < 0)
10053                 fprintf(stderr, "%s changelog: cannot access changelog: %s\n",
10054                         progname, strerror(errno = -rc));
10055
10056         return (rc == 1 ? 0 : rc);
10057 }
10058
10059 static int lfs_changelog_clear(int argc, char **argv)
10060 {
10061         long long endrec;
10062         int rc;
10063
10064         if (argc != 4)
10065                 return CMD_HELP;
10066
10067         errno = 0;
10068         endrec = strtoll(argv[3], NULL, 10);
10069         if (errno != 0 || endrec < 0) {
10070                 fprintf(stderr,
10071                         "%s: bad endrec '%s'\n",
10072                         argv[0], argv[3]);
10073                 return CMD_HELP;
10074         }
10075
10076         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
10077
10078         if (rc == -EINVAL)
10079                 fprintf(stderr, "%s: record out of range: %llu\n",
10080                         argv[0], endrec);
10081         else if (rc == -ENOENT)
10082                 fprintf(stderr, "%s: no changelog user: %s\n",
10083                         argv[0], argv[2]);
10084         else if (rc)
10085                 fprintf(stderr, "%s error: %s\n", argv[0],
10086                         strerror(-rc));
10087
10088         if (rc)
10089                 errno = -rc;
10090
10091         return rc;
10092 }
10093
10094 static void rstripc(char *str, int c)
10095 {
10096         char *end = str + strlen(str);
10097
10098         for (; str < end && end[-1] == c; --end)
10099                 end[-1] = '\0';
10100 }
10101
10102 /* Helper function to lfs_fid2path. To print out only the file names and
10103  * not the full path. Do not call OBD_IOC_FID2PATH for every file. Instead
10104  * read the trusted.link xattr and loop over all the records to get all the
10105  * file names.
10106  */
10107 static int lfs_fid2path_prn_name(char *mnt_dir, char *path_buf,
10108                                  bool print_linkno, bool print_fid, char *ptr,
10109                                  const char *fid_str, int linktmp)
10110 {
10111         char buf[65536]; /* BUFFER_SIZE 65536 */
10112         char full_path[PATH_MAX * 2 + 2];
10113         struct link_ea_header *leh;
10114         struct link_ea_entry *lee;
10115         ssize_t size;
10116         int reclen, i, rc = 0;
10117
10118         /* Generate full_path */
10119         snprintf(full_path, sizeof(full_path) - 1, "%s/%s", mnt_dir, path_buf);
10120
10121         size = getxattr(full_path, "trusted.link", buf, sizeof(buf));
10122         if (size < 0) {
10123                 fprintf(stderr, "%s: failed to read %s xattr: %s\n", path_buf,
10124                         "trusted.link", strerror(errno));
10125                 rc = -errno;
10126                 goto fail;
10127         }
10128
10129         leh = (struct link_ea_header *)buf;
10130
10131         if (leh->leh_magic == __swab32(LINK_EA_MAGIC))
10132                 leh->leh_reccount = __swab32(leh->leh_reccount);
10133
10134         lee = (struct link_ea_entry *)(leh + 1);
10135
10136         for (i = 0; i < leh->leh_reccount; i++) {
10137                 reclen = (lee->lee_reclen[0] << 8) | lee->lee_reclen[1];
10138
10139                 /* handle -n -l case */
10140                 if (print_linkno) {
10141                         ptr = strrchr(path_buf, '/');
10142                         if (!ptr)
10143                                 ptr = path_buf;
10144                         else
10145                                 ptr = ptr + 1;
10146
10147                         if (strcmp(ptr, lee->lee_name) == 0) {
10148                                 if (print_fid)
10149                                         printf("%s ", fid_str);
10150
10151                                 printf("%d ", linktmp);
10152                                 printf("%s\n", lee->lee_name);
10153                                 break;
10154                         }
10155                 } else {
10156                         if (print_fid)
10157                                 printf("%s ", fid_str);
10158                         printf("%s\n", lee->lee_name);
10159                 }
10160
10161                 /* Get next record */
10162                 lee = (struct link_ea_entry *)((char *)lee + reclen);
10163         }
10164 fail:
10165         return rc;
10166 }
10167
10168 static int lfs_fid2path(int argc, char **argv)
10169 {
10170         struct option long_opts[] = {
10171                 { .val = '0',   .name = "print0",       .has_arg = no_argument },
10172                 { .val = 'c',   .name = "cur",  .has_arg = no_argument },
10173                 { .val = 'c',   .name = "current",      .has_arg = no_argument },
10174                 { .val = 'c',   .name = "print-link",   .has_arg = no_argument },
10175                 { .val = 'f',   .name = "print-fid",    .has_arg = no_argument },
10176                 { .val = 'l',   .name = "link", .has_arg = required_argument },
10177                 { .val = 'n',   .name = "name", .has_arg = no_argument },
10178                 { .name = NULL } };
10179         char short_opts[] = "0cfl:pr:n";
10180         bool print_only_fname = false;
10181         bool print_linkno = false;
10182         bool print_link = false;
10183         bool print_fid = false;
10184         bool print_mnt_dir;
10185         char mnt_dir[PATH_MAX] = "";
10186         int mnt_fd = -1;
10187         char *path_or_fsname;
10188         long long recno = -1;
10189         int linkno = -1;
10190         char *endptr = NULL;
10191         char link_separator = '\n';
10192         int rc = 0;
10193         int c;
10194         int i;
10195
10196         while ((c = getopt_long(argc, argv, short_opts,long_opts, NULL)) !=
10197                 -1) {
10198                 switch (c) {
10199                 case '0':
10200                         link_separator = '\0';
10201                         break;
10202                 case 'c':
10203                         print_link = true;
10204                         break;
10205                 case 'f':
10206                         print_fid = true;
10207                         break;
10208                 case 'l':
10209                         errno = 0;
10210                         linkno = strtol(optarg, &endptr, 10);
10211                         if (errno != 0 || *endptr != '\0' || linkno < 0) {
10212                                 fprintf(stderr,
10213                                         "%s fid2path: invalid linkno '%s'\n",
10214                                         progname, optarg);
10215                                 return CMD_HELP;
10216                         }
10217                         print_linkno = true;
10218                         break;
10219                 case 'n':
10220                         /* Bypass the full parent path if true
10221                          * only print the final filename */
10222                         print_only_fname = true;
10223                         break;
10224                 case 'r':
10225                         /* recno is something to do with changelogs
10226                          * that was never implemented. We just pass it
10227                          * through for the MDT to ignore.
10228                          */
10229                         errno = 0;
10230                         recno = strtoll(optarg, &endptr, 10);
10231                         if (errno != 0 || *endptr != '\0' || recno < 0) {
10232                                 fprintf(stderr,
10233                                         "%s fid2path: invalid recno '%s'\n",
10234                                         progname, optarg);
10235                                 return CMD_HELP;
10236                         }
10237                         break;
10238                 default:
10239                         fprintf(stderr,
10240                                 "%s fid2path: unrecognized option '%s'\n",
10241                                 progname, argv[optind - 1]);
10242                         return CMD_HELP;
10243                 }
10244         }
10245
10246         if (argc - optind < 2) {
10247                 fprintf(stderr,
10248                         "Usage: %s fid2path FSNAME|ROOT FID...\n",
10249                         progname);
10250                 return CMD_HELP;
10251         }
10252
10253         path_or_fsname = argv[optind];
10254
10255         if (*path_or_fsname == '/') {
10256                 print_mnt_dir = true;
10257                 rc = llapi_search_mounts(path_or_fsname, 0, mnt_dir, NULL);
10258         } else {
10259                 print_mnt_dir = false;
10260                 rc = llapi_search_rootpath(mnt_dir, path_or_fsname);
10261         }
10262
10263         if (rc < 0) {
10264                 fprintf(stderr,
10265                         "%s fid2path: cannot resolve mount point for '%s': %s\n",
10266                         progname, path_or_fsname, strerror(-rc));
10267                 goto out;
10268         }
10269
10270         mnt_fd = open(mnt_dir, O_RDONLY | O_DIRECTORY);
10271         if (mnt_fd < 0) {
10272                 fprintf(stderr,
10273                         "%s fid2path: cannot open mount point for '%s': %s\n",
10274                         progname, path_or_fsname, strerror(-rc));
10275                 goto out;
10276         }
10277
10278         /* Strip trailing slashes from mnt_dir. */
10279         rstripc(mnt_dir + 1, '/');
10280
10281         for (i = optind + 1; i < argc; i++) {
10282                 const char *fid_str = argv[i];
10283                 struct lu_fid fid;
10284                 char *ptr = NULL;
10285                 int rc2;
10286
10287                 rc2 = llapi_fid_parse(fid_str, &fid, NULL);
10288                 if (rc2 < 0) {
10289                         fprintf(stderr,
10290                                 "%s fid2path: invalid FID '%s'\n",
10291                                 progname, fid_str);
10292                         if (rc == 0)
10293                                 rc = rc2;
10294
10295                         continue;
10296                 }
10297
10298                 int linktmp = (linkno >= 0) ? linkno : 0;
10299
10300                 while (1) {
10301                         int oldtmp = linktmp;
10302                         long long rectmp = recno;
10303                         char path_buf[PATH_MAX];
10304
10305                         rc2 = llapi_fid2path_at(mnt_fd, &fid, path_buf,
10306                                                 sizeof(path_buf), &rectmp,
10307                                                 &linktmp);
10308                         if (rc2 < 0) {
10309                                 fprintf(stderr,
10310                                         "%s fid2path: cannot find %s %s: %s\n",
10311                                         progname, path_or_fsname, fid_str,
10312                                         strerror(-rc2));
10313                                 if (rc == 0)
10314                                         rc = rc2;
10315                                 break;
10316                         }
10317
10318                         if (print_only_fname && !print_link) {
10319                                 /* '-n' is passed as option here.
10320                                  * For all other cases of -c fall back
10321                                  * to default(else) path as to get the link
10322                                  * count associated with the file name call
10323                                  * to OBD_IOC_FID2PATH is required
10324                                  */
10325                                 rc = lfs_fid2path_prn_name(mnt_dir,
10326                                                            path_buf,
10327                                                            print_linkno,
10328                                                            print_fid, ptr,
10329                                                            fid_str, linktmp);
10330                                 /* llapi_fid2path_at() is already called once
10331                                  * in this case. No need to call it again.
10332                                  * Break out as we have all the filenames.
10333                                  */
10334                                 break;
10335                         }
10336
10337                         if (print_fid)
10338                                 printf("%s ", fid_str);
10339
10340                         if (print_link)
10341                                 printf("%d ", linktmp);
10342
10343                         /* You may think this looks wrong or weird (and it is!)
10344                          * but we are actually trying to preserve the old quirky
10345                          * behaviors (enforced by our old quirky tests!) that
10346                          * make lfs so much fun to work on:
10347                          *
10348                          *   lustre 0x200000007:0x1:0x0 => "/"
10349                          *   /mnt/lustre 0x200000007:0x1:0x0 => "/mnt/lustre//"
10350                          *
10351                          * Note that llapi_fid2path() returns "" for the root
10352                          * FID. */
10353                         if (!print_only_fname) {
10354                                 printf("%s%s%s%c",
10355                                        print_mnt_dir ? mnt_dir : "",
10356                                        (print_mnt_dir || *path_buf == '\0') ?
10357                                        "/" : "", path_buf, link_separator);
10358                         } else {
10359                                 ptr = strrchr(path_buf, '/');
10360                                 if (!ptr)
10361                                         printf("%s\n", path_buf);
10362                                 else
10363                                         printf("%s\n", ptr + 1);
10364                         }
10365
10366                         if (linkno >= 0)
10367                                 /* specified linkno */
10368                                 break;
10369
10370                         if (oldtmp == linktmp)
10371                                 /* no more links */
10372                                 break;
10373                 }
10374         }
10375 out:
10376         if (!(mnt_fd < 0))
10377                 close(mnt_fd);
10378
10379         return rc;
10380 }
10381
10382 static int lfs_path2fid(int argc, char **argv)
10383 {
10384         struct option long_opts[] = {
10385                 { .val = 'p', .name = "parents", .has_arg = no_argument },
10386                 { .name = NULL } };
10387         char            **path;
10388         const char        short_opts[] = "p";
10389         const char       *sep = "";
10390         struct lu_fid     fid;
10391         int               rc = 0;
10392         bool              show_parents = false;
10393
10394         while ((rc = getopt_long(argc, argv, short_opts,
10395                                  long_opts, NULL)) != -1) {
10396                 switch (rc) {
10397                 case 'p':
10398                         show_parents = true;
10399                         break;
10400                 default:
10401                         fprintf(stderr,
10402                                 "%s path2fid: unrecognized option '%s'\n",
10403                                 progname, argv[optind - 1]);
10404                         return CMD_HELP;
10405                 }
10406         }
10407
10408         if (optind > argc - 1) {
10409                 fprintf(stderr, "%s path2fid: FILE... must be specified\n",
10410                         progname);
10411                 return CMD_HELP;
10412         } else if (optind < argc - 1) {
10413                 sep = ": ";
10414         }
10415
10416         rc = 0;
10417         for (path = argv + optind; optind < argc; path++, optind++) {
10418                 int err = 0;
10419
10420                 if (!show_parents) {
10421                         err = llapi_path2fid(*path, &fid);
10422                         if (!err)
10423                                 printf("%s%s"DFID"\n",
10424                                        *sep != '\0' ? *path : "", sep,
10425                                        PFID(&fid));
10426                 } else {
10427                         char            name[NAME_MAX + 1];
10428                         unsigned int    linkno = 0;
10429
10430                         while ((err = llapi_path2parent(*path, linkno, &fid,
10431                                                 name, sizeof(name))) == 0) {
10432                                 if (*sep != '\0' && linkno == 0)
10433                                         printf("%s%s", *path, sep);
10434
10435                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
10436                                        PFID(&fid), name);
10437                                 linkno++;
10438                         }
10439
10440                         /* err == -ENODATA is end-of-loop */
10441                         if (linkno > 0 && err == -ENODATA) {
10442                                 printf("\n");
10443                                 err = 0;
10444                         }
10445                 }
10446
10447                 if (err) {
10448                         fprintf(stderr,
10449                                 "%s path2fid: cannot get %sfid for '%s': %s\n",
10450                                 progname, show_parents ? "parent " : "", *path,
10451                                 strerror(-err));
10452                         if (rc == 0) {
10453                                 rc = err;
10454                                 errno = -err;
10455                         }
10456                 }
10457         }
10458
10459         return rc;
10460 }
10461
10462 #define MAX_ERRNO       4095
10463 #define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO)
10464
10465 static int lfs_rmfid_and_show_errors(int rootfd, struct fid_array *fa)
10466 {
10467         int rc, rc2, k;
10468
10469         rc = llapi_rmfid_at(rootfd, fa);
10470         if (rc < 0) {
10471                 fprintf(stderr, "%s rmfid: cannot remove FIDs: %s\n",
10472                         progname, strerror(-rc));
10473                 return rc;
10474         }
10475
10476         for (k = 0; k < fa->fa_nr; k++) {
10477                 rc2 = (__s32)fa->fa_fids[k].f_ver;
10478                 if (!IS_ERR_VALUE(rc2))
10479                         continue;
10480
10481                 if (rc == 0)
10482                         rc = rc2;
10483
10484                 fa->fa_fids[k].f_ver = 0;
10485                 fprintf(stderr, "%s rmfid: cannot remove "DFID": %s\n",
10486                         progname, PFID(&fa->fa_fids[k]), strerror(-rc2));
10487         }
10488
10489         return rc;
10490 }
10491
10492 static int lfs_rmfid(int argc, char **argv)
10493 {
10494         int rc = 0, rc2, rc3 = 0, nr;
10495         struct fid_array *fa;
10496         const char *device;
10497         char *fidstr;
10498         int rootfd;
10499
10500         /* Interactive mode: Adjust optind */
10501         if (!optind)
10502                 optind++;
10503
10504         device = argv[optind++];
10505
10506         if (optind > argc - 1) {
10507                 fprintf(stderr, "%s rmfid: missing dirname\n", progname);
10508                 return CMD_HELP;
10509         }
10510
10511         nr = argc - optind;
10512
10513         rc = llapi_root_path_open(device, &rootfd);
10514         if (rc < 0) {
10515                 fprintf(stderr,
10516                         "%s rmfid: error opening device/fsname '%s': %s\n",
10517                         progname, device, strerror(-rc));
10518                 return -rc;
10519         }
10520
10521         fa = malloc(offsetof(struct fid_array, fa_fids[nr + 1]));
10522         if (!fa) {
10523                 rc = -errno ?: -ENOMEM;
10524                 fprintf(stderr, "%s rmfid: error allocating %zd bytes: %s\n",
10525                         progname, offsetof(struct fid_array, fa_fids[nr + 1]),
10526                         strerror(-rc));
10527                 goto out_close;
10528         }
10529
10530         fa->fa_nr = 0;
10531         rc = 0;
10532         while (optind < argc) {
10533                 char *origfidstr;
10534                 int found;
10535
10536                 origfidstr = fidstr = argv[optind++];
10537                 while (*fidstr == '[')
10538                         fidstr++;
10539                 found = sscanf(fidstr, SFID, RFID(&fa->fa_fids[fa->fa_nr]));
10540                 if (found != 3) {
10541                         fprintf(stderr, "lfs rmfid: '%s': Wrong FID format\n",
10542                                 origfidstr);
10543                         if (!rc3)
10544                                 rc3 = -EINVAL; /* Invalid argument */
10545                         continue;
10546                 }
10547                 fa->fa_nr++;
10548                 if (fa->fa_nr == OBD_MAX_FIDS_IN_ARRAY) {
10549                         /* start another batch */
10550                         rc2 = lfs_rmfid_and_show_errors(rootfd, fa);
10551                         if (rc2 && !rc)
10552                                 rc = rc2;
10553                         if (rc3)
10554                                 rc = rc3;
10555                         fa->fa_nr = 0;
10556                 }
10557         }
10558         if (fa->fa_nr) {
10559                 rc2 = lfs_rmfid_and_show_errors(rootfd, fa);
10560                 if (rc2 && !rc)
10561                         rc = rc2;
10562                 if (rc3)
10563                         rc = rc3;
10564         }
10565
10566         if (fa) {
10567                 free(fa);
10568                 fa = NULL;
10569         }
10570
10571 out_close:
10572         close(rootfd);
10573         return rc;
10574 }
10575
10576 static int lfs_data_version(int argc, char **argv)
10577 {
10578         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
10579         __u64 data_version;
10580         char *path;
10581         int fd;
10582         int rc;
10583         int c;
10584
10585         if (argc < 2) {
10586                 fprintf(stderr, "%s: FILE must be specified\n",
10587                         progname);
10588                 return CMD_HELP;
10589         }
10590
10591         while ((c = getopt(argc, argv, "hnrw")) != -1) {
10592                 switch (c) {
10593                 case 'n':
10594                         data_version_flags = 0;
10595                         break;
10596                 case 'r':
10597                         data_version_flags |= LL_DV_RD_FLUSH;
10598                         break;
10599                 case 'w':
10600                         data_version_flags |= LL_DV_WR_FLUSH;
10601                         break;
10602                 default:
10603                         fprintf(stderr,
10604                                 "%s data_version: unrecognized option '%s'\n",
10605                                 progname, argv[optind - 1]);
10606                         fallthrough;
10607                 case 'h':
10608                         return CMD_HELP;
10609                 }
10610         }
10611         if (optind == argc) {
10612                 fprintf(stderr, "%s data_version: FILE must be specified\n",
10613                         progname);
10614                 return CMD_HELP;
10615         }
10616
10617         path = argv[optind];
10618         fd = open(path, O_RDONLY);
10619         if (fd < 0) {
10620                 rc = -errno;
10621                 fprintf(stderr, "%s data_version: cannot open file '%s': %s\n",
10622                         progname, path, strerror(-rc));
10623                 return rc;
10624         }
10625
10626         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
10627         if (rc < 0)
10628                 fprintf(stderr,
10629                         "%s data_version: cannot get version for '%s': %s\n",
10630                         progname, path, strerror(-rc));
10631         else
10632                 printf("%ju" "\n", (uintmax_t)data_version);
10633
10634         close(fd);
10635         return rc;
10636 }
10637
10638 static int lfs_hsm_state(int argc, char **argv)
10639 {
10640         int rc = 0;
10641         int i = 1;
10642         char *path;
10643         struct hsm_user_state hus;
10644
10645         if (argc < 2)
10646                 return CMD_HELP;
10647
10648         do {
10649                 int rc2;
10650                 path = argv[i];
10651
10652                 rc2 = llapi_hsm_state_get(path, &hus);
10653                 if (rc2) {
10654                         fprintf(stderr,
10655                                 "%s %s: get HSM state for '%s' failed: %s\n",
10656                                 progname, argv[0], path, strerror(-rc2));
10657                         if (!rc)
10658                                 rc = rc2;
10659                         continue;
10660                 }
10661
10662                 /* Display path name and status flags */
10663                 printf("%s: (0x%08x)", path, hus.hus_states);
10664
10665                 if (hus.hus_states & HS_RELEASED)
10666                         printf(" released");
10667                 if (hus.hus_states & HS_EXISTS)
10668                         printf(" exists");
10669                 if (hus.hus_states & HS_DIRTY)
10670                         printf(" dirty");
10671                 if (hus.hus_states & HS_ARCHIVED)
10672                         printf(" archived");
10673                 /* Display user-settable flags */
10674                 if (hus.hus_states & HS_NORELEASE)
10675                         printf(" never_release");
10676                 if (hus.hus_states & HS_NOARCHIVE)
10677                         printf(" never_archive");
10678                 if (hus.hus_states & HS_LOST)
10679                         printf(" lost_from_hsm");
10680
10681                 if (hus.hus_archive_id != 0)
10682                         printf(", archive_id:%d", hus.hus_archive_id);
10683                 printf("\n");
10684
10685         } while (++i < argc);
10686
10687         return rc;
10688 }
10689
10690 #define LFS_HSM_SET   0
10691 #define LFS_HSM_CLEAR 1
10692
10693 /**
10694  * Generic function to set or clear HSM flags.
10695  * Used by hsm_set and hsm_clear.
10696  *
10697  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
10698  */
10699 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
10700 {
10701         struct option long_opts[] = {
10702         { .val = 'A',   .name = "archived",     .has_arg = no_argument },
10703         { .val = 'a',   .name = "noarchive",    .has_arg = no_argument },
10704         { .val = 'd',   .name = "dirty",        .has_arg = no_argument },
10705         { .val = 'e',   .name = "exists",       .has_arg = no_argument },
10706         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10707         { .val = 'i',   .name = "archive-id",   .has_arg = required_argument },
10708         { .val = 'l',   .name = "lost",         .has_arg = no_argument },
10709         { .val = 'r',   .name = "norelease",    .has_arg = no_argument },
10710         { .name = NULL } };
10711         __u64 mask = 0;
10712         int c, rc = 0;
10713         char *path;
10714         __u32 archive_id = 0;
10715         char *end = NULL;
10716
10717         if (argc < 3)
10718                 return CMD_HELP;
10719
10720         while ((c = getopt_long(argc, argv, "aAdehi:lr",
10721                                 long_opts, NULL)) != -1) {
10722                 switch (c) {
10723                 case 'l':
10724                         mask |= HS_LOST;
10725                         break;
10726                 case 'a':
10727                         mask |= HS_NOARCHIVE;
10728                         break;
10729                 case 'A':
10730                         mask |= HS_ARCHIVED;
10731                         break;
10732                 case 'r':
10733                         mask |= HS_NORELEASE;
10734                         break;
10735                 case 'd':
10736                         mask |= HS_DIRTY;
10737                         break;
10738                 case 'e':
10739                         mask |= HS_EXISTS;
10740                         break;
10741                 case 'i':
10742                         errno = 0;
10743                         archive_id = strtol(optarg, &end, 10);
10744                         if (errno != 0 || *end != '\0' || archive_id < 0) {
10745                                 fprintf(stderr,
10746                                         "%s: invalid archive_id: '%s'\n",
10747                                         progname, end);
10748                                 return CMD_HELP;
10749                         }
10750                         break;
10751                 default:
10752                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10753                                 progname, argv[optind - 1]);
10754                         fallthrough;
10755                 case 'h':
10756                         return CMD_HELP;
10757                 }
10758         }
10759
10760         /* User should have specified a flag */
10761         if (mask == 0)
10762                 return CMD_HELP;
10763
10764         while (optind < argc) {
10765                 int rc2;
10766                 path = argv[optind];
10767
10768                 /* If mode == 0, this means we apply the mask. */
10769                 if (mode == LFS_HSM_SET)
10770                         rc2 = llapi_hsm_state_set(path, mask, 0, archive_id);
10771                 else
10772                         rc2 = llapi_hsm_state_set(path, 0, mask, 0);
10773
10774                 if (rc2) {
10775                         fprintf(stderr,
10776                                 "%s %s: change hsm flags for '%s' failed: %s\n",
10777                                 progname, argv[0], path, strerror(-rc2));
10778                         if (!rc)
10779                                 rc = rc2;
10780                 }
10781                 optind++;
10782         }
10783
10784         return rc;
10785 }
10786
10787 static int lfs_hsm_action(int argc, char **argv)
10788 {
10789         struct hsm_current_action hca;
10790         struct hsm_extent he;
10791         enum hsm_user_action hua;
10792         enum hsm_progress_states hps;
10793         int rc = 0;
10794         int i = 1;
10795         char *path;
10796
10797         if (argc < 2)
10798                 return CMD_HELP;
10799
10800         do {
10801                 int rc2;
10802                 path = argv[i];
10803
10804                 rc2 = llapi_hsm_current_action(path, &hca);
10805                 if (rc2) {
10806                         fprintf(stderr,
10807                                 "%s %s: get hsm action for '%s' failed: %s\n",
10808                                 progname, argv[0], path, strerror(-rc2));
10809
10810                         if (!rc)
10811                                 rc = rc2;
10812                         continue;
10813                 }
10814                 he = hca.hca_location;
10815                 hua = hca.hca_action;
10816                 hps = hca.hca_state;
10817
10818                 printf("%s: %s", path, hsm_user_action2name(hua));
10819
10820                 /* Skip file without action */
10821                 if (hca.hca_action == HUA_NONE) {
10822                         printf("\n");
10823                         continue;
10824                 }
10825
10826                 printf(" %s ", hsm_progress_state2name(hps));
10827
10828                 if ((hps == HPS_RUNNING) &&
10829                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
10830                         printf("(%llu bytes moved)\n",
10831                                (unsigned long long)he.length);
10832                 else if ((he.offset + he.length) == LUSTRE_EOF)
10833                         printf("(from %llu to EOF)\n",
10834                                (unsigned long long)he.offset);
10835                 else
10836                         printf("(from %llu to %llu)\n",
10837                                (unsigned long long)he.offset,
10838                                (unsigned long long)(he.offset + he.length));
10839
10840         } while (++i < argc);
10841
10842         return rc;
10843 }
10844
10845 static int lfs_hsm_set(int argc, char **argv)
10846 {
10847         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
10848 }
10849
10850 static int lfs_hsm_clear(int argc, char **argv)
10851 {
10852         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
10853 }
10854
10855 /**
10856  * Check file state and return its fid, to be used by lfs_hsm_request().
10857  *
10858  * \param[in]     file      Path to file to check
10859  * \param[in,out] fid       Pointer to allocated lu_fid struct.
10860  * \param[in,out] last_dev  Pointer to last device id used.
10861  *
10862  * \return 0 on success.
10863  */
10864 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
10865                                 dev_t *last_dev)
10866 {
10867         struct stat     st;
10868         int             rc;
10869
10870         rc = lstat(file, &st);
10871         if (rc) {
10872                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
10873                 return -errno;
10874         }
10875         /*
10876          * Checking for regular file as archiving as posix copytool
10877          * rejects archiving files other than regular files
10878          */
10879         if (!S_ISREG(st.st_mode)) {
10880                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
10881                 return CMD_HELP;
10882         }
10883         /* A request should be ... */
10884         if (*last_dev != st.st_dev && *last_dev != 0) {
10885                 fprintf(stderr,
10886                         "All files should be on the same filesystem: %s\n",
10887                         file);
10888                 return -EINVAL;
10889         }
10890         *last_dev = st.st_dev;
10891
10892         rc = llapi_path2fid(file, fid);
10893         if (rc) {
10894                 fprintf(stderr, "Cannot read FID of %s: %s\n",
10895                         file, strerror(-rc));
10896                 return rc;
10897         }
10898         return 0;
10899 }
10900
10901 /* Fill an HSM HUR item with a given file name.
10902  *
10903  * If mntpath is set, then the filename is actually a FID, and no
10904  * lookup on the filesystem will be performed.
10905  *
10906  * \param[in]  hur         the user request to fill
10907  * \param[in]  idx         index of the item inside the HUR to fill
10908  * \param[in]  mntpath     mountpoint of Lustre
10909  * \param[in]  fname       filename (if mtnpath is NULL)
10910  *                         or FID (if mntpath is set)
10911  * \param[in]  last_dev    pointer to last device id used
10912  *
10913  * \retval 0 on success
10914  * \retval CMD_HELP or a negative errno on error
10915  */
10916 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
10917                          const char *mntpath, const char *fname,
10918                          dev_t *last_dev)
10919 {
10920         struct hsm_user_item *hui = &hur->hur_user_item[idx];
10921         int rc;
10922
10923         hui->hui_extent.length = -1;
10924
10925         if (mntpath) {
10926                 rc = llapi_fid_parse(fname, &hui->hui_fid, NULL);
10927                 if (rc)
10928                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
10929                                 fname);
10930         } else {
10931                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
10932         }
10933
10934         if (rc == 0)
10935                 hur->hur_request.hr_itemcount++;
10936
10937         return rc;
10938 }
10939
10940 static int lfs_hsm_request(int argc, char **argv, int action)
10941 {
10942         struct option long_opts[] = {
10943         { .val = 'a',   .name = "archive",      .has_arg = required_argument },
10944         { .val = 'D',   .name = "data",         .has_arg = required_argument },
10945         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10946         { .val = 'l',   .name = "filelist",     .has_arg = required_argument },
10947         { .val = 'm',   .name = "mntpath",      .has_arg = required_argument },
10948         { .name = NULL } };
10949         dev_t last_dev = 0;
10950         struct hsm_user_request *hur, *oldhur;
10951         int c, i;
10952         size_t len;
10953         int nbfile;
10954         char *line = NULL;
10955         char *filelist = NULL;
10956         char fullpath[PATH_MAX];
10957         char *opaque = NULL;
10958         int opaque_len = 0;
10959         int archive_id = 0;
10960         FILE *fp;
10961         int nbfile_alloc = 0;
10962         char *some_file = NULL;
10963         char *mntpath = NULL;
10964         int rc;
10965
10966         if (argc < 2) {
10967                 rc = CMD_HELP;
10968                 goto out_cmd_help;
10969         }
10970
10971         while ((c = getopt_long(argc, argv, "a:D:hl:m:",
10972                                 long_opts, NULL)) != -1) {
10973                 switch (c) {
10974                 case 'l':
10975                         filelist = optarg;
10976                         break;
10977                 case 'D':
10978                         opaque = optarg;
10979                         break;
10980                 case 'a':
10981                         if (action != HUA_ARCHIVE &&
10982                             action != HUA_REMOVE) {
10983                                 fprintf(stderr,
10984                                         "error: -a is supported only when archiving or removing\n");
10985                                 rc = CMD_HELP;
10986                                 goto out_cmd_help;
10987                         }
10988                         archive_id = atoi(optarg);
10989                         break;
10990                 case 'm':
10991                         if (!some_file) {
10992                                 mntpath = optarg;
10993                                 some_file = strdup(optarg);
10994                         }
10995                         break;
10996                 default:
10997                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10998                                 progname, argv[optind - 1]);
10999                         fallthrough;
11000                 case 'h':
11001                         rc = CMD_HELP;
11002                         goto out_cmd_help;
11003                 }
11004         }
11005
11006         /* All remaining args are files, so we have at least nbfile */
11007         nbfile = argc - optind;
11008
11009         if ((nbfile == 0) && (!filelist)) {
11010                 rc = errno;
11011                 goto out_errno;
11012         }
11013
11014         if (opaque)
11015                 opaque_len = strlen(opaque);
11016
11017         /*
11018          * Alloc the request structure with enough place to store all files
11019          * from command line.
11020          */
11021         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
11022         if (!hur) {
11023                 fprintf(stderr, "Cannot create the request: %s\n",
11024                         strerror(errno));
11025                 rc = errno;
11026                 goto out_errno;
11027         }
11028         nbfile_alloc = nbfile;
11029
11030         hur->hur_request.hr_action = action;
11031         hur->hur_request.hr_archive_id = archive_id;
11032         hur->hur_request.hr_flags = 0;
11033
11034         /* All remaining args are files, add them */
11035         if (nbfile != 0 && some_file == NULL)
11036                 some_file = strdup(argv[optind]);
11037
11038         for (i = 0; i < nbfile; i++) {
11039                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
11040                                    &last_dev);
11041                 if (rc)
11042                         goto out_hur;
11043         }
11044
11045         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
11046
11047         /* If a filelist was specified, read the filelist from it. */
11048         if (filelist) {
11049                 fp = fopen(filelist, "r");
11050                 if (!fp) {
11051                         fprintf(stderr, "Cannot read the file list %s: %s\n",
11052                                 filelist, strerror(errno));
11053                         rc = -errno;
11054                         goto out_hur;
11055                 }
11056
11057                 while ((rc = getline(&line, &len, fp)) != -1) {
11058                         /*
11059                          * If allocated buffer was too small, get something
11060                          * larger
11061                          */
11062                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
11063                                 ssize_t size;
11064
11065                                 nbfile_alloc = nbfile_alloc * 2 + 1;
11066                                 oldhur = hur;
11067                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
11068                                                                    opaque_len);
11069                                 if (!hur) {
11070                                         fprintf(stderr,
11071                                                 "hsm: cannot allocate the request: %s\n",
11072                                                 strerror(errno));
11073                                         hur = oldhur;
11074                                         rc = -errno;
11075                                         fclose(fp);
11076                                         goto out_hur;
11077                                 }
11078                                 size = hur_len(oldhur);
11079                                 if (size < 0) {
11080                                         fprintf(stderr,
11081                                                 "hsm: cannot allocate %u files + %u bytes data\n",
11082                                                 oldhur->hur_request.hr_itemcount,
11083                                                 oldhur->hur_request.hr_data_len);
11084                                         free(hur);
11085                                         hur = oldhur;
11086                                         rc = -E2BIG;
11087                                         fclose(fp);
11088                                         goto out_hur;
11089                                 }
11090                                 memcpy(hur, oldhur, size);
11091                                 free(oldhur);
11092                         }
11093
11094                         /* Chop CR */
11095                         if (line[strlen(line) - 1] == '\n')
11096                                 line[strlen(line) - 1] = '\0';
11097
11098                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
11099                                            mntpath, line, &last_dev);
11100                         if (rc) {
11101                                 fclose(fp);
11102                                 goto out_hur;
11103                         }
11104
11105                         if (!some_file) {
11106                                 some_file = line;
11107                                 line = NULL;
11108                         }
11109                 }
11110
11111                 rc = fclose(fp);
11112                 free(line);
11113         }
11114
11115         /* If a --data was used, add it to the request */
11116         hur->hur_request.hr_data_len = opaque_len;
11117         if (opaque)
11118                 memcpy(hur_data(hur), opaque, opaque_len);
11119
11120         /* Send the HSM request */
11121         if (realpath(some_file, fullpath) == NULL) {
11122                 fprintf(stderr, "Could not find path '%s': %s\n",
11123                         some_file, strerror(errno));
11124         }
11125         rc = llapi_hsm_request(fullpath, hur);
11126         if (rc)
11127                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
11128                         some_file, strerror(-rc));
11129
11130 out_hur:
11131         free(hur);
11132 out_errno:
11133         free(some_file);
11134 out_cmd_help:
11135         return rc;
11136 }
11137
11138 static int lfs_hsm_archive(int argc, char **argv)
11139 {
11140         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
11141 }
11142
11143 static int lfs_hsm_restore(int argc, char **argv)
11144 {
11145         return lfs_hsm_request(argc, argv, HUA_RESTORE);
11146 }
11147
11148 static int lfs_hsm_release(int argc, char **argv)
11149 {
11150         return lfs_hsm_request(argc, argv, HUA_RELEASE);
11151 }
11152
11153 static int lfs_hsm_remove(int argc, char **argv)
11154 {
11155         return lfs_hsm_request(argc, argv, HUA_REMOVE);
11156 }
11157
11158 static int lfs_hsm_cancel(int argc, char **argv)
11159 {
11160         return lfs_hsm_request(argc, argv, HUA_CANCEL);
11161 }
11162
11163 static int lfs_swap_layouts(int argc, char **argv)
11164 {
11165         int noxtime = 0;
11166
11167         if (argc == 4 && !strcmp(argv[1], "-n"))
11168                 noxtime = 1;
11169         else if (argc != 3)
11170                 return CMD_HELP;
11171
11172         return llapi_swap_layouts(argv[1+noxtime], argv[2+noxtime],
11173                                   0, 0, noxtime ? 0 :
11174                                   (SWAP_LAYOUTS_KEEP_MTIME |
11175                                   SWAP_LAYOUTS_KEEP_ATIME));
11176 }
11177
11178 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
11179
11180 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
11181
11182 static int lfs_get_mode(const char *string)
11183 {
11184         enum lock_mode_user mode;
11185
11186         for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
11187                 if (lock_mode_names[mode] == NULL)
11188                         continue;
11189                 if (strcasecmp(string, lock_mode_names[mode]) == 0)
11190                         return mode;
11191         }
11192
11193         return -EINVAL;
11194 }
11195
11196 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
11197 {
11198         enum lu_ladvise_type advice;
11199
11200         for (advice = 0;
11201              advice < ARRAY_SIZE(ladvise_names); advice++) {
11202                 if (ladvise_names[advice] == NULL)
11203                         continue;
11204                 if (strcmp(string, ladvise_names[advice]) == 0)
11205                         return advice;
11206         }
11207
11208         return LU_LADVISE_INVALID;
11209 }
11210
11211 static int lfs_ladvise(int argc, char **argv)
11212 {
11213         struct option long_opts[] = {
11214         { .val = 'a',   .name = "advice",       .has_arg = required_argument },
11215         { .val = 'b',   .name = "background",   .has_arg = no_argument },
11216         { .val = 'e',   .name = "end",          .has_arg = required_argument },
11217         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11218         { .val = 'l',   .name = "length",       .has_arg = required_argument },
11219         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
11220         { .val = 's',   .name = "start",        .has_arg = required_argument },
11221         { .val = 'u',   .name = "unset",        .has_arg = no_argument },
11222         { .name = NULL } };
11223         struct llapi_lu_ladvise advice;
11224         enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
11225         unsigned long long start = 0;
11226         unsigned long long end = LUSTRE_EOF;
11227         unsigned long long length = 0;
11228         unsigned long long size_units;
11229         unsigned long long flags = 0;
11230         int c, fd, rc = 0;
11231         const char *path;
11232         int mode = 0;
11233
11234         optind = 0;
11235         while ((c = getopt_long(argc, argv, "a:be:hl:m:s:u",
11236                                 long_opts, NULL)) != -1) {
11237                 switch (c) {
11238                 case 'a':
11239                         advice_type = lfs_get_ladvice(optarg);
11240                         if (advice_type == LU_LADVISE_INVALID) {
11241                                 fprintf(stderr,
11242                                         "%s: invalid advice type '%s'\n",
11243                                         progname, optarg);
11244                                 fprintf(stderr, "Valid types:");
11245
11246                                 for (advice_type = 0;
11247                                      advice_type < ARRAY_SIZE(ladvise_names);
11248                                      advice_type++) {
11249                                         if (ladvise_names[advice_type] == NULL)
11250                                                 continue;
11251                                         fprintf(stderr, " %s",
11252                                                 ladvise_names[advice_type]);
11253                                 }
11254                                 fprintf(stderr, "\n");
11255
11256                                 return CMD_HELP;
11257                         }
11258                         break;
11259                 case 'b':
11260                         flags |= LF_ASYNC;
11261                         break;
11262                 case 'u':
11263                         flags |= LF_UNSET;
11264                         break;
11265                 case 'e':
11266                         size_units = 1;
11267                         rc = llapi_parse_size(optarg, &end,
11268                                               &size_units, 0);
11269                         if (rc) {
11270                                 fprintf(stderr, "%s: bad end offset '%s'\n",
11271                                         argv[0], optarg);
11272                                 return CMD_HELP;
11273                         }
11274                         break;
11275                 case 's':
11276                         size_units = 1;
11277                         rc = llapi_parse_size(optarg, &start,
11278                                               &size_units, 0);
11279                         if (rc) {
11280                                 fprintf(stderr,
11281                                         "%s: bad start offset '%s'\n",
11282                                         argv[0], optarg);
11283                                 return CMD_HELP;
11284                         }
11285                         break;
11286                 case 'l':
11287                         size_units = 1;
11288                         rc = llapi_parse_size(optarg, &length,
11289                                               &size_units, 0);
11290                         if (rc) {
11291                                 fprintf(stderr, "%s: bad length '%s'\n",
11292                                         argv[0], optarg);
11293                                 return CMD_HELP;
11294                         }
11295                         break;
11296                 case 'm':
11297                         mode = lfs_get_mode(optarg);
11298                         if (mode < 0) {
11299                                 fprintf(stderr,
11300                                         "%s: bad mode '%s', valid modes are READ or WRITE\n",
11301                                         argv[0], optarg);
11302                                 return CMD_HELP;
11303                         }
11304                         break;
11305                 default:
11306                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11307                                 progname, argv[optind - 1]);
11308                         fallthrough;
11309                 case 'h':
11310                         return CMD_HELP;
11311                 }
11312         }
11313
11314         if (advice_type == LU_LADVISE_INVALID) {
11315                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
11316                 fprintf(stderr, "Valid types:");
11317                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
11318                      advice_type++) {
11319                         if (ladvise_names[advice_type] == NULL)
11320                                 continue;
11321                         fprintf(stderr, " %s", ladvise_names[advice_type]);
11322                 }
11323                 fprintf(stderr, "\n");
11324                 return CMD_HELP;
11325         }
11326
11327         if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
11328                 fprintf(stderr,
11329                         "%s: Lock no expand advice is a per file descriptor advice, so when called from lfs, it does nothing.\n",
11330                         argv[0]);
11331                 return CMD_HELP;
11332         }
11333
11334         if (argc <= optind) {
11335                 fprintf(stderr, "%s: please give one or more file names\n",
11336                         argv[0]);
11337                 return CMD_HELP;
11338         }
11339
11340         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
11341                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
11342                         argv[0]);
11343                 return CMD_HELP;
11344         }
11345
11346         if (end == LUSTRE_EOF && length != 0)
11347                 end = start + length;
11348
11349         if (end <= start) {
11350                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
11351                         argv[0], start, end);
11352                 return CMD_HELP;
11353         }
11354
11355         if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
11356                 fprintf(stderr, "%s: mode is only valid with lockahead\n",
11357                         argv[0]);
11358                 return CMD_HELP;
11359         }
11360
11361         if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
11362                 fprintf(stderr, "%s: mode is required with lockahead\n",
11363                         argv[0]);
11364                 return CMD_HELP;
11365         }
11366
11367         while (optind < argc) {
11368                 int rc2;
11369
11370                 path = argv[optind++];
11371
11372                 fd = open(path, O_RDONLY);
11373                 if (fd < 0) {
11374                         rc2 = -errno;
11375                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
11376                                 argv[0], path, strerror(-rc2));
11377                         if (!rc)
11378                                 rc = rc2;
11379                         continue;
11380                 }
11381
11382                 advice.lla_start = start;
11383                 advice.lla_end = end;
11384                 advice.lla_advice = advice_type;
11385                 advice.lla_value1 = 0;
11386                 advice.lla_value2 = 0;
11387                 advice.lla_value3 = 0;
11388                 advice.lla_value4 = 0;
11389                 if (advice_type == LU_LADVISE_LOCKAHEAD) {
11390                         advice.lla_lockahead_mode = mode;
11391                         advice.lla_peradvice_flags = flags;
11392                 }
11393
11394                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
11395                 close(fd);
11396                 if (rc2 < 0) {
11397                         fprintf(stderr,
11398                                 "%s: cannot give advice '%s' to file '%s': %s\n",
11399                                 argv[0], ladvise_names[advice_type],
11400                                 path, strerror(errno));
11401
11402                         if (!rc)
11403                                 rc = rc2;
11404                         continue;
11405                 }
11406         }
11407
11408         return rc;
11409 }
11410
11411 static const char *const heat_names[] = LU_HEAT_NAMES;
11412
11413 static int lfs_heat_get(int argc, char **argv)
11414 {
11415         struct lu_heat *heat;
11416         int rc = 0, rc2;
11417         char *path;
11418         int fd;
11419         int i;
11420
11421         if (argc <= 1)
11422                 return CMD_HELP;
11423
11424         heat = calloc(sizeof(*heat) + sizeof(__u64) * OBD_HEAT_COUNT, 1);
11425         if (!heat) {
11426                 fprintf(stderr, "%s: memory allocation failed\n", argv[0]);
11427                 return -ENOMEM;
11428         }
11429
11430         optind = 1;
11431         while (optind < argc) {
11432                 path = argv[optind++];
11433
11434                 fd = open(path, O_RDONLY);
11435                 if (fd < 0) {
11436                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
11437                                 argv[0], path, strerror(errno));
11438                         rc2 = -errno;
11439                         goto next;
11440                 }
11441
11442                 heat->lh_count = OBD_HEAT_COUNT;
11443                 rc2 = llapi_heat_get(fd, heat);
11444                 close(fd);
11445                 if (rc2 < 0) {
11446                         fprintf(stderr,
11447                                 "%s: cannot get heat of file '%s': %s\n",
11448                                 argv[0], path, strerror(errno));
11449                         goto next;
11450                 }
11451
11452                 printf("flags: %x\n", heat->lh_flags);
11453                 for (i = 0; i < heat->lh_count; i++)
11454                         printf("%s: %llu\n", heat_names[i],
11455                                (unsigned long long)heat->lh_heat[i]);
11456 next:
11457                 if (rc == 0 && rc2 < 0)
11458                         rc = rc2;
11459         }
11460
11461         free(heat);
11462         return rc;
11463 }
11464
11465 static int lfs_heat_set(int argc, char **argv)
11466 {
11467         struct option long_opts[] = {
11468         { .val = 'c',   .name = "clear",        .has_arg = no_argument },
11469         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11470         { .val = 'o',   .name = "off",          .has_arg = no_argument },
11471         { .val = 'O',   .name = "on",           .has_arg = no_argument },
11472         { .name = NULL } };
11473         enum lu_heat_flag flags = 0;
11474         int rc = 0, rc2;
11475         char *path;
11476         int fd;
11477         int c;
11478
11479         if (argc <= 1)
11480                 return CMD_HELP;
11481
11482         optind = 0;
11483         while ((c = getopt_long(argc, argv, "choO", long_opts, NULL)) != -1) {
11484                 switch (c) {
11485                 case 'c':
11486                         flags |= LU_HEAT_FLAG_CLEAR;
11487                         break;
11488                 case 'o':
11489                         flags |= LU_HEAT_FLAG_CLEAR;
11490                         flags |= LU_HEAT_FLAG_OFF;
11491                         break;
11492                 case 'O':
11493                         flags &= ~LU_HEAT_FLAG_OFF;
11494                         break;
11495                 default:
11496                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11497                                 progname, argv[optind - 1]);
11498                         fallthrough;
11499                 case 'h':
11500                         return CMD_HELP;
11501                 }
11502         }
11503
11504         if (argc <= optind) {
11505                 fprintf(stderr, "%s: please give one or more file names\n",
11506                         argv[0]);
11507                 return CMD_HELP;
11508         }
11509
11510         while (optind < argc) {
11511                 path = argv[optind++];
11512
11513                 fd = open(path, O_RDONLY);
11514                 if (fd < 0) {
11515                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
11516                                 argv[0], path, strerror(errno));
11517                         rc2 = -errno;
11518                         goto next;
11519                 }
11520
11521                 rc2 = llapi_heat_set(fd, flags);
11522                 close(fd);
11523                 if (rc2 < 0) {
11524                         fprintf(stderr,
11525                                 "%s: cannot setflags heat of file '%s': %s\n",
11526                                 argv[0], path, strerror(errno));
11527                         goto next;
11528                 }
11529 next:
11530                 if (rc == 0 && rc2 < 0)
11531                         rc = rc2;
11532         }
11533         return rc;
11534 }
11535
11536 /**
11537  * The input string contains a comma delimited list of component ids and
11538  * ranges, for example "1,2-4,7".
11539  */
11540 static int parse_mirror_ids(__u16 *ids, int size, char *arg)
11541 {
11542         bool end_of_loop = false;
11543         char *ptr = NULL;
11544         int nr = 0;
11545         int rc;
11546
11547         if (!arg)
11548                 return -EINVAL;
11549
11550         while (!end_of_loop) {
11551                 int start_index;
11552                 int end_index;
11553                 int i;
11554                 char *endptr = NULL;
11555
11556                 rc = -EINVAL;
11557                 ptr = strchrnul(arg, ',');
11558                 end_of_loop = *ptr == '\0';
11559                 *ptr = '\0';
11560
11561                 start_index = strtol(arg, &endptr, 0);
11562                 if (endptr == arg) /* no data at all */
11563                         break;
11564                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
11565                         break;
11566                 if (start_index < 0)
11567                         break;
11568
11569                 end_index = start_index;
11570                 if (*endptr == '-') {
11571                         end_index = strtol(endptr + 1, &endptr, 0);
11572                         if (*endptr != '\0')
11573                                 break;
11574                         if (end_index < start_index)
11575                                 break;
11576                 }
11577
11578                 for (i = start_index; i <= end_index && size > 0; i++) {
11579                         int j;
11580
11581                         /* remove duplicate */
11582                         for (j = 0; j < nr; j++) {
11583                                 if (ids[j] == i)
11584                                         break;
11585                         }
11586                         if (j == nr) { /* no duplicate */
11587                                 ids[nr++] = i;
11588                                 --size;
11589                         }
11590                 }
11591
11592                 if (size == 0 && i < end_index)
11593                         break;
11594
11595                 *ptr = ',';
11596                 arg = ++ptr;
11597                 rc = 0;
11598         }
11599         if (!end_of_loop && ptr)
11600                 *ptr = ',';
11601
11602         return rc < 0 ? rc : nr;
11603 }
11604
11605 /**
11606  * struct verify_mirror_id - Mirror id to be verified.
11607  * @mirror_id:   A specified mirror id.
11608  * @is_valid_id: @mirror_id is valid or not in the mirrored file.
11609  */
11610 struct verify_mirror_id {
11611         __u16 mirror_id;
11612         bool is_valid_id;
11613 };
11614
11615 /**
11616  * compare_mirror_ids() - Compare mirror ids.
11617  * @layout: Mirror component list.
11618  * @cbdata: Callback data in verify_mirror_id structure.
11619  *
11620  * This is a callback function called by llapi_layout_comp_iterate()
11621  * to compare the specified mirror id with the one in the current
11622  * component of @layout. If they are the same, then the specified
11623  * mirror id is valid.
11624  *
11625  * Return: a negative error code on failure or
11626  *         LLAPI_LAYOUT_ITER_CONT: Proceed iteration
11627  *         LLAPI_LAYOUT_ITER_STOP: Stop iteration
11628  */
11629 static inline
11630 int compare_mirror_ids(struct llapi_layout *layout, void *cbdata)
11631 {
11632         struct verify_mirror_id *mirror_id_cbdata =
11633                                  (struct verify_mirror_id *)cbdata;
11634         uint32_t mirror_id;
11635         int rc = 0;
11636
11637         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
11638         if (rc < 0) {
11639                 rc = -errno;
11640                 fprintf(stderr,
11641                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
11642                         progname, strerror(errno));
11643                 return rc;
11644         }
11645
11646         if (mirror_id_cbdata->mirror_id == mirror_id) {
11647                 mirror_id_cbdata->is_valid_id = true;
11648                 return LLAPI_LAYOUT_ITER_STOP;
11649         }
11650
11651         return LLAPI_LAYOUT_ITER_CONT;
11652 }
11653
11654 /**
11655  * verify_mirror_ids() - Verify specified mirror ids.
11656  * @fname:      Mirrored file name.
11657  * @mirror_ids: Specified mirror ids to be verified.
11658  * @ids_nr:     Number of specified mirror ids.
11659  *
11660  * This function verifies that specified @mirror_ids are valid
11661  * in the mirrored file @fname.
11662  *
11663  * Return: 0 on success or a negative error code on failure.
11664  */
11665 static inline
11666 int verify_mirror_ids(const char *fname, __u16 *mirror_ids, int ids_nr)
11667 {
11668         struct llapi_layout *layout = NULL;
11669         struct verify_mirror_id mirror_id_cbdata = { 0 };
11670         struct stat stbuf;
11671         uint32_t flr_state;
11672         int i;
11673         int fd;
11674         int rc = 0;
11675         int rc2 = 0;
11676
11677         if (ids_nr <= 0)
11678                 return -EINVAL;
11679
11680         if (stat(fname, &stbuf) < 0) {
11681                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
11682                         progname, fname, strerror(errno));
11683                 rc = -errno;
11684                 goto error;
11685         }
11686
11687         if (!S_ISREG(stbuf.st_mode)) {
11688                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
11689                         progname, fname);
11690                 rc = -EINVAL;
11691                 goto error;
11692         }
11693
11694         fd = open(fname, O_DIRECT | O_RDONLY);
11695         if (fd < 0) {
11696                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
11697                         progname, fname, strerror(errno));
11698                 rc = -errno;
11699                 goto error;
11700         }
11701
11702         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
11703         if (rc < 0) {
11704                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
11705                         progname, fname, strerror(errno));
11706                 goto close_fd;
11707         }
11708
11709         layout = llapi_layout_get_by_fd(fd, 0);
11710         if (!layout) {
11711                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
11712                         progname, fname, strerror(errno));
11713                 rc = -errno;
11714                 llapi_lease_release(fd);
11715                 goto close_fd;
11716         }
11717
11718         rc = llapi_layout_flags_get(layout, &flr_state);
11719         if (rc < 0) {
11720                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
11721                         progname, fname, strerror(errno));
11722                 rc = -errno;
11723                 goto free_layout;
11724         }
11725
11726         flr_state &= LCM_FL_FLR_MASK;
11727         switch (flr_state) {
11728         case LCM_FL_NONE:
11729                 rc = -EINVAL;
11730                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
11731                         progname, fname, llapi_layout_flags_string(flr_state));
11732                 goto free_layout;
11733         default:
11734                 break;
11735         }
11736
11737         rc2 = 0;
11738         for (i = 0; i < ids_nr; i++) {
11739                 mirror_id_cbdata.mirror_id = mirror_ids[i];
11740                 mirror_id_cbdata.is_valid_id = false;
11741
11742                 rc = llapi_layout_comp_iterate(layout, compare_mirror_ids,
11743                                                &mirror_id_cbdata);
11744                 if (rc < 0) {
11745                         rc = -errno;
11746                         fprintf(stderr,
11747                                 "%s: '%s' failed to verify mirror id: %u.\n",
11748                                 progname, fname, mirror_ids[i]);
11749                         goto free_layout;
11750                 }
11751
11752                 if (!mirror_id_cbdata.is_valid_id) {
11753                         rc2 = -EINVAL;
11754                         fprintf(stderr,
11755                                 "%s: '%s' invalid specified mirror id: %u.\n",
11756                                 progname, fname, mirror_ids[i]);
11757                 }
11758         }
11759         rc = rc2;
11760
11761 free_layout:
11762         llapi_layout_free(layout);
11763         llapi_lease_release(fd);
11764 close_fd:
11765         close(fd);
11766 error:
11767         return rc;
11768 }
11769
11770 static inline
11771 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
11772                            __u16 *mirror_ids, int ids_nr,
11773                            long stats_interval_sec, long bandwidth_bytes_sec)
11774 {
11775         struct llapi_resync_comp comp_array[1024] = { { 0 } };
11776         struct llapi_layout *layout;
11777         struct stat stbuf;
11778         uint32_t flr_state;
11779         uint64_t start;
11780         uint64_t end;
11781         int comp_size = 0;
11782         int idx;
11783         int fd;
11784         int rc;
11785         int rc2;
11786
11787         if (stat(fname, &stbuf) < 0) {
11788                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
11789                         progname, fname, strerror(errno));
11790                 rc = -errno;
11791                 goto error;
11792         }
11793         if (!S_ISREG(stbuf.st_mode)) {
11794                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
11795                         progname, fname);
11796                 rc = -EINVAL;
11797                 goto error;
11798         }
11799
11800         /* Allow mirror resync even without the key on encrypted files */
11801         fd = open(fname, O_DIRECT | O_RDWR | O_CIPHERTEXT);
11802         if (fd < 0) {
11803                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
11804                         progname, fname, strerror(errno));
11805                 rc = -errno;
11806                 goto error;
11807         }
11808
11809         layout = llapi_layout_get_by_fd(fd, 0);
11810         if (!layout) {
11811                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
11812                         progname, fname, strerror(errno));
11813                 rc = -errno;
11814                 goto close_fd;
11815         }
11816
11817         rc = llapi_layout_flags_get(layout, &flr_state);
11818         if (rc) {
11819                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
11820                         progname, fname, strerror(errno));
11821                 rc = -errno;
11822                 goto free_layout;
11823         }
11824
11825         flr_state &= LCM_FL_FLR_MASK;
11826         if (flr_state == LCM_FL_NONE) {
11827                 rc = -EINVAL;
11828                 fprintf(stderr, "%s: '%s' is not a FLR file.\n",
11829                         progname, fname);
11830                 goto free_layout;
11831         }
11832
11833         /* get stale component info */
11834         comp_size = llapi_mirror_find_stale(layout, comp_array,
11835                                             ARRAY_SIZE(comp_array),
11836                                             mirror_ids, ids_nr);
11837         if (comp_size <= 0) {
11838                 rc = comp_size;
11839                 goto free_layout;
11840         }
11841
11842         ioc->lil_mode = LL_LEASE_WRLCK;
11843         ioc->lil_flags = LL_LEASE_RESYNC;
11844         rc = llapi_lease_set(fd, ioc);
11845         if (rc < 0) {
11846                 if (rc == -EALREADY)
11847                         rc = 0;
11848                 else
11849                         fprintf(stderr,
11850                             "%s: '%s' llapi_lease_get_ext resync failed: %s.\n",
11851                                 progname, fname, strerror(-rc));
11852                 goto free_layout;
11853         }
11854
11855         /* get the read range [start, end) */
11856         start = comp_array[0].lrc_start;
11857         end = comp_array[0].lrc_end;
11858         for (idx = 1; idx < comp_size; idx++) {
11859                 if (comp_array[idx].lrc_start < start)
11860                         start = comp_array[idx].lrc_start;
11861                 if (end < comp_array[idx].lrc_end)
11862                         end = comp_array[idx].lrc_end;
11863         }
11864
11865         rc = llapi_lease_check(fd);
11866         if (rc != LL_LEASE_WRLCK) {
11867                 fprintf(stderr, "%s: '%s' lost lease lock.\n",
11868                         progname, fname);
11869                 goto free_layout;
11870         }
11871
11872         rc = llapi_mirror_resync_many_params(fd, layout, comp_array, comp_size,
11873                                              start, end, stats_interval_sec,
11874                                              bandwidth_bytes_sec);
11875         if (rc < 0)
11876                 fprintf(stderr, "%s: '%s' llapi_mirror_resync_many: %s.\n",
11877                         progname, fname, strerror(-rc));
11878
11879         rc2 = migrate_set_timestamps(fd, &stbuf);
11880         if (rc2 < 0) {
11881                 fprintf(stderr, "%s: '%s' cannot set timestamps: %s\n",
11882                         progname, fname, strerror(-rc2));
11883                 if (!rc)
11884                         rc = rc2;
11885                 goto free_layout;
11886         }
11887
11888         /* need to do the lease unlock even resync fails */
11889         ioc->lil_mode = LL_LEASE_UNLCK;
11890         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
11891         ioc->lil_count = 0;
11892         for (idx = 0; idx < comp_size; idx++) {
11893                 if (comp_array[idx].lrc_synced) {
11894                         ioc->lil_ids[ioc->lil_count] = comp_array[idx].lrc_id;
11895                         ioc->lil_count++;
11896                 }
11897         }
11898
11899         rc2 = llapi_lease_set(fd, ioc);
11900         /**
11901          * llapi_lease_set returns lease mode when it request to unlock
11902          * the lease lock.
11903          */
11904         if (rc2 <= 0) {
11905                 /* rc2 == 0 means lost lease lock */
11906                 if (rc2 == 0 && rc == 0)
11907                         rc = -EBUSY;
11908                 else
11909                         rc = rc2;
11910                 fprintf(stderr, "%s: resync file '%s' failed: %s.\n",
11911                         progname, fname,
11912                         rc2 == 0 ? "lost lease lock" : strerror(-rc2));
11913
11914                 llapi_lease_release(fd);
11915                 goto free_layout;
11916         }
11917
11918 free_layout:
11919         llapi_layout_free(layout);
11920 close_fd:
11921         close(fd);
11922 error:
11923         return rc;
11924 }
11925
11926 static inline int lfs_mirror_resync(int argc, char **argv)
11927 {
11928         struct option long_opts[] = {
11929         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11930         { .val = 'o',   .name = "only",         .has_arg = required_argument },
11931         { .val = 'W',   .name = "bandwidth",    .has_arg = required_argument },
11932         { .val = LFS_STATS_OPT,
11933                         .name = "stats",        .has_arg = no_argument},
11934         { .val = LFS_STATS_INTERVAL_OPT,
11935                         .name = "stats-interval",
11936                                                 .has_arg = required_argument},
11937         { .name = NULL } };
11938         struct ll_ioc_lease *ioc = NULL;
11939         __u16 mirror_ids[128] = { 0 };
11940         unsigned int stats_interval_sec = 0;
11941         unsigned long long bandwidth_bytes_sec = 0;
11942         unsigned long long bandwidth_unit = ONE_MB;
11943         int ids_nr = 0;
11944         int c;
11945         int rc = 0;
11946
11947         while ((c = getopt_long(argc, argv, "ho:W:", long_opts, NULL)) >= 0) {
11948                 char *end;
11949                 switch (c) {
11950                 case 'o':
11951                         rc = parse_mirror_ids(mirror_ids,
11952                                         sizeof(mirror_ids) / sizeof(__u16),
11953                                         optarg);
11954                         if (rc < 0) {
11955                                 fprintf(stderr,
11956                                         "%s: bad mirror ids '%s'.\n",
11957                                         argv[0], optarg);
11958                                 goto error;
11959                         }
11960                         ids_nr = rc;
11961                         break;
11962                 case 'W':
11963                         if (llapi_parse_size(optarg, &bandwidth_bytes_sec,
11964                                              &bandwidth_unit, 0) < 0) {
11965                                 fprintf(stderr,
11966                                         "error: %s: bad value for bandwidth '%s'\n",
11967                                         argv[0], optarg);
11968                                 goto error;
11969                         }
11970                         break;
11971                 case LFS_STATS_OPT:
11972                         stats_interval_sec = 5;
11973                         break;
11974                 case LFS_STATS_INTERVAL_OPT:
11975                         stats_interval_sec = strtol(optarg, &end, 0);
11976                         break;
11977                 default:
11978                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11979                                 progname, argv[optind - 1]);
11980                         fallthrough;
11981                 case 'h':
11982                         rc = CMD_HELP;
11983                         goto error;
11984                 }
11985         }
11986
11987         if (argc == optind) {
11988                 fprintf(stderr, "%s: no file name given.\n", argv[0]);
11989                 rc = CMD_HELP;
11990                 goto error;
11991         }
11992
11993         if (ids_nr > 0 && argc > optind + 1) {
11994                 fprintf(stderr,
11995                     "%s: option '--only' cannot be used upon multiple files.\n",
11996                         argv[0]);
11997                 rc = CMD_HELP;
11998                 goto error;
11999         }
12000
12001         if (ids_nr > 0) {
12002                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
12003                 if (rc < 0)
12004                         goto error;
12005         }
12006
12007         /* set the lease on the file */
12008         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
12009         if (!ioc) {
12010                 fprintf(stderr, "%s: cannot alloc id array for ioc: %s.\n",
12011                         argv[0], strerror(errno));
12012                 rc = -errno;
12013                 goto error;
12014         }
12015
12016         for (; optind < argc; optind++) {
12017                 rc = lfs_mirror_resync_file(argv[optind], ioc,
12018                                             mirror_ids, ids_nr,
12019                                             stats_interval_sec,
12020                                             bandwidth_bytes_sec);
12021                 /* ignore previous file's error, continue with next file */
12022
12023                 /* reset ioc */
12024                 memset(ioc, 0, sizeof(*ioc) + sizeof(__u32) * 4096);
12025         }
12026
12027         free(ioc);
12028 error:
12029         return rc;
12030 }
12031
12032 static inline int verify_mirror_id_by_fd(int fd, __u16 mirror_id)
12033 {
12034         struct llapi_layout *layout;
12035         int rc;
12036
12037         layout = llapi_layout_get_by_fd(fd, 0);
12038         if (!layout) {
12039                 fprintf(stderr, "could not get layout.\n");
12040                 return  -EINVAL;
12041         }
12042
12043         rc = llapi_layout_comp_iterate(layout, find_mirror_id, &mirror_id);
12044         if (rc < 0) {
12045                 fprintf(stderr, "failed to iterate layout\n");
12046                 llapi_layout_free(layout);
12047
12048                 return rc;
12049         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
12050                 fprintf(stderr, "does not find mirror with ID %u\n", mirror_id);
12051                 llapi_layout_free(layout);
12052
12053                 return -EINVAL;
12054         }
12055         llapi_layout_free(layout);
12056
12057         return 0;
12058 }
12059
12060 /**
12061  * Check whether two files are the same file
12062  * \retval      0  same file
12063  * \retval      1  not the same file
12064  * \retval      <0 error code
12065  */
12066 static inline int check_same_file(int fd, const char *f2)
12067 {
12068         struct stat stbuf1;
12069         struct stat stbuf2;
12070
12071         if (fstat(fd, &stbuf1) < 0)
12072                 return -errno;
12073
12074         if (stat(f2, &stbuf2) < 0)
12075                 return 1;
12076
12077         if (stbuf1.st_rdev == stbuf2.st_rdev &&
12078             stbuf1.st_ino == stbuf2.st_ino)
12079                 return 0;
12080
12081         return 1;
12082 }
12083
12084 static inline int lfs_mirror_read(int argc, char **argv)
12085 {
12086         int rc = CMD_HELP;
12087         __u16 mirror_id = 0;
12088         const char *outfile = NULL;
12089         char *fname;
12090         int fd = 0;
12091         int outfd;
12092         int c;
12093         void *buf;
12094         const size_t buflen = 4 << 20;
12095         ssize_t page_size;
12096         off_t pos;
12097         struct option long_opts[] = {
12098         { .val = 'h',   .name = "help",         .has_arg = no_argument },
12099         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
12100         { .val = 'o',   .name = "outfile",      .has_arg = required_argument },
12101         { .name = NULL } };
12102
12103         while ((c = getopt_long(argc, argv, "hN:o:", long_opts, NULL)) >= 0) {
12104                 char *end;
12105
12106                 switch (c) {
12107                 case 'N': {
12108                         unsigned long int id;
12109
12110                         errno = 0;
12111                         id = strtoul(optarg, &end, 0);
12112                         if (errno != 0 || *end != '\0' || id == 0 ||
12113                             id > UINT16_MAX) {
12114                                 fprintf(stderr,
12115                                         "%s %s: invalid mirror ID '%s'\n",
12116                                         progname, argv[0], optarg);
12117                                 return rc;
12118                         }
12119
12120                         mirror_id = (__u16)id;
12121                         break;
12122                 }
12123                 case 'o':
12124                         outfile = optarg;
12125                         break;
12126                 default:
12127                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12128                                 progname, argv[optind - 1]);
12129                         fallthrough;
12130                 case 'h':
12131                         return CMD_HELP;
12132                 }
12133         }
12134
12135         if (argc == optind) {
12136                 fprintf(stderr, "%s %s: no mirrored file provided\n",
12137                         progname, argv[0]);
12138                 return rc;
12139         } else if (argc > optind + 1) {
12140                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
12141                 return rc;
12142         }
12143
12144         if (mirror_id == 0) {
12145                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
12146                         progname, argv[0]);
12147                 return rc;
12148         }
12149
12150         /* open mirror file */
12151         fname = argv[optind];
12152         fd = open(fname, O_DIRECT | O_RDONLY);
12153         if (fd < 0) {
12154                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
12155                         progname, argv[0], fname, strerror(errno));
12156                 return rc;
12157         }
12158
12159         /* verify mirror id */
12160         rc = verify_mirror_id_by_fd(fd, mirror_id);
12161         if (rc) {
12162                 fprintf(stderr,
12163                         "%s %s: cannot find mirror with ID %u in '%s'\n",
12164                         progname, argv[0], mirror_id, fname);
12165                 goto close_fd;
12166         }
12167
12168         /* open output file - O_EXCL ensures output is not the same as input */
12169         if (outfile) {
12170                 outfd = open(outfile, O_EXCL | O_WRONLY | O_CREAT, 0644);
12171                 if (outfd < 0) {
12172                         fprintf(stderr, "%s %s: cannot create file '%s': %s\n",
12173                                 progname, argv[0], outfile, strerror(errno));
12174                         rc = -errno;
12175                         goto close_fd;
12176                 }
12177         } else {
12178                 outfd = STDOUT_FILENO;
12179         }
12180
12181         page_size = sysconf(_SC_PAGESIZE);
12182         if (page_size < 0) {
12183                 rc = -errno;
12184                 goto close_fd;
12185         }
12186
12187         /* allocate buffer */
12188         rc = posix_memalign(&buf, page_size, buflen);
12189         if (rc) {
12190                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
12191                                 progname, argv[0], rc);
12192                 goto close_outfd;
12193         }
12194
12195         pos = 0;
12196         while (1) {
12197                 ssize_t bytes_read;
12198                 ssize_t written = 0;
12199
12200                 bytes_read = llapi_mirror_read(fd, mirror_id, buf, buflen, pos);
12201                 if (bytes_read < 0) {
12202                         rc = bytes_read;
12203                         fprintf(stderr,
12204                                 "%s %s: fail to read data from mirror %u: %s\n",
12205                                 progname, argv[0], mirror_id, strerror(-rc));
12206                         goto free_buf;
12207                 }
12208
12209                 /* EOF reached */
12210                 if (bytes_read == 0)
12211                         break;
12212
12213                 while (written < bytes_read) {
12214                         ssize_t written2;
12215
12216                         written2 = write(outfd, buf + written,
12217                                          bytes_read - written);
12218                         if (written2 < 0) {
12219                                 fprintf(stderr,
12220                                         "%s %s: fail to write %s: %s\n",
12221                                         progname, argv[0], outfile ? : "STDOUT",
12222                                         strerror(errno));
12223                                 rc = -errno;
12224                                 goto free_buf;
12225                         }
12226                         written += written2;
12227                 }
12228
12229                 if (written != bytes_read) {
12230                         fprintf(stderr,
12231                 "%s %s: written %ld bytes does not match with %ld read.\n",
12232                                 progname, argv[0], written, bytes_read);
12233                         rc = -EIO;
12234                         goto free_buf;
12235                 }
12236
12237                 pos += bytes_read;
12238         }
12239
12240         fsync(outfd);
12241         rc = 0;
12242
12243 free_buf:
12244         free(buf);
12245 close_outfd:
12246         if (outfile)
12247                 close(outfd);
12248 close_fd:
12249         close(fd);
12250
12251         return rc;
12252 }
12253
12254 static inline int lfs_mirror_write(int argc, char **argv)
12255 {
12256         int rc = CMD_HELP;
12257         __u16 mirror_id = 0;
12258         const char *inputfile = NULL;
12259         char *fname;
12260         int fd = 0;
12261         int inputfd;
12262         int c;
12263         void *buf;
12264         const size_t buflen = 4 << 20;
12265         off_t pos;
12266         ssize_t page_size = sysconf(_SC_PAGESIZE);
12267         struct ll_ioc_lease_id ioc;
12268         struct option long_opts[] = {
12269         { .val = 'h',   .name = "help",         .has_arg = no_argument },
12270         { .val = 'i',   .name = "inputfile",    .has_arg = required_argument },
12271         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
12272         { .name = NULL } };
12273
12274         while ((c = getopt_long(argc, argv, "hi:N:", long_opts, NULL)) >= 0) {
12275                 char *end;
12276
12277                 switch (c) {
12278                 case 'N': {
12279                         unsigned long int id;
12280
12281                         errno = 0;
12282                         id = strtoul(optarg, &end, 0);
12283                         if (errno != 0 || *end != '\0' || id == 0 ||
12284                             id > UINT16_MAX) {
12285                                 fprintf(stderr,
12286                                         "%s %s: invalid mirror ID '%s'\n",
12287                                         progname, argv[0], optarg);
12288                                 return rc;
12289                         }
12290
12291                         mirror_id = (__u16)id;
12292                         break;
12293                 }
12294                 case 'i':
12295                         inputfile = optarg;
12296                         break;
12297                 default:
12298                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12299                                 progname, argv[optind - 1]);
12300                         fallthrough;
12301                 case 'h':
12302                         return CMD_HELP;
12303                 }
12304         }
12305
12306         if (argc == optind) {
12307                 fprintf(stderr, "%s %s: no mirrored file provided\n",
12308                         progname, argv[0]);
12309                 return rc;
12310         } else if (argc > optind + 1) {
12311                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
12312                 return rc;
12313         }
12314
12315         if (mirror_id == 0) {
12316                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
12317                         progname, argv[0]);
12318                 return rc;
12319         }
12320
12321         /* open mirror file */
12322         fname = argv[optind];
12323         fd = open(fname, O_DIRECT | O_WRONLY);
12324         if (fd < 0) {
12325                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
12326                         progname, argv[0], fname, strerror(errno));
12327                 return rc;
12328         }
12329
12330         /* verify mirror id */
12331         rc = verify_mirror_id_by_fd(fd, mirror_id);
12332         if (rc) {
12333                 fprintf(stderr,
12334                         "%s %s: cannot find mirror with ID %u in '%s'\n",
12335                         progname, argv[0], mirror_id, fname);
12336                 goto close_fd;
12337         }
12338
12339         /* open input file */
12340         if (inputfile) {
12341                 rc = check_same_file(fd, inputfile);
12342                 if (rc == 0) {
12343                         fprintf(stderr,
12344                         "%s %s: input file cannot be the mirrored file '%s'\n",
12345                                 progname, argv[0], fname);
12346                         goto close_fd;
12347                 }
12348                 if (rc < 0)
12349                         goto close_fd;
12350
12351                 inputfd = open(inputfile, O_RDONLY, 0644);
12352                 if (inputfd < 0) {
12353                         fprintf(stderr, "%s %s: cannot open file '%s': %s\n",
12354                                 progname, argv[0], inputfile, strerror(errno));
12355                         rc = -errno;
12356                         goto close_fd;
12357                 }
12358         } else {
12359                 inputfd = STDIN_FILENO;
12360         }
12361
12362         /* allocate buffer */
12363         rc = posix_memalign(&buf, page_size, buflen);
12364         if (rc) {
12365                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
12366                         progname, argv[0], rc);
12367                 goto close_inputfd;
12368         }
12369
12370         /* prepare target mirror components instantiation */
12371         ioc.lil_mode = LL_LEASE_WRLCK;
12372         ioc.lil_flags = LL_LEASE_RESYNC;
12373         ioc.lil_mirror_id = mirror_id;
12374         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
12375         if (rc < 0) {
12376                 fprintf(stderr,
12377                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
12378                         progname, argv[0], fname, strerror(errno));
12379                 goto free_buf;
12380         }
12381
12382         pos = 0;
12383         while (1) {
12384                 ssize_t bytes_read;
12385                 ssize_t written;
12386                 size_t to_write;
12387
12388                 rc = llapi_lease_check(fd);
12389                 if (rc != LL_LEASE_WRLCK) {
12390                         fprintf(stderr, "%s %s: '%s' lost lease lock\n",
12391                                 progname, argv[0], fname);
12392                         goto free_buf;
12393                 }
12394
12395                 bytes_read = read(inputfd, buf, buflen);
12396                 if (bytes_read < 0) {
12397                         rc = bytes_read;
12398                         fprintf(stderr,
12399                                 "%s %s: fail to read data from '%s': %s\n",
12400                                 progname, argv[0], inputfile ? : "STDIN",
12401                                 strerror(errno));
12402                         rc = -errno;
12403                         goto free_buf;
12404                 }
12405
12406                 /* EOF reached */
12407                 if (bytes_read == 0)
12408                         break;
12409
12410                 /* round up to page align to make direct IO happy. */
12411                 to_write = (bytes_read + page_size - 1) & ~(page_size - 1);
12412
12413                 written = llapi_mirror_write(fd, mirror_id, buf, to_write,
12414                                              pos);
12415                 if (written < 0) {
12416                         rc = written;
12417                         fprintf(stderr,
12418                               "%s %s: fail to write to mirror %u: %s\n",
12419                                 progname, argv[0], mirror_id,
12420                                 strerror(-rc));
12421                         goto free_buf;
12422                 }
12423
12424                 pos += bytes_read;
12425         }
12426
12427         if (pos & (page_size - 1)) {
12428                 rc = llapi_mirror_truncate(fd, mirror_id, pos);
12429                 if (rc < 0)
12430                         goto free_buf;
12431         }
12432
12433         ioc.lil_mode = LL_LEASE_UNLCK;
12434         ioc.lil_flags = LL_LEASE_RESYNC_DONE;
12435         ioc.lil_count = 0;
12436         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
12437         if (rc <= 0) {
12438                 if (rc == 0)
12439                         rc = -EBUSY;
12440                 fprintf(stderr,
12441                         "%s %s: release lease lock of '%s' failed: %s\n",
12442                         progname, argv[0], fname, strerror(-rc));
12443                 goto free_buf;
12444         }
12445
12446         rc = 0;
12447
12448 free_buf:
12449         free(buf);
12450 close_inputfd:
12451         if (inputfile)
12452                 close(inputfd);
12453 close_fd:
12454         close(fd);
12455
12456         return rc;
12457 }
12458
12459 static inline int get_other_mirror_ids(int fd, __u16 *ids, __u16 exclude_id)
12460 {
12461         struct llapi_layout *layout;
12462         struct collect_ids_data cid = { .cid_ids = ids,
12463                                         .cid_count = 0,
12464                                         .cid_exclude = exclude_id, };
12465         int rc;
12466
12467         layout = llapi_layout_get_by_fd(fd, 0);
12468         if (!layout) {
12469                 fprintf(stderr, "could not get layout\n");
12470                 return -EINVAL;
12471         }
12472
12473         rc = llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
12474         if (rc < 0) {
12475                 fprintf(stderr, "failed to iterate layout\n");
12476                 llapi_layout_free(layout);
12477
12478                 return rc;
12479         }
12480         llapi_layout_free(layout);
12481
12482         return cid.cid_count;
12483 }
12484
12485 #ifndef MIRROR_ID_NEG
12486 #define MIRROR_ID_NEG         0x8000
12487 #endif
12488
12489 static inline int lfs_mirror_copy(int argc, char **argv)
12490 {
12491         int rc = CMD_HELP;
12492         __u16 read_mirror_id = 0;
12493         __u16 ids[128] = { 0 };
12494         int count = 0;
12495         struct llapi_layout *layout = NULL;
12496         struct llapi_resync_comp comp_array[1024] = { { 0 } };
12497         int comp_size = 0;
12498         char *fname;
12499         int fd = 0;
12500         int c;
12501         int i;
12502         ssize_t copied;
12503         struct ll_ioc_lease *ioc = NULL;
12504         struct ll_ioc_lease_id *resync_ioc;
12505         struct option long_opts[] = {
12506         { .val = 'h',   .name = "help",         .has_arg = no_argument },
12507         { .val = 'i',   .name = "read-mirror",  .has_arg = required_argument },
12508         { .val = 'o',   .name = "write-mirror", .has_arg = required_argument },
12509         { .name = NULL } };
12510         char cmd[PATH_MAX];
12511
12512         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12513         progname = cmd;
12514         while ((c = getopt_long(argc, argv, "hi:o:", long_opts, NULL)) >= 0) {
12515                 char *end;
12516
12517                 switch (c) {
12518                 case 'i': {
12519                         unsigned long int id;
12520
12521                         errno = 0;
12522                         id = strtoul(optarg, &end, 0);
12523                         if (errno != 0 || *end != '\0' || id == 0 ||
12524                             id > UINT16_MAX) {
12525                                 fprintf(stderr,
12526                                         "%s: invalid read mirror ID '%s'\n",
12527                                         progname, optarg);
12528                                 return rc;
12529                         }
12530
12531                         read_mirror_id = (__u16)id;
12532                         break;
12533                 }
12534                 case 'o':
12535                         if (!strcmp(optarg, "-1")) {
12536                                 /* specify all other mirrors */
12537                                 ids[0] = (__u16)-1;
12538                                 count = 1;
12539                         } else {
12540                                 count = parse_mirror_ids((__u16 *)ids,
12541                                                          ARRAY_SIZE(ids),
12542                                                          optarg);
12543                                 if (count < 0)
12544                                         return rc;
12545                         }
12546                         break;
12547                 default:
12548                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12549                                 progname, argv[optind - 1]);
12550                         fallthrough;
12551                 case 'h':
12552                         return CMD_HELP;
12553                 }
12554         }
12555
12556         if (argc == optind) {
12557                 fprintf(stderr, "%s %s: no mirrored file provided\n",
12558                         progname, argv[0]);
12559                 return rc;
12560         } else if (argc > optind + 1) {
12561                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
12562                 return rc;
12563         }
12564
12565         if (read_mirror_id == 0) {
12566                 fprintf(stderr,
12567                         "%s %s: no valid read mirror ID %d is provided\n",
12568                         progname, argv[0], read_mirror_id);
12569                 return rc;
12570         }
12571
12572         if (count == 0) {
12573                 fprintf(stderr,
12574                         "%s %s: no write mirror ID is provided\n",
12575                         progname, argv[0]);
12576                 return rc;
12577         }
12578
12579         for (i = 0; i < count; i++) {
12580                 if (read_mirror_id == ids[i]) {
12581                         fprintf(stderr,
12582                         "%s %s: read and write mirror ID cannot be the same\n",
12583                                 progname, argv[0]);
12584                         return rc;
12585                 }
12586         }
12587
12588         /* open mirror file */
12589         fname = argv[optind];
12590
12591         fd = open(fname, O_DIRECT | O_RDWR);
12592         if (fd < 0) {
12593                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
12594                         progname, argv[0], fname, strerror(errno));
12595                 return rc;
12596         }
12597
12598         /* write to all other mirrors */
12599         if (ids[0] == (__u16)-1) {
12600                 count = get_other_mirror_ids(fd, ids, read_mirror_id);
12601                 if (count <= 0) {
12602                         rc = count;
12603                         fprintf(stderr,
12604                         "%s %s: failed to get other mirror ids in '%s': %d\n",
12605                                 progname, argv[0], fname, rc);
12606                         goto close_fd;
12607                 }
12608         }
12609
12610         /* verify mirror id */
12611         rc = verify_mirror_id_by_fd(fd, read_mirror_id);
12612         if (rc) {
12613                 fprintf(stderr,
12614                         "%s %s: cannot find mirror with ID %u in '%s'\n",
12615                         progname, argv[0], read_mirror_id, fname);
12616                 goto close_fd;
12617         }
12618
12619         for (i = 0; i < count; i++) {
12620                 rc = verify_mirror_id_by_fd(fd, ids[i]);
12621                 if (rc) {
12622                         fprintf(stderr,
12623                         "%s %s: cannot find mirror with ID %u in '%s'\n",
12624                                 progname, argv[0], ids[i], fname);
12625                         goto close_fd;
12626                 }
12627         }
12628
12629         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
12630         if (!ioc) {
12631                 fprintf(stderr,
12632                         "%s %s: cannot alloc comp id array for ioc: %s\n",
12633                         progname, argv[0], strerror(errno));
12634                 rc = -errno;
12635                 goto close_fd;
12636         }
12637
12638         /* get stale component info */
12639         layout = llapi_layout_get_by_fd(fd, 0);
12640         if (!layout) {
12641                 fprintf(stderr, "%s %s: failed to get layout of '%s': %s\n",
12642                         progname, argv[0], fname, strerror(errno));
12643                 rc = -errno;
12644                 goto free_ioc;
12645         }
12646         comp_size = llapi_mirror_find_stale(layout, comp_array,
12647                                             ARRAY_SIZE(comp_array),
12648                                             ids, count);
12649         llapi_layout_free(layout);
12650         if (comp_size < 0) {
12651                 rc = comp_size;
12652                 goto free_ioc;
12653         }
12654
12655         /* prepare target mirror components instantiation */
12656         resync_ioc = (struct ll_ioc_lease_id *)ioc;
12657         resync_ioc->lil_mode = LL_LEASE_WRLCK;
12658         resync_ioc->lil_flags = LL_LEASE_RESYNC;
12659         if (count == 1)
12660                 resync_ioc->lil_mirror_id = ids[0];
12661         else
12662                 resync_ioc->lil_mirror_id = read_mirror_id | MIRROR_ID_NEG;
12663         rc = llapi_lease_set(fd, ioc);
12664         if (rc < 0) {
12665                 fprintf(stderr,
12666                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
12667                         progname, argv[0], fname, strerror(errno));
12668                 goto free_ioc;
12669         }
12670
12671         copied = llapi_mirror_copy_many(fd, read_mirror_id, ids, count);
12672         if (copied < 0) {
12673                 rc = copied;
12674                 fprintf(stderr, "%s %s: copy error: %d\n",
12675                         progname, argv[0], rc);
12676                 goto free_ioc;
12677         }
12678
12679         fprintf(stdout, "mirror copied successfully: ");
12680         for (i = 0; i < copied; i++)
12681                 fprintf(stdout, "%d ", ids[i]);
12682         fprintf(stdout, "\n");
12683
12684         ioc->lil_mode = LL_LEASE_UNLCK;
12685         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
12686         ioc->lil_count = 0;
12687         for (i = 0; i < comp_size; i++) {
12688                 int j;
12689
12690                 for (j = 0; j < copied; j++) {
12691                         if (comp_array[i].lrc_mirror_id != ids[j])
12692                                 continue;
12693
12694                         ioc->lil_ids[ioc->lil_count] = comp_array[i].lrc_id;
12695                         ioc->lil_count++;
12696                 }
12697         }
12698         rc = llapi_lease_set(fd, ioc);
12699         if (rc <= 0) {
12700                 if (rc == 0)
12701                         rc = -EBUSY;
12702                 fprintf(stderr,
12703                         "%s %s: release lease lock of '%s' failed: %s\n",
12704                         progname, argv[0], fname, strerror(errno));
12705                 goto free_ioc;
12706         }
12707
12708         rc = 0;
12709
12710 free_ioc:
12711         free(ioc);
12712 close_fd:
12713         close(fd);
12714
12715         return rc;
12716 }
12717
12718 /**
12719  * struct verify_chunk - Mirror chunk to be verified.
12720  * @chunk:        [start, end) of the chunk.
12721  * @mirror_count: Number of mirror ids in @mirror_id array.
12722  * @mirror_id:    Array of valid mirror ids that cover the chunk.
12723  */
12724 struct verify_chunk {
12725         struct lu_extent chunk;
12726         unsigned int mirror_count;
12727         __u16 mirror_id[LUSTRE_MIRROR_COUNT_MAX];
12728 };
12729
12730 /**
12731  * print_chunks() - Print chunk information.
12732  * @fname:       Mirrored file name.
12733  * @chunks:      Array of chunks.
12734  * @chunk_count: Number of chunks in @chunks array.
12735  *
12736  * This function prints [start, end) of each chunk in @chunks
12737  * for mirrored file @fname, and also prints the valid mirror ids
12738  * that cover the chunk.
12739  *
12740  * Return: void.
12741  */
12742 static inline
12743 void print_chunks(const char *fname, struct verify_chunk *chunks,
12744                   int chunk_count)
12745 {
12746         int i;
12747         int j;
12748
12749         fprintf(stdout, "Chunks to be verified in %s:\n", fname);
12750         for (i = 0; i < chunk_count; i++) {
12751                 fprintf(stdout, DEXT, PEXT(&chunks[i].chunk));
12752
12753                 if (chunks[i].mirror_count == 0)
12754                         fprintf(stdout, "\t[");
12755                 else {
12756                         fprintf(stdout, "\t[%u", chunks[i].mirror_id[0]);
12757                         for (j = 1; j < chunks[i].mirror_count; j++)
12758                                 fprintf(stdout, ", %u", chunks[i].mirror_id[j]);
12759                 }
12760                 fprintf(stdout, "]\t%u\n", chunks[i].mirror_count);
12761         }
12762         fprintf(stdout, "\n");
12763 }
12764
12765 /**
12766  * print_checksums() - Print CRC-32 checksum values.
12767  * @chunk: A chunk and its corresponding valid mirror ids.
12768  * @crc:   CRC-32 checksum values on the chunk for each valid mirror.
12769  *
12770  * This function prints CRC-32 checksum values on @chunk for
12771  * each valid mirror that covers it.
12772  *
12773  * Return: void.
12774  */
12775 static inline
12776 void print_checksums(struct verify_chunk *chunk, unsigned long *crc,
12777                      unsigned long long pos, unsigned long long len)
12778 {
12779         int i;
12780
12781         fprintf(stdout,
12782                 "CRC-32 checksum value for chunk "DEXT":\n", pos, pos + len);
12783         for (i = 0; i < chunk->mirror_count; i++)
12784                 fprintf(stdout, "Mirror %u:\t%#lx\n",
12785                         chunk->mirror_id[i], crc[i]);
12786         fprintf(stdout, "\n");
12787 }
12788
12789 /**
12790  * filter_mirror_id() - Filter specified mirror ids.
12791  * @chunks:      Array of chunks.
12792  * @chunk_count: Number of chunks in @chunks array.
12793  * @mirror_ids:  Specified mirror ids to be verified.
12794  * @ids_nr:      Number of specified mirror ids.
12795  *
12796  * This function scans valid mirror ids that cover each chunk in @chunks
12797  * and filters specified mirror ids.
12798  *
12799  * Return: void.
12800  */
12801 static inline
12802 void filter_mirror_id(struct verify_chunk *chunks, int chunk_count,
12803                       __u16 *mirror_ids, int ids_nr)
12804 {
12805         int i;
12806         int j;
12807         int k;
12808         __u16 valid_id[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
12809         unsigned int valid_count = 0;
12810
12811         for (i = 0; i < chunk_count; i++) {
12812                 if (chunks[i].mirror_count == 0)
12813                         continue;
12814
12815                 valid_count = 0;
12816                 for (j = 0; j < ids_nr; j++) {
12817                         for (k = 0; k < chunks[i].mirror_count; k++) {
12818                                 if (chunks[i].mirror_id[k] == mirror_ids[j]) {
12819                                         valid_id[valid_count] = mirror_ids[j];
12820                                         valid_count++;
12821                                         break;
12822                                 }
12823                         }
12824                 }
12825
12826                 memcpy(chunks[i].mirror_id, valid_id,
12827                        sizeof(__u16) * valid_count);
12828                 chunks[i].mirror_count = valid_count;
12829         }
12830 }
12831
12832 /**
12833  * lfs_mirror_prepare_chunk() - Find mirror chunks to be verified.
12834  * @layout:      Mirror component list.
12835  * @chunks:      Array of chunks.
12836  * @chunks_size: Array size of @chunks.
12837  *
12838  * This function scans the components in @layout from offset 0 to LUSTRE_EOF
12839  * to find out chunk segments and store them in @chunks array.
12840  *
12841  * The @mirror_id array in each element of @chunks will store the valid
12842  * mirror ids that cover the chunk. If a mirror component covering the
12843  * chunk has LCME_FL_STALE or LCME_FL_OFFLINE flag, then the mirror id
12844  * will not be stored into the @mirror_id array, and the chunk for that
12845  * mirror will not be verified.
12846  *
12847  * The @mirror_count in each element of @chunks will store the number of
12848  * mirror ids in @mirror_id array. If @mirror_count is 0, it indicates the
12849  * chunk is invalid in all of the mirrors. And if @mirror_count is 1, it
12850  * indicates the chunk is valid in only one mirror. In both cases, the
12851  * chunk will not be verified.
12852  *
12853  * Here is an example:
12854  *
12855  *  0      1M     2M     3M     4M           EOF
12856  *  +------+-------------+--------------------+
12857  *  |      |             |      S             |       mirror1
12858  *  +------+------+------+------+-------------+
12859  *  |             |   S  |   S  |             |       mirror2
12860  *  +-------------+------+------+-------------+
12861  *
12862  * prepared @chunks array will contain 5 elements:
12863  * (([0, 1M), [1, 2], 2),
12864  *  ([1M, 2M), [1, 2], 2),
12865  *  ([2M, 3M), [1], 1),
12866  *  ([3M, 4M], [], 0),
12867  *  ([4M, EOF), [2], 1))
12868  *
12869  * Return: the actual array size of @chunks on success
12870  *         or a negative error code on failure.
12871  */
12872 static inline
12873 int lfs_mirror_prepare_chunk(struct llapi_layout *layout,
12874                              struct verify_chunk *chunks,
12875                              size_t chunks_size)
12876 {
12877         uint64_t start;
12878         uint64_t end;
12879         uint32_t mirror_id;
12880         uint32_t flags;
12881         int idx = 0;
12882         int i = 0;
12883         int rc = 0;
12884
12885         memset(chunks, 0, sizeof(*chunks) * chunks_size);
12886
12887         while (1) {
12888                 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
12889                 if (rc < 0) {
12890                         fprintf(stderr,
12891                                 "%s: move to the first layout component: %s.\n",
12892                                 progname, strerror(errno));
12893                         goto error;
12894                 }
12895
12896                 i = 0;
12897                 rc = 0;
12898                 chunks[idx].chunk.e_end = LUSTRE_EOF;
12899                 while (rc == 0) {
12900                         rc = llapi_layout_comp_extent_get(layout, &start, &end);
12901                         if (rc < 0) {
12902                                 fprintf(stderr,
12903                                         "%s: llapi_layout_comp_extent_get failed: %s.\n",
12904                                         progname, strerror(errno));
12905                                 goto error;
12906                         }
12907
12908                         if (start > chunks[idx].chunk.e_start ||
12909                             end <= chunks[idx].chunk.e_start)
12910                                 goto next;
12911
12912                         if (end < chunks[idx].chunk.e_end)
12913                                 chunks[idx].chunk.e_end = end;
12914
12915                         rc = llapi_layout_comp_flags_get(layout, &flags);
12916                         if (rc < 0) {
12917                                 fprintf(stderr,
12918                                         "%s: llapi_layout_comp_flags_get failed: %s.\n",
12919                                         progname, strerror(errno));
12920                                 goto error;
12921                         }
12922
12923                         if (flags & LCME_FL_STALE || flags & LCME_FL_OFFLINE)
12924                                 goto next;
12925
12926                         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
12927                         if (rc < 0) {
12928                                 fprintf(stderr,
12929                                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
12930                                         progname, strerror(errno));
12931                                 goto error;
12932                         }
12933
12934                         if (i >= ARRAY_SIZE(chunks[idx].mirror_id)) {
12935                                 fprintf(stderr,
12936                                         "%s: mirror_id array is too small.\n",
12937                                         progname);
12938                                 rc = -EINVAL;
12939                                 goto error;
12940                         }
12941                         chunks[idx].mirror_id[i] = mirror_id;
12942                         i++;
12943
12944 next:
12945                         rc = llapi_layout_comp_use(layout,
12946                                                    LLAPI_LAYOUT_COMP_USE_NEXT);
12947                         if (rc < 0) {
12948                                 fprintf(stderr,
12949                                         "%s: move to the next layout component: %s.\n",
12950                                         progname, strerror(errno));
12951                                 goto error;
12952                         }
12953                 } /* loop through all components */
12954
12955                 chunks[idx].mirror_count = i;
12956
12957                 if (chunks[idx].chunk.e_end == LUSTRE_EOF)
12958                         break;
12959
12960                 idx++;
12961                 if (idx >= chunks_size) {
12962                         fprintf(stderr, "%s: chunks array is too small.\n",
12963                                 progname);
12964                         rc = -EINVAL;
12965                         goto error;
12966                 }
12967
12968                 chunks[idx].chunk.e_start = chunks[idx - 1].chunk.e_end;
12969         }
12970
12971 error:
12972         return rc < 0 ? rc : idx + 1;
12973 }
12974
12975 /**
12976  * lfs_mirror_verify_chunk() - Verify a chunk.
12977  * @fd:        File descriptor of the mirrored file.
12978  * @file_size: Size of the mirrored file.
12979  * @chunk:     A chunk and its corresponding valid mirror ids.
12980  * @verbose:   Verbose mode.
12981  *
12982  * This function verifies a @chunk contains exactly the same data
12983  * ammong the mirrors that cover it.
12984  *
12985  * If @verbose is specified, then the function will print where the
12986  * differences are if the data do not match. Otherwise, it will
12987  * just return an error in that case.
12988  *
12989  * Return: 0 on success or a negative error code on failure.
12990  */
12991 static inline
12992 int lfs_mirror_verify_chunk(int fd, size_t file_size,
12993                             struct verify_chunk *chunk, int verbose)
12994 {
12995         const size_t buflen = 4 * 1024 * 1024; /* 4M */
12996         void *buf;
12997         size_t page_size;
12998         ssize_t bytes_read;
12999         ssize_t bytes_done;
13000         size_t count;
13001         off_t pos;
13002         unsigned long crc;
13003         unsigned long crc_array[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
13004         int i;
13005         int rc = 0;
13006
13007         if (file_size == 0)
13008                 return 0;
13009
13010         page_size = sysconf(_SC_PAGESIZE);
13011         if (page_size < 0) {
13012                 rc = -errno;
13013                 return rc;
13014         }
13015
13016         rc = posix_memalign(&buf, page_size, buflen);
13017         if (rc) /* error code is returned directly */
13018                 return -rc;
13019
13020         if (verbose > 1) {
13021                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
13022                         PEXT(&chunk->chunk));
13023                 for (i = 0; i < chunk->mirror_count; i++)
13024                         fprintf(stdout, " %u", chunk->mirror_id[i]);
13025                 fprintf(stdout, "\n");
13026         }
13027
13028         bytes_done = 0;
13029         count = MIN(chunk->chunk.e_end, file_size) - chunk->chunk.e_start;
13030         pos = chunk->chunk.e_start;
13031         while (bytes_done < count) {
13032                 /* compute initial CRC-32 checksum */
13033                 crc = crc32(0L, Z_NULL, 0);
13034                 memset(crc_array, 0, sizeof(crc_array));
13035
13036                 bytes_read = 0;
13037                 for (i = 0; i < chunk->mirror_count; i++) {
13038                         bytes_read = llapi_mirror_read(fd, chunk->mirror_id[i],
13039                                                        buf, buflen, pos);
13040                         if (bytes_read < 0) {
13041                                 rc = bytes_read;
13042                                 fprintf(stderr,
13043                                         "%s: failed to read data from mirror %u: %s.\n",
13044                                         progname, chunk->mirror_id[i],
13045                                         strerror(-rc));
13046                                 goto error;
13047                         }
13048
13049                         /* compute new CRC-32 checksum */
13050                         crc_array[i] = crc32(crc, buf, bytes_read);
13051                 }
13052
13053                 if (verbose)
13054                         print_checksums(chunk, crc_array, pos, buflen);
13055
13056                 /* compare CRC-32 checksum values */
13057                 for (i = 1; i < chunk->mirror_count; i++) {
13058                         if (crc_array[i] != crc_array[0]) {
13059                                 rc = -EINVAL;
13060
13061                                 fprintf(stderr,
13062                                         "%s: chunk "DEXT" has different checksum value on mirror %u:%lx and mirror %u:%lx.\n",
13063                                         progname, PEXT(&chunk->chunk),
13064                                         chunk->mirror_id[0], crc_array[0],
13065                                         chunk->mirror_id[i], crc_array[i]);
13066                                 print_checksums(chunk, crc_array, pos, buflen);
13067                         }
13068                 }
13069
13070                 pos += bytes_read;
13071                 bytes_done += bytes_read;
13072         }
13073
13074         if (verbose > 1 && rc == 0) {
13075                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
13076                         PEXT(&chunk->chunk));
13077                 for (i = 0; i < chunk->mirror_count; i++)
13078                         fprintf(stdout, " %u", chunk->mirror_id[i]);
13079                 fprintf(stdout, " PASS\n\n");
13080         }
13081
13082 error:
13083         free(buf);
13084         return rc;
13085 }
13086
13087 /**
13088  * lfs_mirror_verify_file() - Verify a mirrored file.
13089  * @fname:      Mirrored file name.
13090  * @mirror_ids: Specified mirror ids to be verified.
13091  * @ids_nr:     Number of specified mirror ids.
13092  * @verbose:    Verbose mode.
13093  *
13094  * This function verifies that each SYNC mirror of a mirrored file
13095  * specified by @fname contains exactly the same data.
13096  *
13097  * If @mirror_ids is specified, then the function will verify the
13098  * mirrors specified by @mirror_ids contain exactly the same data.
13099  *
13100  * If @verbose is specified, then the function will print where the
13101  * differences are if the data do not match. Otherwise, it will
13102  * just return an error in that case.
13103  *
13104  * Return: 0 on success or a negative error code on failure.
13105  */
13106 static inline
13107 int lfs_mirror_verify_file(const char *fname, __u16 *mirror_ids, int ids_nr,
13108                            int verbose)
13109 {
13110         struct verify_chunk chunks_array[1024] = { };
13111         struct llapi_layout *layout = NULL;
13112         struct stat stbuf;
13113         uint32_t flr_state;
13114         int fd;
13115         int chunk_count = 0;
13116         int idx = 0;
13117         int rc = 0;
13118         int rc1 = 0;
13119         int rc2 = 0;
13120
13121         if (stat(fname, &stbuf) < 0) {
13122                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
13123                         progname, fname, strerror(errno));
13124                 rc = -errno;
13125                 goto error;
13126         }
13127
13128         if (!S_ISREG(stbuf.st_mode)) {
13129                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
13130                         progname, fname);
13131                 rc = -EINVAL;
13132                 goto error;
13133         }
13134
13135         if (stbuf.st_size == 0) {
13136                 if (verbose)
13137                         fprintf(stdout, "%s: '%s' file size is 0.\n",
13138                                 progname, fname);
13139                 rc = 0;
13140                 goto error;
13141         }
13142
13143         /* Allow mirror verify even without the key on encrypted files */
13144         fd = open(fname, O_DIRECT | O_RDONLY | O_CIPHERTEXT);
13145         if (fd < 0) {
13146                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
13147                         progname, fname, strerror(errno));
13148                 rc = -errno;
13149                 goto error;
13150         }
13151
13152         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
13153         if (rc < 0) {
13154                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
13155                         progname, fname, strerror(errno));
13156                 goto close_fd;
13157         }
13158
13159         layout = llapi_layout_get_by_fd(fd, 0);
13160         if (!layout) {
13161                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
13162                         progname, fname, strerror(errno));
13163                 rc = -errno;
13164                 llapi_lease_release(fd);
13165                 goto close_fd;
13166         }
13167
13168         rc = llapi_layout_flags_get(layout, &flr_state);
13169         if (rc < 0) {
13170                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
13171                         progname, fname, strerror(errno));
13172                 rc = -errno;
13173                 goto free_layout;
13174         }
13175
13176         flr_state &= LCM_FL_FLR_MASK;
13177         switch (flr_state) {
13178         case LCM_FL_NONE:
13179                 rc = -EINVAL;
13180                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
13181                         progname, fname, llapi_layout_flags_string(flr_state));
13182                 goto free_layout;
13183         default:
13184                 break;
13185         }
13186
13187         /* find out mirror chunks to be verified */
13188         chunk_count = lfs_mirror_prepare_chunk(layout, chunks_array,
13189                                                ARRAY_SIZE(chunks_array));
13190         if (chunk_count < 0) {
13191                 rc = chunk_count;
13192                 goto free_layout;
13193         }
13194
13195         if (ids_nr > 0)
13196                 /* filter specified mirror ids */
13197                 filter_mirror_id(chunks_array, chunk_count, mirror_ids, ids_nr);
13198
13199         if (verbose > 2)
13200                 print_chunks(fname, chunks_array, chunk_count);
13201
13202         for (idx = 0; idx < chunk_count; idx++) {
13203                 if (chunks_array[idx].chunk.e_start >= stbuf.st_size) {
13204                         if (verbose)
13205                                 fprintf(stdout,
13206                                         "%s: '%s' chunk "DEXT" exceeds file size %#llx: skipped\n",
13207                                         progname, fname,
13208                                         PEXT(&chunks_array[idx].chunk),
13209                                         (unsigned long long)stbuf.st_size);
13210                         break;
13211                 }
13212
13213                 if (chunks_array[idx].mirror_count == 0) {
13214                         fprintf(stderr,
13215                                 "%s: '%s' chunk "DEXT" is invalid in all of the mirrors: ",
13216                                 progname, fname,
13217                                 PEXT(&chunks_array[idx].chunk));
13218                         if (verbose) {
13219                                 fprintf(stderr, "skipped\n");
13220                                 continue;
13221                         }
13222                         rc = -EINVAL;
13223                         fprintf(stderr, "failed\n");
13224                         goto free_layout;
13225                 }
13226
13227                 if (chunks_array[idx].mirror_count == 1) {
13228                         if (verbose)
13229                                 fprintf(stdout,
13230                                         "%s: '%s' chunk "DEXT" is only valid in mirror %u: skipped\n",
13231                                         progname, fname,
13232                                         PEXT(&chunks_array[idx].chunk),
13233                                         chunks_array[idx].mirror_id[0]);
13234                         continue;
13235                 }
13236
13237                 rc = llapi_lease_check(fd);
13238                 if (rc != LL_LEASE_RDLCK) {
13239                         fprintf(stderr, "%s: '%s' lost lease lock.\n",
13240                                 progname, fname);
13241                         goto free_layout;
13242                 }
13243
13244                 /* verify one chunk */
13245                 rc1 = lfs_mirror_verify_chunk(fd, stbuf.st_size,
13246                                               &chunks_array[idx], verbose);
13247                 if (rc1 < 0) {
13248                         rc2 = rc1;
13249                         if (!verbose) {
13250                                 rc = rc1;
13251                                 goto free_layout;
13252                         }
13253                 }
13254         }
13255
13256         if (rc2 < 0)
13257                 rc = rc2;
13258
13259 free_layout:
13260         llapi_layout_free(layout);
13261         llapi_lease_release(fd);
13262 close_fd:
13263         close(fd);
13264 error:
13265         return rc;
13266 }
13267
13268 /**
13269  * lfs_mirror_verify() - Parse and execute lfs mirror verify command.
13270  * @argc: The count of lfs mirror verify command line arguments.
13271  * @argv: Array of strings for lfs mirror verify command line arguments.
13272  *
13273  * This function parses lfs mirror verify command and verifies the
13274  * specified mirrored file(s).
13275  *
13276  * Return: 0 on success or a negative error code on failure.
13277  */
13278 static inline int lfs_mirror_verify(int argc, char **argv)
13279 {
13280         __u16 mirror_ids[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
13281         int ids_nr = 0;
13282         int c;
13283         int verbose = 0;
13284         int rc = 0;
13285         int rc1 = 0;
13286         char cmd[PATH_MAX];
13287
13288         struct option long_opts[] = {
13289         { .val = 'h',   .name = "help",         .has_arg = no_argument },
13290         { .val = 'o',   .name = "only",         .has_arg = required_argument },
13291         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
13292         { .name = NULL } };
13293
13294         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
13295         progname = cmd;
13296         while ((c = getopt_long(argc, argv, "ho:v", long_opts, NULL)) >= 0) {
13297                 switch (c) {
13298                 case 'o':
13299                         rc = parse_mirror_ids(mirror_ids,
13300                                               ARRAY_SIZE(mirror_ids),
13301                                               optarg);
13302                         if (rc < 0) {
13303                                 fprintf(stderr,
13304                                         "%s: bad mirror ids '%s'.\n",
13305                                         progname, optarg);
13306                                 goto error;
13307                         }
13308                         ids_nr = rc;
13309                         if (ids_nr < 2) {
13310                                 fprintf(stderr,
13311                                         "%s: at least 2 mirror ids needed with '--only' option.\n",
13312                                         progname);
13313                                 rc = CMD_HELP;
13314                                 goto error;
13315                         }
13316                         break;
13317                 case 'v':
13318                         verbose++;
13319                         break;
13320                 default:
13321                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13322                                 progname, argv[optind - 1]);
13323                         fallthrough;
13324                 case 'h':
13325                         rc = CMD_HELP;
13326                         goto error;
13327                 }
13328         }
13329
13330         if (argc == optind) {
13331                 fprintf(stderr, "%s: no file name given.\n", progname);
13332                 rc = CMD_HELP;
13333                 goto error;
13334         }
13335
13336         if (ids_nr > 0 && argc > optind + 1) {
13337                 fprintf(stderr,
13338                         "%s: '--only' cannot be used upon multiple files.\n",
13339                         progname);
13340                 rc = CMD_HELP;
13341                 goto error;
13342         }
13343
13344         if (ids_nr > 0) {
13345                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
13346                 if (rc < 0)
13347                         goto error;
13348         }
13349
13350         rc = 0;
13351         for (; optind < argc; optind++) {
13352                 rc1 = lfs_mirror_verify_file(argv[optind], mirror_ids, ids_nr,
13353                                              verbose);
13354                 if (rc1 < 0)
13355                         rc = rc1;
13356         }
13357 error:
13358         return rc;
13359 }
13360
13361 /**
13362  * lfs_mirror() - Parse and execute lfs mirror commands.
13363  * @argc: The count of lfs mirror command line arguments.
13364  * @argv: Array of strings for lfs mirror command line arguments.
13365  *
13366  * This function parses lfs mirror commands and performs the
13367  * corresponding functions specified in mirror_cmdlist[].
13368  *
13369  * Return: 0 on success or an error code on failure.
13370  */
13371 static int lfs_mirror(int argc, char **argv)
13372 {
13373         char cmd[PATH_MAX];
13374         int rc = 0;
13375
13376         setlinebuf(stdout);
13377
13378         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
13379         progname = cmd;
13380         program_invocation_short_name = cmd;
13381         rc = cfs_parser(argc, argv, mirror_cmdlist);
13382
13383         return rc < 0 ? -rc : rc;
13384 }
13385
13386 static void lustre_som_swab(struct lustre_som_attrs *attrs)
13387 {
13388 #if __BYTE_ORDER == __BIG_ENDIAN
13389         __swab16s(&attrs->lsa_valid);
13390         __swab64s(&attrs->lsa_size);
13391         __swab64s(&attrs->lsa_blocks);
13392 #endif
13393 }
13394
13395 enum lfs_som_type {
13396         LFS_SOM_SIZE = 0x1,
13397         LFS_SOM_BLOCKS = 0x2,
13398         LFS_SOM_FLAGS = 0x4,
13399         LFS_SOM_ATTR_ALL = LFS_SOM_SIZE | LFS_SOM_BLOCKS |
13400                            LFS_SOM_FLAGS,
13401 };
13402
13403 static int lfs_getsom(int argc, char **argv)
13404 {
13405         const char *path;
13406         struct lustre_som_attrs *attrs;
13407         char buf[sizeof(*attrs) + 64];
13408         enum lfs_som_type type = LFS_SOM_ATTR_ALL;
13409         int rc = 0, c;
13410
13411         while ((c = getopt(argc, argv, "bfhs")) != -1) {
13412                 switch (c) {
13413                 case 'b':
13414                         type = LFS_SOM_BLOCKS;
13415                         break;
13416                 case 'f':
13417                         type = LFS_SOM_FLAGS;
13418                         break;
13419                 case 's':
13420                         type = LFS_SOM_SIZE;
13421                         break;
13422                 default:
13423                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13424                                 progname, argv[optind - 1]);
13425                         fallthrough;
13426                 case 'h':
13427                         return CMD_HELP;
13428                 }
13429         }
13430
13431         argc -= optind;
13432         argv += optind;
13433
13434         if (argc != 1) {
13435                 fprintf(stderr, "%s: %s\n",
13436                         progname, argc == 0 ? "miss file target" :
13437                         "input more than 2 files");
13438                 return CMD_HELP;
13439         }
13440
13441         path = argv[0];
13442         attrs = (void *)buf;
13443         rc = lgetxattr(path, "trusted.som", attrs, sizeof(buf));
13444         if (rc < 0) {
13445                 rc = -errno;
13446                 fprintf(stderr, "%s failed to get som xattr: %s (%d)\n",
13447                         argv[0], strerror(errno), errno);
13448                 return rc;
13449         }
13450
13451         lustre_som_swab(attrs);
13452
13453         switch (type) {
13454         case LFS_SOM_ATTR_ALL:
13455                 printf("file: %s size: %llu blocks: %llu flags: %x\n",
13456                        path, (unsigned long long)attrs->lsa_size,
13457                        (unsigned long long)attrs->lsa_blocks,
13458                        attrs->lsa_valid);
13459                 break;
13460         case LFS_SOM_SIZE:
13461                 printf("%llu\n", (unsigned long long)attrs->lsa_size);
13462                 break;
13463         case LFS_SOM_BLOCKS:
13464                 printf("%llu\n", (unsigned long long)attrs->lsa_blocks);
13465                 break;
13466         case LFS_SOM_FLAGS:
13467                 printf("%x\n", attrs->lsa_valid);
13468                 break;
13469         default:
13470                 fprintf(stderr, "%s: unknown option\n", progname);
13471                 return CMD_HELP;
13472         }
13473
13474         return 0;
13475 }
13476
13477 static int lfs_pcc_attach(int argc, char **argv)
13478 {
13479         struct option long_opts[] = {
13480         { .val = 'h',   .name = "help", .has_arg = no_argument },
13481         { .val = 'i',   .name = "id",   .has_arg = required_argument },
13482         { .val = 'r',   .name = "readonly",     .has_arg = no_argument },
13483         { .name = NULL } };
13484         int c;
13485         int rc = 0;
13486         __u32 attach_id = 0;
13487         const char *path;
13488         char *end;
13489         char fullpath[PATH_MAX];
13490         enum lu_pcc_type type = LU_PCC_READWRITE;
13491
13492         optind = 0;
13493         while ((c = getopt_long(argc, argv, "hi:r",
13494                                 long_opts, NULL)) != -1) {
13495                 switch (c) {
13496                 case 'i':
13497                         errno = 0;
13498                         attach_id = strtoul(optarg, &end, 0);
13499                         if (errno != 0 || *end != '\0' ||
13500                             attach_id == 0 || attach_id > UINT32_MAX) {
13501                                 fprintf(stderr,
13502                                         "error: %s: bad archive ID '%s'\n",
13503                                         progname, optarg);
13504                                 return CMD_HELP;
13505                         }
13506                         break;
13507                 case 'r':
13508                         type = LU_PCC_READONLY;
13509                         break;
13510                 case '?':
13511                         return CMD_HELP;
13512                 default:
13513                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13514                                 progname, argv[optind - 1]);
13515                         fallthrough;
13516                 case 'h':
13517                         return CMD_HELP;
13518                 }
13519         }
13520
13521         if (attach_id == 0) {
13522                 fprintf(stderr, "%s: must specify attach ID\n", argv[0]);
13523                 return CMD_HELP;
13524         }
13525
13526         if (argc <= optind) {
13527                 fprintf(stderr, "%s: must specify one or more file names\n",
13528                         argv[0]);
13529                 return CMD_HELP;
13530         }
13531
13532         while (optind < argc) {
13533                 int rc2;
13534
13535                 path = argv[optind++];
13536                 if (!realpath(path, fullpath)) {
13537                         fprintf(stderr, "%s: could not find path '%s': %s\n",
13538                                 argv[0], path, strerror(errno));
13539                         if (rc == 0)
13540                                 rc = -EINVAL;
13541                         continue;
13542                 }
13543
13544                 rc2 = llapi_pcc_attach(fullpath, attach_id, type);
13545                 if (rc2 < 0) {
13546                         fprintf(stderr,
13547                                 "%s: cannot attach '%s' to PCC with attach ID '%u': %s\n",
13548                                 argv[0], path, attach_id, strerror(-rc2));
13549                         if (rc == 0)
13550                                 rc = rc2;
13551                 }
13552         }
13553         return rc;
13554 }
13555
13556 static int lfs_pcc_attach_fid(int argc, char **argv)
13557 {
13558         struct option long_opts[] = {
13559         { .val = 'h',   .name = "help",         .has_arg = no_argument },
13560         { .val = 'i',   .name = "id",           .has_arg = required_argument },
13561         { .val = 'r',   .name = "readonly",     .has_arg = no_argument },
13562         { .val = 'm',   .name = "mnt",          .has_arg = required_argument },
13563         { .name = NULL } };
13564         int c;
13565         int rc = 0;
13566         __u32 attach_id = 0;
13567         char *end;
13568         const char *mntpath = NULL;
13569         const char *fidstr;
13570         enum lu_pcc_type type = LU_PCC_READWRITE;
13571
13572         optind = 0;
13573         while ((c = getopt_long(argc, argv, "hi:m:r",
13574                                 long_opts, NULL)) != -1) {
13575                 switch (c) {
13576                 case 'i':
13577                         errno = 0;
13578                         attach_id = strtoul(optarg, &end, 0);
13579                         if (errno != 0 || *end != '\0' ||
13580                             attach_id > UINT32_MAX) {
13581                                 fprintf(stderr,
13582                                         "error: %s: bad attach ID '%s'\n",
13583                                         argv[0], optarg);
13584                                 return CMD_HELP;
13585                         }
13586                         break;
13587                 case 'r':
13588                         type = LU_PCC_READONLY;
13589                         break;
13590                 case 'm':
13591                         mntpath = optarg;
13592                         break;
13593                 default:
13594                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13595                                 progname, argv[optind - 1]);
13596                         fallthrough;
13597                 case 'h':
13598                         return CMD_HELP;
13599                 }
13600         }
13601
13602         if (attach_id == 0) {
13603                 fprintf(stderr, "%s: must specify an archive ID\n", argv[0]);
13604                 return CMD_HELP;
13605         }
13606
13607         if (!mntpath) {
13608                 fprintf(stderr, "%s: must specify Lustre mount point\n",
13609                         argv[0]);
13610                 return CMD_HELP;
13611         }
13612
13613         if (argc <= optind) {
13614                 fprintf(stderr, "%s: must specify one or more fids\n", argv[0]);
13615                 return CMD_HELP;
13616         }
13617
13618         while (optind < argc) {
13619                 int rc2;
13620
13621                 fidstr = argv[optind++];
13622
13623                 rc2 = llapi_pcc_attach_fid_str(mntpath, fidstr,
13624                                                attach_id, type);
13625                 if (rc2 < 0) {
13626                         fprintf(stderr,
13627                                 "%s: cannot attach '%s' on '%s' to PCC with attach ID '%u': %s\n",
13628                                 argv[0], fidstr, mntpath, attach_id,
13629                                 strerror(rc2));
13630                 }
13631                 if (rc == 0 && rc2 < 0)
13632                         rc = rc2;
13633         }
13634         return rc;
13635 }
13636
13637 static int lfs_pcc_detach(int argc, char **argv)
13638 {
13639         struct option long_opts[] = {
13640         { .val = 'h',   .name = "help", .has_arg = no_argument },
13641         { .val = 'k',   .name = "keep", .has_arg = no_argument },
13642         { .name = NULL } };
13643         int c;
13644         int rc = 0;
13645         const char *path;
13646         char fullpath[PATH_MAX];
13647         __u32 detach_opt = PCC_DETACH_OPT_UNCACHE;
13648
13649         optind = 0;
13650         while ((c = getopt_long(argc, argv, "hk",
13651                                 long_opts, NULL)) != -1) {
13652                 switch (c) {
13653                 case 'k':
13654                         detach_opt = PCC_DETACH_OPT_NONE;
13655                         break;
13656                 default:
13657                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13658                                 progname, argv[optind - 1]);
13659                         fallthrough;
13660                 case 'h':
13661                         return CMD_HELP;
13662                 }
13663         }
13664
13665         while (optind < argc) {
13666                 int rc2;
13667
13668                 path = argv[optind++];
13669                 if (!realpath(path, fullpath)) {
13670                         fprintf(stderr, "%s: could not find path '%s': %s\n",
13671                                 argv[0], path, strerror(errno));
13672                         if (rc == 0)
13673                                 rc = -EINVAL;
13674                         continue;
13675                 }
13676
13677                 rc2 = llapi_pcc_detach_file(fullpath, detach_opt);
13678                 if (rc2 < 0) {
13679                         rc2 = -errno;
13680                         fprintf(stderr,
13681                                 "%s: cannot detach '%s' from PCC: %s\n",
13682                                 argv[0], path, strerror(errno));
13683                         if (rc == 0)
13684                                 rc = rc2;
13685                 }
13686         }
13687         return rc;
13688 }
13689
13690 static int lfs_pcc_detach_fid(int argc, char **argv)
13691 {
13692         struct option long_opts[] = {
13693         { .val = 'h',   .name = "help", .has_arg = no_argument },
13694         { .val = 'k',   .name = "keep", .has_arg = no_argument },
13695         { .name = NULL } };
13696         int c;
13697         int rc = 0;
13698         const char *fid;
13699         const char *mntpath;
13700         __u32 detach_opt = PCC_DETACH_OPT_UNCACHE;
13701
13702         optind = 0;
13703         while ((c = getopt_long(argc, argv, "hk",
13704                                 long_opts, NULL)) != -1) {
13705                 switch (c) {
13706                 case 'k':
13707                         detach_opt = PCC_DETACH_OPT_NONE;
13708                         break;
13709                 default:
13710                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13711                                 progname, argv[optind - 1]);
13712                         fallthrough;
13713                 case 'h':
13714                         return CMD_HELP;
13715                 }
13716         }
13717
13718         mntpath = argv[optind++];
13719
13720         while (optind < argc) {
13721                 int rc2;
13722
13723                 fid = argv[optind++];
13724
13725                 rc2 = llapi_pcc_detach_fid_str(mntpath, fid, detach_opt);
13726                 if (rc2 < 0) {
13727                         fprintf(stderr,
13728                                 "%s: cannot detach '%s' on '%s' from PCC: %s\n",
13729                                 argv[0], fid, mntpath, strerror(-rc2));
13730                         if (rc == 0)
13731                                 rc = rc2;
13732                 }
13733         }
13734         return rc;
13735 }
13736
13737 static int lfs_pcc_state(int argc, char **argv)
13738 {
13739         int rc = 0;
13740         const char *path;
13741         char fullpath[PATH_MAX];
13742         struct lu_pcc_state state;
13743
13744         optind = 1;
13745
13746         if (argc <= 1) {
13747                 fprintf(stderr, "%s: must specify one or more file names\n",
13748                         progname);
13749                 return CMD_HELP;
13750         }
13751
13752         while (optind < argc) {
13753                 int rc2;
13754
13755                 path = argv[optind++];
13756                 if (!realpath(path, fullpath)) {
13757                         fprintf(stderr, "%s: could not find path '%s': %s\n",
13758                                 argv[0], path, strerror(errno));
13759                         if (rc == 0)
13760                                 rc = -EINVAL;
13761                         continue;
13762                 }
13763
13764                 rc2 = llapi_pcc_state_get(fullpath, &state);
13765                 if (rc2 < 0) {
13766                         if (rc == 0)
13767                                 rc = rc2;
13768                         fprintf(stderr,
13769                                 "%s: cannot get PCC state of '%s': %s\n",
13770                                 argv[0], path, strerror(-rc2));
13771                         continue;
13772                 }
13773
13774                 printf("file: %s", path);
13775                 printf(", type: %s", pcc_type2string(state.pccs_type));
13776                 if (state.pccs_type == LU_PCC_NONE &&
13777                     state.pccs_open_count == 0) {
13778                         printf("\n");
13779                         continue;
13780                 }
13781
13782                 printf(", PCC file: %s", state.pccs_path);
13783                 printf(", user number: %u", state.pccs_open_count);
13784                 printf(", flags: %x", state.pccs_flags);
13785                 printf("\n");
13786         }
13787         return rc;
13788 }
13789
13790 /**
13791  * lfs_pcc() - Parse and execute lfs pcc commands.
13792  * @argc: The count of lfs pcc command line arguments.
13793  * @argv: Array of strings for lfs pcc command line arguments.
13794  *
13795  * This function parses lfs pcc commands and performs the
13796  * corresponding functions specified in pcc_cmdlist[].
13797  *
13798  * Return: 0 on success or an error code on failure.
13799  */
13800 static int lfs_pcc(int argc, char **argv)
13801 {
13802         char cmd[PATH_MAX];
13803         int rc = 0;
13804
13805         setlinebuf(stdout);
13806
13807         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
13808         progname = cmd;
13809         program_invocation_short_name = cmd;
13810         rc = cfs_parser(argc, argv, pcc_cmdlist);
13811
13812         return rc < 0 ? -rc : rc;
13813 }
13814
13815 int main(int argc, char **argv)
13816 {
13817         int rc;
13818
13819         /* Ensure that liblustreapi constructor has run */
13820         if (!llapi_liblustreapi_initialized())
13821                 fprintf(stderr, "liblustreapi was not properly initialized\n");
13822
13823         setlinebuf(stdout);
13824         opterr = 0;
13825
13826         progname = program_invocation_short_name; /* Used in error messages */
13827         llapi_set_command_name(argv[1]);
13828         rc = cfs_parser(argc, argv, cmdlist);
13829         llapi_clear_command_name();
13830
13831         return rc < 0 ? -rc : rc;
13832 }