Whamcloud - gitweb
LU-12998 mds: add no_create parameter to stop creates
[fs/lustre-release.git] / lustre / utils / lfs.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  *
31  * lustre/utils/lfs.c
32  *
33  * Author: Peter J. Braam <braam@clusterfs.com>
34  * Author: Phil Schwan <phil@clusterfs.com>
35  * Author: Robert Read <rread@clusterfs.com>
36  */
37
38 /* for O_DIRECTORY */
39 #ifndef _GNU_SOURCE
40 #define _GNU_SOURCE
41 #endif
42
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <inttypes.h>
46 #include <getopt.h>
47 #include <string.h>
48 #include <mntent.h>
49 #include <unistd.h>
50 #include <errno.h>
51 #include <err.h>
52 #include <pwd.h>
53 #include <grp.h>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
56 #include <sys/time.h>
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <sys/param.h>
60 #include <sys/xattr.h>
61 #include <fcntl.h>
62 #include <dirent.h>
63 #include <time.h>
64 #include <ctype.h>
65 #include <zlib.h>
66 #include <libgen.h>
67 #include <asm/byteorder.h>
68 #include "lfs_project.h"
69
70 #include <libcfs/util/string.h>
71 #include <libcfs/util/ioctl.h>
72 #include <libcfs/util/parser.h>
73 #include <libcfs/util/string.h>
74 #include <lustre/lustreapi.h>
75 #include <linux/lustre/lustre_ver.h>
76 #include <linux/lustre/lustre_param.h>
77 #include <linux/lnet/nidstr.h>
78 #include <lnetconfig/cyaml.h>
79 #include "lstddef.h"
80 #include <uapi/linux/lustre/lustre_idl.h>
81
82 #ifndef NSEC_PER_SEC
83 # define NSEC_PER_SEC 1000000000UL
84 #endif
85 #define ONE_MB 0x100000
86
87 /* all functions */
88 static int lfs_find(int argc, char **argv);
89 static int lfs_getstripe(int argc, char **argv);
90 static int lfs_getdirstripe(int argc, char **argv);
91 static int lfs_setdirstripe(int argc, char **argv);
92 static int lfs_rmentry(int argc, char **argv);
93 static int lfs_unlink_foreign(int argc, char **argv);
94 static int lfs_osts(int argc, char **argv);
95 static int lfs_mdts(int argc, char **argv);
96 static int lfs_df(int argc, char **argv);
97 static int lfs_getname(int argc, char **argv);
98 static int lfs_check(int argc, char **argv);
99 #ifdef HAVE_SYS_QUOTA_H
100 static int lfs_setquota(int argc, char **argv);
101 static int lfs_quota(int argc, char **argv);
102 static int lfs_project(int argc, char **argv);
103 #endif
104 static int lfs_flushctx(int argc, char **argv);
105 static int lfs_poollist(int argc, char **argv);
106 static int lfs_changelog(int argc, char **argv);
107 static int lfs_changelog_clear(int argc, char **argv);
108 static int lfs_fid2path(int argc, char **argv);
109 static int lfs_path2fid(int argc, char **argv);
110 static int lfs_rmfid(int argc, char **argv);
111 static int lfs_data_version(int argc, char **argv);
112 static int lfs_hsm_state(int argc, char **argv);
113 static int lfs_hsm_set(int argc, char **argv);
114 static int lfs_hsm_clear(int argc, char **argv);
115 static int lfs_hsm_action(int argc, char **argv);
116 static int lfs_hsm_archive(int argc, char **argv);
117 static int lfs_hsm_restore(int argc, char **argv);
118 static int lfs_hsm_release(int argc, char **argv);
119 static int lfs_hsm_remove(int argc, char **argv);
120 static int lfs_hsm_cancel(int argc, char **argv);
121 static int lfs_swap_layouts(int argc, char **argv);
122 static int lfs_mv(int argc, char **argv);
123 static int lfs_ladvise(int argc, char **argv);
124 static int lfs_getsom(int argc, char **argv);
125 static int lfs_heat_get(int argc, char **argv);
126 static int lfs_heat_set(int argc, char **argv);
127 static int lfs_mirror(int argc, char **argv);
128 static inline int lfs_mirror_resync(int argc, char **argv);
129 static inline int lfs_mirror_verify(int argc, char **argv);
130 static inline int lfs_mirror_read(int argc, char **argv);
131 static inline int lfs_mirror_write(int argc, char **argv);
132 static inline int lfs_mirror_copy(int argc, char **argv);
133 static int lfs_pcc_attach(int argc, char **argv);
134 static int lfs_pcc_attach_fid(int argc, char **argv);
135 static int lfs_pcc_detach(int argc, char **argv);
136 static int lfs_pcc_detach_fid(int argc, char **argv);
137 static int lfs_pcc_state(int argc, char **argv);
138 static int lfs_pcc(int argc, char **argv);
139
140 static int lfs_migrate_to_dom(int fd_src, int fd_dst, char *name,
141                               __u64 migration_flags,
142                               unsigned long long bandwidth_bytes_sec,
143                               long stats_interval_sec);
144
145 struct pool_to_id_cbdata {
146         const char *pool;
147         __u32 id;
148 };
149
150 static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata);
151 static int find_mirror_id_by_pool(struct llapi_layout *layout, void *cbdata);
152
153 enum setstripe_origin {
154         SO_SETSTRIPE,
155         SO_MIGRATE,
156         SO_MIGRATE_MDT,
157         SO_MIRROR_CREATE,
158         SO_MIRROR_EXTEND,
159         SO_MIRROR_SPLIT,
160         SO_MIRROR_DELETE,
161 };
162
163 static int lfs_setstripe_internal(int argc, char **argv,
164                                   enum setstripe_origin opc);
165
166 static inline int lfs_setstripe(int argc, char **argv)
167 {
168         return lfs_setstripe_internal(argc, argv, SO_SETSTRIPE);
169 }
170
171 static inline int lfs_setstripe_migrate(int argc, char **argv)
172 {
173         return lfs_setstripe_internal(argc, argv, SO_MIGRATE);
174 }
175
176 static inline int lfs_mirror_create(int argc, char **argv)
177 {
178         return lfs_setstripe_internal(argc, argv, SO_MIRROR_CREATE);
179 }
180
181 static inline int lfs_mirror_extend(int argc, char **argv)
182 {
183         return lfs_setstripe_internal(argc, argv, SO_MIRROR_EXTEND);
184 }
185
186 static inline int lfs_mirror_split(int argc, char **argv)
187 {
188         return lfs_setstripe_internal(argc, argv, SO_MIRROR_SPLIT);
189 }
190
191 static inline int lfs_mirror_delete(int argc, char **argv)
192 {
193         return lfs_setstripe_internal(argc, argv, SO_MIRROR_DELETE);
194 }
195
196 /* Setstripe and migrate share mostly the same parameters */
197 #define SSM_CMD_COMMON(cmd) \
198         "usage: "cmd" [--component-end|-E COMP_END]\n"                  \
199         "                 [--copy=LUSTRE_SRC]\n"                        \
200         "                 [--extension-size|--ext-size|-z SIZE]\n"      \
201         "                 [--help|-h] [--layout|-L PATTERN]\n"          \
202         "                 [--layout|-L PATTERN]\n"                      \
203         "                 [--mirror-count|-N[MIRROR_COUNT]]\n"          \
204         "                 [--ost|-o OST_INDICES]\n"                     \
205         "                 [--overstripe-count|-C STRIPE_COUNT]\n"       \
206         "                 [--pool|-p POOL_NAME]\n"                      \
207         "                 [--stripe-count|-c STRIPE_COUNT]\n"           \
208         "                 [--stripe-index|-i START_OST_IDX]\n"          \
209         "                 [--stripe-size|-S STRIPE_SIZE]\n"             \
210         "                 [--yaml|-y YAML_TEMPLATE_FILE]\n"
211
212 #define MIRROR_EXTEND_USAGE                                             \
213         "                 {--mirror-count|-N[MIRROR_COUNT]}\n"          \
214         "                 [SETSTRIPE_OPTIONS|-f|--file VICTIM_FILE]\n"  \
215         "                 [--no-verify]\n"
216
217 #define SETSTRIPE_USAGE                                                 \
218         SSM_CMD_COMMON("setstripe")                                     \
219         MIRROR_EXTEND_USAGE                                             \
220         "                 DIRECTORY|FILENAME\n"
221
222 #define MIGRATE_USAGE                                                   \
223         SSM_CMD_COMMON("migrate  ")                                     \
224         "                 [--block|-b] [--non-block|-n]\n"              \
225         "                 [--non-direct|-D] [--verbose|-v]\n"           \
226         "                 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         "               [--default|-D] [--mode|-o mode]\n"              \
233         "               [--max-inherit|-X max_inherit]\n"               \
234         "               [--max-inherit-rr max_inherit_rr] <dir>\n"      \
235         "To create dir with a foreign (free format) layout :\n"         \
236         "setdirstripe|mkdir --foreign[=FOREIGN_TYPE] -x|-xattr STRING " \
237         "               [--mode|-o MODE] [--flags HEX] DIRECTORY\n"
238
239 /**
240  * command_t mirror_cmdlist - lfs mirror commands.
241  */
242 command_t mirror_cmdlist[] = {
243         { .pc_name = "create", .pc_func = lfs_mirror_create,
244           .pc_help = "Create a mirrored file.\n"
245                 "usage: lfs mirror create --mirror-count|-N[MIRROR_COUNT]\n"
246                 "           [SETSTRIPE_OPTIONS] ... FILENAME|DIRECTORY ...\n" },
247         { .pc_name = "delete", .pc_func = lfs_mirror_delete,
248           .pc_help = "Delete a mirror from a file.\n"
249         "usage: lfs mirror delete {--mirror-id <mirror_id> |\n"
250         "\t               --component-id|--comp-id|-I COMP_ID |\n"
251         "\t               -p <pool>} MIRRORED_FILE ...\n"
252         },
253         { .pc_name = "extend", .pc_func = lfs_mirror_extend,
254           .pc_help = "Extend a mirrored file.\n"
255                 "usage: lfs mirror extend "
256                 "{--mirror-count|-N[MIRROR_COUNT]} [--no-verify]|\n"
257         "\t\t--stats|--stats-interval=<sec>|\n"
258         "\t\t--W <bandwidth>|--bandwidth-limit=<bandwidth>\n"
259         "\t\t[SETSTRIPE_OPTIONS|-f VICTIM_FILE] ... FILENAME ...\n" },
260         { .pc_name = "split", .pc_func = lfs_mirror_split,
261           .pc_help = "Split a mirrored file.\n"
262         "usage: lfs mirror split {--mirror-id MIRROR_ID |\n"
263         "\t             --component-id|-I COMP_ID|-p POOL} [--destroy|-d]\n"
264         "\t             [-f NEW_FILE] MIRRORED_FILE ...\n" },
265         { .pc_name = "read", .pc_func = lfs_mirror_read,
266           .pc_help = "Read the content of a specified mirror of a file.\n"
267                 "usage: lfs mirror read {--mirror-id|-N MIRROR_ID}\n"
268                 "\t\t[--outfile|-o <output_file>] <mirrored_file>\n" },
269         { .pc_name = "write", .pc_func = lfs_mirror_write,
270           .pc_help = "Write to a specified mirror of a file.\n"
271                 "usage: lfs mirror write {--mirror-id|-N MIRROR_ID}\n"
272                 "\t\t[--inputfile|-i <input_file>] <mirrored_file>\n" },
273         { .pc_name = "copy", .pc_func = lfs_mirror_copy,
274           .pc_help = "Copy a specified mirror to other mirror(s) of a file.\n"
275                 "usage: lfs mirror copy {--read-mirror|-i MIRROR_ID0}\n"
276                 "\t\t{--write-mirror|-o MIRROR_ID1[,...]} <mirrored_file>\n" },
277         { .pc_name = "resync", .pc_func = lfs_mirror_resync,
278           .pc_help = "Resynchronizes out-of-sync mirrored file(s).\n"
279                 "usage: lfs mirror resync [--only MIRROR_ID[,...]>]|\n"
280                 "\t\t--stats|--stats-interval=<sec>|\n"
281                 "\t\t--W <bandwidth>|--bandwidth-limit=<bandwidth>\n"
282                 "\t\t<mirrored_file> [<mirrored_file2>...]\n" },
283         { .pc_name = "verify", .pc_func = lfs_mirror_verify,
284           .pc_help = "Verify mirrored file(s).\n"
285                 "usage: lfs mirror verify [--only MIRROR_ID[,...]]\n"
286                 "\t\t[--verbose|-v] <mirrored_file> [<mirrored_file2> ...]\n" },
287         { .pc_help = NULL }
288 };
289
290 /**
291  * command_t pcc_cmdlist - lfs pcc commands.
292  */
293 command_t pcc_cmdlist[] = {
294         { .pc_name = "attach", .pc_func = lfs_pcc_attach,
295           .pc_help = "Attach given files to the Persistent Client Cache.\n"
296                 "usage: lfs pcc attach <--id|-i NUM> <file> ...\n"
297                 "\t-i: archive id for RW-PCC\n" },
298         { .pc_name = "attach_fid", .pc_func = lfs_pcc_attach_fid,
299           .pc_help = "Attach given files into PCC by FID(s).\n"
300                 "usage: lfs pcc attach_id {--id|-i NUM} {--mnt|-m MOUNTPOINT} FID ...\n"
301                 "\t-i: archive id for RW-PCC\n"
302                 "\t-m: Lustre mount point\n" },
303         { .pc_name = "state", .pc_func = lfs_pcc_state,
304           .pc_help = "Display the PCC state for given files.\n"
305                 "usage: lfs pcc state <file> ...\n" },
306         { .pc_name = "detach", .pc_func = lfs_pcc_detach,
307           .pc_help = "Detach given files from the Persistent Client Cache.\n"
308                 "usage: lfs pcc detach <file> ...\n" },
309         { .pc_name = "detach_fid", .pc_func = lfs_pcc_detach_fid,
310           .pc_help = "Detach given files from PCC by FID(s).\n"
311                 "usage: lfs pcc detach_fid <mntpath> <fid>...\n" },
312         { .pc_help = NULL }
313 };
314
315 /* all available commands */
316 command_t cmdlist[] = {
317         {"setstripe", lfs_setstripe, 0,
318          "To create a file with specified striping/composite layout, or\n"
319          "create/replace the default layout on an existing directory:\n"
320          SSM_CMD_COMMON("setstripe")
321          "                 [--mode MODE]\n"
322          "                 <directory|filename>\n"
323          " or\n"
324          "To add component(s) to an existing composite file:\n"
325          SSM_CMD_COMMON("setstripe --component-add")
326          "To totally delete the default striping from an existing directory:\n"
327          "usage: setstripe [--delete|-d] <directory>\n"
328          " or\n"
329          "To create a mirrored file or set s default mirror layout on a directory:\n"
330          "usage: setstripe {--mirror-count|-N}[MIRROR_COUNT] [SETSTRIPE_OPTIONS] <directory|filename>\n"
331          " or\n"
332          "To delete the last component(s) from an existing composite file\n"
333          "(note that this will also delete any data in those components):\n"
334          "usage: setstripe --component-del [--component-id|-I COMP_ID]\n"
335          "                               [--component-flags|-F COMP_FLAGS]\n"
336          "                               <filename>\n"
337          "\tCOMP_ID:     Unique component ID to delete\n"
338          "\tCOMP_FLAGS:  'init' indicating all instantiated components\n"
339          "\t             '^init' indicating all uninstantiated components\n"
340          "\t-I and -F cannot be specified at the same time\n"
341          " or\n"
342          "To set or clear flags on a specific component\n"
343          "(note that this command can only be applied to mirrored files:\n"
344          "usage: setstripe --comp-set {-I COMP_ID|--comp-flags=COMP_FLAGS}\n"
345          "                            <filename>\n"
346          " or\n"
347          "To create a file with a foreign (free format) layout:\n"
348          "usage: setstripe --foreign[=FOREIGN_TYPE]\n"
349          "                 --xattr|-x LAYOUT_STRING [--flags HEX]\n"
350          "                 [--mode MODE] <filename>\n"},
351         {"getstripe", lfs_getstripe, 0,
352          "To list the layout pattern for a given file or files in a\n"
353          "directory or recursively for all files in a directory tree.\n"
354          "usage: getstripe [--ost|-O UUID] [--quiet|-q] [--verbose|-v]\n"
355          "                 [--stripe-count|-c] [--stripe-index|-i] [--fid|-F]\n"
356          "                 [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
357          "                 [--mdt-index|-m] [--recursive|-r] [--raw|-R]\n"
358          "                 [--layout|-L] [--generation|-g] [--yaml|-y]\n"
359          "                 [--help|-h] [--hex-idx]\n"
360          "                 [--component-id|-I[=COMP_ID]]\n"
361          "                 [--component-flags[=COMP_FLAGS]]\n"
362          "                 [--component-count]\n"
363          "                 [--extension-size|--ext-size|-z]\n"
364          "                 [--component-start[=[+-]COMP_START]]\n"
365          "                 [--component-end[=[+-]COMP_END]|-E[[+-]comp_end]]\n"
366          "                 [[!] --mirror-index=[+-]INDEX |\n"
367          "                 [!] --mirror-id=[+-]MIRROR_ID] [--mirror-count|-N]\n"
368          "                 [--no-follow]\n"
369          "                 <directory|filename> ..."},
370         {"setdirstripe", lfs_setdirstripe, 0,
371          "Create striped directory on specified MDT, same as mkdir.\n"
372          "May be restricted to root or group users, depending on settings.\n"
373          "usage: setdirstripe [OPTION] <directory>\n"
374          SETDIRSTRIPE_USAGE},
375         {"getdirstripe", lfs_getdirstripe, 0,
376          "To list the layout pattern info for a given directory\n"
377          "or recursively for all directories in a directory tree.\n"
378          "usage: getdirstripe [--mdt-count|-c] [--mdt-index|-m|-i]\n"
379          "                    [--help|-h] [--hex-idx] [--mdt-hash|-H]\n"
380          "                    [--obd|-O UUID] [--recursive|-r] [--raw|-R]\n"
381          "                    [--yaml|-y] [--verbose|-v] [--default|-D]\n"
382          "                    [--max-inherit|-X]\n"
383          "                    [--max-inherit-rr] <dir> ..."},
384         {"mkdir", lfs_setdirstripe, 0,
385          "Create striped directory on specified MDT, same as setdirstripe.\n"
386          "usage: mkdir [OPTION] <directory>\n"
387          SETDIRSTRIPE_USAGE},
388         {"rm_entry", lfs_rmentry, 0,
389          "To remove the name entry of the remote directory. Note: This\n"
390          "command will only delete the name entry, i.e. the remote directory\n"
391          "will become inaccessable after this command. This can only be done\n"
392          "by the administrator\n"
393          "usage: rm_entry <dir>\n"},
394         {"rmentry", lfs_rmentry, 0, "remove a dir entry, same as 'rm_entry'\n"},
395         {"unlink_foreign", lfs_unlink_foreign, 0,
396          "To remove the foreign file/dir.\n"
397          "Note: This is for files/dirs prevented to be removed using\n"
398          "unlink/rmdir, but works also for regular ones\n"
399          "usage: unlink_foreign <foreign_dir/file> [<foreign_dir/file> ...]\n"},
400         {"pool_list", lfs_poollist, 0,
401          "List pools or pool OSTs\n"
402          "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
403         {"find", lfs_find, 0,
404          "find files matching given attributes recursively in directory tree.\n"
405          "usage: find <directory|filename> ...\n"
406          "     [[!] --atime|-A [+-]N[smhdwy]] [[!] --btime|-B [+-]N[smhdwy]]\n"
407          "     [[!] --ctime|-C [+-]N[smhdwy]] [[!] --mtime|-M [+-]N[smhdwy]]\n"
408          "     [[!] --attrs=[^]ATTR[,...]]\n"
409          "     [[!] --blocks|-b N] [[!] --component-count [+-]<comp_cnt>]\n"
410          "     [[!] --component-start [+-]N[kMGTPE]]\n"
411          "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
412          "     [[!] --component-flags {init,stale,prefer,prefrd,prefwr,offline,nosync,extension}]\n"
413          "     [[!] --extension-size|--ext-size|-z [+-]N[kMGT]]\n"
414          "     [[!] --foreign[=<foreign_type>]]\n"
415          "     [[!] --gid|-g|--group|-G <gid>|<gname>] [--help|-h]\n"
416          "     [[!] --layout|-L released,raid0,mdt] [--lazy|-l] [[!] --links [+-]n]\n"
417          "     [--maxdepth|-D N] [[!] --mdt-count|-T [+-]<stripes>]\n"
418          "     [[!] --mdt-hash|-H <[^][blm],[^]fnv_1a_64,all_char,crush,...>\n"
419          "     [[!] --mdt-index|--mdt|-m <uuid|index,...>]\n"
420          "     [[!] --mirror-count|-N [+-]<n>]\n"
421          "     [[!] --mirror-state <[^]state>]\n"
422          "     [[!] --name|-n <pattern>] [[!] --newer[XY] <reference>]\n"
423          "     [[!] --ost|-O <uuid|index,...>] [[!] --perm [/-]mode]\n"
424          "     [[!] --pool <pool>] [--print|-P] [--print0|-0] [--printf <format>]\n"
425          "     [[!] --projid <projid>] [[!] --size|-s [+-]N[bkMGTPE]]\n"
426          "     [[!] --stripe-count|-c [+-]<stripes>]\n"
427          "     [[!] --stripe-index|-i <index,...>]\n"
428          "     [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
429          "     [[!] --uid|-u|--user|-U <uid>|<uname>]\n"
430          "\t !: used before an option indicates 'NOT' requested attribute\n"
431          "\t -: used before a value indicates less than requested value\n"
432          "\t +: used before a value indicates more than requested value\n"
433          "\t ^: used before a flag indicates to exclude it\n"},
434         {"check", lfs_check, 0,
435          "Display the status of MGTs, MDTs or OSTs (as specified in the command)\n"
436          "or all the servers (MGTs, MDTs and OSTs) [for specified path only].\n"
437          "usage: check {mgts|osts|mdts|all} [path]"},
438         {"osts", lfs_osts, 0, "list OSTs connected to client "
439          "[for specified path only]\n" "usage: osts [path]"},
440         {"mdts", lfs_mdts, 0, "list MDTs connected to client "
441          "[for specified path only]\n" "usage: mdts [path]"},
442         {"df", lfs_df, 0,
443          "report filesystem disk space usage or inodes usage "
444          "of each MDS and all OSDs or a batch belonging to a specific pool.\n"
445          "Usage: df [--inodes|-i] [--human-readable|-h] [--lazy|-l]\n"
446          "          [--pool|-p <fsname>[.<pool>]] [path]"},
447         {"getname", lfs_getname, 0,
448          "list instances and specified mount points [for specified path only]\n"
449          "Usage: getname [--help|-h] [--instance|-i] [--fsname|-n] [path ...]"},
450 #ifdef HAVE_SYS_QUOTA_H
451         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
452          "usage: setquota [-t][-D] {-u|-U|-g|-G|-p|-P} {-b|-B|-i|-I LIMIT} [--pool POOL] FILESYSTEM\n"
453          "       setquota {-u|-g|-p} --delete FILESYSTEM\n"},
454         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
455          "usage: quota [-q] [-v] [-h] [-o OBD_UUID|-i MDT_IDX|-I OST_IDX]\n"
456          "             [{-u|-g|-p} UNAME|UID|GNAME|GID|PROJID]\n"
457          "             [--pool <OST pool name>] <filesystem>\n"
458          "       quota -t <-u|-g|-p> [--pool <OST pool name>] <filesystem>\n"
459          "       quota [-q] [-v] [h] {-U|-G|-P} [--pool <OST pool name>] <filesystem>"},
460         {"project", lfs_project, 0,
461          "Change or list project attribute for specified file or directory.\n"
462          "usage: project [-d|-r] <file|directory...>\n"
463          "         list project ID and flags on file(s) or directories\n"
464          "       project [-p id] [-s] [-r] <file|directory...>\n"
465          "         set project ID and/or inherit flag for specified file(s) or directories\n"
466          "       project -c [-d|-r [-p id] [-0]] <file|directory...>\n"
467          "         check project ID and flags on file(s) or directories, print outliers\n"
468          "       project -C [-d|-r] [-k] <file|directory...>\n"
469          "         clear the project inherit flag and ID on the file or directory\n"
470         },
471 #endif
472         {"flushctx", lfs_flushctx, 0,
473          "Flush security context for current user.\n"
474          "usage: flushctx [-k] [-r] [mountpoint...]"},
475         {"changelog", lfs_changelog, 0,
476          "Show the metadata changes on an MDT."
477          "\nusage: changelog <mdtname> [startrec [endrec]]"},
478         {"changelog_clear", lfs_changelog_clear, 0,
479          "Indicate that old changelog records up to <endrec> are no longer of "
480          "interest to consumer <id>, allowing the system to free up space.\n"
481          "An <endrec> of 0 means all records.\n"
482          "usage: changelog_clear <mdtname> <id> <endrec>"},
483         {"fid2path", lfs_fid2path, 0,
484          "Resolve the full path(s) for given FID(s). For a specific hardlink "
485          "specify link number <linkno>.\n"
486          "usage: fid2path [--print0|-0] [--print-fid|-f] [--print-link|-c] "
487          "[--link|-l <linkno>] [--name|-n] <fsname|root> <fid>..."},
488         {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
489          "usage: path2fid [--parents] <path> ..."},
490         {"rmfid", lfs_rmfid, 0, "Remove file(s) by FID(s)\n"
491          "usage: rmfid <fsname|rootpath> <fid> ..."},
492         {"data_version", lfs_data_version, 0, "Display file data version for "
493          "a given path.\n" "usage: data_version [-n|-r|-w] <path>"},
494         {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
495          "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
496         {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
497          "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
498          "[--archived] [--lost] [--archive-id NUM] <file> ..."},
499         {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
500          "files.\n"
501          "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
502          "[--archived] [--lost] <file> ..."},
503         {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
504          "given files.\n" "usage: hsm_action <file> ..."},
505         {"hsm_archive", lfs_hsm_archive, 0,
506          "Archive file to external storage.\n"
507          "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
508          "<file> ..."},
509         {"hsm_restore", lfs_hsm_restore, 0,
510          "Restore file from external storage.\n"
511          "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
512         {"hsm_release", lfs_hsm_release, 0,
513          "Release files from Lustre.\n"
514          "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
515         {"hsm_remove", lfs_hsm_remove, 0,
516          "Remove file copy from external storage.\n"
517          "usage: hsm_remove [--filelist FILELIST] [--data DATA] "
518          "[--archive NUM]\n"
519          "                  (FILE [FILE ...] | "
520          "--mntpath MOUNTPATH FID [FID ...])\n"
521          "\n"
522          "Note: To remove an archived copy of a file already deleted from a "
523          "Lustre FS, the\n"
524          "--mntpath option and a list of FIDs must be specified"
525         },
526         {"hsm_cancel", lfs_hsm_cancel, 0,
527          "Cancel requests related to specified files.\n"
528          "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
529         {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
530          "usage: swap_layouts <path1> <path2>"},
531         {"migrate", lfs_setstripe_migrate, 0,
532          "migrate directories and their inodes between MDTs.\n"
533          "usage: migrate [--mdt-count|-c STRIPE_COUNT] [--directory|-d]\n"
534          "               [--mdt-hash|-H HASH_TYPE]\n"
535          "               [--mdt-index|-m START_MDT_INDEX] [--verbose|-v]\n"
536          "               DIRECTORY\n"
537          "\n"
538          "migrate file objects from one OST layout to another\n"
539          "(may be not safe with concurent writes).\n"
540          MIGRATE_USAGE },
541         {"mv", lfs_mv, 0,
542          "To move directories between MDTs. This command is deprecated, "
543          "use \"migrate\" instead.\n"
544          "usage: mv <directory|filename> [--mdt-index|-m MDT_INDEX] "
545          "[--verbose|-v]\n"},
546         {"ladvise", lfs_ladvise, 0,
547          "Provide servers with advice about access patterns for a file.\n"
548          "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
549          "               [--background|-b] [--unset|-u]\n\n"
550          "               {--end|-e END[kMGT]|--length|-l LENGTH[kMGT]}\n"
551          "               {[--mode|-m [READ,WRITE]}\n"
552          "               <file> ...\n"},
553         {"mirror", lfs_mirror, mirror_cmdlist,
554          "lfs commands used to manage files with mirrored components:\n"
555          "lfs mirror create - create a mirrored file or directory\n"
556          "lfs mirror extend - add mirror(s) to an existing file\n"
557          "lfs mirror split  - split a mirror from an existing mirrored file\n"
558          "lfs mirror resync - resynchronize out-of-sync mirrored file(s)\n"
559          "lfs mirror read   - read a mirror content of a mirrored file\n"
560          "lfs mirror write  - write to a mirror of a mirrored file\n"
561          "lfs mirror copy   - copy a mirror to other mirror(s) of a file\n"
562          "lfs mirror verify - verify mirrored file(s)\n"},
563         {"getsom", lfs_getsom, 0, "To list the SOM info for a given file.\n"
564          "usage: getsom [-s] [-b] [-f] <path>\n"
565          "\t-s: Only show the size value of the SOM data for a given file\n"
566          "\t-b: Only show the blocks value of the SOM data for a given file\n"
567          "\t-f: Only show the flags value of the SOM data for a given file\n"},
568         {"heat_get", lfs_heat_get, 0,
569          "To get heat of files.\n"
570          "usage: heat_get <file> ...\n"},
571         {"heat_set", lfs_heat_set, 0,
572          "To set heat flags of files.\n"
573          "usage: heat_set [--clear|-c] [--off|-o] [--on|-O] <file> ...\n"
574          "\t--clear|-c: Clear file heat for given files\n"
575          "\t--off|-o:   Turn off file heat for given files\n"
576          "\t--on|-O:    Turn on file heat for given files\n"},
577         {"pcc", lfs_pcc, pcc_cmdlist,
578          "lfs commands used to interact with PCC features:\n"
579          "lfs pcc attach - attach given files to Persistent Client Cache\n"
580          "lfs pcc attach_fid - attach given files into PCC by FID(s)\n"
581          "lfs pcc state  - display the PCC state for given files\n"
582          "lfs pcc detach - detach given files from Persistent Client Cache\n"
583          "lfs pcc detach_fid - detach given files from PCC by FID(s)\n"},
584         { 0, 0, 0, NULL }
585 };
586
587 static int check_hashtype(const char *hashtype)
588 {
589         int type_num = atoi(hashtype);
590         int i;
591
592         /* numeric hash type */
593         if (hashtype && lmv_is_known_hash_type(type_num))
594                 return type_num;
595         /* string hash type */
596         for (i = LMV_HASH_TYPE_ALL_CHARS; i < ARRAY_SIZE(mdt_hash_name); i++)
597                 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
598                         return i;
599
600         return 0;
601 }
602
603 static uint32_t check_foreign_type_name(const char *foreign_type_name)
604 {
605         uint32_t i;
606
607         for (i = 0; i < LU_FOREIGN_TYPE_UNKNOWN; i++) {
608                 if (!lu_foreign_types[i].lft_name)
609                         break;
610                 if (strcmp(foreign_type_name,
611                            lu_foreign_types[i].lft_name) == 0)
612                         return lu_foreign_types[i].lft_type;
613         }
614
615         return LU_FOREIGN_TYPE_UNKNOWN;
616 }
617
618 static const char *error_loc = "syserror";
619
620 static int
621 migrate_open_files(const char *name, __u64 migration_flags,
622                    const struct llapi_stripe_param *param,
623                    struct llapi_layout *layout, int *fd_src_ptr,
624                    int *fd_dst_ptr)
625 {
626         int                      fd_src = -1;
627         int                      fd_dst = -1;
628         int                      rflags;
629         int                      mdt_index;
630         int                      random_value;
631         char                     parent[PATH_MAX];
632         char                     volatile_file[PATH_MAX];
633         char                    *ptr;
634         int                      rc;
635         struct stat              st;
636         struct stat              stv;
637
638         if (!param && !layout) {
639                 error_loc = "layout information";
640                 return -EINVAL;
641         }
642
643         /* search for file directory pathname */
644         if (strlen(name) > sizeof(parent) - 1) {
645                 error_loc = "source file name";
646                 return -ERANGE;
647         }
648
649         strncpy(parent, name, sizeof(parent));
650         ptr = strrchr(parent, '/');
651         if (!ptr) {
652                 if (!getcwd(parent, sizeof(parent))) {
653                         error_loc = "getcwd";
654                         return -errno;
655                 }
656         } else {
657                 if (ptr == parent) /* leading '/' */
658                         ptr = parent + 1;
659                 *ptr = '\0';
660         }
661
662         /* even if the file is only read, WR mode is nedeed to allow
663          * layout swap on fd
664          */
665         /* Allow migrating even without the key on encrypted files */
666         rflags = O_RDWR | O_NOATIME | O_CIPHERTEXT;
667         if (!(migration_flags & LLAPI_MIGRATION_NONDIRECT))
668                 rflags |= O_DIRECT;
669 source_open:
670         fd_src = open(name, rflags);
671         if (fd_src < 0) {
672                 /* If encrypted file without the key,
673                  * retry mirror extend in O_DIRECT.
674                  */
675                 if (errno == ENOKEY && !(rflags & O_DIRECT) &&
676                     migration_flags & LLAPI_MIGRATION_MIRROR) {
677                         rflags |= O_DIRECT;
678                         goto source_open;
679                 }
680                 rc = -errno;
681                 error_loc = "cannot open source file";
682                 return rc;
683         }
684
685         rc = llapi_file_fget_mdtidx(fd_src, &mdt_index);
686         if (rc < 0) {
687                 error_loc = "cannot get MDT index";
688                 goto out;
689         }
690
691         do {
692                 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW |
693                         /* Allow migrating without the key on encrypted files */
694                         O_CIPHERTEXT;
695                 mode_t open_mode = S_IRUSR | S_IWUSR;
696
697                 if (rflags & O_DIRECT)
698                         open_flags |= O_DIRECT;
699                 random_value = random();
700                 rc = snprintf(volatile_file, sizeof(volatile_file),
701                               "%s/%s:%.4X:%.4X:fd=%.2d", parent,
702                               LUSTRE_VOLATILE_HDR, mdt_index,
703                               random_value, fd_src);
704                 if (rc >= sizeof(volatile_file)) {
705                         rc = -ENAMETOOLONG;
706                         break;
707                 }
708
709                 /* create, open a volatile file, use caching (ie no directio) */
710                 if (layout) {
711                         /* Returns -1 and sets errno on error: */
712                         fd_dst = llapi_layout_file_open(volatile_file,
713                                                          open_flags, open_mode,
714                                                          layout);
715                         if (fd_dst < 0)
716                                 fd_dst = -errno;
717                 } else {
718                         /* Does the right thing on error: */
719                         fd_dst = llapi_file_open_param(volatile_file,
720                                                         open_flags,
721                                                         open_mode, param);
722                 }
723         } while (fd_dst < 0 && (rc = fd_dst) == -EEXIST);
724
725         if (rc < 0) {
726                 error_loc = "cannot create volatile file";
727                 goto out;
728         }
729
730         /*
731          * In case the MDT does not support creation of volatile files
732          * we should try to unlink it.
733          */
734         (void)unlink(volatile_file);
735
736         /*
737          * Not-owner (root?) special case.
738          * Need to set owner/group of volatile file like original.
739          * This will allow to pass related check during layout_swap.
740          */
741         rc = fstat(fd_src, &st);
742         if (rc != 0) {
743                 rc = -errno;
744                 error_loc = "cannot stat source file";
745                 goto out;
746         }
747
748         rc = fstat(fd_dst, &stv);
749         if (rc != 0) {
750                 rc = -errno;
751                 error_loc = "cannot stat volatile";
752                 goto out;
753         }
754
755         if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
756                 rc = fchown(fd_dst, st.st_uid, st.st_gid);
757                 if (rc != 0) {
758                         rc = -errno;
759                         error_loc = "cannot change ownwership of volatile";
760                         goto out;
761                 }
762         }
763
764 out:
765         if (rc < 0) {
766                 if (fd_src > 0)
767                         close(fd_src);
768                 if (fd_dst > 0)
769                         close(fd_dst);
770         } else {
771                 *fd_src_ptr = fd_src;
772                 *fd_dst_ptr = fd_dst;
773                 error_loc = NULL;
774         }
775         return rc;
776 }
777
778 struct timespec timespec_sub(struct timespec *before, struct timespec *after)
779 {
780         struct timespec ret;
781
782         ret.tv_sec = after->tv_sec - before->tv_sec;
783         if (after->tv_nsec < before->tv_nsec) {
784                 ret.tv_sec--;
785                 ret.tv_nsec = NSEC_PER_SEC + after->tv_nsec - before->tv_nsec;
786         } else {
787                 ret.tv_nsec = after->tv_nsec - before->tv_nsec;
788         }
789
790         return ret;
791 }
792
793 static void stats_log(struct timespec *now, struct timespec *start_time,
794                       ssize_t read_bytes, size_t write_bytes,
795                       off_t file_size_bytes)
796 {
797         struct timespec diff = timespec_sub(start_time, now);
798
799         if (file_size_bytes == 0)
800                 return;
801
802         if (diff.tv_sec == 0 && diff.tv_nsec == 0)
803                 return;
804
805         printf("- { seconds: %li, rmbps: %5.2g, wmbps: %5.2g, copied: %lu, size: %lu, pct: %lu%% }\n",
806                 diff.tv_sec,
807                 (double) read_bytes/((ONE_MB * diff.tv_sec) +
808                         ((ONE_MB * diff.tv_nsec)/NSEC_PER_SEC)),
809                 (double) write_bytes/((ONE_MB * diff.tv_sec) +
810                         ((ONE_MB * diff.tv_nsec)/NSEC_PER_SEC)),
811                 write_bytes/ONE_MB, file_size_bytes/ONE_MB,
812                 ((write_bytes*100)/file_size_bytes));
813 }
814
815 static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int),
816                              unsigned long long bandwidth_bytes_sec,
817                              long stats_interval_sec, off_t file_size_bytes)
818 {
819         struct llapi_layout *layout;
820         size_t buf_size = 64 * ONE_MB;
821         uint64_t stripe_size = ONE_MB;
822         void *buf = NULL;
823         off_t pos = 0;
824         off_t data_end = 0;
825         size_t page_size = sysconf(_SC_PAGESIZE);
826         bool sparse;
827         int rc;
828         size_t write_bytes = 0;
829         ssize_t read_bytes = 0;
830         struct timespec start_time;
831         struct timespec now;
832         struct timespec last_bw_print;
833
834         layout = llapi_layout_get_by_fd(fd_src, 0);
835         if (layout) {
836                 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
837                 if (rc == 0) {
838                         /* We like big bufs */
839                         if (stripe_size > buf_size)
840                                 buf_size = stripe_size;
841                         else
842                                 /* Trim to stripe_size multiple */
843                                 buf_size -= buf_size % stripe_size;
844                 }
845
846                 llapi_layout_free(layout);
847         }
848
849         /* limit transfer size to what can be sent in one second */
850         if (bandwidth_bytes_sec && bandwidth_bytes_sec < buf_size)
851                 buf_size = (bandwidth_bytes_sec + stripe_size - 1) &
852                         ~(stripe_size - 1);
853
854         /* Use a page-aligned buffer for direct I/O */
855         rc = posix_memalign(&buf, page_size, buf_size);
856         if (rc != 0)
857                 return -rc;
858
859         sparse = llapi_file_is_sparse(fd_src);
860         if (sparse) {
861                 rc = ftruncate(fd_dst, pos);
862                 if (rc < 0) {
863                         rc = -errno;
864                         free(buf);
865                         return rc;
866                 }
867         }
868
869         clock_gettime(CLOCK_MONOTONIC, &start_time);
870         now = last_bw_print = start_time;
871
872         while (1) {
873                 off_t data_off;
874                 size_t to_read, to_write;
875                 ssize_t rsize;
876
877                 if (sparse && pos >= data_end) {
878                         size_t data_size;
879
880                         data_off = llapi_data_seek(fd_src, pos, &data_size);
881                         if (data_off < 0) {
882                                 /* Non-fatal, switch to full copy */
883                                 sparse = false;
884                                 continue;
885                         }
886                         /* hole at the end of file, truncate up to it */
887                         if (!data_size) {
888                                 rc = ftruncate(fd_dst, data_off);
889                                 if (rc < 0)
890                                         goto out;
891                         }
892                         pos = data_off & ~(page_size - 1);
893                         data_end = data_off + data_size;
894                         to_read = ((data_end - pos - 1) | (page_size - 1)) + 1;
895                         to_read = MIN(to_read, buf_size);
896                 } else {
897                         to_read = buf_size;
898                 }
899
900                 if (check_file) {
901                         rc = check_file(fd_src);
902                         if (rc < 0)
903                                 goto out;
904                 }
905
906                 rsize = pread(fd_src, buf, to_read, pos);
907                 read_bytes += rsize;
908                 if (rsize < 0) {
909                         rc = -errno;
910                         goto out;
911                 }
912                 /* EOF */
913                 if (rsize == 0)
914                         break;
915
916                 to_write = rsize;
917                 while (to_write > 0) {
918                         unsigned long long write_target;
919                         ssize_t written;
920                         struct timespec diff;
921
922                         written = pwrite(fd_dst, buf, to_write, pos);
923                         if (written < 0) {
924                                 rc = -errno;
925                                 goto out;
926                         }
927                         pos += written;
928                         to_write -= written;
929                         write_bytes += written;
930
931                         if (bandwidth_bytes_sec == 0)
932                                 continue;
933
934                         clock_gettime(CLOCK_MONOTONIC, &now);
935                         diff = timespec_sub(&start_time, &now);
936                         write_target = ((bandwidth_bytes_sec * diff.tv_sec) +
937                                 ((bandwidth_bytes_sec *
938                                 diff.tv_nsec)/NSEC_PER_SEC));
939
940                         if (write_target < write_bytes) {
941                                 unsigned long long excess;
942                                 struct timespec delay = { 0, 0 };
943
944                                 excess = write_bytes - write_target;
945
946                                 if (excess == 0)
947                                         continue;
948
949                                 delay.tv_sec = excess / bandwidth_bytes_sec;
950                                 delay.tv_nsec = (excess % bandwidth_bytes_sec) *
951                                         NSEC_PER_SEC / bandwidth_bytes_sec;
952
953                                 do {
954                                         rc = clock_nanosleep(CLOCK_MONOTONIC, 0,
955                                                              &delay, &delay);
956                                 } while (rc < 0 && errno == EINTR);
957
958                                 if (rc < 0) {
959                                         if (stats_interval_sec)
960                                                 fprintf(stderr,
961                                                         "error %s: delay for bandwidth control failed: %s\n",
962                                                         progname,
963                                                         strerror(-rc));
964                                         rc = 0;
965                                 }
966                         }
967                 }
968
969                 clock_gettime(CLOCK_MONOTONIC, &now);
970                 if (stats_interval_sec && (write_bytes != file_size_bytes) &&
971                         (now.tv_sec >= last_bw_print.tv_sec +
972                         stats_interval_sec)) {
973                         stats_log(&now, &start_time,
974                                   read_bytes, write_bytes,
975                                   file_size_bytes);
976                         last_bw_print = now;
977                 }
978
979                 if (rc || rsize < to_read)
980                         break;
981         }
982
983         /* Output at least one log, regardless of stats_interval */
984         if (stats_interval_sec) {
985                 clock_gettime(CLOCK_MONOTONIC, &now);
986                 stats_log(&now, &start_time, read_bytes, write_bytes,
987                           file_size_bytes);
988         }
989
990         rc = fsync(fd_dst);
991         if (rc < 0)
992                 rc = -errno;
993 out:
994         /* Try to avoid page cache pollution after migration. */
995         (void)posix_fadvise(fd_src, 0, 0, POSIX_FADV_DONTNEED);
996         (void)posix_fadvise(fd_dst, 0, 0, POSIX_FADV_DONTNEED);
997
998         free(buf);
999         return rc;
1000 }
1001
1002 static int migrate_set_timestamps(int fd, const struct stat *st)
1003 {
1004         struct timeval tv[2] = {
1005                 {.tv_sec = st->st_atime},
1006                 {.tv_sec = st->st_mtime}
1007         };
1008
1009         return futimes(fd, tv);
1010 }
1011
1012 static int migrate_block(int fd_src, int fd_dst,
1013                          unsigned long long bandwidth_bytes_sec,
1014                          long stats_interval_sec)
1015 {
1016         struct stat st;
1017         __u64   dv1;
1018         int     gid;
1019         int     rc;
1020         int     rc2;
1021
1022         do
1023                 gid = random();
1024         while (gid == 0);
1025
1026
1027         /* The grouplock blocks all concurrent accesses to the file. */
1028         rc = llapi_group_lock(fd_src, gid);
1029         if (rc < 0) {
1030                 error_loc = "cannot get group lock";
1031                 return rc;
1032         }
1033
1034         rc = fstat(fd_src, &st);
1035         if (rc < 0) {
1036                 error_loc = "cannot stat source file";
1037                 rc = -errno;
1038                 goto out_unlock;
1039         }
1040
1041         /*
1042          * LL_DV_RD_FLUSH should not be set, otherwise the servers will try to
1043          * get extent locks on the OST objects. This will conflict with our
1044          * extent group locks.
1045          */
1046         rc = llapi_get_data_version(fd_src, &dv1, 0);
1047         if (rc < 0) {
1048                 error_loc = "cannot get dataversion";
1049                 goto out_unlock;
1050         }
1051
1052         rc = migrate_copy_data(fd_src, fd_dst, NULL, bandwidth_bytes_sec,
1053                                stats_interval_sec, st.st_size);
1054         if (rc < 0) {
1055                 error_loc = "data copy failed";
1056                 goto out_unlock;
1057         }
1058
1059         /* Make sure we keep original atime/mtime values */
1060         rc = migrate_set_timestamps(fd_dst, &st);
1061         if (rc < 0) {
1062                 error_loc = "set target file timestamp failed";
1063                 goto out_unlock;
1064         }
1065
1066         /*
1067          * swap layouts
1068          * for a migration we need to check data version on file did
1069          * not change.
1070          *
1071          * Pass in gid=0 since we already own grouplock.
1072          */
1073         rc = llapi_fswap_layouts_grouplock(fd_src, fd_dst, dv1, 0, 0,
1074                                            SWAP_LAYOUTS_CHECK_DV1);
1075         if (rc == -EAGAIN) {
1076                 error_loc = "file changed";
1077                 goto out_unlock;
1078         } else if (rc < 0) {
1079                 error_loc = "cannot swap layout";
1080                 goto out_unlock;
1081         }
1082
1083 out_unlock:
1084         rc2 = llapi_group_unlock(fd_src, gid);
1085         if (rc2 < 0 && rc == 0) {
1086                 error_loc = "unlock group lock";
1087                 rc = rc2;
1088         }
1089
1090         return rc;
1091 }
1092
1093 /**
1094  * Internal helper for migrate_copy_data(). Check lease and report error if
1095  * need be.
1096  *
1097  * \param[in]  fd           File descriptor on which to check the lease.
1098  *
1099  * \retval 0       Migration can keep on going.
1100  * \retval -errno  Error occurred, abort migration.
1101  */
1102 static int check_lease(int fd)
1103 {
1104         int rc;
1105
1106         rc = llapi_lease_check(fd);
1107         if (rc > 0)
1108                 return 0; /* llapi_check_lease returns > 0 on success. */
1109
1110         return -EBUSY;
1111 }
1112
1113 static int migrate_nonblock(int fd_src, int fd_dst,
1114                             unsigned long long bandwidth_bytes_sec,
1115                             long stats_interval_sec)
1116 {
1117         struct stat st;
1118         __u64   dv1;
1119         __u64   dv2;
1120         int     rc;
1121
1122         rc = fstat(fd_src, &st);
1123         if (rc < 0) {
1124                 error_loc = "cannot stat source file";
1125                 return -errno;
1126         }
1127
1128         rc = llapi_get_data_version(fd_src, &dv1, LL_DV_RD_FLUSH);
1129         if (rc < 0) {
1130                 error_loc = "cannot get data version";
1131                 return rc;
1132         }
1133
1134         rc = migrate_copy_data(fd_src, fd_dst, check_lease,
1135                                bandwidth_bytes_sec,
1136                                stats_interval_sec, st.st_size);
1137         if (rc < 0) {
1138                 error_loc = "data copy failed";
1139                 return rc;
1140         }
1141
1142         rc = llapi_get_data_version(fd_src, &dv2, LL_DV_RD_FLUSH);
1143         if (rc != 0) {
1144                 error_loc = "cannot get data version";
1145                 return rc;
1146         }
1147
1148         if (dv1 != dv2) {
1149                 rc = -EAGAIN;
1150                 error_loc = "source file changed";
1151                 return rc;
1152         }
1153
1154         /* Make sure we keep original atime/mtime values */
1155         rc = migrate_set_timestamps(fd_dst, &st);
1156         if (rc < 0) {
1157                 error_loc = "set target file timestamp failed";
1158                 return -errno;
1159         }
1160         return 0;
1161 }
1162
1163 static
1164 int lfs_layout_compid_by_pool(char *fname, const char *pool, int *comp_id)
1165 {
1166         struct pool_to_id_cbdata data = { .pool = pool };
1167         struct llapi_layout *layout = NULL;
1168         int rc;
1169
1170         layout = llapi_layout_get_by_path(fname, 0);
1171         if (!layout) {
1172                 fprintf(stderr,
1173                         "error %s: file '%s' couldn't get layout: rc=%d\n",
1174                         progname, fname, errno);
1175                 rc = -errno;
1176                 goto free_layout;
1177         }
1178         rc = llapi_layout_sanity(layout, false, true);
1179         if (rc < 0) {
1180                 llapi_layout_sanity_perror(errno);
1181                 goto free_layout;
1182         }
1183         rc = llapi_layout_comp_iterate(layout, find_comp_id_by_pool, &data);
1184         if (rc < 0)
1185                 goto free_layout;
1186
1187         *comp_id = data.id;
1188         rc = 0;
1189
1190 free_layout:
1191         if (layout)
1192                 llapi_layout_free(layout);
1193         return rc;
1194 }
1195
1196 static int lfs_component_set(char *fname, int comp_id, const char *pool,
1197                              __u32 flags, __u32 neg_flags)
1198 {
1199         __u32 ids[2];
1200         __u32 flags_array[2];
1201         size_t count = 0;
1202         int rc;
1203
1204         if (!comp_id) {
1205                 if (pool == NULL) {
1206                         fprintf(stderr,
1207                                 "error %s: neither component id nor pool is specified\n",
1208                                 progname);
1209                         return -EINVAL;
1210                 }
1211                 rc = lfs_layout_compid_by_pool(fname, pool, &comp_id);
1212                 if (rc)
1213                         return rc;
1214         }
1215
1216         if (flags) {
1217                 ids[count] = comp_id;
1218                 flags_array[count] = flags;
1219                 ++count;
1220         }
1221
1222         if (neg_flags) {
1223                 if (neg_flags & LCME_FL_STALE) {
1224                         fprintf(stderr,
1225                                 "%s: cannot clear 'stale' flags from component. Please use lfs-mirror-resync(1) instead\n",
1226                                 progname);
1227                         return -EINVAL;
1228                 }
1229
1230                 ids[count] = comp_id;
1231                 flags_array[count] = neg_flags | LCME_FL_NEG;
1232                 ++count;
1233         }
1234
1235         rc = llapi_layout_file_comp_set(fname, ids, flags_array, count);
1236         if (rc) {
1237                 if (errno == EUCLEAN) {
1238                         rc = -errno;
1239                         fprintf(stderr,
1240                                 "%s: cannot set 'stale' flag on component '%#x' of the last non-stale mirror of '%s'\n",
1241                                 progname, comp_id, fname);
1242                 } else {
1243                         fprintf(stderr,
1244                                 "%s: cannot change the flags of component '%#x' of file '%s': %x / ^(%x)\n",
1245                                 progname, comp_id, fname, flags, neg_flags);
1246                 }
1247         }
1248
1249         return rc;
1250 }
1251
1252 static int lfs_component_del(char *fname, __u32 comp_id,
1253                              __u32 flags, __u32 neg_flags)
1254 {
1255         int     rc = 0;
1256
1257         if (flags && neg_flags) {
1258                 fprintf(stderr,
1259                         "%s: cannot specify both positive and negative flags\n",
1260                         progname);
1261                 return -EINVAL;
1262         }
1263
1264         if (!flags && neg_flags)
1265                 flags = neg_flags | LCME_FL_NEG;
1266
1267         if (flags && comp_id) {
1268                 fprintf(stderr,
1269                         "%s: cannot specify component ID and flags at the same time\n",
1270                         progname);
1271                 return -EINVAL;
1272         }
1273
1274         if (!flags && !comp_id) {
1275                 fprintf(stderr,
1276                         "%s: neither flags nor component ID is specified\n",
1277                         progname);
1278                 return -EINVAL;
1279         }
1280
1281         if (flags) {
1282                 if (flags & ~LCME_KNOWN_FLAGS) {
1283                         fprintf(stderr,
1284                                 "%s setstripe: unknown flags %#x\n",
1285                                 progname, flags);
1286                         return -EINVAL;
1287                 }
1288         } else if (comp_id > LCME_ID_MAX) {
1289                 fprintf(stderr, "%s setstripe: invalid component id %u\n",
1290                         progname, comp_id);
1291                 return -EINVAL;
1292         }
1293
1294         rc = llapi_layout_file_comp_del(fname, comp_id, flags);
1295         if (rc)
1296                 fprintf(stderr,
1297                         "%s setstripe: cannot delete component %#x from '%s': %s\n",
1298                         progname, comp_id, fname, strerror(errno));
1299         return rc;
1300 }
1301
1302 static int lfs_component_add(char *fname, struct llapi_layout *layout)
1303 {
1304         int     rc;
1305
1306         if (!layout)
1307                 return -EINVAL;
1308
1309         rc = llapi_layout_file_comp_add(fname, layout);
1310         if (rc)
1311                 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
1312                         fname, strerror(errno));
1313         return rc;
1314 }
1315
1316 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
1317                                 struct llapi_layout *layout)
1318 {
1319         struct stat     st;
1320         int     fd;
1321
1322         if (!layout)
1323                 return -EINVAL;
1324
1325         fd = lstat(fname, &st);
1326         if (fd == 0 && S_ISDIR(st.st_mode))
1327                 open_flags = O_DIRECTORY | O_RDONLY;
1328
1329         fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
1330         if (fd < 0)
1331                 fprintf(stderr, "%s: cannot %s '%s': %s\n", progname,
1332                         S_ISDIR(st.st_mode) ?
1333                                 "set default composite layout for" :
1334                                 "create composite file",
1335                         fname, strerror(errno));
1336         return fd;
1337 }
1338
1339 static int lfs_migrate(char *name, __u64 migration_flags,
1340                         struct llapi_stripe_param *param,
1341                         struct llapi_layout *layout,
1342                         unsigned long long bandwidth_bytes_sec,
1343                         long stats_interval_sec)
1344 {
1345         struct llapi_layout *existing;
1346         uint64_t dom_new, dom_cur;
1347         int fd_src = -1;
1348         int fd_dst = -1;
1349         int rc;
1350
1351         rc = migrate_open_files(name, migration_flags, param, layout,
1352                                 &fd_src, &fd_dst);
1353         if (rc < 0)
1354                 goto out;
1355
1356         rc = llapi_layout_dom_size(layout, &dom_new);
1357         if (rc) {
1358                 error_loc = "cannot get new layout DoM size";
1359                 goto out;
1360         }
1361         /* special case for migration to DOM layout*/
1362         existing = llapi_layout_get_by_fd(fd_src, 0);
1363         if (!existing) {
1364                 error_loc = "cannot get existing layout";
1365                 goto out;
1366         }
1367
1368         rc = llapi_layout_dom_size(existing, &dom_cur);
1369         if (rc) {
1370                 error_loc = "cannot get current layout DoM size";
1371                 goto out;
1372         }
1373
1374         /*
1375          * if file has DoM layout already then migration is possible to
1376          * the new layout with the same DoM component via swap layout,
1377          * if new layout used bigger DOM size, then mirroring is used
1378          */
1379         if (dom_new > dom_cur) {
1380                 rc = lfs_migrate_to_dom(fd_src, fd_dst, name,
1381                                         migration_flags,
1382                                         bandwidth_bytes_sec,
1383                                         stats_interval_sec);
1384                 if (rc)
1385                         error_loc = "cannot migrate to DOM layout";
1386                 goto out_closed;
1387         }
1388
1389         if (stats_interval_sec)
1390                 printf("%s:\n", name);
1391
1392         if (!(migration_flags & LLAPI_MIGRATION_NONBLOCK)) {
1393                 /*
1394                  * Blocking mode (forced if servers do not support file lease).
1395                  * It is also the default mode, since we cannot distinguish
1396                  * between a broken lease and a server that does not support
1397                  * atomic swap/close (LU-6785)
1398                  */
1399                 rc = migrate_block(fd_src, fd_dst, bandwidth_bytes_sec,
1400                                    stats_interval_sec);
1401                 goto out;
1402         }
1403
1404         rc = llapi_lease_acquire(fd_src, LL_LEASE_RDLCK);
1405         if (rc < 0) {
1406                 error_loc = "cannot get lease";
1407                 goto out;
1408         }
1409
1410         rc = migrate_nonblock(fd_src, fd_dst, bandwidth_bytes_sec,
1411                               stats_interval_sec);
1412         if (rc < 0) {
1413                 llapi_lease_release(fd_src);
1414                 goto out;
1415         }
1416
1417         /*
1418          * Atomically put lease, swap layouts and close.
1419          * for a migration we need to check data version on file did
1420          * not change.
1421          */
1422         rc = llapi_fswap_layouts(fd_src, fd_dst, 0, 0, SWAP_LAYOUTS_CLOSE);
1423         if (rc < 0) {
1424                 error_loc = "cannot swap layout";
1425                 goto out;
1426         }
1427
1428 out:
1429         if (fd_src >= 0)
1430                 close(fd_src);
1431
1432         if (fd_dst >= 0)
1433                 close(fd_dst);
1434 out_closed:
1435         if (rc < 0)
1436                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1437                         progname, name, error_loc, strerror(-rc));
1438         else if (migration_flags & LLAPI_MIGRATION_VERBOSE)
1439                 printf("%s\n", name);
1440
1441         return rc;
1442 }
1443
1444 static int comp_str2flags(char *string, __u32 *flags, __u32 *neg_flags)
1445 {
1446         char *name;
1447         char *dup_string = NULL;
1448         int rc = 0;
1449
1450         *flags = 0;
1451         *neg_flags = 0;
1452
1453         if (!string || !string[0])
1454                 return -EINVAL;
1455
1456         dup_string = strdup(string);
1457         if (!dup_string) {
1458                 llapi_printf(LLAPI_MSG_ERROR,
1459                              "%s: insufficient memory\n",
1460                              progname);
1461                 return -ENOMEM;
1462         }
1463
1464         for (name = strtok(dup_string, ","); name; name = strtok(NULL, ",")) {
1465                 bool found = false;
1466                 int i;
1467
1468                 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1469                         __u32 comp_flag = comp_flags_table[i].cfn_flag;
1470                         const char *comp_name = comp_flags_table[i].cfn_name;
1471
1472                         if (strcmp(name, comp_name) == 0) {
1473                                 *flags |= comp_flag;
1474                                 found = true;
1475                         } else if (strncmp(name, "^", 1) == 0 &&
1476                                    strcmp(name + 1, comp_name) == 0) {
1477                                 *neg_flags |= comp_flag;
1478                                 found = true;
1479                         }
1480                 }
1481                 if (!found) {
1482                         llapi_printf(LLAPI_MSG_ERROR,
1483                                      "%s: component flag '%s' not supported\n",
1484                                      progname, name);
1485                         rc = -EINVAL;
1486                         goto out_free;
1487                 }
1488         }
1489
1490         if (!*flags && !*neg_flags)
1491                 rc = -EINVAL;
1492
1493         /* don't allow to set and exclude the same flag */
1494         if (*flags & *neg_flags)
1495                 rc = -EINVAL;
1496
1497 out_free:
1498         free(dup_string);
1499         return rc;
1500 }
1501
1502 static int mdthash_input(char *string, __u32 *inflags,
1503                          __u32 *exflags, __u32 *type)
1504 {
1505         char *name;
1506         struct mhf_list {
1507                 char *name;
1508                 __u32 flag;
1509         } mhflist[] = {
1510                 {"migrating", LMV_HASH_FLAG_MIGRATION},
1511                 {"bad_type", LMV_HASH_FLAG_BAD_TYPE},
1512                 {"badtype", LMV_HASH_FLAG_BAD_TYPE},
1513                 {"lost_lmv", LMV_HASH_FLAG_LOST_LMV},
1514                 {"lostlmv", LMV_HASH_FLAG_LOST_LMV},
1515         };
1516
1517         if (string == NULL)
1518                 return -EINVAL;
1519
1520         *inflags = 0;
1521         *exflags = 0;
1522         *type = 0;
1523         for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1524                 bool found = false;
1525                 int i;
1526
1527                 for (i = 0; i < ARRAY_SIZE(mhflist); i++) {
1528                         if (strcmp(name, mhflist[i].name) == 0 ||
1529                             name[0] == mhflist[i].name[0]) {
1530                                 *inflags |= mhflist[i].flag;
1531                                 found = true;
1532                         } else if (name[0] == '^' &&
1533                                    (strcmp(name + 1, mhflist[i].name) == 0 ||
1534                                     name[1] == mhflist[i].name[0])) {
1535                                 *exflags |= mhflist[i].flag;
1536                                 found = true;
1537                         }
1538                 }
1539                 if (!found) {
1540                         i = check_hashtype(name);
1541                         if (i > 0) {
1542                                 *type |= 1 << i;
1543                                 continue;
1544                         }
1545                         llapi_printf(LLAPI_MSG_ERROR,
1546                                      "%s: invalid mdt_hash value '%s'\n",
1547                                      progname, name);
1548                         return -EINVAL;
1549                 }
1550         }
1551
1552         /* don't allow to include and exclude the same flag */
1553         if (*inflags & *exflags) {
1554                 llapi_printf(LLAPI_MSG_ERROR,
1555                              "%s: include and exclude same flag '%s'\n",
1556                              progname, string);
1557                 return -EINVAL;
1558         }
1559
1560         return 0;
1561 }
1562
1563 static int mirror_str2state(char *string, __u16 *state, __u16 *neg_state)
1564 {
1565         if (!string)
1566                 return -EINVAL;
1567
1568         *state = 0;
1569         *neg_state = 0;
1570
1571         if (strncmp(string, "^", 1) == 0) {
1572                 *neg_state = llapi_layout_string_flags(string + 1);
1573                 if (*neg_state != 0)
1574                         return 0;
1575         } else {
1576                 *state = llapi_layout_string_flags(string);
1577                 if (*state != 0)
1578                         return 0;
1579         }
1580
1581         llapi_printf(LLAPI_MSG_ERROR,
1582                      "%s: mirrored file state '%s' not supported\n",
1583                      progname, string);
1584         return -EINVAL;
1585 }
1586
1587 /**
1588  * struct mirror_args - Command-line arguments for mirror(s).
1589  * @m_count:  Number of mirrors to be created with this layout.
1590  * @m_flags:  Mirror level flags, only 'prefer' is supported.
1591  * @m_layout: Mirror layout.
1592  * @m_file:   A victim file. Its layout will be split and used as a mirror.
1593  * @m_next:   Point to the next node of the list.
1594  *
1595  * Command-line arguments for mirror(s) will be parsed and stored in
1596  * a linked list that consists of this structure.
1597  */
1598 struct mirror_args {
1599         __u32                   m_count;
1600         __u32                   m_flags;
1601         struct llapi_layout     *m_layout;
1602         const char              *m_file;
1603         struct mirror_args      *m_next;
1604         bool                    m_inherit;
1605 };
1606
1607 /**
1608  * enum mirror_flags - Flags for extending a mirrored file.
1609  * @MF_NO_VERIFY: Indicates not to verify the mirror(s) from victim file(s)
1610  *             in case the victim file(s) contains the same data as the
1611  *             original mirrored file.
1612  * @MF_DESTROY: Indicates to delete the mirror from the mirrored file.
1613  * @MF_COMP_ID: specified component id instead of mirror id
1614  *
1615  * Flags for extending a mirrored file.
1616  */
1617 enum mirror_flags {
1618         MF_NO_VERIFY    = 0x1,
1619         MF_DESTROY      = 0x2,
1620         MF_COMP_ID      = 0x4,
1621         MF_COMP_POOL    = 0x8,
1622 };
1623
1624 /**
1625  * mirror_create_sanity_check() - Check mirror list.
1626  * @list:  A linked list that stores the mirror arguments.
1627  *
1628  * This function does a sanity check on @list for creating
1629  * a mirrored file.
1630  *
1631  * Return: 0 on success or a negative error code on failure.
1632  */
1633 static int mirror_create_sanity_check(const char *fname,
1634                                       struct mirror_args *list,
1635                                       bool check_fname)
1636 {
1637         int rc = 0;
1638         bool has_m_file = false;
1639         bool has_m_layout = false;
1640
1641         if (!list)
1642                 return -EINVAL;
1643
1644         if (fname && check_fname) {
1645                 struct llapi_layout *layout;
1646
1647                 layout = llapi_layout_get_by_path(fname, 0);
1648                 if (!layout) {
1649                         fprintf(stderr,
1650                                 "error: %s: file '%s' couldn't get layout\n",
1651                                 progname, fname);
1652                         return -ENODATA;
1653                 }
1654
1655                 rc = llapi_layout_sanity(layout, false, true);
1656
1657                 llapi_layout_free(layout);
1658
1659                 if (rc) {
1660                         llapi_layout_sanity_perror(rc);
1661                         return rc;
1662                 }
1663         }
1664
1665         while (list) {
1666                 if (list->m_file) {
1667                         has_m_file = true;
1668                         llapi_layout_free(list->m_layout);
1669
1670                         list->m_layout =
1671                                 llapi_layout_get_by_path(list->m_file, 0);
1672                         if (!list->m_layout) {
1673                                 fprintf(stderr,
1674                                         "error: %s: file '%s' has no layout\n",
1675                                         progname, list->m_file);
1676                                 return -ENODATA;
1677                         }
1678                 } else {
1679                         has_m_layout = true;
1680                         if (!list->m_layout) {
1681                                 fprintf(stderr, "error: %s: no mirror layout\n",
1682                                         progname);
1683                                 return -EINVAL;
1684                         }
1685                 }
1686
1687                 rc = llapi_layout_sanity(list->m_layout, false, true);
1688                 if (rc) {
1689                         llapi_layout_sanity_perror(rc);
1690                         return rc;
1691                 }
1692
1693                 list = list->m_next;
1694         }
1695
1696         if (has_m_file && has_m_layout) {
1697                 fprintf(stderr,
1698                         "error: %s: -f <victim_file> option should not be specified with setstripe options\n",
1699                         progname);
1700                 return -EINVAL;
1701         }
1702
1703         return 0;
1704 }
1705
1706 static int mirror_set_flags(struct llapi_layout *layout, void *cbdata)
1707 {
1708         __u32 mirror_flags = *(__u32 *)cbdata;
1709         uint32_t flags;
1710         int rc;
1711
1712         rc = llapi_layout_comp_flags_get(layout, &flags);
1713         if (rc < 0)
1714                 return rc;
1715
1716         if (!flags) {
1717                 rc = llapi_layout_comp_flags_set(layout, mirror_flags);
1718                 if (rc)
1719                         return rc;
1720         }
1721
1722         return LLAPI_LAYOUT_ITER_CONT;
1723 }
1724
1725 /**
1726  * mirror_create() - Create a mirrored file.
1727  * @fname:        The file to be created.
1728  * @mirror_list:  A linked list that stores the mirror arguments.
1729  *
1730  * This function creates a mirrored file @fname with the mirror(s)
1731  * from @mirror_list.
1732  *
1733  * Return: 0 on success or a negative error code on failure.
1734  */
1735 static int mirror_create(char *fname, struct mirror_args *mirror_list)
1736 {
1737         struct llapi_layout *layout = NULL;
1738         struct mirror_args *cur_mirror = NULL;
1739         uint16_t mirror_count = 0;
1740         int i = 0;
1741         int rc = 0;
1742
1743         rc = mirror_create_sanity_check(fname, mirror_list, false);
1744         if (rc)
1745                 return rc;
1746
1747         cur_mirror = mirror_list;
1748         while (cur_mirror) {
1749                 rc = llapi_layout_comp_iterate(cur_mirror->m_layout,
1750                                                mirror_set_flags,
1751                                                &cur_mirror->m_flags);
1752                 if (rc) {
1753                         rc = -errno;
1754                         fprintf(stderr, "%s: failed to set mirror flags\n",
1755                                 progname);
1756                         goto error;
1757                 }
1758
1759                 for (i = 0; i < cur_mirror->m_count; i++) {
1760                         rc = llapi_layout_merge(&layout, cur_mirror->m_layout);
1761                         if (rc) {
1762                                 rc = -errno;
1763                                 fprintf(stderr,
1764                                         "error: %s: merge layout failed: %s\n",
1765                                         progname, strerror(errno));
1766                                 goto error;
1767                         }
1768                 }
1769                 mirror_count += cur_mirror->m_count;
1770                 cur_mirror = cur_mirror->m_next;
1771         }
1772
1773         if (!layout) {
1774                 fprintf(stderr, "error: %s: layout is NULL\n", progname);
1775                 return -EINVAL;
1776         }
1777
1778         rc = llapi_layout_mirror_count_set(layout, mirror_count);
1779         if (rc) {
1780                 rc = -errno;
1781                 fprintf(stderr, "error: %s: set mirror count failed: %s\n",
1782                         progname, strerror(errno));
1783                 goto error;
1784         }
1785
1786         rc = lfs_component_create(fname, O_CREAT | O_WRONLY, 0666,
1787                                   layout);
1788         if (rc >= 0) {
1789                 close(rc);
1790                 rc = 0;
1791         }
1792
1793 error:
1794         llapi_layout_free(layout);
1795         return rc;
1796 }
1797
1798 /**
1799  * Compare files and check lease on @fd.
1800  *
1801  * \retval bytes number of bytes are the same
1802  */
1803 static ssize_t mirror_file_compare(int fd_src, int fd_dst)
1804 {
1805         const size_t buflen = 4 * 1024 * 1024; /* 4M */
1806         void *buf;
1807         ssize_t bytes_done = 0;
1808         ssize_t bytes_read = 0;
1809
1810         buf = malloc(buflen * 2);
1811         if (!buf)
1812                 return -ENOMEM;
1813
1814         while (1) {
1815                 if (!llapi_lease_check(fd_src)) {
1816                         bytes_done = -EBUSY;
1817                         break;
1818                 }
1819
1820                 bytes_read = read(fd_src, buf, buflen);
1821                 if (bytes_read <= 0)
1822                         break;
1823
1824                 if (bytes_read != read(fd_dst, buf + buflen, buflen))
1825                         break;
1826
1827                 /*
1828                  * XXX: should compute the checksum on each buffer and then
1829                  * compare checksum to avoid cache collision
1830                  */
1831                 if (memcmp(buf, buf + buflen, bytes_read))
1832                         break;
1833
1834                 bytes_done += bytes_read;
1835         }
1836
1837         free(buf);
1838
1839         return bytes_done;
1840 }
1841
1842 static int mirror_extend_file(const char *fname, const char *victim_file,
1843                               enum mirror_flags mirror_flags)
1844 {
1845         int fd = -1;
1846         int fdv = -1;
1847         struct stat stbuf;
1848         struct stat stbuf_v;
1849         struct ll_ioc_lease *data = NULL;
1850         int rc;
1851
1852         fd = open(fname, O_RDWR);
1853         if (fd < 0) {
1854                 error_loc = "open source file";
1855                 rc = -errno;
1856                 goto out;
1857         }
1858
1859         fdv = open(victim_file, O_RDWR);
1860         if (fdv < 0) {
1861                 error_loc = "open target file";
1862                 rc = -errno;
1863                 goto out;
1864         }
1865
1866         if (fstat(fd, &stbuf) || fstat(fdv, &stbuf_v)) {
1867                 error_loc = "stat source or target file";
1868                 rc = -errno;
1869                 goto out;
1870         }
1871
1872         if (stbuf.st_dev != stbuf_v.st_dev) {
1873                 error_loc = "stat source and target file";
1874                 rc = -EXDEV;
1875                 goto out;
1876         }
1877
1878         /* mirrors should be of the same size */
1879         if (stbuf.st_size != stbuf_v.st_size) {
1880                 error_loc = "file sizes don't match";
1881                 rc = -EINVAL;
1882                 goto out;
1883         }
1884
1885         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1886         if (rc < 0) {
1887                 error_loc = "cannot get lease";
1888                 goto out;
1889         }
1890
1891         if (!(mirror_flags & MF_NO_VERIFY)) {
1892                 ssize_t ret;
1893                 /* mirrors should have the same contents */
1894                 ret = mirror_file_compare(fd, fdv);
1895                 if (ret != stbuf.st_size) {
1896                         error_loc = "file busy or contents don't match";
1897                         rc = ret < 0 ? ret : -EINVAL;
1898                         goto out;
1899                 }
1900         }
1901
1902         /* Get rid of caching pages from clients */
1903         rc = llapi_file_flush(fd);
1904         if (rc < 0) {
1905                 error_loc = "cannot get data version";
1906                 goto out;
1907         }
1908
1909         rc = llapi_file_flush(fdv);
1910         if (rc < 0) {
1911                 error_loc = "cannot get data version";
1912                 goto out;
1913         }
1914
1915         rc = migrate_set_timestamps(fd, &stbuf);
1916         if (rc < 0) {
1917                 error_loc = "cannot set source file timestamp";
1918                 goto out;
1919         }
1920
1921         /* Atomically put lease, merge layouts and close. */
1922         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
1923         if (!data) {
1924                 error_loc = "memory allocation";
1925                 goto out;
1926         }
1927         data->lil_mode = LL_LEASE_UNLCK;
1928         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
1929         data->lil_count = 1;
1930         data->lil_ids[0] = fdv;
1931         rc = llapi_lease_set(fd, data);
1932         if (rc < 0) {
1933                 error_loc = "cannot merge layout";
1934                 goto out;
1935         } else if (rc == 0) {
1936                 rc = -EBUSY;
1937                 error_loc = "lost lease lock";
1938                 goto out;
1939         }
1940         rc = 0;
1941
1942 out:
1943         if (data)
1944                 free(data);
1945         if (fd >= 0)
1946                 close(fd);
1947         if (fdv >= 0)
1948                 close(fdv);
1949         if (!rc)
1950                 (void) unlink(victim_file);
1951         if (rc < 0)
1952                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1953                         progname, fname, error_loc, strerror(-rc));
1954         return rc;
1955 }
1956
1957 static int mirror_extend_layout(char *name, struct llapi_layout *m_layout,
1958                                 bool inherit, uint32_t flags,
1959                                 unsigned long long bandwidth_bytes_sec,
1960                                 long stats_interval_sec)
1961 {
1962         struct llapi_layout *f_layout = NULL;
1963         struct ll_ioc_lease *data = NULL;
1964         struct stat st;
1965         int fd_src = -1;
1966         int fd_dst = -1;
1967         int rc = 0;
1968
1969         if (inherit) {
1970                 f_layout = llapi_layout_get_by_path(name, 0);
1971                 if (!f_layout) {
1972                         rc = -EINVAL;
1973                         fprintf(stderr, "%s: cannot get layout\n", progname);
1974                         goto out;
1975                 }
1976                 rc = llapi_layout_get_last_init_comp(f_layout);
1977                 if (rc) {
1978                         fprintf(stderr, "%s: cannot get the last init comp\n",
1979                                 progname);
1980                         goto out;
1981                 }
1982                 rc = llapi_layout_mirror_inherit(f_layout, m_layout);
1983                 if (rc) {
1984                         fprintf(stderr,
1985                                 "%s: cannot inherit from the last init comp\n",
1986                                 progname);
1987                         goto out;
1988                 }
1989         }
1990
1991         llapi_layout_comp_flags_set(m_layout, flags);
1992         rc = migrate_open_files(name,
1993                              LLAPI_MIGRATION_NONDIRECT | LLAPI_MIGRATION_MIRROR,
1994                              NULL, m_layout, &fd_src, &fd_dst);
1995         if (rc < 0)
1996                 goto out;
1997
1998         rc = llapi_lease_acquire(fd_src, LL_LEASE_RDLCK);
1999         if (rc < 0) {
2000                 error_loc = "cannot get lease";
2001                 goto out;
2002         }
2003
2004         rc = fstat(fd_src, &st);
2005         if (rc < 0) {
2006                 error_loc = "cannot stat source file";
2007                 goto out;
2008         }
2009
2010         if (stats_interval_sec)
2011                 printf("%s:\n", name);
2012
2013         rc = migrate_nonblock(fd_src, fd_dst, bandwidth_bytes_sec,
2014                               stats_interval_sec);
2015         if (rc < 0) {
2016                 llapi_lease_release(fd_src);
2017                 goto out;
2018         }
2019
2020         rc = migrate_set_timestamps(fd_src, &st);
2021         if (rc < 0) {
2022                 error_loc = "cannot set source file timestamp";
2023                 goto out;
2024         }
2025
2026         /* Atomically put lease, merge layouts and close. */
2027         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
2028         if (!data) {
2029                 error_loc = "memory allocation";
2030                 goto out;
2031         }
2032         data->lil_mode = LL_LEASE_UNLCK;
2033         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
2034         data->lil_count = 1;
2035         data->lil_ids[0] = fd_dst;
2036         rc = llapi_lease_set(fd_src, data);
2037         if (rc < 0) {
2038                 error_loc = "cannot merge layout";
2039                 goto out;
2040         } else if (rc == 0) {
2041                 rc = -EBUSY;
2042                 error_loc = "lost lease lock";
2043                 goto out;
2044         }
2045         rc = 0;
2046
2047 out:
2048         if (data)
2049                 free(data);
2050         if (fd_src >= 0)
2051                 close(fd_src);
2052         if (fd_dst >= 0)
2053                 close(fd_dst);
2054         if (rc < 0)
2055                 fprintf(stderr, "error: %s: %s: %s: %s\n",
2056                         progname, name, error_loc, strerror(-rc));
2057         return rc;
2058 }
2059
2060 static int mirror_extend(char *fname, struct mirror_args *mirror_list,
2061                          enum mirror_flags mirror_flags,
2062                          unsigned long long bandwidth_bytes_sec,
2063                          long stats_interval_sec)
2064 {
2065         int rc = 0;
2066
2067         while (mirror_list) {
2068                 if (mirror_list->m_file) {
2069                         rc = mirror_extend_file(fname, mirror_list->m_file,
2070                                                 mirror_flags);
2071                 } else {
2072                         __u32 mirror_count = mirror_list->m_count;
2073
2074                         while (mirror_count > 0) {
2075                                 rc = mirror_extend_layout(fname,
2076                                                         mirror_list->m_layout,
2077                                                         mirror_list->m_inherit,
2078                                                         mirror_list->m_flags,
2079                                                         bandwidth_bytes_sec,
2080                                                         stats_interval_sec);
2081                                 if (rc)
2082                                         break;
2083
2084                                 --mirror_count;
2085                         }
2086                 }
2087                 if (rc)
2088                         break;
2089
2090                 mirror_list = mirror_list->m_next;
2091         }
2092
2093         return rc;
2094 }
2095
2096 static int find_mirror_id(struct llapi_layout *layout, void *cbdata)
2097 {
2098         uint32_t id;
2099         int rc;
2100
2101         rc = llapi_layout_mirror_id_get(layout, &id);
2102         if (rc < 0)
2103                 return rc;
2104
2105         if ((__u16)id == *(__u16 *)cbdata)
2106                 return LLAPI_LAYOUT_ITER_STOP;
2107
2108         return LLAPI_LAYOUT_ITER_CONT;
2109 }
2110
2111 static int find_comp_id(struct llapi_layout *layout, void *cbdata)
2112 {
2113         uint32_t id;
2114         int rc;
2115
2116         rc = llapi_layout_comp_id_get(layout, &id);
2117         if (rc < 0)
2118                 return rc;
2119
2120         if (id == *(__u32 *)cbdata)
2121                 return LLAPI_LAYOUT_ITER_STOP;
2122
2123         return LLAPI_LAYOUT_ITER_CONT;
2124 }
2125
2126 static int find_mirror_id_by_pool(struct llapi_layout *layout, void *cbdata)
2127 {
2128         char buf[LOV_MAXPOOLNAME + 1];
2129         struct pool_to_id_cbdata *d = (void *)cbdata;
2130         uint32_t id;
2131         int rc;
2132
2133         rc = llapi_layout_pool_name_get(layout, buf, sizeof(buf));
2134         if (rc < 0)
2135                 return rc;
2136         if (strcmp(d->pool, buf))
2137                 return LLAPI_LAYOUT_ITER_CONT;
2138
2139         rc = llapi_layout_mirror_id_get(layout, &id);
2140         if (rc < 0)
2141                 return rc;
2142         d->id = id;
2143
2144         return LLAPI_LAYOUT_ITER_STOP;
2145 }
2146
2147 static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata)
2148 {
2149         char buf[LOV_MAXPOOLNAME + 1];
2150         struct pool_to_id_cbdata *d = (void *)cbdata;
2151         uint32_t id;
2152         int rc;
2153
2154         rc = llapi_layout_pool_name_get(layout, buf, sizeof(buf));
2155         if (rc < 0)
2156                 return rc;
2157         if (strcmp(d->pool, buf))
2158                 return LLAPI_LAYOUT_ITER_CONT;
2159
2160         rc = llapi_layout_comp_id_get(layout, &id);
2161         if (rc < 0)
2162                 return rc;
2163         d->id = id;
2164
2165         return LLAPI_LAYOUT_ITER_STOP;
2166 }
2167
2168 struct collect_ids_data {
2169         __u16   *cid_ids;
2170         int     cid_count;
2171         __u16   cid_exclude;
2172 };
2173
2174 static int collect_mirror_id(struct llapi_layout *layout, void *cbdata)
2175 {
2176         struct collect_ids_data *cid = cbdata;
2177         uint32_t id;
2178         int rc;
2179
2180         rc = llapi_layout_mirror_id_get(layout, &id);
2181         if (rc < 0)
2182                 return rc;
2183
2184         if ((__u16)id != cid->cid_exclude) {
2185                 int i;
2186
2187                 for (i = 0; i < cid->cid_count; i++) {
2188                         /* already collected the mirror id */
2189                         if (id == cid->cid_ids[i])
2190                                 return LLAPI_LAYOUT_ITER_CONT;
2191                 }
2192                 cid->cid_ids[cid->cid_count] = id;
2193                 cid->cid_count++;
2194         }
2195
2196         return LLAPI_LAYOUT_ITER_CONT;
2197 }
2198
2199 /**
2200  * last_non_stale_mirror() - Check if a mirror is the last non-stale mirror.
2201  * @mirror_id: Mirror id to be checked.
2202  * @layout:    Mirror component list.
2203  *
2204  * This function checks if a mirror with specified @mirror_id is the last
2205  * non-stale mirror of a layout @layout.
2206  *
2207  * Return: true or false.
2208  */
2209 static inline
2210 bool last_non_stale_mirror(__u16 mirror_id, struct llapi_layout *layout)
2211 {
2212         __u16 mirror_ids[128] = { 0 };
2213         struct collect_ids_data cid = { .cid_ids = mirror_ids,
2214                                         .cid_count = 0,
2215                                         .cid_exclude = mirror_id, };
2216         int i;
2217
2218         llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
2219
2220         for (i = 0; i < cid.cid_count; i++) {
2221                 struct llapi_resync_comp comp_array[1024] = { { 0 } };
2222                 int comp_size = 0;
2223
2224                 comp_size = llapi_mirror_find_stale(layout, comp_array,
2225                                                     ARRAY_SIZE(comp_array),
2226                                                     &mirror_ids[i], 1);
2227                 if (comp_size == 0)
2228                         return false;
2229         }
2230
2231         return true;
2232 }
2233
2234 static int mirror_split(const char *fname, __u32 id, const char *pool,
2235                         enum mirror_flags mflags, const char *victim_file)
2236 {
2237         struct llapi_layout *layout;
2238         char parent[PATH_MAX];
2239         char victim[PATH_MAX];
2240         int flags = O_CREAT | O_EXCL | O_LOV_DELAY_CREATE | O_NOFOLLOW;
2241         char *ptr;
2242         struct ll_ioc_lease *data;
2243         uint16_t mirror_count;
2244         __u32 mirror_id;
2245         int mdt_index;
2246         int fd, fdv;
2247         bool purge = true; /* delete mirror by setting fdv=fd */
2248         bool is_encrypted;
2249         int rc;
2250
2251         if (victim_file && (strcmp(fname, victim_file) == 0)) {
2252                 fprintf(stderr,
2253                         "error %s: the source file '%s' and -f file are the same\n",
2254                         progname, fname);
2255                 return -EINVAL;
2256         }
2257
2258         /* check fname contains mirror with mirror_id/comp_id */
2259         layout = llapi_layout_get_by_path(fname, 0);
2260         if (!layout) {
2261                 fprintf(stderr,
2262                         "error %s: file '%s' couldn't get layout\n",
2263                         progname, fname);
2264                 return -EINVAL;
2265         }
2266
2267         rc = llapi_layout_sanity(layout, false, true);
2268         if (rc) {
2269                 llapi_layout_sanity_perror(rc);
2270                 goto free_layout;
2271         }
2272
2273         rc = llapi_layout_mirror_count_get(layout, &mirror_count);
2274         if (rc) {
2275                 fprintf(stderr,
2276                         "error %s: file '%s' couldn't get mirror count\n",
2277                         progname, fname);
2278                 goto free_layout;
2279         }
2280         if (mirror_count < 2) {
2281                 fprintf(stderr,
2282                         "error %s: file '%s' has %d component, cannot split\n",
2283                         progname, fname, mirror_count);
2284                 goto free_layout;
2285         }
2286
2287         if (mflags & MF_COMP_POOL) {
2288                 struct pool_to_id_cbdata data = { .pool = pool };
2289
2290                 rc = llapi_layout_comp_iterate(layout, find_mirror_id_by_pool,
2291                                                &data);
2292                 mirror_id = data.id;
2293         } else if (mflags & MF_COMP_ID) {
2294                 rc = llapi_layout_comp_iterate(layout, find_comp_id, &id);
2295                 mirror_id = mirror_id_of(id);
2296         } else {
2297                 rc = llapi_layout_comp_iterate(layout, find_mirror_id, &id);
2298                 mirror_id = id;
2299         }
2300         if (rc < 0) {
2301                 fprintf(stderr, "error %s: failed to iterate layout of '%s'\n",
2302                         progname, fname);
2303                 goto free_layout;
2304         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
2305                 if (mflags & MF_COMP_POOL) {
2306                         fprintf(stderr,
2307                                 "error %s: file '%s' does not contain mirror with pool '%s'\n",
2308                                 progname, fname, pool);
2309                         goto free_layout;
2310                 } else if (mflags & MF_COMP_ID) {
2311                         fprintf(stderr,
2312                                 "error %s: file '%s' does not contain mirror with comp-id %u\n",
2313                                 progname, fname, id);
2314                         goto free_layout;
2315                 } else {
2316                         fprintf(stderr,
2317                                 "error %s: file '%s' does not contain mirror with id %u\n",
2318                                 progname, fname, id);
2319                         goto free_layout;
2320                 }
2321         }
2322
2323         if (last_non_stale_mirror(mirror_id, layout)) {
2324                 rc = -EUCLEAN;
2325                 fprintf(stderr,
2326                         "%s: cannot destroy the last non-stale mirror of file '%s'\n",
2327                         progname, fname);
2328                 goto free_layout;
2329         }
2330
2331         if (!victim_file && mflags & MF_DESTROY)
2332                 /* Allow mirror split even without the key on encrypted files,
2333                  * and in this case of a 'split -d', open file with O_DIRECT
2334                  * (no IOs will be done).
2335                  */
2336                 fd = open(fname, O_RDWR | O_DIRECT | O_CIPHERTEXT);
2337         else
2338                 fd = open(fname, O_RDWR);
2339
2340         if (fd < 0) {
2341                 fprintf(stderr,
2342                         "error %s: open file '%s' failed: %s\n",
2343                         progname, fname, strerror(errno));
2344                 goto free_layout;
2345         }
2346
2347         /* get victim file directory pathname */
2348         if (strlen(fname) > sizeof(parent) - 1) {
2349                 fprintf(stderr, "error %s: file name of '%s' too long\n",
2350                         progname, fname);
2351                 rc = -ERANGE;
2352                 goto close_fd;
2353         }
2354         strncpy(parent, fname, sizeof(parent));
2355         ptr = strrchr(parent, '/');
2356         if (!ptr) {
2357                 if (!getcwd(parent, sizeof(parent))) {
2358                         fprintf(stderr, "error %s: getcwd failed: %s\n",
2359                                 progname, strerror(errno));
2360                         rc = -errno;
2361                         goto close_fd;
2362                 }
2363         } else {
2364                 if (ptr == parent)
2365                         ptr = parent + 1;
2366                 *ptr = '\0';
2367         }
2368
2369         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
2370         if (rc < 0) {
2371                 fprintf(stderr, "%s: cannot get MDT index of '%s'\n",
2372                         progname, fname);
2373                 goto close_fd;
2374         }
2375
2376         rc = llapi_file_is_encrypted(fd);
2377         if (rc < 0) {
2378                 fprintf(stderr, "%s: cannot get flags of '%s': %d\n",
2379                         progname, fname, rc);
2380                 goto close_fd;
2381         }
2382         is_encrypted = rc;
2383
2384 again:
2385         if (!victim_file) {
2386                 /* use a temp file to store the splitted layout */
2387                 if (mflags & MF_DESTROY) {
2388                         char file_path[PATH_MAX];
2389                         unsigned int rnumber;
2390                         int open_flags;
2391
2392                         if (last_non_stale_mirror(mirror_id, layout)) {
2393                                 rc = -EUCLEAN;
2394                                 fprintf(stderr,
2395                                         "%s: cannot destroy the last non-stale mirror of file '%s'\n",
2396                                         progname, fname);
2397                                 goto close_fd;
2398                         }
2399
2400                         if (purge) {
2401                                 /* don't use volatile file for mirror destroy */
2402                                 fdv = fd;
2403                         } else {
2404                                 /**
2405                                  * try the old way to delete mirror using
2406                                  * volatile file.
2407                                  */
2408                                 do {
2409                                         rnumber = random();
2410                                         rc = snprintf(file_path,
2411                                                       sizeof(file_path),
2412                                                       "%s/" LUSTRE_VOLATILE_HDR ":%.4X:%.4X:fd=%.2d",
2413                                                       parent, mdt_index,
2414                                                       rnumber, fd);
2415                                         if (rc < 0 ||
2416                                             rc >= sizeof(file_path)) {
2417                                                 fdv = -ENAMETOOLONG;
2418                                                 break;
2419                                         }
2420
2421                                         open_flags = O_RDWR |
2422                                              (O_LOV_DELAY_CREATE & ~O_ACCMODE) |
2423                                              O_CREAT | O_EXCL | O_NOFOLLOW |
2424                                              /* O_DIRECT for mirror split -d */
2425                                              O_DIRECT |
2426                                              /* Allow split without the key */
2427                                              O_CIPHERTEXT;
2428                                         fdv = open(file_path, open_flags,
2429                                                    S_IRUSR | S_IWUSR);
2430                                         if (fdv < 0)
2431                                                 rc = -errno;
2432                                 } while (fdv < 0 && rc == -EEXIST);
2433                         }
2434                 } else {
2435                         if (is_encrypted) {
2436                                 rc = -1;
2437                                 fprintf(stderr,
2438                                         "error %s: not permitted on encrypted file '%s': %d\n",
2439                                         progname, fname, rc);
2440                                 goto close_fd;
2441                         }
2442
2443                         snprintf(victim, sizeof(victim), "%s.mirror~%u",
2444                                  fname, mirror_id);
2445                         fdv = open(victim, flags, S_IRUSR | S_IWUSR);
2446                 }
2447         } else {
2448                 /* user specified victim file */
2449                 if (is_encrypted) {
2450                         rc = -1;
2451                         fprintf(stderr,
2452                                 "error %s: not permitted on encrypted file '%s': %d\n",
2453                                 progname, fname, rc);
2454                         goto close_fd;
2455                 }
2456                 fdv = open(victim_file, flags, S_IRUSR | S_IWUSR);
2457         }
2458
2459         if (fdv < 0) {
2460                 fprintf(stderr,
2461                         "error %s: create victim file failed: %s\n",
2462                         progname, strerror(errno));
2463                 goto close_fd;
2464         }
2465
2466         /* get lease lock of fname */
2467         rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
2468         if (rc < 0) {
2469                 fprintf(stderr,
2470                         "error %s: cannot get lease of file '%s': %d\n",
2471                         progname, fname, rc);
2472                 goto close_victim;
2473         }
2474
2475         /* Atomatically put lease, split layouts and close. */
2476         data = malloc(offsetof(typeof(*data), lil_ids[2]));
2477         if (!data) {
2478                 rc = -ENOMEM;
2479                 goto close_victim;
2480         }
2481
2482         data->lil_mode = LL_LEASE_UNLCK;
2483         data->lil_flags = LL_LEASE_LAYOUT_SPLIT;
2484         data->lil_count = 2;
2485         data->lil_ids[0] = fdv;
2486         data->lil_ids[1] = mirror_id;
2487         rc = llapi_lease_set(fd, data);
2488         if (rc <= 0) {
2489                 if ((rc == -EINVAL || rc == -EBUSY) && purge) {
2490                         /* could be old MDS which prohibit fd==fdv */
2491                         purge = false;
2492                         goto again;
2493
2494                 }
2495                 if (rc == 0) /* lost lease lock */
2496                         rc = -EBUSY;
2497                 fprintf(stderr,
2498                         "error %s: cannot split '%s': %s\n",
2499                         progname, fname, strerror(-rc));
2500         } else {
2501                 rc = 0;
2502         }
2503         free(data);
2504
2505 close_victim:
2506         if (!purge)
2507                 close(fdv);
2508 close_fd:
2509         close(fd);
2510 free_layout:
2511         llapi_layout_free(layout);
2512         return rc;
2513 }
2514
2515 static inline
2516 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
2517                            __u16 *mirror_ids, int ids_nr,
2518                            long stats_interval_sec, long bandwidth_bytes_sec);
2519
2520
2521 static int lfs_migrate_to_dom(int fd_src, int fd_dst, char *name,
2522                               __u64 migration_flags,
2523                               unsigned long long bandwidth_bytes_sec,
2524                               long stats_interval_sec)
2525 {
2526         struct ll_ioc_lease *data = NULL;
2527         int rc;
2528
2529         rc = llapi_lease_acquire(fd_src, LL_LEASE_RDLCK);
2530         if (rc < 0) {
2531                 error_loc = "cannot get lease";
2532                 goto out_close;
2533         }
2534
2535         if (stats_interval_sec)
2536                 printf("%s:\n", name);
2537
2538         rc = migrate_nonblock(fd_src, fd_dst, bandwidth_bytes_sec,
2539                               stats_interval_sec);
2540         if (rc < 0)
2541                 goto out_release;
2542
2543         /* Atomically put lease, merge layouts, resync and close. */
2544         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
2545         if (!data) {
2546                 error_loc = "memory allocation";
2547                 goto out_release;
2548         }
2549         data->lil_mode = LL_LEASE_UNLCK;
2550         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
2551         data->lil_count = 1;
2552         data->lil_ids[0] = fd_dst;
2553         rc = llapi_lease_set(fd_src, data);
2554         if (rc < 0) {
2555                 error_loc = "cannot merge layout";
2556                 goto out_close;
2557         } else if (rc == 0) {
2558                 rc = -EBUSY;
2559                 error_loc = "lost lease lock";
2560                 goto out_close;
2561         }
2562         close(fd_src);
2563         close(fd_dst);
2564
2565         rc = lfs_mirror_resync_file(name, data, NULL, 0,
2566                                     stats_interval_sec,
2567                                     bandwidth_bytes_sec);
2568         if (rc) {
2569                 error_loc = "cannot resync file";
2570                 goto out;
2571         }
2572
2573         /* delete first mirror now */
2574         rc = mirror_split(name, 1, NULL, MF_DESTROY, NULL);
2575         if (rc < 0)
2576                 error_loc = "cannot delete old layout";
2577         goto out;
2578
2579 out_release:
2580         llapi_lease_release(fd_src);
2581 out_close:
2582         close(fd_src);
2583         close(fd_dst);
2584 out:
2585         if (rc < 0)
2586                 fprintf(stderr, "error: %s: %s: %s: %s\n",
2587                         progname, name, error_loc, strerror(-rc));
2588         else if (migration_flags & LLAPI_MIGRATION_VERBOSE)
2589                 printf("%s\n", name);
2590         if (data)
2591                 free(data);
2592         return rc;
2593 }
2594
2595 /**
2596  * Parse a string containing an target index list into an array of integers.
2597  *
2598  * The input string contains a comma delimited list of individual
2599  * indices and ranges, for example "1,2-4,7". Add the indices into the
2600  * \a tgts array and remove duplicates.
2601  *
2602  * \param[out] tgts             array to store indices in
2603  * \param[in] size              size of \a tgts array
2604  * \param[in] offset            starting index in \a tgts
2605  * \param[in] arg               string containing OST index list
2606  * \param[in/out] overstriping  index list may contain duplicates
2607  *
2608  * \retval positive    number of indices in \a tgts
2609  * \retval -EINVAL     unable to parse \a arg
2610  */
2611 static int parse_targets(__u32 *tgts, int size, int offset, char *arg,
2612                          unsigned long long *pattern)
2613 {
2614         int rc;
2615         int nr = offset;
2616         int slots = size - offset;
2617         char *ptr = NULL;
2618         bool overstriped = false;
2619         bool end_of_loop;
2620
2621         if (!arg)
2622                 return -EINVAL;
2623
2624         end_of_loop = false;
2625         while (!end_of_loop) {
2626                 int start_index = 0;
2627                 int end_index = 0;
2628                 int i;
2629                 char *endptr = NULL;
2630
2631                 rc = -EINVAL;
2632
2633                 ptr = strchrnul(arg, ',');
2634
2635                 end_of_loop = *ptr == '\0';
2636                 *ptr = '\0';
2637
2638                 errno = 0;
2639                 start_index = strtol(arg, &endptr, 0);
2640                 if (endptr == arg) /* no data at all */
2641                         break;
2642                 if (errno != 0 || start_index < -1 ||
2643                     (*endptr != '-' && *endptr != '\0'))
2644                         break;
2645
2646                 end_index = start_index;
2647                 if (*endptr == '-') {
2648                         errno = 0;
2649                         end_index = strtol(endptr + 1, &endptr, 0);
2650                         if (errno != 0 || *endptr != '\0' || end_index < -1)
2651                                 break;
2652                         if (end_index < start_index)
2653                                 break;
2654                 }
2655
2656                 for (i = start_index; i <= end_index && slots > 0; i++) {
2657                         int j;
2658
2659                         /* remove duplicate */
2660                         for (j = 0; j < offset; j++) {
2661                                 if (tgts[j] == i && pattern &&
2662                                     *pattern == LLAPI_LAYOUT_OVERSTRIPING)
2663                                         overstriped = true;
2664                                 else if (tgts[j] == i)
2665                                         return -EINVAL;
2666                         }
2667
2668                         j = offset;
2669
2670                         if (j == offset) { /* check complete */
2671                                 tgts[nr++] = i;
2672                                 --slots;
2673                         }
2674                 }
2675
2676                 if (slots == 0 && i < end_index)
2677                         break;
2678
2679                 *ptr = ',';
2680                 arg = ++ptr;
2681                 offset = nr;
2682                 rc = 0;
2683         }
2684         if (!end_of_loop && ptr)
2685                 *ptr = ',';
2686
2687         if (!overstriped && pattern)
2688                 *pattern = LLAPI_LAYOUT_DEFAULT;
2689
2690         return rc < 0 ? rc : nr;
2691 }
2692
2693 struct lfs_setstripe_args {
2694         unsigned long long       lsa_comp_end;
2695         unsigned long long       lsa_stripe_size;
2696         unsigned long long       lsa_extension_size;
2697         long long                lsa_stripe_count;
2698         long long                lsa_stripe_off;
2699         __u32                    lsa_comp_flags;
2700         __u32                    lsa_comp_neg_flags;
2701         unsigned long long       lsa_pattern;
2702         unsigned int             lsa_mirror_count;
2703         int                      lsa_nr_tgts;
2704         bool                     lsa_first_comp;
2705         bool                     lsa_extension_comp;
2706         __u32                   *lsa_tgts;
2707         char                    *lsa_pool_name;
2708 };
2709
2710 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
2711 {
2712         unsigned int mirror_count = lsa->lsa_mirror_count;
2713         bool first_comp = lsa->lsa_first_comp;
2714
2715         memset(lsa, 0, sizeof(*lsa));
2716
2717         lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
2718         lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
2719         lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2720         lsa->lsa_pattern = LLAPI_LAYOUT_RAID0;
2721         lsa->lsa_pool_name = NULL;
2722
2723         lsa->lsa_mirror_count = mirror_count;
2724         lsa->lsa_first_comp = first_comp;
2725 }
2726
2727 /**
2728  * setstripe_args_init_inherit() - Initialize and inherit stripe options.
2729  * @lsa: Stripe options to be initialized and inherited.
2730  *
2731  * This function initializes stripe options in @lsa and inherit
2732  * stripe_size, stripe_count and OST pool_name options.
2733  *
2734  * Return: void.
2735  */
2736 static inline void setstripe_args_init_inherit(struct lfs_setstripe_args *lsa)
2737 {
2738         unsigned long long stripe_size;
2739         long long stripe_count;
2740         char *pool_name = NULL;
2741
2742         stripe_size = lsa->lsa_stripe_size;
2743         stripe_count = lsa->lsa_stripe_count;
2744         pool_name = lsa->lsa_pool_name;
2745
2746         setstripe_args_init(lsa);
2747
2748         lsa->lsa_stripe_size = stripe_size;
2749         lsa->lsa_stripe_count = stripe_count;
2750         lsa->lsa_pool_name = pool_name;
2751 }
2752
2753 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
2754 {
2755         return (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT ||
2756                 lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ||
2757                 lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
2758                 lsa->lsa_pattern != LLAPI_LAYOUT_RAID0 ||
2759                 lsa->lsa_comp_end != 0);
2760 }
2761
2762 static int lsa_args_stripe_count_check(struct lfs_setstripe_args *lsa)
2763 {
2764         if (lsa->lsa_nr_tgts) {
2765                 if (lsa->lsa_nr_tgts < 0 ||
2766                     lsa->lsa_nr_tgts >= LOV_MAX_STRIPE_COUNT) {
2767                         fprintf(stderr, "Invalid nr_tgts(%d)\n",
2768                                 lsa->lsa_nr_tgts);
2769                         errno = EINVAL;
2770                         return -1;
2771                 }
2772
2773                 if (lsa->lsa_stripe_count > 0 &&
2774                     lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
2775                     lsa->lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
2776                     lsa->lsa_nr_tgts != lsa->lsa_stripe_count) {
2777                         fprintf(stderr, "stripe_count(%lld) != nr_tgts(%d)\n",
2778                                 lsa->lsa_stripe_count,
2779                                 lsa->lsa_nr_tgts);
2780                         errno = EINVAL;
2781                         return -1;
2782                 }
2783         }
2784
2785         return 0;
2786
2787 }
2788
2789 /**
2790  * comp_args_to_layout() - Create or extend a composite layout.
2791  * @composite:       Pointer to the composite layout.
2792  * @lsa:             Stripe options for the new component.
2793  *
2794  * This function creates or extends a composite layout by adding a new
2795  * component with stripe options from @lsa.
2796  *
2797  * When modified, adjust llapi_stripe_param_verify() if needed as well.
2798  *
2799  * Return: 0 on success or an error code on failure.
2800  */
2801 static int comp_args_to_layout(struct llapi_layout **composite,
2802                                struct lfs_setstripe_args *lsa,
2803                                bool set_extent)
2804 {
2805         struct llapi_layout *layout = *composite;
2806         uint64_t prev_end = 0;
2807         uint64_t size;
2808         int i = 0, rc;
2809
2810 new_comp:
2811         if (!layout) {
2812                 layout = llapi_layout_alloc();
2813                 if (!layout) {
2814                         fprintf(stderr, "Alloc llapi_layout failed. %s\n",
2815                                 strerror(errno));
2816                         errno = ENOMEM;
2817                         return -1;
2818                 }
2819                 *composite = layout;
2820                 lsa->lsa_first_comp = true;
2821         } else {
2822                 uint64_t start;
2823
2824                 /*
2825                  * Get current component extent, current component
2826                  * must be the tail component.
2827                  */
2828                 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
2829                 if (rc) {
2830                         fprintf(stderr, "Get comp extent failed. %s\n",
2831                                 strerror(errno));
2832                         return rc;
2833                 }
2834
2835                 if (lsa->lsa_first_comp) {
2836                         prev_end = 0;
2837                         rc = llapi_layout_add_first_comp(layout);
2838                 } else {
2839                         rc = llapi_layout_comp_add(layout);
2840                 }
2841                 if (rc) {
2842                         fprintf(stderr, "Add component failed. %s\n",
2843                                 strerror(errno));
2844                         return rc;
2845                 }
2846         }
2847
2848         rc = llapi_layout_comp_flags_set(layout, lsa->lsa_comp_flags);
2849         if (rc) {
2850                 fprintf(stderr, "Set flags 0x%x failed: %s\n",
2851                         lsa->lsa_comp_flags, strerror(errno));
2852                 return rc;
2853         }
2854
2855         if (set_extent) {
2856                 uint64_t comp_end = lsa->lsa_comp_end;
2857
2858                 /*
2859                  * The extendable component is 0-length, so it can be removed
2860                  * if there is insufficient space to extend it.
2861                  */
2862                 if (lsa->lsa_extension_comp)
2863                         comp_end = prev_end;
2864
2865                 rc = llapi_layout_comp_extent_set(layout, prev_end,
2866                                                   comp_end);
2867                 if (rc) {
2868                         fprintf(stderr, "Set extent [%lu, %lu) failed. %s\n",
2869                                 prev_end, comp_end, strerror(errno));
2870                         return rc;
2871                 }
2872         }
2873         /* reset lsa_first_comp */
2874         lsa->lsa_first_comp = false;
2875
2876         /* Data-on-MDT component setting */
2877         if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
2878                 /* Yaml support */
2879                 if (lsa->lsa_stripe_count == 0)
2880                         lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
2881                 if (lsa->lsa_stripe_size == lsa->lsa_comp_end)
2882                         lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
2883                 if (lsa->lsa_stripe_off == -1 ||
2884                     lsa->lsa_stripe_off == 0)
2885                         lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2886                 /*
2887                  * In case of Data-on-MDT patterns the only extra option
2888                  * applicable is stripe size option.
2889                  */
2890                 if (lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
2891                         fprintf(stderr,
2892                                 "Option 'stripe-count' can't be specified with Data-on-MDT component: %lld\n",
2893                                 lsa->lsa_stripe_count);
2894                         errno = EINVAL;
2895                         return -1;
2896                 }
2897                 if (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT &&
2898                     lsa->lsa_stripe_size != lsa->lsa_comp_end - prev_end) {
2899                         fprintf(stderr,
2900                                 "Option 'stripe-size' can't be specified with Data-on-MDT component: %llu\n",
2901                                 lsa->lsa_stripe_size);
2902                         errno = EINVAL;
2903                         return -1;
2904                 }
2905                 if (lsa->lsa_nr_tgts != 0) {
2906                         fprintf(stderr,
2907                                 "Option 'ost-list' can't be specified with Data-on-MDT component: '%i'\n",
2908                                 lsa->lsa_nr_tgts);
2909                         errno = EINVAL;
2910                         return -1;
2911                 }
2912                 if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
2913                         fprintf(stderr,
2914                                 "Option 'stripe-offset' can't be specified with Data-on-MDT component: %lld\n",
2915                                 lsa->lsa_stripe_off);
2916                         errno = EINVAL;
2917                         return -1;
2918                 }
2919                 if (lsa->lsa_pool_name != 0) {
2920                         fprintf(stderr,
2921                                 "Option 'pool' can't be specified with Data-on-MDT component: '%s'\n",
2922                                 lsa->lsa_pool_name);
2923                         errno = EINVAL;
2924                         return -1;
2925                 }
2926
2927                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
2928                 if (rc) {
2929                         fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
2930                                 lsa->lsa_pattern,
2931                                 strerror(errno));
2932                         return rc;
2933                 }
2934                 /* Data-on-MDT component has always single stripe up to end */
2935                 lsa->lsa_stripe_size = lsa->lsa_comp_end;
2936         } else if (lsa->lsa_pattern == LLAPI_LAYOUT_OVERSTRIPING) {
2937                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
2938                 if (rc) {
2939                         fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
2940                                 lsa->lsa_pattern,
2941                                 strerror(errno));
2942                         return rc;
2943                 }
2944         }
2945
2946         size = lsa->lsa_comp_flags & LCME_FL_EXTENSION ?
2947                 lsa->lsa_extension_size : lsa->lsa_stripe_size;
2948
2949         if (lsa->lsa_comp_flags & LCME_FL_EXTENSION)
2950                 rc = llapi_layout_extension_size_set(layout, size);
2951         else
2952                 rc = llapi_layout_stripe_size_set(layout, size);
2953
2954         if (rc) {
2955                 fprintf(stderr, "Set stripe size %lu failed: %s\n",
2956                         size, strerror(errno));
2957                 return rc;
2958         }
2959
2960         rc = llapi_layout_stripe_count_set(layout, lsa->lsa_stripe_count);
2961         if (rc) {
2962                 fprintf(stderr, "Set stripe count %lld failed: %s\n",
2963                         lsa->lsa_stripe_count, strerror(errno));
2964                 return rc;
2965         }
2966
2967         if (lsa->lsa_pool_name) {
2968                 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
2969                 if (rc) {
2970                         fprintf(stderr, "Set pool name: %s failed. %s\n",
2971                                 lsa->lsa_pool_name, strerror(errno));
2972                         return rc;
2973                 }
2974         } else {
2975                 rc = llapi_layout_pool_name_set(layout, "");
2976                 if (rc) {
2977                         fprintf(stderr, "Clear pool name failed: %s\n",
2978                                 strerror(errno));
2979                         return rc;
2980                 }
2981         }
2982
2983         rc = lsa_args_stripe_count_check(lsa);
2984         if (rc)
2985                 return rc;
2986
2987         if (lsa->lsa_nr_tgts > 0) {
2988                 bool found = false;
2989
2990                 for (i = 0; i < lsa->lsa_nr_tgts; i++) {
2991                         rc = llapi_layout_ost_index_set(layout, i,
2992                                                         lsa->lsa_tgts[i]);
2993                         if (rc)
2994                                 break;
2995
2996                         /* Make sure stripe offset is in OST list. */
2997                         if (lsa->lsa_tgts[i] == lsa->lsa_stripe_off)
2998                                 found = true;
2999                 }
3000                 if (!found) {
3001                         fprintf(stderr, "Invalid stripe offset '%lld', not in the target list",
3002                                 lsa->lsa_stripe_off);
3003                         errno = EINVAL;
3004                         return -1;
3005                 }
3006         } else if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT &&
3007                    lsa->lsa_stripe_off != -1) {
3008                 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
3009         }
3010         if (rc) {
3011                 fprintf(stderr, "Set ost index %d failed. %s\n",
3012                         i, strerror(errno));
3013                 return rc;
3014         }
3015
3016         /* Create the second, virtual component of extension space */
3017         if (lsa->lsa_extension_comp) {
3018                 lsa->lsa_comp_flags |= LCME_FL_EXTENSION;
3019                 lsa->lsa_extension_comp = false;
3020                 goto new_comp;
3021         }
3022
3023         return rc;
3024 }
3025
3026 static int build_component(struct llapi_layout **layout,
3027                            struct lfs_setstripe_args *lsa, bool set_extent)
3028 {
3029         int rc;
3030
3031         rc = comp_args_to_layout(layout, lsa, set_extent);
3032         if (rc)
3033                 return rc;
3034
3035         if (lsa->lsa_mirror_count > 0) {
3036                 rc = llapi_layout_mirror_count_set(*layout,
3037                                                    lsa->lsa_mirror_count);
3038                 if (rc)
3039                         return rc;
3040
3041                 rc = llapi_layout_flags_set(*layout, LCM_FL_RDONLY);
3042                 if (rc)
3043                         return rc;
3044                 lsa->lsa_mirror_count = 0;
3045         }
3046
3047         return rc;
3048 }
3049
3050 static int build_prev_component(struct llapi_layout **layout,
3051                                 struct lfs_setstripe_args *prev,
3052                                 struct lfs_setstripe_args *lsa,
3053                                 bool set_extent)
3054 {
3055         int extension = lsa->lsa_comp_flags & LCME_FL_EXTENSION;
3056         int rc;
3057
3058         if (prev->lsa_stripe_size) {
3059                 if (extension) {
3060                         prev->lsa_comp_end = lsa->lsa_comp_end;
3061                         prev->lsa_extension_size = lsa->lsa_extension_size;
3062                         prev->lsa_extension_comp = true;
3063                 }
3064
3065                 rc = build_component(layout, prev, true);
3066                 if (rc)
3067                         return rc;
3068         }
3069
3070         /*
3071          * Copy lsa to previous lsa;
3072          * if this is an extension component, make the previous invalid;
3073          */
3074         if (extension)
3075                 prev->lsa_stripe_size = 0;
3076         else
3077                 *prev = *lsa;
3078
3079         return 0;
3080 }
3081
3082 #ifndef LCME_TEMPLATE_FLAGS
3083 #define LCME_TEMPLATE_FLAGS     (LCME_FL_PREF_RW | LCME_FL_NOSYNC | \
3084                                  LCME_FL_EXTENSION)
3085 #endif
3086
3087 static int build_layout_from_yaml_node(struct cYAML *node,
3088                                        struct llapi_layout **layout,
3089                                        struct lfs_setstripe_args *lsa,
3090                                        struct lfs_setstripe_args *prevp)
3091 {
3092         struct lfs_setstripe_args prev = { 0 };
3093         __u32 *osts = lsa->lsa_tgts;
3094         char *string;
3095         int rc = 0;
3096
3097         if (!prevp)
3098                 prevp = &prev;
3099
3100         while (node) {
3101                 string = node->cy_string;
3102
3103                 if (node->cy_type == CYAML_TYPE_OBJECT) {
3104                         /* go deep to sub blocks */
3105                         if (string && !strncmp(string, "component", 9) &&
3106                             strncmp(string, "component0", 10) &&
3107                             strncmp(string, "components", 10)) {
3108                                 rc = build_prev_component(layout, prevp, lsa,
3109                                                           true);
3110                                 if (rc)
3111                                         return rc;
3112
3113                                 /* initialize lsa. */
3114                                 setstripe_args_init(lsa);
3115                                 lsa->lsa_first_comp = false;
3116                                 lsa->lsa_tgts = osts;
3117                         }
3118
3119                         rc = build_layout_from_yaml_node(node->cy_child, layout,
3120                                                          lsa, prevp);
3121                         if (rc)
3122                                 return rc;
3123                 } else {
3124                         if (!node->cy_string)
3125                                 return -EINVAL;
3126
3127                         /* skip leading lmm_ if present, to simplify parsing */
3128                         if (strncmp(string, "lmm_", 4) == 0)
3129                                 string += 4;
3130
3131                         if (node->cy_type == CYAML_TYPE_STRING) {
3132                                 if (!strcmp(string, "lcme_extent.e_end")) {
3133                                         if (!strcmp(node->cy_valuestring, "EOF") ||
3134                                             !strcmp(node->cy_valuestring, "eof"))
3135                                                 lsa->lsa_comp_end = LUSTRE_EOF;
3136                                 } else if (!strcmp(string, "pool")) {
3137                                         lsa->lsa_pool_name = node->cy_valuestring;
3138                                 } else if (!strcmp(string, "pattern")) {
3139                                         if (!strcmp(node->cy_valuestring, "mdt"))
3140                                                 lsa->lsa_pattern = LLAPI_LAYOUT_MDT;
3141                                         if (!strcmp(node->cy_valuestring,
3142                                                     "raid0,overstriped"))
3143                                                 lsa->lsa_pattern =
3144                                                         LLAPI_LAYOUT_OVERSTRIPING;
3145                                 } else if (!strcmp(string, "lcme_flags")) {
3146                                         rc = comp_str2flags(node->cy_valuestring,
3147                                                             &lsa->lsa_comp_flags,
3148                                                             &lsa->lsa_comp_neg_flags);
3149                                         if (rc)
3150                                                 return rc;
3151                                         /*
3152                                          * Only template flags have meaning in
3153                                          * the layout for a new file
3154                                          */
3155                                         lsa->lsa_comp_flags &= LCME_TEMPLATE_FLAGS;
3156                                 }
3157                         } else if (node->cy_type == CYAML_TYPE_NUMBER) {
3158                                 if (!strcmp(string, "lcm_mirror_count")) {
3159                                         lsa->lsa_mirror_count = node->cy_valueint;
3160                                 } else if (!strcmp(string, "lcme_extent.e_start")) {
3161                                         if (node->cy_valueint == 0)
3162                                                 lsa->lsa_first_comp = true;
3163                                 } else if (!strcmp(string, "lcme_extent.e_end")) {
3164                                         if (node->cy_valueint == -1)
3165                                                 lsa->lsa_comp_end = LUSTRE_EOF;
3166                                         else
3167                                                 lsa->lsa_comp_end = node->cy_valueint;
3168                                 } else if (!strcmp(string, "stripe_count")) {
3169                                         lsa->lsa_stripe_count = node->cy_valueint;
3170                                 } else if (!strcmp(string, "stripe_size")) {
3171                                         lsa->lsa_stripe_size = node->cy_valueint;
3172                                 } else if (!strcmp(string, "extension_size")) {
3173                                         lsa->lsa_extension_size = node->cy_valueint;
3174                                         lsa->lsa_extension_comp = true;
3175                                 } else if (!strcmp(string, "stripe_offset")) {
3176                                         lsa->lsa_stripe_off = node->cy_valueint;
3177                                 } else if (!strcmp(string, "l_ost_idx")) {
3178                                         osts[lsa->lsa_nr_tgts] = node->cy_valueint;
3179                                         lsa->lsa_nr_tgts++;
3180                                 }
3181                         }
3182                 }
3183                 node = node->cy_next;
3184         }
3185
3186         if (prevp == &prev) {
3187                 rc = build_prev_component(layout, prevp, lsa, true);
3188                 if (rc)
3189                         return rc;
3190
3191                 if (!(lsa->lsa_comp_flags & LCME_FL_EXTENSION))
3192                         rc = build_component(layout, lsa, *layout != NULL);
3193         }
3194
3195         return rc;
3196 }
3197
3198 static int lfs_comp_create_from_yaml(char *template,
3199                                      struct llapi_layout **layout,
3200                                      struct lfs_setstripe_args *lsa,
3201                                      __u32 *osts)
3202 {
3203         struct cYAML *tree = NULL, *err_rc = NULL;
3204         int rc = 0;
3205
3206         tree = cYAML_build_tree(template, NULL, 0, &err_rc, false);
3207         if (!tree) {
3208                 fprintf(stderr, "%s: cannot parse YAML file %s\n",
3209                         progname, template);
3210                 cYAML_build_error(-EINVAL, -1, "yaml", "from comp yaml",
3211                                   "can't parse", &err_rc);
3212                 cYAML_print_tree2file(stderr, err_rc);
3213                 cYAML_free_tree(err_rc);
3214                 rc = -EINVAL;
3215                 goto err;
3216         }
3217
3218         /* initialize lsa for plain file */
3219         setstripe_args_init(lsa);
3220         lsa->lsa_tgts = osts;
3221
3222         rc = build_layout_from_yaml_node(tree, layout, lsa, NULL);
3223         if (rc) {
3224                 fprintf(stderr, "%s: cannot build layout from YAML file %s.\n",
3225                         progname, template);
3226                 goto err;
3227         }
3228         /* clean clean lsa */
3229         setstripe_args_init(lsa);
3230
3231 err:
3232         if (tree)
3233                 cYAML_free_tree(tree);
3234         return rc;
3235 }
3236
3237 /**
3238  * Get the extension size from the next (SEL) component and extend the
3239  * current component on it. The start of the next component is to be
3240  * adjusted as well.
3241  *
3242  * \param[in] layout    the current layout
3243  * \param[in] start     the start of the current component
3244  * \param[in,out] end   the end of the current component
3245  * \param[in] offset    the offset to adjust the end position to instead of
3246  *                      extension size
3247  *
3248  * \retval 0            - extended successfully
3249  * \retval < 0          - error
3250  */
3251 static int layout_extend_comp(struct llapi_layout *layout,
3252                               uint64_t start, uint64_t *end,
3253                               uint64_t offset)
3254 {
3255         uint64_t size, next_start, next_end;
3256         int rc;
3257
3258         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
3259         if (rc < 0) {
3260                 fprintf(stderr,
3261                         "%s setstripe: cannot move component cursor: %s\n",
3262                         progname, strerror(errno));
3263                 return rc;
3264         }
3265
3266         /*
3267          * Even if the @size will not be used below, this will fail if
3268          * this is not a SEL component - a good confirmation we are
3269          * working on right components.
3270          */
3271         rc = llapi_layout_extension_size_get(layout, &size);
3272         if (rc < 0) {
3273                 fprintf(stderr,
3274                         "%s setstripe: cannot get component ext size: %s\n",
3275                         progname, strerror(errno));
3276                 return rc;
3277         }
3278
3279         rc = llapi_layout_comp_extent_get(layout, &next_start, &next_end);
3280         if (rc) {
3281                 fprintf(stderr, "%s setstripe: cannot get extent: %s\n",
3282                         progname, strerror(errno));
3283                 return rc;
3284         }
3285
3286         next_start += offset ?: size;
3287         rc = llapi_layout_comp_extent_set(layout, next_start, next_end);
3288         if (rc) {
3289                 fprintf(stderr, "%s setstripe: cannot set extent: %s\n",
3290                         progname, strerror(errno));
3291                 return rc;
3292         }
3293
3294         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_PREV);
3295         if (rc < 0) {
3296                 fprintf(stderr,
3297                         "%s setstripe: cannot move component cursor: %s\n",
3298                         progname, strerror(errno));
3299                 return rc;
3300         }
3301
3302         *end += offset ?: size;
3303         rc = llapi_layout_comp_extent_set(layout, start, *end);
3304         if (rc) {
3305                 fprintf(stderr, "%s setstripe: cannot set extent: %s\n",
3306                         progname, strerror(errno));
3307                 return rc;
3308         }
3309
3310         return 0;
3311 }
3312
3313 /**
3314  * In 'lfs setstripe --component-add' mode, we need to fetch the extent
3315  * end of the last component in the existing file, and adjust the
3316  * first extent start of the components to be added accordingly.
3317  *
3318  * In the create mode, we need to check if the first component is an extendable
3319  * SEL component and extend its length to the extension size (first component
3320  * of the PFL file is initialised at the create time, cannot be 0-lenght.
3321  */
3322 static int layout_adjust_first_extent(char *fname, struct llapi_layout *layout,
3323                                       bool comp_add)
3324 {
3325         struct llapi_layout *head;
3326         uint64_t start = 0, prev_end = 0;
3327         uint64_t end;
3328         int rc, ret = 0;
3329
3330         if (!layout || !(comp_add || llapi_layout_is_composite(layout)))
3331                 return 0;
3332
3333         errno = 0;
3334         while (comp_add) {
3335                 head = llapi_layout_get_by_path(fname, 0);
3336                 if (!head) {
3337                         fprintf(stderr,
3338                                 "%s setstripe: cannot read layout from '%s': %s\n",
3339                                 progname, fname, strerror(errno));
3340                         return -EINVAL;
3341                 } else if (errno == ENODATA) {
3342                         /*
3343                          * file without LOVEA, this component-add will be turned
3344                          * into a component-create.
3345                          */
3346                         llapi_layout_free(head);
3347                         ret = -ENODATA;
3348
3349                         /*
3350                          * the new layout will be added to an empty one, it
3351                          * still needs to be adjusted below
3352                          */
3353                         comp_add = 0;
3354                         break;
3355                 } else if (!llapi_layout_is_composite(head)) {
3356                         fprintf(stderr,
3357                                 "%s setstripe: '%s' not a composite file\n",
3358                                 progname, fname);
3359                         llapi_layout_free(head);
3360                         return -EINVAL;
3361                 }
3362
3363                 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
3364                 if (rc) {
3365                         fprintf(stderr,
3366                                 "%s setstripe: cannot get prev extent: %s\n",
3367                                 progname, strerror(errno));
3368                         llapi_layout_free(head);
3369                         return rc;
3370                 }
3371
3372                 llapi_layout_free(head);
3373                 break;
3374         }
3375
3376         /* Make sure we use the first component of the layout to be added. */
3377         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
3378         if (rc < 0) {
3379                 fprintf(stderr,
3380                         "%s setstripe: cannot move component cursor: %s\n",
3381                         progname, strerror(errno));
3382                 return rc;
3383         }
3384
3385         rc = llapi_layout_comp_extent_get(layout, &start, &end);
3386         if (rc) {
3387                 fprintf(stderr, "%s setstripe: cannot get extent: %s\n",
3388                         progname, strerror(errno));
3389                 return rc;
3390         }
3391
3392         if (start == 0 && end == 0) {
3393                 rc = layout_extend_comp(layout, start, &end,
3394                                         comp_add ? prev_end : 0);
3395                 if (rc)
3396                         return rc;
3397         }
3398
3399         if (start > prev_end || end < prev_end) {
3400                 fprintf(stderr,
3401                         "%s setstripe: first extent [%lu, %lu) not adjacent with extent end %lu\n",
3402                         progname, start, end, prev_end);
3403                 return -EINVAL;
3404         }
3405
3406         rc = llapi_layout_comp_extent_set(layout, prev_end, end);
3407         if (rc) {
3408                 fprintf(stderr,
3409                         "%s setstripe: cannot set component extent [%lu, %lu): %s\n",
3410                         progname, prev_end, end, strerror(errno));
3411                 return rc;
3412         }
3413
3414         return ret;
3415 }
3416
3417 static int mirror_adjust_first_extents(struct mirror_args *list)
3418 {
3419         int rc = 0;
3420
3421         if (!list)
3422                 return 0;
3423
3424         while (list) {
3425                 rc = layout_adjust_first_extent(NULL, list->m_layout, false);
3426                 if (rc)
3427                         break;
3428                 list = list->m_next;
3429         }
3430
3431         return rc;
3432 }
3433
3434 static inline bool arg_is_eof(char *arg)
3435 {
3436         return !strncmp(arg, "-1", strlen("-1")) ||
3437                !strncmp(arg, "EOF", strlen("EOF")) ||
3438                !strncmp(arg, "eof", strlen("eof"));
3439 }
3440
3441 /**
3442  * lfs_mirror_alloc() - Allocate a mirror argument structure.
3443  *
3444  * Return: Valid mirror_args pointer on success and
3445  *         NULL if memory allocation fails.
3446  */
3447 static struct mirror_args *lfs_mirror_alloc(void)
3448 {
3449         struct mirror_args *mirror = NULL;
3450
3451         while (1) {
3452                 mirror = calloc(1, sizeof(*mirror));
3453                 if (mirror) {
3454                         mirror->m_inherit = false;
3455                         break;
3456                 }
3457
3458                 sleep(1);
3459         }
3460
3461         return mirror;
3462 }
3463
3464 /**
3465  * lfs_mirror_free() - Free memory allocated for a mirror argument
3466  *                     structure.
3467  * @mirror: Previously allocated mirror argument structure by
3468  *          lfs_mirror_alloc().
3469  *
3470  * Free memory allocated for @mirror.
3471  *
3472  * Return: void.
3473  */
3474 static void lfs_mirror_free(struct mirror_args *mirror)
3475 {
3476         if (mirror->m_layout)
3477                 llapi_layout_free(mirror->m_layout);
3478         free(mirror);
3479 }
3480
3481 /**
3482  * lfs_mirror_list_free() - Free memory allocated for a mirror list.
3483  * @mirror_list: Previously allocated mirror list.
3484  *
3485  * Free memory allocated for @mirror_list.
3486  *
3487  * Return: void.
3488  */
3489 static void lfs_mirror_list_free(struct mirror_args *mirror_list)
3490 {
3491         struct mirror_args *next_mirror = NULL;
3492
3493         while (mirror_list) {
3494                 next_mirror = mirror_list->m_next;
3495                 lfs_mirror_free(mirror_list);
3496                 mirror_list = next_mirror;
3497         }
3498 }
3499
3500 enum {
3501         LFS_SETQUOTA_DELETE = (CHAR_MAX + 1),
3502         LFS_POOL_OPT,
3503         LFS_COMP_COUNT_OPT,
3504         LFS_COMP_START_OPT,
3505         LFS_COMP_FLAGS_OPT,
3506         LFS_COMP_DEL_OPT,
3507         LFS_COMP_SET_OPT,
3508         LFS_COMP_ADD_OPT,
3509         LFS_COMP_NO_VERIFY_OPT,
3510         LFS_PROJID_OPT,
3511         LFS_LAYOUT_FLAGS_OPT, /* used for mirror and foreign flags */
3512         LFS_MIRROR_ID_OPT,
3513         LFS_MIRROR_STATE_OPT,
3514         LFS_LAYOUT_COPY,
3515         LFS_MIRROR_INDEX_OPT,
3516         LFS_LAYOUT_FOREIGN_OPT,
3517         LFS_MODE_OPT,
3518         LFS_NEWERXY_OPT,
3519         LFS_INHERIT_RR_OPT,
3520         LFS_FIND_PERM,
3521         LFS_PRINTF_OPT,
3522         LFS_NO_FOLLOW_OPT,
3523         LFS_HEX_IDX_OPT,
3524         LFS_STATS_OPT,
3525         LFS_STATS_INTERVAL_OPT,
3526         LFS_LINKS_OPT,
3527         LFS_ATTRS_OPT
3528 };
3529
3530 #ifndef LCME_USER_MIRROR_FLAGS
3531 /* The mirror flags can be set by users at creation time. */
3532 #define LCME_USER_MIRROR_FLAGS  (LCME_FL_PREF_RW)
3533 #endif
3534
3535 /* functions */
3536 static int lfs_setstripe_internal(int argc, char **argv,
3537                                   enum setstripe_origin opc)
3538 {
3539         struct lfs_setstripe_args        lsa = { 0 };
3540         struct llapi_stripe_param       *param = NULL;
3541         struct find_param                migrate_mdt_param = {
3542                 .fp_max_depth = -1,
3543                 .fp_mdt_index = -1,
3544         };
3545         char                            *fname;
3546         int                              result = 0;
3547         int                              result2 = 0;
3548         char                            *end;
3549         int                              c;
3550         int                              delete = 0;
3551         unsigned long long               size_units = 1;
3552         bool                             migrate_mode = false;
3553         bool                             migrate_mdt_mode = false;
3554         bool                             setstripe_mode = false;
3555         bool                             migration_block = false;
3556         __u64                            migration_flags = 0;
3557         __u32                            tgts[LOV_MAX_STRIPE_COUNT] = { 0 };
3558         int                              comp_del = 0, comp_set = 0;
3559         int                              comp_add = 0;
3560         __u32                            comp_id = 0;
3561         struct llapi_layout             *layout = NULL;
3562         struct llapi_layout             **lpp = &layout;
3563         bool                             mirror_mode = false;
3564         bool                             has_m_file = false;
3565         __u32                            mirror_count = 0;
3566         enum mirror_flags                mirror_flags = 0;
3567         struct mirror_args              *mirror_list = NULL;
3568         struct mirror_args              *new_mirror = NULL;
3569         struct mirror_args              *last_mirror = NULL;
3570         __u16                            mirror_id = 0;
3571         char                             cmd[PATH_MAX];
3572         bool from_yaml = false;
3573         bool from_copy = false;
3574         char *template = NULL;
3575         bool foreign_mode = false;
3576         char *xattr = NULL;
3577         uint32_t type = LU_FOREIGN_TYPE_NONE, flags = 0;
3578         char *mode_opt = NULL;
3579         mode_t previous_umask = 0;
3580         mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
3581         unsigned long long bandwidth_bytes_sec = 0;
3582         unsigned long long bandwidth_unit = ONE_MB;
3583         long stats_interval_sec = 0;
3584
3585         struct option long_opts[] = {
3586 /* find { .val = '0',   .name = "null",         .has_arg = no_argument }, */
3587 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
3588         /* --block is only valid in migrate mode */
3589         { .val = 'b',   .name = "block",        .has_arg = no_argument },
3590 /* find { .val = 'B',   .name = "btime",        .has_arg = required_argument }*/
3591         { .val = LFS_COMP_ADD_OPT,
3592                         .name = "comp-add",     .has_arg = no_argument },
3593         { .val = LFS_COMP_ADD_OPT,
3594                         .name = "component-add", .has_arg = no_argument },
3595         { .val = LFS_COMP_DEL_OPT,
3596                         .name = "comp-del",     .has_arg = no_argument },
3597         { .val = LFS_COMP_DEL_OPT,
3598                         .name = "component-del", .has_arg = no_argument },
3599         { .val = LFS_COMP_FLAGS_OPT,
3600                         .name = "comp-flags",   .has_arg = required_argument },
3601         { .val = LFS_COMP_FLAGS_OPT,
3602                         .name = "component-flags",
3603                                                 .has_arg = required_argument },
3604         { .val = LFS_COMP_SET_OPT,
3605                         .name = "comp-set",     .has_arg = no_argument },
3606         { .val = LFS_COMP_SET_OPT,
3607                         .name = "component-set",
3608                                                 .has_arg = no_argument},
3609         { .val = LFS_COMP_NO_VERIFY_OPT,
3610                         .name = "no-verify",    .has_arg = no_argument},
3611         { .val = LFS_LAYOUT_FLAGS_OPT,
3612                         .name = "flags",        .has_arg = required_argument},
3613         { .val = LFS_LAYOUT_FOREIGN_OPT,
3614                         .name = "foreign",      .has_arg = optional_argument},
3615         { .val = LFS_MIRROR_ID_OPT,
3616                         .name = "mirror-id",    .has_arg = required_argument},
3617         { .val = LFS_MODE_OPT,
3618                         .name = "mode",         .has_arg = required_argument},
3619         { .val = LFS_LAYOUT_COPY,
3620                         .name = "copy",         .has_arg = required_argument},
3621         { .val = LFS_STATS_OPT,
3622                         .name = "stats",        .has_arg = no_argument},
3623         { .val = LFS_STATS_INTERVAL_OPT,
3624                         .name = "stats-interval",
3625                                                 .has_arg = required_argument},
3626         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument},
3627         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument},
3628         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument},
3629         { .val = 'C',   .name = "overstripe-count",
3630                                                 .has_arg = required_argument},
3631         { .val = 'd',   .name = "delete",       .has_arg = no_argument},
3632         { .val = 'd',   .name = "destroy",      .has_arg = no_argument},
3633         /* used with "lfs migrate -m" */
3634         { .val = 'd',   .name = "directory",    .has_arg = no_argument},
3635         /* --non-direct is only valid in migrate mode */
3636         { .val = 'D',   .name = "non-direct",   .has_arg = no_argument },
3637         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument},
3638         { .val = 'E',   .name = "component-end",
3639                                                 .has_arg = required_argument},
3640         { .val = 'f',   .name = "file",         .has_arg = required_argument },
3641 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
3642 /* find { .val = 'g',   .name = "gid",          .has_arg = no_argument }, */
3643 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
3644         { .val = 'h',   .name = "help",         .has_arg = no_argument },
3645         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument},
3646         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument},
3647         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument},
3648         { .val = 'I',   .name = "comp-id",      .has_arg = required_argument},
3649         { .val = 'I',   .name = "component-id", .has_arg = required_argument},
3650 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
3651         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
3652         { .val = 'm',   .name = "mdt",          .has_arg = required_argument},
3653         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument},
3654         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument},
3655         /* --non-block is only valid in migrate mode */
3656         { .val = 'n',   .name = "non-block",    .has_arg = no_argument },
3657         { .val = 'N',   .name = "mirror-count", .has_arg = optional_argument},
3658         { .val = 'o',   .name = "ost",          .has_arg = required_argument },
3659 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3660         { .val = 'o',   .name = "ost-list",     .has_arg = required_argument },
3661         { .val = 'o',   .name = "ost_list",     .has_arg = required_argument },
3662 #endif
3663         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
3664 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
3665 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
3666 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
3667         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
3668         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
3669 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
3670 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
3671 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
3672 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
3673         /* --verbose is only valid in migrate mode */
3674         { .val = 'v',   .name = "verbose",      .has_arg = no_argument},
3675         { .val = 'W',   .name = "bandwidth",    .has_arg = required_argument },
3676         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
3677 /* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/
3678         { .val = 'y',   .name = "yaml",         .has_arg = required_argument },
3679         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument},
3680         { .val = 'z',   .name = "extension-size", .has_arg = required_argument},
3681         { .name = NULL } };
3682
3683         setstripe_args_init(&lsa);
3684
3685         migrate_mode = (opc == SO_MIGRATE);
3686         mirror_mode = (opc == SO_MIRROR_CREATE || opc == SO_MIRROR_EXTEND);
3687         setstripe_mode = (opc == SO_SETSTRIPE);
3688         if (opc == SO_MIRROR_DELETE) {
3689                 delete = 1;
3690                 mirror_flags = MF_DESTROY;
3691         }
3692
3693         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
3694         progname = cmd;
3695         while ((c = getopt_long(argc, argv,
3696                                 "bc:C:dDE:f:hH:i:I:m:N::no:p:L:s:S:vx:W:y:z:",
3697                                 long_opts, NULL)) >= 0) {
3698                 size_units = 1;
3699                 switch (c) {
3700                 case 0:
3701                         /* Long options. */
3702                         break;
3703                 case LFS_COMP_ADD_OPT:
3704                         comp_add = 1;
3705                         break;
3706                 case LFS_COMP_DEL_OPT:
3707                         comp_del = 1;
3708                         break;
3709                 case LFS_COMP_FLAGS_OPT:
3710                         result = comp_str2flags(optarg, &lsa.lsa_comp_flags,
3711                                                 &lsa.lsa_comp_neg_flags);
3712                         if (result != 0)
3713                                 goto usage_error;
3714                         if (mirror_mode && lsa.lsa_comp_neg_flags) {
3715                                 fprintf(stderr,
3716                                         "%s: inverted flags are not supported\n",
3717                                         progname);
3718                                 goto usage_error;
3719                         }
3720                         break;
3721                 case LFS_COMP_SET_OPT:
3722                         comp_set = 1;
3723                         break;
3724                 case LFS_COMP_NO_VERIFY_OPT:
3725                         mirror_flags |= MF_NO_VERIFY;
3726                         break;
3727                 case LFS_MIRROR_ID_OPT: {
3728                         unsigned long int id;
3729
3730                         errno = 0;
3731                         id = strtoul(optarg, &end, 0);
3732                         if (errno != 0 || *end != '\0' || id == 0 ||
3733                             id > UINT16_MAX) {
3734                                 fprintf(stderr,
3735                                         "%s %s: invalid mirror ID '%s'\n",
3736                                         progname, argv[0], optarg);
3737                                 goto usage_error;
3738                         }
3739
3740                         mirror_id = (__u16)id;
3741                         break;
3742                 }
3743                 case LFS_LAYOUT_FLAGS_OPT: {
3744                         uint32_t neg_flags;
3745
3746                         /* check for numeric flags (foreign and mirror cases) */
3747                         if (setstripe_mode && !mirror_mode && !last_mirror) {
3748                                 errno = 0;
3749                                 flags = strtoul(optarg, &end, 16);
3750                                 if (errno != 0 || *end != '\0' ||
3751                                     flags >= UINT32_MAX) {
3752                                         fprintf(stderr,
3753                                                 "%s %s: invalid hex flags '%s'\n",
3754                                                 progname, argv[0], optarg);
3755                                         return CMD_HELP;
3756                                 }
3757                                 if (!foreign_mode) {
3758                                         fprintf(stderr,
3759                                                 "%s %s: hex flags must be specified with --foreign option\n",
3760                                                 progname, argv[0]);
3761                                         return CMD_HELP;
3762                                 }
3763                                 break;
3764                         }
3765
3766                         if (!mirror_mode || !last_mirror) {
3767                                 fprintf(stderr,
3768                                         "error: %s: --flags must be specified with --mirror-count|-N option\n",
3769                                         progname);
3770                                 goto usage_error;
3771                         }
3772
3773                         result = comp_str2flags(optarg, &last_mirror->m_flags,
3774                                                 &neg_flags);
3775                         if (result != 0)
3776                                 goto usage_error;
3777
3778                         if (neg_flags) {
3779                                 fprintf(stderr,
3780                                         "%s: inverted flags are not supported\n",
3781                                         progname);
3782                                 result = -EINVAL;
3783                                 goto usage_error;
3784                         }
3785                         if (last_mirror->m_flags & ~LCME_USER_MIRROR_FLAGS) {
3786                                 fprintf(stderr,
3787                                         "%s: unsupported mirror flags: %s\n",
3788                                         progname, optarg);
3789                                 result = -EINVAL;
3790                                 goto error;
3791                         }
3792                         break;
3793                 }
3794                 case LFS_LAYOUT_FOREIGN_OPT:
3795                         if (optarg) {
3796                                 /* check pure numeric */
3797                                 type = strtoul(optarg, &end, 0);
3798                                 if (*end) {
3799                                         /* check name */
3800                                         type = check_foreign_type_name(optarg);
3801                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
3802                                                 fprintf(stderr,
3803                                                         "%s %s: unrecognized foreign type '%s'\n",
3804                                                         progname, argv[0],
3805                                                         optarg);
3806                                                 return CMD_HELP;
3807                                         }
3808                                 } else if (type >= UINT32_MAX) {
3809                                         fprintf(stderr,
3810                                                 "%s %s: invalid foreign type '%s'\n",
3811                                                 progname, argv[0], optarg);
3812                                         return CMD_HELP;
3813                                 }
3814                         }
3815                         foreign_mode = true;
3816                         break;
3817                 case LFS_MODE_OPT:
3818                         mode_opt = optarg;
3819                         if (mode_opt) {
3820                                 mode = strtoul(mode_opt, &end, 8);
3821                                 if (*end != '\0') {
3822                                         fprintf(stderr,
3823                                                 "%s %s: bad mode '%s'\n",
3824                                                 progname, argv[0], mode_opt);
3825                                         return CMD_HELP;
3826                                 }
3827                                 previous_umask = umask(0);
3828                         }
3829                         break;
3830                 case LFS_LAYOUT_COPY:
3831                         from_copy = true;
3832                         template = optarg;
3833                         break;
3834                 case LFS_STATS_OPT:
3835                         stats_interval_sec = 5;
3836                         break;
3837                 case LFS_STATS_INTERVAL_OPT:
3838                         stats_interval_sec = strtol(optarg, &end, 0);
3839                         if (stats_interval_sec == 0 && errno) {
3840                                 fprintf(stderr,
3841                                         "%s %s: invalid stats interval %s\n",
3842                                         progname, argv[0], optarg);
3843                                 goto usage_error;
3844                         }
3845                         break;
3846                 case 'b':
3847                         if (!migrate_mode) {
3848                                 fprintf(stderr,
3849                                         "%s %s: -b|--block valid only for migrate command\n",
3850                                         progname, argv[0]);
3851                                 goto usage_error;
3852                         }
3853                         migration_block = true;
3854                         break;
3855                 case 'C':
3856                         if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) {
3857                                 fprintf(stderr,
3858                                         "%s %s: -C|--overstripe-count incompatible with DoM layout\n",
3859                                         progname, argv[0]);
3860                                 goto usage_error;
3861                         }
3862                         lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
3863                         fallthrough;
3864                 case 'c':
3865                         errno = 0;
3866                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
3867                         if (errno != 0 || *end != '\0'|| optarg == end ||
3868                             lsa.lsa_stripe_count < -1 ||
3869                             lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
3870                                 fprintf(stderr,
3871                                         "%s %s: invalid stripe count '%s'\n",
3872                                         progname, argv[0], optarg);
3873                                 goto usage_error;
3874                         }
3875
3876                         if (lsa.lsa_stripe_count == -1)
3877                                 lsa.lsa_stripe_count = LLAPI_LAYOUT_WIDE;
3878                         break;
3879                 case 'd':
3880                         if (migrate_mode) {
3881                                 migrate_mdt_param.fp_max_depth = 1;
3882                         } else {
3883                                 /* delete the default striping pattern */
3884                                 delete = 1;
3885                                 if (opc == SO_MIRROR_SPLIT) {
3886                                         if (has_m_file) {
3887                                                 fprintf(stderr,
3888                                                       "%s %s: -d cannot used with -f\n",
3889                                                         progname, argv[0]);
3890                                                 goto usage_error;
3891                                         }
3892                                         mirror_flags |= MF_DESTROY;
3893                                 }
3894                         }
3895                         break;
3896                 case 'D':
3897                         if (!migrate_mode) {
3898                                 fprintf(stderr,
3899                                         "%s %s: -D|--non-direct is valid only for migrate command\n",
3900                                         progname, argv[0]);
3901                                 goto usage_error;
3902                         }
3903                         migration_flags |= LLAPI_MIGRATION_NONDIRECT;
3904                         break;
3905                 case 'E':
3906                         if (lsa.lsa_comp_end != 0) {
3907                                 result = comp_args_to_layout(lpp, &lsa, true);
3908                                 if (result) {
3909                                         fprintf(stderr, "%s: invalid layout\n",
3910                                                 progname);
3911                                         goto usage_error;
3912                                 }
3913
3914                                 setstripe_args_init_inherit(&lsa);
3915                         }
3916
3917                         if (arg_is_eof(optarg)) {
3918                                 lsa.lsa_comp_end = LUSTRE_EOF;
3919                         } else {
3920                                 result = llapi_parse_size(optarg,
3921                                                           &lsa.lsa_comp_end,
3922                                                           &size_units, 0);
3923                                 /* assume units of KB if too small */
3924                                 if (lsa.lsa_comp_end < 4096)
3925                                         lsa.lsa_comp_end *= 1024;
3926                                 if (result ||
3927                                     lsa.lsa_comp_end & (LOV_MIN_STRIPE_SIZE - 1)) {
3928                                         fprintf(stderr,
3929                                                 "%s %s: invalid component end '%s'\n",
3930                                                 progname, argv[0], optarg);
3931                                         goto usage_error;
3932                                 }
3933                         }
3934                         break;
3935                 case 'H':
3936                         if (!migrate_mode) {
3937                                 fprintf(stderr,
3938                                         "--mdt-hash is valid only for migrate command\n");
3939                                 return CMD_HELP;
3940                         }
3941
3942                         lsa.lsa_pattern = check_hashtype(optarg);
3943                         if (lsa.lsa_pattern == 0) {
3944                                 fprintf(stderr,
3945                                         "%s %s: bad stripe hash type '%s'\n",
3946                                         progname, argv[0], optarg);
3947                                 return CMD_HELP;
3948                         }
3949                         break;
3950                 case 'i':
3951                         errno = 0;
3952                         lsa.lsa_stripe_off = strtol(optarg, &end, 0);
3953                         if (errno != 0 || *end != '\0' || optarg == end ||
3954                             lsa.lsa_stripe_off < -1 ||
3955                             lsa.lsa_stripe_off > LOV_V1_INSANE_STRIPE_COUNT) {
3956                                 fprintf(stderr,
3957                                         "%s %s: invalid stripe offset '%s'\n",
3958                                         progname, argv[0], optarg);
3959                                 goto usage_error;
3960                         }
3961                         if (lsa.lsa_stripe_off == -1)
3962                                 lsa.lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
3963                         break;
3964                 case 'I':
3965                         comp_id = strtoul(optarg, &end, 0);
3966                         if (*end != '\0' || comp_id == 0 ||
3967                             comp_id > LCME_ID_MAX) {
3968                                 fprintf(stderr,
3969                                         "%s %s: invalid component ID '%s'\n",
3970                                         progname, argv[0], optarg);
3971                                 goto usage_error;
3972                         }
3973                         break;
3974                 case 'f':
3975                         if (opc != SO_MIRROR_EXTEND && opc != SO_MIRROR_SPLIT) {
3976                                 fprintf(stderr,
3977                                         "error: %s: invalid option: %s\n",
3978                                         progname, argv[optopt + 1]);
3979                                 goto usage_error;
3980                         }
3981                         if (opc == SO_MIRROR_EXTEND) {
3982                                 if (!last_mirror) {
3983                                         fprintf(stderr,
3984                                 "error: %s: '-N' must exist in front of '%s'\n",
3985                                                 progname, argv[optopt + 1]);
3986                                         goto usage_error;
3987                                 }
3988                                 last_mirror->m_file = optarg;
3989                                 last_mirror->m_count = 1;
3990                         } else {
3991                                 /* mirror split */
3992                                 if (!mirror_list)
3993                                         mirror_list = lfs_mirror_alloc();
3994                                 mirror_list->m_file = optarg;
3995                         }
3996                         has_m_file = true;
3997                         break;
3998                 case 'L':
3999                         if (strcmp(argv[optind - 1], "mdt") == 0) {
4000                                 /* Can be only the first component */
4001                                 if (layout) {
4002                                         result = -EINVAL;
4003                                         fprintf(stderr,
4004                                                 "error: 'mdt' layout can be only the first one\n");
4005                                         goto error;
4006                                 }
4007                                 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
4008                                         result = -EFBIG;
4009                                         fprintf(stderr,
4010                                                 "error: 'mdt' layout size is too big\n");
4011                                         goto error;
4012                                 }
4013                                 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
4014                                 lsa.lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
4015                         } else if (strcmp(argv[optind - 1], "raid0") != 0) {
4016                                 result = -EINVAL;
4017                                 fprintf(stderr,
4018                                         "error: layout '%s' is unknown, supported layouts are: 'mdt', 'raid0'\n",
4019                                         argv[optind]);
4020                                 goto error;
4021                         }
4022                         break;
4023                 case 'm':
4024                         if (!migrate_mode) {
4025                                 fprintf(stderr,
4026                                         "%s %s: -m|--mdt-index is valid only for migrate command\n",
4027                                         progname, argv[0]);
4028                                 goto usage_error;
4029                         }
4030                         migrate_mdt_mode = true;
4031                         lsa.lsa_nr_tgts = parse_targets(tgts,
4032                                                 sizeof(tgts) / sizeof(__u32),
4033                                                 lsa.lsa_nr_tgts, optarg, NULL);
4034                         if (lsa.lsa_nr_tgts < 0) {
4035                                 fprintf(stderr,
4036                                         "%s: invalid MDT target(s) '%s'\n",
4037                                         progname, optarg);
4038                                 goto usage_error;
4039                         }
4040
4041                         lsa.lsa_tgts = tgts;
4042                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4043                                 lsa.lsa_stripe_off = tgts[0];
4044                         break;
4045                 case 'n':
4046                         if (!migrate_mode) {
4047                                 fprintf(stderr,
4048                                         "%s %s: -n|--non-block valid only for migrate command\n",
4049                                         progname, argv[0]);
4050                                 goto usage_error;
4051                         }
4052                         migration_flags |= LLAPI_MIGRATION_NONBLOCK;
4053                         break;
4054                 case 'N':
4055                         if (opc == SO_SETSTRIPE) {
4056                                 opc = SO_MIRROR_CREATE;
4057                                 mirror_mode = true;
4058                         }
4059                         mirror_count = 1;
4060                         if (optarg) {
4061                                 errno = 0;
4062                                 mirror_count = strtoul(optarg, &end, 0);
4063                                 if (errno != 0 || *end != '\0' ||
4064                                     mirror_count == 0 ||
4065                                     mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
4066                                         fprintf(stderr,
4067                                                 "error: %s: bad mirror count: %s\n",
4068                                                 progname, optarg);
4069                                         result = -EINVAL;
4070                                         goto error;
4071                                 }
4072                         }
4073
4074                         new_mirror = lfs_mirror_alloc();
4075                         new_mirror->m_count = mirror_count;
4076
4077                         if (!mirror_list)
4078                                 mirror_list = new_mirror;
4079
4080                         if (last_mirror) {
4081                                 /* wrap up last mirror */
4082                                 if (!setstripe_args_specified(&lsa))
4083                                         last_mirror->m_inherit = true;
4084                                 if (lsa.lsa_comp_end == 0)
4085                                         lsa.lsa_comp_end = LUSTRE_EOF;
4086
4087                                 result = comp_args_to_layout(lpp, &lsa, true);
4088                                 if (result) {
4089                                         lfs_mirror_free(new_mirror);
4090                                         goto error;
4091                                 }
4092
4093                                 setstripe_args_init_inherit(&lsa);
4094
4095                                 last_mirror->m_next = new_mirror;
4096                         }
4097
4098                         last_mirror = new_mirror;
4099                         lpp = &last_mirror->m_layout;
4100                         break;
4101                 case 'o':
4102 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
4103                         if (strcmp(argv[optind - 1], "--ost-list") == 0)
4104                                 fprintf(stderr,
4105                                         "warning: '--ost-list' is deprecated, use '--ost' instead\n");
4106 #endif
4107                         if (lsa.lsa_pattern == LLAPI_LAYOUT_MDT) {
4108                                 fprintf(stderr,
4109                                         "%s %s: -o|--ost incompatible with DoM layout\n",
4110                                         progname, argv[0]);
4111                                 goto usage_error;
4112                         }
4113                         /*
4114                          * -o allows overstriping, and must note it because
4115                          * parse_targets is shared with MDT striping, which
4116                          * does not allow duplicates
4117                          */
4118                         lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
4119                         lsa.lsa_nr_tgts = parse_targets(tgts,
4120                                                 sizeof(tgts) / sizeof(__u32),
4121                                                 lsa.lsa_nr_tgts, optarg,
4122                                                 &lsa.lsa_pattern);
4123                         if (lsa.lsa_nr_tgts < 0) {
4124                                 fprintf(stderr,
4125                                         "%s %s: invalid OST target(s) '%s'\n",
4126                                         progname, argv[0], optarg);
4127                                 goto usage_error;
4128                         }
4129
4130                         lsa.lsa_tgts = tgts;
4131                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4132                                 lsa.lsa_stripe_off = tgts[0];
4133                         break;
4134                 case 'p':
4135                         if (!optarg)
4136                                 goto usage_error;
4137
4138                         if (optarg[0] == '\0' || lov_pool_is_inherited(optarg))
4139                                 lsa.lsa_pool_name = NULL;
4140                         else
4141                                 lsa.lsa_pool_name = optarg;
4142                         break;
4143                 case 'S':
4144                         result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
4145                                                   &size_units, 0);
4146                         /* assume units of KB if too small to be valid */
4147                         if (lsa.lsa_stripe_size < 4096)
4148                                 lsa.lsa_stripe_size *= 1024;
4149                         if (result ||
4150                             lsa.lsa_stripe_size & (LOV_MIN_STRIPE_SIZE - 1)) {
4151                                 fprintf(stderr,
4152                                         "%s %s: invalid stripe size '%s'\n",
4153                                         progname, argv[0], optarg);
4154                                 goto usage_error;
4155                         }
4156                         break;
4157                 case 'v':
4158                         if (!migrate_mode) {
4159                                 fprintf(stderr,
4160                                         "%s %s: -v|--verbose valid only for migrate command\n",
4161                                         progname, argv[0]);
4162                                 goto usage_error;
4163                         }
4164                         migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
4165                         migration_flags = LLAPI_MIGRATION_VERBOSE;
4166                         break;
4167                 case 'x':
4168                         xattr = optarg;
4169                         break;
4170                 case 'W':
4171                         if (!migrate_mode && !mirror_mode) {
4172                                 fprintf(stderr,
4173                                         "--bandwidth is valid only for migrate and mirror mode\n");
4174                                 goto error;
4175                         }
4176                         if (llapi_parse_size(optarg, &bandwidth_bytes_sec,
4177                                              &bandwidth_unit, 0) < 0) {
4178                                 fprintf(stderr,
4179                                         "error: %s: bad value for bandwidth '%s'\n",
4180                                         argv[0], optarg);
4181                                 goto error;
4182                         }
4183                         break;
4184                 case 'y':
4185                         from_yaml = true;
4186                         template = optarg;
4187                         break;
4188                 case 'z':
4189                         result = llapi_parse_size(optarg,
4190                                                   &lsa.lsa_extension_size,
4191                                                   &size_units, 0);
4192                         if (result) {
4193                                 fprintf(stderr,
4194                                         "%s %s: invalid extension size '%s'\n",
4195                                         progname, argv[0], optarg);
4196                                 goto usage_error;
4197                         }
4198
4199                         lsa.lsa_extension_comp = true;
4200                         break;
4201                 default:
4202                         fprintf(stderr, "%s: unrecognized option '%s'\n",
4203                                 progname, argv[optind - 1]);
4204                 case 'h':
4205                         goto usage_error;
4206                 }
4207         }
4208
4209         fname = argv[optind];
4210
4211         if (optind == argc) {
4212                 fprintf(stderr, "%s %s: FILE must be specified\n",
4213                         progname, argv[0]);
4214                 goto usage_error;
4215         }
4216
4217         /* lfs migrate $filename should keep the file's layout by default */
4218         if (migrate_mode && !layout && !from_yaml &&
4219             !setstripe_args_specified(&lsa) && !lsa.lsa_pool_name)
4220                 from_copy = true;
4221
4222         if (xattr && !foreign_mode) {
4223                 /*
4224                  * only print a warning as this is harmless and will be ignored
4225                  */
4226                 fprintf(stderr,
4227                         "%s %s: xattr has been specified for non-foreign layout\n",
4228                         progname, argv[0]);
4229         } else if (foreign_mode && !xattr) {
4230                 fprintf(stderr,
4231                         "%s %s: xattr must be provided in foreign mode\n",
4232                         progname, argv[0]);
4233                 goto usage_error;
4234         }
4235
4236         if (foreign_mode && (!setstripe_mode || comp_add | comp_del ||
4237             comp_set || comp_id || delete || from_copy ||
4238             setstripe_args_specified(&lsa) || lsa.lsa_nr_tgts ||
4239             lsa.lsa_tgts)) {
4240                 fprintf(stderr,
4241                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
4242                         progname, argv[0]);
4243                 return CMD_HELP;
4244         }
4245
4246         if (mirror_mode && mirror_count == 0) {
4247                 fprintf(stderr,
4248                         "error: %s: --mirror-count|-N option is required\n",
4249                         progname);
4250                 result = -EINVAL;
4251                 goto error;
4252         }
4253
4254         if (mirror_mode) {
4255                 if (!setstripe_args_specified(&lsa))
4256                         last_mirror->m_inherit = true;
4257                 if (lsa.lsa_comp_end == 0)
4258                         lsa.lsa_comp_end = LUSTRE_EOF;
4259         }
4260
4261         if (lsa.lsa_comp_end != 0) {
4262                 result = comp_args_to_layout(lpp, &lsa, true);
4263                 if (result) {
4264                         fprintf(stderr, "error: %s: invalid layout\n",
4265                                 progname);
4266                         result = -EINVAL;
4267                         goto error;
4268                 }
4269         }
4270
4271         if (mirror_flags & MF_NO_VERIFY) {
4272                 if (opc != SO_MIRROR_EXTEND) {
4273                         fprintf(stderr,
4274                                 "error: %s: --no-verify is valid only for lfs mirror extend command\n",
4275                                 progname);
4276                         result = -EINVAL;
4277                         goto error;
4278                 } else if (!has_m_file) {
4279                         fprintf(stderr,
4280                                 "error: %s: --no-verify must be specified with -f <victim_file> option\n",
4281                                 progname);
4282                         result = -EINVAL;
4283                         goto error;
4284                 }
4285         }
4286
4287         if (comp_set && !comp_id && !lsa.lsa_pool_name) {
4288                 fprintf(stderr,
4289                         "%s %s: --component-set doesn't have component-id set\n",
4290                         progname, argv[0]);
4291                 goto usage_error;
4292         }
4293
4294         if ((delete + comp_set + comp_del + comp_add) > 1) {
4295                 fprintf(stderr,
4296                         "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
4297                         progname, argv[0]);
4298                 goto usage_error;
4299         }
4300
4301         if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
4302                        lsa.lsa_comp_flags != 0 || layout != NULL)) {
4303                 fprintf(stderr,
4304                         "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
4305                         progname, argv[0]);
4306                 goto usage_error;
4307         }
4308
4309         if ((comp_set || comp_del) &&
4310             (setstripe_args_specified(&lsa) || layout != NULL)) {
4311                 fprintf(stderr,
4312                         "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
4313                         progname, argv[0]);
4314                 goto usage_error;
4315         }
4316
4317         if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
4318                 fprintf(stderr,
4319                         "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
4320                         progname, argv[0]);
4321                 goto usage_error;
4322         }
4323
4324         if (comp_add || comp_del) {
4325                 struct stat st;
4326
4327                 result = lstat(fname, &st);
4328                 if (result == 0 && S_ISDIR(st.st_mode)) {
4329                         fprintf(stderr,
4330                                 "%s setstripe: cannot use --component-add or --component-del for directory\n",
4331                                 progname);
4332                         goto usage_error;
4333                 }
4334
4335                 if (mirror_mode) {
4336                         fprintf(stderr,
4337                                 "error: %s: can't use --component-add or --component-del for mirror operation\n",
4338                                 progname);
4339                         goto usage_error;
4340                 }
4341         }
4342
4343         if (comp_add) {
4344                 if (!layout) {
4345                         fprintf(stderr,
4346                                 "%s %s: option -E must be specified with --component-add\n",
4347                                 progname, argv[0]);
4348                         goto usage_error;
4349                 }
4350         }
4351
4352         if (from_yaml && from_copy) {
4353                 fprintf(stderr,
4354                         "%s: can't specify --yaml and --copy together\n",
4355                         progname);
4356                 goto error;
4357         }
4358
4359         if ((from_yaml || from_copy) &&
4360             (setstripe_args_specified(&lsa) || layout != NULL)) {
4361                 fprintf(stderr,
4362                         "error: %s: can't specify --yaml or --copy with -c, -S, -i, -o, -p or -E options.\n",
4363                         argv[0]);
4364                 goto error;
4365         }
4366
4367         if ((migration_flags & LLAPI_MIGRATION_NONBLOCK) && migration_block) {
4368                 fprintf(stderr,
4369                         "%s %s: options --non-block and --block are mutually exclusive\n",
4370                         progname, argv[0]);
4371                 goto usage_error;
4372         }
4373
4374         if (!comp_del && !comp_set && opc != SO_MIRROR_SPLIT &&
4375             opc != SO_MIRROR_DELETE && comp_id != 0) {
4376                 fprintf(stderr,
4377                         "%s: option -I can only be used with --component-del or --component-set or lfs mirror split\n",
4378                         progname);
4379                 goto usage_error;
4380         }
4381
4382         if (migrate_mdt_mode) {
4383                 struct lmv_user_md *lmu;
4384
4385                 /* initialize migrate mdt parameters */
4386                 lmu = calloc(1, lmv_user_md_size(lsa.lsa_nr_tgts,
4387                                                  LMV_USER_MAGIC_SPECIFIC));
4388                 if (!lmu) {
4389                         fprintf(stderr,
4390                                 "%s %s: cannot allocate memory for lmv_user_md: %s\n",
4391                                 progname, argv[0], strerror(ENOMEM));
4392                         result = -ENOMEM;
4393                         goto error;
4394                 }
4395                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
4396                         lmu->lum_stripe_count = lsa.lsa_stripe_count;
4397                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT) {
4398                         fprintf(stderr,
4399                                 "%s %s: migrate should specify MDT index\n",
4400                                 progname, argv[0]);
4401                         free(lmu);
4402                         goto usage_error;
4403                 }
4404                 lmu->lum_stripe_offset = lsa.lsa_stripe_off;
4405                 if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
4406                         lmu->lum_hash_type = lsa.lsa_pattern;
4407                 else
4408                         lmu->lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
4409                 if (lsa.lsa_pool_name) {
4410                         strncpy(lmu->lum_pool_name, lsa.lsa_pool_name,
4411                                 sizeof(lmu->lum_pool_name) - 1);
4412                         lmu->lum_pool_name[sizeof(lmu->lum_pool_name) - 1] = 0;
4413                 }
4414                 if (lsa.lsa_nr_tgts > 1) {
4415                         int i;
4416
4417                         if (lsa.lsa_stripe_count > 0 &&
4418                             lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
4419                             lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
4420                                 fprintf(stderr,
4421                                         "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
4422                                         progname, lsa.lsa_stripe_count,
4423                                         lsa.lsa_nr_tgts);
4424                                 free(lmu);
4425                                 goto usage_error;
4426                         }
4427
4428                         lmu->lum_magic = LMV_USER_MAGIC_SPECIFIC;
4429                         lmu->lum_stripe_count = lsa.lsa_nr_tgts;
4430                         for (i = 0; i < lsa.lsa_nr_tgts; i++)
4431                                 lmu->lum_objects[i].lum_mds = lsa.lsa_tgts[i];
4432                 } else {
4433                         lmu->lum_magic = LMV_USER_MAGIC;
4434                 }
4435
4436                 migrate_mdt_param.fp_lmv_md = lmu;
4437                 migrate_mdt_param.fp_migrate = 1;
4438         } else if (!layout) {
4439                 if (lsa_args_stripe_count_check(&lsa))
4440                         goto usage_error;
4441
4442                 /* initialize stripe parameters */
4443                 param = calloc(1, offsetof(typeof(*param),
4444                                lsp_osts[lsa.lsa_nr_tgts]));
4445                 if (!param) {
4446                         fprintf(stderr,
4447                                 "%s %s: cannot allocate memory for parameters: %s\n",
4448                                 progname, argv[0], strerror(ENOMEM));
4449                         result = -ENOMEM;
4450                         goto error;
4451                 }
4452
4453                 if (lsa.lsa_stripe_size != LLAPI_LAYOUT_DEFAULT)
4454                         param->lsp_stripe_size = lsa.lsa_stripe_size;
4455                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
4456                         if (lsa.lsa_stripe_count == LLAPI_LAYOUT_WIDE)
4457                                 param->lsp_stripe_count = -1;
4458                         else
4459                                 param->lsp_stripe_count = lsa.lsa_stripe_count;
4460                 }
4461                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
4462                         param->lsp_stripe_offset = -1;
4463                 else
4464                         param->lsp_stripe_offset = lsa.lsa_stripe_off;
4465                 param->lsp_stripe_pattern =
4466                                 llapi_pattern_to_lov(lsa.lsa_pattern);
4467                 if (param->lsp_stripe_pattern == EINVAL) {
4468                         fprintf(stderr, "error: %s: invalid stripe pattern\n",
4469                                 argv[0]);
4470                         free(param);
4471                         goto usage_error;
4472                 }
4473                 param->lsp_pool = lsa.lsa_pool_name;
4474                 param->lsp_is_specific = false;
4475
4476                 if (lsa.lsa_nr_tgts > 0) {
4477                         param->lsp_is_specific = true;
4478                         param->lsp_stripe_count = lsa.lsa_nr_tgts;
4479                         memcpy(param->lsp_osts, tgts,
4480                                sizeof(*tgts) * lsa.lsa_nr_tgts);
4481                 }
4482         }
4483
4484         if (from_yaml) {
4485                 /* generate a layout from a YAML template */
4486                 result = lfs_comp_create_from_yaml(template, &layout,
4487                                                    &lsa, tgts);
4488                 if (result) {
4489                         fprintf(stderr,
4490                                 "error: %s: can't create composite layout from template file %s\n",
4491                                 argv[0], template);
4492                         goto error;
4493                 }
4494         }
4495
4496         if (layout != NULL || mirror_list != NULL) {
4497                 if (mirror_list)
4498                         result = mirror_adjust_first_extents(mirror_list);
4499                 else
4500                         result = layout_adjust_first_extent(fname, layout,
4501                                                             comp_add);
4502                 if (result == -ENODATA)
4503                         comp_add = 0;
4504                 else if (result != 0) {
4505                         fprintf(stderr, "error: %s: invalid layout\n",
4506                                 progname);
4507                         goto error;
4508                 }
4509         }
4510
4511         for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
4512                 if (from_copy) {
4513                         layout = llapi_layout_get_by_path(template ?: fname, 0);
4514                         if (!layout) {
4515                                 fprintf(stderr,
4516                                         "%s: can't create composite layout from file %s: %s\n",
4517                                         progname, template ?: fname,
4518                                         strerror(errno));
4519                                 result = -errno;
4520                                 goto error;
4521                         }
4522                 }
4523
4524                 if (migrate_mdt_mode) {
4525                         result = llapi_migrate_mdt(fname, &migrate_mdt_param);
4526                 } else if (migrate_mode) {
4527                         if (from_copy) {
4528                                 /*
4529                                  * Strip the source layout of specific
4530                                  * OST object/index values.
4531                                  */
4532                                 result = llapi_layout_ost_index_set(layout, 0,
4533                                                 LLAPI_LAYOUT_DEFAULT);
4534                                 if (result) {
4535                                         fprintf(stderr,
4536                                                 "%s: set default ost index failed: %s\n",
4537                                                 progname, strerror(errno));
4538                                         result = -errno;
4539                                         goto error;
4540                                 }
4541                         }
4542
4543                         result = lfs_migrate(fname, migration_flags, param,
4544                                              layout, bandwidth_bytes_sec,
4545                                              stats_interval_sec);
4546                 } else if (comp_set != 0) {
4547                         result = lfs_component_set(fname, comp_id,
4548                                                    lsa.lsa_pool_name,
4549                                                    lsa.lsa_comp_flags,
4550                                                    lsa.lsa_comp_neg_flags);
4551                 } else if (comp_del != 0) {
4552                         result = lfs_component_del(fname, comp_id,
4553                                                    lsa.lsa_comp_flags,
4554                                                    lsa.lsa_comp_neg_flags);
4555                 } else if (comp_add != 0) {
4556                         result = lfs_component_add(fname, layout);
4557                 } else if (opc == SO_MIRROR_CREATE) {
4558                         result = mirror_create(fname, mirror_list);
4559                 } else if (opc == SO_MIRROR_EXTEND) {
4560                         result = mirror_extend(fname, mirror_list,
4561                                                mirror_flags,
4562                                                bandwidth_bytes_sec,
4563                                                stats_interval_sec);
4564                 } else if (opc == SO_MIRROR_SPLIT || opc == SO_MIRROR_DELETE) {
4565                         if (!mirror_id && !comp_id && !lsa.lsa_pool_name) {
4566                                 fprintf(stderr,
4567                                         "%s: no mirror id, component id, or pool name specified to delete from '%s'\n",
4568                                         progname, fname);
4569                                 goto usage_error;
4570                         }
4571                         if (lsa.lsa_pool_name)
4572                                 mirror_flags |= MF_COMP_POOL;
4573                         else if (mirror_id != 0)
4574                                 comp_id = mirror_id;
4575                         else
4576                                 mirror_flags |= MF_COMP_ID;
4577                         if (has_m_file && !strcmp(fname, mirror_list->m_file)) {
4578                                 fprintf(stderr,
4579                                         "%s: the file specified by -f cannot be same as the source file '%s'\n",
4580                                         progname, fname);
4581                                 goto usage_error;
4582                         }
4583                         result = mirror_split(fname, comp_id, lsa.lsa_pool_name,
4584                                               mirror_flags,
4585                                               has_m_file ? mirror_list->m_file :
4586                                               NULL);
4587                 } else if (layout) {
4588                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
4589                                                       mode, layout);
4590                         if (result >= 0) {
4591                                 close(result);
4592                                 result = 0;
4593                         }
4594                 } else if (foreign_mode) {
4595                         result = llapi_file_create_foreign(fname, mode, type,
4596                                                            flags, xattr);
4597                         if (result >= 0) {
4598                                 close(result);
4599                                 result = 0;
4600                         }
4601                 } else {
4602                         result = llapi_file_open_param(fname,
4603                                                        O_CREAT | O_WRONLY,
4604                                                        mode, param);
4605                         if (result >= 0) {
4606                                 close(result);
4607                                 result = 0;
4608                         }
4609                 }
4610                 if (result) {
4611                         /* Save the first error encountered. */
4612                         if (result2 == 0)
4613                                 result2 = result;
4614                         continue;
4615                 }
4616         }
4617
4618         if (mode_opt)
4619                 umask(previous_umask);
4620
4621         free(param);
4622         free(migrate_mdt_param.fp_lmv_md);
4623         llapi_layout_free(layout);
4624         lfs_mirror_list_free(mirror_list);
4625         return result2;
4626 usage_error:
4627         result = CMD_HELP;
4628 error:
4629         llapi_layout_free(layout);
4630         lfs_mirror_list_free(mirror_list);
4631         return result;
4632 }
4633
4634 static int lfs_poollist(int argc, char **argv)
4635 {
4636         if (argc != 2)
4637                 return CMD_HELP;
4638
4639         return llapi_poollist(argv[1]);
4640 }
4641
4642 #define FP_DEFAULT_TIME_MARGIN (24 * 60 * 60)
4643 static int set_time(struct find_param *param, time_t *time, time_t *set,
4644                     char *str)
4645 {
4646         long long t = 0;
4647         int sign = 0;
4648         char *endptr = "AD";
4649         char *timebuf;
4650
4651         if (str[0] == '+')
4652                 sign = 1;
4653         else if (str[0] == '-')
4654                 sign = -1;
4655
4656         if (sign)
4657                 str++;
4658
4659         for (timebuf = str; *endptr && *(endptr + 1); timebuf = endptr + 1) {
4660                 long long val = strtoll(timebuf, &endptr, 0);
4661                 int unit = 1;
4662
4663                 switch (*endptr) {
4664                 case  'y':
4665                         unit *= 52; /* 52 weeks + 1 day below */
4666                         fallthrough;
4667                 case  'w':
4668                         unit *= 7;
4669                         if (param->fp_time_margin == FP_DEFAULT_TIME_MARGIN)
4670                                 param->fp_time_margin *= (1 + unit / 52);
4671                         unit += (*endptr == 'y'); /* +1 day for 365 days/year */
4672                         fallthrough;
4673                 case '\0': /* days are default unit if none used */
4674                         fallthrough;
4675                 case  'd':
4676                         unit *= 24;
4677                         fallthrough;
4678                 case  'h':
4679                         unit *= 60;
4680                         fallthrough;
4681                 case  'm':
4682                         unit *= 60;
4683                         fallthrough;
4684                 case  's':
4685                         break;
4686                         /* don't need to multiply by 1 for seconds */
4687                 default:
4688                         fprintf(stderr,
4689                                 "%s find: bad time string '%s': %s\n",
4690                                 progname, timebuf, strerror(EINVAL));
4691                         return INT_MAX;
4692                 }
4693
4694                 if (param->fp_time_margin == 0 ||
4695                     (*endptr && unit < param->fp_time_margin))
4696                         param->fp_time_margin = unit;
4697
4698                 t += val * unit;
4699         }
4700         if (*time < t) {
4701                 if (sign != 0)
4702                         str--;
4703                 fprintf(stderr, "%s find: bad time '%s': too large\n",
4704                         progname, str);
4705                 return INT_MAX;
4706         }
4707
4708         *set = *time - t;
4709
4710         return sign;
4711 }
4712
4713 static int str2quotaid(__u32 *id, const char *arg)
4714 {
4715         unsigned long int projid_tmp = 0;
4716         char *endptr = NULL;
4717
4718         projid_tmp = strtoul(arg, &endptr, 10);
4719         if (*endptr != '\0')
4720                 return -EINVAL;
4721         /* UINT32_MAX is not allowed - see projid_valid()/INVALID_PROJID */
4722         if (projid_tmp >= UINT32_MAX)
4723                 return -ERANGE;
4724
4725         *id = projid_tmp;
4726         return 0;
4727 }
4728
4729 static int name2uid(unsigned int *id, const char *name)
4730 {
4731         struct passwd *passwd;
4732
4733         passwd = getpwnam(name);
4734         if (!passwd)
4735                 return -ENOENT;
4736         *id = passwd->pw_uid;
4737
4738         return 0;
4739 }
4740
4741 static int name2gid(unsigned int *id, const char *name)
4742 {
4743         struct group *group;
4744
4745         group = getgrnam(name);
4746         if (!group)
4747                 return -ENOENT;
4748         *id = group->gr_gid;
4749
4750         return 0;
4751 }
4752
4753 static inline int name2projid(unsigned int *id, const char *name)
4754 {
4755         return -ENOTSUP;
4756 }
4757
4758 static int uid2name(char **name, unsigned int id)
4759 {
4760         struct passwd *passwd;
4761
4762         passwd = getpwuid(id);
4763         if (!passwd)
4764                 return -ENOENT;
4765         *name = passwd->pw_name;
4766
4767         return 0;
4768 }
4769
4770 static inline int gid2name(char **name, unsigned int id)
4771 {
4772         struct group *group;
4773
4774         group = getgrgid(id);
4775         if (!group)
4776                 return -ENOENT;
4777         *name = group->gr_name;
4778
4779         return 0;
4780 }
4781
4782 static int name2layout(__u32 *layout, char *name)
4783 {
4784         char *ptr, *layout_name;
4785
4786         *layout = 0;
4787         for (ptr = name; ; ptr = NULL) {
4788                 layout_name = strtok(ptr, ",");
4789                 if (!layout_name)
4790                         break;
4791                 if (strcmp(layout_name, "released") == 0)
4792                         *layout |= LOV_PATTERN_F_RELEASED;
4793                 else if (strcmp(layout_name, "raid0") == 0)
4794                         *layout |= LOV_PATTERN_RAID0;
4795                 else if (strcmp(layout_name, "mdt") == 0)
4796                         *layout |= LOV_PATTERN_MDT;
4797                 else if (strcmp(layout_name, "overstriping") == 0)
4798                         *layout |= LOV_PATTERN_OVERSTRIPING;
4799                 else
4800                         return -1;
4801         }
4802         return 0;
4803 }
4804
4805 static int name2attrs(char *name, __u64 *attrs, __u64 *neg_attrs)
4806 {
4807         char *ptr, *attr_name = name;
4808         struct attrs_name *ap;
4809         int islongopt = 0; /* 1 true; 0 not known yet; -1 false. */
4810
4811         *attrs = 0;
4812         *neg_attrs = 0;
4813
4814         if (strchr(name, ','))
4815                 islongopt = 1;
4816
4817         for (ptr = name; ; ptr = NULL) {
4818                 if (islongopt != -1)
4819                         attr_name = strtok(ptr, ",");
4820                 else
4821                         attr_name = attr_name + 1;
4822                 if (!attr_name || *attr_name == '\0')
4823                         break;
4824
4825                 for (ap = (struct attrs_name *)attrs_array;
4826                      ap->an_attr != 0;
4827                      ap++) {
4828                         if (islongopt != -1 &&
4829                             strcmp(attr_name, ap->an_name) == 0) {
4830                                 *attrs |= ap->an_attr;
4831                                 islongopt = 1;
4832                                 break;
4833                         } else if (islongopt != -1 && attr_name[0] == '^' &&
4834                                    strcmp(attr_name + 1, ap->an_name) == 0) {
4835                                 *neg_attrs |= ap->an_attr;
4836                                 islongopt = 1;
4837                                 break;
4838                         } else if (islongopt != 1 &&
4839                                    *attr_name == ap->an_shortname) {
4840                                 *attrs |= ap->an_attr;
4841                                 islongopt = -1;
4842                                 break;
4843                         } else if (islongopt != 1 && *attr_name == '^' &&
4844                                    attr_name[1] == ap->an_shortname) {
4845                                 *neg_attrs |= ap->an_attr;
4846                                 islongopt = -1;
4847                                 attr_name++;
4848                                 break;
4849                         }
4850                 }
4851
4852                 if (ap->an_attr == 0) {
4853                         /* provided attr is unknown */
4854                         fprintf(stderr, "error: bad attribute name '%s'\n",
4855                                 attr_name);
4856                         return -1;
4857                 }
4858         }
4859         return 0;
4860 }
4861
4862 static int parse_symbolic(const char *input, mode_t *outmode, const char **end)
4863 {
4864         int loop;
4865         int user, group, other;
4866         int who, all;
4867         char c, op;
4868         mode_t perm;
4869         mode_t usermask;
4870         mode_t previous_flags;
4871
4872         user = group = other = 0;
4873         all = 0;
4874         loop = 1;
4875         perm = 0;
4876         previous_flags = 0;
4877         *end = input;
4878         usermask = 0;
4879
4880         while (loop) {
4881                 switch (*input) {
4882                 case 'u':
4883                         user = 1;
4884                         break;
4885                 case 'g':
4886                         group = 1;
4887                         break;
4888                 case 'o':
4889                         other = 1;
4890                         break;
4891                 case 'a':
4892                         user = group = other = 1;
4893                         all = 1;
4894                         break;
4895                 default:
4896                         loop = 0;
4897                 }
4898
4899                 if (loop)
4900                         input++;
4901         }
4902
4903         who = user || group || other;
4904         if (!who) {
4905                 /* get the umask */
4906                 usermask = umask(0022);
4907                 umask(usermask);
4908                 usermask &= 07777;
4909         }
4910
4911         if (*input == '-' || *input == '+' || *input == '=')
4912                 op = *input++;
4913         else
4914                 /* operation is required */
4915                 return -1;
4916
4917         /* get the flags in *outmode */
4918         switch (*input) {
4919         case 'u':
4920                 previous_flags = (*outmode & 0700);
4921                 perm |= user  ? previous_flags : 0;
4922                 perm |= group ? (previous_flags >> 3) : 0;
4923                 perm |= other ? (previous_flags >> 6) : 0;
4924                 input++;
4925                 goto write_perm;
4926         case 'g':
4927                 previous_flags = (*outmode & 0070);
4928                 perm |= user  ? (previous_flags << 3) : 0;
4929                 perm |= group ? previous_flags : 0;
4930                 perm |= other ? (previous_flags >> 3) : 0;
4931                 input++;
4932                 goto write_perm;
4933         case 'o':
4934                 previous_flags = (*outmode & 0007);
4935                 perm |= user  ? (previous_flags << 6) : 0;
4936                 perm |= group ? (previous_flags << 3) : 0;
4937                 perm |= other ? previous_flags : 0;
4938                 input++;
4939                 goto write_perm;
4940         default:
4941                 break;
4942         }
4943
4944         /* this part is optional,
4945          * if empty perm = 0 and *outmode is not modified
4946          */
4947         loop = 1;
4948         while (loop) {
4949                 c = *input;
4950                 switch (c) {
4951                 case 'r':
4952                         perm |= user  ? 0400 : 0;
4953                         perm |= group ? 0040 : 0;
4954                         perm |= other ? 0004 : 0;
4955                         /* set read permission for uog except for umask's
4956                          * permissions
4957                          */
4958                         perm |= who   ? 0 : (0444 & ~usermask);
4959                         break;
4960                 case 'w':
4961                         perm |= user  ? 0200 : 0;
4962                         perm |= group ? 0020 : 0;
4963                         perm |= other ? 0002 : 0;
4964                         /* set write permission for uog except for umask'
4965                          * permissions
4966                          */
4967                         perm |= who   ? 0 : (0222 & ~usermask);
4968                         break;
4969                 case 'x':
4970                         perm |= user  ? 0100 : 0;
4971                         perm |= group ? 0010 : 0;
4972                         perm |= other ? 0001 : 0;
4973                         /* set execute permission for uog except for umask'
4974                          * permissions
4975                          */
4976                         perm |= who   ? 0 : (0111 & ~usermask);
4977                         break;
4978                 case 'X':
4979                         /*
4980                          * Adds execute permission to 'u', 'g' and/or 'g' if
4981                          * specified and either 'u', 'g' or 'o' already has
4982                          * execute permissions.
4983                          */
4984                         if ((*outmode & 0111) != 0) {
4985                                 perm |= user  ? 0100 : 0;
4986                                 perm |= group ? 0010 : 0;
4987                                 perm |= other ? 0001 : 0;
4988                                 perm |= !who  ? 0111 : 0;
4989                         }
4990                         break;
4991                 case 's':
4992                         /* s is ignored if o is given, but it's not an error */
4993                         if (other && !group && !user)
4994                                 break;
4995                         perm |= user  ? S_ISUID : 0;
4996                         perm |= group ? S_ISGID : 0;
4997                         break;
4998                 case 't':
4999                         /* 't' should be used when 'a' is given
5000                          * or who is empty
5001                          */
5002                         perm |= (!who || all) ? S_ISVTX : 0;
5003                         /* using ugo with t is not an error */
5004                         break;
5005                 default:
5006                         loop = 0;
5007                         break;
5008                 }
5009                 if (loop)
5010                         input++;
5011         }
5012
5013 write_perm:
5014         /* uog flags should be only one character long */
5015         if (previous_flags && (*input != '\0' && *input != ','))
5016                 return -1;
5017
5018         switch (op) {
5019         case '-':
5020                 /* remove the flags from outmode */
5021                 *outmode &= ~perm;
5022                 break;
5023         case '+':
5024                 /* add the flags to outmode */
5025                 *outmode |= perm;
5026                 break;
5027         case '=':
5028                 /* set the flags of outmode to perm */
5029                 if (perm != 0)
5030                         *outmode = perm;
5031                 break;
5032         }
5033
5034         *end = input;
5035         return 0;
5036 }
5037
5038 static int str2mode_t(const char *input, mode_t *outmode)
5039 {
5040         int ret;
5041         const char *iter;
5042
5043         ret = 0;
5044
5045         if (*input >= '0' && *input <= '7') {
5046                 /* parse octal representation */
5047                 char *end;
5048
5049                 iter = input;
5050
5051                 /* look for invalid digits in octal representation */
5052                 while (isdigit(*iter))
5053                         if (*iter++ > '7')
5054                                 return -1;
5055
5056                 errno = 0;
5057                 *outmode = strtoul(input, &end, 8);
5058
5059                 if (errno != 0 || *outmode > 07777) {
5060                         *outmode = 0;
5061                         ret = -1;
5062                 }
5063
5064         } else if (*input == '8' || *input == '9') {
5065                 /* error: invalid octal number */
5066                 ret = -1;
5067         } else {
5068                 /* parse coma seperated list of symbolic representation */
5069                 int rc;
5070                 const char *end;
5071
5072                 *outmode = 0;
5073                 rc = 0;
5074                 end = NULL;
5075
5076                 do {
5077                         rc = parse_symbolic(input, outmode, &end);
5078                         if (rc)
5079                                 return -1;
5080
5081                         input = end+1;
5082                 } while (*end == ',');
5083
5084                 if (*end != '\0')
5085                         ret = -1;
5086         }
5087         return ret;
5088 }
5089
5090 static int lfs_find(int argc, char **argv)
5091 {
5092         int c, rc;
5093         int ret = 0;
5094         time_t t;
5095         struct find_param param = {
5096                 .fp_max_depth = -1,
5097                 .fp_quiet = 1,
5098                 .fp_time_margin = FP_DEFAULT_TIME_MARGIN,
5099         };
5100         struct option long_opts[] = {
5101         { .val = 'A',   .name = "atime",        .has_arg = required_argument },
5102         { .val = LFS_ATTRS_OPT,
5103                         .name = "attrs",        .has_arg = required_argument },
5104         { .val = 'b',   .name = "blocks",       .has_arg = required_argument },
5105         { .val = 'B',   .name = "btime",        .has_arg = required_argument },
5106         { .val = 'B',   .name = "Btime",        .has_arg = required_argument },
5107         { .val = LFS_COMP_COUNT_OPT,
5108                         .name = "comp-count",   .has_arg = required_argument },
5109         { .val = LFS_COMP_COUNT_OPT,
5110                         .name = "component-count",
5111                                                 .has_arg = required_argument },
5112         { .val = LFS_COMP_FLAGS_OPT,
5113                         .name = "comp-flags",   .has_arg = required_argument },
5114         { .val = LFS_COMP_FLAGS_OPT,
5115                         .name = "component-flags",
5116                                                 .has_arg = required_argument },
5117         { .val = LFS_COMP_START_OPT,
5118                         .name = "comp-start",   .has_arg = required_argument },
5119         { .val = LFS_COMP_START_OPT,
5120                         .name = "component-start",
5121                                                 .has_arg = required_argument },
5122         { .val = LFS_MIRROR_STATE_OPT,
5123                         .name = "mirror-state", .has_arg = required_argument },
5124         { .val = LFS_NEWERXY_OPT,
5125                         .name = "newer",        .has_arg = required_argument},
5126         { .val = LFS_NEWERXY_OPT,
5127                         .name = "neweraa",      .has_arg = required_argument},
5128         { .val = LFS_NEWERXY_OPT,
5129                         .name = "neweram",      .has_arg = required_argument},
5130         { .val = LFS_NEWERXY_OPT,
5131                         .name = "newerac",      .has_arg = required_argument},
5132         { .val = LFS_NEWERXY_OPT,
5133                         .name = "newerab",      .has_arg = required_argument},
5134         { .val = LFS_NEWERXY_OPT,
5135                         .name = "newerma",      .has_arg = required_argument},
5136         { .val = LFS_NEWERXY_OPT,
5137                         .name = "newermm",      .has_arg = required_argument},
5138         { .val = LFS_NEWERXY_OPT,
5139                         .name = "newermc",      .has_arg = required_argument},
5140         { .val = LFS_NEWERXY_OPT,
5141                         .name = "newermb",      .has_arg = required_argument},
5142         { .val = LFS_NEWERXY_OPT,
5143                         .name = "newerca",      .has_arg = required_argument},
5144         { .val = LFS_NEWERXY_OPT,
5145                         .name = "newercm",      .has_arg = required_argument},
5146         { .val = LFS_NEWERXY_OPT,
5147                         .name = "newercc",      .has_arg = required_argument},
5148         { .val = LFS_NEWERXY_OPT,
5149                         .name = "newercb",      .has_arg = required_argument},
5150         { .val = LFS_NEWERXY_OPT,
5151                         .name = "newerba",      .has_arg = required_argument},
5152         { .val = LFS_NEWERXY_OPT,
5153                         .name = "newerbm",      .has_arg = required_argument},
5154         { .val = LFS_NEWERXY_OPT,
5155                         .name = "newerbc",      .has_arg = required_argument},
5156         { .val = LFS_NEWERXY_OPT,
5157                         .name = "newerbb",      .has_arg = required_argument},
5158         { .val = LFS_NEWERXY_OPT,
5159                         .name = "newerBa",      .has_arg = required_argument},
5160         { .val = LFS_NEWERXY_OPT,
5161                         .name = "newerBm",      .has_arg = required_argument},
5162         { .val = LFS_NEWERXY_OPT,
5163                         .name = "newerBc",      .has_arg = required_argument},
5164         { .val = LFS_NEWERXY_OPT,
5165                         .name = "newerBB",      .has_arg = required_argument},
5166         { .val = LFS_NEWERXY_OPT,
5167                         .name = "newerat",      .has_arg = required_argument},
5168         { .val = LFS_NEWERXY_OPT,
5169                         .name = "newermt",      .has_arg = required_argument},
5170         { .val = LFS_NEWERXY_OPT,
5171                         .name = "newerct",      .has_arg = required_argument},
5172         { .val = LFS_NEWERXY_OPT,
5173                         .name = "newerbt",      .has_arg = required_argument},
5174         { .val = LFS_NEWERXY_OPT,
5175                         .name = "newerBt",      .has_arg = required_argument},
5176         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument },
5177         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument },
5178         { .val = 'C',   .name = "ctime",        .has_arg = required_argument },
5179 /* getstripe { .val = 'd', .name = "directory", .has_arg = no_argument }, */
5180         { .val = 'D',   .name = "maxdepth",     .has_arg = required_argument },
5181         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument },
5182         { .val = 'E',   .name = "component-end",
5183                                                 .has_arg = required_argument },
5184 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
5185         { .val = LFS_LAYOUT_FOREIGN_OPT,
5186                         .name = "foreign",      .has_arg = optional_argument},
5187         { .val = 'g',   .name = "gid",          .has_arg = required_argument },
5188         { .val = 'G',   .name = "group",        .has_arg = required_argument },
5189         { .val = 'h',   .name = "help",         .has_arg = no_argument },
5190         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
5191         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument },
5192         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument },
5193 /* getstripe { .val = 'I', .name = "comp-id",   .has_arg = required_argument }*/
5194         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
5195         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
5196         { .val = LFS_LINKS_OPT,
5197                         .name = "links",        .has_arg = required_argument },
5198         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
5199         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
5200         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument },
5201         { .val = 'M',   .name = "mtime",        .has_arg = required_argument },
5202         { .val = 'n',   .name = "name",         .has_arg = required_argument },
5203         { .val = 'N',   .name = "mirror-count", .has_arg = required_argument },
5204 /* find { .val = 'o'    .name = "or", .has_arg = no_argument }, like find(1) */
5205         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
5206         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
5207         { .val = LFS_FIND_PERM,
5208                         .name = "perm",         .has_arg = required_argument },
5209         /* no short option for pool yet, can be 'p' after 2.18 */
5210         { .val = LFS_POOL_OPT,
5211                         .name = "pool",         .has_arg = required_argument },
5212         { .val = '0',   .name = "print0",       .has_arg = no_argument },
5213         { .val = 'P',   .name = "print",        .has_arg = no_argument },
5214         { .val = LFS_PRINTF_OPT,
5215                         .name = "printf",       .has_arg = required_argument },
5216         { .val = LFS_PROJID_OPT,
5217                         .name = "projid",       .has_arg = required_argument },
5218 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
5219 /* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
5220 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
5221         { .val = 's',   .name = "size",         .has_arg = required_argument },
5222         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
5223         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
5224         { .val = 't',   .name = "type",         .has_arg = required_argument },
5225         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
5226         { .val = 'u',   .name = "uid",          .has_arg = required_argument },
5227         { .val = 'U',   .name = "user",         .has_arg = required_argument },
5228 /* getstripe { .val = 'v', .name = "verbose",   .has_arg = no_argument }, */
5229 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }, */
5230         { .val = 'z',   .name = "extension-size",
5231                                                 .has_arg = required_argument },
5232         { .val = 'z',   .name = "ext-size",     .has_arg = required_argument },
5233         { .name = NULL } };
5234         int prev_optind = optind;
5235         int optidx = 0;
5236         int pathstart = -1;
5237         int pathend = -1;
5238         int pathbad = -1;
5239         int neg_opt = 0;
5240         time_t *xtime;
5241         int *xsign;
5242         int isoption;
5243         char *endptr;
5244
5245         time(&t);
5246
5247         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
5248         while ((c = getopt_long_only(argc, argv,
5249                 "-0A:b:B:c:C:D:E:g:G:hH:i:lL:m:M:n:N:O:Ppqrs:S:t:T:u:U:z:",
5250                 long_opts, &optidx)) >= 0) {
5251                 xtime = NULL;
5252                 xsign = NULL;
5253                 if (neg_opt)
5254                         --neg_opt;
5255                 /* '!' is part of option */
5256                 /*
5257                  * when getopt_long_only() finds a string which is not
5258                  * an option nor a known option argument it returns 1
5259                  * in that case if we already have found pathstart and pathend
5260                  * (i.e. we have the list of pathnames),
5261                  * the only supported value is "!"
5262                  */
5263                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
5264                 if (!isoption && pathend != -1) {
5265                         fprintf(stderr,
5266                                 "err: %s: filename|dirname must either precede options or follow options\n",
5267                                 argv[0]);
5268                         ret = CMD_HELP;
5269                         goto err;
5270                 }
5271                 if (!isoption && pathstart == -1)
5272                         pathstart = prev_optind;
5273                 if (isoption && pathstart != -1 && pathend == -1)
5274                         pathend = prev_optind;
5275
5276                 prev_optind = optind;
5277
5278                 switch (c) {
5279                 case 0:
5280                         /* Long options. */
5281                         break;
5282                 case 1:
5283                         /*
5284                          * unknown; opt is "!" or path component,
5285                          * checking done above.
5286                          */
5287                         if (strcmp(optarg, "!") == 0)
5288                                 neg_opt = 2;
5289                         break;
5290                 case 'A':
5291                         xtime = &param.fp_atime;
5292                         xsign = &param.fp_asign;
5293                         param.fp_exclude_atime = !!neg_opt;
5294                         /* no break, this falls through to 'B' for btime */
5295                         fallthrough;
5296                 case 'B':
5297                         if (c == 'B') {
5298                                 xtime = &param.fp_btime;
5299                                 xsign = &param.fp_bsign;
5300                                 param.fp_exclude_btime = !!neg_opt;
5301                         }
5302                         /* no break, this falls through to 'C' for ctime */
5303                         fallthrough;
5304                 case 'C':
5305                         if (c == 'C') {
5306                                 xtime = &param.fp_ctime;
5307                                 xsign = &param.fp_csign;
5308                                 param.fp_exclude_ctime = !!neg_opt;
5309                         }
5310                         /* no break, this falls through to 'M' for mtime */
5311                         fallthrough;
5312                 case 'M':
5313                         if (c == 'M') {
5314                                 xtime = &param.fp_mtime;
5315                                 xsign = &param.fp_msign;
5316                                 param.fp_exclude_mtime = !!neg_opt;
5317                         }
5318                         rc = set_time(&param, &t, xtime, optarg);
5319                         if (rc == INT_MAX) {
5320                                 ret = -1;
5321                                 goto err;
5322                         }
5323                         if (rc)
5324                                 *xsign = rc;
5325                         break;
5326                 case LFS_ATTRS_OPT:
5327                         ret = name2attrs(optarg, &param.fp_attrs,
5328                                          &param.fp_neg_attrs);
5329                         if (ret)
5330                                 goto err;
5331                         param.fp_exclude_attrs = !!neg_opt;
5332                         break;
5333                 case 'b':
5334                         if (optarg[0] == '+') {
5335                                 param.fp_blocks_sign = -1;
5336                                 optarg++;
5337                         } else if (optarg[0] == '-') {
5338                                 param.fp_blocks_sign =  1;
5339                                 optarg++;
5340                         }
5341
5342                         param.fp_blocks_units = 1024;
5343                         ret = llapi_parse_size(optarg, &param.fp_blocks,
5344                                                &param.fp_blocks_units, 0);
5345                         if (ret) {
5346                                 fprintf(stderr, "error: bad blocks '%s'\n",
5347                                         optarg);
5348                                 goto err;
5349                         }
5350                         param.fp_check_blocks = 1;
5351                         param.fp_exclude_blocks = !!neg_opt;
5352                         break;
5353                 case LFS_COMP_COUNT_OPT:
5354                         if (optarg[0] == '+') {
5355                                 param.fp_comp_count_sign = -1;
5356                                 optarg++;
5357                         } else if (optarg[0] == '-') {
5358                                 param.fp_comp_count_sign =  1;
5359                                 optarg++;
5360                         }
5361
5362                         errno = 0;
5363                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
5364                         if (errno != 0 || *endptr != '\0' ||
5365                             param.fp_comp_count > UINT32_MAX) {
5366                                 fprintf(stderr,
5367                                         "error: bad component count '%s'\n",
5368                                         optarg);
5369                                 goto err;
5370                         }
5371                         param.fp_check_comp_count = 1;
5372                         param.fp_exclude_comp_count = !!neg_opt;
5373                         break;
5374                 case LFS_COMP_FLAGS_OPT:
5375                         rc = comp_str2flags(optarg, &param.fp_comp_flags,
5376                                             &param.fp_comp_neg_flags);
5377                         if (rc) {
5378                                 fprintf(stderr,
5379                                         "error: bad component flags '%s'\n",
5380                                         optarg);
5381                                 goto err;
5382                         }
5383                         param.fp_check_comp_flags = 1;
5384                         if (neg_opt) {
5385                                 __u32 flags = param.fp_comp_neg_flags;
5386
5387                                 param.fp_comp_neg_flags = param.fp_comp_flags;
5388                                 param.fp_comp_flags = flags;
5389                         }
5390                         break;
5391                 case LFS_COMP_START_OPT:
5392                         if (optarg[0] == '+') {
5393                                 param.fp_comp_start_sign = -1;
5394                                 optarg++;
5395                         } else if (optarg[0] == '-') {
5396                                 param.fp_comp_start_sign =  1;
5397                                 optarg++;
5398                         }
5399
5400                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
5401                                               &param.fp_comp_start_units, 0);
5402                         if (rc) {
5403                                 fprintf(stderr,
5404                                         "error: bad component start '%s'\n",
5405                                         optarg);
5406                                 goto err;
5407                         }
5408                         param.fp_check_comp_start = 1;
5409                         param.fp_exclude_comp_start = !!neg_opt;
5410                         break;
5411                 case LFS_MIRROR_STATE_OPT:
5412                         rc = mirror_str2state(optarg, &param.fp_mirror_state,
5413                                               &param.fp_mirror_neg_state);
5414                         if (rc) {
5415                                 fprintf(stderr,
5416                                         "error: bad mirrored file state '%s'\n",
5417                                         optarg);
5418                                 goto err;
5419                         }
5420                         param.fp_check_mirror_state = 1;
5421                         if (neg_opt) {
5422                                 __u16 state = param.fp_mirror_neg_state;
5423
5424                                 param.fp_mirror_neg_state =
5425                                         param.fp_mirror_state;
5426                                 param.fp_mirror_state = state;
5427                         }
5428                         break;
5429                 case 'c':
5430                         if (optarg[0] == '+') {
5431                                 param.fp_stripe_count_sign = -1;
5432                                 optarg++;
5433                         } else if (optarg[0] == '-') {
5434                                 param.fp_stripe_count_sign =  1;
5435                                 optarg++;
5436                         }
5437
5438                         errno = 0;
5439                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
5440                         if (errno != 0 || *endptr != '\0' ||
5441                             param.fp_stripe_count > LOV_MAX_STRIPE_COUNT) {
5442                                 fprintf(stderr,
5443                                         "error: bad stripe_count '%s'\n",
5444                                         optarg);
5445                                 ret = -1;
5446                                 goto err;
5447                         }
5448                         param.fp_check_stripe_count = 1;
5449                         param.fp_exclude_stripe_count = !!neg_opt;
5450                         break;
5451                 case 'D':
5452                         errno = 0;
5453                         param.fp_max_depth = strtol(optarg, 0, 0);
5454                         if (errno != 0 || param.fp_max_depth < 0) {
5455                                 fprintf(stderr,
5456                                         "error: bad maxdepth '%s'\n",
5457                                         optarg);
5458                                 ret = -1;
5459                                 goto err;
5460                         }
5461                         break;
5462                 case 'E':
5463                         if (optarg[0] == '+') {
5464                                 param.fp_comp_end_sign = -1;
5465                                 optarg++;
5466                         } else if (optarg[0] == '-') {
5467                                 param.fp_comp_end_sign =  1;
5468                                 optarg++;
5469                         }
5470
5471                         if (arg_is_eof(optarg)) {
5472                                 param.fp_comp_end = LUSTRE_EOF;
5473                                 param.fp_comp_end_units = 1;
5474                                 rc = 0;
5475                         } else {
5476                                 rc = llapi_parse_size(optarg,
5477                                                 &param.fp_comp_end,
5478                                                 &param.fp_comp_end_units, 0);
5479                                 /* assume units of KB if too small */
5480                                 if (param.fp_comp_end < 4096)
5481                                         param.fp_comp_end *= 1024;
5482                         }
5483                         if (rc) {
5484                                 fprintf(stderr,
5485                                         "error: bad component end '%s'\n",
5486                                         optarg);
5487                                 goto err;
5488                         }
5489                         param.fp_check_comp_end = 1;
5490                         param.fp_exclude_comp_end = !!neg_opt;
5491                         break;
5492                 case LFS_LAYOUT_FOREIGN_OPT: {
5493                         /* all types by default */
5494                         uint32_t type = LU_FOREIGN_TYPE_UNKNOWN;
5495
5496                         if (optarg) {
5497                                 /* check pure numeric */
5498                                 type = strtoul(optarg, &endptr, 0);
5499                                 if (*endptr) {
5500                                         /* check name */
5501                                         type = check_foreign_type_name(optarg);
5502                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
5503                                                 fprintf(stderr,
5504                                                         "%s %s: unknown foreign type '%s'\n",
5505                                                         progname, argv[0],
5506                                                         optarg);
5507                                                 return CMD_HELP;
5508                                         }
5509                                 } else if (type >= UINT32_MAX) {
5510                                         fprintf(stderr,
5511                                                 "%s %s: invalid foreign type '%s'\n",
5512                                                 progname, argv[0], optarg);
5513                                         return CMD_HELP;
5514                                 }
5515                         }
5516                         param.fp_foreign_type = type;
5517                         param.fp_check_foreign = 1;
5518                         param.fp_exclude_foreign = !!neg_opt;
5519                         break;
5520                 }
5521                 case LFS_NEWERXY_OPT: {
5522                         char x = 'm';
5523                         char y = 'm';
5524                         int xidx;
5525                         int negidx;
5526                         time_t *newery;
5527                         time_t ref = time(NULL);
5528
5529                         /* no need to check bad options, they won't get here */
5530                         if (strlen(long_opts[optidx].name) == 7) {
5531                                 x = long_opts[optidx].name[5];
5532                                 y = long_opts[optidx].name[6];
5533                         }
5534
5535                         if (y == 't') {
5536                                 static const char *const fmts[] = {
5537                                         "%Y-%m-%d %H:%M:%S",
5538                                         "%Y-%m-%d %H:%M",
5539                                         "%Y-%m-%d",
5540                                         "%H:%M:%S", /* sometime today */
5541                                         "%H:%M",
5542                                         "@%s",
5543                                         "%s",
5544                                         NULL };
5545                                 struct tm tm;
5546                                 bool found = false;
5547                                 int i;
5548
5549                                 for (i = 0; fmts[i] != NULL; i++) {
5550                                         char *ptr;
5551
5552                                         /* Init for times relative to today */
5553                                         if (strncmp(fmts[i], "%H", 2) == 0) {
5554                                                 localtime_r(&ref, &tm);
5555                                         } else {
5556                                                 memset(&tm, 0, sizeof(tm));
5557                                                 tm.tm_isdst = -1;
5558                                         }
5559                                         ptr = strptime(optarg, fmts[i], &tm);
5560                                         /* Skip spaces */
5561                                         while (ptr && isspace(*ptr))
5562                                                 ptr++;
5563                                         if (ptr == optarg + strlen(optarg)) {
5564                                                 found = true;
5565                                                 break;
5566                                         }
5567                                 }
5568
5569                                 if (!found) {
5570                                         fprintf(stderr,
5571                                                 "%s: invalid time '%s'\n",
5572                                                 progname, optarg);
5573                                         fprintf(stderr,
5574                                                 "supported formats are:\n  ");
5575                                         for (i = 0; fmts[i] != NULL; i++)
5576                                                 fprintf(stderr, "'%s', ",
5577                                                         fmts[i]);
5578                                         fprintf(stderr, "\n");
5579                                         ret = -EINVAL;
5580                                         goto err;
5581                                 }
5582
5583                                 ref = mktime(&tm);
5584                         } else if (y == 'b' || y == 'B') {
5585                                 lstatx_t stx;
5586
5587                                 rc = llapi_get_lum_file(optarg, NULL, &stx,
5588                                                         NULL, 0);
5589                                 if (rc || !(stx.stx_mask & STATX_BTIME)) {
5590                                         if (!(stx.stx_mask & STATX_BTIME))
5591                                                 ret = -EOPNOTSUPP;
5592                                         else
5593                                                 ret = -errno;
5594                                         fprintf(stderr,
5595                                                 "%s: get btime failed '%s': %s\n",
5596                                                 progname, optarg,
5597                                                 strerror(-ret));
5598                                         goto err;
5599                                 }
5600
5601                                 ref = stx.stx_btime.tv_sec;
5602                         } else {
5603                                 struct stat statbuf;
5604
5605                                 if (stat(optarg, &statbuf) < 0) {
5606                                         fprintf(stderr,
5607                                                 "%s: cannot stat file '%s': %s\n",
5608                                                 progname, optarg,
5609                                                 strerror(errno));
5610                                         ret = -errno;
5611                                         goto err;
5612                                 }
5613
5614                                 switch (y) {
5615                                 case 'a':
5616                                         ref = statbuf.st_atime;
5617                                         break;
5618                                 case 'm':
5619                                         ref = statbuf.st_mtime;
5620                                         break;
5621                                 case 'c':
5622                                         ref = statbuf.st_ctime;
5623                                         break;
5624                                 default:
5625                                         fprintf(stderr,
5626                                                 "%s: invalid Y argument: '%c'\n",
5627                                                 progname, x);
5628                                         ret = -EINVAL;
5629                                         goto err;
5630                                 }
5631                         }
5632
5633                         switch (x) {
5634                         case 'a':
5635                                 xidx = NEWERXY_ATIME;
5636                                 break;
5637                         case 'm':
5638                                 xidx = NEWERXY_MTIME;
5639                                 break;
5640                         case 'c':
5641                                 xidx = NEWERXY_CTIME;
5642                                 break;
5643                         case 'b':
5644                         case 'B':
5645                                 xidx = NEWERXY_BTIME;
5646                                 break;
5647                         default:
5648                                 fprintf(stderr,
5649                                         "%s: invalid X argument: '%c'\n",
5650                                         progname, x);
5651                                 ret = -EINVAL;
5652                                 goto err;
5653                         }
5654
5655                         negidx = !!neg_opt;
5656                         newery = &param.fp_newery[xidx][negidx];
5657
5658                         if (*newery == 0) {
5659                                 *newery = ref;
5660                         } else {
5661                                 if (negidx)
5662                                         *newery = *newery > ref ? ref : *newery;
5663                                 else
5664                                         *newery = *newery > ref ? *newery : ref;
5665                         }
5666                         param.fp_newerxy = 1;
5667                         break;
5668                 }
5669                 case 'g':
5670                 case 'G':
5671                         rc = name2gid(&param.fp_gid, optarg);
5672                         if (rc) {
5673                                 if (str2quotaid(&param.fp_gid, optarg)) {
5674                                         fprintf(stderr,
5675                                                 "Group/GID: %s cannot be found.\n",
5676                                                 optarg);
5677                                         ret = -1;
5678                                         goto err;
5679                                 }
5680                         }
5681                         param.fp_exclude_gid = !!neg_opt;
5682                         param.fp_check_gid = 1;
5683                         break;
5684                 case 'H':
5685                         rc = mdthash_input(optarg, &param.fp_hash_inflags,
5686                                            &param.fp_hash_exflags,
5687                                            &param.fp_hash_type);
5688                         if (rc) {
5689                                 ret = -1;
5690                                 goto err;
5691                         }
5692                         if (param.fp_hash_inflags || param.fp_hash_exflags)
5693                                 param.fp_check_hash_flag = 1;
5694                         param.fp_exclude_hash_type = !!neg_opt;
5695                         break;
5696                 case 'l':
5697                         param.fp_lazy = 1;
5698                         break;
5699                 case 'L':
5700                         ret = name2layout(&param.fp_layout, optarg);
5701                         if (ret)
5702                                 goto err;
5703                         param.fp_exclude_layout = !!neg_opt;
5704                         param.fp_check_layout = 1;
5705                         break;
5706                 case LFS_LINKS_OPT:
5707                         if (optarg[0] == '+') {
5708                                 param.fp_nlink_sign = -1;
5709                                 optarg++;
5710                         } else if (optarg[0] == '-') {
5711                                 param.fp_nlink_sign =  1;
5712                                 optarg++;
5713                         }
5714                         errno = 0;
5715                         param.fp_nlink = strtoul(optarg, &endptr, 0);
5716                         if (errno != 0 || *endptr != '\0' || !param.fp_nlink) {
5717                                 fprintf(stderr, "error: bad link count '%s'\n",
5718                                         optarg);
5719                                 ret = -1;
5720                                 goto err;
5721                         }
5722                         param.fp_exclude_nlink = !!neg_opt;
5723                         break;
5724                 case 'u':
5725                 case 'U':
5726                         rc = name2uid(&param.fp_uid, optarg);
5727                         if (rc) {
5728                                 if (str2quotaid(&param.fp_uid, optarg)) {
5729                                         fprintf(stderr,
5730                                                 "User/UID: %s cannot be found.\n",
5731                                                 optarg);
5732                                         ret = -1;
5733                                         goto err;
5734                                 }
5735                         }
5736                         param.fp_exclude_uid = !!neg_opt;
5737                         param.fp_check_uid = 1;
5738                         break;
5739                 case 'n':
5740                         param.fp_pattern = (char *)optarg;
5741                         param.fp_exclude_pattern = !!neg_opt;
5742                         break;
5743                 case 'N':
5744                         if (optarg[0] == '+') {
5745                                 param.fp_mirror_count_sign = -1;
5746                                 optarg++;
5747                         } else if (optarg[0] == '-') {
5748                                 param.fp_mirror_count_sign =  1;
5749                                 optarg++;
5750                         }
5751
5752                         errno = 0;
5753                         param.fp_mirror_count = strtoul(optarg, &endptr, 0);
5754                         if (errno != 0 || *endptr != '\0' ||
5755                             param.fp_mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
5756                                 fprintf(stderr,
5757                                         "error: bad mirror count '%s'\n",
5758                                         optarg);
5759                                 goto err;
5760                         }
5761                         param.fp_check_mirror_count = 1;
5762                         param.fp_exclude_mirror_count = !!neg_opt;
5763                         break;
5764                 case 'm':
5765                 case 'i':
5766                 case 'O': {
5767                         char *buf, *token, *next, *p;
5768                         int len = 1;
5769                         void *tmp;
5770
5771                         buf = strdup(optarg);
5772                         if (!buf) {
5773                                 ret = -ENOMEM;
5774                                 goto err;
5775                         }
5776
5777                         param.fp_exclude_obd = !!neg_opt;
5778
5779                         token = buf;
5780                         while (token && *token) {
5781                                 token = strchr(token, ',');
5782                                 if (token) {
5783                                         len++;
5784                                         token++;
5785                                 }
5786                         }
5787                         if (c == 'm') {
5788                                 param.fp_exclude_mdt = !!neg_opt;
5789                                 param.fp_num_alloc_mdts += len;
5790                                 tmp = realloc(param.fp_mdt_uuid,
5791                                               param.fp_num_alloc_mdts *
5792                                               sizeof(*param.fp_mdt_uuid));
5793                                 if (!tmp) {
5794                                         ret = -ENOMEM;
5795                                         goto err_free;
5796                                 }
5797
5798                                 param.fp_mdt_uuid = tmp;
5799                         } else {
5800                                 param.fp_exclude_obd = !!neg_opt;
5801                                 param.fp_num_alloc_obds += len;
5802                                 tmp = realloc(param.fp_obd_uuid,
5803                                               param.fp_num_alloc_obds *
5804                                               sizeof(*param.fp_obd_uuid));
5805                                 if (!tmp) {
5806                                         ret = -ENOMEM;
5807                                         goto err_free;
5808                                 }
5809
5810                                 param.fp_obd_uuid = tmp;
5811                         }
5812                         for (token = buf; token && *token; token = next) {
5813                                 struct obd_uuid *puuid;
5814
5815                                 if (c == 'm') {
5816                                         puuid =
5817                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
5818                                 } else {
5819                                         puuid =
5820                                         &param.fp_obd_uuid[param.fp_num_obds++];
5821                                 }
5822                                 p = strchr(token, ',');
5823                                 next = 0;
5824                                 if (p) {
5825                                         *p = 0;
5826                                         next = p+1;
5827                                 }
5828
5829                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
5830                                         ret = -E2BIG;
5831                                         goto err_free;
5832                                 }
5833
5834                                 strncpy(puuid->uuid, token,
5835                                         sizeof(puuid->uuid));
5836                         }
5837 err_free:
5838                         if (buf)
5839                                 free(buf);
5840                         break;
5841                 }
5842 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 18, 53, 0)
5843                 case 'p':
5844 #endif
5845                 case LFS_POOL_OPT:
5846                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
5847                                 fprintf(stderr,
5848                                         "Pool name %s is too long (max %d)\n",
5849                                         optarg, LOV_MAXPOOLNAME);
5850                                 ret = -1;
5851                                 goto err;
5852                         }
5853                         /*
5854                          * We do check for empty pool because empty pool
5855                          * is used to find V1 LOV attributes
5856                          */
5857                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
5858                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
5859                         param.fp_exclude_pool = !!neg_opt;
5860                         param.fp_check_pool = 1;
5861                         break;
5862                 case '0':
5863                         param.fp_zero_end = 1;
5864                         break;
5865                 case 'P': /* we always print, this option is a no-op */
5866                         break;
5867                 case LFS_PRINTF_OPT:
5868                         param.fp_format_printf_str = strdup(optarg);
5869                         break;
5870                 case LFS_PROJID_OPT:
5871                         rc = name2projid(&param.fp_projid, optarg);
5872                         if (rc) {
5873                                 if (str2quotaid(&param.fp_projid, optarg)) {
5874                                         fprintf(stderr,
5875                                                 "Invalid project ID: %s\n",
5876                                                 optarg);
5877                                         ret = -1;
5878                                         goto err;
5879                                 }
5880                         }
5881                         param.fp_exclude_projid = !!neg_opt;
5882                         param.fp_check_projid = 1;
5883                         break;
5884                 case 's':
5885                         if (optarg[0] == '+') {
5886                                 param.fp_size_sign = -1;
5887                                 optarg++;
5888                         } else if (optarg[0] == '-') {
5889                                 param.fp_size_sign =  1;
5890                                 optarg++;
5891                         }
5892
5893                         ret = llapi_parse_size(optarg, &param.fp_size,
5894                                                &param.fp_size_units, 0);
5895                         if (ret) {
5896                                 fprintf(stderr, "error: bad file size '%s'\n",
5897                                         optarg);
5898                                 goto err;
5899                         }
5900                         param.fp_check_size = 1;
5901                         param.fp_exclude_size = !!neg_opt;
5902                         break;
5903                 case 'S':
5904                         if (optarg[0] == '+') {
5905                                 param.fp_stripe_size_sign = -1;
5906                                 optarg++;
5907                         } else if (optarg[0] == '-') {
5908                                 param.fp_stripe_size_sign =  1;
5909                                 optarg++;
5910                         }
5911
5912                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
5913                                                &param.fp_stripe_size_units, 0);
5914                         /* assume units of KB if too small to be valid */
5915                         if (param.fp_stripe_size < 4096)
5916                                 param.fp_stripe_size *= 1024;
5917                         if (ret) {
5918                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
5919                                         optarg);
5920                                 goto err;
5921                         }
5922                         param.fp_check_stripe_size = 1;
5923                         param.fp_exclude_stripe_size = !!neg_opt;
5924                         break;
5925                 case 't':
5926                         param.fp_exclude_type = !!neg_opt;
5927                         switch (optarg[0]) {
5928                         case 'b':
5929                                 param.fp_type = S_IFBLK;
5930                                 break;
5931                         case 'c':
5932                                 param.fp_type = S_IFCHR;
5933                                 break;
5934                         case 'd':
5935                                 param.fp_type = S_IFDIR;
5936                                 break;
5937                         case 'f':
5938                                 param.fp_type = S_IFREG;
5939                                 break;
5940                         case 'l':
5941                                 param.fp_type = S_IFLNK;
5942                                 break;
5943                         case 'p':
5944                                 param.fp_type = S_IFIFO;
5945                                 break;
5946                         case 's':
5947                                 param.fp_type = S_IFSOCK;
5948                                 break;
5949                         default:
5950                                 fprintf(stderr, "%s: bad type '%s'\n",
5951                                         progname, optarg);
5952                                 ret = CMD_HELP;
5953                                 goto err;
5954                         }
5955                         break;
5956                 case LFS_FIND_PERM:
5957                         param.fp_exclude_perm = !!neg_opt;
5958                         param.fp_perm_sign = LFS_FIND_PERM_EXACT;
5959                         if (*optarg == '/') {
5960                                 param.fp_perm_sign = LFS_FIND_PERM_ANY;
5961                                 optarg++;
5962                         } else if (*optarg == '-') {
5963                                 param.fp_perm_sign = LFS_FIND_PERM_ALL;
5964                                 optarg++;
5965                         }
5966
5967                         if (str2mode_t(optarg, &param.fp_perm)) {
5968                                 fprintf(stderr, "error: invalid mode '%s'\n",
5969                                         optarg);
5970                                 ret = -1;
5971                                 goto err;
5972                         }
5973                         break;
5974                 case 'T':
5975                         if (optarg[0] == '+') {
5976                                 param.fp_mdt_count_sign = -1;
5977                                 optarg++;
5978                         } else if (optarg[0] == '-') {
5979                                 param.fp_mdt_count_sign =  1;
5980                                 optarg++;
5981                         }
5982
5983                         errno = 0;
5984                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
5985                         if (errno != 0 || *endptr != '\0' ||
5986                             param.fp_mdt_count >= UINT32_MAX) {
5987                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
5988                                         optarg);
5989                                 ret = -1;
5990                                 goto err;
5991                         }
5992                         param.fp_check_mdt_count = 1;
5993                         param.fp_exclude_mdt_count = !!neg_opt;
5994                         break;
5995                 case 'z':
5996                         if (optarg[0] == '+') {
5997                                 param.fp_ext_size_sign = -1;
5998                                 optarg++;
5999                         } else if (optarg[0] == '-') {
6000                                 param.fp_ext_size_sign =  1;
6001                                 optarg++;
6002                         }
6003
6004                         ret = llapi_parse_size(optarg, &param.fp_ext_size,
6005                                                &param.fp_ext_size_units, 0);
6006                         if (ret) {
6007                                 fprintf(stderr, "error: bad ext-size '%s'\n",
6008                                         optarg);
6009                                 goto err;
6010                         }
6011                         param.fp_ext_size /= SEL_UNIT_SIZE;
6012                         param.fp_ext_size_units /= SEL_UNIT_SIZE;
6013                         param.fp_check_ext_size = 1;
6014                         param.fp_exclude_ext_size = !!neg_opt;
6015                         break;
6016                 default:
6017                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6018                                 progname, argv[optind - 1]);
6019                 case 'h':
6020                         ret = CMD_HELP;
6021                         goto err;
6022                 }
6023         }
6024         if (!param.fp_verbose)
6025                 param.fp_verbose = VERBOSE_DEFAULT;
6026
6027         if (pathstart == -1) {
6028                 fprintf(stderr, "error: %s: no filename|pathname\n",
6029                         argv[0]);
6030                 ret = CMD_HELP;
6031                 goto err;
6032         } else if (pathend == -1) {
6033                 /* no options */
6034                 pathend = argc;
6035         }
6036
6037         do {
6038                 rc = llapi_find(argv[pathstart], &param);
6039                 if (rc && !ret) {
6040                         ret = rc;
6041                         pathbad = pathstart;
6042                 }
6043         } while (++pathstart < pathend);
6044
6045         if (ret)
6046                 fprintf(stderr, "%s: failed for '%s': %s\n",
6047                         progname, argv[pathbad], strerror(-rc));
6048
6049 err:
6050         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
6051                 free(param.fp_obd_uuid);
6052
6053         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
6054                 free(param.fp_mdt_uuid);
6055
6056         if (param.fp_format_printf_str)
6057                 free(param.fp_format_printf_str);
6058
6059         return ret;
6060 }
6061
6062 static int lfs_getstripe_internal(int argc, char **argv,
6063                                   struct find_param *param)
6064 {
6065         struct option long_opts[] = {
6066 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
6067 /* find { .val = 'b',   .name = "blocks",       .has_arg = required_argument }*/
6068 /* find { .val = 'B',   .name = "btime",        .has_arg = required_argument }*/
6069 /* find { .val = 'B',   .name = "Btime",        .has_arg = required_argument }*/
6070         { .val = LFS_COMP_COUNT_OPT,
6071                         .name = "comp-count",   .has_arg = no_argument },
6072         { .val = LFS_COMP_COUNT_OPT,
6073                 .name = "component-count",      .has_arg = no_argument },
6074         { .val = LFS_COMP_FLAGS_OPT,
6075                         .name = "comp-flags",   .has_arg = optional_argument },
6076         { .val = LFS_COMP_FLAGS_OPT,
6077                 .name = "component-flags",      .has_arg = optional_argument },
6078         { .val = LFS_COMP_START_OPT,
6079                         .name = "comp-start",   .has_arg = optional_argument },
6080         { .val = LFS_COMP_START_OPT,
6081                 .name = "component-start",      .has_arg = optional_argument },
6082         { .val = 'c',   .name = "stripe-count", .has_arg = no_argument },
6083         { .val = 'c',   .name = "stripe_count", .has_arg = no_argument },
6084 /* find { .val = 'C',   .name = "ctime",        .has_arg = required_argument }*/
6085         { .val = 'd',   .name = "directory",    .has_arg = no_argument },
6086         { .val = 'D',   .name = "default",      .has_arg = no_argument },
6087         { .val = 'E',   .name = "comp-end",     .has_arg = optional_argument },
6088         { .val = 'E',   .name = "component-end", .has_arg = optional_argument },
6089         { .val = 'F',   .name = "fid",          .has_arg = no_argument },
6090         { .val = 'g',   .name = "generation",   .has_arg = no_argument },
6091 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
6092         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6093         { .val = LFS_HEX_IDX_OPT,
6094                         .name = "hex-idx",      .has_arg = no_argument },
6095 /* dirstripe { .val = 'H', .name = "mdt-hash",  .has_arg = required_argument }*/
6096         { .val = 'i',   .name = "stripe-index", .has_arg = no_argument },
6097         { .val = 'i',   .name = "stripe_index", .has_arg = no_argument },
6098         { .val = 'I',   .name = "comp-id",      .has_arg = optional_argument },
6099         { .val = 'I',   .name = "component-id", .has_arg = optional_argument },
6100 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
6101         { .val = 'L',   .name = "layout",       .has_arg = no_argument },
6102         { .val = 'm',   .name = "mdt",          .has_arg = no_argument },
6103         { .val = 'm',   .name = "mdt-index",    .has_arg = no_argument },
6104         { .val = 'm',   .name = "mdt_index",    .has_arg = no_argument },
6105 /* find { .val = 'M',   .name = "mtime",        .has_arg = required_argument }*/
6106 /* find { .val = 'n',   .name = "name",         .has_arg = required_argument }*/
6107         { .val = 'N',   .name = "mirror-count", .has_arg = no_argument },
6108         { .val = LFS_MIRROR_INDEX_OPT,
6109                         .name = "mirror-index", .has_arg = required_argument },
6110         { .val = LFS_MIRROR_ID_OPT,
6111                         .name = "mirror-id",    .has_arg = required_argument },
6112         { .val = LFS_NO_FOLLOW_OPT,
6113                         .name = "no-follow",    .has_arg = no_argument },
6114         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
6115         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
6116         { .val = 'p',   .name = "pool",         .has_arg = no_argument },
6117 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
6118         { .val = 'q',   .name = "quiet",        .has_arg = no_argument },
6119         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
6120         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
6121         { .val = 'S',   .name = "stripe-size",  .has_arg = no_argument },
6122         { .val = 'S',   .name = "stripe_size",  .has_arg = no_argument },
6123 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
6124 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
6125 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
6126 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
6127         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
6128 /* dirstripe { .val = 'X',.name = "max-inherit",.has_arg = required_argument }*/
6129 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }*/
6130         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
6131         { .val = 'z',   .name = "extension-size", .has_arg = no_argument },
6132         { .val = 'z',   .name = "ext-size",     .has_arg = no_argument },
6133         { .name = NULL } };
6134         int c, rc = 0;
6135         int neg_opt = 0;
6136         int pathstart = -1, pathend = -1;
6137         int isoption;
6138         char *end, *tmp;
6139
6140         while ((c = getopt_long(argc, argv,
6141                         "-cdDE::FghiI::LmMNoO:pqrRsSvyz",
6142                         long_opts, NULL)) != -1) {
6143                 if (neg_opt)
6144                         --neg_opt;
6145
6146                 /* '!' is part of option */
6147                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
6148                 if (!isoption && pathend != -1) {
6149                         fprintf(stderr,
6150                                 "error: %s: filename|dirname must either precede options or follow options\n",
6151                                 argv[0]);
6152                         return CMD_HELP;
6153                 }
6154                 if (!isoption && pathstart == -1)
6155                         pathstart = optind - 1;
6156                 if (isoption && pathstart != -1 && pathend == -1)
6157                         pathend = optind - 2;
6158
6159                 switch (c) {
6160                 case 1:
6161                         /* unknown: opt is "!" */
6162                         if (strcmp(optarg, "!") == 0)
6163                                 neg_opt = 2;
6164                         break;
6165                 case 'c':
6166                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6167                                 param->fp_verbose |= VERBOSE_COUNT;
6168                                 param->fp_max_depth = 0;
6169                         }
6170                         break;
6171                 case LFS_COMP_COUNT_OPT:
6172                         param->fp_verbose |= VERBOSE_COMP_COUNT;
6173                         param->fp_max_depth = 0;
6174                         break;
6175                 case LFS_COMP_FLAGS_OPT:
6176                         if (optarg) {
6177                                 rc = comp_str2flags(optarg,
6178                                                     &param->fp_comp_flags,
6179                                                     &param->fp_comp_neg_flags);
6180                                 if (rc != 0) {
6181                                         fprintf(stderr,
6182                                                 "error: %s bad component flags '%s'.\n",
6183                                                 argv[0], optarg);
6184                                         return CMD_HELP;
6185                                 }
6186                                 param->fp_check_comp_flags = 1;
6187                         } else {
6188                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
6189                                 param->fp_max_depth = 0;
6190                         }
6191                         break;
6192                 case LFS_COMP_START_OPT:
6193                         if (optarg) {
6194                                 tmp = optarg;
6195                                 if (tmp[0] == '+') {
6196                                         param->fp_comp_start_sign = -1;
6197                                         tmp++;
6198                                 } else if (tmp[0] == '-') {
6199                                         param->fp_comp_start_sign = 1;
6200                                         tmp++;
6201                                 }
6202                                 rc = llapi_parse_size(tmp,
6203                                                 &param->fp_comp_start,
6204                                                 &param->fp_comp_start_units, 0);
6205                                 if (rc != 0) {
6206                                         fprintf(stderr,
6207                                                 "error: %s bad component start '%s'.\n",
6208                                                 argv[0], tmp);
6209                                         return CMD_HELP;
6210                                 }
6211                                 param->fp_check_comp_start = 1;
6212                         } else {
6213                                 param->fp_verbose |= VERBOSE_COMP_START;
6214                                 param->fp_max_depth = 0;
6215                         }
6216                         break;
6217                 case LFS_MIRROR_INDEX_OPT: {
6218                         unsigned long int mirror_index;
6219
6220                         if (optarg[0] == '+') {
6221                                 param->fp_mirror_index_sign = -1;
6222                                 optarg++;
6223                         } else if (optarg[0] == '-') {
6224                                 param->fp_mirror_index_sign = 1;
6225                                 optarg++;
6226                         }
6227
6228                         errno = 0;
6229                         mirror_index = strtoul(optarg, &end, 0);
6230                         if (errno != 0 || *end != '\0' ||
6231                             mirror_index > UINT16_MAX || (mirror_index == 0 &&
6232                             param->fp_mirror_index_sign == 0 && neg_opt == 0)) {
6233                                 fprintf(stderr,
6234                                         "%s %s: invalid mirror index '%s'\n",
6235                                         progname, argv[0], optarg);
6236                                 return CMD_HELP;
6237                         }
6238
6239                         param->fp_mirror_index = (__u16)mirror_index;
6240
6241                         if (param->fp_mirror_id != 0) {
6242                                 fprintf(stderr,
6243                                         "%s %s: can't specify both mirror index and mirror ID\n",
6244                                         progname, argv[0]);
6245                                 return CMD_HELP;
6246                         }
6247                         param->fp_check_mirror_index = 1;
6248                         param->fp_exclude_mirror_index = !!neg_opt;
6249                         break;
6250                 }
6251                 case LFS_MIRROR_ID_OPT: {
6252                         unsigned long int mirror_id;
6253
6254                         if (optarg[0] == '+') {
6255                                 param->fp_mirror_id_sign = -1;
6256                                 optarg++;
6257                         } else if (optarg[0] == '-') {
6258                                 param->fp_mirror_id_sign = 1;
6259                                 optarg++;
6260                         }
6261
6262                         errno = 0;
6263                         mirror_id = strtoul(optarg, &end, 0);
6264                         if (errno != 0 || *end != '\0' ||
6265                             mirror_id > UINT16_MAX || (mirror_id == 0 &&
6266                             param->fp_mirror_id_sign == 0 && neg_opt == 0)) {
6267                                 fprintf(stderr,
6268                                         "%s %s: invalid mirror ID '%s'\n",
6269                                         progname, argv[0], optarg);
6270                                 return CMD_HELP;
6271                         }
6272
6273                         param->fp_mirror_id = (__u16)mirror_id;
6274
6275                         if (param->fp_mirror_index != 0) {
6276                                 fprintf(stderr,
6277                                         "%s %s: can't specify both mirror index and mirror ID\n",
6278                                         progname, argv[0]);
6279                                 return CMD_HELP;
6280                         }
6281                         param->fp_check_mirror_id = 1;
6282                         param->fp_exclude_mirror_id = !!neg_opt;
6283                         break;
6284                 }
6285                 case LFS_NO_FOLLOW_OPT:
6286                         param->fp_no_follow = true;
6287                         break;
6288                 case LFS_HEX_IDX_OPT:
6289                         param->fp_hex_idx = true;
6290                         break;
6291                 case 'd':
6292                         param->fp_max_depth = 0;
6293                         break;
6294                 case 'D':
6295                         param->fp_get_default_lmv = 1;
6296                         break;
6297                 case 'E':
6298                         if (optarg) {
6299                                 tmp = optarg;
6300                                 if (tmp[0] == '+') {
6301                                         param->fp_comp_end_sign = -1;
6302                                         tmp++;
6303                                 } else if (tmp[0] == '-') {
6304                                         param->fp_comp_end_sign = 1;
6305                                         tmp++;
6306                                 }
6307
6308                                 if (arg_is_eof(tmp)) {
6309                                         param->fp_comp_end = LUSTRE_EOF;
6310                                         param->fp_comp_end_units = 1;
6311                                         rc = 0;
6312                                 } else {
6313                                         rc = llapi_parse_size(tmp,
6314                                                 &param->fp_comp_end,
6315                                                 &param->fp_comp_end_units, 0);
6316                                         /* assume units of KB if too small */
6317                                         if (param->fp_comp_end < 4096)
6318                                                 param->fp_comp_end *= 1024;
6319                                 }
6320                                 if (rc != 0) {
6321                                         fprintf(stderr,
6322                                                 "error: %s bad component end '%s'.\n",
6323                                                 argv[0], tmp);
6324                                         return CMD_HELP;
6325                                 }
6326                                 param->fp_check_comp_end = 1;
6327                         } else {
6328                                 param->fp_verbose |= VERBOSE_COMP_END;
6329                                 param->fp_max_depth = 0;
6330                         }
6331                         break;
6332                 case 'F':
6333                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6334                                 param->fp_verbose |= VERBOSE_DFID;
6335                                 param->fp_max_depth = 0;
6336                         }
6337                         break;
6338                 case 'g':
6339                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6340                                 param->fp_verbose |= VERBOSE_GENERATION;
6341                                 param->fp_max_depth = 0;
6342                         }
6343                         break;
6344                 case 'i':
6345                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6346                                 param->fp_verbose |= VERBOSE_STRIPE_OFFSET;
6347                                 param->fp_max_depth = 0;
6348                         }
6349                         break;
6350                 case 'I':
6351                         if (optarg) {
6352                                 param->fp_comp_id = strtoul(optarg, &end, 0);
6353                                 if (*end != '\0' || param->fp_comp_id == 0 ||
6354                                     param->fp_comp_id > LCME_ID_MAX) {
6355                                         fprintf(stderr,
6356                                                 "error: %s bad component id '%s'\n",
6357                                                 argv[0], optarg);
6358                                         return CMD_HELP;
6359                                 }
6360                                 param->fp_check_comp_id = 1;
6361                         } else {
6362                                 param->fp_max_depth = 0;
6363                                 param->fp_verbose |= VERBOSE_COMP_ID;
6364                         }
6365                         break;
6366                 case 'L':
6367                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6368                                 param->fp_verbose |= VERBOSE_PATTERN;
6369                                 param->fp_max_depth = 0;
6370                         }
6371                         break;
6372 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6373                 case 'M':
6374                         fprintf(stderr,
6375                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
6376 #endif
6377                 case 'm':
6378                         if (!(param->fp_verbose & VERBOSE_DETAIL))
6379                                 param->fp_max_depth = 0;
6380                         param->fp_verbose |= VERBOSE_MDTINDEX;
6381                         break;
6382                 case 'N':
6383                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6384                                 param->fp_verbose |= VERBOSE_MIRROR_COUNT;
6385                                 param->fp_max_depth = 0;
6386                         }
6387                         break;
6388                 case 'O':
6389                         if (param->fp_obd_uuid) {
6390                                 fprintf(stderr,
6391                                         "error: %s: only one obduuid allowed",
6392                                         argv[0]);
6393                                 return CMD_HELP;
6394                         }
6395                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
6396                         break;
6397                 case 'p':
6398                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6399                                 param->fp_verbose |= VERBOSE_POOL;
6400                                 param->fp_max_depth = 0;
6401                         }
6402                         break;
6403                 case 'q':
6404                         param->fp_quiet++;
6405                         break;
6406                 case 'r':
6407                         param->fp_recursive = 1;
6408                         break;
6409                 case 'R':
6410                         param->fp_raw = 1;
6411                         break;
6412                 case 'S':
6413                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6414                                 param->fp_verbose |= VERBOSE_STRIPE_SIZE;
6415                                 param->fp_max_depth = 0;
6416                         }
6417                         break;
6418                 case 'v':
6419                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
6420                         break;
6421                 case 'y':
6422                         param->fp_yaml = 1;
6423                         break;
6424                 case 'z':
6425                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
6426                                 param->fp_verbose |= VERBOSE_EXT_SIZE;
6427                                 param->fp_max_depth = 0;
6428                         }
6429                         break;
6430                 default:
6431                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6432                                 progname, argv[optind - 1]);
6433                 case 'h':
6434                         return CMD_HELP;
6435                 }
6436         }
6437
6438         if (pathstart == -1) {
6439                 fprintf(stderr, "error: %s: no filename|pathname\n",
6440                                 argv[0]);
6441                 return CMD_HELP;
6442         } else if (pathend == -1) {
6443                 /* no options */
6444                 pathend = argc;
6445         }
6446
6447         if (pathend > argc)
6448                 return CMD_HELP;
6449
6450         if (param->fp_recursive)
6451                 param->fp_max_depth = -1;
6452         else if (param->fp_verbose & VERBOSE_DETAIL)
6453                 param->fp_max_depth = 1;
6454
6455         if (!param->fp_verbose)
6456                 param->fp_verbose = VERBOSE_DEFAULT;
6457         if (param->fp_quiet)
6458                 param->fp_verbose = VERBOSE_OBJID;
6459
6460         do {
6461                 int rc2;
6462
6463                 rc2 = llapi_getstripe(argv[pathstart], param);
6464                 if (rc2) {
6465                         fprintf(stderr, "%s: %s for '%s' failed: %s\n",
6466                                 progname, argv[0], argv[optind - 1],
6467                                 strerror(-rc2));
6468                         if (!rc)
6469                                 rc = rc2;
6470                 }
6471         } while (++pathstart < pathend);
6472
6473         return rc;
6474 }
6475
6476 static int lfs_tgts(int argc, char **argv)
6477 {
6478         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
6479         struct find_param param;
6480         int index = 0, rc = 0;
6481
6482         if (argc > 2)
6483                 return CMD_HELP;
6484
6485         if (argc == 2 && !realpath(argv[1], path)) {
6486                 rc = -errno;
6487                 fprintf(stderr, "error: invalid path '%s': %s\n",
6488                         argv[1], strerror(-rc));
6489                 return rc;
6490         }
6491
6492         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
6493                 /* Check if we have a mount point */
6494                 if (mntdir[0] == '\0')
6495                         continue;
6496
6497                 memset(&param, 0, sizeof(param));
6498                 if (!strcmp(argv[0], "mdts"))
6499                         param.fp_get_lmv = 1;
6500
6501                 rc = llapi_ostlist(mntdir, &param);
6502                 if (rc) {
6503                         fprintf(stderr, "error: %s: failed on %s\n",
6504                                 argv[0], mntdir);
6505                 }
6506                 if (path[0] != '\0')
6507                         break;
6508                 memset(mntdir, 0, PATH_MAX);
6509         }
6510
6511         return rc;
6512 }
6513
6514 static int lfs_getstripe(int argc, char **argv)
6515 {
6516         struct find_param param = { 0 };
6517
6518         param.fp_max_depth = 1;
6519         return lfs_getstripe_internal(argc, argv, &param);
6520 }
6521
6522 /* functions */
6523 static int lfs_getdirstripe(int argc, char **argv)
6524 {
6525         struct find_param param = { 0 };
6526         struct option long_opts[] = {
6527         { .val = 'c',   .name = "mdt-count",     .has_arg = no_argument },
6528         { .val = 'D',   .name = "default",       .has_arg = no_argument },
6529         { .val = 'h',   .name = "help",         .has_arg = no_argument },
6530         { .val = 'H',   .name = "mdt-hash",      .has_arg = no_argument },
6531         { .val = LFS_HEX_IDX_OPT,
6532                         .name = "hex-idx",       .has_arg = no_argument },
6533         { .val = 'i',   .name = "mdt-index",     .has_arg = no_argument },
6534         { .val = 'm',   .name = "mdt-index",     .has_arg = no_argument },
6535         { .val = 'O',   .name = "obd",           .has_arg = required_argument },
6536         { .val = 'r',   .name = "recursive",     .has_arg = no_argument },
6537         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
6538         { .val = 'T',   .name = "mdt-count",     .has_arg = no_argument },
6539         { .val = 'v',   .name = "verbose",       .has_arg = no_argument },
6540         { .val = 'X',   .name = "max-inherit",   .has_arg = no_argument },
6541         { .val = LFS_INHERIT_RR_OPT,
6542                         .name = "max-inherit-rr", .has_arg = no_argument },
6543         { .val = 'y',   .name = "yaml",          .has_arg = no_argument },
6544         { .name = NULL } };
6545         int c, rc = 0;
6546
6547         param.fp_get_lmv = 1;
6548
6549         while ((c = getopt_long(argc, argv,
6550                                 "cDhHimO:rRtTvXy", long_opts, NULL)) != -1) {
6551                 switch (c) {
6552                 case 'c':
6553                 case 'T':
6554                         param.fp_verbose |= VERBOSE_COUNT;
6555                         break;
6556                 case 'D':
6557                         param.fp_get_default_lmv = 1;
6558                         break;
6559 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
6560                 case 't':
6561                         fprintf(stderr,
6562                                 "warning: '-t' deprecated, use '--mdt-hash' or '-H' instead\n");
6563                         fallthrough;
6564 #endif
6565                 case 'H':
6566                         param.fp_verbose |= VERBOSE_HASH_TYPE;
6567                         break;
6568                 case LFS_HEX_IDX_OPT:
6569                         param.fp_hex_idx = 1;
6570                         break;
6571                 case 'i':
6572                         fallthrough;
6573                 case 'm':
6574                         param.fp_verbose |= VERBOSE_STRIPE_OFFSET;
6575                         break;
6576                 case 'O':
6577                         if (param.fp_obd_uuid) {
6578                                 fprintf(stderr,
6579                                         "%s: only one obduuid allowed",
6580                                         progname);
6581                                 return CMD_HELP;
6582                         }
6583                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
6584                         break;
6585                 case 'r':
6586                         param.fp_recursive = 1;
6587                         break;
6588                 case 'R':
6589                         param.fp_raw = 1;
6590                         break;
6591                 case 'v':
6592                         param.fp_verbose |= VERBOSE_DEFAULT;
6593                         param.fp_verbose |= VERBOSE_DETAIL;
6594                         break;
6595                 case 'X':
6596                         param.fp_verbose |= VERBOSE_INHERIT;
6597                         break;
6598                 case LFS_INHERIT_RR_OPT:
6599                         param.fp_verbose |= VERBOSE_INHERIT_RR;
6600                         break;
6601                 case 'y':
6602                         param.fp_yaml = 1;
6603                         break;
6604                 default:
6605                         fprintf(stderr, "%s: unrecognized option '%s'\n",
6606                                 progname, argv[optind - 1]);
6607                         fallthrough;
6608                 case 'h':
6609                         return CMD_HELP;
6610                 }
6611         }
6612
6613         if (optind >= argc)
6614                 return CMD_HELP;
6615
6616         if (param.fp_recursive)
6617                 param.fp_max_depth = -1;
6618
6619         if (!param.fp_verbose)
6620                 param.fp_verbose = VERBOSE_DEFAULT;
6621
6622         do {
6623                 int rc2;
6624
6625                 rc2 = llapi_getstripe(argv[optind], &param);
6626                 if (rc2) {
6627                         fprintf(stderr, "%s: %s for '%s' failed: %s\n",
6628                                 progname, argv[0], argv[optind],
6629                                 strerror(-rc2));
6630                         if (!rc)
6631                                 rc = rc2;
6632                 }
6633         } while (++optind < argc);
6634
6635         return rc;
6636 }
6637
6638 enum mntdf_flags {
6639         MNTDF_INODES    = 0x0001,
6640         MNTDF_COOKED    = 0x0002,
6641         MNTDF_LAZY      = 0x0004,
6642         MNTDF_VERBOSE   = 0x0008,
6643         MNTDF_SHOW      = 0x0010,
6644         MNTDF_DECIMAL   = 0x0020,
6645 };
6646
6647 #define COOK(value, base)                                       \
6648 ({                                                              \
6649         int radix = 0;                                          \
6650         while (value > base) {                                  \
6651                 value /= base;                                  \
6652                 radix++;                                        \
6653         }                                                       \
6654         radix;                                                  \
6655 })
6656 #define UUF     "%-20s"
6657 #define CSF     "%11s"
6658 #define CDF     "%11llu"
6659 #define HDF     "%8.1f%c"
6660 #define RSF     "%4s"
6661 #define RDF     "%3d%%"
6662
6663 static inline int obd_statfs_ratio(const struct obd_statfs *st, bool inodes)
6664 {
6665         double avail, used, ratio = 0;
6666
6667         if (inodes) {
6668                 avail = st->os_ffree;
6669                 used = st->os_files - st->os_ffree;
6670         } else {
6671                 avail = st->os_bavail;
6672                 used = st->os_blocks - st->os_bfree;
6673         }
6674         if (avail + used > 0)
6675                 ratio = used / (used + avail) * 100;
6676
6677         /* Round up to match df(1) usage percentage */
6678         return (ratio - (int)ratio) > 0 ? (int)(ratio + 1) : (int)ratio;
6679 }
6680
6681 /*
6682  * This is to identify various problem states for "lfs df" if .osn_err = true,
6683  * so only show flags reflecting those states by default. Informational states
6684  * are only shown with "-v" and use lower-case names to distinguish them.
6685  * UNUSED[12] were for "EROFS = 30" until 1.6 but are now available for use.
6686  */
6687 static struct obd_statfs_state_names {
6688         enum obd_statfs_state   osn_state;
6689         const char              osn_name;
6690         bool                    osn_err;
6691 } oss_names[] = {
6692         { .osn_state = OS_STATFS_DEGRADED,   .osn_name = 'D', .osn_err = true },
6693         { .osn_state = OS_STATFS_READONLY,   .osn_name = 'R', .osn_err = true },
6694         { .osn_state = OS_STATFS_NOCREATE,   .osn_name = 'N', .osn_err = true },
6695         { .osn_state = OS_STATFS_UNUSED1,    .osn_name = '?', .osn_err = true },
6696         { .osn_state = OS_STATFS_UNUSED2,    .osn_name = '?', .osn_err = true },
6697         { .osn_state = OS_STATFS_ENOSPC,     .osn_name = 'S', .osn_err = true },
6698         { .osn_state = OS_STATFS_ENOINO,     .osn_name = 'I', .osn_err = true },
6699         { .osn_state = OS_STATFS_SUM,        .osn_name = 'a', /* aggregate */ },
6700         { .osn_state = OS_STATFS_NONROT,     .osn_name = 'f', /* flash */     },
6701 };
6702
6703 static int showdf(char *mntdir, struct obd_statfs *stat,
6704                   char *uuid, enum mntdf_flags flags,
6705                   char *type, int index, int rc)
6706 {
6707         long long avail, used, total;
6708         int ratio = 0;
6709         char *suffix = flags & MNTDF_DECIMAL ? "kMGTPEZY" : "KMGTPEZY";
6710         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
6711         char tbuf[3 * sizeof(__u64)];
6712         char ubuf[3 * sizeof(__u64)];
6713         char abuf[3 * sizeof(__u64)];
6714         char rbuf[3 * sizeof(__u64)];
6715
6716         if (!uuid || !stat)
6717                 return -EINVAL;
6718
6719         switch (rc) {
6720         case 0:
6721                 if (flags & MNTDF_INODES) {
6722                         avail = stat->os_ffree;
6723                         used = stat->os_files - stat->os_ffree;
6724                         total = stat->os_files;
6725                 } else {
6726                         int shift = flags & MNTDF_COOKED ? 0 : 10;
6727
6728                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
6729                         used  = ((stat->os_blocks - stat->os_bfree) *
6730                                  stat->os_bsize) >> shift;
6731                         total = (stat->os_blocks * stat->os_bsize) >> shift;
6732                 }
6733
6734                 ratio = obd_statfs_ratio(stat, flags & MNTDF_INODES);
6735
6736                 if (flags & MNTDF_COOKED) {
6737                         int base = flags & MNTDF_DECIMAL ? 1000 : 1024;
6738                         double cook_val;
6739                         int i;
6740
6741                         cook_val = (double)total;
6742                         i = COOK(cook_val, base);
6743                         if (i > 0)
6744                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
6745                                          suffix[i - 1]);
6746                         else
6747                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
6748
6749                         cook_val = (double)used;
6750                         i = COOK(cook_val, base);
6751                         if (i > 0)
6752                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
6753                                          suffix[i - 1]);
6754                         else
6755                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
6756
6757                         cook_val = (double)avail;
6758                         i = COOK(cook_val, base);
6759                         if (i > 0)
6760                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
6761                                          suffix[i - 1]);
6762                         else
6763                                 snprintf(abuf, sizeof(abuf), CDF, avail);
6764                 } else {
6765                         snprintf(tbuf, sizeof(tbuf), CDF, total);
6766                         snprintf(ubuf, sizeof(tbuf), CDF, used);
6767                         snprintf(abuf, sizeof(tbuf), CDF, avail);
6768                 }
6769
6770                 sprintf(rbuf, RDF, ratio);
6771                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
6772                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
6773                 if (type)
6774                         printf("[%s:%d]", type, index);
6775
6776                 if (stat->os_state) {
6777                         uint32_t i;
6778
6779                         printf(" ");
6780                         for (i = 0; i < ARRAY_SIZE(oss_names); i++) {
6781                                 if (oss_names[i].osn_state & stat->os_state &&
6782                                     (oss_names[i].osn_err ||
6783                                      flags & MNTDF_VERBOSE))
6784                                         printf("%c", oss_names[i].osn_name);
6785                         }
6786                 }
6787
6788                 printf("\n");
6789                 break;
6790         case -ENODATA:
6791                 printf(UUF": inactive device\n", uuid);
6792                 break;
6793         default:
6794                 printf(UUF": %s\n", uuid, strerror(-rc));
6795                 break;
6796         }
6797
6798         return 0;
6799 }
6800
6801 struct ll_stat_type {
6802         int   st_op;
6803         char *st_name;
6804 };
6805
6806 #define LL_STATFS_MAX   LOV_MAX_STRIPE_COUNT
6807
6808 struct ll_statfs_data {
6809         int                     sd_index;
6810         struct obd_statfs       sd_st;
6811 };
6812
6813 struct ll_statfs_buf {
6814         int                     sb_count;
6815         struct ll_statfs_data   sb_buf[LL_STATFS_MAX];
6816 };
6817
6818 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags,
6819                  int ops, struct ll_statfs_buf *lsb)
6820 {
6821         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
6822         struct obd_uuid uuid_buf;
6823         char *poolname = NULL;
6824         struct ll_stat_type types[] = {
6825                 { .st_op = LL_STATFS_LMV,       .st_name = "MDT" },
6826                 { .st_op = LL_STATFS_LOV,       .st_name = "OST" },
6827                 { .st_name = NULL } };
6828         struct ll_stat_type *tp;
6829         __u64 ost_files = 0;
6830         __u64 ost_ffree = 0;
6831         __u32 index;
6832         __u32 type;
6833         int fd;
6834         int rc = 0;
6835         int rc2;
6836
6837         if (pool) {
6838                 poolname = strchr(pool, '.');
6839                 if (poolname) {
6840                         if (strncmp(fsname, pool, strlen(fsname))) {
6841                                 fprintf(stderr, "filesystem name incorrect\n");
6842                                 return -ENODEV;
6843                         }
6844                         poolname++;
6845                 } else
6846                         poolname = pool;
6847         }
6848
6849         fd = open(mntdir, O_RDONLY);
6850         if (fd < 0) {
6851                 rc = -errno;
6852                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
6853                         strerror(errno));
6854                 return rc;
6855         }
6856
6857         if (flags & MNTDF_SHOW) {
6858                 if (flags & MNTDF_INODES)
6859                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
6860                                "UUID", "Inodes", "IUsed", "IFree",
6861                                "IUse%", "Mounted on");
6862                 else
6863                         printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
6864                                "UUID",
6865                                flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
6866                                "Used", "Available", "Use%", "Mounted on");
6867         }
6868
6869         for (tp = types; tp->st_name != NULL; tp++) {
6870                 bool have_ost = false;
6871
6872                 if (!(tp->st_op & ops))
6873                         continue;
6874
6875                 for (index = 0; index < LOV_ALL_STRIPES &&
6876                      (!lsb || lsb->sb_count < LL_STATFS_MAX); index++) {
6877                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
6878                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
6879                         type = flags & MNTDF_LAZY ?
6880                                 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
6881                         rc2 = llapi_obd_fstatfs(fd, type, index,
6882                                                 &stat_buf, &uuid_buf);
6883                         if (rc2 == -ENODEV)
6884                                 break;
6885                         if (rc2 == -EAGAIN)
6886                                 continue;
6887                         if (rc2 == -ENODATA) { /* Inactive device, OK. */
6888                                 if (!(flags & MNTDF_VERBOSE))
6889                                         continue;
6890                         } else if (rc2 < 0 && rc == 0) {
6891                                 rc = rc2;
6892                         }
6893
6894                         /*
6895                          * If we have OSTs then don't report MDT block counts.
6896                          * For MDT-only filesystems the expectation is that all
6897                          * layouts have a DoM component.  For filesystems with
6898                          * OSTs, files are not necessarily going to store data
6899                          * on MDTs, and MDT space is limited to a fraction of
6900                          * OST space, so don't include it in the summary.
6901                          */
6902                         if (tp->st_op == LL_STATFS_LOV && !have_ost) {
6903                                 have_ost = true;
6904                                 sum.os_blocks = 0;
6905                                 sum.os_bfree = 0;
6906                                 sum.os_bavail = 0;
6907                         }
6908
6909                         if (poolname && tp->st_op == LL_STATFS_LOV &&
6910                             llapi_search_ost(fsname, poolname,
6911                                              obd_uuid2str(&uuid_buf)) != 1)
6912                                 continue;
6913
6914                         /*
6915                          * the llapi_obd_fstatfs() call may have returned with
6916                          * an error, but if it filled in uuid_buf we will at
6917                          * lease use that to print out a message for that OBD.
6918                          * If we didn't get anything in the uuid_buf, then fill
6919                          * it in so that we can print an error message.
6920                          */
6921                         if (uuid_buf.uuid[0] == '\0')
6922                                 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
6923                                          "%s%04x", tp->st_name, index);
6924                         if (!rc && lsb) {
6925                                 lsb->sb_buf[lsb->sb_count].sd_index = index;
6926                                 lsb->sb_buf[lsb->sb_count].sd_st = stat_buf;
6927                                 lsb->sb_count++;
6928                         }
6929                         if (flags & MNTDF_SHOW)
6930                                 showdf(mntdir, &stat_buf,
6931                                        obd_uuid2str(&uuid_buf), flags,
6932                                        tp->st_name, index, rc2);
6933
6934                         if (rc2)
6935                                 continue;
6936
6937                         if (tp->st_op == LL_STATFS_LMV) {
6938                                 sum.os_ffree += stat_buf.os_ffree;
6939                                 sum.os_files += stat_buf.os_files;
6940                         } else /* if (tp->st_op == LL_STATFS_LOV) */ {
6941                                 ost_files += stat_buf.os_files;
6942                                 ost_ffree += stat_buf.os_ffree;
6943                         }
6944                         sum.os_blocks += stat_buf.os_blocks *
6945                                          stat_buf.os_bsize;
6946                         sum.os_bfree  += stat_buf.os_bfree *
6947                                          stat_buf.os_bsize;
6948                         sum.os_bavail += stat_buf.os_bavail *
6949                                          stat_buf.os_bsize;
6950                 }
6951         }
6952
6953         close(fd);
6954
6955         /*
6956          * If we have _some_ OSTs, but don't have as many free objects on the
6957          * OST as inodes on the MDTs, reduce the reported number of inodes
6958          * to compensate, so that the "inodes in use" number is correct.
6959          * This should be kept in sync with ll_statfs_internal().
6960          */
6961         if (ost_files && ost_ffree < sum.os_ffree) {
6962                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
6963                 sum.os_ffree = ost_ffree;
6964         }
6965         if (flags & MNTDF_SHOW) {
6966                 printf("\n");
6967                 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
6968                 printf("\n");
6969         }
6970
6971         return rc;
6972 }
6973
6974 enum {
6975         LAYOUT_INHERIT_UNSET    = -2,
6976 };
6977
6978 /* functions */
6979 static int lfs_setdirstripe(int argc, char **argv)
6980 {
6981         char *dname;
6982         struct lfs_setstripe_args lsa = { 0 };
6983         struct llapi_stripe_param *param = NULL;
6984         __u32 mdts[LMV_MAX_STRIPE_COUNT] = { 0 };
6985         char *end;
6986         int c;
6987         char *mode_opt = NULL;
6988         bool default_stripe = false;
6989         bool delete = false;
6990         bool foreign_mode = false;
6991         bool mdt_count_set = false;
6992         mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
6993         mode_t previous_mode = 0;
6994         char *xattr = NULL;
6995         __u32 type = LU_FOREIGN_TYPE_SYMLINK, flags = 0;
6996         int max_inherit = LAYOUT_INHERIT_UNSET;
6997         int max_inherit_rr = LAYOUT_INHERIT_UNSET;
6998         struct option long_opts[] = {
6999         { .val = 'c',   .name = "count",        .has_arg = required_argument },
7000         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
7001         { .val = 'd',   .name = "delete",       .has_arg = no_argument },
7002         { .val = 'D',   .name = "default",      .has_arg = no_argument },
7003         { .val = 'D',   .name = "default_stripe", .has_arg = no_argument },
7004         { .val = LFS_LAYOUT_FLAGS_OPT,
7005                         .name = "flags",        .has_arg = required_argument },
7006         { .val = LFS_LAYOUT_FOREIGN_OPT,
7007                         .name = "foreign",      .has_arg = optional_argument},
7008         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7009         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
7010 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 17, 53, 0)
7011         { .val = 'i',   .name = "mdt-index",    .has_arg = required_argument },
7012         { .val = 'i',   .name = "mdt",          .has_arg = required_argument },
7013 #else
7014 /* find { .val = 'l',   .name = "lazy",         .has_arg = no_argument }, */
7015         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
7016         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
7017 #endif
7018 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7019         { .val = 'i',   .name = "index",        .has_arg = required_argument },
7020 #endif
7021         { .val = 'o',   .name = "mode",         .has_arg = required_argument },
7022 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7023         { .val = 't',   .name = "hash-type",    .has_arg = required_argument },
7024 #endif
7025         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
7026         { .val = 'x',   .name = "xattr",        .has_arg = required_argument },
7027         { .val = 'X',   .name = "max-inherit",  .has_arg = required_argument },
7028         { .val = LFS_INHERIT_RR_OPT,
7029                         .name = "max-inherit-rr", .has_arg = required_argument},
7030 /* setstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
7031 /* setstripe { .val = 'W', .name = "bandwidth", .has_arg = required_argument }, */
7032         { .name = NULL } };
7033         int result = 0;
7034
7035         setstripe_args_init(&lsa);
7036
7037         while ((c = getopt_long(argc, argv, "c:dDi:hH:m:o:t:T:x:X:",
7038                                 long_opts, NULL)) >= 0) {
7039                 switch (c) {
7040                 case 0:
7041                         /* Long options. */
7042                         break;
7043                 case 'c':
7044                 case 'T':
7045                         errno = 0;
7046                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
7047                         if (errno != 0 || *end != '\0' ||
7048                             lsa.lsa_stripe_count < -1 ||
7049                             lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
7050                                 fprintf(stderr,
7051                                         "%s: invalid stripe count '%s'\n",
7052                                         progname, optarg);
7053                                 return CMD_HELP;
7054                         }
7055                         mdt_count_set = true;
7056                         break;
7057                 case 'd':
7058                         delete = true;
7059                         default_stripe = true;
7060                         break;
7061                 case 'D':
7062                         default_stripe = true;
7063                         break;
7064                 case LFS_LAYOUT_FOREIGN_OPT:
7065                         if (optarg) {
7066                                 /* check pure numeric */
7067                                 type = strtoul(optarg, &end, 0);
7068                                 if (*end) {
7069                                         /* check name */
7070                                         type = check_foreign_type_name(optarg);
7071                                         if (type == LU_FOREIGN_TYPE_UNKNOWN) {
7072                                                 fprintf(stderr,
7073                                                         "%s %s: unknown foreign type '%s'\n",
7074                                                         progname, argv[0],
7075                                                         optarg);
7076                                                 return CMD_HELP;
7077                                         }
7078                                 } else if (type >= UINT32_MAX) {
7079                                         fprintf(stderr,
7080                                                 "%s %s: invalid foreign type '%s'\n",
7081                                                 progname, argv[0], optarg);
7082                                         return CMD_HELP;
7083                                 }
7084                         }
7085                         foreign_mode = true;
7086                         break;
7087                 case LFS_LAYOUT_FLAGS_OPT:
7088                         errno = 0;
7089                         flags = strtoul(optarg, &end, 16);
7090                         if (errno != 0 || *end != '\0' ||
7091                             flags >= UINT32_MAX) {
7092                                 fprintf(stderr,
7093                                         "%s %s: invalid hex flags '%s'\n",
7094                                         progname, argv[0], optarg);
7095                                 return CMD_HELP;
7096                         }
7097                         if (!foreign_mode) {
7098                                 fprintf(stderr,
7099                                         "%s %s: hex flags must be specified with --foreign option\n",
7100                                         progname, argv[0]);
7101                                 return CMD_HELP;
7102                         }
7103                         break;
7104 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7105                 case 't':
7106                         fprintf(stderr,
7107                                 "warning: '--hash-type' and '-t' deprecated, use '--mdt-hash' or '-H' instead\n");
7108                         fallthrough;
7109 #endif
7110                 case 'H':
7111                         lsa.lsa_pattern = check_hashtype(optarg);
7112                         if (lsa.lsa_pattern == 0) {
7113                                 fprintf(stderr,
7114                                         "%s %s: bad directory hash type '%s'\n",
7115                                         progname, argv[0], optarg);
7116                                 return CMD_HELP;
7117                         }
7118                         break;
7119                 case 'i':
7120 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 17, 53, 0)
7121                 case 'm':
7122 #endif
7123 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7124                         if (strcmp(argv[optind - 1], "--index") == 0)
7125                                 fprintf(stderr,
7126                                         "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
7127                                         progname, argv[0]);
7128 #endif
7129                         lsa.lsa_nr_tgts = parse_targets(mdts,
7130                                                 sizeof(mdts) / sizeof(__u32),
7131                                                 lsa.lsa_nr_tgts, optarg, NULL);
7132                         if (lsa.lsa_nr_tgts < 0) {
7133                                 fprintf(stderr,
7134                                         "%s %s: invalid MDT target(s) '%s'\n",
7135                                         progname, argv[0], optarg);
7136                                 return CMD_HELP;
7137                         }
7138
7139                         lsa.lsa_tgts = mdts;
7140                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
7141                                 lsa.lsa_stripe_off = mdts[0];
7142                         break;
7143                 case 'o':
7144                         mode_opt = optarg;
7145                         break;
7146                 case 'x':
7147                         xattr = optarg;
7148                         break;
7149                 case 'X':
7150                         errno = 0;
7151                         max_inherit = strtol(optarg, &end, 10);
7152                         if (errno != 0 || *end != '\0' || max_inherit < -2) {
7153                                 fprintf(stderr,
7154                                         "%s %s: invalid max-inherit '%s'\n",
7155                                         progname, argv[0], optarg);
7156                                 return CMD_HELP;
7157                         }
7158                         if (max_inherit == 0) {
7159                                 max_inherit = LMV_INHERIT_NONE;
7160                         } else if (max_inherit == -1) {
7161                                 max_inherit = LMV_INHERIT_UNLIMITED;
7162                         } else if (max_inherit > LMV_INHERIT_MAX) {
7163                                 fprintf(stderr,
7164                                         "%s %s: max-inherit %d exceeds maximum %u\n",
7165                                         progname, argv[0], max_inherit,
7166                                         LMV_INHERIT_MAX);
7167                                 return CMD_HELP;
7168                         }
7169                         break;
7170                 case LFS_INHERIT_RR_OPT:
7171                         if (!default_stripe) {
7172                                 fprintf(stderr,
7173                                         "%s %s: '--max-inherit-rr' must be specified with '-D'\n",
7174                                         progname, argv[0]);
7175                                 return CMD_HELP;
7176                         }
7177                         errno = 0;
7178                         max_inherit_rr = strtol(optarg, &end, 10);
7179                         if (errno != 0 || *end != '\0' || max_inherit_rr < -2) {
7180                                 fprintf(stderr,
7181                                         "%s %s: invalid max-inherit-rr '%s'\n",
7182                                         progname, argv[0], optarg);
7183                                 return CMD_HELP;
7184                         }
7185                         if (max_inherit_rr == 0) {
7186                                 max_inherit_rr = LMV_INHERIT_RR_NONE;
7187                         } else if (max_inherit_rr == -1) {
7188                                 max_inherit_rr = LMV_INHERIT_RR_UNLIMITED;
7189                         } else if (max_inherit_rr > LMV_INHERIT_RR_MAX) {
7190                                 fprintf(stderr,
7191                                         "%s %s: max-inherit-rr %d exceeds maximum %u\n",
7192                                         progname, argv[0], max_inherit_rr,
7193                                         LMV_INHERIT_RR_MAX);
7194                                 return CMD_HELP;
7195                         }
7196                         break;
7197                 default:
7198                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7199                                 progname, argv[optind - 1]);
7200                         fallthrough;
7201                 case 'h':
7202                         return CMD_HELP;
7203                 }
7204         }
7205
7206         if (optind == argc) {
7207                 fprintf(stderr, "%s %s: DIR must be specified\n",
7208                         progname, argv[0]);
7209                 return CMD_HELP;
7210         }
7211
7212         if (xattr && !foreign_mode) {
7213                 /*
7214                  * only print a warning as this is armless and will be
7215                  * ignored
7216                  */
7217                 fprintf(stderr,
7218                         "%s %s: xattr has been specified for non-foreign layout\n",
7219                         progname, argv[0]);
7220         } else if (foreign_mode && !xattr) {
7221                 fprintf(stderr,
7222                         "%s %s: xattr must be provided in foreign mode\n",
7223                         progname, argv[0]);
7224                 return CMD_HELP;
7225         }
7226
7227         if (foreign_mode && (delete || default_stripe || lsa.lsa_nr_tgts ||
7228             lsa.lsa_tgts || setstripe_args_specified(&lsa))) {
7229                 fprintf(stderr,
7230                         "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
7231                         progname, argv[0]);
7232                 return CMD_HELP;
7233         }
7234
7235         if (!delete && lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT &&
7236             lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT && !foreign_mode) {
7237                 /* if no parameters set, create directory on least-used MDTs */
7238                 lsa.lsa_stripe_off = LMV_OFFSET_DEFAULT;
7239                 lsa.lsa_stripe_count = 1;
7240         }
7241
7242         if (delete &&
7243             (lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
7244              lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)) {
7245                 fprintf(stderr,
7246                         "%s %s: cannot specify -d with -c or -i options\n",
7247                         progname, argv[0]);
7248                 return CMD_HELP;
7249         }
7250
7251         if (mode_opt) {
7252                 mode = strtoul(mode_opt, &end, 8);
7253                 if (*end != '\0') {
7254                         fprintf(stderr,
7255                                 "%s %s: bad MODE '%s'\n",
7256                                 progname, argv[0], mode_opt);
7257                         return CMD_HELP;
7258                 }
7259                 previous_mode = umask(0);
7260         }
7261
7262         /* check max-inherit and warn user in some cases */
7263         if (default_stripe &&
7264             (lsa.lsa_stripe_count < 0 || lsa.lsa_stripe_count > 1)) {
7265                 if (max_inherit == LMV_INHERIT_UNLIMITED)
7266                         fprintf(stderr,
7267                         "%s %s: unrecommended max-inherit=-1 when default stripe-count=%lld\n",
7268                         progname, argv[0], lsa.lsa_stripe_count);
7269                 else if (max_inherit > LMV_INHERIT_DEFAULT_STRIPED + 2 &&
7270                          max_inherit != LMV_INHERIT_NONE)
7271                         fprintf(stderr,
7272                                 "%s %s: unrecommended max-inherit=%d when default stripe-count=%lld\n",
7273                                 progname, argv[0], max_inherit,
7274                                 lsa.lsa_stripe_count);
7275         }
7276
7277         if (default_stripe && lsa.lsa_nr_tgts > 1 && !mdt_count_set) {
7278                 fprintf(stderr,
7279                         "%s %s: trying to create unrecommended default striped directory layout,\n"
7280                         "       '-D -i x,y,z' will stripe every new directory across all MDTs,\n"
7281                         "       add -c with the number of MDTs to do this anyway\n",
7282                         progname, argv[0]);
7283                 return CMD_HELP;
7284         }
7285
7286         if (max_inherit_rr != LAYOUT_INHERIT_UNSET &&
7287             lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT &&
7288             lsa.lsa_stripe_off != LMV_OFFSET_DEFAULT) {
7289                 fprintf(stderr,
7290                         "%s %s: max-inherit-rr needs mdt-index=-1, not %lld\n",
7291                         progname, argv[0], lsa.lsa_stripe_off);
7292                 return CMD_HELP;
7293         }
7294
7295         /* foreign LMV/dir case */
7296         if (foreign_mode) {
7297                 if (argc > optind + 1) {
7298                         fprintf(stderr,
7299                                 "%s %s: cannot specify multiple foreign dirs\n",
7300                                 progname, argv[0]);
7301                         return CMD_HELP;
7302                 }
7303
7304                 dname = argv[optind];
7305                 result = llapi_dir_create_foreign(dname, mode, type, flags,
7306                                                   xattr);
7307                 if (result != 0)
7308                         fprintf(stderr,
7309                                 "%s mkdir: can't create foreign dir '%s': %s\n",
7310                                 progname, dname, strerror(-result));
7311                 return result;
7312         }
7313
7314         /*
7315          * initialize stripe parameters, in case param is converted to specific,
7316          * i.e, 'lfs mkdir -i -1 -c N', always allocate space for lsp_tgts.
7317          */
7318         param = calloc(1, offsetof(typeof(*param),
7319                        lsp_tgts[lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ?
7320                                 lsa.lsa_stripe_count : lsa.lsa_nr_tgts]));
7321         if (!param) {
7322                 fprintf(stderr,
7323                         "%s %s: cannot allocate memory for parameters: %s\n",
7324                         progname, argv[0], strerror(ENOMEM));
7325                 return CMD_HELP;
7326         }
7327
7328         /* if "lfs setdirstripe -D -i -1" is used, assume 1-stripe directory */
7329         if (default_stripe && lsa.lsa_stripe_off == LMV_OFFSET_DEFAULT &&
7330             (lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT ||
7331              lsa.lsa_stripe_count == 0))
7332                 lsa.lsa_stripe_count = 1;
7333         if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
7334                 param->lsp_stripe_count = lsa.lsa_stripe_count;
7335         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
7336                 param->lsp_stripe_offset = LMV_OFFSET_DEFAULT;
7337         else
7338                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
7339         if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
7340                 param->lsp_stripe_pattern = lsa.lsa_pattern;
7341         else
7342                 param->lsp_stripe_pattern = LMV_HASH_TYPE_UNKNOWN;
7343         param->lsp_pool = lsa.lsa_pool_name;
7344         param->lsp_is_specific = false;
7345
7346         if (max_inherit == LAYOUT_INHERIT_UNSET) {
7347                 if (lsa.lsa_stripe_count == 0 || lsa.lsa_stripe_count == 1 ||
7348                     lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT)
7349                         max_inherit = LMV_INHERIT_DEFAULT_PLAIN;
7350                 else
7351                         max_inherit = LMV_INHERIT_DEFAULT_STRIPED;
7352         }
7353         param->lsp_max_inherit = max_inherit;
7354         if (default_stripe) {
7355
7356                 if (max_inherit_rr == LAYOUT_INHERIT_UNSET)
7357                         max_inherit_rr = LMV_INHERIT_RR_DEFAULT;
7358                 param->lsp_max_inherit_rr = max_inherit_rr;
7359         }
7360         if (strcmp(argv[0], "mkdir") == 0)
7361                 param->lsp_is_create = true;
7362         if (lsa.lsa_nr_tgts > 1) {
7363                 if (lsa.lsa_stripe_count > 0 &&
7364                     lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
7365                     lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
7366                         fprintf(stderr,
7367                                 "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
7368                                 argv[0], lsa.lsa_stripe_count,
7369                                 lsa.lsa_nr_tgts);
7370                         free(param);
7371                         return CMD_HELP;
7372                 }
7373
7374                 param->lsp_is_specific = true;
7375                 param->lsp_stripe_count = lsa.lsa_nr_tgts;
7376                 memcpy(param->lsp_tgts, mdts, sizeof(*mdts) * lsa.lsa_nr_tgts);
7377         }
7378
7379         dname = argv[optind];
7380         do {
7381                 if (default_stripe) {
7382                         result = llapi_dir_set_default_lmv(dname, param);
7383                         if (result)
7384                                 fprintf(stderr,
7385                                         "%s setdirstripe: cannot set default stripe on dir '%s': %s\n",
7386                                         progname, dname, strerror(-result));
7387                         continue;
7388                 }
7389
7390                 result = llapi_dir_create(dname, mode, param);
7391                 if (result)
7392                         fprintf(stderr,
7393                                 "%s setdirstripe: cannot create dir '%s': %s\n",
7394                                 progname, dname, strerror(-result));
7395         } while (!result && (dname = argv[++optind]));
7396
7397         if (mode_opt)
7398                 umask(previous_mode);
7399
7400         free(param);
7401         return result;
7402 }
7403
7404 static int lfs_rmentry(int argc, char **argv)
7405 {
7406         char *dname;
7407         int index;
7408         int result = 0;
7409
7410         if (argc <= 1) {
7411                 fprintf(stderr, "error: %s: missing dirname\n",
7412                         argv[0]);
7413                 return CMD_HELP;
7414         }
7415
7416         index = 1;
7417         dname = argv[index];
7418         while (dname) {
7419                 int rc2;
7420
7421                 rc2 = llapi_direntry_remove(dname);
7422                 if (rc2) {
7423                         fprintf(stderr,
7424                                 "%s %s: remove dir entry '%s' failed: %s\n",
7425                                 progname, argv[0], dname, strerror(-rc2));
7426                         if (!result)
7427                                 result = rc2;
7428                 }
7429                 dname = argv[++index];
7430         }
7431         return result;
7432 }
7433
7434 static int lfs_unlink_foreign(int argc, char **argv)
7435 {
7436         char *name;
7437         int   index;
7438         int   result = 0;
7439
7440         if (argc <= 1) {
7441                 fprintf(stderr, "error: %s: missing pathname\n",
7442                         argv[0]);
7443                 return CMD_HELP;
7444         }
7445
7446         index = 1;
7447         name = argv[index];
7448         while (name != NULL) {
7449                 result = llapi_unlink_foreign(name);
7450                 if (result) {
7451                         fprintf(stderr,
7452                                 "error: %s: unlink foreign entry '%s' failed\n",
7453                                 argv[0], name);
7454                         break;
7455                 }
7456                 name = argv[++index];
7457         }
7458         return result;
7459 }
7460
7461 static int lfs_mv(int argc, char **argv)
7462 {
7463         struct lmv_user_md lmu = { LMV_USER_MAGIC };
7464         struct find_param param = {
7465                 .fp_max_depth = -1,
7466                 .fp_mdt_index = -1,
7467         };
7468         char *end;
7469         int c;
7470         int rc = 0;
7471         struct option long_opts[] = {
7472         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
7473         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
7474         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7475         { .name = NULL } };
7476
7477         while ((c = getopt_long(argc, argv, "m:M:v", long_opts, NULL)) != -1) {
7478                 switch (c) {
7479 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
7480                 case 'M':
7481                         fprintf(stderr,
7482                                 "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
7483 #endif
7484                 case 'm':
7485                         errno = 0;
7486                         lmu.lum_stripe_offset = strtoul(optarg, &end, 0);
7487                         if (errno != 0 || *end != '\0' ||
7488                             lmu.lum_stripe_offset >= UINT32_MAX) {
7489                                 fprintf(stderr, "%s mv: bad MDT index '%s'\n",
7490                                         progname, optarg);
7491                                 return CMD_HELP;
7492                         }
7493                         break;
7494                 case 'v':
7495                         param.fp_verbose = VERBOSE_DETAIL;
7496                         break;
7497                 default:
7498                         fprintf(stderr, "%s mv: unrecognized option '%s'\n",
7499                                 progname, argv[optind - 1]);
7500                         return CMD_HELP;
7501                 }
7502         }
7503
7504         if (lmu.lum_stripe_offset == LMV_OFFSET_DEFAULT) {
7505                 fprintf(stderr, "%s mv: MDT index must be specified\n",
7506                         progname);
7507                 return CMD_HELP;
7508         }
7509
7510         if (optind >= argc) {
7511                 fprintf(stderr, "%s mv: DIR must be specified\n", progname);
7512                 return CMD_HELP;
7513         }
7514
7515         lmu.lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
7516
7517         /* initialize migrate mdt parameters */
7518         param.fp_lmv_md = &lmu;
7519         param.fp_migrate = 1;
7520         rc = llapi_migrate_mdt(argv[optind], &param);
7521         if (rc != 0)
7522                 fprintf(stderr, "%s mv: cannot migrate '%s' to MDT%04x: %s\n",
7523                         progname, argv[optind], lmu.lum_stripe_offset,
7524                         strerror(-rc));
7525         return rc;
7526 }
7527
7528 static int lfs_osts(int argc, char **argv)
7529 {
7530         return lfs_tgts(argc, argv);
7531 }
7532
7533 static int lfs_mdts(int argc, char **argv)
7534 {
7535         return lfs_tgts(argc, argv);
7536 }
7537
7538 static int lfs_df(int argc, char **argv)
7539 {
7540         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
7541         enum mntdf_flags flags = MNTDF_SHOW;
7542         int ops = LL_STATFS_LMV | LL_STATFS_LOV;
7543         int c, rc = 0, rc1 = 0, index = 0, arg_idx = 0;
7544         char fsname[PATH_MAX] = "", *pool_name = NULL;
7545         struct option long_opts[] = {
7546         { .val = 'h',   .name = "human-readable", .has_arg = no_argument },
7547         { .val = 'H',   .name = "si",           .has_arg = no_argument },
7548         { .val = 'i',   .name = "inodes",       .has_arg = no_argument },
7549         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
7550         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
7551         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7552         { .name = NULL} };
7553
7554         while ((c = getopt_long(argc, argv, "hHilp:v", long_opts, NULL)) != -1) {
7555                 switch (c) {
7556                 case 'h':
7557                         flags = (flags & ~MNTDF_DECIMAL) | MNTDF_COOKED;
7558                         break;
7559                 case 'H':
7560                         flags |= MNTDF_COOKED | MNTDF_DECIMAL;
7561                         break;
7562                 case 'i':
7563                         flags |= MNTDF_INODES;
7564                         break;
7565                 case 'l':
7566                         flags |= MNTDF_LAZY;
7567                         break;
7568                 case 'p':
7569                         pool_name = optarg;
7570                         break;
7571                 case 'v':
7572                         flags |= MNTDF_VERBOSE;
7573                         break;
7574                 default:
7575                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7576                                 progname, argv[optind - 1]);
7577                         return CMD_HELP;
7578                 }
7579         }
7580
7581         /* Handle case where path is not specified */
7582         if (optind == argc) {
7583                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7584                         /* Check if we have a mount point */
7585                         if (mntdir[0] == '\0')
7586                                 continue;
7587
7588                         rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
7589                         if (rc || path[0] != '\0')
7590                                 break;
7591
7592                         fsname[0] = '\0'; /* avoid matching in next loop */
7593                         mntdir[0] = '\0'; /* avoid matching in next loop */
7594                         path[0] = '\0'; /* clean for next loop */
7595                 }
7596                 return rc;
7597         }
7598
7599         /* Loop through all the remaining arguments. These are Lustre FS
7600          * paths.
7601          */
7602         for (arg_idx = optind; arg_idx <= argc - 1; arg_idx++) {
7603                 bool valid = false;
7604
7605                 fsname[0] = '\0'; /* start clean */
7606                 mntdir[0] = '\0'; /* start clean */
7607                 path[0] = '\0';   /* start clean */
7608
7609                 /* path does not exists at all */
7610                 if (!realpath(argv[arg_idx], path)) {
7611                         rc = -errno;
7612                         fprintf(stderr, "error: invalid path '%s': %s\n",
7613                                 argv[arg_idx], strerror(-rc));
7614                         /* save first seen error */
7615                         if (!rc1)
7616                                 rc1 = rc;
7617
7618                         continue;
7619                 }
7620
7621                 /* path exists but may not be a Lustre filesystem */
7622                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7623                         /* Check if we have a mount point */
7624                         if (mntdir[0] == '\0')
7625                                 continue;
7626
7627                         rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
7628                         if (rc || path[0] != '\0') {
7629                                 valid = true;
7630
7631                                 /* save first seen error */
7632                                 if (!rc1)
7633                                         rc1 = rc;
7634                                 break;
7635                         }
7636                 }
7637
7638                 if (!valid) {
7639                         llapi_printf(LLAPI_MSG_ERROR,
7640                                      "%s:%s Not a Lustre filesystem\n",
7641                                      argv[0], argv[arg_idx]);
7642                         /* save first seen error */
7643                         if (!rc1)
7644                                 rc1 = -EOPNOTSUPP;
7645                 }
7646         }
7647
7648         return rc1;
7649 }
7650
7651 static int print_instance(const char *mntdir, char *buf, size_t buflen,
7652                           bool opt_instance, bool opt_fsname, bool opt_mntdir)
7653 {
7654         int rc = 0;
7655
7656         if (opt_fsname == opt_instance) { /* both true or both false */
7657                 rc = llapi_getname(mntdir, buf, buflen);
7658         } else if (opt_fsname) {
7659                 /*
7660                  * llapi_search_mounts() fills @buf with fsname, but that is not
7661                  * called if explicit paths are specified on the command-line
7662                  */
7663                 if (buf[0] == '\0')
7664                         rc = llapi_get_fsname(mntdir, buf, buflen);
7665         } else /* if (opt_instance) */ {
7666                 rc = llapi_get_instance(mntdir, buf, buflen);
7667         }
7668
7669         if (rc < 0) {
7670                 fprintf(stderr, "cannot get instance for '%s': %s\n",
7671                         mntdir, strerror(-rc));
7672                 return rc;
7673         }
7674
7675         if (opt_mntdir)
7676                 printf("%s %s\n", buf, mntdir);
7677         else
7678                 printf("%s\n", buf);
7679
7680         return 0;
7681 }
7682
7683 static int lfs_getname(int argc, char **argv)
7684 {
7685         struct option long_opts[] = {
7686         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7687         { .val = 'i',   .name = "instance",     .has_arg = no_argument },
7688         { .val = 'n',   .name = "fsname",       .has_arg = no_argument },
7689         { .name = NULL} };
7690         bool opt_instance = false, opt_fsname = false;
7691         char fsname[PATH_MAX] = "";
7692         int rc = 0, rc2, c;
7693
7694         while ((c = getopt_long(argc, argv, "hin", long_opts, NULL)) != -1) {
7695                 switch (c) {
7696                 case 'i':
7697                         opt_instance = true;
7698                         break;
7699                 case 'n':
7700                         opt_fsname = true;
7701                         break;
7702                 default:
7703                         fprintf(stderr, "%s: unrecognized option '%s'\n",
7704                                 progname, argv[optind - 1]);
7705                         fallthrough;
7706                 case 'h':
7707                         return CMD_HELP;
7708                 }
7709         }
7710
7711         if (optind == argc) { /* no paths specified, get all paths. */
7712                 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "";
7713                 int index = 0;
7714
7715                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
7716                         rc2 = print_instance(mntdir, fsname, sizeof(fsname),
7717                                              opt_instance, opt_fsname, true);
7718                         if (!rc)
7719                                 rc = rc2;
7720                         path[0] = fsname[0] = mntdir[0] = '\0';
7721                 }
7722         } else { /* paths specified, only attempt to search these. */
7723                 bool opt_mntdir;
7724
7725                 /* if only one path is given, print only requested info */
7726                 opt_mntdir = argc - optind > 1 || (opt_instance == opt_fsname);
7727
7728                 for (; optind < argc; optind++) {
7729                         rc2 = print_instance(argv[optind], fsname,
7730                                              sizeof(fsname), opt_instance,
7731                                              opt_fsname, opt_mntdir);
7732                         if (!rc)
7733                                 rc = rc2;
7734                         fsname[0] = '\0';
7735                 }
7736         }
7737
7738         return rc;
7739 }
7740
7741 static int lfs_check(int argc, char **argv)
7742 {
7743         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
7744         int num_types = 1;
7745         char *obd_types[3];
7746         char obd_type1[4];
7747         char obd_type2[4];
7748         char obd_type3[4];
7749         int rc;
7750
7751         if (argc < 2 || argc > 3) {
7752                 fprintf(stderr, "%s check: server type must be specified\n",
7753                         progname);
7754                 return CMD_HELP;
7755         }
7756
7757         obd_types[0] = obd_type1;
7758         obd_types[1] = obd_type2;
7759         obd_types[2] = obd_type3;
7760
7761         if (strcmp(argv[1], "osts") == 0) {
7762                 strcpy(obd_types[0], "osc");
7763         } else if (strcmp(argv[1], "mdts") == 0 ||
7764                    strcmp(argv[1], "mds") == 0) {
7765                 strcpy(obd_types[0], "mdc");
7766         } else if (strcmp(argv[1], "mgts") == 0) {
7767                 strcpy(obd_types[0], "mgc");
7768         } else if (strcmp(argv[1], "all") == 0 ||
7769                    strcmp(argv[1], "servers") == 0) {
7770                 num_types = 3;
7771                 strcpy(obd_types[0], "osc");
7772                 strcpy(obd_types[1], "mdc");
7773                 strcpy(obd_types[2], "mgc");
7774         } else {
7775                 fprintf(stderr, "%s check: unrecognized option '%s'\n",
7776                         progname, argv[1]);
7777                 return CMD_HELP;
7778         }
7779
7780         if (argc >= 3 && !realpath(argv[2], path)) {
7781                 rc = -errno;
7782                 fprintf(stderr, "error: invalid path '%s': %s\n",
7783                         argv[2], strerror(-rc));
7784                 return rc;
7785         }
7786
7787         rc = llapi_search_mounts(path, 0, mntdir, NULL);
7788         if (rc < 0 || mntdir[0] == '\0') {
7789                 fprintf(stderr,
7790                         "%s %s: cannot find mounted Lustre filesystem: %s\n",
7791                         progname, argv[0],
7792                         (rc < 0) ? strerror(-rc) : strerror(ENODEV));
7793                 return rc;
7794         }
7795
7796         rc = llapi_target_check(num_types, obd_types, path);
7797         if (rc)
7798                 fprintf(stderr, "%s %s: cannot check target '%s': %s\n",
7799                         progname, argv[0], argv[1], strerror(-rc));
7800
7801         return rc;
7802 }
7803
7804 #ifdef HAVE_SYS_QUOTA_H
7805 #define ADD_OVERFLOW(a, b) \
7806                      ((((a) + (b)) < (a)) ? \
7807                       ((a) = ULONG_MAX) : ((a) = (a) + (b)))
7808
7809 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
7810  * returns the value or ULONG_MAX on integer overflow or incorrect format
7811  * Notes:
7812  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
7813  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
7814  *        3. empty integer value is interpreted as 0
7815  */
7816 static unsigned long str2sec(const char *timestr)
7817 {
7818         const char spec[] = "smhdw";
7819         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
7820         unsigned long val = 0;
7821         char *tail;
7822
7823         if (strpbrk(timestr, spec) == NULL) {
7824                 /*
7825                  * no specifiers inside the time string,
7826                  * should treat it as an integer value
7827                  */
7828                 val = strtoul(timestr, &tail, 10);
7829                 return *tail ? ULONG_MAX : val;
7830         }
7831
7832         /* format string is XXwXXdXXhXXmXXs */
7833         while (*timestr) {
7834                 unsigned long v;
7835                 int ind;
7836                 char *ptr;
7837
7838                 v = strtoul(timestr, &tail, 10);
7839                 if (v == ULONG_MAX || *tail == '\0')
7840                         /*
7841                          * value too large (ULONG_MAX or more)
7842                          * or missing specifier
7843                          */
7844                         goto error;
7845
7846                 ptr = strchr(spec, *tail);
7847                 if (!ptr)
7848                         /* unknown specifier */
7849                         goto error;
7850
7851                 ind = ptr - spec;
7852
7853                 /* check if product will overflow the type */
7854                 if (!(v < ULONG_MAX / mult[ind]))
7855                         goto error;
7856
7857                 ADD_OVERFLOW(val, mult[ind] * v);
7858                 if (val == ULONG_MAX)
7859                         goto error;
7860
7861                 timestr = tail + 1;
7862         }
7863
7864         return val;
7865
7866 error:
7867         return ULONG_MAX;
7868 }
7869
7870 #define ARG2ULL(nr, str, def_units)                                     \
7871 do {                                                                    \
7872         unsigned long long limit, units = def_units;                    \
7873         int rc;                                                         \
7874                                                                         \
7875         rc = llapi_parse_size(str, &limit, &units, 1);                  \
7876         if (rc < 0) {                                                   \
7877                 fprintf(stderr, "%s: invalid limit '%s'\n",             \
7878                         progname, str);                                 \
7879                 return CMD_HELP;                                        \
7880         }                                                               \
7881         nr = limit;                                                     \
7882 } while (0)
7883
7884 static inline int has_times_option(int argc, char **argv)
7885 {
7886         int i;
7887
7888         for (i = 1; i < argc; i++)
7889                 if (!strcmp(argv[i], "-t"))
7890                         return 1;
7891
7892         return 0;
7893 }
7894
7895 static inline int lfs_verify_poolarg(char *pool)
7896 {
7897         if (strnlen(optarg, LOV_MAXPOOLNAME + 1) > LOV_MAXPOOLNAME) {
7898                 fprintf(stderr,
7899                         "Pool name '%.*s' is longer than %d\n",
7900                         LOV_MAXPOOLNAME, pool, LOV_MAXPOOLNAME);
7901                 return 1;
7902         }
7903         return 0;
7904 }
7905
7906 /* special grace time, only notify the user when its quota is over soft limit
7907  * but doesn't block new writes until the hard limit is reached.
7908  */
7909 #define NOTIFY_GRACE            "notify"
7910 #define NOTIFY_GRACE_TIME       LQUOTA_GRACE_MASK
7911
7912 #ifndef toqb
7913 static inline __u64 lustre_stoqb(size_t space)
7914 {
7915         return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
7916 }
7917 #else
7918 #define lustre_stoqb   toqb
7919 #endif
7920
7921 int lfs_setquota_times(int argc, char **argv, struct if_quotactl *qctl)
7922 {
7923         int c, rc;
7924         char *mnt, *obd_type = (char *)qctl->obd_type;
7925         struct obd_dqblk *dqb = &qctl->qc_dqblk;
7926         struct obd_dqinfo *dqi = &qctl->qc_dqinfo;
7927         struct option long_opts[] = {
7928         { .val = 'b',   .name = "block-grace",  .has_arg = required_argument },
7929         { .val = 'g',   .name = "group",        .has_arg = no_argument },
7930         { .val = 'h',   .name = "help",         .has_arg = no_argument },
7931         { .val = 'i',   .name = "inode-grace",  .has_arg = required_argument },
7932         { .val = 'p',   .name = "projid",       .has_arg = no_argument },
7933         { .val = 't',   .name = "times",        .has_arg = no_argument },
7934         { .val = 'u',   .name = "user",         .has_arg = no_argument },
7935         { .val = LFS_POOL_OPT,
7936                         .name = "pool",         .has_arg = required_argument },
7937         { .name = NULL } };
7938         int qtype;
7939
7940         qctl->qc_cmd  = LUSTRE_Q_SETINFO;
7941         qctl->qc_type = ALLQUOTA;
7942
7943         while ((c = getopt_long(argc, argv, "b:ghi:ptu",
7944                                 long_opts, NULL)) != -1) {
7945                 switch (c) {
7946                 case 'u':
7947                         qtype = USRQUOTA;
7948                         goto quota_type;
7949                 case 'g':
7950                         qtype = GRPQUOTA;
7951                         goto quota_type;
7952                 case 'p':
7953                         qtype = PRJQUOTA;
7954 quota_type:
7955                         if (qctl->qc_type != ALLQUOTA) {
7956                                 fprintf(stderr,
7957                                         "%s: -u/g/p cannot be used more than once\n",
7958                                         progname);
7959                                 return CMD_HELP;
7960                         }
7961                         qctl->qc_type = qtype;
7962                         break;
7963                 case 'b':
7964                         if (strncmp(optarg, NOTIFY_GRACE,
7965                                     strlen(NOTIFY_GRACE)) == 0) {
7966                                 dqi->dqi_bgrace = NOTIFY_GRACE_TIME;
7967                         } else {
7968                                 dqi->dqi_bgrace = str2sec(optarg);
7969                                 if (dqi->dqi_bgrace >= NOTIFY_GRACE_TIME) {
7970                                         fprintf(stderr,
7971                                                 "%s: bad block-grace: %s\n",
7972                                                 progname, optarg);
7973                                         return CMD_HELP;
7974                                 }
7975                         }
7976                         dqb->dqb_valid |= QIF_BTIME;
7977                         break;
7978                 case 'i':
7979                         if (strncmp(optarg, NOTIFY_GRACE,
7980                                     strlen(NOTIFY_GRACE)) == 0) {
7981                                 dqi->dqi_igrace = NOTIFY_GRACE_TIME;
7982                         } else {
7983                                 dqi->dqi_igrace = str2sec(optarg);
7984                                 if (dqi->dqi_igrace >= NOTIFY_GRACE_TIME) {
7985                                         fprintf(stderr,
7986                                                 "%s: bad inode-grace: %s\n",
7987                                                 progname, optarg);
7988                                         return CMD_HELP;
7989                                 }
7990                         }
7991                         dqb->dqb_valid |= QIF_ITIME;
7992                         break;
7993                 case 't': /* Yes, of course! */
7994                         break;
7995                 case LFS_POOL_OPT:
7996                         if (lfs_verify_poolarg(optarg))
7997                                 return -1;
7998                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
7999                         qctl->qc_cmd  = LUSTRE_Q_SETINFOPOOL;
8000                         break;
8001                 /* getopt prints error message for us when opterr != 0 */
8002                 default:
8003                         fprintf(stderr, "%s: unrecognized option '%s'\n",
8004                                 progname, argv[optind - 1]);
8005                         fallthrough;
8006                 case 'h':
8007                         return CMD_HELP;
8008                 }
8009         }
8010
8011         if (qctl->qc_type == ALLQUOTA) {
8012                 fprintf(stderr, "%s: neither -u, -g nor -p specified\n",
8013                         progname);
8014                 return CMD_HELP;
8015         }
8016
8017         if (optind != argc - 1) {
8018                 fprintf(stderr, "%s: unexpected parameter '%s'\n",
8019                         progname, argv[optind + 1]);
8020                 return CMD_HELP;
8021         }
8022
8023         mnt = argv[optind];
8024         rc = llapi_quotactl(mnt, qctl);
8025         if (rc) {
8026                 if (*obd_type)
8027                         fprintf(stderr, "%s %s ", obd_type,
8028                                 obd_uuid2str(&qctl->obd_uuid));
8029                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
8030                 return rc;
8031         }
8032
8033         return 0;
8034 }
8035
8036 static int lfs_reset_quota(char *mnt, struct if_quotactl *qctl)
8037 {
8038         struct if_quotactl tmp_qctl;
8039         int index, md_count, dt_count;
8040         int wait_phase = 0, wait_index = 0, wait_count = 0;
8041         int rc, rc2;
8042
8043         /* reset the quota ID, the existing quota setting will be returned */
8044         rc = llapi_quotactl(mnt, qctl);
8045         if (rc)
8046                 return rc;
8047
8048         /* sanity check */
8049         if ((qctl->qc_dqblk.dqb_valid & QIF_LIMITS) != QIF_LIMITS) {
8050                 fprintf(stderr,
8051                         "the existing quota settings are not returned!\n");
8052                 return -EINVAL;
8053         }
8054
8055         rc = llapi_get_obd_count(mnt, &md_count, 1);
8056         if (rc) {
8057                 fprintf(stderr, "can not get mdt count: %s\n", strerror(-rc));
8058                 return rc;
8059         }
8060
8061         rc = llapi_get_obd_count(mnt, &dt_count, 0);
8062         if (rc) {
8063                 fprintf(stderr, "can not get ost count: %s\n", strerror(-rc));
8064                 return rc;
8065         }
8066
8067         memset(&tmp_qctl, 0, sizeof(tmp_qctl));
8068         tmp_qctl.qc_type = qctl->qc_type;
8069         tmp_qctl.qc_id = qctl->qc_id;
8070         tmp_qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
8071
8072 retry:
8073         if (wait_phase == 0) {
8074                 for (index = wait_index; index < md_count; index++) {
8075                         tmp_qctl.qc_idx = index;
8076                         tmp_qctl.qc_valid = QC_MDTIDX;
8077                         rc = llapi_quotactl(mnt, &tmp_qctl);
8078                         if (rc == -ENODEV || rc == -ENODATA)
8079                                 continue;
8080                         if (rc) {
8081                                 fprintf(stderr, "quotactl mdt%d failed: %s\n",
8082                                         index, strerror(-rc));
8083                                 break;
8084                         }
8085                         /* check whether the md quota grant is reset */
8086                         if (tmp_qctl.qc_dqblk.dqb_valid & QIF_LIMITS &&
8087                             tmp_qctl.qc_dqblk.dqb_ihardlimit != 0)
8088                                 break;
8089                 }
8090
8091                 if (index < md_count) {
8092                         wait_phase = 0;
8093                         wait_index = index;
8094                         goto wait;
8095                 }
8096         } else {
8097                 for (index = wait_index; index < dt_count; index++) {
8098                         tmp_qctl.qc_idx = index;
8099                         tmp_qctl.qc_valid = QC_OSTIDX;
8100                         rc = llapi_quotactl(mnt, &tmp_qctl);
8101                         if (rc == -ENODEV || rc == -ENODATA)
8102                                 continue;
8103                         if (rc) {
8104                                 fprintf(stderr, "quotactl mdt%d failed: %s\n",
8105                                         index, strerror(-rc));
8106                                 break;
8107                         }
8108                         /* check whether the dt quota grant is reset */
8109                         if (tmp_qctl.qc_dqblk.dqb_valid & QIF_LIMITS &&
8110                             tmp_qctl.qc_dqblk.dqb_bhardlimit != 0)
8111                                 break;
8112                 }
8113
8114                 if (index < dt_count) {
8115                         wait_phase = 1;
8116                         wait_index = index;
8117                         goto wait;
8118                 }
8119         }
8120
8121         if (wait_phase == 0) {
8122                 wait_phase = 1;
8123                 goto retry;
8124         }
8125
8126         goto out;
8127
8128 wait:
8129         if (rc || wait_count > 30) {
8130                 fprintf(stderr, "fail to reset the quota ID %d on OBDs\n",
8131                         qctl->qc_id);
8132                 goto out;
8133         }
8134
8135         wait_count++;
8136         sleep(1);
8137         fprintf(stdout, "wait %d seconds for OBDs to reset the quota ID %u\n",
8138                 wait_count, qctl->qc_id);
8139         goto retry;
8140
8141
8142 out:
8143         /* restore the quota setting */
8144         if (qctl->qc_dqblk.dqb_isoftlimit == 0 &&
8145             qctl->qc_dqblk.dqb_ihardlimit == 0 &&
8146             qctl->qc_dqblk.dqb_bsoftlimit == 0 &&
8147             qctl->qc_dqblk.dqb_bhardlimit == 0)
8148                 return rc;
8149
8150         memcpy(&tmp_qctl, qctl, sizeof(tmp_qctl));
8151         tmp_qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
8152         rc2 = llapi_quotactl(mnt, &tmp_qctl);
8153         if (!rc2)
8154                 return rc;
8155
8156         fprintf(stderr,
8157                 "fail to restore the quota setting: %s, please restore it manually by\n  lfs setquota %s %d",
8158                 strerror(-rc2),
8159                 qctl->qc_type == USRQUOTA ? "-u" :
8160                                 (qctl->qc_type == GRPQUOTA ? "-g" : "-p"),
8161                 qctl->qc_id);
8162
8163         if (qctl->qc_dqblk.dqb_isoftlimit != 0)
8164                 fprintf(stderr, " -i %llu",
8165                         (unsigned long long)qctl->qc_dqblk.dqb_isoftlimit);
8166         if (qctl->qc_dqblk.dqb_ihardlimit != 0)
8167                 fprintf(stderr, " -I %llu",
8168                         (unsigned long long)qctl->qc_dqblk.dqb_ihardlimit);
8169         if (qctl->qc_dqblk.dqb_bsoftlimit != 0)
8170                 fprintf(stderr, " -b %llu",
8171                         (unsigned long long)qctl->qc_dqblk.dqb_bsoftlimit);
8172         if (qctl->qc_dqblk.dqb_bhardlimit != 0)
8173                 fprintf(stderr, " -B %llu",
8174                         (unsigned long long)qctl->qc_dqblk.dqb_bhardlimit);
8175
8176         fprintf(stderr, " %s\n", mnt);
8177         if (!rc)
8178                 rc = rc2;
8179
8180         return rc;
8181 }
8182
8183 #define BSLIMIT (1 << 0)
8184 #define BHLIMIT (1 << 1)
8185 #define ISLIMIT (1 << 2)
8186 #define IHLIMIT (1 << 3)
8187
8188 int lfs_setquota(int argc, char **argv)
8189 {
8190         int c, rc = 0;
8191         struct if_quotactl *qctl;
8192         char *mnt, *obd_type;
8193         struct obd_dqblk *dqb;
8194         struct option long_opts[] = {
8195         { .val = 'b',   .name = "block-softlimit",
8196                                                 .has_arg = required_argument },
8197         { .val = 'B',   .name = "block-hardlimit",
8198                                                 .has_arg = required_argument },
8199         { .val = 'd',   .name = "default",      .has_arg = no_argument },
8200         { .val = LFS_SETQUOTA_DELETE,
8201                         .name = "delete",       .has_arg = no_argument },
8202         { .val = 'g',   .name = "group",        .has_arg = required_argument },
8203         { .val = 'G',   .name = "default-grp",  .has_arg = no_argument },
8204         { .val = 'h',   .name = "help",         .has_arg = no_argument },
8205         { .val = 'i',   .name = "inode-softlimit",
8206                                                 .has_arg = required_argument },
8207         { .val = 'I',   .name = "inode-hardlimit",
8208                                                 .has_arg = required_argument },
8209         { .val = 'p',   .name = "projid",       .has_arg = required_argument },
8210         { .val = 'P',   .name = "default-prj",  .has_arg = no_argument },
8211         { .val = 'r',   .name = "reset",        .has_arg = no_argument },
8212         { .val = 'u',   .name = "user",         .has_arg = required_argument },
8213         { .val = 'U',   .name = "default-usr",  .has_arg = no_argument },
8214         { .val = LFS_POOL_OPT,
8215                         .name = "pool",         .has_arg = required_argument },
8216         { .name = NULL } };
8217         unsigned int limit_mask = 0;
8218         bool use_default = false;
8219         int qtype, qctl_len;
8220
8221         qctl_len = sizeof(*qctl) + LOV_MAXPOOLNAME + 1;
8222         qctl = malloc(qctl_len);
8223         if (!qctl)
8224                 return -ENOMEM;
8225
8226         memset(qctl, 0, qctl_len);
8227         obd_type = (char *)qctl->obd_type;
8228         dqb = &qctl->qc_dqblk;
8229
8230         if (has_times_option(argc, argv)) {
8231                 rc = lfs_setquota_times(argc, argv, qctl);
8232                 goto out;
8233         }
8234
8235         qctl->qc_cmd  = LUSTRE_Q_SETQUOTA;
8236         qctl->qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
8237                                    * so it can be used as a marker that qc_type
8238                                    * isn't reinitialized from command line
8239                                    */
8240         while ((c = getopt_long(argc, argv, "b:B:dDg:Ghi:I:p:Pru:U",
8241                 long_opts, NULL)) != -1) {
8242                 switch (c) {
8243                 case 'U':
8244                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8245                         qtype = USRQUOTA;
8246                         qctl->qc_id = 0;
8247                         goto quota_type_def;
8248                 case 'u':
8249                         qtype = USRQUOTA;
8250                         rc = name2uid(&qctl->qc_id, optarg);
8251                         goto quota_type;
8252                 case 'G':
8253                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8254                         qtype = GRPQUOTA;
8255                         qctl->qc_id = 0;
8256                         goto quota_type_def;
8257                 case 'g':
8258                         qtype = GRPQUOTA;
8259                         rc = name2gid(&qctl->qc_id, optarg);
8260                         goto quota_type;
8261                 case 'P':
8262                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8263                         qtype = PRJQUOTA;
8264                         qctl->qc_id = 0;
8265                         goto quota_type_def;
8266                 case 'p':
8267                         qtype = PRJQUOTA;
8268                         rc = name2projid(&qctl->qc_id, optarg);
8269 quota_type:
8270                         if (rc) {
8271                                 if (str2quotaid(&qctl->qc_id, optarg)) {
8272                                         fprintf(stderr,
8273                                                 "%s setquota: invalid id '%s'\n",
8274                                                 progname, optarg);
8275                                         rc = -1;
8276                                         goto out;
8277                                 }
8278                         }
8279
8280                         if (qctl->qc_id == 0) {
8281                                 fprintf(stderr,
8282                                         "%s setquota: can't set quota for root usr/group/project.\n",
8283                                         progname);
8284                                 rc = -1;
8285                                 goto out;
8286                         }
8287
8288 quota_type_def:
8289                         if (qctl->qc_type != ALLQUOTA) {
8290                                 fprintf(stderr,
8291                                         "%s setquota: only one of -u, -U, -g, -G, -p or -P may be specified\n",
8292                                         progname);
8293                                 rc = CMD_HELP;
8294                                 goto out;
8295                         }
8296                         qctl->qc_type = qtype;
8297                         break;
8298 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
8299                 case 'd':
8300                         fprintf(stderr,
8301                                 "%s setquota: '-d' deprecated, use '-D' or '--default'\n",
8302                                 progname);
8303                         fallthrough;
8304 #endif
8305                 case 'D':
8306                         use_default = true;
8307                         qctl->qc_cmd = LUSTRE_Q_SETDEFAULT;
8308                         break;
8309                 case LFS_SETQUOTA_DELETE:
8310                         qctl->qc_cmd = LUSTRE_Q_DELETEQID;
8311                         break;
8312                 case 'b':
8313                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
8314                         dqb->dqb_bsoftlimit >>= 10;
8315                         limit_mask |= BSLIMIT;
8316                         if (dqb->dqb_bsoftlimit &&
8317                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
8318                                 fprintf(stderr,
8319                                         "%s setquota: warning: block softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8320                                         progname,
8321                                         (unsigned long long)dqb->dqb_bsoftlimit,
8322                                         progname);
8323                         break;
8324                 case 'B':
8325                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
8326                         dqb->dqb_bhardlimit >>= 10;
8327                         limit_mask |= BHLIMIT;
8328                         if (dqb->dqb_bhardlimit &&
8329                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
8330                                 fprintf(stderr,
8331                                         "%s setquota: warning: block hardlimit '%llu' smaller than minimum qunit size\n"
8332                                         "See '%s help setquota' or Lustre manual for details\n",
8333                                         progname,
8334                                         (unsigned long long)dqb->dqb_bhardlimit,
8335                                         progname);
8336                         break;
8337                 case 'i':
8338                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
8339                         limit_mask |= ISLIMIT;
8340                         if (dqb->dqb_isoftlimit &&
8341                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
8342                                 fprintf(stderr,
8343                                         "%s setquota: warning: inode softlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8344                                         progname,
8345                                         (unsigned long long)dqb->dqb_isoftlimit,
8346                                         progname);
8347                         break;
8348                 case 'I':
8349                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
8350                         limit_mask |= IHLIMIT;
8351                         if (dqb->dqb_ihardlimit &&
8352                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
8353                                 fprintf(stderr,
8354                                         "%s setquota: warning: inode hardlimit '%llu' smaller than minimum qunit size\nSee '%s help setquota' or Lustre manual for details\n",
8355                                         progname,
8356                                         (unsigned long long)dqb->dqb_ihardlimit,
8357                                         progname);
8358                         break;
8359                 case LFS_POOL_OPT:
8360                         if (lfs_verify_poolarg(optarg)) {
8361                                 rc = -1;
8362                                 goto out;
8363                         }
8364                         strncpy(qctl->qc_poolname, optarg, LOV_MAXPOOLNAME);
8365                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_SETDEFAULT ?
8366                                                 LUSTRE_Q_SETDEFAULT_POOL :
8367                                                 LUSTRE_Q_SETQUOTAPOOL;
8368                         break;
8369                 case 'r':
8370                         qctl->qc_cmd = LUSTRE_Q_RESETQID;
8371                         break;
8372                 default:
8373                         fprintf(stderr,
8374                                 "%s setquota: unrecognized option '%s'\n",
8375                                 progname, argv[optind - 1]);
8376                         fallthrough;
8377                 case 'h':
8378                         rc = CMD_HELP;
8379                         goto out;
8380                 }
8381         }
8382
8383         if (qctl->qc_type == ALLQUOTA) {
8384                 fprintf(stderr,
8385                         "%s setquota: either -u or -g must be specified\n",
8386                         progname);
8387                 rc = CMD_HELP;
8388                 goto out;
8389         }
8390
8391         if (!use_default && qctl->qc_cmd != LUSTRE_Q_DELETEQID &&
8392             qctl->qc_cmd != LUSTRE_Q_RESETQID && limit_mask == 0) {
8393                 fprintf(stderr,
8394                         "%s setquota: at least one limit must be specified\n",
8395                         progname);
8396                 rc = CMD_HELP;
8397                 goto out;
8398         }
8399
8400         if ((use_default || qctl->qc_cmd == LUSTRE_Q_DELETEQID ||
8401              qctl->qc_cmd == LUSTRE_Q_RESETQID) && limit_mask != 0) {
8402                 fprintf(stderr,
8403                         "%s setquota: limits should not be specified when using default quota, deleting or resetting quota ID\n",
8404                         progname);
8405                 rc = CMD_HELP;
8406                 goto out;
8407         }
8408
8409         if (use_default && qctl->qc_id == 0) {
8410                 fprintf(stderr,
8411                         "%s setquota: can not set default quota for root user/group/project\n",
8412                         progname);
8413                 rc = CMD_HELP;
8414                 goto out;
8415         }
8416
8417         if ((qctl->qc_cmd == LUSTRE_Q_DELETEQID ||
8418              qctl->qc_cmd == LUSTRE_Q_RESETQID)  && qctl->qc_id == 0) {
8419                 fprintf(stderr,
8420                         "%s setquota: can not delete or reset root user/group/project\n",
8421                         progname);
8422                 rc = CMD_HELP;
8423                 goto out;
8424         }
8425
8426         if (optind != argc - 1) {
8427                 fprintf(stderr,
8428                         "%s setquota: filesystem not specified or unexpected argument '%s'\n",
8429                         progname, argv[optind]);
8430                 rc = CMD_HELP;
8431                 goto out;
8432         }
8433
8434         mnt = argv[optind];
8435
8436         if (use_default) {
8437                 dqb->dqb_bhardlimit = 0;
8438                 dqb->dqb_bsoftlimit = 0;
8439                 dqb->dqb_ihardlimit = 0;
8440                 dqb->dqb_isoftlimit = 0;
8441                 dqb->dqb_itime = 0;
8442                 dqb->dqb_btime = 0;
8443                 dqb->dqb_valid |= QIF_LIMITS | QIF_TIMES;
8444                 /* do not set inode limits for Pool Quotas */
8445                 if (qctl->qc_cmd  == LUSTRE_Q_SETDEFAULT_POOL)
8446                         dqb->dqb_valid ^= QIF_ILIMITS | QIF_ITIME;
8447         } else if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
8448                    (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
8449                 /* sigh, we can't just set blimits/ilimits */
8450                 struct if_quotactl *tmp_qctl;
8451
8452                 tmp_qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1);
8453                 if (!tmp_qctl)
8454                         goto out;
8455
8456                 if (qctl->qc_cmd == LUSTRE_Q_SETQUOTAPOOL) {
8457                         tmp_qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
8458                         strncpy(tmp_qctl->qc_poolname, qctl->qc_poolname,
8459                                 LOV_MAXPOOLNAME);
8460                 } else {
8461                         tmp_qctl->qc_cmd  = LUSTRE_Q_GETQUOTA;
8462                 }
8463                 tmp_qctl->qc_type = qctl->qc_type;
8464                 tmp_qctl->qc_id = qctl->qc_id;
8465
8466                 rc = llapi_quotactl(mnt, tmp_qctl);
8467                 if (rc < 0) {
8468                         free(tmp_qctl);
8469                         goto out;
8470                 }
8471
8472                 if (!(limit_mask & BHLIMIT))
8473                         dqb->dqb_bhardlimit = tmp_qctl->qc_dqblk.dqb_bhardlimit;
8474                 if (!(limit_mask & BSLIMIT))
8475                         dqb->dqb_bsoftlimit = tmp_qctl->qc_dqblk.dqb_bsoftlimit;
8476                 if (!(limit_mask & IHLIMIT))
8477                         dqb->dqb_ihardlimit = tmp_qctl->qc_dqblk.dqb_ihardlimit;
8478                 if (!(limit_mask & ISLIMIT))
8479                         dqb->dqb_isoftlimit = tmp_qctl->qc_dqblk.dqb_isoftlimit;
8480
8481                 /* Keep grace times if we have got no softlimit arguments */
8482                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
8483                         dqb->dqb_valid |= QIF_BTIME;
8484                         dqb->dqb_btime = tmp_qctl->qc_dqblk.dqb_btime;
8485                 }
8486
8487                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
8488                         dqb->dqb_valid |= QIF_ITIME;
8489                         dqb->dqb_itime = tmp_qctl->qc_dqblk.dqb_itime;
8490                 }
8491                 free(tmp_qctl);
8492         }
8493
8494         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
8495         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
8496
8497         if (qctl->qc_cmd == LUSTRE_Q_RESETQID)
8498                 rc = lfs_reset_quota(mnt, qctl);
8499         else
8500                 rc = llapi_quotactl(mnt, qctl);
8501
8502         if (rc) {
8503                 if (*obd_type)
8504                         fprintf(stderr,
8505                                 "%s setquota: cannot quotactl '%s' '%s': %s\n",
8506                                 progname, obd_type,
8507                                 obd_uuid2str(&qctl->obd_uuid), strerror(-rc));
8508                 else
8509                         fprintf(stderr,
8510                                 "%s setquota: quotactl failed: %s\n",
8511                                 progname, strerror(-rc));
8512         }
8513 out:
8514         if (rc)
8515                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
8516
8517         free(qctl);
8518         return rc;
8519 }
8520
8521 /* Converts seconds value into format string
8522  * result is returned in buf
8523  * Notes:
8524  *        1. result is in descenting order: 1w2d3h4m5s
8525  *        2. zero fields are not filled (except for p. 3): 5d1s
8526  *        3. zero seconds value is presented as "0s"
8527  */
8528 static char *__sec2str(time_t seconds, char *buf)
8529 {
8530         const char spec[] = "smhdw";
8531         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
8532         unsigned long c;
8533         char *tail = buf;
8534         int i;
8535
8536         for (i = ARRAY_SIZE(mult) - 1 ; i >= 0; i--) {
8537                 c = seconds / mult[i];
8538
8539                 if (c > 0 || (i == 0 && buf == tail))
8540                         tail += scnprintf(tail, 40-(tail-buf), "%lu%c", c,
8541                                           spec[i]);
8542
8543                 seconds %= mult[i];
8544         }
8545
8546         return tail;
8547 }
8548
8549 static void sec2str(time_t seconds, char *buf, int rc)
8550 {
8551         char *tail = buf;
8552
8553         if (rc)
8554                 *tail++ = '[';
8555
8556         tail = __sec2str(seconds, tail);
8557
8558         if (rc && tail - buf < 39) {
8559                 *tail++ = ']';
8560                 *tail++ = 0;
8561         }
8562 }
8563
8564 static void diff2str(time_t seconds, char *buf, time_t now)
8565 {
8566         buf[0] = 0;
8567         if (!seconds)
8568                 return;
8569         if (seconds <= now) {
8570                 strcpy(buf, "expired");
8571                 return;
8572         }
8573         __sec2str(seconds - now, buf);
8574 }
8575
8576 static void print_quota_title(char *name, struct if_quotactl *qctl,
8577                               bool human_readable, bool show_default)
8578 {
8579         if (show_default) {
8580                 printf("Disk default %s quota:\n", qtype_name(qctl->qc_type));
8581                 printf("%15s %8s%8s%8s %8s%8s%8s\n",
8582                        "Filesystem", "bquota", "blimit", "bgrace",
8583                        "iquota", "ilimit", "igrace");
8584         } else {
8585                 printf("Disk quotas for %s %s (%cid %u):\n",
8586                        qtype_name(qctl->qc_type), name,
8587                        *qtype_name(qctl->qc_type), qctl->qc_id);
8588                 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
8589                        "Filesystem", human_readable ? "used" : "kbytes",
8590                        "quota", "limit", "grace",
8591                        "files", "quota", "limit", "grace");
8592         }
8593 }
8594
8595 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
8596 {
8597         if (!h) {
8598                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
8599         } else {
8600                 if (num >> 40)
8601                         snprintf(buf, buflen, "%5.4gP",
8602                                  (double)num / ((__u64)1 << 40));
8603                 else if (num >> 30)
8604                         snprintf(buf, buflen, "%5.4gT",
8605                                  (double)num / (1 << 30));
8606                 else if (num >> 20)
8607                         snprintf(buf, buflen, "%5.4gG",
8608                                  (double)num / (1 << 20));
8609                 else if (num >> 10)
8610                         snprintf(buf, buflen, "%5.4gM",
8611                                  (double)num / (1 << 10));
8612                 else
8613                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
8614         }
8615 }
8616
8617 #ifdef HAVE_NATIVE_CLIENT
8618 /* In the current Lustre implementation, the grace time is either the time
8619  * or the timestamp to be used after some quota ID exceeds the soft limt,
8620  * 48 bits should be enough, its high 16 bits can be used as quota flags.
8621  */
8622 #define LQUOTA_GRACE_BITS       48
8623 #define LQUOTA_GRACE_MASK       ((1ULL << LQUOTA_GRACE_BITS) - 1)
8624 #define LQUOTA_GRACE_MAX        LQUOTA_GRACE_MASK
8625 #define LQUOTA_GRACE(t)         (t & LQUOTA_GRACE_MASK)
8626 #define LQUOTA_FLAG(t)          (t >> LQUOTA_GRACE_BITS)
8627 #define LQUOTA_GRACE_FLAG(t, f) ((__u64)t | (__u64)f << LQUOTA_GRACE_BITS)
8628 #endif
8629
8630 #define STRBUF_LEN      24
8631 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
8632                         int rc, bool h, bool show_default)
8633 {
8634         time_t now;
8635
8636         time(&now);
8637
8638         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA ||
8639             qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
8640             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT ||
8641             qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL) {
8642                 int bover = 0, iover = 0;
8643                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
8644                 char numbuf[3][STRBUF_LEN + 2]; /* 2 for brackets or wildcard */
8645                 char timebuf[40];
8646                 char strbuf[STRBUF_LEN];
8647
8648                 dqb->dqb_btime &= LQUOTA_GRACE_MASK;
8649                 dqb->dqb_itime &= LQUOTA_GRACE_MASK;
8650
8651                 if (dqb->dqb_bhardlimit &&
8652                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
8653                         bover = 1;
8654                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
8655                         if (dqb->dqb_btime > now)
8656                                 bover = 2;
8657                         else
8658                                 bover = 3;
8659                 }
8660
8661                 if (dqb->dqb_ihardlimit &&
8662                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
8663                         iover = 1;
8664                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
8665                         if (dqb->dqb_itime > now)
8666                                 iover = 2;
8667                         else
8668                                 iover = 3;
8669                 }
8670
8671                 if (strlen(mnt) > 15)
8672                         printf("%s\n%15s", mnt, "");
8673                 else
8674                         printf("%15s", mnt);
8675
8676                 if (show_default)
8677                         snprintf(timebuf, sizeof(timebuf), "%llu",
8678                                  (unsigned long long)dqb->dqb_btime);
8679                 else if (bover)
8680                         diff2str(dqb->dqb_btime, timebuf, now);
8681
8682                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
8683                            strbuf, sizeof(strbuf), h);
8684                 if (rc == -EREMOTEIO)
8685                         sprintf(numbuf[0], "%s*", strbuf);
8686                 else
8687                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
8688                                 "%s" : "[%s]", strbuf);
8689
8690                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
8691                 if (type == QC_GENERAL)
8692                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
8693                                 "%s" : "[%s]", strbuf);
8694                 else
8695                         sprintf(numbuf[1], "%s", "-");
8696
8697                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
8698                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
8699                         "%s" : "[%s]", strbuf);
8700
8701                 if (show_default)
8702                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
8703                 else
8704                         printf(" %7s%c %6s %7s %7s",
8705                                numbuf[0], bover ? '*' : ' ', numbuf[1],
8706                                numbuf[2], bover > 1 ? timebuf : "-");
8707
8708                 if (show_default)
8709                         snprintf(timebuf, sizeof(timebuf), "%llu",
8710                                  (unsigned long long)dqb->dqb_itime);
8711                 else if (iover)
8712                         diff2str(dqb->dqb_itime, timebuf, now);
8713
8714                 snprintf(numbuf[0], sizeof(numbuf),
8715                          (dqb->dqb_valid & QIF_INODES) ? "%ju" : "[%ju]",
8716                          (uintmax_t)dqb->dqb_curinodes);
8717
8718                 if (type == QC_GENERAL)
8719                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
8720                                 "%ju" : "[%ju]",
8721                                 (uintmax_t)dqb->dqb_isoftlimit);
8722                 else
8723                         sprintf(numbuf[1], "%s", "-");
8724
8725                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
8726                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
8727
8728                 if (show_default)
8729                         printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
8730                 else if (type != QC_OSTIDX)
8731                         printf(" %7s%c %6s %7s %7s",
8732                                numbuf[0], iover ? '*' : ' ', numbuf[1],
8733                                numbuf[2], iover > 1 ? timebuf : "-");
8734                 else
8735                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
8736                 printf("\n");
8737         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
8738                    qctl->qc_cmd == LUSTRE_Q_GETINFOPOOL ||
8739                    qctl->qc_cmd == Q_GETOINFO) {
8740                 char bgtimebuf[40];
8741                 char igtimebuf[40];
8742
8743                 if (qctl->qc_dqinfo.dqi_bgrace == NOTIFY_GRACE_TIME)
8744                         strncpy(bgtimebuf, NOTIFY_GRACE, 40);
8745                 else
8746                         sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
8747                 if (qctl->qc_dqinfo.dqi_igrace == NOTIFY_GRACE_TIME)
8748                         strncpy(igtimebuf, NOTIFY_GRACE, 40);
8749                 else
8750                         sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
8751
8752                 printf("Block grace time: %s; Inode grace time: %s\n",
8753                        bgtimebuf, igtimebuf);
8754         }
8755 }
8756
8757 static int tgt_name2index(const char *tgtname, unsigned int *idx)
8758 {
8759         char *dash, *endp;
8760
8761         /* format is "lustre-OST0001" */
8762         dash = memchr(tgtname, '-', LUSTRE_MAXFSNAME + 1);
8763         if (!dash) {
8764                 fprintf(stderr, "wrong tgtname format '%s'\n", tgtname);
8765                 return -EINVAL;
8766         }
8767         dash += 4;
8768
8769         *idx = strtoul(dash, &endp, 16);
8770         if (*idx > 0xffff) {
8771                 fprintf(stderr, "wrong index %s\n", tgtname);
8772                 return -ERANGE;
8773         }
8774
8775         return 0;
8776 }
8777
8778 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
8779                            bool h, __u64 *total)
8780 {
8781         int rc = 0, rc1 = 0, count = 0, i = 0;
8782         char **list = NULL, *buffer = NULL;
8783         __u32 valid = qctl->qc_valid;
8784
8785         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL && is_mdt)
8786                 return 0;
8787
8788         /* Is it correct for the case OST0000, OST0002, OST0003 -
8789          * we will ask OST0001 that is absent and won't ask OST0003? */
8790         rc = llapi_get_obd_count(mnt, &count, is_mdt);
8791         if (rc) {
8792                 fprintf(stderr, "can not get %s count: %s\n",
8793                         is_mdt ? "mdt" : "ost", strerror(-rc));
8794                 return rc;
8795         }
8796
8797         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
8798                 char fname[PATH_MAX];
8799                 char fsname[LUSTRE_MAXFSNAME + 1];
8800                 int bufsize = sizeof(struct obd_uuid) * count;
8801
8802                 rc = llapi_search_fsname(mnt, fsname);
8803                 if (rc) {
8804                         fprintf(stderr, "cannot get fsname for mountpoint %s\n",
8805                                 mnt);
8806                         goto out;
8807                 }
8808                 buffer = malloc(bufsize + sizeof(*list) * count);
8809                 if (!buffer)
8810                         return -ENOMEM;
8811                 list = (char **)(buffer + bufsize);
8812                 snprintf(fname, PATH_MAX, "%s.%s", fsname, qctl->qc_poolname);
8813                 count = llapi_get_poolmembers(fname, list, count,
8814                                               buffer, bufsize);
8815                 if (count <= 0)
8816                         goto out;
8817         }
8818
8819         for (i = 0; i < count; i++) {
8820                 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
8821                         unsigned int index;
8822
8823                         if (tgt_name2index(list[i], &index))
8824                                 continue;
8825                         qctl->qc_idx = index;
8826                 } else {
8827                         qctl->qc_idx = i;
8828                 }
8829
8830                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
8831                 rc = llapi_quotactl(mnt, qctl);
8832                 if (rc) {
8833                         /* It is remote client case. */
8834                         if (rc == -EOPNOTSUPP) {
8835                                 rc = 0;
8836                                 goto out;
8837                         }
8838
8839                         /* no target for this index yet */
8840                         if (rc == -ENODEV) {
8841                                 rc = 0;
8842                                 continue;
8843                         }
8844
8845                         /* inactive target */
8846                         if (rc == -ENODATA) {
8847                                 char name[UUID_MAX+8];
8848
8849                                 snprintf(name, sizeof(name), "%s[inact]",
8850                                         obd_uuid2str(&qctl->obd_uuid));
8851                                 memset(&qctl->qc_dqinfo, 0,
8852                                        sizeof(qctl->qc_dqinfo));
8853                                 memset(&qctl->qc_dqblk, 0,
8854                                        sizeof(qctl->qc_dqblk));
8855                                 print_quota(name, qctl, qctl->qc_valid, 0, h,
8856                                             false);
8857                                 rc = 0;
8858                                 continue;
8859                         }
8860
8861                         if (!rc1)
8862                                 rc1 = rc;
8863                         fprintf(stderr, "quotactl %s%d failed.\n",
8864                                 is_mdt ? "mdt" : "ost", qctl->qc_idx);
8865                         continue;
8866                 }
8867
8868                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
8869                             qctl->qc_valid, 0, h, false);
8870                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
8871                                    qctl->qc_dqblk.dqb_bhardlimit;
8872         }
8873 out:
8874         if (buffer)
8875                 free(buffer);
8876         qctl->qc_valid = valid;
8877         return rc ? : rc1;
8878 }
8879
8880 static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
8881                            int verbose, int quiet, bool human_readable,
8882                            bool show_default)
8883 {
8884         int rc1 = 0, rc2 = 0, rc3 = 0;
8885         char *obd_type = (char *)qctl->obd_type;
8886         char *obd_uuid = (char *)qctl->obd_uuid.uuid;
8887         __u64 total_ialloc = 0, total_balloc = 0;
8888         bool use_default_for_blk = false;
8889         bool use_default_for_file = false;
8890         int inacc;
8891
8892         rc1 = llapi_quotactl(mnt, qctl);
8893         if (rc1 < 0) {
8894                 switch (rc1) {
8895                 case -ESRCH:
8896                         fprintf(stderr, "%s quotas are not enabled.\n",
8897                                 qtype_name(qctl->qc_type));
8898                         goto out;
8899                 case -EPERM:
8900                         fprintf(stderr, "Permission denied.\n");
8901                 case -ENODEV:
8902                 case -ENOENT:
8903                         /* We already got error message. */
8904                         goto out;
8905                 default:
8906                         fprintf(stderr, "Unexpected quotactl error: %s\n",
8907                                 strerror(-rc1));
8908                 }
8909         }
8910
8911         if (!show_default && qctl->qc_id == 0) {
8912                 qctl->qc_dqblk.dqb_bhardlimit = 0;
8913                 qctl->qc_dqblk.dqb_bsoftlimit = 0;
8914                 qctl->qc_dqblk.dqb_ihardlimit = 0;
8915                 qctl->qc_dqblk.dqb_isoftlimit = 0;
8916                 qctl->qc_dqblk.dqb_btime = 0;
8917                 qctl->qc_dqblk.dqb_itime = 0;
8918                 qctl->qc_dqblk.dqb_valid |= QIF_LIMITS | QIF_TIMES;
8919         }
8920
8921         if (qctl->qc_dqblk.dqb_valid & QIF_BTIME &&
8922             LQUOTA_FLAG(qctl->qc_dqblk.dqb_btime) & LQUOTA_FLAG_DEFAULT) {
8923                 use_default_for_blk = true;
8924                 qctl->qc_dqblk.dqb_btime &= LQUOTA_GRACE_MASK;
8925         }
8926
8927         if (qctl->qc_dqblk.dqb_valid & QIF_ITIME &&
8928             LQUOTA_FLAG(qctl->qc_dqblk.dqb_itime) & LQUOTA_FLAG_DEFAULT) {
8929                 use_default_for_file = true;
8930                 qctl->qc_dqblk.dqb_itime &= LQUOTA_GRACE_MASK;
8931         }
8932
8933         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
8934              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
8935              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL ||
8936              qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) && !quiet)
8937                 print_quota_title(name, qctl, human_readable, show_default);
8938
8939         if (rc1 && *obd_type)
8940                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
8941
8942         if (qctl->qc_valid != QC_GENERAL)
8943                 mnt = "";
8944
8945         inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
8946                  qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
8947                 ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
8948                  (QIF_LIMITS|QIF_USAGE));
8949
8950         print_quota(mnt, qctl, QC_GENERAL, rc1, human_readable, show_default);
8951
8952         if (!show_default && verbose &&
8953             qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO &&
8954             qctl->qc_cmd != LUSTRE_Q_GETINFOPOOL) {
8955                 char strbuf[STRBUF_LEN];
8956
8957                 rc2 = print_obd_quota(mnt, qctl, 1, human_readable,
8958                                       &total_ialloc);
8959                 rc3 = print_obd_quota(mnt, qctl, 0, human_readable,
8960                                       &total_balloc);
8961                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
8962                            human_readable);
8963                 printf("Total allocated inode limit: %ju, total allocated block limit: %s\n",
8964                        (uintmax_t)total_ialloc, strbuf);
8965         }
8966
8967         if (use_default_for_blk)
8968                 printf("%cid %u is using default block quota setting\n",
8969                        *qtype_name(qctl->qc_type), qctl->qc_id);
8970
8971         if (use_default_for_file)
8972                 printf("%cid %u is using default file quota setting\n",
8973                        *qtype_name(qctl->qc_type), qctl->qc_id);
8974
8975         if (rc1 || rc2 || rc3 || inacc)
8976                 printf("Some errors happened when getting quota info. Some devices may be not working or deactivated. The data in \"[]\" is inaccurate.\n");
8977 out:
8978         if (rc1)
8979                 return rc1;
8980         if (rc2)
8981                 return rc2;
8982         if (rc3)
8983                 return rc3;
8984         if (inacc)
8985                 return -EIO;
8986
8987         return 0;
8988 }
8989
8990 static int lfs_project(int argc, char **argv)
8991 {
8992         int ret = 0, err = 0, c, i;
8993         struct project_handle_control phc = { 0 };
8994         enum lfs_project_ops_t op;
8995
8996         phc.newline = true;
8997         phc.assign_projid = false;
8998         /* default action */
8999         op = LFS_PROJECT_LIST;
9000
9001         while ((c = getopt(argc, argv, "p:cCsdkr0")) != -1) {
9002                 switch (c) {
9003                 case 'c':
9004                         if (op != LFS_PROJECT_LIST) {
9005                                 fprintf(stderr,
9006                                         "%s: cannot specify '-c' '-C' '-s' together\n",
9007                                         progname);
9008                                 return CMD_HELP;
9009                         }
9010
9011                         op = LFS_PROJECT_CHECK;
9012                         break;
9013                 case 'C':
9014                         if (op != LFS_PROJECT_LIST) {
9015                                 fprintf(stderr,
9016                                         "%s: cannot specify '-c' '-C' '-s' together\n",
9017                                         progname);
9018                                 return CMD_HELP;
9019                         }
9020
9021                         op = LFS_PROJECT_CLEAR;
9022                         break;
9023                 case 's':
9024                         if (op != LFS_PROJECT_LIST) {
9025                                 fprintf(stderr,
9026                                         "%s: cannot specify '-c' '-C' '-s' together\n",
9027                                         progname);
9028                                 return CMD_HELP;
9029                         }
9030
9031                         phc.set_inherit = true;
9032                         op = LFS_PROJECT_SET;
9033                         break;
9034                 case 'd':
9035                         phc.dironly = true;
9036                         break;
9037                 case 'k':
9038                         phc.keep_projid = true;
9039                         break;
9040                 case 'r':
9041                         phc.recursive = true;
9042                         break;
9043                 case 'p':
9044                         if (str2quotaid(&phc.projid, optarg)) {
9045                                 fprintf(stderr,
9046                                         "Invalid project ID: %s\n",
9047                                         optarg);
9048                                 return CMD_HELP;
9049                         }
9050
9051                         phc.assign_projid = true;
9052
9053                         break;
9054                 case '0':
9055                         phc.newline = false;
9056                         break;
9057                 default:
9058                         fprintf(stderr, "%s: invalid option '%c'\n",
9059                                 progname, optopt);
9060                         return CMD_HELP;
9061                 }
9062         }
9063
9064         if (phc.assign_projid && op == LFS_PROJECT_LIST) {
9065                 op = LFS_PROJECT_SET;
9066                 phc.set_projid = true;
9067         } else if (phc.assign_projid && op == LFS_PROJECT_SET) {
9068                 phc.set_projid = true;
9069         }
9070
9071         switch (op) {
9072         case LFS_PROJECT_CHECK:
9073                 if (phc.keep_projid) {
9074                         fprintf(stderr,
9075                                 "%s: '-k' is useless together with '-c'\n",
9076                                 progname);
9077                         return CMD_HELP;
9078                 }
9079                 break;
9080         case LFS_PROJECT_CLEAR:
9081                 if (!phc.newline) {
9082                         fprintf(stderr,
9083                                 "%s: '-0' is useless together with '-C'\n",
9084                                 progname);
9085                         return CMD_HELP;
9086                 }
9087                 if (phc.assign_projid) {
9088                         fprintf(stderr,
9089                                 "%s: '-p' is useless together with '-C'\n",
9090                                 progname);
9091                         return CMD_HELP;
9092                 }
9093                 break;
9094         case LFS_PROJECT_SET:
9095                 if (!phc.newline) {
9096                         fprintf(stderr,
9097                                 "%s: '-0' is useless together with '-s'\n",
9098                                 progname);
9099                         return CMD_HELP;
9100                 }
9101                 if (phc.keep_projid) {
9102                         fprintf(stderr,
9103                                 "%s: '-k' is useless together with '-s'\n",
9104                                 progname);
9105                         return CMD_HELP;
9106                 }
9107                 break;
9108         default:
9109                 if (!phc.newline) {
9110                         fprintf(stderr,
9111                                 "%s: '-0' is useless for list operations\n",
9112                                 progname);
9113                         return CMD_HELP;
9114                 }
9115                 break;
9116         }
9117
9118         argv += optind;
9119         argc -= optind;
9120         if (argc == 0) {
9121                 fprintf(stderr, "%s: missing file or directory target(s)\n",
9122                         progname);
9123                 return CMD_HELP;
9124         }
9125
9126         for (i = 0; i < argc; i++) {
9127                 switch (op) {
9128                 case LFS_PROJECT_CHECK:
9129                         err = lfs_project_check(argv[i], &phc);
9130                         break;
9131                 case LFS_PROJECT_LIST:
9132                         err = lfs_project_list(argv[i], &phc);
9133                         break;
9134                 case LFS_PROJECT_CLEAR:
9135                         err = lfs_project_clear(argv[i], &phc);
9136                         break;
9137                 case LFS_PROJECT_SET:
9138                         err = lfs_project_set(argv[i], &phc);
9139                         break;
9140                 default:
9141                         break;
9142                 }
9143                 if (err && !ret)
9144                         ret = err;
9145         }
9146
9147         return ret;
9148 }
9149
9150 static int lfs_quota(int argc, char **argv)
9151 {
9152         int c;
9153         char *mnt, *name = NULL;
9154         struct if_quotactl *qctl;
9155         char *obd_uuid;
9156         int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
9157         __u32 valid = QC_GENERAL, idx = 0;
9158         bool human_readable = false;
9159         bool show_default = false;
9160         int qtype;
9161         bool show_pools = false;
9162         struct option long_opts[] = {
9163         { .val = LFS_POOL_OPT, .name = "pool", .has_arg = optional_argument },
9164         { .name = NULL } };
9165         char **poollist = NULL;
9166         char *buf = NULL;
9167         int poolcount, i;
9168
9169         qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1);
9170         if (!qctl)
9171                 return -ENOMEM;
9172
9173         qctl->qc_cmd = LUSTRE_Q_GETQUOTA;
9174         qctl->qc_type = ALLQUOTA;
9175         obd_uuid = (char *)qctl->obd_uuid.uuid;
9176
9177         while ((c = getopt_long(argc, argv, "gGi:I:o:pPqtuUvh",
9178                 long_opts, NULL)) != -1) {
9179                 switch (c) {
9180                 case 'U':
9181                         show_default = true;
9182                 case 'u':
9183                         qtype = USRQUOTA;
9184                         goto quota_type;
9185                 case 'G':
9186                         show_default = true;
9187                 case 'g':
9188                         qtype = GRPQUOTA;
9189                         goto quota_type;
9190                 case 'P':
9191                         show_default = true;
9192                 case 'p':
9193                         qtype = PRJQUOTA;
9194 quota_type:
9195                         if (qctl->qc_type != ALLQUOTA) {
9196                                 fprintf(stderr,
9197                                         "%s quota: only one of -u, -g, or -p may be specified\n",
9198                                         progname);
9199                                 rc = CMD_HELP;
9200                                 goto out;
9201                         }
9202                         qctl->qc_type = qtype;
9203                         break;
9204                 case 't':
9205                         qctl->qc_cmd = LUSTRE_Q_GETINFO;
9206                         break;
9207                 case 'o':
9208                         valid = qctl->qc_valid = QC_UUID;
9209                         snprintf(obd_uuid, sizeof(*obd_uuid), "%s", optarg);
9210                         break;
9211                 case 'i':
9212                         valid = qctl->qc_valid = QC_MDTIDX;
9213                         idx = qctl->qc_idx = atoi(optarg);
9214                         if (idx == 0 && *optarg != '0') {
9215                                 fprintf(stderr,
9216                                         "%s quota: invalid MDT index '%s'\n",
9217                                         progname, optarg);
9218                                 rc = CMD_HELP;
9219                                 goto out;
9220                         }
9221                         break;
9222                 case 'I':
9223                         valid = qctl->qc_valid = QC_OSTIDX;
9224                         idx = qctl->qc_idx = atoi(optarg);
9225                         if (idx == 0 && *optarg != '0') {
9226                                 fprintf(stderr,
9227                                         "%s quota: invalid OST index '%s'\n",
9228                                         progname, optarg);
9229                                 rc = CMD_HELP;
9230                                 goto out;
9231                         }
9232                         break;
9233                 case 'v':
9234                         verbose = 1;
9235                         break;
9236                 case 'q':
9237                         quiet = 1;
9238                         break;
9239                 case 'h':
9240                         human_readable = true;
9241                         break;
9242                 case LFS_POOL_OPT:
9243                         if ((!optarg) && (argv[optind] != NULL) &&
9244                                 (argv[optind][0] != '-') &&
9245                                 (argv[optind][0] != '/')) {
9246                                 optarg = argv[optind++];
9247                                 if (lfs_verify_poolarg(optarg)) {
9248                                         rc = -EINVAL;
9249                                         goto out;
9250                                 }
9251                                 strncpy(qctl->qc_poolname, optarg,
9252                                         LOV_MAXPOOLNAME);
9253                                 if (qctl->qc_cmd == LUSTRE_Q_GETINFO)
9254                                         qctl->qc_cmd = LUSTRE_Q_GETINFOPOOL;
9255                                 else
9256                                         qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
9257                                 break;
9258                         }
9259
9260                         /* optarg is NULL */
9261                         show_pools = true;
9262                         qctl->qc_cmd = LUSTRE_Q_GETQUOTAPOOL;
9263                         break;
9264                 default:
9265                         fprintf(stderr, "%s quota: unrecognized option '%s'\n",
9266                                 progname, argv[optind - 1]);
9267                         rc = CMD_HELP;
9268                         goto out;
9269                 }
9270         }
9271
9272         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
9273         if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
9274              qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) &&
9275              qctl->qc_type == ALLQUOTA &&
9276              optind == argc - 1 && !show_default) {
9277                 qctl->qc_idx = idx;
9278
9279                 for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) {
9280                         qctl->qc_type = qtype;
9281                         qctl->qc_valid = valid;
9282                         if (qtype == USRQUOTA) {
9283                                 qctl->qc_id = geteuid();
9284                                 rc = uid2name(&name, qctl->qc_id);
9285                         } else {
9286                                 qctl->qc_id = getegid();
9287                                 rc = gid2name(&name, qctl->qc_id);
9288                                 memset(&qctl->qc_dqblk, 0,
9289                                        sizeof(qctl->qc_dqblk));
9290                         }
9291                         if (rc)
9292                                 name = "<unknown>";
9293                         mnt = argv[optind];
9294                         rc1 = get_print_quota(mnt, name, qctl, verbose, quiet,
9295                                               human_readable, show_default);
9296                         if (rc1 && !rc)
9297                                 rc = rc1;
9298                 }
9299                 goto out;
9300         /* lfs quota -u username /path/to/lustre/mount */
9301         } else if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
9302                    qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
9303                 /* options should be followed by u/g-name and mntpoint */
9304                 if ((!show_default && optind + 2 != argc) ||
9305                     (show_default && optind + 1 != argc) ||
9306                     qctl->qc_type == ALLQUOTA) {
9307                         fprintf(stderr,
9308                                 "%s quota: name and mount point must be specified\n",
9309                                 progname);
9310                         rc = CMD_HELP;
9311                         goto out;
9312                 }
9313
9314                 if (!show_default) {
9315                         name = argv[optind++];
9316                         switch (qctl->qc_type) {
9317                         case USRQUOTA:
9318                                 rc = name2uid(&qctl->qc_id, name);
9319                                 break;
9320                         case GRPQUOTA:
9321                                 rc = name2gid(&qctl->qc_id, name);
9322                                 break;
9323                         case PRJQUOTA:
9324                                 rc = name2projid(&qctl->qc_id, name);
9325                                 break;
9326                         default:
9327                                 rc = -ENOTSUP;
9328                                 break;
9329                         }
9330                 } else {
9331                         qctl->qc_valid = QC_GENERAL;
9332                         qctl->qc_cmd = qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ?
9333                                         LUSTRE_Q_GETDEFAULT_POOL :
9334                                         LUSTRE_Q_GETDEFAULT;
9335                         qctl->qc_id = 0;
9336                 }
9337
9338                 if (rc) {
9339                         if (str2quotaid(&qctl->qc_id, name)) {
9340                                 fprintf(stderr, "%s quota: invalid id '%s'\n",
9341                                         progname, name);
9342                                 rc = CMD_HELP;
9343                                 goto out;
9344                         }
9345                 }
9346         } else if (optind + 1 != argc || qctl->qc_type == ALLQUOTA) {
9347                 fprintf(stderr, "%s quota: missing quota info argument(s)\n",
9348                         progname);
9349                 rc = CMD_HELP;
9350                 goto out;
9351         }
9352
9353         mnt = argv[optind];
9354         if (show_pools) {
9355                 char *p;
9356
9357                 i = 0;
9358                 rc = llapi_get_poolbuf(mnt, &buf, &poollist, &poolcount);
9359                 if (rc)
9360                         goto out;
9361
9362                 for (i = 0; i < poolcount; i++) {
9363                         p = memchr(poollist[i], '.', MAXNAMLEN);
9364                         if (!p) {
9365                                 fprintf(stderr, "bad string format %.*s\n",
9366                                         MAXNAMLEN, poollist[i]);
9367                                 rc = -EINVAL;
9368                                 goto out;
9369                         }
9370                         p++;
9371                         printf("Quotas for pool: %s\n", p);
9372                         strncpy(qctl->qc_poolname, p, LOV_MAXPOOLNAME);
9373                         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
9374                                              human_readable, show_default);
9375                         if (rc)
9376                                 break;
9377                 }
9378                 goto out;
9379         }
9380
9381         rc = get_print_quota(mnt, name, qctl, verbose, quiet,
9382                              human_readable, show_default);
9383 out:
9384         free(buf);
9385         free(qctl);
9386         return rc;
9387 }
9388 #endif /* HAVE_SYS_QUOTA_H! */
9389
9390 static int flushctx_ioctl(char *mp)
9391 {
9392         int fd, rc;
9393
9394         fd = open(mp, O_RDONLY);
9395         if (fd == -1) {
9396                 fprintf(stderr, "flushctx: error open %s: %s\n",
9397                         mp, strerror(errno));
9398                 return -1;
9399         }
9400
9401         rc = ioctl(fd, LL_IOC_FLUSHCTX);
9402         if (rc == -1)
9403                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
9404                         mp, strerror(errno));
9405
9406         close(fd);
9407         return rc;
9408 }
9409
9410 static int lfs_flushctx(int argc, char **argv)
9411 {
9412         int     kdestroy = 0, reap = 0, c;
9413         char    mntdir[PATH_MAX] = {'\0'};
9414         int     index = 0;
9415         int     rc = 0;
9416
9417         while ((c = getopt(argc, argv, "kr")) != -1) {
9418                 switch (c) {
9419                 case 'k':
9420                         kdestroy = 1;
9421                         break;
9422                 case 'r':
9423                         reap = 1;
9424                         break;
9425                 default:
9426                         fprintf(stderr,
9427                                 "error: %s: option '-%c' unrecognized\n",
9428                                 argv[0], c);
9429                         return CMD_HELP;
9430                 }
9431         }
9432
9433         if (kdestroy) {
9434                 rc = system("kdestroy > /dev/null");
9435                 if (rc) {
9436                         rc = WEXITSTATUS(rc);
9437                         fprintf(stderr,
9438                                 "error destroying tickets: %d, continuing\n",
9439                                 rc);
9440                 }
9441         }
9442
9443         if (optind >= argc) {
9444                 /* flush for all mounted lustre fs. */
9445                 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
9446                         /* Check if we have a mount point */
9447                         if (mntdir[0] == '\0')
9448                                 continue;
9449
9450                         if (flushctx_ioctl(mntdir))
9451                                 rc = -1;
9452
9453                         mntdir[0] = '\0'; /* avoid matching in next loop */
9454                 }
9455         } else {
9456                 /* flush fs as specified */
9457                 while (optind < argc) {
9458                         if (flushctx_ioctl(argv[optind++]))
9459                                 rc = -1;
9460                 }
9461         }
9462
9463         if (reap) {
9464                 rc = system("keyctl reap > /dev/null");
9465                 if (rc != 0) {
9466                         rc = WEXITSTATUS(rc);
9467                         fprintf(stderr, "error reaping keyring: %d\n", rc);
9468                 }
9469         }
9470
9471         return rc;
9472 }
9473
9474 static int lfs_changelog(int argc, char **argv)
9475 {
9476         void *changelog_priv;
9477         struct changelog_rec *rec;
9478         long long startrec = 0, endrec = 0;
9479         char *mdd;
9480         struct option long_opts[] = {
9481                 { .val = 'f', .name = "follow", .has_arg = no_argument },
9482                 { .name = NULL } };
9483         char short_opts[] = "f";
9484         int rc, follow = 0;
9485
9486         while ((rc = getopt_long(argc, argv, short_opts,
9487                 long_opts, NULL)) != -1) {
9488                 switch (rc) {
9489                 case 'f':
9490                         follow++;
9491                         break;
9492                 default:
9493                         fprintf(stderr,
9494                                 "%s changelog: unrecognized option '%s'\n",
9495                                 progname, argv[optind - 1]);
9496                         return CMD_HELP;
9497                 }
9498         }
9499         if (optind >= argc) {
9500                 fprintf(stderr, "%s changelog: mdtname must be specified\n",
9501                         progname);
9502                 return CMD_HELP;
9503         }
9504
9505         mdd = argv[optind++];
9506         if (argc > optind) {
9507                 errno = 0;
9508                 startrec = strtoll(argv[optind++], NULL, 10);
9509                 if (errno != 0 || startrec < 0) {
9510                         fprintf(stderr,
9511                                 "%s changelog: bad startrec\n",
9512                                 progname);
9513                         return CMD_HELP;
9514                 }
9515         }
9516
9517         if (argc > optind) {
9518                 errno = 0;
9519                 endrec = strtoll(argv[optind++], NULL, 10);
9520                 if (errno != 0 || endrec < 0) {
9521                         fprintf(stderr,
9522                                 "%s changelog: bad endrec\n",
9523                                 progname);
9524                         return CMD_HELP;
9525                 }
9526         }
9527
9528         rc = llapi_changelog_start(&changelog_priv,
9529                                    CHANGELOG_FLAG_BLOCK |
9530                                    CHANGELOG_FLAG_JOBID |
9531                                    CHANGELOG_FLAG_EXTRA_FLAGS |
9532                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
9533                                    mdd, startrec);
9534         if (rc < 0) {
9535                 fprintf(stderr, "%s changelog: cannot start changelog: %s\n",
9536                         progname, strerror(errno = -rc));
9537                 return rc;
9538         }
9539
9540         rc = llapi_changelog_set_xflags(changelog_priv,
9541                                         CHANGELOG_EXTRA_FLAG_UIDGID |
9542                                         CHANGELOG_EXTRA_FLAG_NID |
9543                                         CHANGELOG_EXTRA_FLAG_OMODE |
9544                                         CHANGELOG_EXTRA_FLAG_XATTR);
9545         if (rc < 0) {
9546                 fprintf(stderr,
9547                         "%s changelog: cannot set xflags for changelog: %s\n",
9548                         progname, strerror(errno = -rc));
9549                 return rc;
9550         }
9551
9552         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
9553                 time_t secs;
9554                 struct tm ts;
9555
9556                 if (endrec && rec->cr_index > endrec) {
9557                         llapi_changelog_free(&rec);
9558                         break;
9559                 }
9560                 if (rec->cr_index < startrec) {
9561                         llapi_changelog_free(&rec);
9562                         continue;
9563                 }
9564
9565                 secs = rec->cr_time >> 30;
9566                 gmtime_r(&secs, &ts);
9567                 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
9568                        "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
9569                        changelog_type2str(rec->cr_type),
9570                        ts.tm_hour, ts.tm_min, ts.tm_sec,
9571                        (int)(rec->cr_time & ((1 << 30) - 1)),
9572                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
9573                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
9574
9575                 if (rec->cr_flags & CLF_JOBID) {
9576                         struct changelog_ext_jobid *jid =
9577                                 changelog_rec_jobid(rec);
9578
9579                         if (jid->cr_jobid[0] != '\0')
9580                                 printf(" j=%s", jid->cr_jobid);
9581                 }
9582
9583                 if (rec->cr_flags & CLF_EXTRA_FLAGS) {
9584                         struct changelog_ext_extra_flags *ef =
9585                                 changelog_rec_extra_flags(rec);
9586
9587                         printf(" ef=0x%llx",
9588                                (unsigned long long)ef->cr_extra_flags);
9589
9590                         if (ef->cr_extra_flags & CLFE_UIDGID) {
9591                                 struct changelog_ext_uidgid *uidgid =
9592                                         changelog_rec_uidgid(rec);
9593
9594                                 printf(" u=%llu:%llu",
9595                                        (unsigned long long)uidgid->cr_uid,
9596                                        (unsigned long long)uidgid->cr_gid);
9597                         }
9598                         if (ef->cr_extra_flags & CLFE_NID) {
9599                                 struct changelog_ext_nid *nid =
9600                                         changelog_rec_nid(rec);
9601
9602                                 printf(" nid=%s",
9603                                        libcfs_nid2str(nid->cr_nid));
9604                         }
9605
9606                         if (ef->cr_extra_flags & CLFE_OPEN) {
9607                                 struct changelog_ext_openmode *omd =
9608                                         changelog_rec_openmode(rec);
9609                                 char mode[] = "---";
9610
9611                                 /* exec mode must be exclusive */
9612                                 if (omd->cr_openflags & MDS_FMODE_EXEC) {
9613                                         mode[2] = 'x';
9614                                 } else {
9615                                         if (omd->cr_openflags & MDS_FMODE_READ)
9616                                                 mode[0] = 'r';
9617                                         if (omd->cr_openflags &
9618                                             (MDS_FMODE_WRITE |
9619                                              MDS_OPEN_TRUNC |
9620                                              MDS_OPEN_APPEND))
9621                                                 mode[1] = 'w';
9622                                 }
9623
9624                                 if (strcmp(mode, "---") != 0)
9625                                         printf(" m=%s", mode);
9626                         }
9627
9628                         if (ef->cr_extra_flags & CLFE_XATTR) {
9629                                 struct changelog_ext_xattr *xattr =
9630                                         changelog_rec_xattr(rec);
9631
9632                                 if (xattr->cr_xattr[0] != '\0')
9633                                         printf(" x=%s", xattr->cr_xattr);
9634                         }
9635                 }
9636
9637                 if (!fid_is_zero(&rec->cr_pfid))
9638                         printf(" p="DFID, PFID(&rec->cr_pfid));
9639                 if (rec->cr_namelen)
9640                         printf(" %.*s", rec->cr_namelen,
9641                                changelog_rec_name(rec));
9642
9643                 if (rec->cr_flags & CLF_RENAME) {
9644                         struct changelog_ext_rename *rnm =
9645                                 changelog_rec_rename(rec);
9646
9647                         if (!fid_is_zero(&rnm->cr_sfid))
9648                                 printf(" s="DFID" sp="DFID" %.*s",
9649                                        PFID(&rnm->cr_sfid),
9650                                        PFID(&rnm->cr_spfid),
9651                                        (int)changelog_rec_snamelen(rec),
9652                                        changelog_rec_sname(rec));
9653                 }
9654                 printf("\n");
9655
9656                 llapi_changelog_free(&rec);
9657         }
9658
9659         llapi_changelog_fini(&changelog_priv);
9660
9661         if (rc < 0)
9662                 fprintf(stderr, "%s changelog: cannot access changelog: %s\n",
9663                         progname, strerror(errno = -rc));
9664
9665         return (rc == 1 ? 0 : rc);
9666 }
9667
9668 static int lfs_changelog_clear(int argc, char **argv)
9669 {
9670         long long endrec;
9671         int rc;
9672
9673         if (argc != 4)
9674                 return CMD_HELP;
9675
9676         errno = 0;
9677         endrec = strtoll(argv[3], NULL, 10);
9678         if (errno != 0 || endrec < 0) {
9679                 fprintf(stderr,
9680                         "%s: bad endrec '%s'\n",
9681                         argv[0], argv[3]);
9682                 return CMD_HELP;
9683         }
9684
9685         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
9686
9687         if (rc == -EINVAL)
9688                 fprintf(stderr, "%s: record out of range: %llu\n",
9689                         argv[0], endrec);
9690         else if (rc == -ENOENT)
9691                 fprintf(stderr, "%s: no changelog user: %s\n",
9692                         argv[0], argv[2]);
9693         else if (rc)
9694                 fprintf(stderr, "%s error: %s\n", argv[0],
9695                         strerror(-rc));
9696
9697         if (rc)
9698                 errno = -rc;
9699
9700         return rc;
9701 }
9702
9703 static void rstripc(char *str, int c)
9704 {
9705         char *end = str + strlen(str);
9706
9707         for (; str < end && end[-1] == c; --end)
9708                 end[-1] = '\0';
9709 }
9710
9711 /* Helper function to lfs_fid2path. To print out only the file names and
9712  * not the full path. Do not call OBD_IOC_FID2PATH for every file. Instead
9713  * read the trusted.link xattr and loop over all the records to get all the
9714  * file names.
9715  */
9716 static int lfs_fid2path_prn_name(char *mnt_dir, char *path_buf,
9717                                  bool print_linkno, bool print_fid, char *ptr,
9718                                  const char *fid_str, int linktmp)
9719 {
9720         char buf[65536]; /* BUFFER_SIZE 65536 */
9721         char full_path[PATH_MAX * 2 + 2];
9722         struct link_ea_header *leh;
9723         struct link_ea_entry *lee;
9724         ssize_t size;
9725         int reclen, i, rc = 0;
9726
9727         /* Generate full_path */
9728         snprintf(full_path, sizeof(full_path) - 1, "%s/%s", mnt_dir, path_buf);
9729
9730         size = getxattr(full_path, "trusted.link", buf, sizeof(buf));
9731         if (size < 0) {
9732                 fprintf(stderr, "%s: failed to read %s xattr: %s\n", path_buf,
9733                         "trusted.link", strerror(errno));
9734                 rc = -errno;
9735                 goto fail;
9736         }
9737
9738         leh = (struct link_ea_header *)buf;
9739
9740         if (leh->leh_magic == __swab32(LINK_EA_MAGIC))
9741                 leh->leh_reccount = __swab32(leh->leh_reccount);
9742
9743         lee = (struct link_ea_entry *)(leh + 1);
9744
9745         for (i = 0; i < leh->leh_reccount; i++) {
9746                 reclen = (lee->lee_reclen[0] << 8) | lee->lee_reclen[1];
9747
9748                 /* handle -n -l case */
9749                 if (print_linkno) {
9750                         ptr = strrchr(path_buf, '/');
9751                         if (!ptr)
9752                                 ptr = path_buf;
9753                         else
9754                                 ptr = ptr + 1;
9755
9756                         if (strcmp(ptr, lee->lee_name) == 0) {
9757                                 if (print_fid)
9758                                         printf("%s ", fid_str);
9759
9760                                 printf("%d ", linktmp);
9761                                 printf("%s\n", lee->lee_name);
9762                                 break;
9763                         }
9764                 } else {
9765                         if (print_fid)
9766                                 printf("%s ", fid_str);
9767                         printf("%s\n", lee->lee_name);
9768                 }
9769
9770                 /* Get next record */
9771                 lee = (struct link_ea_entry *)((char *)lee + reclen);
9772         }
9773 fail:
9774         return rc;
9775 }
9776
9777 static int lfs_fid2path(int argc, char **argv)
9778 {
9779         struct option long_opts[] = {
9780                 { .val = '0',   .name = "print0",       .has_arg = no_argument },
9781                 { .val = 'c',   .name = "cur",  .has_arg = no_argument },
9782                 { .val = 'c',   .name = "current",      .has_arg = no_argument },
9783                 { .val = 'c',   .name = "print-link",   .has_arg = no_argument },
9784                 { .val = 'f',   .name = "print-fid",    .has_arg = no_argument },
9785                 { .val = 'l',   .name = "link", .has_arg = required_argument },
9786                 { .val = 'n',   .name = "name", .has_arg = no_argument },
9787                 { .name = NULL } };
9788         char short_opts[] = "0cfl:pr:n";
9789         bool print_only_fname = false;
9790         bool print_linkno = false;
9791         bool print_link = false;
9792         bool print_fid = false;
9793         bool print_mnt_dir;
9794         char mnt_dir[PATH_MAX] = "";
9795         int mnt_fd = -1;
9796         char *path_or_fsname;
9797         long long recno = -1;
9798         int linkno = -1;
9799         char *endptr = NULL;
9800         char link_separator = '\n';
9801         int rc = 0;
9802         int c;
9803         int i;
9804
9805         while ((c = getopt_long(argc, argv, short_opts,long_opts, NULL)) !=
9806                 -1) {
9807                 switch (c) {
9808                 case '0':
9809                         link_separator = '\0';
9810                         break;
9811                 case 'c':
9812                         print_link = true;
9813                         break;
9814                 case 'f':
9815                         print_fid = true;
9816                         break;
9817                 case 'l':
9818                         errno = 0;
9819                         linkno = strtol(optarg, &endptr, 10);
9820                         if (errno != 0 || *endptr != '\0' || linkno < 0) {
9821                                 fprintf(stderr,
9822                                         "%s fid2path: invalid linkno '%s'\n",
9823                                         progname, optarg);
9824                                 return CMD_HELP;
9825                         }
9826                         print_linkno = true;
9827                         break;
9828                 case 'n':
9829                         /* Bypass the full parent path if true
9830                          * only print the final filename */
9831                         print_only_fname = true;
9832                         break;
9833                 case 'r':
9834                         /* recno is something to do with changelogs
9835                          * that was never implemented. We just pass it
9836                          * through for the MDT to ignore.
9837                          */
9838                         errno = 0;
9839                         recno = strtoll(optarg, &endptr, 10);
9840                         if (errno != 0 || *endptr != '\0' || recno < 0) {
9841                                 fprintf(stderr,
9842                                         "%s fid2path: invalid recno '%s'\n",
9843                                         progname, optarg);
9844                                 return CMD_HELP;
9845                         }
9846                         break;
9847                 default:
9848                         fprintf(stderr,
9849                                 "%s fid2path: unrecognized option '%s'\n",
9850                                 progname, argv[optind - 1]);
9851                         return CMD_HELP;
9852                 }
9853         }
9854
9855         if (argc - optind < 2) {
9856                 fprintf(stderr,
9857                         "Usage: %s fid2path FSNAME|ROOT FID...\n",
9858                         progname);
9859                 return CMD_HELP;
9860         }
9861
9862         path_or_fsname = argv[optind];
9863
9864         if (*path_or_fsname == '/') {
9865                 print_mnt_dir = true;
9866                 rc = llapi_search_mounts(path_or_fsname, 0, mnt_dir, NULL);
9867         } else {
9868                 print_mnt_dir = false;
9869                 rc = llapi_search_rootpath(mnt_dir, path_or_fsname);
9870         }
9871
9872         if (rc < 0) {
9873                 fprintf(stderr,
9874                         "%s fid2path: cannot resolve mount point for '%s': %s\n",
9875                         progname, path_or_fsname, strerror(-rc));
9876                 goto out;
9877         }
9878
9879         mnt_fd = open(mnt_dir, O_RDONLY | O_DIRECTORY);
9880         if (mnt_fd < 0) {
9881                 fprintf(stderr,
9882                         "%s fid2path: cannot open mount point for '%s': %s\n",
9883                         progname, path_or_fsname, strerror(-rc));
9884                 goto out;
9885         }
9886
9887         /* Strip trailing slashes from mnt_dir. */
9888         rstripc(mnt_dir + 1, '/');
9889
9890         for (i = optind + 1; i < argc; i++) {
9891                 const char *fid_str = argv[i];
9892                 struct lu_fid fid;
9893                 char *ptr = NULL;
9894                 int rc2;
9895
9896                 rc2 = llapi_fid_parse(fid_str, &fid, NULL);
9897                 if (rc2 < 0) {
9898                         fprintf(stderr,
9899                                 "%s fid2path: invalid FID '%s'\n",
9900                                 progname, fid_str);
9901                         if (rc == 0)
9902                                 rc = rc2;
9903
9904                         continue;
9905                 }
9906
9907                 int linktmp = (linkno >= 0) ? linkno : 0;
9908
9909                 while (1) {
9910                         int oldtmp = linktmp;
9911                         long long rectmp = recno;
9912                         char path_buf[PATH_MAX];
9913
9914                         rc2 = llapi_fid2path_at(mnt_fd, &fid, path_buf,
9915                                                 sizeof(path_buf), &rectmp,
9916                                                 &linktmp);
9917                         if (rc2 < 0) {
9918                                 fprintf(stderr,
9919                                         "%s fid2path: cannot find %s %s: %s\n",
9920                                         progname, path_or_fsname, fid_str,
9921                                         strerror(-rc2));
9922                                 if (rc == 0)
9923                                         rc = rc2;
9924                                 break;
9925                         }
9926
9927                         if (print_only_fname && !print_link) {
9928                                 /* '-n' is passed as option here.
9929                                  * For all other cases of -c fall back
9930                                  * to default(else) path as to get the link
9931                                  * count associated with the file name call
9932                                  * to OBD_IOC_FID2PATH is required
9933                                  */
9934                                 rc = lfs_fid2path_prn_name(mnt_dir,
9935                                                            path_buf,
9936                                                            print_linkno,
9937                                                            print_fid, ptr,
9938                                                            fid_str, linktmp);
9939                                 /* llapi_fid2path_at() is already called once
9940                                  * in this case. No need to call it again.
9941                                  * Break out as we have all the filenames.
9942                                  */
9943                                 break;
9944                         }
9945
9946                         if (print_fid)
9947                                 printf("%s ", fid_str);
9948
9949                         if (print_link)
9950                                 printf("%d ", linktmp);
9951
9952                         /* You may think this looks wrong or weird (and it is!)
9953                          * but we are actually trying to preserve the old quirky
9954                          * behaviors (enforced by our old quirky tests!) that
9955                          * make lfs so much fun to work on:
9956                          *
9957                          *   lustre 0x200000007:0x1:0x0 => "/"
9958                          *   /mnt/lustre 0x200000007:0x1:0x0 => "/mnt/lustre//"
9959                          *
9960                          * Note that llapi_fid2path() returns "" for the root
9961                          * FID. */
9962                         if (!print_only_fname) {
9963                                 printf("%s%s%s%c",
9964                                        print_mnt_dir ? mnt_dir : "",
9965                                        (print_mnt_dir || *path_buf == '\0') ?
9966                                        "/" : "", path_buf, link_separator);
9967                         } else {
9968                                 ptr = strrchr(path_buf, '/');
9969                                 if (!ptr)
9970                                         printf("%s\n", path_buf);
9971                                 else
9972                                         printf("%s\n", ptr + 1);
9973                         }
9974
9975                         if (linkno >= 0)
9976                                 /* specified linkno */
9977                                 break;
9978
9979                         if (oldtmp == linktmp)
9980                                 /* no more links */
9981                                 break;
9982                 }
9983         }
9984 out:
9985         if (!(mnt_fd < 0))
9986                 close(mnt_fd);
9987
9988         return rc;
9989 }
9990
9991 static int lfs_path2fid(int argc, char **argv)
9992 {
9993         struct option long_opts[] = {
9994                 { .val = 'p', .name = "parents", .has_arg = no_argument },
9995                 { .name = NULL } };
9996         char            **path;
9997         const char        short_opts[] = "p";
9998         const char       *sep = "";
9999         struct lu_fid     fid;
10000         int               rc = 0;
10001         bool              show_parents = false;
10002
10003         while ((rc = getopt_long(argc, argv, short_opts,
10004                                  long_opts, NULL)) != -1) {
10005                 switch (rc) {
10006                 case 'p':
10007                         show_parents = true;
10008                         break;
10009                 default:
10010                         fprintf(stderr,
10011                                 "%s path2fid: unrecognized option '%s'\n",
10012                                 progname, argv[optind - 1]);
10013                         return CMD_HELP;
10014                 }
10015         }
10016
10017         if (optind > argc - 1) {
10018                 fprintf(stderr, "%s path2fid: FILE... must be specified\n",
10019                         progname);
10020                 return CMD_HELP;
10021         } else if (optind < argc - 1) {
10022                 sep = ": ";
10023         }
10024
10025         rc = 0;
10026         for (path = argv + optind; optind < argc; path++, optind++) {
10027                 int err = 0;
10028
10029                 if (!show_parents) {
10030                         err = llapi_path2fid(*path, &fid);
10031                         if (!err)
10032                                 printf("%s%s"DFID"\n",
10033                                        *sep != '\0' ? *path : "", sep,
10034                                        PFID(&fid));
10035                 } else {
10036                         char            name[NAME_MAX + 1];
10037                         unsigned int    linkno = 0;
10038
10039                         while ((err = llapi_path2parent(*path, linkno, &fid,
10040                                                 name, sizeof(name))) == 0) {
10041                                 if (*sep != '\0' && linkno == 0)
10042                                         printf("%s%s", *path, sep);
10043
10044                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
10045                                        PFID(&fid), name);
10046                                 linkno++;
10047                         }
10048
10049                         /* err == -ENODATA is end-of-loop */
10050                         if (linkno > 0 && err == -ENODATA) {
10051                                 printf("\n");
10052                                 err = 0;
10053                         }
10054                 }
10055
10056                 if (err) {
10057                         fprintf(stderr,
10058                                 "%s path2fid: cannot get %sfid for '%s': %s\n",
10059                                 progname, show_parents ? "parent " : "", *path,
10060                                 strerror(-err));
10061                         if (rc == 0) {
10062                                 rc = err;
10063                                 errno = -err;
10064                         }
10065                 }
10066         }
10067
10068         return rc;
10069 }
10070
10071 #define MAX_ERRNO       4095
10072 #define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO)
10073
10074 static int lfs_rmfid_and_show_errors(int rootfd, struct fid_array *fa)
10075 {
10076         int rc, rc2, k;
10077
10078         rc = llapi_rmfid_at(rootfd, fa);
10079         if (rc < 0) {
10080                 fprintf(stderr, "%s rmfid: cannot remove FIDs: %s\n",
10081                         progname, strerror(-rc));
10082                 return rc;
10083         }
10084
10085         for (k = 0; k < fa->fa_nr; k++) {
10086                 rc2 = (__s32)fa->fa_fids[k].f_ver;
10087                 if (!IS_ERR_VALUE(rc2))
10088                         continue;
10089
10090                 if (rc == 0)
10091                         rc = rc2;
10092
10093                 fa->fa_fids[k].f_ver = 0;
10094                 fprintf(stderr, "%s rmfid: cannot remove "DFID": %s\n",
10095                         progname, PFID(&fa->fa_fids[k]), strerror(-rc2));
10096         }
10097
10098         return rc;
10099 }
10100
10101 static int lfs_rmfid(int argc, char **argv)
10102 {
10103         int rc = 0, rc2, rc3 = 0, nr;
10104         struct fid_array *fa;
10105         const char *device;
10106         char *fidstr;
10107         int rootfd;
10108
10109         /* Interactive mode: Adjust optind */
10110         if (!optind)
10111                 optind++;
10112
10113         device = argv[optind++];
10114
10115         if (optind > argc - 1) {
10116                 fprintf(stderr, "%s rmfid: missing dirname\n", progname);
10117                 return CMD_HELP;
10118         }
10119
10120         nr = argc - optind;
10121
10122         rc = llapi_root_path_open(device, &rootfd);
10123         if (rc < 0) {
10124                 fprintf(stderr,
10125                         "%s rmfid: error opening device/fsname '%s': %s\n",
10126                         progname, device, strerror(-rc));
10127                 return -rc;
10128         }
10129
10130         fa = malloc(offsetof(struct fid_array, fa_fids[nr + 1]));
10131         if (!fa) {
10132                 fprintf(stderr, "%s rmfid: error allocating %zd bytes: %s\n",
10133                         progname, offsetof(struct fid_array, fa_fids[nr + 1]),
10134                         strerror(errno));
10135                 return -ENOMEM;
10136         }
10137
10138         fa->fa_nr = 0;
10139         rc = 0;
10140         while (optind < argc) {
10141                 char *origfidstr;
10142                 int found;
10143
10144                 origfidstr = fidstr = argv[optind++];
10145                 while (*fidstr == '[')
10146                         fidstr++;
10147                 found = sscanf(fidstr, SFID, RFID(&fa->fa_fids[fa->fa_nr]));
10148                 if (found != 3) {
10149                         fprintf(stderr, "lfs rmfid: '%s': Wrong FID format\n",
10150                                 origfidstr);
10151                         if (!rc3)
10152                                 rc3 = -EINVAL; /* Invalid argument */
10153                         continue;
10154                 }
10155                 fa->fa_nr++;
10156                 if (fa->fa_nr == OBD_MAX_FIDS_IN_ARRAY) {
10157                         /* start another batch */
10158                         rc2 = lfs_rmfid_and_show_errors(rootfd, fa);
10159                         if (rc2 && !rc)
10160                                 rc = rc2;
10161                         if (rc3)
10162                                 rc = rc3;
10163                         fa->fa_nr = 0;
10164                 }
10165         }
10166         if (fa->fa_nr) {
10167                 rc2 = lfs_rmfid_and_show_errors(rootfd, fa);
10168                 if (rc2 && !rc)
10169                         rc = rc2;
10170                 if (rc3)
10171                         rc = rc3;
10172         }
10173
10174         if (fa) {
10175                 free(fa);
10176                 fa = NULL;
10177         }
10178
10179         close(rootfd);
10180         return rc;
10181 }
10182
10183 static int lfs_data_version(int argc, char **argv)
10184 {
10185         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
10186         __u64 data_version;
10187         char *path;
10188         int fd;
10189         int rc;
10190         int c;
10191
10192         if (argc < 2) {
10193                 fprintf(stderr, "%s: FILE must be specified\n",
10194                         progname);
10195                 return CMD_HELP;
10196         }
10197
10198         while ((c = getopt(argc, argv, "hnrw")) != -1) {
10199                 switch (c) {
10200                 case 'n':
10201                         data_version_flags = 0;
10202                         break;
10203                 case 'r':
10204                         data_version_flags |= LL_DV_RD_FLUSH;
10205                         break;
10206                 case 'w':
10207                         data_version_flags |= LL_DV_WR_FLUSH;
10208                         break;
10209                 default:
10210                         fprintf(stderr,
10211                                 "%s data_version: unrecognized option '%s'\n",
10212                                 progname, argv[optind - 1]);
10213                         fallthrough;
10214                 case 'h':
10215                         return CMD_HELP;
10216                 }
10217         }
10218         if (optind == argc) {
10219                 fprintf(stderr, "%s data_version: FILE must be specified\n",
10220                         progname);
10221                 return CMD_HELP;
10222         }
10223
10224         path = argv[optind];
10225         fd = open(path, O_RDONLY);
10226         if (fd < 0) {
10227                 rc = -errno;
10228                 fprintf(stderr, "%s data_version: cannot open file '%s': %s\n",
10229                         progname, path, strerror(-rc));
10230                 return rc;
10231         }
10232
10233         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
10234         if (rc < 0)
10235                 fprintf(stderr,
10236                         "%s data_version: cannot get version for '%s': %s\n",
10237                         progname, path, strerror(-rc));
10238         else
10239                 printf("%ju" "\n", (uintmax_t)data_version);
10240
10241         close(fd);
10242         return rc;
10243 }
10244
10245 static int lfs_hsm_state(int argc, char **argv)
10246 {
10247         int rc = 0;
10248         int i = 1;
10249         char *path;
10250         struct hsm_user_state hus;
10251
10252         if (argc < 2)
10253                 return CMD_HELP;
10254
10255         do {
10256                 int rc2;
10257                 path = argv[i];
10258
10259                 rc2 = llapi_hsm_state_get(path, &hus);
10260                 if (rc2) {
10261                         fprintf(stderr,
10262                                 "%s %s: get HSM state for '%s' failed: %s\n",
10263                                 progname, argv[0], path, strerror(-rc2));
10264                         if (!rc)
10265                                 rc = rc2;
10266                         continue;
10267                 }
10268
10269                 /* Display path name and status flags */
10270                 printf("%s: (0x%08x)", path, hus.hus_states);
10271
10272                 if (hus.hus_states & HS_RELEASED)
10273                         printf(" released");
10274                 if (hus.hus_states & HS_EXISTS)
10275                         printf(" exists");
10276                 if (hus.hus_states & HS_DIRTY)
10277                         printf(" dirty");
10278                 if (hus.hus_states & HS_ARCHIVED)
10279                         printf(" archived");
10280                 /* Display user-settable flags */
10281                 if (hus.hus_states & HS_NORELEASE)
10282                         printf(" never_release");
10283                 if (hus.hus_states & HS_NOARCHIVE)
10284                         printf(" never_archive");
10285                 if (hus.hus_states & HS_LOST)
10286                         printf(" lost_from_hsm");
10287
10288                 if (hus.hus_archive_id != 0)
10289                         printf(", archive_id:%d", hus.hus_archive_id);
10290                 printf("\n");
10291
10292         } while (++i < argc);
10293
10294         return rc;
10295 }
10296
10297 #define LFS_HSM_SET   0
10298 #define LFS_HSM_CLEAR 1
10299
10300 /**
10301  * Generic function to set or clear HSM flags.
10302  * Used by hsm_set and hsm_clear.
10303  *
10304  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
10305  */
10306 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
10307 {
10308         struct option long_opts[] = {
10309         { .val = 'A',   .name = "archived",     .has_arg = no_argument },
10310         { .val = 'a',   .name = "noarchive",    .has_arg = no_argument },
10311         { .val = 'd',   .name = "dirty",        .has_arg = no_argument },
10312         { .val = 'e',   .name = "exists",       .has_arg = no_argument },
10313         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10314         { .val = 'i',   .name = "archive-id",   .has_arg = required_argument },
10315         { .val = 'l',   .name = "lost",         .has_arg = no_argument },
10316         { .val = 'r',   .name = "norelease",    .has_arg = no_argument },
10317         { .name = NULL } };
10318         __u64 mask = 0;
10319         int c, rc = 0;
10320         char *path;
10321         __u32 archive_id = 0;
10322         char *end = NULL;
10323
10324         if (argc < 3)
10325                 return CMD_HELP;
10326
10327         while ((c = getopt_long(argc, argv, "aAdehi:lr",
10328                                 long_opts, NULL)) != -1) {
10329                 switch (c) {
10330                 case 'l':
10331                         mask |= HS_LOST;
10332                         break;
10333                 case 'a':
10334                         mask |= HS_NOARCHIVE;
10335                         break;
10336                 case 'A':
10337                         mask |= HS_ARCHIVED;
10338                         break;
10339                 case 'r':
10340                         mask |= HS_NORELEASE;
10341                         break;
10342                 case 'd':
10343                         mask |= HS_DIRTY;
10344                         break;
10345                 case 'e':
10346                         mask |= HS_EXISTS;
10347                         break;
10348                 case 'i':
10349                         errno = 0;
10350                         archive_id = strtol(optarg, &end, 10);
10351                         if (errno != 0 || *end != '\0' || archive_id < 0) {
10352                                 fprintf(stderr,
10353                                         "%s: invalid archive_id: '%s'\n",
10354                                         progname, end);
10355                                 return CMD_HELP;
10356                         }
10357                         break;
10358                 default:
10359                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10360                                 progname, argv[optind - 1]);
10361                         fallthrough;
10362                 case 'h':
10363                         return CMD_HELP;
10364                 }
10365         }
10366
10367         /* User should have specified a flag */
10368         if (mask == 0)
10369                 return CMD_HELP;
10370
10371         while (optind < argc) {
10372                 int rc2;
10373                 path = argv[optind];
10374
10375                 /* If mode == 0, this means we apply the mask. */
10376                 if (mode == LFS_HSM_SET)
10377                         rc2 = llapi_hsm_state_set(path, mask, 0, archive_id);
10378                 else
10379                         rc2 = llapi_hsm_state_set(path, 0, mask, 0);
10380
10381                 if (rc2) {
10382                         fprintf(stderr,
10383                                 "%s %s: change hsm flags for '%s' failed: %s\n",
10384                                 progname, argv[0], path, strerror(-rc2));
10385                         if (!rc)
10386                                 rc = rc2;
10387                 }
10388                 optind++;
10389         }
10390
10391         return rc;
10392 }
10393
10394 static int lfs_hsm_action(int argc, char **argv)
10395 {
10396         struct hsm_current_action hca;
10397         struct hsm_extent he;
10398         enum hsm_user_action hua;
10399         enum hsm_progress_states hps;
10400         int rc = 0;
10401         int i = 1;
10402         char *path;
10403
10404         if (argc < 2)
10405                 return CMD_HELP;
10406
10407         do {
10408                 int rc2;
10409                 path = argv[i];
10410
10411                 rc2 = llapi_hsm_current_action(path, &hca);
10412                 if (rc2) {
10413                         fprintf(stderr,
10414                                 "%s %s: get hsm action for '%s' failed: %s\n",
10415                                 progname, argv[0], path, strerror(-rc2));
10416
10417                         if (!rc)
10418                                 rc = rc2;
10419                         continue;
10420                 }
10421                 he = hca.hca_location;
10422                 hua = hca.hca_action;
10423                 hps = hca.hca_state;
10424
10425                 printf("%s: %s", path, hsm_user_action2name(hua));
10426
10427                 /* Skip file without action */
10428                 if (hca.hca_action == HUA_NONE) {
10429                         printf("\n");
10430                         continue;
10431                 }
10432
10433                 printf(" %s ", hsm_progress_state2name(hps));
10434
10435                 if ((hps == HPS_RUNNING) &&
10436                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
10437                         printf("(%llu bytes moved)\n",
10438                                (unsigned long long)he.length);
10439                 else if ((he.offset + he.length) == LUSTRE_EOF)
10440                         printf("(from %llu to EOF)\n",
10441                                (unsigned long long)he.offset);
10442                 else
10443                         printf("(from %llu to %llu)\n",
10444                                (unsigned long long)he.offset,
10445                                (unsigned long long)(he.offset + he.length));
10446
10447         } while (++i < argc);
10448
10449         return rc;
10450 }
10451
10452 static int lfs_hsm_set(int argc, char **argv)
10453 {
10454         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
10455 }
10456
10457 static int lfs_hsm_clear(int argc, char **argv)
10458 {
10459         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
10460 }
10461
10462 /**
10463  * Check file state and return its fid, to be used by lfs_hsm_request().
10464  *
10465  * \param[in]     file      Path to file to check
10466  * \param[in,out] fid       Pointer to allocated lu_fid struct.
10467  * \param[in,out] last_dev  Pointer to last device id used.
10468  *
10469  * \return 0 on success.
10470  */
10471 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
10472                                 dev_t *last_dev)
10473 {
10474         struct stat     st;
10475         int             rc;
10476
10477         rc = lstat(file, &st);
10478         if (rc) {
10479                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
10480                 return -errno;
10481         }
10482         /*
10483          * Checking for regular file as archiving as posix copytool
10484          * rejects archiving files other than regular files
10485          */
10486         if (!S_ISREG(st.st_mode)) {
10487                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
10488                 return CMD_HELP;
10489         }
10490         /* A request should be ... */
10491         if (*last_dev != st.st_dev && *last_dev != 0) {
10492                 fprintf(stderr,
10493                         "All files should be on the same filesystem: %s\n",
10494                         file);
10495                 return -EINVAL;
10496         }
10497         *last_dev = st.st_dev;
10498
10499         rc = llapi_path2fid(file, fid);
10500         if (rc) {
10501                 fprintf(stderr, "Cannot read FID of %s: %s\n",
10502                         file, strerror(-rc));
10503                 return rc;
10504         }
10505         return 0;
10506 }
10507
10508 /* Fill an HSM HUR item with a given file name.
10509  *
10510  * If mntpath is set, then the filename is actually a FID, and no
10511  * lookup on the filesystem will be performed.
10512  *
10513  * \param[in]  hur         the user request to fill
10514  * \param[in]  idx         index of the item inside the HUR to fill
10515  * \param[in]  mntpath     mountpoint of Lustre
10516  * \param[in]  fname       filename (if mtnpath is NULL)
10517  *                         or FID (if mntpath is set)
10518  * \param[in]  last_dev    pointer to last device id used
10519  *
10520  * \retval 0 on success
10521  * \retval CMD_HELP or a negative errno on error
10522  */
10523 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
10524                          const char *mntpath, const char *fname,
10525                          dev_t *last_dev)
10526 {
10527         struct hsm_user_item *hui = &hur->hur_user_item[idx];
10528         int rc;
10529
10530         hui->hui_extent.length = -1;
10531
10532         if (mntpath) {
10533                 rc = llapi_fid_parse(fname, &hui->hui_fid, NULL);
10534                 if (rc)
10535                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
10536                                 fname);
10537         } else {
10538                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
10539         }
10540
10541         if (rc == 0)
10542                 hur->hur_request.hr_itemcount++;
10543
10544         return rc;
10545 }
10546
10547 static int lfs_hsm_request(int argc, char **argv, int action)
10548 {
10549         struct option long_opts[] = {
10550         { .val = 'a',   .name = "archive",      .has_arg = required_argument },
10551         { .val = 'D',   .name = "data",         .has_arg = required_argument },
10552         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10553         { .val = 'l',   .name = "filelist",     .has_arg = required_argument },
10554         { .val = 'm',   .name = "mntpath",      .has_arg = required_argument },
10555         { .name = NULL } };
10556         dev_t last_dev = 0;
10557         struct hsm_user_request *hur, *oldhur;
10558         int c, i;
10559         size_t len;
10560         int nbfile;
10561         char *line = NULL;
10562         char *filelist = NULL;
10563         char fullpath[PATH_MAX];
10564         char *opaque = NULL;
10565         int opaque_len = 0;
10566         int archive_id = 0;
10567         FILE *fp;
10568         int nbfile_alloc = 0;
10569         char *some_file = NULL;
10570         char *mntpath = NULL;
10571         int rc;
10572
10573         if (argc < 2) {
10574                 rc = CMD_HELP;
10575                 goto out_cmd_help;
10576         }
10577
10578         while ((c = getopt_long(argc, argv, "a:D:hl:m:",
10579                                 long_opts, NULL)) != -1) {
10580                 switch (c) {
10581                 case 'l':
10582                         filelist = optarg;
10583                         break;
10584                 case 'D':
10585                         opaque = optarg;
10586                         break;
10587                 case 'a':
10588                         if (action != HUA_ARCHIVE &&
10589                             action != HUA_REMOVE) {
10590                                 fprintf(stderr,
10591                                         "error: -a is supported only when archiving or removing\n");
10592                                 rc = CMD_HELP;
10593                                 goto out_cmd_help;
10594                         }
10595                         archive_id = atoi(optarg);
10596                         break;
10597                 case 'm':
10598                         if (!some_file) {
10599                                 mntpath = optarg;
10600                                 some_file = strdup(optarg);
10601                         }
10602                         break;
10603                 default:
10604                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10605                                 progname, argv[optind - 1]);
10606                         fallthrough;
10607                 case 'h':
10608                         rc = CMD_HELP;
10609                         goto out_cmd_help;
10610                 }
10611         }
10612
10613         /* All remaining args are files, so we have at least nbfile */
10614         nbfile = argc - optind;
10615
10616         if ((nbfile == 0) && (!filelist)) {
10617                 rc = errno;
10618                 goto out_errno;
10619         }
10620
10621         if (opaque)
10622                 opaque_len = strlen(opaque);
10623
10624         /*
10625          * Alloc the request structure with enough place to store all files
10626          * from command line.
10627          */
10628         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
10629         if (!hur) {
10630                 fprintf(stderr, "Cannot create the request: %s\n",
10631                         strerror(errno));
10632                 rc = errno;
10633                 goto out_errno;
10634         }
10635         nbfile_alloc = nbfile;
10636
10637         hur->hur_request.hr_action = action;
10638         hur->hur_request.hr_archive_id = archive_id;
10639         hur->hur_request.hr_flags = 0;
10640
10641         /* All remaining args are files, add them */
10642         if (nbfile != 0 && some_file == NULL)
10643                 some_file = strdup(argv[optind]);
10644
10645         for (i = 0; i < nbfile; i++) {
10646                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
10647                                    &last_dev);
10648                 if (rc)
10649                         goto out_hur;
10650         }
10651
10652         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
10653
10654         /* If a filelist was specified, read the filelist from it. */
10655         if (filelist) {
10656                 fp = fopen(filelist, "r");
10657                 if (!fp) {
10658                         fprintf(stderr, "Cannot read the file list %s: %s\n",
10659                                 filelist, strerror(errno));
10660                         rc = -errno;
10661                         goto out_hur;
10662                 }
10663
10664                 while ((rc = getline(&line, &len, fp)) != -1) {
10665                         /*
10666                          * If allocated buffer was too small, get something
10667                          * larger
10668                          */
10669                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
10670                                 ssize_t size;
10671
10672                                 nbfile_alloc = nbfile_alloc * 2 + 1;
10673                                 oldhur = hur;
10674                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
10675                                                                    opaque_len);
10676                                 if (!hur) {
10677                                         fprintf(stderr,
10678                                                 "hsm: cannot allocate the request: %s\n",
10679                                                 strerror(errno));
10680                                         hur = oldhur;
10681                                         rc = -errno;
10682                                         fclose(fp);
10683                                         goto out_hur;
10684                                 }
10685                                 size = hur_len(oldhur);
10686                                 if (size < 0) {
10687                                         fprintf(stderr,
10688                                                 "hsm: cannot allocate %u files + %u bytes data\n",
10689                                                 oldhur->hur_request.hr_itemcount,
10690                                                 oldhur->hur_request.hr_data_len);
10691                                         free(hur);
10692                                         hur = oldhur;
10693                                         rc = -E2BIG;
10694                                         fclose(fp);
10695                                         goto out_hur;
10696                                 }
10697                                 memcpy(hur, oldhur, size);
10698                                 free(oldhur);
10699                         }
10700
10701                         /* Chop CR */
10702                         if (line[strlen(line) - 1] == '\n')
10703                                 line[strlen(line) - 1] = '\0';
10704
10705                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
10706                                            mntpath, line, &last_dev);
10707                         if (rc) {
10708                                 fclose(fp);
10709                                 goto out_hur;
10710                         }
10711
10712                         if (!some_file) {
10713                                 some_file = line;
10714                                 line = NULL;
10715                         }
10716                 }
10717
10718                 rc = fclose(fp);
10719                 free(line);
10720         }
10721
10722         /* If a --data was used, add it to the request */
10723         hur->hur_request.hr_data_len = opaque_len;
10724         if (opaque)
10725                 memcpy(hur_data(hur), opaque, opaque_len);
10726
10727         /* Send the HSM request */
10728         if (realpath(some_file, fullpath) == NULL) {
10729                 fprintf(stderr, "Could not find path '%s': %s\n",
10730                         some_file, strerror(errno));
10731         }
10732         rc = llapi_hsm_request(fullpath, hur);
10733         if (rc)
10734                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
10735                         some_file, strerror(-rc));
10736
10737 out_hur:
10738         free(hur);
10739 out_errno:
10740         free(some_file);
10741 out_cmd_help:
10742         return rc;
10743 }
10744
10745 static int lfs_hsm_archive(int argc, char **argv)
10746 {
10747         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
10748 }
10749
10750 static int lfs_hsm_restore(int argc, char **argv)
10751 {
10752         return lfs_hsm_request(argc, argv, HUA_RESTORE);
10753 }
10754
10755 static int lfs_hsm_release(int argc, char **argv)
10756 {
10757         return lfs_hsm_request(argc, argv, HUA_RELEASE);
10758 }
10759
10760 static int lfs_hsm_remove(int argc, char **argv)
10761 {
10762         return lfs_hsm_request(argc, argv, HUA_REMOVE);
10763 }
10764
10765 static int lfs_hsm_cancel(int argc, char **argv)
10766 {
10767         return lfs_hsm_request(argc, argv, HUA_CANCEL);
10768 }
10769
10770 static int lfs_swap_layouts(int argc, char **argv)
10771 {
10772         if (argc != 3)
10773                 return CMD_HELP;
10774
10775         return llapi_swap_layouts(argv[1], argv[2], 0, 0,
10776                                   SWAP_LAYOUTS_KEEP_MTIME |
10777                                   SWAP_LAYOUTS_KEEP_ATIME);
10778 }
10779
10780 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
10781
10782 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
10783
10784 int lfs_get_mode(const char *string)
10785 {
10786         enum lock_mode_user mode;
10787
10788         for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
10789                 if (lock_mode_names[mode] == NULL)
10790                         continue;
10791                 if (strcasecmp(string, lock_mode_names[mode]) == 0)
10792                         return mode;
10793         }
10794
10795         return -EINVAL;
10796 }
10797
10798 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
10799 {
10800         enum lu_ladvise_type advice;
10801
10802         for (advice = 0;
10803              advice < ARRAY_SIZE(ladvise_names); advice++) {
10804                 if (ladvise_names[advice] == NULL)
10805                         continue;
10806                 if (strcmp(string, ladvise_names[advice]) == 0)
10807                         return advice;
10808         }
10809
10810         return LU_LADVISE_INVALID;
10811 }
10812
10813 static int lfs_ladvise(int argc, char **argv)
10814 {
10815         struct option long_opts[] = {
10816         { .val = 'a',   .name = "advice",       .has_arg = required_argument },
10817         { .val = 'b',   .name = "background",   .has_arg = no_argument },
10818         { .val = 'e',   .name = "end",          .has_arg = required_argument },
10819         { .val = 'h',   .name = "help",         .has_arg = no_argument },
10820         { .val = 'l',   .name = "length",       .has_arg = required_argument },
10821         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
10822         { .val = 's',   .name = "start",        .has_arg = required_argument },
10823         { .val = 'u',   .name = "unset",        .has_arg = no_argument },
10824         { .name = NULL } };
10825         struct llapi_lu_ladvise advice;
10826         enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
10827         unsigned long long start = 0;
10828         unsigned long long end = LUSTRE_EOF;
10829         unsigned long long length = 0;
10830         unsigned long long size_units;
10831         unsigned long long flags = 0;
10832         int c, fd, rc = 0;
10833         const char *path;
10834         int mode = 0;
10835
10836         optind = 0;
10837         while ((c = getopt_long(argc, argv, "a:be:hl:m:s:u",
10838                                 long_opts, NULL)) != -1) {
10839                 switch (c) {
10840                 case 'a':
10841                         advice_type = lfs_get_ladvice(optarg);
10842                         if (advice_type == LU_LADVISE_INVALID) {
10843                                 fprintf(stderr,
10844                                         "%s: invalid advice type '%s'\n",
10845                                         progname, optarg);
10846                                 fprintf(stderr, "Valid types:");
10847
10848                                 for (advice_type = 0;
10849                                      advice_type < ARRAY_SIZE(ladvise_names);
10850                                      advice_type++) {
10851                                         if (ladvise_names[advice_type] == NULL)
10852                                                 continue;
10853                                         fprintf(stderr, " %s",
10854                                                 ladvise_names[advice_type]);
10855                                 }
10856                                 fprintf(stderr, "\n");
10857
10858                                 return CMD_HELP;
10859                         }
10860                         break;
10861                 case 'b':
10862                         flags |= LF_ASYNC;
10863                         break;
10864                 case 'u':
10865                         flags |= LF_UNSET;
10866                         break;
10867                 case 'e':
10868                         size_units = 1;
10869                         rc = llapi_parse_size(optarg, &end,
10870                                               &size_units, 0);
10871                         if (rc) {
10872                                 fprintf(stderr, "%s: bad end offset '%s'\n",
10873                                         argv[0], optarg);
10874                                 return CMD_HELP;
10875                         }
10876                         break;
10877                 case 's':
10878                         size_units = 1;
10879                         rc = llapi_parse_size(optarg, &start,
10880                                               &size_units, 0);
10881                         if (rc) {
10882                                 fprintf(stderr,
10883                                         "%s: bad start offset '%s'\n",
10884                                         argv[0], optarg);
10885                                 return CMD_HELP;
10886                         }
10887                         break;
10888                 case 'l':
10889                         size_units = 1;
10890                         rc = llapi_parse_size(optarg, &length,
10891                                               &size_units, 0);
10892                         if (rc) {
10893                                 fprintf(stderr, "%s: bad length '%s'\n",
10894                                         argv[0], optarg);
10895                                 return CMD_HELP;
10896                         }
10897                         break;
10898                 case 'm':
10899                         mode = lfs_get_mode(optarg);
10900                         if (mode < 0) {
10901                                 fprintf(stderr,
10902                                         "%s: bad mode '%s', valid modes are READ or WRITE\n",
10903                                         argv[0], optarg);
10904                                 return CMD_HELP;
10905                         }
10906                         break;
10907                 default:
10908                         fprintf(stderr, "%s: unrecognized option '%s'\n",
10909                                 progname, argv[optind - 1]);
10910                         fallthrough;
10911                 case 'h':
10912                         return CMD_HELP;
10913                 }
10914         }
10915
10916         if (advice_type == LU_LADVISE_INVALID) {
10917                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
10918                 fprintf(stderr, "Valid types:");
10919                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
10920                      advice_type++) {
10921                         if (ladvise_names[advice_type] == NULL)
10922                                 continue;
10923                         fprintf(stderr, " %s", ladvise_names[advice_type]);
10924                 }
10925                 fprintf(stderr, "\n");
10926                 return CMD_HELP;
10927         }
10928
10929         if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
10930                 fprintf(stderr,
10931                         "%s: Lock no expand advice is a per file descriptor advice, so when called from lfs, it does nothing.\n",
10932                         argv[0]);
10933                 return CMD_HELP;
10934         }
10935
10936         if (argc <= optind) {
10937                 fprintf(stderr, "%s: please give one or more file names\n",
10938                         argv[0]);
10939                 return CMD_HELP;
10940         }
10941
10942         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
10943                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
10944                         argv[0]);
10945                 return CMD_HELP;
10946         }
10947
10948         if (end == LUSTRE_EOF && length != 0)
10949                 end = start + length;
10950
10951         if (end <= start) {
10952                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
10953                         argv[0], start, end);
10954                 return CMD_HELP;
10955         }
10956
10957         if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
10958                 fprintf(stderr, "%s: mode is only valid with lockahead\n",
10959                         argv[0]);
10960                 return CMD_HELP;
10961         }
10962
10963         if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
10964                 fprintf(stderr, "%s: mode is required with lockahead\n",
10965                         argv[0]);
10966                 return CMD_HELP;
10967         }
10968
10969         while (optind < argc) {
10970                 int rc2;
10971
10972                 path = argv[optind++];
10973
10974                 fd = open(path, O_RDONLY);
10975                 if (fd < 0) {
10976                         rc2 = -errno;
10977                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
10978                                 argv[0], path, strerror(-rc2));
10979                         if (!rc)
10980                                 rc = rc2;
10981                         continue;
10982                 }
10983
10984                 advice.lla_start = start;
10985                 advice.lla_end = end;
10986                 advice.lla_advice = advice_type;
10987                 advice.lla_value1 = 0;
10988                 advice.lla_value2 = 0;
10989                 advice.lla_value3 = 0;
10990                 advice.lla_value4 = 0;
10991                 if (advice_type == LU_LADVISE_LOCKAHEAD) {
10992                         advice.lla_lockahead_mode = mode;
10993                         advice.lla_peradvice_flags = flags;
10994                 }
10995
10996                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
10997                 close(fd);
10998                 if (rc2 < 0) {
10999                         fprintf(stderr,
11000                                 "%s: cannot give advice '%s' to file '%s': %s\n",
11001                                 argv[0], ladvise_names[advice_type],
11002                                 path, strerror(errno));
11003
11004                         if (!rc)
11005                                 rc = rc2;
11006                         continue;
11007                 }
11008         }
11009
11010         return rc;
11011 }
11012
11013 static const char *const heat_names[] = LU_HEAT_NAMES;
11014
11015 static int lfs_heat_get(int argc, char **argv)
11016 {
11017         struct lu_heat *heat;
11018         int rc = 0, rc2;
11019         char *path;
11020         int fd;
11021         int i;
11022
11023         if (argc <= 1)
11024                 return CMD_HELP;
11025
11026         heat = calloc(sizeof(*heat) + sizeof(__u64) * OBD_HEAT_COUNT, 1);
11027         if (!heat) {
11028                 fprintf(stderr, "%s: memory allocation failed\n", argv[0]);
11029                 return -ENOMEM;
11030         }
11031
11032         optind = 1;
11033         while (optind < argc) {
11034                 path = argv[optind++];
11035
11036                 fd = open(path, O_RDONLY);
11037                 if (fd < 0) {
11038                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
11039                                 argv[0], path, strerror(errno));
11040                         rc2 = -errno;
11041                         goto next;
11042                 }
11043
11044                 heat->lh_count = OBD_HEAT_COUNT;
11045                 rc2 = llapi_heat_get(fd, heat);
11046                 close(fd);
11047                 if (rc2 < 0) {
11048                         fprintf(stderr,
11049                                 "%s: cannot get heat of file '%s': %s\n",
11050                                 argv[0], path, strerror(errno));
11051                         goto next;
11052                 }
11053
11054                 printf("flags: %x\n", heat->lh_flags);
11055                 for (i = 0; i < heat->lh_count; i++)
11056                         printf("%s: %llu\n", heat_names[i],
11057                                (unsigned long long)heat->lh_heat[i]);
11058 next:
11059                 if (rc == 0 && rc2 < 0)
11060                         rc = rc2;
11061         }
11062
11063         free(heat);
11064         return rc;
11065 }
11066
11067 static int lfs_heat_set(int argc, char **argv)
11068 {
11069         struct option long_opts[] = {
11070         { .val = 'c',   .name = "clear",        .has_arg = no_argument },
11071         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11072         { .val = 'o',   .name = "off",          .has_arg = no_argument },
11073         { .val = 'O',   .name = "on",           .has_arg = no_argument },
11074         { .name = NULL } };
11075         enum lu_heat_flag flags = 0;
11076         int rc = 0, rc2;
11077         char *path;
11078         int fd;
11079         int c;
11080
11081         if (argc <= 1)
11082                 return CMD_HELP;
11083
11084         optind = 0;
11085         while ((c = getopt_long(argc, argv, "choO", long_opts, NULL)) != -1) {
11086                 switch (c) {
11087                 case 'c':
11088                         flags |= LU_HEAT_FLAG_CLEAR;
11089                         break;
11090                 case 'o':
11091                         flags |= LU_HEAT_FLAG_CLEAR;
11092                         flags |= LU_HEAT_FLAG_OFF;
11093                         break;
11094                 case 'O':
11095                         flags &= ~LU_HEAT_FLAG_OFF;
11096                         break;
11097                 default:
11098                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11099                                 progname, argv[optind - 1]);
11100                         fallthrough;
11101                 case 'h':
11102                         return CMD_HELP;
11103                 }
11104         }
11105
11106         if (argc <= optind) {
11107                 fprintf(stderr, "%s: please give one or more file names\n",
11108                         argv[0]);
11109                 return CMD_HELP;
11110         }
11111
11112         while (optind < argc) {
11113                 path = argv[optind++];
11114
11115                 fd = open(path, O_RDONLY);
11116                 if (fd < 0) {
11117                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
11118                                 argv[0], path, strerror(errno));
11119                         rc2 = -errno;
11120                         goto next;
11121                 }
11122
11123                 rc2 = llapi_heat_set(fd, flags);
11124                 close(fd);
11125                 if (rc2 < 0) {
11126                         fprintf(stderr,
11127                                 "%s: cannot setflags heat of file '%s': %s\n",
11128                                 argv[0], path, strerror(errno));
11129                         goto next;
11130                 }
11131 next:
11132                 if (rc == 0 && rc2 < 0)
11133                         rc = rc2;
11134         }
11135         return rc;
11136 }
11137
11138 /**
11139  * The input string contains a comma delimited list of component ids and
11140  * ranges, for example "1,2-4,7".
11141  */
11142 static int parse_mirror_ids(__u16 *ids, int size, char *arg)
11143 {
11144         bool end_of_loop = false;
11145         char *ptr = NULL;
11146         int nr = 0;
11147         int rc;
11148
11149         if (!arg)
11150                 return -EINVAL;
11151
11152         while (!end_of_loop) {
11153                 int start_index;
11154                 int end_index;
11155                 int i;
11156                 char *endptr = NULL;
11157
11158                 rc = -EINVAL;
11159                 ptr = strchrnul(arg, ',');
11160                 end_of_loop = *ptr == '\0';
11161                 *ptr = '\0';
11162
11163                 start_index = strtol(arg, &endptr, 0);
11164                 if (endptr == arg) /* no data at all */
11165                         break;
11166                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
11167                         break;
11168                 if (start_index < 0)
11169                         break;
11170
11171                 end_index = start_index;
11172                 if (*endptr == '-') {
11173                         end_index = strtol(endptr + 1, &endptr, 0);
11174                         if (*endptr != '\0')
11175                                 break;
11176                         if (end_index < start_index)
11177                                 break;
11178                 }
11179
11180                 for (i = start_index; i <= end_index && size > 0; i++) {
11181                         int j;
11182
11183                         /* remove duplicate */
11184                         for (j = 0; j < nr; j++) {
11185                                 if (ids[j] == i)
11186                                         break;
11187                         }
11188                         if (j == nr) { /* no duplicate */
11189                                 ids[nr++] = i;
11190                                 --size;
11191                         }
11192                 }
11193
11194                 if (size == 0 && i < end_index)
11195                         break;
11196
11197                 *ptr = ',';
11198                 arg = ++ptr;
11199                 rc = 0;
11200         }
11201         if (!end_of_loop && ptr)
11202                 *ptr = ',';
11203
11204         return rc < 0 ? rc : nr;
11205 }
11206
11207 /**
11208  * struct verify_mirror_id - Mirror id to be verified.
11209  * @mirror_id:   A specified mirror id.
11210  * @is_valid_id: @mirror_id is valid or not in the mirrored file.
11211  */
11212 struct verify_mirror_id {
11213         __u16 mirror_id;
11214         bool is_valid_id;
11215 };
11216
11217 /**
11218  * compare_mirror_ids() - Compare mirror ids.
11219  * @layout: Mirror component list.
11220  * @cbdata: Callback data in verify_mirror_id structure.
11221  *
11222  * This is a callback function called by llapi_layout_comp_iterate()
11223  * to compare the specified mirror id with the one in the current
11224  * component of @layout. If they are the same, then the specified
11225  * mirror id is valid.
11226  *
11227  * Return: a negative error code on failure or
11228  *         LLAPI_LAYOUT_ITER_CONT: Proceed iteration
11229  *         LLAPI_LAYOUT_ITER_STOP: Stop iteration
11230  */
11231 static inline
11232 int compare_mirror_ids(struct llapi_layout *layout, void *cbdata)
11233 {
11234         struct verify_mirror_id *mirror_id_cbdata =
11235                                  (struct verify_mirror_id *)cbdata;
11236         uint32_t mirror_id;
11237         int rc = 0;
11238
11239         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
11240         if (rc < 0) {
11241                 rc = -errno;
11242                 fprintf(stderr,
11243                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
11244                         progname, strerror(errno));
11245                 return rc;
11246         }
11247
11248         if (mirror_id_cbdata->mirror_id == mirror_id) {
11249                 mirror_id_cbdata->is_valid_id = true;
11250                 return LLAPI_LAYOUT_ITER_STOP;
11251         }
11252
11253         return LLAPI_LAYOUT_ITER_CONT;
11254 }
11255
11256 /**
11257  * verify_mirror_ids() - Verify specified mirror ids.
11258  * @fname:      Mirrored file name.
11259  * @mirror_ids: Specified mirror ids to be verified.
11260  * @ids_nr:     Number of specified mirror ids.
11261  *
11262  * This function verifies that specified @mirror_ids are valid
11263  * in the mirrored file @fname.
11264  *
11265  * Return: 0 on success or a negative error code on failure.
11266  */
11267 static inline
11268 int verify_mirror_ids(const char *fname, __u16 *mirror_ids, int ids_nr)
11269 {
11270         struct llapi_layout *layout = NULL;
11271         struct verify_mirror_id mirror_id_cbdata = { 0 };
11272         struct stat stbuf;
11273         uint32_t flr_state;
11274         int i;
11275         int fd;
11276         int rc = 0;
11277         int rc2 = 0;
11278
11279         if (ids_nr <= 0)
11280                 return -EINVAL;
11281
11282         if (stat(fname, &stbuf) < 0) {
11283                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
11284                         progname, fname, strerror(errno));
11285                 rc = -errno;
11286                 goto error;
11287         }
11288
11289         if (!S_ISREG(stbuf.st_mode)) {
11290                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
11291                         progname, fname);
11292                 rc = -EINVAL;
11293                 goto error;
11294         }
11295
11296         fd = open(fname, O_DIRECT | O_RDONLY);
11297         if (fd < 0) {
11298                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
11299                         progname, fname, strerror(errno));
11300                 rc = -errno;
11301                 goto error;
11302         }
11303
11304         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
11305         if (rc < 0) {
11306                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
11307                         progname, fname, strerror(errno));
11308                 goto close_fd;
11309         }
11310
11311         layout = llapi_layout_get_by_fd(fd, 0);
11312         if (!layout) {
11313                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
11314                         progname, fname, strerror(errno));
11315                 rc = -errno;
11316                 llapi_lease_release(fd);
11317                 goto close_fd;
11318         }
11319
11320         rc = llapi_layout_flags_get(layout, &flr_state);
11321         if (rc < 0) {
11322                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
11323                         progname, fname, strerror(errno));
11324                 rc = -errno;
11325                 goto free_layout;
11326         }
11327
11328         flr_state &= LCM_FL_FLR_MASK;
11329         switch (flr_state) {
11330         case LCM_FL_NONE:
11331                 rc = -EINVAL;
11332                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
11333                         progname, fname, llapi_layout_flags_string(flr_state));
11334                 goto free_layout;
11335         default:
11336                 break;
11337         }
11338
11339         rc2 = 0;
11340         for (i = 0; i < ids_nr; i++) {
11341                 mirror_id_cbdata.mirror_id = mirror_ids[i];
11342                 mirror_id_cbdata.is_valid_id = false;
11343
11344                 rc = llapi_layout_comp_iterate(layout, compare_mirror_ids,
11345                                                &mirror_id_cbdata);
11346                 if (rc < 0) {
11347                         rc = -errno;
11348                         fprintf(stderr,
11349                                 "%s: '%s' failed to verify mirror id: %u.\n",
11350                                 progname, fname, mirror_ids[i]);
11351                         goto free_layout;
11352                 }
11353
11354                 if (!mirror_id_cbdata.is_valid_id) {
11355                         rc2 = -EINVAL;
11356                         fprintf(stderr,
11357                                 "%s: '%s' invalid specified mirror id: %u.\n",
11358                                 progname, fname, mirror_ids[i]);
11359                 }
11360         }
11361         rc = rc2;
11362
11363 free_layout:
11364         llapi_layout_free(layout);
11365         llapi_lease_release(fd);
11366 close_fd:
11367         close(fd);
11368 error:
11369         return rc;
11370 }
11371
11372 static inline
11373 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
11374                            __u16 *mirror_ids, int ids_nr,
11375                            long stats_interval_sec, long bandwidth_bytes_sec)
11376 {
11377         struct llapi_resync_comp comp_array[1024] = { { 0 } };
11378         struct llapi_layout *layout;
11379         struct stat stbuf;
11380         uint32_t flr_state;
11381         uint64_t start;
11382         uint64_t end;
11383         int comp_size = 0;
11384         int idx;
11385         int fd;
11386         int rc;
11387         int rc2;
11388
11389         if (stat(fname, &stbuf) < 0) {
11390                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
11391                         progname, fname, strerror(errno));
11392                 rc = -errno;
11393                 goto error;
11394         }
11395         if (!S_ISREG(stbuf.st_mode)) {
11396                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
11397                         progname, fname);
11398                 rc = -EINVAL;
11399                 goto error;
11400         }
11401
11402         /* Allow mirror resync even without the key on encrypted files */
11403         fd = open(fname, O_DIRECT | O_RDWR | O_CIPHERTEXT);
11404         if (fd < 0) {
11405                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
11406                         progname, fname, strerror(errno));
11407                 rc = -errno;
11408                 goto error;
11409         }
11410
11411         layout = llapi_layout_get_by_fd(fd, 0);
11412         if (!layout) {
11413                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
11414                         progname, fname, strerror(errno));
11415                 rc = -errno;
11416                 goto close_fd;
11417         }
11418
11419         rc = llapi_layout_flags_get(layout, &flr_state);
11420         if (rc) {
11421                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
11422                         progname, fname, strerror(errno));
11423                 rc = -errno;
11424                 goto free_layout;
11425         }
11426
11427         flr_state &= LCM_FL_FLR_MASK;
11428         if (flr_state == LCM_FL_NONE) {
11429                 rc = -EINVAL;
11430                 fprintf(stderr, "%s: '%s' is not a FLR file.\n",
11431                         progname, fname);
11432                 goto free_layout;
11433         }
11434
11435         /* get stale component info */
11436         comp_size = llapi_mirror_find_stale(layout, comp_array,
11437                                             ARRAY_SIZE(comp_array),
11438                                             mirror_ids, ids_nr);
11439         if (comp_size <= 0) {
11440                 rc = comp_size;
11441                 goto free_layout;
11442         }
11443
11444         ioc->lil_mode = LL_LEASE_WRLCK;
11445         ioc->lil_flags = LL_LEASE_RESYNC;
11446         rc = llapi_lease_set(fd, ioc);
11447         if (rc < 0) {
11448                 if (rc == -EALREADY)
11449                         rc = 0;
11450                 else
11451                         fprintf(stderr,
11452                             "%s: '%s' llapi_lease_get_ext resync failed: %s.\n",
11453                                 progname, fname, strerror(-rc));
11454                 goto free_layout;
11455         }
11456
11457         /* get the read range [start, end) */
11458         start = comp_array[0].lrc_start;
11459         end = comp_array[0].lrc_end;
11460         for (idx = 1; idx < comp_size; idx++) {
11461                 if (comp_array[idx].lrc_start < start)
11462                         start = comp_array[idx].lrc_start;
11463                 if (end < comp_array[idx].lrc_end)
11464                         end = comp_array[idx].lrc_end;
11465         }
11466
11467         rc = llapi_lease_check(fd);
11468         if (rc != LL_LEASE_WRLCK) {
11469                 fprintf(stderr, "%s: '%s' lost lease lock.\n",
11470                         progname, fname);
11471                 goto free_layout;
11472         }
11473
11474         rc = llapi_mirror_resync_many_params(fd, layout, comp_array, comp_size,
11475                                              start, end, stats_interval_sec,
11476                                              bandwidth_bytes_sec);
11477         if (rc < 0)
11478                 fprintf(stderr, "%s: '%s' llapi_mirror_resync_many: %s.\n",
11479                         progname, fname, strerror(-rc));
11480
11481         rc2 = migrate_set_timestamps(fd, &stbuf);
11482         if (rc2 < 0) {
11483                 fprintf(stderr, "%s: '%s' cannot set timestamps: %s\n",
11484                         progname, fname, strerror(-rc2));
11485                 if (!rc)
11486                         rc = rc2;
11487                 goto free_layout;
11488         }
11489
11490         /* need to do the lease unlock even resync fails */
11491         ioc->lil_mode = LL_LEASE_UNLCK;
11492         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
11493         ioc->lil_count = 0;
11494         for (idx = 0; idx < comp_size; idx++) {
11495                 if (comp_array[idx].lrc_synced) {
11496                         ioc->lil_ids[ioc->lil_count] = comp_array[idx].lrc_id;
11497                         ioc->lil_count++;
11498                 }
11499         }
11500
11501         rc2 = llapi_lease_set(fd, ioc);
11502         /**
11503          * llapi_lease_set returns lease mode when it request to unlock
11504          * the lease lock.
11505          */
11506         if (rc2 <= 0) {
11507                 /* rc2 == 0 means lost lease lock */
11508                 if (rc2 == 0 && rc == 0)
11509                         rc = -EBUSY;
11510                 else
11511                         rc = rc2;
11512                 fprintf(stderr, "%s: resync file '%s' failed: %s.\n",
11513                         progname, fname,
11514                         rc2 == 0 ? "lost lease lock" : strerror(-rc2));
11515
11516                 llapi_lease_release(fd);
11517                 goto free_layout;
11518         }
11519
11520 free_layout:
11521         llapi_layout_free(layout);
11522 close_fd:
11523         close(fd);
11524 error:
11525         return rc;
11526 }
11527
11528 static inline int lfs_mirror_resync(int argc, char **argv)
11529 {
11530         struct option long_opts[] = {
11531         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11532         { .val = 'o',   .name = "only",         .has_arg = required_argument },
11533         { .val = 'W',   .name = "bandwidth",    .has_arg = required_argument },
11534         { .val = LFS_STATS_OPT,
11535                         .name = "stats",        .has_arg = no_argument},
11536         { .val = LFS_STATS_INTERVAL_OPT,
11537                         .name = "stats-interval",
11538                                                 .has_arg = required_argument},
11539         { .name = NULL } };
11540         struct ll_ioc_lease *ioc = NULL;
11541         __u16 mirror_ids[128] = { 0 };
11542         unsigned int stats_interval_sec = 0;
11543         unsigned long long bandwidth_bytes_sec = 0;
11544         unsigned long long bandwidth_unit = ONE_MB;
11545         int ids_nr = 0;
11546         int c;
11547         int rc = 0;
11548
11549         while ((c = getopt_long(argc, argv, "ho:W:", long_opts, NULL)) >= 0) {
11550                 char *end;
11551                 switch (c) {
11552                 case 'o':
11553                         rc = parse_mirror_ids(mirror_ids,
11554                                         sizeof(mirror_ids) / sizeof(__u16),
11555                                         optarg);
11556                         if (rc < 0) {
11557                                 fprintf(stderr,
11558                                         "%s: bad mirror ids '%s'.\n",
11559                                         argv[0], optarg);
11560                                 goto error;
11561                         }
11562                         ids_nr = rc;
11563                         break;
11564                 case 'W':
11565                         if (llapi_parse_size(optarg, &bandwidth_bytes_sec,
11566                                              &bandwidth_unit, 0) < 0) {
11567                                 fprintf(stderr,
11568                                         "error: %s: bad value for bandwidth '%s'\n",
11569                                         argv[0], optarg);
11570                                 goto error;
11571                         }
11572                         break;
11573                 case LFS_STATS_OPT:
11574                         stats_interval_sec = 5;
11575                         break;
11576                 case LFS_STATS_INTERVAL_OPT:
11577                         stats_interval_sec = strtol(optarg, &end, 0);
11578                         break;
11579                 default:
11580                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11581                                 progname, argv[optind - 1]);
11582                         fallthrough;
11583                 case 'h':
11584                         rc = CMD_HELP;
11585                         goto error;
11586                 }
11587         }
11588
11589         if (argc == optind) {
11590                 fprintf(stderr, "%s: no file name given.\n", argv[0]);
11591                 rc = CMD_HELP;
11592                 goto error;
11593         }
11594
11595         if (ids_nr > 0 && argc > optind + 1) {
11596                 fprintf(stderr,
11597                     "%s: option '--only' cannot be used upon multiple files.\n",
11598                         argv[0]);
11599                 rc = CMD_HELP;
11600                 goto error;
11601         }
11602
11603         if (ids_nr > 0) {
11604                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
11605                 if (rc < 0)
11606                         goto error;
11607         }
11608
11609         /* set the lease on the file */
11610         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
11611         if (!ioc) {
11612                 fprintf(stderr, "%s: cannot alloc id array for ioc: %s.\n",
11613                         argv[0], strerror(errno));
11614                 rc = -errno;
11615                 goto error;
11616         }
11617
11618         for (; optind < argc; optind++) {
11619                 rc = lfs_mirror_resync_file(argv[optind], ioc,
11620                                             mirror_ids, ids_nr,
11621                                             stats_interval_sec,
11622                                             bandwidth_bytes_sec);
11623                 /* ignore previous file's error, continue with next file */
11624
11625                 /* reset ioc */
11626                 memset(ioc, 0, sizeof(*ioc) + sizeof(__u32) * 4096);
11627         }
11628
11629         free(ioc);
11630 error:
11631         return rc;
11632 }
11633
11634 static inline int verify_mirror_id_by_fd(int fd, __u16 mirror_id)
11635 {
11636         struct llapi_layout *layout;
11637         int rc;
11638
11639         layout = llapi_layout_get_by_fd(fd, 0);
11640         if (!layout) {
11641                 fprintf(stderr, "could not get layout.\n");
11642                 return  -EINVAL;
11643         }
11644
11645         rc = llapi_layout_comp_iterate(layout, find_mirror_id, &mirror_id);
11646         if (rc < 0) {
11647                 fprintf(stderr, "failed to iterate layout\n");
11648                 llapi_layout_free(layout);
11649
11650                 return rc;
11651         } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
11652                 fprintf(stderr, "does not find mirror with ID %u\n", mirror_id);
11653                 llapi_layout_free(layout);
11654
11655                 return -EINVAL;
11656         }
11657         llapi_layout_free(layout);
11658
11659         return 0;
11660 }
11661
11662 /**
11663  * Check whether two files are the same file
11664  * \retval      0  same file
11665  * \retval      1  not the same file
11666  * \retval      <0 error code
11667  */
11668 static inline int check_same_file(int fd, const char *f2)
11669 {
11670         struct stat stbuf1;
11671         struct stat stbuf2;
11672
11673         if (fstat(fd, &stbuf1) < 0)
11674                 return -errno;
11675
11676         if (stat(f2, &stbuf2) < 0)
11677                 return 1;
11678
11679         if (stbuf1.st_rdev == stbuf2.st_rdev &&
11680             stbuf1.st_ino == stbuf2.st_ino)
11681                 return 0;
11682
11683         return 1;
11684 }
11685
11686 static inline int lfs_mirror_read(int argc, char **argv)
11687 {
11688         int rc = CMD_HELP;
11689         __u16 mirror_id = 0;
11690         const char *outfile = NULL;
11691         char *fname;
11692         int fd = 0;
11693         int outfd;
11694         int c;
11695         void *buf;
11696         const size_t buflen = 4 << 20;
11697         off_t pos;
11698         struct option long_opts[] = {
11699         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11700         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
11701         { .val = 'o',   .name = "outfile",      .has_arg = required_argument },
11702         { .name = NULL } };
11703
11704         while ((c = getopt_long(argc, argv, "hN:o:", long_opts, NULL)) >= 0) {
11705                 char *end;
11706
11707                 switch (c) {
11708                 case 'N': {
11709                         unsigned long int id;
11710
11711                         errno = 0;
11712                         id = strtoul(optarg, &end, 0);
11713                         if (errno != 0 || *end != '\0' || id == 0 ||
11714                             id > UINT16_MAX) {
11715                                 fprintf(stderr,
11716                                         "%s %s: invalid mirror ID '%s'\n",
11717                                         progname, argv[0], optarg);
11718                                 return rc;
11719                         }
11720
11721                         mirror_id = (__u16)id;
11722                         break;
11723                 }
11724                 case 'o':
11725                         outfile = optarg;
11726                         break;
11727                 default:
11728                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11729                                 progname, argv[optind - 1]);
11730                         fallthrough;
11731                 case 'h':
11732                         return CMD_HELP;
11733                 }
11734         }
11735
11736         if (argc == optind) {
11737                 fprintf(stderr, "%s %s: no mirrored file provided\n",
11738                         progname, argv[0]);
11739                 return rc;
11740         } else if (argc > optind + 1) {
11741                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
11742                 return rc;
11743         }
11744
11745         if (mirror_id == 0) {
11746                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
11747                         progname, argv[0]);
11748                 return rc;
11749         }
11750
11751         /* open mirror file */
11752         fname = argv[optind];
11753         fd = open(fname, O_DIRECT | O_RDONLY);
11754         if (fd < 0) {
11755                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
11756                         progname, argv[0], fname, strerror(errno));
11757                 return rc;
11758         }
11759
11760         /* verify mirror id */
11761         rc = verify_mirror_id_by_fd(fd, mirror_id);
11762         if (rc) {
11763                 fprintf(stderr,
11764                         "%s %s: cannot find mirror with ID %u in '%s'\n",
11765                         progname, argv[0], mirror_id, fname);
11766                 goto close_fd;
11767         }
11768
11769         /* open output file - O_EXCL ensures output is not the same as input */
11770         if (outfile) {
11771                 outfd = open(outfile, O_EXCL | O_WRONLY | O_CREAT, 0644);
11772                 if (outfd < 0) {
11773                         fprintf(stderr, "%s %s: cannot create file '%s': %s\n",
11774                                 progname, argv[0], outfile, strerror(errno));
11775                         rc = -errno;
11776                         goto close_fd;
11777                 }
11778         } else {
11779                 outfd = STDOUT_FILENO;
11780         }
11781
11782         /* allocate buffer */
11783         rc = posix_memalign(&buf, sysconf(_SC_PAGESIZE), buflen);
11784         if (rc) {
11785                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
11786                                 progname, argv[0], rc);
11787                 goto close_outfd;
11788         }
11789
11790         pos = 0;
11791         while (1) {
11792                 ssize_t bytes_read;
11793                 ssize_t written = 0;
11794
11795                 bytes_read = llapi_mirror_read(fd, mirror_id, buf, buflen, pos);
11796                 if (bytes_read < 0) {
11797                         rc = bytes_read;
11798                         fprintf(stderr,
11799                                 "%s %s: fail to read data from mirror %u: %s\n",
11800                                 progname, argv[0], mirror_id, strerror(-rc));
11801                         goto free_buf;
11802                 }
11803
11804                 /* EOF reached */
11805                 if (bytes_read == 0)
11806                         break;
11807
11808                 while (written < bytes_read) {
11809                         ssize_t written2;
11810
11811                         written2 = write(outfd, buf + written,
11812                                          bytes_read - written);
11813                         if (written2 < 0) {
11814                                 fprintf(stderr,
11815                                         "%s %s: fail to write %s: %s\n",
11816                                         progname, argv[0], outfile ? : "STDOUT",
11817                                         strerror(errno));
11818                                 rc = -errno;
11819                                 goto free_buf;
11820                         }
11821                         written += written2;
11822                 }
11823
11824                 if (written != bytes_read) {
11825                         fprintf(stderr,
11826                 "%s %s: written %ld bytes does not match with %ld read.\n",
11827                                 progname, argv[0], written, bytes_read);
11828                         rc = -EIO;
11829                         goto free_buf;
11830                 }
11831
11832                 pos += bytes_read;
11833         }
11834
11835         fsync(outfd);
11836         rc = 0;
11837
11838 free_buf:
11839         free(buf);
11840 close_outfd:
11841         if (outfile)
11842                 close(outfd);
11843 close_fd:
11844         close(fd);
11845
11846         return rc;
11847 }
11848
11849 static inline int lfs_mirror_write(int argc, char **argv)
11850 {
11851         int rc = CMD_HELP;
11852         __u16 mirror_id = 0;
11853         const char *inputfile = NULL;
11854         char *fname;
11855         int fd = 0;
11856         int inputfd;
11857         int c;
11858         void *buf;
11859         const size_t buflen = 4 << 20;
11860         off_t pos;
11861         size_t page_size = sysconf(_SC_PAGESIZE);
11862         struct ll_ioc_lease_id ioc;
11863         struct option long_opts[] = {
11864         { .val = 'h',   .name = "help",         .has_arg = no_argument },
11865         { .val = 'i',   .name = "inputfile",    .has_arg = required_argument },
11866         { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
11867         { .name = NULL } };
11868
11869         while ((c = getopt_long(argc, argv, "hi:N:", long_opts, NULL)) >= 0) {
11870                 char *end;
11871
11872                 switch (c) {
11873                 case 'N': {
11874                         unsigned long int id;
11875
11876                         errno = 0;
11877                         id = strtoul(optarg, &end, 0);
11878                         if (errno != 0 || *end != '\0' || id == 0 ||
11879                             id > UINT16_MAX) {
11880                                 fprintf(stderr,
11881                                         "%s %s: invalid mirror ID '%s'\n",
11882                                         progname, argv[0], optarg);
11883                                 return rc;
11884                         }
11885
11886                         mirror_id = (__u16)id;
11887                         break;
11888                 }
11889                 case 'i':
11890                         inputfile = optarg;
11891                         break;
11892                 default:
11893                         fprintf(stderr, "%s: unrecognized option '%s'\n",
11894                                 progname, argv[optind - 1]);
11895                         fallthrough;
11896                 case 'h':
11897                         return CMD_HELP;
11898                 }
11899         }
11900
11901         if (argc == optind) {
11902                 fprintf(stderr, "%s %s: no mirrored file provided\n",
11903                         progname, argv[0]);
11904                 return rc;
11905         } else if (argc > optind + 1) {
11906                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
11907                 return rc;
11908         }
11909
11910         if (mirror_id == 0) {
11911                 fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
11912                         progname, argv[0]);
11913                 return rc;
11914         }
11915
11916         /* open mirror file */
11917         fname = argv[optind];
11918         fd = open(fname, O_DIRECT | O_WRONLY);
11919         if (fd < 0) {
11920                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
11921                         progname, argv[0], fname, strerror(errno));
11922                 return rc;
11923         }
11924
11925         /* verify mirror id */
11926         rc = verify_mirror_id_by_fd(fd, mirror_id);
11927         if (rc) {
11928                 fprintf(stderr,
11929                         "%s %s: cannot find mirror with ID %u in '%s'\n",
11930                         progname, argv[0], mirror_id, fname);
11931                 goto close_fd;
11932         }
11933
11934         /* open input file */
11935         if (inputfile) {
11936                 rc = check_same_file(fd, inputfile);
11937                 if (rc == 0) {
11938                         fprintf(stderr,
11939                         "%s %s: input file cannot be the mirrored file '%s'\n",
11940                                 progname, argv[0], fname);
11941                         goto close_fd;
11942                 }
11943                 if (rc < 0)
11944                         goto close_fd;
11945
11946                 inputfd = open(inputfile, O_RDONLY, 0644);
11947                 if (inputfd < 0) {
11948                         fprintf(stderr, "%s %s: cannot open file '%s': %s\n",
11949                                 progname, argv[0], inputfile, strerror(errno));
11950                         rc = -errno;
11951                         goto close_fd;
11952                 }
11953         } else {
11954                 inputfd = STDIN_FILENO;
11955         }
11956
11957         /* allocate buffer */
11958         rc = posix_memalign(&buf, page_size, buflen);
11959         if (rc) {
11960                 fprintf(stderr, "%s %s: posix_memalign returns %d\n",
11961                         progname, argv[0], rc);
11962                 goto close_inputfd;
11963         }
11964
11965         /* prepare target mirror components instantiation */
11966         ioc.lil_mode = LL_LEASE_WRLCK;
11967         ioc.lil_flags = LL_LEASE_RESYNC;
11968         ioc.lil_mirror_id = mirror_id;
11969         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
11970         if (rc < 0) {
11971                 fprintf(stderr,
11972                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
11973                         progname, argv[0], fname, strerror(errno));
11974                 goto free_buf;
11975         }
11976
11977         pos = 0;
11978         while (1) {
11979                 ssize_t bytes_read;
11980                 ssize_t written;
11981                 size_t to_write;
11982
11983                 rc = llapi_lease_check(fd);
11984                 if (rc != LL_LEASE_WRLCK) {
11985                         fprintf(stderr, "%s %s: '%s' lost lease lock\n",
11986                                 progname, argv[0], fname);
11987                         goto free_buf;
11988                 }
11989
11990                 bytes_read = read(inputfd, buf, buflen);
11991                 if (bytes_read < 0) {
11992                         rc = bytes_read;
11993                         fprintf(stderr,
11994                                 "%s %s: fail to read data from '%s': %s\n",
11995                                 progname, argv[0], inputfile ? : "STDIN",
11996                                 strerror(errno));
11997                         rc = -errno;
11998                         goto free_buf;
11999                 }
12000
12001                 /* EOF reached */
12002                 if (bytes_read == 0)
12003                         break;
12004
12005                 /* round up to page align to make direct IO happy. */
12006                 to_write = (bytes_read + page_size - 1) & ~(page_size - 1);
12007
12008                 written = llapi_mirror_write(fd, mirror_id, buf, to_write,
12009                                              pos);
12010                 if (written < 0) {
12011                         rc = written;
12012                         fprintf(stderr,
12013                               "%s %s: fail to write to mirror %u: %s\n",
12014                                 progname, argv[0], mirror_id,
12015                                 strerror(-rc));
12016                         goto free_buf;
12017                 }
12018
12019                 pos += bytes_read;
12020         }
12021
12022         if (pos & (page_size - 1)) {
12023                 rc = llapi_mirror_truncate(fd, mirror_id, pos);
12024                 if (rc < 0)
12025                         goto free_buf;
12026         }
12027
12028         ioc.lil_mode = LL_LEASE_UNLCK;
12029         ioc.lil_flags = LL_LEASE_RESYNC_DONE;
12030         ioc.lil_count = 0;
12031         rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
12032         if (rc <= 0) {
12033                 if (rc == 0)
12034                         rc = -EBUSY;
12035                 fprintf(stderr,
12036                         "%s %s: release lease lock of '%s' failed: %s\n",
12037                         progname, argv[0], fname, strerror(-rc));
12038                 goto free_buf;
12039         }
12040
12041         rc = 0;
12042
12043 free_buf:
12044         free(buf);
12045 close_inputfd:
12046         if (inputfile)
12047                 close(inputfd);
12048 close_fd:
12049         close(fd);
12050
12051         return rc;
12052 }
12053
12054 static inline int get_other_mirror_ids(int fd, __u16 *ids, __u16 exclude_id)
12055 {
12056         struct llapi_layout *layout;
12057         struct collect_ids_data cid = { .cid_ids = ids,
12058                                         .cid_count = 0,
12059                                         .cid_exclude = exclude_id, };
12060         int rc;
12061
12062         layout = llapi_layout_get_by_fd(fd, 0);
12063         if (!layout) {
12064                 fprintf(stderr, "could not get layout\n");
12065                 return -EINVAL;
12066         }
12067
12068         rc = llapi_layout_comp_iterate(layout, collect_mirror_id, &cid);
12069         if (rc < 0) {
12070                 fprintf(stderr, "failed to iterate layout\n");
12071                 llapi_layout_free(layout);
12072
12073                 return rc;
12074         }
12075         llapi_layout_free(layout);
12076
12077         return cid.cid_count;
12078 }
12079
12080 #ifndef MIRROR_ID_NEG
12081 #define MIRROR_ID_NEG         0x8000
12082 #endif
12083
12084 static inline int lfs_mirror_copy(int argc, char **argv)
12085 {
12086         int rc = CMD_HELP;
12087         __u16 read_mirror_id = 0;
12088         __u16 ids[128] = { 0 };
12089         int count = 0;
12090         struct llapi_layout *layout = NULL;
12091         struct llapi_resync_comp comp_array[1024] = { { 0 } };
12092         int comp_size = 0;
12093         char *fname;
12094         int fd = 0;
12095         int c;
12096         int i;
12097         ssize_t copied;
12098         struct ll_ioc_lease *ioc = NULL;
12099         struct ll_ioc_lease_id *resync_ioc;
12100         struct option long_opts[] = {
12101         { .val = 'h',   .name = "help",         .has_arg = no_argument },
12102         { .val = 'i',   .name = "read-mirror",  .has_arg = required_argument },
12103         { .val = 'o',   .name = "write-mirror", .has_arg = required_argument },
12104         { .name = NULL } };
12105         char cmd[PATH_MAX];
12106
12107         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12108         progname = cmd;
12109         while ((c = getopt_long(argc, argv, "hi:o:", long_opts, NULL)) >= 0) {
12110                 char *end;
12111
12112                 switch (c) {
12113                 case 'i': {
12114                         unsigned long int id;
12115
12116                         errno = 0;
12117                         id = strtoul(optarg, &end, 0);
12118                         if (errno != 0 || *end != '\0' || id == 0 ||
12119                             id > UINT16_MAX) {
12120                                 fprintf(stderr,
12121                                         "%s: invalid read mirror ID '%s'\n",
12122                                         progname, optarg);
12123                                 return rc;
12124                         }
12125
12126                         read_mirror_id = (__u16)id;
12127                         break;
12128                 }
12129                 case 'o':
12130                         if (!strcmp(optarg, "-1")) {
12131                                 /* specify all other mirrors */
12132                                 ids[0] = (__u16)-1;
12133                                 count = 1;
12134                         } else {
12135                                 count = parse_mirror_ids((__u16 *)ids,
12136                                                          ARRAY_SIZE(ids),
12137                                                          optarg);
12138                                 if (count < 0)
12139                                         return rc;
12140                         }
12141                         break;
12142                 default:
12143                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12144                                 progname, argv[optind - 1]);
12145                         fallthrough;
12146                 case 'h':
12147                         return CMD_HELP;
12148                 }
12149         }
12150
12151         if (argc == optind) {
12152                 fprintf(stderr, "%s %s: no mirrored file provided\n",
12153                         progname, argv[0]);
12154                 return rc;
12155         } else if (argc > optind + 1) {
12156                 fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
12157                 return rc;
12158         }
12159
12160         if (read_mirror_id == 0) {
12161                 fprintf(stderr,
12162                         "%s %s: no valid read mirror ID %d is provided\n",
12163                         progname, argv[0], read_mirror_id);
12164                 return rc;
12165         }
12166
12167         if (count == 0) {
12168                 fprintf(stderr,
12169                         "%s %s: no write mirror ID is provided\n",
12170                         progname, argv[0]);
12171                 return rc;
12172         }
12173
12174         for (i = 0; i < count; i++) {
12175                 if (read_mirror_id == ids[i]) {
12176                         fprintf(stderr,
12177                         "%s %s: read and write mirror ID cannot be the same\n",
12178                                 progname, argv[0]);
12179                         return rc;
12180                 }
12181         }
12182
12183         /* open mirror file */
12184         fname = argv[optind];
12185
12186         fd = open(fname, O_DIRECT | O_RDWR);
12187         if (fd < 0) {
12188                 fprintf(stderr, "%s %s: cannot open '%s': %s\n",
12189                         progname, argv[0], fname, strerror(errno));
12190                 return rc;
12191         }
12192
12193         /* write to all other mirrors */
12194         if (ids[0] == (__u16)-1) {
12195                 count = get_other_mirror_ids(fd, ids, read_mirror_id);
12196                 if (count <= 0) {
12197                         rc = count;
12198                         fprintf(stderr,
12199                         "%s %s: failed to get other mirror ids in '%s': %d\n",
12200                                 progname, argv[0], fname, rc);
12201                         goto close_fd;
12202                 }
12203         }
12204
12205         /* verify mirror id */
12206         rc = verify_mirror_id_by_fd(fd, read_mirror_id);
12207         if (rc) {
12208                 fprintf(stderr,
12209                         "%s %s: cannot find mirror with ID %u in '%s'\n",
12210                         progname, argv[0], read_mirror_id, fname);
12211                 goto close_fd;
12212         }
12213
12214         for (i = 0; i < count; i++) {
12215                 rc = verify_mirror_id_by_fd(fd, ids[i]);
12216                 if (rc) {
12217                         fprintf(stderr,
12218                         "%s %s: cannot find mirror with ID %u in '%s'\n",
12219                                 progname, argv[0], ids[i], fname);
12220                         goto close_fd;
12221                 }
12222         }
12223
12224         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
12225         if (!ioc) {
12226                 fprintf(stderr,
12227                         "%s %s: cannot alloc comp id array for ioc: %s\n",
12228                         progname, argv[0], strerror(errno));
12229                 rc = -errno;
12230                 goto close_fd;
12231         }
12232
12233         /* get stale component info */
12234         layout = llapi_layout_get_by_fd(fd, 0);
12235         if (!layout) {
12236                 fprintf(stderr, "%s %s: failed to get layout of '%s': %s\n",
12237                         progname, argv[0], fname, strerror(errno));
12238                 rc = -errno;
12239                 goto free_ioc;
12240         }
12241         comp_size = llapi_mirror_find_stale(layout, comp_array,
12242                                             ARRAY_SIZE(comp_array),
12243                                             ids, count);
12244         llapi_layout_free(layout);
12245         if (comp_size < 0) {
12246                 rc = comp_size;
12247                 goto free_ioc;
12248         }
12249
12250         /* prepare target mirror components instantiation */
12251         resync_ioc = (struct ll_ioc_lease_id *)ioc;
12252         resync_ioc->lil_mode = LL_LEASE_WRLCK;
12253         resync_ioc->lil_flags = LL_LEASE_RESYNC;
12254         if (count == 1)
12255                 resync_ioc->lil_mirror_id = ids[0];
12256         else
12257                 resync_ioc->lil_mirror_id = read_mirror_id | MIRROR_ID_NEG;
12258         rc = llapi_lease_set(fd, ioc);
12259         if (rc < 0) {
12260                 fprintf(stderr,
12261                         "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
12262                         progname, argv[0], fname, strerror(errno));
12263                 goto free_ioc;
12264         }
12265
12266         copied = llapi_mirror_copy_many(fd, read_mirror_id, ids, count);
12267         if (copied < 0) {
12268                 rc = copied;
12269                 fprintf(stderr, "%s %s: copy error: %d\n",
12270                         progname, argv[0], rc);
12271                 goto free_ioc;
12272         }
12273
12274         fprintf(stdout, "mirror copied successfully: ");
12275         for (i = 0; i < copied; i++)
12276                 fprintf(stdout, "%d ", ids[i]);
12277         fprintf(stdout, "\n");
12278
12279         ioc->lil_mode = LL_LEASE_UNLCK;
12280         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
12281         ioc->lil_count = 0;
12282         for (i = 0; i < comp_size; i++) {
12283                 int j;
12284
12285                 for (j = 0; j < copied; j++) {
12286                         if (comp_array[i].lrc_mirror_id != ids[j])
12287                                 continue;
12288
12289                         ioc->lil_ids[ioc->lil_count] = comp_array[i].lrc_id;
12290                         ioc->lil_count++;
12291                 }
12292         }
12293         rc = llapi_lease_set(fd, ioc);
12294         if (rc <= 0) {
12295                 if (rc == 0)
12296                         rc = -EBUSY;
12297                 fprintf(stderr,
12298                         "%s %s: release lease lock of '%s' failed: %s\n",
12299                         progname, argv[0], fname, strerror(errno));
12300                 goto free_ioc;
12301         }
12302
12303         rc = 0;
12304
12305 free_ioc:
12306         free(ioc);
12307 close_fd:
12308         close(fd);
12309
12310         return rc;
12311 }
12312
12313 /**
12314  * struct verify_chunk - Mirror chunk to be verified.
12315  * @chunk:        [start, end) of the chunk.
12316  * @mirror_count: Number of mirror ids in @mirror_id array.
12317  * @mirror_id:    Array of valid mirror ids that cover the chunk.
12318  */
12319 struct verify_chunk {
12320         struct lu_extent chunk;
12321         unsigned int mirror_count;
12322         __u16 mirror_id[LUSTRE_MIRROR_COUNT_MAX];
12323 };
12324
12325 /**
12326  * print_chunks() - Print chunk information.
12327  * @fname:       Mirrored file name.
12328  * @chunks:      Array of chunks.
12329  * @chunk_count: Number of chunks in @chunks array.
12330  *
12331  * This function prints [start, end) of each chunk in @chunks
12332  * for mirrored file @fname, and also prints the valid mirror ids
12333  * that cover the chunk.
12334  *
12335  * Return: void.
12336  */
12337 static inline
12338 void print_chunks(const char *fname, struct verify_chunk *chunks,
12339                   int chunk_count)
12340 {
12341         int i;
12342         int j;
12343
12344         fprintf(stdout, "Chunks to be verified in %s:\n", fname);
12345         for (i = 0; i < chunk_count; i++) {
12346                 fprintf(stdout, DEXT, PEXT(&chunks[i].chunk));
12347
12348                 if (chunks[i].mirror_count == 0)
12349                         fprintf(stdout, "\t[");
12350                 else {
12351                         fprintf(stdout, "\t[%u", chunks[i].mirror_id[0]);
12352                         for (j = 1; j < chunks[i].mirror_count; j++)
12353                                 fprintf(stdout, ", %u", chunks[i].mirror_id[j]);
12354                 }
12355                 fprintf(stdout, "]\t%u\n", chunks[i].mirror_count);
12356         }
12357         fprintf(stdout, "\n");
12358 }
12359
12360 /**
12361  * print_checksums() - Print CRC-32 checksum values.
12362  * @chunk: A chunk and its corresponding valid mirror ids.
12363  * @crc:   CRC-32 checksum values on the chunk for each valid mirror.
12364  *
12365  * This function prints CRC-32 checksum values on @chunk for
12366  * each valid mirror that covers it.
12367  *
12368  * Return: void.
12369  */
12370 static inline
12371 void print_checksums(struct verify_chunk *chunk, unsigned long *crc,
12372                      unsigned long long pos, unsigned long long len)
12373 {
12374         int i;
12375
12376         fprintf(stdout,
12377                 "CRC-32 checksum value for chunk "DEXT":\n", pos, pos + len);
12378         for (i = 0; i < chunk->mirror_count; i++)
12379                 fprintf(stdout, "Mirror %u:\t%#lx\n",
12380                         chunk->mirror_id[i], crc[i]);
12381         fprintf(stdout, "\n");
12382 }
12383
12384 /**
12385  * filter_mirror_id() - Filter specified mirror ids.
12386  * @chunks:      Array of chunks.
12387  * @chunk_count: Number of chunks in @chunks array.
12388  * @mirror_ids:  Specified mirror ids to be verified.
12389  * @ids_nr:      Number of specified mirror ids.
12390  *
12391  * This function scans valid mirror ids that cover each chunk in @chunks
12392  * and filters specified mirror ids.
12393  *
12394  * Return: void.
12395  */
12396 static inline
12397 void filter_mirror_id(struct verify_chunk *chunks, int chunk_count,
12398                       __u16 *mirror_ids, int ids_nr)
12399 {
12400         int i;
12401         int j;
12402         int k;
12403         __u16 valid_id[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
12404         unsigned int valid_count = 0;
12405
12406         for (i = 0; i < chunk_count; i++) {
12407                 if (chunks[i].mirror_count == 0)
12408                         continue;
12409
12410                 valid_count = 0;
12411                 for (j = 0; j < ids_nr; j++) {
12412                         for (k = 0; k < chunks[i].mirror_count; k++) {
12413                                 if (chunks[i].mirror_id[k] == mirror_ids[j]) {
12414                                         valid_id[valid_count] = mirror_ids[j];
12415                                         valid_count++;
12416                                         break;
12417                                 }
12418                         }
12419                 }
12420
12421                 memcpy(chunks[i].mirror_id, valid_id,
12422                        sizeof(__u16) * valid_count);
12423                 chunks[i].mirror_count = valid_count;
12424         }
12425 }
12426
12427 /**
12428  * lfs_mirror_prepare_chunk() - Find mirror chunks to be verified.
12429  * @layout:      Mirror component list.
12430  * @chunks:      Array of chunks.
12431  * @chunks_size: Array size of @chunks.
12432  *
12433  * This function scans the components in @layout from offset 0 to LUSTRE_EOF
12434  * to find out chunk segments and store them in @chunks array.
12435  *
12436  * The @mirror_id array in each element of @chunks will store the valid
12437  * mirror ids that cover the chunk. If a mirror component covering the
12438  * chunk has LCME_FL_STALE or LCME_FL_OFFLINE flag, then the mirror id
12439  * will not be stored into the @mirror_id array, and the chunk for that
12440  * mirror will not be verified.
12441  *
12442  * The @mirror_count in each element of @chunks will store the number of
12443  * mirror ids in @mirror_id array. If @mirror_count is 0, it indicates the
12444  * chunk is invalid in all of the mirrors. And if @mirror_count is 1, it
12445  * indicates the chunk is valid in only one mirror. In both cases, the
12446  * chunk will not be verified.
12447  *
12448  * Here is an example:
12449  *
12450  *  0      1M     2M     3M     4M           EOF
12451  *  +------+-------------+--------------------+
12452  *  |      |             |      S             |       mirror1
12453  *  +------+------+------+------+-------------+
12454  *  |             |   S  |   S  |             |       mirror2
12455  *  +-------------+------+------+-------------+
12456  *
12457  * prepared @chunks array will contain 5 elements:
12458  * (([0, 1M), [1, 2], 2),
12459  *  ([1M, 2M), [1, 2], 2),
12460  *  ([2M, 3M), [1], 1),
12461  *  ([3M, 4M], [], 0),
12462  *  ([4M, EOF), [2], 1))
12463  *
12464  * Return: the actual array size of @chunks on success
12465  *         or a negative error code on failure.
12466  */
12467 static inline
12468 int lfs_mirror_prepare_chunk(struct llapi_layout *layout,
12469                              struct verify_chunk *chunks,
12470                              size_t chunks_size)
12471 {
12472         uint64_t start;
12473         uint64_t end;
12474         uint32_t mirror_id;
12475         uint32_t flags;
12476         int idx = 0;
12477         int i = 0;
12478         int rc = 0;
12479
12480         memset(chunks, 0, sizeof(*chunks) * chunks_size);
12481
12482         while (1) {
12483                 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
12484                 if (rc < 0) {
12485                         fprintf(stderr,
12486                                 "%s: move to the first layout component: %s.\n",
12487                                 progname, strerror(errno));
12488                         goto error;
12489                 }
12490
12491                 i = 0;
12492                 rc = 0;
12493                 chunks[idx].chunk.e_end = LUSTRE_EOF;
12494                 while (rc == 0) {
12495                         rc = llapi_layout_comp_extent_get(layout, &start, &end);
12496                         if (rc < 0) {
12497                                 fprintf(stderr,
12498                                         "%s: llapi_layout_comp_extent_get failed: %s.\n",
12499                                         progname, strerror(errno));
12500                                 goto error;
12501                         }
12502
12503                         if (start > chunks[idx].chunk.e_start ||
12504                             end <= chunks[idx].chunk.e_start)
12505                                 goto next;
12506
12507                         if (end < chunks[idx].chunk.e_end)
12508                                 chunks[idx].chunk.e_end = end;
12509
12510                         rc = llapi_layout_comp_flags_get(layout, &flags);
12511                         if (rc < 0) {
12512                                 fprintf(stderr,
12513                                         "%s: llapi_layout_comp_flags_get failed: %s.\n",
12514                                         progname, strerror(errno));
12515                                 goto error;
12516                         }
12517
12518                         if (flags & LCME_FL_STALE || flags & LCME_FL_OFFLINE)
12519                                 goto next;
12520
12521                         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
12522                         if (rc < 0) {
12523                                 fprintf(stderr,
12524                                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
12525                                         progname, strerror(errno));
12526                                 goto error;
12527                         }
12528
12529                         if (i >= ARRAY_SIZE(chunks[idx].mirror_id)) {
12530                                 fprintf(stderr,
12531                                         "%s: mirror_id array is too small.\n",
12532                                         progname);
12533                                 rc = -EINVAL;
12534                                 goto error;
12535                         }
12536                         chunks[idx].mirror_id[i] = mirror_id;
12537                         i++;
12538
12539 next:
12540                         rc = llapi_layout_comp_use(layout,
12541                                                    LLAPI_LAYOUT_COMP_USE_NEXT);
12542                         if (rc < 0) {
12543                                 fprintf(stderr,
12544                                         "%s: move to the next layout component: %s.\n",
12545                                         progname, strerror(errno));
12546                                 goto error;
12547                         }
12548                 } /* loop through all components */
12549
12550                 chunks[idx].mirror_count = i;
12551
12552                 if (chunks[idx].chunk.e_end == LUSTRE_EOF)
12553                         break;
12554
12555                 idx++;
12556                 if (idx >= chunks_size) {
12557                         fprintf(stderr, "%s: chunks array is too small.\n",
12558                                 progname);
12559                         rc = -EINVAL;
12560                         goto error;
12561                 }
12562
12563                 chunks[idx].chunk.e_start = chunks[idx - 1].chunk.e_end;
12564         }
12565
12566 error:
12567         return rc < 0 ? rc : idx + 1;
12568 }
12569
12570 /**
12571  * lfs_mirror_verify_chunk() - Verify a chunk.
12572  * @fd:        File descriptor of the mirrored file.
12573  * @file_size: Size of the mirrored file.
12574  * @chunk:     A chunk and its corresponding valid mirror ids.
12575  * @verbose:   Verbose mode.
12576  *
12577  * This function verifies a @chunk contains exactly the same data
12578  * ammong the mirrors that cover it.
12579  *
12580  * If @verbose is specified, then the function will print where the
12581  * differences are if the data do not match. Otherwise, it will
12582  * just return an error in that case.
12583  *
12584  * Return: 0 on success or a negative error code on failure.
12585  */
12586 static inline
12587 int lfs_mirror_verify_chunk(int fd, size_t file_size,
12588                             struct verify_chunk *chunk, int verbose)
12589 {
12590         const size_t buflen = 4 * 1024 * 1024; /* 4M */
12591         void *buf;
12592         size_t page_size = sysconf(_SC_PAGESIZE);
12593         ssize_t bytes_read;
12594         ssize_t bytes_done;
12595         size_t count;
12596         off_t pos;
12597         unsigned long crc;
12598         unsigned long crc_array[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
12599         int i;
12600         int rc = 0;
12601
12602         if (file_size == 0)
12603                 return 0;
12604
12605         rc = posix_memalign(&buf, page_size, buflen);
12606         if (rc) /* error code is returned directly */
12607                 return -rc;
12608
12609         if (verbose > 1) {
12610                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
12611                         PEXT(&chunk->chunk));
12612                 for (i = 0; i < chunk->mirror_count; i++)
12613                         fprintf(stdout, " %u", chunk->mirror_id[i]);
12614                 fprintf(stdout, "\n");
12615         }
12616
12617         bytes_done = 0;
12618         count = MIN(chunk->chunk.e_end, file_size) - chunk->chunk.e_start;
12619         pos = chunk->chunk.e_start;
12620         while (bytes_done < count) {
12621                 /* compute initial CRC-32 checksum */
12622                 crc = crc32(0L, Z_NULL, 0);
12623                 memset(crc_array, 0, sizeof(crc_array));
12624
12625                 bytes_read = 0;
12626                 for (i = 0; i < chunk->mirror_count; i++) {
12627                         bytes_read = llapi_mirror_read(fd, chunk->mirror_id[i],
12628                                                        buf, buflen, pos);
12629                         if (bytes_read < 0) {
12630                                 rc = bytes_read;
12631                                 fprintf(stderr,
12632                                         "%s: failed to read data from mirror %u: %s.\n",
12633                                         progname, chunk->mirror_id[i],
12634                                         strerror(-rc));
12635                                 goto error;
12636                         }
12637
12638                         /* compute new CRC-32 checksum */
12639                         crc_array[i] = crc32(crc, buf, bytes_read);
12640                 }
12641
12642                 if (verbose)
12643                         print_checksums(chunk, crc_array, pos, buflen);
12644
12645                 /* compare CRC-32 checksum values */
12646                 for (i = 1; i < chunk->mirror_count; i++) {
12647                         if (crc_array[i] != crc_array[0]) {
12648                                 rc = -EINVAL;
12649
12650                                 fprintf(stderr,
12651                                         "%s: chunk "DEXT" has different checksum value on mirror %u:%lx and mirror %u:%lx.\n",
12652                                         progname, PEXT(&chunk->chunk),
12653                                         chunk->mirror_id[0], crc_array[0],
12654                                         chunk->mirror_id[i], crc_array[i]);
12655                                 print_checksums(chunk, crc_array, pos, buflen);
12656                         }
12657                 }
12658
12659                 pos += bytes_read;
12660                 bytes_done += bytes_read;
12661         }
12662
12663         if (verbose > 1 && rc == 0) {
12664                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
12665                         PEXT(&chunk->chunk));
12666                 for (i = 0; i < chunk->mirror_count; i++)
12667                         fprintf(stdout, " %u", chunk->mirror_id[i]);
12668                 fprintf(stdout, " PASS\n\n");
12669         }
12670
12671 error:
12672         free(buf);
12673         return rc;
12674 }
12675
12676 /**
12677  * lfs_mirror_verify_file() - Verify a mirrored file.
12678  * @fname:      Mirrored file name.
12679  * @mirror_ids: Specified mirror ids to be verified.
12680  * @ids_nr:     Number of specified mirror ids.
12681  * @verbose:    Verbose mode.
12682  *
12683  * This function verifies that each SYNC mirror of a mirrored file
12684  * specified by @fname contains exactly the same data.
12685  *
12686  * If @mirror_ids is specified, then the function will verify the
12687  * mirrors specified by @mirror_ids contain exactly the same data.
12688  *
12689  * If @verbose is specified, then the function will print where the
12690  * differences are if the data do not match. Otherwise, it will
12691  * just return an error in that case.
12692  *
12693  * Return: 0 on success or a negative error code on failure.
12694  */
12695 static inline
12696 int lfs_mirror_verify_file(const char *fname, __u16 *mirror_ids, int ids_nr,
12697                            int verbose)
12698 {
12699         struct verify_chunk chunks_array[1024] = { };
12700         struct llapi_layout *layout = NULL;
12701         struct stat stbuf;
12702         uint32_t flr_state;
12703         int fd;
12704         int chunk_count = 0;
12705         int idx = 0;
12706         int rc = 0;
12707         int rc1 = 0;
12708         int rc2 = 0;
12709
12710         if (stat(fname, &stbuf) < 0) {
12711                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
12712                         progname, fname, strerror(errno));
12713                 rc = -errno;
12714                 goto error;
12715         }
12716
12717         if (!S_ISREG(stbuf.st_mode)) {
12718                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
12719                         progname, fname);
12720                 rc = -EINVAL;
12721                 goto error;
12722         }
12723
12724         if (stbuf.st_size == 0) {
12725                 if (verbose)
12726                         fprintf(stdout, "%s: '%s' file size is 0.\n",
12727                                 progname, fname);
12728                 rc = 0;
12729                 goto error;
12730         }
12731
12732         /* Allow mirror verify even without the key on encrypted files */
12733         fd = open(fname, O_DIRECT | O_RDONLY | O_CIPHERTEXT);
12734         if (fd < 0) {
12735                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
12736                         progname, fname, strerror(errno));
12737                 rc = -errno;
12738                 goto error;
12739         }
12740
12741         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
12742         if (rc < 0) {
12743                 fprintf(stderr, "%s: '%s' llapi_lease_acquire failed: %s.\n",
12744                         progname, fname, strerror(errno));
12745                 goto close_fd;
12746         }
12747
12748         layout = llapi_layout_get_by_fd(fd, 0);
12749         if (!layout) {
12750                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
12751                         progname, fname, strerror(errno));
12752                 rc = -errno;
12753                 llapi_lease_release(fd);
12754                 goto close_fd;
12755         }
12756
12757         rc = llapi_layout_flags_get(layout, &flr_state);
12758         if (rc < 0) {
12759                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
12760                         progname, fname, strerror(errno));
12761                 rc = -errno;
12762                 goto free_layout;
12763         }
12764
12765         flr_state &= LCM_FL_FLR_MASK;
12766         switch (flr_state) {
12767         case LCM_FL_NONE:
12768                 rc = -EINVAL;
12769                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
12770                         progname, fname, llapi_layout_flags_string(flr_state));
12771                 goto free_layout;
12772         default:
12773                 break;
12774         }
12775
12776         /* find out mirror chunks to be verified */
12777         chunk_count = lfs_mirror_prepare_chunk(layout, chunks_array,
12778                                                ARRAY_SIZE(chunks_array));
12779         if (chunk_count < 0) {
12780                 rc = chunk_count;
12781                 goto free_layout;
12782         }
12783
12784         if (ids_nr > 0)
12785                 /* filter specified mirror ids */
12786                 filter_mirror_id(chunks_array, chunk_count, mirror_ids, ids_nr);
12787
12788         if (verbose > 2)
12789                 print_chunks(fname, chunks_array, chunk_count);
12790
12791         for (idx = 0; idx < chunk_count; idx++) {
12792                 if (chunks_array[idx].chunk.e_start >= stbuf.st_size) {
12793                         if (verbose)
12794                                 fprintf(stdout,
12795                                         "%s: '%s' chunk "DEXT" exceeds file size %#llx: skipped\n",
12796                                         progname, fname,
12797                                         PEXT(&chunks_array[idx].chunk),
12798                                         (unsigned long long)stbuf.st_size);
12799                         break;
12800                 }
12801
12802                 if (chunks_array[idx].mirror_count == 0) {
12803                         fprintf(stderr,
12804                                 "%s: '%s' chunk "DEXT" is invalid in all of the mirrors: ",
12805                                 progname, fname,
12806                                 PEXT(&chunks_array[idx].chunk));
12807                         if (verbose) {
12808                                 fprintf(stderr, "skipped\n");
12809                                 continue;
12810                         }
12811                         rc = -EINVAL;
12812                         fprintf(stderr, "failed\n");
12813                         goto free_layout;
12814                 }
12815
12816                 if (chunks_array[idx].mirror_count == 1) {
12817                         if (verbose)
12818                                 fprintf(stdout,
12819                                         "%s: '%s' chunk "DEXT" is only valid in mirror %u: skipped\n",
12820                                         progname, fname,
12821                                         PEXT(&chunks_array[idx].chunk),
12822                                         chunks_array[idx].mirror_id[0]);
12823                         continue;
12824                 }
12825
12826                 rc = llapi_lease_check(fd);
12827                 if (rc != LL_LEASE_RDLCK) {
12828                         fprintf(stderr, "%s: '%s' lost lease lock.\n",
12829                                 progname, fname);
12830                         goto free_layout;
12831                 }
12832
12833                 /* verify one chunk */
12834                 rc1 = lfs_mirror_verify_chunk(fd, stbuf.st_size,
12835                                               &chunks_array[idx], verbose);
12836                 if (rc1 < 0) {
12837                         rc2 = rc1;
12838                         if (!verbose) {
12839                                 rc = rc1;
12840                                 goto free_layout;
12841                         }
12842                 }
12843         }
12844
12845         if (rc2 < 0)
12846                 rc = rc2;
12847
12848 free_layout:
12849         llapi_layout_free(layout);
12850         llapi_lease_release(fd);
12851 close_fd:
12852         close(fd);
12853 error:
12854         return rc;
12855 }
12856
12857 /**
12858  * lfs_mirror_verify() - Parse and execute lfs mirror verify command.
12859  * @argc: The count of lfs mirror verify command line arguments.
12860  * @argv: Array of strings for lfs mirror verify command line arguments.
12861  *
12862  * This function parses lfs mirror verify command and verifies the
12863  * specified mirrored file(s).
12864  *
12865  * Return: 0 on success or a negative error code on failure.
12866  */
12867 static inline int lfs_mirror_verify(int argc, char **argv)
12868 {
12869         __u16 mirror_ids[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
12870         int ids_nr = 0;
12871         int c;
12872         int verbose = 0;
12873         int rc = 0;
12874         int rc1 = 0;
12875         char cmd[PATH_MAX];
12876
12877         struct option long_opts[] = {
12878         { .val = 'h',   .name = "help",         .has_arg = no_argument },
12879         { .val = 'o',   .name = "only",         .has_arg = required_argument },
12880         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
12881         { .name = NULL } };
12882
12883         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12884         progname = cmd;
12885         while ((c = getopt_long(argc, argv, "ho:v", long_opts, NULL)) >= 0) {
12886                 switch (c) {
12887                 case 'o':
12888                         rc = parse_mirror_ids(mirror_ids,
12889                                               ARRAY_SIZE(mirror_ids),
12890                                               optarg);
12891                         if (rc < 0) {
12892                                 fprintf(stderr,
12893                                         "%s: bad mirror ids '%s'.\n",
12894                                         progname, optarg);
12895                                 goto error;
12896                         }
12897                         ids_nr = rc;
12898                         if (ids_nr < 2) {
12899                                 fprintf(stderr,
12900                                         "%s: at least 2 mirror ids needed with '--only' option.\n",
12901                                         progname);
12902                                 rc = CMD_HELP;
12903                                 goto error;
12904                         }
12905                         break;
12906                 case 'v':
12907                         verbose++;
12908                         break;
12909                 default:
12910                         fprintf(stderr, "%s: unrecognized option '%s'\n",
12911                                 progname, argv[optind - 1]);
12912                         fallthrough;
12913                 case 'h':
12914                         rc = CMD_HELP;
12915                         goto error;
12916                 }
12917         }
12918
12919         if (argc == optind) {
12920                 fprintf(stderr, "%s: no file name given.\n", progname);
12921                 rc = CMD_HELP;
12922                 goto error;
12923         }
12924
12925         if (ids_nr > 0 && argc > optind + 1) {
12926                 fprintf(stderr,
12927                         "%s: '--only' cannot be used upon multiple files.\n",
12928                         progname);
12929                 rc = CMD_HELP;
12930                 goto error;
12931         }
12932
12933         if (ids_nr > 0) {
12934                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
12935                 if (rc < 0)
12936                         goto error;
12937         }
12938
12939         rc = 0;
12940         for (; optind < argc; optind++) {
12941                 rc1 = lfs_mirror_verify_file(argv[optind], mirror_ids, ids_nr,
12942                                              verbose);
12943                 if (rc1 < 0)
12944                         rc = rc1;
12945         }
12946 error:
12947         return rc;
12948 }
12949
12950 /**
12951  * lfs_mirror() - Parse and execute lfs mirror commands.
12952  * @argc: The count of lfs mirror command line arguments.
12953  * @argv: Array of strings for lfs mirror command line arguments.
12954  *
12955  * This function parses lfs mirror commands and performs the
12956  * corresponding functions specified in mirror_cmdlist[].
12957  *
12958  * Return: 0 on success or an error code on failure.
12959  */
12960 static int lfs_mirror(int argc, char **argv)
12961 {
12962         char cmd[PATH_MAX];
12963         int rc = 0;
12964
12965         setlinebuf(stdout);
12966
12967         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
12968         progname = cmd;
12969         program_invocation_short_name = cmd;
12970         rc = cfs_parser(argc, argv, mirror_cmdlist);
12971
12972         return rc < 0 ? -rc : rc;
12973 }
12974
12975 static void lustre_som_swab(struct lustre_som_attrs *attrs)
12976 {
12977 #if __BYTE_ORDER == __BIG_ENDIAN
12978         __swab16s(&attrs->lsa_valid);
12979         __swab64s(&attrs->lsa_size);
12980         __swab64s(&attrs->lsa_blocks);
12981 #endif
12982 }
12983
12984 enum lfs_som_type {
12985         LFS_SOM_SIZE = 0x1,
12986         LFS_SOM_BLOCKS = 0x2,
12987         LFS_SOM_FLAGS = 0x4,
12988         LFS_SOM_ATTR_ALL = LFS_SOM_SIZE | LFS_SOM_BLOCKS |
12989                            LFS_SOM_FLAGS,
12990 };
12991
12992 static int lfs_getsom(int argc, char **argv)
12993 {
12994         const char *path;
12995         struct lustre_som_attrs *attrs;
12996         char buf[sizeof(*attrs) + 64];
12997         enum lfs_som_type type = LFS_SOM_ATTR_ALL;
12998         int rc = 0, c;
12999
13000         while ((c = getopt(argc, argv, "bfhs")) != -1) {
13001                 switch (c) {
13002                 case 'b':
13003                         type = LFS_SOM_BLOCKS;
13004                         break;
13005                 case 'f':
13006                         type = LFS_SOM_FLAGS;
13007                         break;
13008                 case 's':
13009                         type = LFS_SOM_SIZE;
13010                         break;
13011                 default:
13012                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13013                                 progname, argv[optind - 1]);
13014                         fallthrough;
13015                 case 'h':
13016                         return CMD_HELP;
13017                 }
13018         }
13019
13020         argc -= optind;
13021         argv += optind;
13022
13023         if (argc != 1) {
13024                 fprintf(stderr, "%s: %s\n",
13025                         progname, argc == 0 ? "miss file target" :
13026                         "input more than 2 files");
13027                 return CMD_HELP;
13028         }
13029
13030         path = argv[0];
13031         attrs = (void *)buf;
13032         rc = lgetxattr(path, "trusted.som", attrs, sizeof(buf));
13033         if (rc < 0) {
13034                 rc = -errno;
13035                 fprintf(stderr, "%s failed to get som xattr: %s (%d)\n",
13036                         argv[0], strerror(errno), errno);
13037                 return rc;
13038         }
13039
13040         lustre_som_swab(attrs);
13041
13042         switch (type) {
13043         case LFS_SOM_ATTR_ALL:
13044                 printf("file: %s size: %llu blocks: %llu flags: %x\n",
13045                        path, (unsigned long long)attrs->lsa_size,
13046                        (unsigned long long)attrs->lsa_blocks,
13047                        attrs->lsa_valid);
13048                 break;
13049         case LFS_SOM_SIZE:
13050                 printf("%llu\n", (unsigned long long)attrs->lsa_size);
13051                 break;
13052         case LFS_SOM_BLOCKS:
13053                 printf("%llu\n", (unsigned long long)attrs->lsa_blocks);
13054                 break;
13055         case LFS_SOM_FLAGS:
13056                 printf("%x\n", attrs->lsa_valid);
13057                 break;
13058         default:
13059                 fprintf(stderr, "%s: unknown option\n", progname);
13060                 return CMD_HELP;
13061         }
13062
13063         return 0;
13064 }
13065
13066 static int lfs_pcc_attach(int argc, char **argv)
13067 {
13068         struct option long_opts[] = {
13069         { .val = 'h',   .name = "help", .has_arg = no_argument },
13070         { .val = 'i',   .name = "id",   .has_arg = required_argument },
13071         { .name = NULL } };
13072         int c;
13073         int rc = 0;
13074         __u32 archive_id = 0;
13075         const char *path;
13076         char *end;
13077         char fullpath[PATH_MAX];
13078         enum lu_pcc_type type = LU_PCC_READWRITE;
13079
13080         optind = 0;
13081         while ((c = getopt_long(argc, argv, "hi:",
13082                                 long_opts, NULL)) != -1) {
13083                 switch (c) {
13084                 case 'i':
13085                         errno = 0;
13086                         archive_id = strtoul(optarg, &end, 0);
13087                         if (errno != 0 || *end != '\0' ||
13088                             archive_id == 0 || archive_id > UINT32_MAX) {
13089                                 fprintf(stderr,
13090                                         "error: %s: bad archive ID '%s'\n",
13091                                         progname, optarg);
13092                                 return CMD_HELP;
13093                         }
13094                         break;
13095                 default:
13096                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13097                                 progname, argv[optind - 1]);
13098                         fallthrough;
13099                 case 'h':
13100                         return CMD_HELP;
13101                 }
13102         }
13103
13104         if (archive_id == 0) {
13105                 fprintf(stderr, "%s: must specify attach ID\n", argv[0]);
13106                 return CMD_HELP;
13107         }
13108
13109         if (argc <= optind) {
13110                 fprintf(stderr, "%s: must specify one or more file names\n",
13111                         argv[0]);
13112                 return CMD_HELP;
13113         }
13114
13115         while (optind < argc) {
13116                 int rc2;
13117
13118                 path = argv[optind++];
13119                 if (!realpath(path, fullpath)) {
13120                         fprintf(stderr, "%s: could not find path '%s': %s\n",
13121                                 argv[0], path, strerror(errno));
13122                         if (rc == 0)
13123                                 rc = -EINVAL;
13124                         continue;
13125                 }
13126
13127                 rc2 = llapi_pcc_attach(fullpath, archive_id, type);
13128                 if (rc2 < 0) {
13129                         fprintf(stderr,
13130                                 "%s: cannot attach '%s' to PCC with archive ID '%u': %s\n",
13131                                 argv[0], path, archive_id, strerror(-rc2));
13132                         if (rc == 0)
13133                                 rc = rc2;
13134                 }
13135         }
13136         return rc;
13137 }
13138
13139 static int lfs_pcc_attach_fid(int argc, char **argv)
13140 {
13141         struct option long_opts[] = {
13142         { .val = 'h',   .name = "help", .has_arg = no_argument },
13143         { .val = 'i',   .name = "id",   .has_arg = required_argument },
13144         { .val = 'm',   .name = "mnt",  .has_arg = required_argument },
13145         { .name = NULL } };
13146         int c;
13147         int rc = 0;
13148         __u32 archive_id = 0;
13149         char *end;
13150         const char *mntpath = NULL;
13151         const char *fidstr;
13152         enum lu_pcc_type type = LU_PCC_READWRITE;
13153
13154         optind = 0;
13155         while ((c = getopt_long(argc, argv, "hi:m:",
13156                                 long_opts, NULL)) != -1) {
13157                 switch (c) {
13158                 case 'i':
13159                         errno = 0;
13160                         archive_id = strtoul(optarg, &end, 0);
13161                         if (errno != 0 || *end != '\0' ||
13162                             archive_id > UINT32_MAX) {
13163                                 fprintf(stderr,
13164                                         "error: %s: bad archive ID '%s'\n",
13165                                         argv[0], optarg);
13166                                 return CMD_HELP;
13167                         }
13168                         break;
13169                 case 'm':
13170                         mntpath = optarg;
13171                         break;
13172                 default:
13173                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13174                                 progname, argv[optind - 1]);
13175                         fallthrough;
13176                 case 'h':
13177                         return CMD_HELP;
13178                 }
13179         }
13180
13181         if (archive_id == 0) {
13182                 fprintf(stderr, "%s: must specify an archive ID\n", argv[0]);
13183                 return CMD_HELP;
13184         }
13185
13186         if (!mntpath) {
13187                 fprintf(stderr, "%s: must specify Lustre mount point\n",
13188                         argv[0]);
13189                 return CMD_HELP;
13190         }
13191
13192         if (argc <= optind) {
13193                 fprintf(stderr, "%s: must specify one or more fids\n", argv[0]);
13194                 return CMD_HELP;
13195         }
13196
13197         while (optind < argc) {
13198                 int rc2;
13199
13200                 fidstr = argv[optind++];
13201
13202                 rc2 = llapi_pcc_attach_fid_str(mntpath, fidstr,
13203                                                archive_id, type);
13204                 if (rc2 < 0) {
13205                         fprintf(stderr,
13206                                 "%s: cannot attach '%s' on '%s' to PCC with archive ID '%u': %s\n",
13207                                 argv[0], fidstr, mntpath, archive_id,
13208                                 strerror(rc2));
13209                 }
13210                 if (rc == 0 && rc2 < 0)
13211                         rc = rc2;
13212         }
13213         return rc;
13214 }
13215
13216 static int lfs_pcc_detach(int argc, char **argv)
13217 {
13218         struct option long_opts[] = {
13219         { .val = 'h',   .name = "help", .has_arg = no_argument },
13220         { .val = 'k',   .name = "keep", .has_arg = no_argument },
13221         { .name = NULL } };
13222         int c;
13223         int rc = 0;
13224         const char *path;
13225         char fullpath[PATH_MAX];
13226         __u32 detach_opt = PCC_DETACH_OPT_UNCACHE;
13227
13228         optind = 0;
13229         while ((c = getopt_long(argc, argv, "hk",
13230                                 long_opts, NULL)) != -1) {
13231                 switch (c) {
13232                 case 'k':
13233                         detach_opt = PCC_DETACH_OPT_NONE;
13234                         break;
13235                 default:
13236                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13237                                 progname, argv[optind - 1]);
13238                         fallthrough;
13239                 case 'h':
13240                         return CMD_HELP;
13241                 }
13242         }
13243
13244         while (optind < argc) {
13245                 int rc2;
13246
13247                 path = argv[optind++];
13248                 if (!realpath(path, fullpath)) {
13249                         fprintf(stderr, "%s: could not find path '%s': %s\n",
13250                                 argv[0], path, strerror(errno));
13251                         if (rc == 0)
13252                                 rc = -EINVAL;
13253                         continue;
13254                 }
13255
13256                 rc2 = llapi_pcc_detach_file(fullpath, detach_opt);
13257                 if (rc2 < 0) {
13258                         rc2 = -errno;
13259                         fprintf(stderr,
13260                                 "%s: cannot detach '%s' from PCC: %s\n",
13261                                 argv[0], path, strerror(errno));
13262                         if (rc == 0)
13263                                 rc = rc2;
13264                 }
13265         }
13266         return rc;
13267 }
13268
13269 static int lfs_pcc_detach_fid(int argc, char **argv)
13270 {
13271         struct option long_opts[] = {
13272         { .val = 'h',   .name = "help", .has_arg = no_argument },
13273         { .val = 'k',   .name = "keep", .has_arg = no_argument },
13274         { .name = NULL } };
13275         int c;
13276         int rc = 0;
13277         const char *fid;
13278         const char *mntpath;
13279         __u32 detach_opt = PCC_DETACH_OPT_UNCACHE;
13280
13281         optind = 0;
13282         while ((c = getopt_long(argc, argv, "hk",
13283                                 long_opts, NULL)) != -1) {
13284                 switch (c) {
13285                 case 'k':
13286                         detach_opt = PCC_DETACH_OPT_NONE;
13287                         break;
13288                 default:
13289                         fprintf(stderr, "%s: unrecognized option '%s'\n",
13290                                 progname, argv[optind - 1]);
13291                         fallthrough;
13292                 case 'h':
13293                         return CMD_HELP;
13294                 }
13295         }
13296
13297         mntpath = argv[optind++];
13298
13299         while (optind < argc) {
13300                 int rc2;
13301
13302                 fid = argv[optind++];
13303
13304                 rc2 = llapi_pcc_detach_fid_str(mntpath, fid, detach_opt);
13305                 if (rc2 < 0) {
13306                         fprintf(stderr,
13307                                 "%s: cannot detach '%s' on '%s' from PCC: %s\n",
13308                                 argv[0], fid, mntpath, strerror(-rc2));
13309                         if (rc == 0)
13310                                 rc = rc2;
13311                 }
13312         }
13313         return rc;
13314 }
13315
13316 static int lfs_pcc_state(int argc, char **argv)
13317 {
13318         int rc = 0;
13319         const char *path;
13320         char fullpath[PATH_MAX];
13321         struct lu_pcc_state state;
13322
13323         optind = 1;
13324
13325         if (argc <= 1) {
13326                 fprintf(stderr, "%s: must specify one or more file names\n",
13327                         progname);
13328                 return CMD_HELP;
13329         }
13330
13331         while (optind < argc) {
13332                 int rc2;
13333
13334                 path = argv[optind++];
13335                 if (!realpath(path, fullpath)) {
13336                         fprintf(stderr, "%s: could not find path '%s': %s\n",
13337                                 argv[0], path, strerror(errno));
13338                         if (rc == 0)
13339                                 rc = -EINVAL;
13340                         continue;
13341                 }
13342
13343                 rc2 = llapi_pcc_state_get(fullpath, &state);
13344                 if (rc2 < 0) {
13345                         if (rc == 0)
13346                                 rc = rc2;
13347                         fprintf(stderr,
13348                                 "%s: cannot get PCC state of '%s': %s\n",
13349                                 argv[0], path, strerror(-rc2));
13350                         continue;
13351                 }
13352
13353                 printf("file: %s", path);
13354                 printf(", type: %s", pcc_type2string(state.pccs_type));
13355                 if (state.pccs_type == LU_PCC_NONE &&
13356                     state.pccs_open_count == 0) {
13357                         printf("\n");
13358                         continue;
13359                 }
13360
13361                 printf(", PCC file: %s", state.pccs_path);
13362                 printf(", user number: %u", state.pccs_open_count);
13363                 printf(", flags: %x", state.pccs_flags);
13364                 printf("\n");
13365         }
13366         return rc;
13367 }
13368
13369 /**
13370  * lfs_pcc() - Parse and execute lfs pcc commands.
13371  * @argc: The count of lfs pcc command line arguments.
13372  * @argv: Array of strings for lfs pcc command line arguments.
13373  *
13374  * This function parses lfs pcc commands and performs the
13375  * corresponding functions specified in pcc_cmdlist[].
13376  *
13377  * Return: 0 on success or an error code on failure.
13378  */
13379 static int lfs_pcc(int argc, char **argv)
13380 {
13381         char cmd[PATH_MAX];
13382         int rc = 0;
13383
13384         setlinebuf(stdout);
13385
13386         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
13387         progname = cmd;
13388         program_invocation_short_name = cmd;
13389         rc = cfs_parser(argc, argv, pcc_cmdlist);
13390
13391         return rc < 0 ? -rc : rc;
13392 }
13393
13394 int main(int argc, char **argv)
13395 {
13396         int rc;
13397
13398         /* Ensure that liblustreapi constructor has run */
13399         if (!llapi_liblustreapi_initialized())
13400                 fprintf(stderr, "liblustreapi was not properly initialized\n");
13401
13402         setlinebuf(stdout);
13403         opterr = 0;
13404
13405         progname = program_invocation_short_name; /* Used in error messages */
13406         llapi_set_command_name(argv[1]);
13407         rc = cfs_parser(argc, argv, cmdlist);
13408         llapi_clear_command_name();
13409
13410         return rc < 0 ? -rc : rc;
13411 }