Whamcloud - gitweb
LU-9378 utils: split getstripe and find from lfs.1
[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  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lustre/utils/lfs.c
33  *
34  * Author: Peter J. Braam <braam@clusterfs.com>
35  * Author: Phil Schwan <phil@clusterfs.com>
36  * Author: Robert Read <rread@clusterfs.com>
37  */
38
39 /* for O_DIRECTORY */
40 #ifndef _GNU_SOURCE
41 #define _GNU_SOURCE
42 #endif
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <inttypes.h>
47 #include <getopt.h>
48 #include <string.h>
49 #include <mntent.h>
50 #include <unistd.h>
51 #include <errno.h>
52 #include <err.h>
53 #include <pwd.h>
54 #include <grp.h>
55 #include <sys/ioctl.h>
56 #include <sys/quota.h>
57 #include <sys/time.h>
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 #include <sys/param.h>
61 #include <fcntl.h>
62 #include <dirent.h>
63 #include <time.h>
64 #include <ctype.h>
65 #include <zlib.h>
66 #include "lfs_project.h"
67
68 #include <libcfs/util/string.h>
69 #include <libcfs/util/ioctl.h>
70 #include <libcfs/util/parser.h>
71 #include <lustre/lustreapi.h>
72 #include <linux/lustre/lustre_ver.h>
73 #include <linux/lustre/lustre_param.h>
74 #include <linux/lnet/nidstr.h>
75
76 #ifndef ARRAY_SIZE
77 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
78 #endif /* !ARRAY_SIZE */
79
80 /* all functions */
81 static int lfs_find(int argc, char **argv);
82 static int lfs_getstripe(int argc, char **argv);
83 static int lfs_getdirstripe(int argc, char **argv);
84 static int lfs_setdirstripe(int argc, char **argv);
85 static int lfs_rmentry(int argc, char **argv);
86 static int lfs_osts(int argc, char **argv);
87 static int lfs_mdts(int argc, char **argv);
88 static int lfs_df(int argc, char **argv);
89 static int lfs_getname(int argc, char **argv);
90 static int lfs_check(int argc, char **argv);
91 #ifdef HAVE_SYS_QUOTA_H
92 static int lfs_setquota(int argc, char **argv);
93 static int lfs_quota(int argc, char **argv);
94 static int lfs_project(int argc, char **argv);
95 #endif
96 static int lfs_flushctx(int argc, char **argv);
97 static int lfs_cp(int argc, char **argv);
98 static int lfs_ls(int argc, char **argv);
99 static int lfs_poollist(int argc, char **argv);
100 static int lfs_changelog(int argc, char **argv);
101 static int lfs_changelog_clear(int argc, char **argv);
102 static int lfs_fid2path(int argc, char **argv);
103 static int lfs_path2fid(int argc, char **argv);
104 static int lfs_data_version(int argc, char **argv);
105 static int lfs_hsm_state(int argc, char **argv);
106 static int lfs_hsm_set(int argc, char **argv);
107 static int lfs_hsm_clear(int argc, char **argv);
108 static int lfs_hsm_action(int argc, char **argv);
109 static int lfs_hsm_archive(int argc, char **argv);
110 static int lfs_hsm_restore(int argc, char **argv);
111 static int lfs_hsm_release(int argc, char **argv);
112 static int lfs_hsm_remove(int argc, char **argv);
113 static int lfs_hsm_cancel(int argc, char **argv);
114 static int lfs_swap_layouts(int argc, char **argv);
115 static int lfs_mv(int argc, char **argv);
116 static int lfs_ladvise(int argc, char **argv);
117 static int lfs_mirror(int argc, char **argv);
118 static int lfs_mirror_list_commands(int argc, char **argv);
119 static int lfs_list_commands(int argc, char **argv);
120 static inline int lfs_mirror_resync(int argc, char **argv);
121 static inline int lfs_mirror_verify(int argc, char **argv);
122
123 enum setstripe_origin {
124         SO_SETSTRIPE,
125         SO_MIGRATE,
126         SO_MIRROR_CREATE,
127         SO_MIRROR_EXTEND
128 };
129 static int lfs_setstripe0(int argc, char **argv, enum setstripe_origin opc);
130
131 static inline int lfs_setstripe(int argc, char **argv)
132 {
133         return lfs_setstripe0(argc, argv, SO_SETSTRIPE);
134 }
135 static inline int lfs_setstripe_migrate(int argc, char **argv)
136 {
137         return lfs_setstripe0(argc, argv, SO_MIGRATE);
138 }
139 static inline int lfs_mirror_create(int argc, char **argv)
140 {
141         return lfs_setstripe0(argc, argv, SO_MIRROR_CREATE);
142 }
143 static inline int lfs_mirror_extend(int argc, char **argv)
144 {
145         return lfs_setstripe0(argc, argv, SO_MIRROR_EXTEND);
146 }
147
148 /* Setstripe and migrate share mostly the same parameters */
149 #define SSM_CMD_COMMON(cmd) \
150         "usage: "cmd" [--component-end|-E <comp_end>]\n"                \
151         "                 [--stripe-count|-c <stripe_count>]\n"         \
152         "                 [--stripe-index|-i <start_ost_idx>]\n"        \
153         "                 [--stripe-size|-S <stripe_size>]\n"           \
154         "                 [--layout|-L <pattern>]\n"            \
155         "                 [--pool|-p <pool_name>]\n"                    \
156         "                 [--ost|-o <ost_indices>]\n"
157
158 #define SSM_HELP_COMMON \
159         "\tstripe_count: Number of OSTs to stripe over (0=fs default, -1 all)\n" \
160         "\tstart_ost_idx: OST index of first stripe (-1=default round robin)\n"\
161         "\tstripe_size:  Number of bytes on each OST (0=fs default)\n" \
162         "\t              Can be specified with K, M or G (for KB, MB, GB\n" \
163         "\t              respectively)\n"                               \
164         "\tpool_name:    Name of OST pool to use (default none)\n"      \
165         "\tlayout:       stripe pattern type: raid0, mdt (default raid0)\n"\
166         "\tost_indices:  List of OST indices, can be repeated multiple times\n"\
167         "\t              Indices be specified in a format of:\n"        \
168         "\t                -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n"        \
169         "\t              Or:\n"                                         \
170         "\t                -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n"  \
171         "\t              If --pool is set with --ost, then the OSTs\n"  \
172         "\t              must be the members of the pool.\n"            \
173         "\tcomp_end:     Extent end of component, start after previous end.\n"\
174         "\t              Can be specified with K, M or G (for KB, MB, GB\n" \
175         "\t              respectively, -1 for EOF). Must be a multiple of\n"\
176         "\t              stripe_size.\n"
177
178 #define MIRROR_CREATE_HELP                                                     \
179         "\tmirror_count: Number of mirrors to be created with the upcoming\n"  \
180         "\t              setstripe layout options\n"                           \
181         "\t              It defaults to 1 if not specified; if specified,\n"   \
182         "\t              it must follow the option without a space.\n"         \
183         "\t              The option can also be repeated multiple times to\n"  \
184         "\t              separate mirrors that have different layouts.\n"      \
185         "\tsetstripe options: Mirror layout\n"                                 \
186         "\t              It can be a plain layout or a composite layout.\n"    \
187         "\t              If not specified, the stripe options inherited\n"     \
188         "\t              from the previous component will be used.\n"          \
189         "\tparent:       Use default stripe options from parent directory\n"   \
190         "\tflags:        set flags to the component of the current mirror.\n"  \
191         "\t              Only \"prefer\" flag is supported so far.\n"
192
193 #define MIRROR_EXTEND_HELP                                                     \
194         MIRROR_CREATE_HELP                                                     \
195         "\tvictim_file:  The layout of victim_file will be split and used\n"   \
196         "\t              as a mirror added to the mirrored file.\n"            \
197         "\tno-verify:    This option indicates not to verify the mirror(s)\n"  \
198         "\t              from victim file(s) in case the victim file(s)\n"     \
199         "\t              contains the same data as the original mirrored\n"    \
200         "\t              file.\n"
201
202 #define MIRROR_EXTEND_USAGE                                                    \
203         "                 <--mirror-count|-N[mirror_count]>\n"                 \
204         "                 [setstripe options|--parent|-f <victim_file>]\n"     \
205         "                 [--no-verify]\n"
206
207 #define SETSTRIPE_USAGE                                                 \
208         SSM_CMD_COMMON("setstripe")                                     \
209         MIRROR_EXTEND_USAGE                                             \
210         "                 <directory|filename>\n"                       \
211         SSM_HELP_COMMON                                                 \
212         MIRROR_EXTEND_HELP
213
214 #define MIGRATE_USAGE                                                   \
215         SSM_CMD_COMMON("migrate  ")                                     \
216         "                 [--block|-b]\n"                               \
217         "                 [--non-block|-n]\n"                           \
218         "                 <filename>\n"                                 \
219         SSM_HELP_COMMON                                                 \
220         "\n"                                                            \
221         "\tblock:        Block file access during data migration (default)\n" \
222         "\tnon-block:    Abort migrations if concurrent access is detected\n" \
223
224 #define SETDIRSTRIPE_USAGE                                      \
225         "               [--mdt-count|-c stripe_count>\n"        \
226         "               [--mdt-index|-i mdt_index]\n"           \
227         "               [--mdt-hash|-H mdt_hash]\n"             \
228         "               [--default|-D] [--mode|-m mode] <dir>\n"        \
229         "\tstripe_count: stripe count of the striped directory\n"       \
230         "\tmdt_index: MDT index of first stripe\n"                      \
231         "\tmdt_hash:  hash type of the striped directory. mdt types:\n" \
232         "       fnv_1a_64 FNV-1a hash algorithm (default)\n"            \
233         "       all_char  sum of characters % MDT_COUNT (not recommended)\n" \
234         "\tdefault_stripe: set default dirstripe of the directory\n"    \
235         "\tmode: the mode of the directory\n"
236
237 /**
238  * command_t mirror_cmdlist - lfs mirror commands.
239  */
240 command_t mirror_cmdlist[] = {
241         { .pc_name = "create", .pc_func = lfs_mirror_create,
242           .pc_help = "Create a mirrored file.\n"
243                 "usage: lfs mirror create "
244                 "<--mirror-count|-N[mirror_count]> "
245                 "[setstripe options|--parent] ... <filename|directory>\n"
246           MIRROR_CREATE_HELP },
247         { .pc_name = "extend", .pc_func = lfs_mirror_extend,
248           .pc_help = "Extend a mirrored file.\n"
249                 "usage: lfs mirror extend "
250                 "<--mirror-count|-N[mirror_count]> [--no-verify] "
251                 "[setstripe options|--parent|-f <victim_file>] ... <filename>\n"
252           MIRROR_EXTEND_HELP },
253         { .pc_name = "resync", .pc_func = lfs_mirror_resync,
254           .pc_help = "Resynchronizes out-of-sync mirrored file(s).\n"
255                 "usage: lfs mirror resync [--only <mirror_id[,...]>] "
256                 "<mirrored file> [<mirrored file2>...]\n"},
257         { .pc_name = "verify", .pc_func = lfs_mirror_verify,
258           .pc_help = "Verify mirrored file(s).\n"
259                 "usage: lfs mirror verify "
260                 "[--only <mirror_id,mirror_id2[,...]>] "
261                 "[--verbose|-v] <mirrored_file> [<mirrored_file2> ...]\n"},
262         { .pc_name = "--list-commands", .pc_func = lfs_mirror_list_commands,
263           .pc_help = "list commands supported by lfs mirror"},
264         { .pc_name = "help", .pc_func = Parser_help, .pc_help = "help" },
265         { .pc_name = "exit", .pc_func = Parser_quit, .pc_help = "quit" },
266         { .pc_name = "quit", .pc_func = Parser_quit, .pc_help = "quit" },
267         { .pc_help = NULL }
268 };
269
270 /* all available commands */
271 command_t cmdlist[] = {
272         {"setstripe", lfs_setstripe, 0,
273          "To create a file with specified striping/composite layout, or\n"
274          "create/replace the default layout on an existing directory:\n"
275          SSM_CMD_COMMON("setstripe")
276          "                 <directory|filename>\n"
277          " or\n"
278          "To add component(s) to an existing composite file:\n"
279          SSM_CMD_COMMON("setstripe --component-add")
280          SSM_HELP_COMMON
281          "To totally delete the default striping from an existing directory:\n"
282          "usage: setstripe -d <directory>\n"
283          " or\n"
284          "To delete the last component(s) from an existing composite file\n"
285          "(note that this will also delete any data in those components):\n"
286          "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
287          "                               [--component-flags|-F <comp_flags>]\n"
288          "                               <filename>\n"
289          "\tcomp_id:     Unique component ID to delete\n"
290          "\tcomp_flags:  'init' indicating all instantiated components\n"
291          "\t             '^init' indicating all uninstantiated components\n"
292          "\t-I and -F cannot be specified at the same time\n"},
293         {"getstripe", lfs_getstripe, 0,
294          "To list the layout pattern for a given file or files in a\n"
295          "directory or recursively for all files in a directory tree.\n"
296          "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
297          "                 [--stripe-count|-c] [--stripe-index|-i] [--fid|-F]\n"
298          "                 [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
299          "                 [--mdt-index|-m] [--recursive|-r] [--raw|-R]\n"
300          "                 [--layout|-L] [--generation|-g] [--yaml|-y]\n"
301          "                 [--component-id[=comp_id]|-I[comp_id]]\n"
302          "                 [--component-flags[=comp_flags]]\n"
303          "                 [--component-count]\n"
304          "                 [--component-start[=[+-]comp_start]]\n"
305          "                 [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
306          "                 <directory|filename> ..."},
307         {"setdirstripe", lfs_setdirstripe, 0,
308          "To create a striped directory on a specified MDT. This can only\n"
309          "be done on MDT0 with the right of administrator.\n"
310          "usage: setdirstripe [OPTION] <directory>\n"
311          SETDIRSTRIPE_USAGE},
312         {"getdirstripe", lfs_getdirstripe, 0,
313          "To list the layout pattern info for a given directory\n"
314          "or recursively for all directories in a directory tree.\n"
315          "usage: getdirstripe [--mdt-count|-c] [--mdt-index|-m|-i]\n"
316          "                    [--mdt-hash|-H] [--obd|-O <uuid>]\n"
317          "                    [--recursive|-r] [--yaml|-y]\n"
318          "                    [--default|-D] <dir> ..."},
319         {"mkdir", lfs_setdirstripe, 0,
320          "To create a striped directory on a specified MDT. This can only\n"
321          "be done on MDT0 with the right of administrator.\n"
322          "usage: mkdir [OPTION] <directory>\n"
323          SETDIRSTRIPE_USAGE},
324         {"rm_entry", lfs_rmentry, 0,
325          "To remove the name entry of the remote directory. Note: This\n"
326          "command will only delete the name entry, i.e. the remote directory\n"
327          "will become inaccessable after this command. This can only be done\n"
328          "by the administrator\n"
329          "usage: rm_entry <dir>\n"},
330         {"pool_list", lfs_poollist, 0,
331          "List pools or pool OSTs\n"
332          "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
333         {"find", lfs_find, 0,
334          "find files matching given attributes recursively in directory tree.\n"
335          "usage: find <directory|filename> ...\n"
336          "     [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
337          "     [[!] --mtime|-M [+-]N] [--maxdepth|-D N]\n"
338          "     [[!] --mdt-index|--mdt|-m <uuid|index,...>]\n"
339          "     [[!] --name|-n <pattern>] [[!] --ost|-O <uuid|index,...>]\n"
340          "     [--print|-P] [--print0|-0] [[!] --size|-s [+-]N[bkMGTPE]]\n"
341          "     [[!] --stripe-count|-c [+-]<stripes>]\n"
342          "     [[!] --stripe-index|-i <index,...>]\n"
343          "     [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
344          "     [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
345          "     [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
346          "     [[!] --projid <projid>]\n"
347          "     [[!] --layout|-L released,raid0,mdt]\n"
348          "     [[!] --component-count [+-]<comp_cnt>]\n"
349          "     [[!] --component-start [+-]N[kMGTPE]]\n"
350          "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
351          "     [[!] --component-flags <comp_flags>]\n"
352          "     [[!] --mdt-count|-T [+-]<stripes>]\n"
353          "     [[!] --mdt-hash|-H <hashtype>\n"
354          "\t !: used before an option indicates 'NOT' requested attribute\n"
355          "\t -: used before a value indicates less than requested value\n"
356          "\t +: used before a value indicates more than requested value\n"
357          "\thashtype:   hash type of the striped directory.\n"
358          "\t            fnv_1a_64 FNV-1a hash algorithm\n"
359          "\t            all_char  sum of characters % MDT_COUNT\n"},
360         {"check", lfs_check, 0,
361          "Display the status of MDS or OSTs (as specified in the command)\n"
362          "or all the servers (MDS and OSTs).\n"
363          "usage: check <osts|mds|servers>"},
364         {"osts", lfs_osts, 0, "list OSTs connected to client "
365          "[for specified path only]\n" "usage: osts [path]"},
366         {"mdts", lfs_mdts, 0, "list MDTs connected to client "
367          "[for specified path only]\n" "usage: mdts [path]"},
368         {"df", lfs_df, 0,
369          "report filesystem disk space usage or inodes usage"
370          "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
371          "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
372         {"getname", lfs_getname, 0, "list instances and specified mount points "
373          "[for specified path only]\n"
374          "Usage: getname [-h]|[path ...] "},
375 #ifdef HAVE_SYS_QUOTA_H
376         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
377          "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
378          "                -b <block-softlimit> -B <block-hardlimit>\n"
379          "                -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
380          "       setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
381          "                [--block-softlimit <block-softlimit>]\n"
382          "                [--block-hardlimit <block-hardlimit>]\n"
383          "                [--inode-softlimit <inode-softlimit>]\n"
384          "                [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
385          "       setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
386          "                [--block-grace <block-grace>]\n"
387          "                [--inode-grace <inode-grace>] <filesystem>\n"
388          "       -b can be used instead of --block-softlimit/--block-grace\n"
389          "       -B can be used instead of --block-hardlimit\n"
390          "       -i can be used instead of --inode-softlimit/--inode-grace\n"
391          "       -I can be used instead of --inode-hardlimit\n\n"
392          "Note: The total quota space will be split into many qunits and\n"
393          "      balanced over all server targets, the minimal qunit size is\n"
394          "      1M bytes for block space and 1K inodes for inode space.\n\n"
395          "      Quota space rebalancing process will stop when this mininum\n"
396          "      value is reached. As a result, quota exceeded can be returned\n"
397          "      while many targets still have 1MB or 1K inodes of spare\n"
398          "      quota space."},
399         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
400          "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
401                        "<ost_idx>]\n"
402          "             [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
403          "       quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
404         {"project", lfs_project, 0,
405          "Change or list project attribute for specified file or directory.\n"
406          "usage: project [-d|-r] <file|directory...>\n"
407          "         list project ID and flags on file(s) or directories\n"
408          "       project [-p id] [-s] [-r] <file|directory...>\n"
409          "         set project ID and/or inherit flag for specified file(s) or directories\n"
410          "       project -c [-d|-r [-p id] [-0]] <file|directory...>\n"
411          "         check project ID and flags on file(s) or directories, print outliers\n"
412          "       project -C [-r] [-k] <file|directory...>\n"
413          "         clear the project inherit flag and ID on the file or directory\n"
414         },
415 #endif
416         {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
417          "usage: flushctx [-k] [mountpoint...]"},
418         {"cp", lfs_cp, 0,
419          "Remote user copy files and directories.\n"
420          "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
421         {"ls", lfs_ls, 0,
422          "Remote user list directory contents.\n"
423          "usage: ls [OPTION]... [FILE]..."},
424         {"changelog", lfs_changelog, 0,
425          "Show the metadata changes on an MDT."
426          "\nusage: changelog <mdtname> [startrec [endrec]]"},
427         {"changelog_clear", lfs_changelog_clear, 0,
428          "Indicate that old changelog records up to <endrec> are no longer of "
429          "interest to consumer <id>, allowing the system to free up space.\n"
430          "An <endrec> of 0 means all records.\n"
431          "usage: changelog_clear <mdtname> <id> <endrec>"},
432         {"fid2path", lfs_fid2path, 0,
433          "Resolve the full path(s) for given FID(s). For a specific hardlink "
434          "specify link number <linkno>.\n"
435         /* "For a historical link name, specify changelog record <recno>.\n" */
436          "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
437                 /* [ --rec <recno> ] */ },
438         {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
439          "usage: path2fid [--parents] <path> ..."},
440         {"data_version", lfs_data_version, 0, "Display file data version for "
441          "a given path.\n" "usage: data_version -[n|r|w] <path>"},
442         {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
443          "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
444         {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
445          "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
446          "[--archived] [--lost] [--archive-id NUM] <file> ..."},
447         {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
448          "files.\n"
449          "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
450          "[--archived] [--lost] <file> ..."},
451         {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
452          "given files.\n" "usage: hsm_action <file> ..."},
453         {"hsm_archive", lfs_hsm_archive, 0,
454          "Archive file to external storage.\n"
455          "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
456          "<file> ..."},
457         {"hsm_restore", lfs_hsm_restore, 0,
458          "Restore file from external storage.\n"
459          "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
460         {"hsm_release", lfs_hsm_release, 0,
461          "Release files from Lustre.\n"
462          "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
463         {"hsm_remove", lfs_hsm_remove, 0,
464          "Remove file copy from external storage.\n"
465          "usage: hsm_remove [--filelist FILELIST] [--data DATA] "
466          "[--archive NUM]\n"
467          "                  (FILE [FILE ...] | "
468          "--mntpath MOUNTPATH FID [FID ...])\n"
469          "\n"
470          "Note: To remove an archived copy of a file already deleted from a "
471          "Lustre FS, the\n"
472          "--mntpath option and a list of FIDs must be specified"
473         },
474         {"hsm_cancel", lfs_hsm_cancel, 0,
475          "Cancel requests related to specified files.\n"
476          "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
477         {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
478          "usage: swap_layouts <path1> <path2>"},
479         {"migrate", lfs_setstripe_migrate, 0,
480          "migrate a directory between MDTs.\n"
481          "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
482          "<directory>\n"
483          "\tmdt_idx:      index of the destination MDT\n"
484          "\n"
485          "migrate file objects from one OST "
486          "layout\nto another (may be not safe with concurent writes).\n"
487          "usage: migrate  "
488          "[--stripe-count|-c] <stripe_count>\n"
489          "              [--stripe-index|-i] <start_ost_index>\n"
490          "              [--stripe-size|-S] <stripe_size>\n"
491          "              [--pool|-p] <pool_name>\n"
492          "              [--ost|-o] <ost_indices>\n"
493          "              [--block|-b]\n"
494          "              [--non-block|-n]\n"
495          "              <file|directory>\n"
496          "\tstripe_count:     number of OSTs to stripe a file over\n"
497          "\tstripe_ost_index: index of the first OST to stripe a file over\n"
498          "\tstripe_size:      number of bytes to store before moving to the next OST\n"
499          "\tpool_name:        name of the predefined pool of OSTs\n"
500          "\tost_indices:      OSTs to stripe over, in order\n"
501          "\tblock:            wait for the operation to return before continuing\n"
502          "\tnon-block:        do not wait for the operation to return.\n"},
503         {"mv", lfs_mv, 0,
504          "To move directories between MDTs. This command is deprecated, "
505          "use \"migrate\" instead.\n"
506          "usage: mv <directory|filename> [--mdt-index|-m] <mdt_index> "
507          "[--verbose|-v]\n"},
508         {"ladvise", lfs_ladvise, 0,
509          "Provide servers with advice about access patterns for a file.\n"
510          "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
511          "               [--background|-b] [--unset|-u]\n\n"
512          "               {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
513          "               {[--mode|-m [READ,WRITE]}\n"
514          "               <file> ...\n"},
515         {"mirror", lfs_mirror, mirror_cmdlist,
516          "lfs commands used to manage files with mirrored components:\n"
517          "lfs mirror create - create a mirrored file or directory\n"
518          "lfs mirror extend - add mirror(s) to an existing file\n"
519          "lfs mirror split  - split a mirror from an existing mirrored file\n"
520          "lfs mirror resync - resynchronize out-of-sync mirrored file(s)\n"
521          "lfs mirror verify - verify mirrored file(s)\n"},
522         {"help", Parser_help, 0, "help"},
523         {"exit", Parser_quit, 0, "quit"},
524         {"quit", Parser_quit, 0, "quit"},
525         {"--version", Parser_version, 0,
526          "output build version of the utility and exit"},
527         {"--list-commands", lfs_list_commands, 0,
528          "list commands supported by the utility and exit"},
529         { 0, 0, 0, NULL }
530 };
531
532
533 static int check_hashtype(const char *hashtype)
534 {
535         int i;
536
537         for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
538                 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
539                         return i;
540
541         return 0;
542 }
543
544
545 static const char *error_loc = "syserror";
546
547 enum {
548         MIGRATION_NONBLOCK      = 1 << 0,
549         MIGRATION_MIRROR        = 1 << 1,
550 };
551
552 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
553                                 struct llapi_layout *layout);
554
555 static int
556 migrate_open_files(const char *name, const struct llapi_stripe_param *param,
557                    struct llapi_layout *layout, int *fd_src, int *fd_tgt)
558 {
559         int                      fd = -1;
560         int                      fdv = -1;
561         int                      mdt_index;
562         int                      random_value;
563         char                     parent[PATH_MAX];
564         char                     volatile_file[PATH_MAX];
565         char                    *ptr;
566         int                      rc;
567         struct stat              st;
568         struct stat              stv;
569
570         if (param == NULL && layout == NULL) {
571                 error_loc = "layout information";
572                 return -EINVAL;
573         }
574
575         /* search for file directory pathname */
576         if (strlen(name) > sizeof(parent) - 1) {
577                 error_loc = "source file name";
578                 return -ERANGE;
579         }
580
581         strncpy(parent, name, sizeof(parent));
582         ptr = strrchr(parent, '/');
583         if (ptr == NULL) {
584                 if (getcwd(parent, sizeof(parent)) == NULL) {
585                         error_loc = "getcwd";
586                         return -errno;
587                 }
588         } else {
589                 if (ptr == parent) /* leading '/' */
590                         ptr = parent + 1;
591                 *ptr = '\0';
592         }
593
594         /* open file, direct io */
595         /* even if the file is only read, WR mode is nedeed to allow
596          * layout swap on fd */
597         fd = open(name, O_RDWR | O_DIRECT);
598         if (fd < 0) {
599                 rc = -errno;
600                 error_loc = "cannot open source file";
601                 return rc;
602         }
603
604         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
605         if (rc < 0) {
606                 error_loc = "cannot get MDT index";
607                 goto out;
608         }
609
610         do {
611                 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
612                 mode_t open_mode = S_IRUSR | S_IWUSR;
613
614                 random_value = random();
615                 rc = snprintf(volatile_file, sizeof(volatile_file),
616                               "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
617                               mdt_index, random_value);
618                 if (rc >= sizeof(volatile_file)) {
619                         rc = -ENAMETOOLONG;
620                         break;
621                 }
622
623                 /* create, open a volatile file, use caching (ie no directio) */
624                 if (param != NULL)
625                         fdv = llapi_file_open_param(volatile_file, open_flags,
626                                                     open_mode, param);
627                 else
628                         fdv = lfs_component_create(volatile_file, open_flags,
629                                                    open_mode, layout);
630         } while (fdv < 0 && (rc = fdv) == -EEXIST);
631
632         if (rc < 0) {
633                 error_loc = "cannot create volatile file";
634                 goto out;
635         }
636
637         /* In case the MDT does not support creation of volatile files
638          * we should try to unlink it. */
639         (void)unlink(volatile_file);
640
641         /* Not-owner (root?) special case.
642          * Need to set owner/group of volatile file like original.
643          * This will allow to pass related check during layout_swap.
644          */
645         rc = fstat(fd, &st);
646         if (rc != 0) {
647                 rc = -errno;
648                 error_loc = "cannot stat source file";
649                 goto out;
650         }
651
652         rc = fstat(fdv, &stv);
653         if (rc != 0) {
654                 rc = -errno;
655                 error_loc = "cannot stat volatile";
656                 goto out;
657         }
658
659         if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
660                 rc = fchown(fdv, st.st_uid, st.st_gid);
661                 if (rc != 0) {
662                         rc = -errno;
663                         error_loc = "cannot change ownwership of volatile";
664                         goto out;
665                 }
666         }
667
668 out:
669         if (rc < 0) {
670                 if (fd > 0)
671                         close(fd);
672                 if (fdv > 0)
673                         close(fdv);
674         } else {
675                 *fd_src = fd;
676                 *fd_tgt = fdv;
677                 error_loc = NULL;
678         }
679         return rc;
680 }
681
682 static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int))
683 {
684         struct llapi_layout *layout;
685         size_t   buf_size = 4 * 1024 * 1024;
686         void    *buf = NULL;
687         ssize_t  rsize = -1;
688         ssize_t  wsize = 0;
689         size_t   rpos = 0;
690         size_t   wpos = 0;
691         off_t    bufoff = 0;
692         int      rc;
693
694         layout = llapi_layout_get_by_fd(fd_src, 0);
695         if (layout != NULL) {
696                 uint64_t stripe_size;
697
698                 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
699                 if (rc == 0)
700                         buf_size = stripe_size;
701
702                 llapi_layout_free(layout);
703         }
704
705         /* Use a page-aligned buffer for direct I/O */
706         rc = posix_memalign(&buf, getpagesize(), buf_size);
707         if (rc != 0)
708                 return -rc;
709
710         while (1) {
711                 /* read new data only if we have written all
712                  * previously read data */
713                 if (wpos == rpos) {
714                         if (check_file) {
715                                 rc = check_file(fd_src);
716                                 if (rc < 0)
717                                         break;
718                         }
719
720                         rsize = read(fd_src, buf, buf_size);
721                         if (rsize < 0) {
722                                 rc = -errno;
723                                 break;
724                         }
725                         rpos += rsize;
726                         bufoff = 0;
727                 }
728                 /* eof ? */
729                 if (rsize == 0)
730                         break;
731
732                 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
733                 if (wsize < 0) {
734                         rc = -errno;
735                         break;
736                 }
737                 wpos += wsize;
738                 bufoff += wsize;
739         }
740
741         if (rc == 0) {
742                 rc = fsync(fd_dst);
743                 if (rc < 0)
744                         rc = -errno;
745         }
746
747         free(buf);
748         return rc;
749 }
750
751 static int migrate_copy_timestamps(int fd, int fdv)
752 {
753         struct stat st;
754
755         if (fstat(fd, &st) == 0) {
756                 struct timeval tv[2] = {
757                         {.tv_sec = st.st_atime},
758                         {.tv_sec = st.st_mtime}
759                 };
760
761                 return futimes(fdv, tv);
762         }
763
764         return -errno;
765 }
766
767 static int migrate_block(int fd, int fdv)
768 {
769         __u64   dv1;
770         int     gid;
771         int     rc;
772         int     rc2;
773
774         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
775         if (rc < 0) {
776                 error_loc = "cannot get dataversion";
777                 return rc;
778         }
779
780         do
781                 gid = random();
782         while (gid == 0);
783
784         /* The grouplock blocks all concurrent accesses to the file.
785          * It has to be taken after llapi_get_data_version as it would
786          * block it too. */
787         rc = llapi_group_lock(fd, gid);
788         if (rc < 0) {
789                 error_loc = "cannot get group lock";
790                 return rc;
791         }
792
793         rc = migrate_copy_data(fd, fdv, NULL);
794         if (rc < 0) {
795                 error_loc = "data copy failed";
796                 goto out_unlock;
797         }
798
799         /* Make sure we keep original atime/mtime values */
800         rc = migrate_copy_timestamps(fd, fdv);
801         if (rc < 0) {
802                 error_loc = "timestamp copy failed";
803                 goto out_unlock;
804         }
805
806         /* swap layouts
807          * for a migration we need to check data version on file did
808          * not change.
809          *
810          * Pass in gid=0 since we already own grouplock. */
811         rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
812                                            SWAP_LAYOUTS_CHECK_DV1);
813         if (rc == -EAGAIN) {
814                 error_loc = "file changed";
815                 goto out_unlock;
816         } else if (rc < 0) {
817                 error_loc = "cannot swap layout";
818                 goto out_unlock;
819         }
820
821 out_unlock:
822         rc2 = llapi_group_unlock(fd, gid);
823         if (rc2 < 0 && rc == 0) {
824                 error_loc = "unlock group lock";
825                 rc = rc2;
826         }
827
828         return rc;
829 }
830
831 /**
832  * Internal helper for migrate_copy_data(). Check lease and report error if
833  * need be.
834  *
835  * \param[in]  fd           File descriptor on which to check the lease.
836  *
837  * \retval 0       Migration can keep on going.
838  * \retval -errno  Error occurred, abort migration.
839  */
840 static int check_lease(int fd)
841 {
842         int rc;
843
844         rc = llapi_lease_check(fd);
845         if (rc > 0)
846                 return 0; /* llapi_check_lease returns > 0 on success. */
847
848         return -EBUSY;
849 }
850
851 static int migrate_nonblock(int fd, int fdv)
852 {
853         __u64   dv1;
854         __u64   dv2;
855         int     rc;
856
857         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
858         if (rc < 0) {
859                 error_loc = "cannot get data version";
860                 return rc;
861         }
862
863         rc = migrate_copy_data(fd, fdv, check_lease);
864         if (rc < 0) {
865                 error_loc = "data copy failed";
866                 return rc;
867         }
868
869         rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
870         if (rc != 0) {
871                 error_loc = "cannot get data version";
872                 return rc;
873         }
874
875         if (dv1 != dv2) {
876                 rc = -EAGAIN;
877                 error_loc = "source file changed";
878                 return rc;
879         }
880
881         /* Make sure we keep original atime/mtime values */
882         rc = migrate_copy_timestamps(fd, fdv);
883         if (rc < 0) {
884                 error_loc = "timestamp copy failed";
885                 return rc;
886         }
887
888         return 0;
889 }
890
891 static int lfs_component_set(char *fname, int comp_id,
892                              __u32 flags, __u32 neg_flags)
893 {
894         __u32 ids[2];
895         __u32 flags_array[2];
896         size_t count = 0;
897         int rc;
898
899         if (flags) {
900                 ids[count] = comp_id;
901                 flags_array[count] = flags;
902                 ++count;
903         }
904
905         if (neg_flags) {
906                 ids[count] = comp_id;
907                 flags_array[count] = neg_flags | LCME_FL_NEG;
908                 ++count;
909         }
910
911         rc = llapi_layout_file_comp_set(fname, ids, flags_array, count);
912         if (rc)
913                 fprintf(stderr,
914                         "%s: cannot change the flags of component '%#x' of file '%s': %x / ^(%x)\n",
915                         progname, comp_id, fname, flags, neg_flags);
916
917         return rc;
918 }
919
920 static int lfs_component_del(char *fname, __u32 comp_id,
921                              __u32 flags, __u32 neg_flags)
922 {
923         int     rc = 0;
924
925         if (flags && neg_flags)
926                 return -EINVAL;
927
928         if (!flags && neg_flags)
929                 flags = neg_flags | LCME_FL_NEG;
930
931         if ((flags && comp_id) || (!flags && !comp_id))
932                 return -EINVAL;
933
934         /* LCME_FL_INIT is the only supported flag in PFL */
935         if (flags) {
936                 if (flags & ~LCME_KNOWN_FLAGS) {
937                         fprintf(stderr,
938                                 "%s setstripe: unknown flags %#x\n",
939                                 progname, flags);
940                         return -EINVAL;
941                 }
942         } else if (comp_id > LCME_ID_MAX) {
943                 fprintf(stderr, "%s setstripe: invalid component id %u\n",
944                         progname, comp_id);
945                 return -EINVAL;
946         }
947
948         rc = llapi_layout_file_comp_del(fname, comp_id, flags);
949         if (rc)
950                 fprintf(stderr,
951                         "%s setstripe: cannot delete component %#x from '%s': %s\n",
952                         progname, comp_id, fname, strerror(errno));
953         return rc;
954 }
955
956 static int lfs_component_add(char *fname, struct llapi_layout *layout)
957 {
958         int     rc;
959
960         if (layout == NULL)
961                 return -EINVAL;
962
963         rc = llapi_layout_file_comp_add(fname, layout);
964         if (rc)
965                 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
966                         fname, strerror(errno));
967         return rc;
968 }
969
970 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
971                                 struct llapi_layout *layout)
972 {
973         struct stat     st;
974         int     fd;
975
976         if (layout == NULL)
977                 return -EINVAL;
978
979         fd = lstat(fname, &st);
980         if (fd == 0 && S_ISDIR(st.st_mode))
981                 open_flags = O_DIRECTORY | O_RDONLY;
982
983         fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
984         if (fd < 0)
985                 fprintf(stderr, "%s: cannot %s '%s': %s\n", progname,
986                         S_ISDIR(st.st_mode) ?
987                                 "set default composite layout for" :
988                                 "create composite file",
989                         fname, strerror(errno));
990         return fd;
991 }
992
993 static int lfs_migrate(char *name, __u64 migration_flags,
994                        struct llapi_stripe_param *param,
995                        struct llapi_layout *layout)
996 {
997         int fd = -1;
998         int fdv = -1;
999         int rc;
1000
1001         rc = migrate_open_files(name, param, layout, &fd, &fdv);
1002         if (rc < 0)
1003                 goto out;
1004
1005         if (!(migration_flags & MIGRATION_NONBLOCK)) {
1006                 /* Blocking mode (forced if servers do not support file lease).
1007                  * It is also the default mode, since we cannot distinguish
1008                  * between a broken lease and a server that does not support
1009                  * atomic swap/close (LU-6785) */
1010                 rc = migrate_block(fd, fdv);
1011                 goto out;
1012         }
1013
1014         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1015         if (rc < 0) {
1016                 error_loc = "cannot get lease";
1017                 goto out;
1018         }
1019
1020         rc = migrate_nonblock(fd, fdv);
1021         if (rc < 0) {
1022                 llapi_lease_release(fd);
1023                 goto out;
1024         }
1025
1026         /* Atomically put lease, swap layouts and close.
1027          * for a migration we need to check data version on file did
1028          * not change. */
1029         rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
1030         if (rc < 0) {
1031                 error_loc = "cannot swap layout";
1032                 goto out;
1033         }
1034
1035 out:
1036         if (fd >= 0)
1037                 close(fd);
1038
1039         if (fdv >= 0)
1040                 close(fdv);
1041
1042         if (rc < 0)
1043                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1044                         progname, name, error_loc, strerror(-rc));
1045         return rc;
1046 }
1047
1048 static int comp_str2flags(char *string, __u32 *flags, __u32 *neg_flags)
1049 {
1050         char *name;
1051
1052         if (string == NULL)
1053                 return -EINVAL;
1054
1055         *flags = 0;
1056         *neg_flags = 0;
1057         for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1058                 bool found = false;
1059                 int i;
1060
1061                 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1062                         __u32 comp_flag = comp_flags_table[i].cfn_flag;
1063                         const char *comp_name = comp_flags_table[i].cfn_name;
1064
1065                         if (strcmp(name, comp_name) == 0) {
1066                                 *flags |= comp_flag;
1067                                 found = true;
1068                         } else if (strncmp(name, "^", 1) == 0 &&
1069                                    strcmp(name + 1, comp_name) == 0) {
1070                                 *neg_flags |= comp_flag;
1071                                 found = true;
1072                         }
1073                 }
1074                 if (!found) {
1075                         llapi_printf(LLAPI_MSG_ERROR,
1076                                      "%s: component flag '%s' not supported\n",
1077                                      progname, name);
1078                         return -EINVAL;
1079                 }
1080         }
1081
1082         if (!*flags && !*neg_flags)
1083                 return -EINVAL;
1084
1085         /* don't allow to set and exclude the same flag */
1086         if (*flags & *neg_flags)
1087                 return -EINVAL;
1088
1089         return 0;
1090 }
1091
1092 /**
1093  * struct mirror_args - Command-line arguments for mirror(s).
1094  * @m_count:  Number of mirrors to be created with this layout.
1095  * @m_flags:  Mirror level flags, only 'prefer' is supported.
1096  * @m_layout: Mirror layout.
1097  * @m_file:   A victim file. Its layout will be split and used as a mirror.
1098  * @m_next:   Point to the next node of the list.
1099  *
1100  * Command-line arguments for mirror(s) will be parsed and stored in
1101  * a linked list that consists of this structure.
1102  */
1103 struct mirror_args {
1104         __u32                   m_count;
1105         __u32                   m_flags;
1106         struct llapi_layout     *m_layout;
1107         const char              *m_file;
1108         struct mirror_args      *m_next;
1109 };
1110
1111 static int mirror_sanity_check_flags(struct llapi_layout *layout, void *unused)
1112 {
1113         uint32_t flags;
1114         int rc;
1115
1116         rc = llapi_layout_comp_flags_get(layout, &flags);
1117         if (rc)
1118                 return -errno;
1119
1120         if (flags & LCME_FL_NEG) {
1121                 fprintf(stderr, "error: %s: negative flags are not supported\n",
1122                         progname);
1123                 return -EINVAL;
1124         }
1125
1126         if (flags & LCME_FL_STALE) {
1127                 fprintf(stderr, "error: %s: setting '%s' is not supported\n",
1128                         progname, comp_flags_table[LCME_FL_STALE].cfn_name);
1129                 return -EINVAL;
1130         }
1131
1132         return LLAPI_LAYOUT_ITER_CONT;
1133 }
1134
1135 static inline int mirror_sanity_check_one(struct llapi_layout *layout)
1136 {
1137         uint64_t start, end;
1138         uint64_t pattern;
1139         int rc;
1140
1141         /* LU-10112: do not support dom+flr in phase 1 */
1142         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1143         if (rc)
1144                 return -errno;
1145
1146         rc = llapi_layout_pattern_get(layout, &pattern);
1147         if (rc)
1148                 return -errno;
1149
1150         if (pattern == LOV_PATTERN_MDT || pattern == LLAPI_LAYOUT_MDT) {
1151                 fprintf(stderr, "error: %s: doesn't support dom+flr for now\n",
1152                         progname);
1153                 return -ENOTSUP;
1154         }
1155
1156         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_LAST);
1157         if (rc)
1158                 return -errno;
1159
1160         rc = llapi_layout_comp_extent_get(layout, &start, &end);
1161         if (rc)
1162                 return -errno;
1163
1164         if (end != LUSTRE_EOF) {
1165                 fprintf(stderr, "error: %s: mirror layout doesn't reach eof\n",
1166                         progname);
1167                 return -EINVAL;
1168         }
1169
1170         rc = llapi_layout_comp_iterate(layout, mirror_sanity_check_flags, NULL);
1171         return rc;
1172 }
1173
1174 /**
1175  * enum mirror_flags - Flags for extending a mirrored file.
1176  * @NO_VERIFY: Indicates not to verify the mirror(s) from victim file(s)
1177  *             in case the victim file(s) contains the same data as the
1178  *             original mirrored file.
1179  *
1180  * Flags for extending a mirrored file.
1181  */
1182 enum mirror_flags {
1183         NO_VERIFY       = 0x1,
1184 };
1185
1186 /**
1187  * mirror_create_sanity_check() - Check mirror list.
1188  * @list:  A linked list that stores the mirror arguments.
1189  *
1190  * This function does a sanity check on @list for creating
1191  * a mirrored file.
1192  *
1193  * Return: 0 on success or a negative error code on failure.
1194  */
1195 static int mirror_create_sanity_check(const char *fname,
1196                                       struct mirror_args *list)
1197 {
1198         int rc = 0;
1199         bool has_m_file = false;
1200         bool has_m_layout = false;
1201
1202         if (list == NULL)
1203                 return -EINVAL;
1204
1205         if (fname) {
1206                 struct llapi_layout *layout;
1207
1208                 layout = llapi_layout_get_by_path(fname, 0);
1209                 if (!layout) {
1210                         fprintf(stderr,
1211                                 "error: %s: file '%s' couldn't get layout\n",
1212                                 progname, fname);
1213                         return -ENODATA;
1214                 }
1215
1216                 rc = mirror_sanity_check_one(layout);
1217                 llapi_layout_free(layout);
1218
1219                 if (rc)
1220                         return rc;
1221         }
1222
1223         while (list != NULL) {
1224                 if (list->m_file != NULL) {
1225                         has_m_file = true;
1226                         llapi_layout_free(list->m_layout);
1227
1228                         list->m_layout =
1229                                 llapi_layout_get_by_path(list->m_file, 0);
1230                         if (list->m_layout == NULL) {
1231                                 fprintf(stderr,
1232                                         "error: %s: file '%s' has no layout\n",
1233                                         progname, list->m_file);
1234                                 return -ENODATA;
1235                         }
1236                 } else {
1237                         has_m_layout = true;
1238                         if (list->m_layout == NULL) {
1239                                 fprintf(stderr, "error: %s: no mirror layout\n",
1240                                         progname);
1241                                 return -EINVAL;
1242                         }
1243                 }
1244
1245                 rc = mirror_sanity_check_one(list->m_layout);
1246                 if (rc)
1247                         return rc;
1248
1249                 list = list->m_next;
1250         }
1251
1252         if (has_m_file && has_m_layout) {
1253                 fprintf(stderr, "error: %s: -f <victim_file> option should not "
1254                         "be specified with setstripe options or "
1255                         "--parent option\n", progname);
1256                 return -EINVAL;
1257         }
1258
1259         return 0;
1260 }
1261
1262 static int mirror_set_flags(struct llapi_layout *layout, void *cbdata)
1263 {
1264         __u32 mirror_flags = *(__u32 *)cbdata;
1265         uint32_t flags;
1266         int rc;
1267
1268         rc = llapi_layout_comp_flags_get(layout, &flags);
1269         if (rc < 0)
1270                 return rc;
1271
1272         if (!flags) {
1273                 rc = llapi_layout_comp_flags_set(layout, mirror_flags);
1274                 if (rc)
1275                         return rc;
1276         }
1277
1278         return LLAPI_LAYOUT_ITER_CONT;
1279 }
1280
1281 /**
1282  * mirror_create() - Create a mirrored file.
1283  * @fname:        The file to be created.
1284  * @mirror_list:  A linked list that stores the mirror arguments.
1285  *
1286  * This function creates a mirrored file @fname with the mirror(s)
1287  * from @mirror_list.
1288  *
1289  * Return: 0 on success or a negative error code on failure.
1290  */
1291 static int mirror_create(char *fname, struct mirror_args *mirror_list)
1292 {
1293         struct llapi_layout *layout = NULL;
1294         struct mirror_args *cur_mirror = NULL;
1295         uint16_t mirror_count = 0;
1296         int i = 0;
1297         int rc = 0;
1298
1299         rc = mirror_create_sanity_check(NULL, mirror_list);
1300         if (rc)
1301                 return rc;
1302
1303         cur_mirror = mirror_list;
1304         while (cur_mirror != NULL) {
1305                 rc = llapi_layout_comp_iterate(cur_mirror->m_layout,
1306                                                mirror_set_flags,
1307                                                &cur_mirror->m_flags);
1308                 if (rc) {
1309                         rc = -errno;
1310                         fprintf(stderr, "%s: failed to set mirror flags\n",
1311                                 progname);
1312                         goto error;
1313                 }
1314
1315                 for (i = 0; i < cur_mirror->m_count; i++) {
1316                         rc = llapi_layout_merge(&layout, cur_mirror->m_layout);
1317                         if (rc) {
1318                                 rc = -errno;
1319                                 fprintf(stderr, "error: %s: "
1320                                         "merge layout failed: %s\n",
1321                                         progname, strerror(errno));
1322                                 goto error;
1323                         }
1324                 }
1325                 mirror_count += cur_mirror->m_count;
1326                 cur_mirror = cur_mirror->m_next;
1327         }
1328
1329         if (layout == NULL) {
1330                 fprintf(stderr, "error: %s: layout is NULL\n", progname);
1331                 return -EINVAL;
1332         }
1333
1334         rc = llapi_layout_mirror_count_set(layout, mirror_count);
1335         if (rc) {
1336                 rc = -errno;
1337                 fprintf(stderr, "error: %s: set mirror count failed: %s\n",
1338                         progname, strerror(errno));
1339                 goto error;
1340         }
1341
1342         rc = lfs_component_create(fname, O_CREAT | O_WRONLY, 0644,
1343                                   layout);
1344         if (rc >= 0) {
1345                 close(rc);
1346                 rc = 0;
1347         }
1348
1349 error:
1350         llapi_layout_free(layout);
1351         return rc;
1352 }
1353
1354 /**
1355  * Compare files and check lease on @fd.
1356  *
1357  * \retval bytes number of bytes are the same
1358  */
1359 static ssize_t mirror_file_compare(int fd, int fdv)
1360 {
1361         const size_t buflen = 4 * 1024 * 1024; /* 4M */
1362         void *buf;
1363         ssize_t bytes_done = 0;
1364         ssize_t bytes_read = 0;
1365
1366         buf = malloc(buflen * 2);
1367         if (!buf)
1368                 return -ENOMEM;
1369
1370         while (1) {
1371                 if (!llapi_lease_check(fd)) {
1372                         bytes_done = -EBUSY;
1373                         break;
1374                 }
1375
1376                 bytes_read = read(fd, buf, buflen);
1377                 if (bytes_read <= 0)
1378                         break;
1379
1380                 if (bytes_read != read(fdv, buf + buflen, buflen))
1381                         break;
1382
1383                 /* XXX: should compute the checksum on each buffer and then
1384                  * compare checksum to avoid cache collision */
1385                 if (memcmp(buf, buf + buflen, bytes_read))
1386                         break;
1387
1388                 bytes_done += bytes_read;
1389         }
1390
1391         free(buf);
1392
1393         return bytes_done;
1394 }
1395
1396 static int mirror_extend_file(const char *fname, const char *victim_file,
1397                               enum mirror_flags mirror_flags)
1398 {
1399         int fd = -1;
1400         int fdv = -1;
1401         struct stat stbuf;
1402         struct stat stbuf_v;
1403         struct ll_ioc_lease *data = NULL;
1404         int rc;
1405
1406         fd = open(fname, O_RDWR);
1407         if (fd < 0) {
1408                 error_loc = "open source file";
1409                 rc = -errno;
1410                 goto out;
1411         }
1412
1413         fdv = open(victim_file, O_RDWR);
1414         if (fdv < 0) {
1415                 error_loc = "open target file";
1416                 rc = -errno;
1417                 goto out;
1418         }
1419
1420         if (fstat(fd, &stbuf) || fstat(fdv, &stbuf_v)) {
1421                 error_loc = "stat source or target file";
1422                 rc = -errno;
1423                 goto out;
1424         }
1425
1426         if (stbuf.st_dev != stbuf_v.st_dev) {
1427                 error_loc = "stat source and target file";
1428                 rc = -EXDEV;
1429                 goto out;
1430         }
1431
1432         /* mirrors should be of the same size */
1433         if (stbuf.st_size != stbuf_v.st_size) {
1434                 error_loc = "file sizes don't match";
1435                 rc = -EINVAL;
1436                 goto out;
1437         }
1438
1439         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1440         if (rc < 0) {
1441                 error_loc = "cannot get lease";
1442                 goto out;
1443         }
1444
1445         if (!(mirror_flags & NO_VERIFY)) {
1446                 ssize_t ret;
1447                 /* mirrors should have the same contents */
1448                 ret = mirror_file_compare(fd, fdv);
1449                 if (ret != stbuf.st_size) {
1450                         error_loc = "file busy or contents don't match";
1451                         rc = ret < 0 ? ret : -EINVAL;
1452                         goto out;
1453                 }
1454         }
1455
1456         /* Get rid of caching pages from clients */
1457         rc = llapi_file_flush(fd);
1458         if (rc < 0) {
1459                 error_loc = "cannot get data version";
1460                 goto out;
1461         }
1462
1463         rc = llapi_file_flush(fdv);
1464         if (rc < 0) {
1465                 error_loc = "cannot get data version";
1466                 goto out;
1467
1468         }
1469
1470         /* Make sure we keep original atime/mtime values */
1471         rc = migrate_copy_timestamps(fd, fdv);
1472         if (rc < 0) {
1473                 error_loc = "cannot copy timestamp";
1474                 goto out;
1475         }
1476
1477         /* Atomically put lease, merge layouts and close. */
1478         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
1479         if (!data) {
1480                 error_loc = "memory allocation";
1481                 goto out;
1482         }
1483         data->lil_mode = LL_LEASE_UNLCK;
1484         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
1485         data->lil_count = 1;
1486         data->lil_ids[0] = fdv;
1487         rc = llapi_lease_set(fd, data);
1488         if (rc < 0) {
1489                 error_loc = "cannot merge layout";
1490                 goto out;
1491         } else if (rc == 0) {
1492                 rc = -EBUSY;
1493                 error_loc = "lost lease lock";
1494                 goto out;
1495         }
1496         rc = 0;
1497
1498 out:
1499         if (data)
1500                 free(data);
1501         if (fd >= 0)
1502                 close(fd);
1503         if (fdv >= 0)
1504                 close(fdv);
1505         if (!rc)
1506                 (void) unlink(victim_file);
1507         if (rc < 0)
1508                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1509                         progname, fname, error_loc, strerror(-rc));
1510         return rc;
1511 }
1512
1513 static int mirror_extend_layout(char *name, struct llapi_layout *layout)
1514 {
1515         struct ll_ioc_lease *data = NULL;
1516         int fd = -1;
1517         int fdv = -1;
1518         int rc;
1519
1520         rc = migrate_open_files(name, NULL, layout, &fd, &fdv);
1521         if (rc < 0)
1522                 goto out;
1523
1524         rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
1525         if (rc < 0) {
1526                 error_loc = "cannot get lease";
1527                 goto out;
1528         }
1529
1530         rc = migrate_nonblock(fd, fdv);
1531         if (rc < 0) {
1532                 llapi_lease_release(fd);
1533                 goto out;
1534         }
1535
1536         /* Atomically put lease, merge layouts and close. */
1537         data = calloc(1, offsetof(typeof(*data), lil_ids[1]));
1538         if (!data) {
1539                 error_loc = "memory allocation";
1540                 goto out;
1541         }
1542         data->lil_mode = LL_LEASE_UNLCK;
1543         data->lil_flags = LL_LEASE_LAYOUT_MERGE;
1544         data->lil_count = 1;
1545         data->lil_ids[0] = fdv;
1546         rc = llapi_lease_set(fd, data);
1547         if (rc < 0) {
1548                 error_loc = "cannot merge layout";
1549                 goto out;
1550         } else if (rc == 0) {
1551                 rc = -EBUSY;
1552                 error_loc = "lost lease lock";
1553                 goto out;
1554         }
1555         rc = 0;
1556
1557 out:
1558         if (data)
1559                 free(data);
1560         if (fd >= 0)
1561                 close(fd);
1562         if (fdv >= 0)
1563                 close(fdv);
1564         if (rc < 0)
1565                 fprintf(stderr, "error: %s: %s: %s: %s\n",
1566                         progname, name, error_loc, strerror(-rc));
1567         return rc;
1568 }
1569
1570 static int mirror_extend(char *fname, struct mirror_args *mirror_list,
1571                          enum mirror_flags mirror_flags)
1572 {
1573         int rc;
1574
1575         rc = mirror_create_sanity_check(fname, mirror_list);
1576         if (rc)
1577                 return rc;
1578
1579         while (mirror_list) {
1580                 if (mirror_list->m_file != NULL) {
1581                         rc = mirror_extend_file(fname, mirror_list->m_file,
1582                                                 mirror_flags);
1583                 } else {
1584                         __u32 mirror_count = mirror_list->m_count;
1585
1586                         while (mirror_count > 0) {
1587                                 rc = mirror_extend_layout(fname,
1588                                                         mirror_list->m_layout);
1589                                 if (rc)
1590                                         break;
1591
1592                                 --mirror_count;
1593                         }
1594                 }
1595                 if (rc)
1596                         break;
1597
1598                 mirror_list = mirror_list->m_next;
1599         }
1600
1601         return rc;
1602 }
1603
1604 /**
1605  * Parse a string containing an target index list into an array of integers.
1606  *
1607  * The input string contains a comma delimited list of individual
1608  * indices and ranges, for example "1,2-4,7". Add the indices into the
1609  * \a tgts array and remove duplicates.
1610  *
1611  * \param[out] tgts    array to store indices in
1612  * \param[in] size     size of \a tgts array
1613  * \param[in] offset   starting index in \a tgts
1614  * \param[in] arg      string containing OST index list
1615  *
1616  * \retval positive    number of indices in \a tgts
1617  * \retval -EINVAL     unable to parse \a arg
1618  */
1619 static int parse_targets(__u32 *tgts, int size, int offset, char *arg)
1620 {
1621         int rc;
1622         int nr = offset;
1623         int slots = size - offset;
1624         char *ptr = NULL;
1625         bool end_of_loop;
1626
1627         if (arg == NULL)
1628                 return -EINVAL;
1629
1630         end_of_loop = false;
1631         while (!end_of_loop) {
1632                 int start_index;
1633                 int end_index;
1634                 int i;
1635                 char *endptr = NULL;
1636
1637                 rc = -EINVAL;
1638
1639                 ptr = strchrnul(arg, ',');
1640
1641                 end_of_loop = *ptr == '\0';
1642                 *ptr = '\0';
1643
1644                 start_index = strtol(arg, &endptr, 0);
1645                 if (endptr == arg) /* no data at all */
1646                         break;
1647                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
1648                         break;
1649
1650                 end_index = start_index;
1651                 if (*endptr == '-') {
1652                         end_index = strtol(endptr + 1, &endptr, 0);
1653                         if (*endptr != '\0')
1654                                 break;
1655                         if (end_index < start_index)
1656                                 break;
1657                 }
1658
1659                 for (i = start_index; i <= end_index && slots > 0; i++) {
1660                         int j;
1661
1662                         /* remove duplicate */
1663                         for (j = 0; j < offset; j++) {
1664                                 if (tgts[j] == i)
1665                                         break;
1666                         }
1667                         if (j == offset) { /* no duplicate */
1668                                 tgts[nr++] = i;
1669                                 --slots;
1670                         }
1671                 }
1672                 if (slots == 0 && i < end_index)
1673                         break;
1674
1675                 *ptr = ',';
1676                 arg = ++ptr;
1677                 offset = nr;
1678                 rc = 0;
1679         }
1680         if (!end_of_loop && ptr != NULL)
1681                 *ptr = ',';
1682
1683         return rc < 0 ? rc : nr;
1684 }
1685
1686 struct lfs_setstripe_args {
1687         unsigned long long       lsa_comp_end;
1688         unsigned long long       lsa_stripe_size;
1689         long long                lsa_stripe_count;
1690         long long                lsa_stripe_off;
1691         __u32                    lsa_comp_flags;
1692         __u32                    lsa_comp_neg_flags;
1693         unsigned long long       lsa_pattern;
1694         int                      lsa_nr_tgts;
1695         __u32                   *lsa_tgts;
1696         char                    *lsa_pool_name;
1697 };
1698
1699 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1700 {
1701         memset(lsa, 0, sizeof(*lsa));
1702
1703         lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
1704         lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
1705         lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
1706         lsa->lsa_pattern = LLAPI_LAYOUT_RAID0;
1707         lsa->lsa_pool_name = NULL;
1708 }
1709
1710 /**
1711  * setstripe_args_init_inherit() - Initialize and inherit stripe options.
1712  * @lsa: Stripe options to be initialized and inherited.
1713  *
1714  * This function initializes stripe options in @lsa and inherit
1715  * stripe_size, stripe_count and OST pool_name options.
1716  *
1717  * Return: void.
1718  */
1719 static inline void setstripe_args_init_inherit(struct lfs_setstripe_args *lsa)
1720 {
1721         unsigned long long stripe_size;
1722         long long stripe_count;
1723         char *pool_name = NULL;
1724
1725         stripe_size = lsa->lsa_stripe_size;
1726         stripe_count = lsa->lsa_stripe_count;
1727         pool_name = lsa->lsa_pool_name;
1728
1729         setstripe_args_init(lsa);
1730
1731         lsa->lsa_stripe_size = stripe_size;
1732         lsa->lsa_stripe_count = stripe_count;
1733         lsa->lsa_pool_name = pool_name;
1734 }
1735
1736 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1737 {
1738         return (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT ||
1739                 lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ||
1740                 lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
1741                 lsa->lsa_pattern != LLAPI_LAYOUT_RAID0 ||
1742                 lsa->lsa_pool_name != NULL ||
1743                 lsa->lsa_comp_end != 0);
1744 }
1745
1746 /**
1747  * comp_args_to_layout() - Create or extend a composite layout.
1748  * @composite:       Pointer to the composite layout.
1749  * @lsa:             Stripe options for the new component.
1750  *
1751  * This function creates or extends a composite layout by adding a new
1752  * component with stripe options from @lsa.
1753  *
1754  * Return: 0 on success or an error code on failure.
1755  */
1756 static int comp_args_to_layout(struct llapi_layout **composite,
1757                                struct lfs_setstripe_args *lsa)
1758 {
1759         struct llapi_layout *layout = *composite;
1760         uint64_t prev_end = 0;
1761         int i = 0, rc;
1762
1763         if (layout == NULL) {
1764                 layout = llapi_layout_alloc();
1765                 if (layout == NULL) {
1766                         fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1767                                 strerror(errno));
1768                         return -ENOMEM;
1769                 }
1770                 *composite = layout;
1771         } else {
1772                 uint64_t start;
1773
1774                 /* Get current component extent, current component
1775                  * must be the tail component. */
1776                 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1777                 if (rc) {
1778                         fprintf(stderr, "Get comp extent failed. %s\n",
1779                                 strerror(errno));
1780                         return rc;
1781                 }
1782
1783                 rc = llapi_layout_comp_add(layout);
1784                 if (rc) {
1785                         fprintf(stderr, "Add component failed. %s\n",
1786                                 strerror(errno));
1787                         return rc;
1788                 }
1789         }
1790
1791         rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1792         if (rc) {
1793                 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1794                         prev_end, lsa->lsa_comp_end, strerror(errno));
1795                 return rc;
1796         }
1797
1798         /* Data-on-MDT component setting */
1799         if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
1800                 /* In case of Data-on-MDT patterns the only extra option
1801                  * applicable is stripe size option. */
1802                 if (lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
1803                         fprintf(stderr, "Option 'stripe-count' can't be "
1804                                 "specified with Data-on-MDT component: %lld\n",
1805                                 lsa->lsa_stripe_count);
1806                         return -EINVAL;
1807                 }
1808                 if (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT) {
1809                         fprintf(stderr, "Option 'stripe-size' can't be "
1810                                 "specified with Data-on-MDT component: %llu\n",
1811                                 lsa->lsa_stripe_size);
1812                         return -EINVAL;
1813                 }
1814                 if (lsa->lsa_nr_tgts != 0) {
1815                         fprintf(stderr, "Option 'ost-list' can't be specified "
1816                                 "with Data-on-MDT component: '%i'\n",
1817                                 lsa->lsa_nr_tgts);
1818                         return -EINVAL;
1819                 }
1820                 if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
1821                         fprintf(stderr, "Option 'stripe-offset' can't be "
1822                                 "specified with Data-on-MDT component: %lld\n",
1823                                 lsa->lsa_stripe_off);
1824                         return -EINVAL;
1825                 }
1826                 if (lsa->lsa_pool_name != 0) {
1827                         fprintf(stderr, "Option 'pool' can't be specified "
1828                                 "with Data-on-MDT component: '%s'\n",
1829                                 lsa->lsa_pool_name);
1830                         return -EINVAL;
1831                 }
1832
1833                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
1834                 if (rc) {
1835                         fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
1836                                 lsa->lsa_pattern, strerror(errno));
1837                         return rc;
1838                 }
1839                 /* Data-on-MDT component has always single stripe up to end */
1840                 lsa->lsa_stripe_size = lsa->lsa_comp_end;
1841         }
1842
1843         rc = llapi_layout_stripe_size_set(layout, lsa->lsa_stripe_size);
1844         if (rc) {
1845                 fprintf(stderr, "Set stripe size %llu failed: %s\n",
1846                         lsa->lsa_stripe_size, strerror(errno));
1847                 return rc;
1848         }
1849
1850         rc = llapi_layout_stripe_count_set(layout, lsa->lsa_stripe_count);
1851         if (rc) {
1852                 fprintf(stderr, "Set stripe count %lld failed: %s\n",
1853                         lsa->lsa_stripe_count, strerror(errno));
1854                 return rc;
1855         }
1856
1857         rc = llapi_layout_comp_flags_set(layout, lsa->lsa_comp_flags);
1858         if (rc) {
1859                 fprintf(stderr, "Set flags 0x%x failed: %s\n",
1860                         lsa->lsa_comp_flags, strerror(errno));
1861                 return rc;
1862         }
1863
1864         if (lsa->lsa_pool_name != NULL) {
1865                 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1866                 if (rc) {
1867                         fprintf(stderr, "Set pool name: %s failed. %s\n",
1868                                 lsa->lsa_pool_name, strerror(errno));
1869                         return rc;
1870                 }
1871         } else {
1872                 rc = llapi_layout_pool_name_set(layout, "");
1873                 if (rc) {
1874                         fprintf(stderr, "Clear pool name failed: %s\n",
1875                                 strerror(errno));
1876                         return rc;
1877                 }
1878         }
1879
1880         if (lsa->lsa_nr_tgts > 0) {
1881                 if (lsa->lsa_stripe_count > 0 &&
1882                     lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
1883                     lsa->lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
1884                     lsa->lsa_nr_tgts != lsa->lsa_stripe_count) {
1885                         fprintf(stderr, "stripe_count(%lld) != nr_osts(%d)\n",
1886                                 lsa->lsa_stripe_count, lsa->lsa_nr_tgts);
1887                         return -EINVAL;
1888                 }
1889                 for (i = 0; i < lsa->lsa_nr_tgts; i++) {
1890                         rc = llapi_layout_ost_index_set(layout, i,
1891                                                         lsa->lsa_tgts[i]);
1892                         if (rc)
1893                                 break;
1894                 }
1895         } else if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
1896                 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1897         }
1898         if (rc) {
1899                 fprintf(stderr, "Set ost index %d failed. %s\n",
1900                         i, strerror(errno));
1901                 return rc;
1902         }
1903
1904         return 0;
1905 }
1906
1907 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1908  * end of the last component in the existing file, and adjust the
1909  * first extent start of the components to be added accordingly. */
1910 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1911 {
1912         struct llapi_layout *head;
1913         uint64_t start, end, stripe_size, prev_end = 0;
1914         int rc;
1915
1916         if (layout == NULL) {
1917                 fprintf(stderr,
1918                         "%s setstripe: layout must be specified\n",
1919                         progname);
1920                 return -EINVAL;
1921         }
1922
1923         errno = 0;
1924         head = llapi_layout_get_by_path(fname, 0);
1925         if (head == NULL) {
1926                 fprintf(stderr,
1927                         "%s setstripe: cannot read layout from '%s': %s\n",
1928                         progname, fname, strerror(errno));
1929                 return -EINVAL;
1930         } else if (errno == ENODATA) {
1931                 /* file without LOVEA, this component-add will be turned
1932                  * into a component-create. */
1933                 llapi_layout_free(head);
1934                 return -ENODATA;
1935         } else if (!llapi_layout_is_composite(head)) {
1936                 fprintf(stderr, "%s setstripe: '%s' not a composite file\n",
1937                         progname, fname);
1938                 llapi_layout_free(head);
1939                 return -EINVAL;
1940         }
1941
1942         rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1943         if (rc) {
1944                 fprintf(stderr, "%s setstripe: cannot get prev extent: %s\n",
1945                         progname, strerror(errno));
1946                 llapi_layout_free(head);
1947                 return rc;
1948         }
1949
1950         llapi_layout_free(head);
1951
1952         /* Make sure we use the first component of the layout to be added. */
1953         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1954         if (rc < 0) {
1955                 fprintf(stderr,
1956                         "%s setstripe: cannot move component cursor: %s\n",
1957                         progname, strerror(errno));
1958                 return rc;
1959         }
1960
1961         rc = llapi_layout_comp_extent_get(layout, &start, &end);
1962         if (rc) {
1963                 fprintf(stderr, "%s setstripe: cannot get extent: %s\n",
1964                         progname, strerror(errno));
1965                 return rc;
1966         }
1967
1968         if (start > prev_end || end <= prev_end) {
1969                 fprintf(stderr,
1970                         "%s setstripe: first extent [%lu, %lu) not adjacent with extent end %lu\n",
1971                         progname, start, end, prev_end);
1972                 return -EINVAL;
1973         }
1974
1975         rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1976         if (rc) {
1977                 fprintf(stderr, "%s setstripe: cannot get stripe size: %s\n",
1978                         progname, strerror(errno));
1979                 return rc;
1980         }
1981
1982         if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1983             (prev_end & (stripe_size - 1))) {
1984                 fprintf(stderr,
1985                         "%s setstripe: stripe size %lu not aligned with %lu\n",
1986                         progname, stripe_size, prev_end);
1987                 return -EINVAL;
1988         }
1989
1990         rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1991         if (rc) {
1992                 fprintf(stderr,
1993                         "%s setstripe: cannot set component extent [%lu, %lu): %s\n",
1994                         progname, prev_end, end, strerror(errno));
1995                 return rc;
1996         }
1997
1998         return 0;
1999 }
2000
2001 static inline bool arg_is_eof(char *arg)
2002 {
2003         return !strncmp(arg, "-1", strlen("-1")) ||
2004                !strncmp(arg, "EOF", strlen("EOF")) ||
2005                !strncmp(arg, "eof", strlen("eof"));
2006 }
2007
2008 /**
2009  * lfs_mirror_alloc() - Allocate a mirror argument structure.
2010  *
2011  * Return: Valid mirror_args pointer on success and
2012  *         NULL if memory allocation fails.
2013  */
2014 static struct mirror_args *lfs_mirror_alloc(void)
2015 {
2016         struct mirror_args *mirror = NULL;
2017
2018         while (1) {
2019                 mirror = calloc(1, sizeof(*mirror));
2020                 if (mirror != NULL)
2021                         break;
2022
2023                 sleep(1);
2024         }
2025
2026         return mirror;
2027 }
2028
2029 /**
2030  * lfs_mirror_free() - Free memory allocated for a mirror argument
2031  *                     structure.
2032  * @mirror: Previously allocated mirror argument structure by
2033  *          lfs_mirror_alloc().
2034  *
2035  * Free memory allocated for @mirror.
2036  *
2037  * Return: void.
2038  */
2039 static void lfs_mirror_free(struct mirror_args *mirror)
2040 {
2041         if (mirror->m_layout != NULL)
2042                 llapi_layout_free(mirror->m_layout);
2043         free(mirror);
2044 }
2045
2046 /**
2047  * lfs_mirror_list_free() - Free memory allocated for a mirror list.
2048  * @mirror_list: Previously allocated mirror list.
2049  *
2050  * Free memory allocated for @mirror_list.
2051  *
2052  * Return: void.
2053  */
2054 static void lfs_mirror_list_free(struct mirror_args *mirror_list)
2055 {
2056         struct mirror_args *next_mirror = NULL;
2057
2058         while (mirror_list != NULL) {
2059                 next_mirror = mirror_list->m_next;
2060                 lfs_mirror_free(mirror_list);
2061                 mirror_list = next_mirror;
2062         }
2063 }
2064
2065 enum {
2066         LFS_POOL_OPT = 3,
2067         LFS_COMP_COUNT_OPT,
2068         LFS_COMP_START_OPT,
2069         LFS_COMP_FLAGS_OPT,
2070         LFS_COMP_DEL_OPT,
2071         LFS_COMP_SET_OPT,
2072         LFS_COMP_ADD_OPT,
2073         LFS_COMP_USE_PARENT_OPT,
2074         LFS_COMP_NO_VERIFY_OPT,
2075         LFS_PROJID_OPT,
2076         LFS_MIRROR_FLAGS_OPT,
2077 };
2078
2079 /* functions */
2080 static int lfs_setstripe0(int argc, char **argv, enum setstripe_origin opc)
2081 {
2082         struct lfs_setstripe_args        lsa;
2083         struct llapi_stripe_param       *param = NULL;
2084         struct find_param                migrate_mdt_param = {
2085                 .fp_max_depth = -1,
2086                 .fp_mdt_index = -1,
2087         };
2088         char                            *fname;
2089         int                              result;
2090         int                              result2 = 0;
2091         char                            *end;
2092         int                              c;
2093         int                              delete = 0;
2094         char                            *mdt_idx_arg = NULL;
2095         unsigned long long               size_units = 1;
2096         bool                             migrate_mode = false;
2097         bool                             migration_block = false;
2098         __u64                            migration_flags = 0;
2099         __u32                            osts[LOV_MAX_STRIPE_COUNT] = { 0 };
2100         int                              comp_del = 0, comp_set = 0;
2101         int                              comp_add = 0;
2102         __u32                            comp_id = 0;
2103         struct llapi_layout             *layout = NULL;
2104         struct llapi_layout             **lpp = &layout;
2105         bool                             mirror_mode = false;
2106         bool                             has_m_file = false;
2107         __u32                            mirror_count = 0;
2108         enum mirror_flags                mirror_flags = 0;
2109         struct mirror_args              *mirror_list = NULL;
2110         struct mirror_args              *new_mirror = NULL;
2111         struct mirror_args              *last_mirror = NULL;
2112         char                             cmd[PATH_MAX];
2113
2114         struct option long_opts[] = {
2115 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
2116         /* --block is only valid in migrate mode */
2117         { .val = 'b',   .name = "block",        .has_arg = no_argument },
2118         { .val = LFS_COMP_ADD_OPT,
2119                         .name = "comp-add",     .has_arg = no_argument },
2120         { .val = LFS_COMP_ADD_OPT,
2121                         .name = "component-add", .has_arg = no_argument },
2122         { .val = LFS_COMP_DEL_OPT,
2123                         .name = "comp-del",     .has_arg = no_argument },
2124         { .val = LFS_COMP_DEL_OPT,
2125                         .name = "component-del", .has_arg = no_argument },
2126         { .val = LFS_COMP_FLAGS_OPT,
2127                         .name = "comp-flags",   .has_arg = required_argument },
2128         { .val = LFS_COMP_FLAGS_OPT,
2129                         .name = "component-flags",
2130                                                 .has_arg = required_argument },
2131         { .val = LFS_COMP_SET_OPT,
2132                         .name = "comp-set",     .has_arg = no_argument },
2133         { .val = LFS_COMP_SET_OPT,
2134                         .name = "component-set",
2135                                                 .has_arg = no_argument},
2136         { .val = LFS_COMP_USE_PARENT_OPT,
2137                         .name = "parent",       .has_arg = no_argument},
2138         { .val = LFS_COMP_NO_VERIFY_OPT,
2139                         .name = "no-verify",    .has_arg = no_argument},
2140         { .val = LFS_MIRROR_FLAGS_OPT,
2141                         .name = "flags",        .has_arg = required_argument},
2142         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument},
2143         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument},
2144 /* find { .val = 'C',   .name = "ctime",        .has_arg = required_argument }*/
2145         { .val = 'd',   .name = "delete",       .has_arg = no_argument},
2146         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument},
2147         { .val = 'E',   .name = "component-end",
2148                                                 .has_arg = required_argument},
2149         { .val = 'f',   .name = "file",         .has_arg = required_argument },
2150 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
2151 /* find { .val = 'g',   .name = "gid",          .has_arg = no_argument }, */
2152 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
2153 /* dirstripe { .val = 'H', .name = "mdt-hash",  .has_arg = required_argument }*/
2154         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument},
2155         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument},
2156         { .val = 'I',   .name = "comp-id",      .has_arg = required_argument},
2157         { .val = 'I',   .name = "component-id", .has_arg = required_argument},
2158         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
2159         { .val = 'm',   .name = "mdt",          .has_arg = required_argument},
2160         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument},
2161         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument},
2162         /* --non-block is only valid in migrate mode */
2163         { .val = 'n',   .name = "non-block",    .has_arg = no_argument },
2164         { .val = 'N',   .name = "mirror-count", .has_arg = optional_argument},
2165         { .val = 'o',   .name = "ost",          .has_arg = required_argument },
2166 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2167         { .val = 'o',   .name = "ost-list",     .has_arg = required_argument },
2168         { .val = 'o',   .name = "ost_list",     .has_arg = required_argument },
2169 #endif
2170         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
2171 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
2172 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
2173 /* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
2174 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
2175         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
2176         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
2177 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
2178 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
2179 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
2180 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
2181         /* --verbose is only valid in migrate mode */
2182         { .val = 'v',   .name = "verbose",      .has_arg = no_argument},
2183 /* getstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
2184         { .name = NULL } };
2185
2186         setstripe_args_init(&lsa);
2187
2188         migrate_mode = (opc == SO_MIGRATE);
2189         mirror_mode = (opc == SO_MIRROR_CREATE || opc == SO_MIRROR_EXTEND);
2190
2191         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
2192         progname = cmd;
2193         while ((c = getopt_long(argc, argv, "bc:dE:f:i:I:m:N::no:p:L:s:S:v",
2194                                 long_opts, NULL)) >= 0) {
2195                 switch (c) {
2196                 case 0:
2197                         /* Long options. */
2198                         break;
2199                 case LFS_COMP_ADD_OPT:
2200                         comp_add = 1;
2201                         break;
2202                 case LFS_COMP_DEL_OPT:
2203                         comp_del = 1;
2204                         break;
2205                 case LFS_COMP_FLAGS_OPT:
2206                         result = comp_str2flags(optarg, &lsa.lsa_comp_flags,
2207                                                 &lsa.lsa_comp_neg_flags);
2208                         if (result != 0)
2209                                 goto usage_error;
2210                         if (mirror_mode && lsa.lsa_comp_neg_flags) {
2211                                 fprintf(stderr, "%s: inverted flags are not supported\n",
2212                                         progname);
2213                                 goto usage_error;
2214                         }
2215                         if (lsa.lsa_comp_neg_flags & LCME_FL_STALE) {
2216                                 fprintf(stderr,
2217                                         "%s: cannot clear 'stale' flags from component. Please use lfs-mirror-resync(1) instead\n",
2218                                         progname);
2219                                 result = -EINVAL;
2220                                 goto error;
2221                         }
2222
2223                         break;
2224                 case LFS_COMP_SET_OPT:
2225                         comp_set = 1;
2226                         break;
2227                 case LFS_COMP_USE_PARENT_OPT:
2228                         if (!mirror_mode) {
2229                                 fprintf(stderr, "error: %s: --parent must be "
2230                                         "specified with --mirror-count|-N "
2231                                         "option\n", progname);
2232                                 goto usage_error;
2233                         }
2234                         setstripe_args_init(&lsa);
2235                         break;
2236                 case LFS_COMP_NO_VERIFY_OPT:
2237                         mirror_flags |= NO_VERIFY;
2238                         break;
2239                 case LFS_MIRROR_FLAGS_OPT: {
2240                         __u32 flags;
2241
2242                         if (!mirror_mode || !last_mirror) {
2243                                 fprintf(stderr, "error: %s: --flags must be specified with --mirror-count|-N option\n",
2244                                         progname);
2245                                 goto usage_error;
2246                         }
2247
2248                         result = comp_str2flags(optarg, &last_mirror->m_flags,
2249                                                 &flags);
2250                         if (result != 0)
2251                                 goto usage_error;
2252
2253                         if (flags) {
2254                                 fprintf(stderr, "%s: inverted flags are not supported\n",
2255                                         progname);
2256                                 result = -EINVAL;
2257                                 goto usage_error;
2258                         }
2259                         if (last_mirror->m_flags & ~LCME_USER_FLAGS) {
2260                                 fprintf(stderr,
2261                                         "%s: unsupported mirror flags: %s\n",
2262                                         progname, optarg);
2263                                 result = -EINVAL;
2264                                 goto error;
2265                         }
2266                         break;
2267                 }
2268                 case 'b':
2269                         if (!migrate_mode) {
2270                                 fprintf(stderr,
2271                                         "%s %s: -b|--block valid only for migrate command\n",
2272                                         progname, argv[0]);
2273                                 goto usage_error;
2274                         }
2275                         migration_block = true;
2276                         break;
2277                 case 'c':
2278                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
2279                         if (*end != '\0') {
2280                                 fprintf(stderr,
2281                                         "%s %s: invalid stripe count '%s'\n",
2282                                         progname, argv[0], optarg);
2283                                 goto usage_error;
2284                         }
2285
2286                         if (lsa.lsa_stripe_count == -1)
2287                                 lsa.lsa_stripe_count = LLAPI_LAYOUT_WIDE;
2288                         break;
2289                 case 'd':
2290                         /* delete the default striping pattern */
2291                         delete = 1;
2292                         break;
2293                 case 'E':
2294                         if (lsa.lsa_comp_end != 0) {
2295                                 result = comp_args_to_layout(lpp, &lsa);
2296                                 if (result) {
2297                                         fprintf(stderr,
2298                                                 "%s %s: invalid layout\n",
2299                                                 progname, argv[0]);
2300                                         goto usage_error;
2301                                 }
2302
2303                                 setstripe_args_init_inherit(&lsa);
2304                         }
2305
2306                         if (arg_is_eof(optarg)) {
2307                                 lsa.lsa_comp_end = LUSTRE_EOF;
2308                         } else {
2309                                 result = llapi_parse_size(optarg,
2310                                                         &lsa.lsa_comp_end,
2311                                                         &size_units, 0);
2312                                 if (result) {
2313                                         fprintf(stderr,
2314                                                 "%s %s: invalid component end '%s'\n",
2315                                                 progname, argv[0], optarg);
2316                                         goto usage_error;
2317                                 }
2318                         }
2319                         break;
2320                 case 'i':
2321                         lsa.lsa_stripe_off = strtol(optarg, &end, 0);
2322                         if (*end != '\0') {
2323                                 fprintf(stderr,
2324                                         "%s %s: invalid stripe offset '%s'\n",
2325                                         progname, argv[0], optarg);
2326                                 goto usage_error;
2327                         }
2328                         if (lsa.lsa_stripe_off == -1)
2329                                 lsa.lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2330                         break;
2331                 case 'I':
2332                         comp_id = strtoul(optarg, &end, 0);
2333                         if (*end != '\0' || comp_id == 0 ||
2334                             comp_id > LCME_ID_MAX) {
2335                                 fprintf(stderr,
2336                                         "%s %s: invalid component ID '%s'\n",
2337                                         progname, argv[0], optarg);
2338                                 goto usage_error;
2339                         }
2340                         break;
2341                 case 'f':
2342                         if (opc != SO_MIRROR_EXTEND) {
2343                                 fprintf(stderr,
2344                                         "error: %s: invalid option: %s\n",
2345                                         progname, argv[optopt + 1]);
2346                                 goto usage_error;
2347                         }
2348                         if (last_mirror == NULL) {
2349                                 fprintf(stderr, "error: %s: '-N' must exist "
2350                                         "in front of '%s'\n",
2351                                         progname, argv[optopt + 1]);
2352                                 goto usage_error;
2353                         }
2354
2355                         last_mirror->m_file = optarg;
2356                         last_mirror->m_count = 1;
2357                         has_m_file = true;
2358                         break;
2359                 case 'L':
2360                         if (strcmp(argv[optind - 1], "mdt") == 0) {
2361                                 /* Can be only the first component */
2362                                 if (layout != NULL) {
2363                                         result = -EINVAL;
2364                                         fprintf(stderr, "error: 'mdt' layout "
2365                                                 "can be only the first one\n");
2366                                         goto error;
2367                                 }
2368                                 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
2369                                         result = -EFBIG;
2370                                         fprintf(stderr, "error: 'mdt' layout "
2371                                                 "size is too big\n");
2372                                         goto error;
2373                                 }
2374                                 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
2375                         } else if (strcmp(argv[optind - 1], "raid0") != 0) {
2376                                 result = -EINVAL;
2377                                 fprintf(stderr, "error: layout '%s' is "
2378                                         "unknown, supported layouts are: "
2379                                         "'mdt', 'raid0'\n", argv[optind]);
2380                                 goto error;
2381                         }
2382                         break;
2383                 case 'm':
2384                         if (!migrate_mode) {
2385                                 fprintf(stderr,
2386                                         "%s %s: -m|--mdt-index valid only for migrate command\n",
2387                                         progname, argv[0]);
2388                                 goto usage_error;
2389                         }
2390                         mdt_idx_arg = optarg;
2391                         break;
2392                 case 'n':
2393                         if (!migrate_mode) {
2394                                 fprintf(stderr,
2395                                         "%s %s: -n|--non-block valid only for migrate command\n",
2396                                         progname, argv[0]);
2397                                 goto usage_error;
2398                         }
2399                         migration_flags |= MIGRATION_NONBLOCK;
2400                         break;
2401                 case 'N':
2402                         if (opc == SO_SETSTRIPE) {
2403                                 opc = SO_MIRROR_CREATE;
2404                                 mirror_mode = true;
2405                         }
2406                         mirror_count = 1;
2407                         if (optarg != NULL) {
2408                                 mirror_count = strtoul(optarg, &end, 0);
2409                                 if (*end != '\0' || mirror_count == 0) {
2410                                         fprintf(stderr,
2411                                                 "error: %s: bad mirror count: %s\n",
2412                                                 progname, optarg);
2413                                         result = -EINVAL;
2414                                         goto error;
2415                                 }
2416                         }
2417
2418                         new_mirror = lfs_mirror_alloc();
2419                         new_mirror->m_count = mirror_count;
2420
2421                         if (mirror_list == NULL)
2422                                 mirror_list = new_mirror;
2423
2424                         if (last_mirror != NULL) {
2425                                 /* wrap up last mirror */
2426                                 if (lsa.lsa_comp_end == 0)
2427                                         lsa.lsa_comp_end = LUSTRE_EOF;
2428
2429                                 result = comp_args_to_layout(lpp, &lsa);
2430                                 if (result) {
2431                                         lfs_mirror_free(new_mirror);
2432                                         goto error;
2433                                 }
2434
2435                                 setstripe_args_init_inherit(&lsa);
2436
2437                                 last_mirror->m_next = new_mirror;
2438                         }
2439
2440                         last_mirror = new_mirror;
2441                         lpp = &last_mirror->m_layout;
2442                         break;
2443                 case 'o':
2444 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2445                         if (strcmp(argv[optind - 1], "--ost-list") == 0)
2446                                 fprintf(stderr, "warning: '--ost-list' is "
2447                                         "deprecated, use '--ost' instead\n");
2448 #endif
2449                         lsa.lsa_nr_tgts = parse_targets(osts,
2450                                                 sizeof(osts) / sizeof(__u32),
2451                                                 lsa.lsa_nr_tgts, optarg);
2452                         if (lsa.lsa_nr_tgts < 0) {
2453                                 fprintf(stderr,
2454                                         "%s %s: invalid OST target(s) '%s'\n",
2455                                         progname, argv[0], optarg);
2456                                 goto usage_error;
2457                         }
2458
2459                         lsa.lsa_tgts = osts;
2460                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
2461                                 lsa.lsa_stripe_off = osts[0];
2462                         break;
2463                 case 'p':
2464                         if (optarg == NULL)
2465                                 goto usage_error;
2466                         lsa.lsa_pool_name = optarg;
2467                         break;
2468                 case 'S':
2469                         result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
2470                                                   &size_units, 0);
2471                         if (result) {
2472                                 fprintf(stderr,
2473                                         "%s %s: invalid stripe size '%s'\n",
2474                                         progname, argv[0], optarg);
2475                                 goto usage_error;
2476                         }
2477                         break;
2478                 case 'v':
2479                         if (!migrate_mode) {
2480                                 fprintf(stderr,
2481                                         "%s %s: -v|--verbose valid only for migrate command\n",
2482                                         progname, argv[0]);
2483                                 goto usage_error;
2484                         }
2485                         migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
2486                         break;
2487                 default:
2488                         fprintf(stderr, "%s %s: unrecognized option '%s'\n",
2489                                 progname, argv[0], argv[optind - 1]);
2490                         goto usage_error;
2491                 }
2492         }
2493
2494         fname = argv[optind];
2495
2496         if (optind == argc) {
2497                 fprintf(stderr, "%s %s: FILE must be specified\n",
2498                         progname, argv[0]);
2499                 goto usage_error;
2500         }
2501
2502         if (mirror_mode && mirror_count == 0) {
2503                 fprintf(stderr,
2504                         "error: %s: --mirror-count|-N option is required\n",
2505                         progname);
2506                 result = -EINVAL;
2507                 goto error;
2508         }
2509
2510         if (mirror_mode) {
2511                 if (lsa.lsa_comp_end == 0)
2512                         lsa.lsa_comp_end = LUSTRE_EOF;
2513         }
2514
2515         if (lsa.lsa_comp_end != 0) {
2516                 result = comp_args_to_layout(lpp, &lsa);
2517                 if (result)
2518                         goto error;
2519         }
2520
2521         if (mirror_flags & NO_VERIFY) {
2522                 if (opc != SO_MIRROR_EXTEND) {
2523                         fprintf(stderr,
2524                                 "error: %s: --no-verify is valid only for lfs mirror extend command\n",
2525                                 progname);
2526                         result = -EINVAL;
2527                         goto error;
2528                 } else if (!has_m_file) {
2529                         fprintf(stderr,
2530                                 "error: %s: --no-verify must be specified with -f <victim_file> option\n",
2531                                 progname);
2532                         result = -EINVAL;
2533                         goto error;
2534                 }
2535         }
2536
2537         /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
2538          * altered by user space tool, so we don't need to support the
2539          * --component-set for this moment. */
2540         if (comp_set && !comp_id) {
2541                 fprintf(stderr, "%s %s: --component-set doesn't have component-id set\n",
2542                         progname, argv[0]);
2543                 goto usage_error;
2544         }
2545
2546         if ((delete + comp_set + comp_del + comp_add) > 1) {
2547                 fprintf(stderr,
2548                         "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
2549                         progname, argv[0]);
2550                 goto usage_error;
2551         }
2552
2553         if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
2554                        lsa.lsa_comp_flags != 0 || layout != NULL)) {
2555                 fprintf(stderr,
2556                         "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
2557                         progname, argv[0]);
2558                 goto usage_error;
2559         }
2560
2561         if ((comp_set || comp_del) &&
2562             (setstripe_args_specified(&lsa) || layout != NULL)) {
2563                 fprintf(stderr,
2564                         "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
2565                         progname, argv[0]);
2566                 goto usage_error;
2567         }
2568
2569         if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
2570                 fprintf(stderr,
2571                         "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
2572                         progname, argv[0]);
2573                 goto usage_error;
2574         }
2575
2576         if (comp_add || comp_del) {
2577                 struct stat st;
2578
2579                 result = lstat(fname, &st);
2580                 if (result == 0 && S_ISDIR(st.st_mode)) {
2581                         fprintf(stderr,
2582                                 "%s setstripe: cannot use --component-add or --component-del for directory\n",
2583                                 progname);
2584                         goto usage_error;
2585                 }
2586
2587                 if (mirror_mode) {
2588                         fprintf(stderr, "error: %s: can't use --component-add "
2589                                 "or --component-del for mirror operation\n",
2590                                 progname);
2591                         goto usage_error;
2592                 }
2593         }
2594
2595         if (comp_add) {
2596                 if (layout == NULL) {
2597                         fprintf(stderr,
2598                                 "%s %s: option -E must be specified with --component-add\n",
2599                                 progname, argv[0]);
2600                         goto usage_error;
2601                 }
2602
2603                 result = adjust_first_extent(fname, layout);
2604                 if (result == -ENODATA)
2605                         comp_add = 0;
2606                 else if (result != 0)
2607                         goto error;
2608         }
2609
2610         if (mdt_idx_arg != NULL && optind > 3) {
2611                 fprintf(stderr,
2612                         "%s %s: option -m cannot be used with other options\n",
2613                         progname, argv[0]);
2614                 goto usage_error;
2615         }
2616
2617         if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
2618                 fprintf(stderr,
2619                         "%s %s: options --non-block and --block are mutually exclusive\n",
2620                         progname, argv[0]);
2621                 goto usage_error;
2622         }
2623
2624         if (!comp_del && !comp_set && comp_id != 0) {
2625                 fprintf(stderr,
2626                         "%s %s: option -I can only be used with --component-del\n",
2627                         progname, argv[0]);
2628                 goto usage_error;
2629         }
2630
2631         if (mdt_idx_arg != NULL) {
2632                 /* initialize migrate mdt parameters */
2633                 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
2634                 if (*end != '\0') {
2635                         fprintf(stderr, "%s %s: invalid MDT index '%s'\n",
2636                                 progname, argv[0], mdt_idx_arg);
2637                         goto usage_error;
2638                 }
2639                 migrate_mdt_param.fp_migrate = 1;
2640         } else if (layout == NULL) {
2641                 /* initialize stripe parameters */
2642                 param = calloc(1, offsetof(typeof(*param),
2643                                lsp_osts[lsa.lsa_nr_tgts]));
2644                 if (param == NULL) {
2645                         fprintf(stderr,
2646                                 "%s %s: cannot allocate memory for parameters: %s\n",
2647                                 progname, argv[0], strerror(ENOMEM));
2648                         result = -ENOMEM;
2649                         goto error;
2650                 }
2651
2652                 if (lsa.lsa_stripe_size != LLAPI_LAYOUT_DEFAULT)
2653                         param->lsp_stripe_size = lsa.lsa_stripe_size;
2654                 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
2655                         if (lsa.lsa_stripe_count == LLAPI_LAYOUT_WIDE)
2656                                 param->lsp_stripe_count = -1;
2657                         else
2658                                 param->lsp_stripe_count = lsa.lsa_stripe_count;
2659                 }
2660                 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
2661                         param->lsp_stripe_offset = -1;
2662                 else
2663                         param->lsp_stripe_offset = lsa.lsa_stripe_off;
2664                 param->lsp_pool = lsa.lsa_pool_name;
2665                 param->lsp_is_specific = false;
2666                 if (lsa.lsa_nr_tgts > 0) {
2667                         if (lsa.lsa_stripe_count > 0 &&
2668                             lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
2669                             lsa.lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
2670                             lsa.lsa_nr_tgts != lsa.lsa_stripe_count) {
2671                                 fprintf(stderr, "error: %s: stripe count %lld "
2672                                         "doesn't match the number of OSTs: %d\n"
2673                                         , argv[0], lsa.lsa_stripe_count,
2674                                         lsa.lsa_nr_tgts);
2675                                 free(param);
2676                                 goto usage_error;
2677                         }
2678
2679                         param->lsp_is_specific = true;
2680                         param->lsp_stripe_count = lsa.lsa_nr_tgts;
2681                         memcpy(param->lsp_osts, osts,
2682                                sizeof(*osts) * lsa.lsa_nr_tgts);
2683                 }
2684         }
2685
2686         for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
2687                 if (mdt_idx_arg != NULL) {
2688                         result = llapi_migrate_mdt(fname, &migrate_mdt_param);
2689                 } else if (migrate_mode) {
2690                         result = lfs_migrate(fname, migration_flags, param,
2691                                              layout);
2692                 } else if (comp_set != 0) {
2693                         result = lfs_component_set(fname, comp_id,
2694                                                    lsa.lsa_comp_flags,
2695                                                    lsa.lsa_comp_neg_flags);
2696                 } else if (comp_del != 0) {
2697                         result = lfs_component_del(fname, comp_id,
2698                                                    lsa.lsa_comp_flags,
2699                                                    lsa.lsa_comp_neg_flags);
2700                 } else if (comp_add != 0) {
2701                         result = lfs_component_add(fname, layout);
2702                 } else if (opc == SO_MIRROR_CREATE) {
2703                         result = mirror_create(fname, mirror_list);
2704                 } else if (opc == SO_MIRROR_EXTEND) {
2705                         result = mirror_extend(fname, mirror_list,
2706                                                mirror_flags);
2707                 } else if (layout != NULL) {
2708                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
2709                                                       0644, layout);
2710                         if (result >= 0) {
2711                                 close(result);
2712                                 result = 0;
2713                         }
2714                 } else {
2715                         result = llapi_file_open_param(fname,
2716                                                        O_CREAT | O_WRONLY,
2717                                                        0644, param);
2718                         if (result >= 0) {
2719                                 close(result);
2720                                 result = 0;
2721                         }
2722                 }
2723                 if (result) {
2724                         /* Save the first error encountered. */
2725                         if (result2 == 0)
2726                                 result2 = result;
2727                         continue;
2728                 }
2729         }
2730
2731         free(param);
2732         llapi_layout_free(layout);
2733         lfs_mirror_list_free(mirror_list);
2734         return result2;
2735 usage_error:
2736         result = CMD_HELP;
2737 error:
2738         llapi_layout_free(layout);
2739         lfs_mirror_list_free(mirror_list);
2740         return result;
2741 }
2742
2743 static int lfs_poollist(int argc, char **argv)
2744 {
2745         if (argc != 2)
2746                 return CMD_HELP;
2747
2748         return llapi_poollist(argv[1]);
2749 }
2750
2751 static int set_time(time_t *time, time_t *set, char *str)
2752 {
2753         time_t t;
2754         int res = 0;
2755
2756         if (str[0] == '+')
2757                 res = 1;
2758         else if (str[0] == '-')
2759                 res = -1;
2760
2761         if (res)
2762                 str++;
2763
2764         t = strtol(str, NULL, 0);
2765         if (*time < t * 24 * 60 * 60) {
2766                 if (res)
2767                         str--;
2768                 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
2769                 return INT_MAX;
2770         }
2771
2772         *set = *time - t * 24 * 60 * 60;
2773         return res;
2774 }
2775 static int name2uid(unsigned int *id, const char *name)
2776 {
2777         struct passwd *passwd;
2778
2779         passwd = getpwnam(name);
2780         if (passwd == NULL)
2781                 return -ENOENT;
2782         *id = passwd->pw_uid;
2783
2784         return 0;
2785 }
2786
2787 static int name2gid(unsigned int *id, const char *name)
2788 {
2789         struct group *group;
2790
2791         group = getgrnam(name);
2792         if (group == NULL)
2793                 return -ENOENT;
2794         *id = group->gr_gid;
2795
2796         return 0;
2797 }
2798
2799 static inline int name2projid(unsigned int *id, const char *name)
2800 {
2801         return -ENOTSUP;
2802 }
2803
2804 static int uid2name(char **name, unsigned int id)
2805 {
2806         struct passwd *passwd;
2807
2808         passwd = getpwuid(id);
2809         if (passwd == NULL)
2810                 return -ENOENT;
2811         *name = passwd->pw_name;
2812
2813         return 0;
2814 }
2815
2816 static inline int gid2name(char **name, unsigned int id)
2817 {
2818         struct group *group;
2819
2820         group = getgrgid(id);
2821         if (group == NULL)
2822                 return -ENOENT;
2823         *name = group->gr_name;
2824
2825         return 0;
2826 }
2827
2828 static int name2layout(__u32 *layout, char *name)
2829 {
2830         char *ptr, *layout_name;
2831
2832         *layout = 0;
2833         for (ptr = name; ; ptr = NULL) {
2834                 layout_name = strtok(ptr, ",");
2835                 if (layout_name == NULL)
2836                         break;
2837                 if (strcmp(layout_name, "released") == 0)
2838                         *layout |= LOV_PATTERN_F_RELEASED;
2839                 else if (strcmp(layout_name, "raid0") == 0)
2840                         *layout |= LOV_PATTERN_RAID0;
2841                 else if (strcmp(layout_name, "mdt") == 0)
2842                         *layout |= LOV_PATTERN_MDT;
2843                 else
2844                         return -1;
2845         }
2846         return 0;
2847 }
2848
2849 static int lfs_find(int argc, char **argv)
2850 {
2851         int c, rc;
2852         int ret = 0;
2853         time_t t;
2854         struct find_param param = {
2855                 .fp_max_depth = -1,
2856                 .fp_quiet = 1,
2857         };
2858         struct option long_opts[] = {
2859         { .val = 'A',   .name = "atime",        .has_arg = required_argument },
2860         { .val = LFS_COMP_COUNT_OPT,
2861                         .name = "comp-count",   .has_arg = required_argument },
2862         { .val = LFS_COMP_COUNT_OPT,
2863                         .name = "component-count",
2864                                                 .has_arg = required_argument },
2865         { .val = LFS_COMP_FLAGS_OPT,
2866                         .name = "comp-flags",   .has_arg = required_argument },
2867         { .val = LFS_COMP_FLAGS_OPT,
2868                         .name = "component-flags",
2869                                                 .has_arg = required_argument },
2870         { .val = LFS_COMP_START_OPT,
2871                         .name = "comp-start",   .has_arg = required_argument },
2872         { .val = LFS_COMP_START_OPT,
2873                         .name = "component-start",
2874                                                 .has_arg = required_argument },
2875         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument },
2876         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument },
2877         { .val = 'C',   .name = "ctime",        .has_arg = required_argument },
2878 /* getstripe { .val = 'd', .name = "directory", .has_arg = no_argument }, */
2879         { .val = 'D',   .name = "maxdepth",     .has_arg = required_argument },
2880         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument },
2881         { .val = 'E',   .name = "component-end",
2882                                                 .has_arg = required_argument },
2883 /* find { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
2884         { .val = 'g',   .name = "gid",          .has_arg = required_argument },
2885         { .val = 'G',   .name = "group",        .has_arg = required_argument },
2886         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
2887         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument },
2888         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument },
2889 /* getstripe { .val = 'I', .name = "comp-id",   .has_arg = required_argument }*/
2890         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
2891         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
2892         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
2893         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument },
2894         { .val = 'M',   .name = "mtime",        .has_arg = required_argument },
2895         { .val = 'n',   .name = "name",         .has_arg = required_argument },
2896 /* find { .val = 'o'    .name = "or", .has_arg = no_argument }, like find(1) */
2897         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
2898         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
2899         /* no short option for pool yet, can be 'p' after 2.18 */
2900         { .val = LFS_POOL_OPT,
2901                         .name = "pool",         .has_arg = required_argument },
2902         { .val = '0',   .name = "print0",       .has_arg = no_argument },
2903         { .val = 'P',   .name = "print",        .has_arg = no_argument },
2904         { .val = LFS_PROJID_OPT,
2905                         .name = "projid",       .has_arg = required_argument },
2906 /* getstripe { .val = 'q', .name = "quiet",     .has_arg = no_argument }, */
2907 /* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
2908 /* getstripe { .val = 'R', .name = "raw",       .has_arg = no_argument }, */
2909         { .val = 's',   .name = "size",         .has_arg = required_argument },
2910         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
2911         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
2912         { .val = 't',   .name = "type",         .has_arg = required_argument },
2913         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
2914         { .val = 'u',   .name = "uid",          .has_arg = required_argument },
2915         { .val = 'U',   .name = "user",         .has_arg = required_argument },
2916 /* getstripe { .val = 'v', .name = "verbose",   .has_arg = no_argument }, */
2917 /* getstripe { .val = 'y', .name = "yaml",      .has_arg = no_argument }, */
2918         { .name = NULL } };
2919         int pathstart = -1;
2920         int pathend = -1;
2921         int neg_opt = 0;
2922         time_t *xtime;
2923         int *xsign;
2924         int isoption;
2925         char *endptr;
2926
2927         time(&t);
2928
2929         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
2930         while ((c = getopt_long_only(argc, argv,
2931                         "-0A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
2932                         long_opts, NULL)) >= 0) {
2933                 xtime = NULL;
2934                 xsign = NULL;
2935                 if (neg_opt)
2936                         --neg_opt;
2937                 /* '!' is part of option */
2938                 /* when getopt_long_only() finds a string which is not
2939                  * an option nor a known option argument it returns 1
2940                  * in that case if we already have found pathstart and pathend
2941                  * (i.e. we have the list of pathnames),
2942                  * the only supported value is "!"
2943                  */
2944                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
2945                 if (!isoption && pathend != -1) {
2946                         fprintf(stderr, "err: %s: filename|dirname must either "
2947                                         "precede options or follow options\n",
2948                                         argv[0]);
2949                         ret = CMD_HELP;
2950                         goto err;
2951                 }
2952                 if (!isoption && pathstart == -1)
2953                         pathstart = optind - 1;
2954                 if (isoption && pathstart != -1 && pathend == -1)
2955                         pathend = optind - 2;
2956                 switch (c) {
2957                 case 0:
2958                         /* Long options. */
2959                         break;
2960                 case 1:
2961                         /* unknown; opt is "!" or path component,
2962                          * checking done above.
2963                          */
2964                         if (strcmp(optarg, "!") == 0)
2965                                 neg_opt = 2;
2966                         break;
2967                 case 'A':
2968                         xtime = &param.fp_atime;
2969                         xsign = &param.fp_asign;
2970                         param.fp_exclude_atime = !!neg_opt;
2971                         /* no break, this falls through to 'C' for ctime */
2972                 case 'C':
2973                         if (c == 'C') {
2974                                 xtime = &param.fp_ctime;
2975                                 xsign = &param.fp_csign;
2976                                 param.fp_exclude_ctime = !!neg_opt;
2977                         }
2978                         /* no break, this falls through to 'M' for mtime */
2979                 case 'M':
2980                         if (c == 'M') {
2981                                 xtime = &param.fp_mtime;
2982                                 xsign = &param.fp_msign;
2983                                 param.fp_exclude_mtime = !!neg_opt;
2984                         }
2985                         rc = set_time(&t, xtime, optarg);
2986                         if (rc == INT_MAX) {
2987                                 ret = -1;
2988                                 goto err;
2989                         }
2990                         if (rc)
2991                                 *xsign = rc;
2992                         break;
2993                 case LFS_COMP_COUNT_OPT:
2994                         if (optarg[0] == '+') {
2995                                 param.fp_comp_count_sign = -1;
2996                                 optarg++;
2997                         } else if (optarg[0] == '-') {
2998                                 param.fp_comp_count_sign =  1;
2999                                 optarg++;
3000                         }
3001
3002                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
3003                         if (*endptr != '\0') {
3004                                 fprintf(stderr, "error: bad component count "
3005                                         "'%s'\n", optarg);
3006                                 goto err;
3007                         }
3008                         param.fp_check_comp_count = 1;
3009                         param.fp_exclude_comp_count = !!neg_opt;
3010                         break;
3011                 case LFS_COMP_FLAGS_OPT:
3012                         rc = comp_str2flags(optarg, &param.fp_comp_flags,
3013                                             &param.fp_comp_neg_flags);
3014                         if (rc) {
3015                                 fprintf(stderr, "error: bad component flags "
3016                                         "'%s'\n", optarg);
3017                                 goto err;
3018                         }
3019                         param.fp_check_comp_flags = 1;
3020                         if (neg_opt) {
3021                                 __u32 flags = param.fp_comp_neg_flags;
3022                                 param.fp_comp_neg_flags = param.fp_comp_flags;
3023                                 param.fp_comp_flags = flags;
3024                         }
3025                         break;
3026                 case LFS_COMP_START_OPT:
3027                         if (optarg[0] == '+') {
3028                                 param.fp_comp_start_sign = -1;
3029                                 optarg++;
3030                         } else if (optarg[0] == '-') {
3031                                 param.fp_comp_start_sign =  1;
3032                                 optarg++;
3033                         }
3034
3035                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
3036                                               &param.fp_comp_start_units, 0);
3037                         if (rc) {
3038                                 fprintf(stderr, "error: bad component start "
3039                                         "'%s'\n", optarg);
3040                                 goto err;
3041                         }
3042                         param.fp_check_comp_start = 1;
3043                         param.fp_exclude_comp_start = !!neg_opt;
3044                         break;
3045                 case 'c':
3046                         if (optarg[0] == '+') {
3047                                 param.fp_stripe_count_sign = -1;
3048                                 optarg++;
3049                         } else if (optarg[0] == '-') {
3050                                 param.fp_stripe_count_sign =  1;
3051                                 optarg++;
3052                         }
3053
3054                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
3055                         if (*endptr != '\0') {
3056                                 fprintf(stderr,"error: bad stripe_count '%s'\n",
3057                                         optarg);
3058                                 ret = -1;
3059                                 goto err;
3060                         }
3061                         param.fp_check_stripe_count = 1;
3062                         param.fp_exclude_stripe_count = !!neg_opt;
3063                         break;
3064                 case 'D':
3065                         param.fp_max_depth = strtol(optarg, 0, 0);
3066                         break;
3067                 case 'E':
3068                         if (optarg[0] == '+') {
3069                                 param.fp_comp_end_sign = -1;
3070                                 optarg++;
3071                         } else if (optarg[0] == '-') {
3072                                 param.fp_comp_end_sign =  1;
3073                                 optarg++;
3074                         }
3075
3076                         if (arg_is_eof(optarg)) {
3077                                 param.fp_comp_end = LUSTRE_EOF;
3078                                 param.fp_comp_end_units = 1;
3079                                 rc = 0;
3080                         } else {
3081                                 rc = llapi_parse_size(optarg,
3082                                                 &param.fp_comp_end,
3083                                                 &param.fp_comp_end_units, 0);
3084                         }
3085                         if (rc) {
3086                                 fprintf(stderr, "error: bad component end "
3087                                         "'%s'\n", optarg);
3088                                 goto err;
3089                         }
3090                         param.fp_check_comp_end = 1;
3091                         param.fp_exclude_comp_end = !!neg_opt;
3092                         break;
3093                 case 'g':
3094                 case 'G':
3095                         rc = name2gid(&param.fp_gid, optarg);
3096                         if (rc) {
3097                                 param.fp_gid = strtoul(optarg, &endptr, 10);
3098                                 if (*endptr != '\0') {
3099                                         fprintf(stderr, "Group/GID: %s cannot "
3100                                                 "be found.\n", optarg);
3101                                         ret = -1;
3102                                         goto err;
3103                                 }
3104                         }
3105                         param.fp_exclude_gid = !!neg_opt;
3106                         param.fp_check_gid = 1;
3107                         break;
3108                 case 'H':
3109                         param.fp_hash_type = check_hashtype(optarg);
3110                         if (param.fp_hash_type == 0) {
3111                                 fprintf(stderr, "error: bad hash_type '%s'\n",
3112                                         optarg);
3113                                 ret = -1;
3114                                 goto err;
3115                         }
3116                         param.fp_check_hash_type = 1;
3117                         param.fp_exclude_hash_type = !!neg_opt;
3118                         break;
3119                 case 'L':
3120                         ret = name2layout(&param.fp_layout, optarg);
3121                         if (ret)
3122                                 goto err;
3123                         param.fp_exclude_layout = !!neg_opt;
3124                         param.fp_check_layout = 1;
3125                         break;
3126                 case 'u':
3127                 case 'U':
3128                         rc = name2uid(&param.fp_uid, optarg);
3129                         if (rc) {
3130                                 param.fp_uid = strtoul(optarg, &endptr, 10);
3131                                 if (*endptr != '\0') {
3132                                         fprintf(stderr, "User/UID: %s cannot "
3133                                                 "be found.\n", optarg);
3134                                         ret = -1;
3135                                         goto err;
3136                                 }
3137                         }
3138                         param.fp_exclude_uid = !!neg_opt;
3139                         param.fp_check_uid = 1;
3140                         break;
3141                 case 'n':
3142                         param.fp_pattern = (char *)optarg;
3143                         param.fp_exclude_pattern = !!neg_opt;
3144                         break;
3145                 case 'm':
3146                 case 'i':
3147                 case 'O': {
3148                         char *buf, *token, *next, *p;
3149                         int len = 1;
3150                         void *tmp;
3151
3152                         buf = strdup(optarg);
3153                         if (buf == NULL) {
3154                                 ret = -ENOMEM;
3155                                 goto err;
3156                         }
3157
3158                         param.fp_exclude_obd = !!neg_opt;
3159
3160                         token = buf;
3161                         while (token && *token) {
3162                                 token = strchr(token, ',');
3163                                 if (token) {
3164                                         len++;
3165                                         token++;
3166                                 }
3167                         }
3168                         if (c == 'm') {
3169                                 param.fp_exclude_mdt = !!neg_opt;
3170                                 param.fp_num_alloc_mdts += len;
3171                                 tmp = realloc(param.fp_mdt_uuid,
3172                                               param.fp_num_alloc_mdts *
3173                                               sizeof(*param.fp_mdt_uuid));
3174                                 if (tmp == NULL) {
3175                                         ret = -ENOMEM;
3176                                         goto err_free;
3177                                 }
3178
3179                                 param.fp_mdt_uuid = tmp;
3180                         } else {
3181                                 param.fp_exclude_obd = !!neg_opt;
3182                                 param.fp_num_alloc_obds += len;
3183                                 tmp = realloc(param.fp_obd_uuid,
3184                                               param.fp_num_alloc_obds *
3185                                               sizeof(*param.fp_obd_uuid));
3186                                 if (tmp == NULL) {
3187                                         ret = -ENOMEM;
3188                                         goto err_free;
3189                                 }
3190
3191                                 param.fp_obd_uuid = tmp;
3192                         }
3193                         for (token = buf; token && *token; token = next) {
3194                                 struct obd_uuid *puuid;
3195                                 if (c == 'm') {
3196                                         puuid =
3197                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
3198                                 } else {
3199                                         puuid =
3200                                         &param.fp_obd_uuid[param.fp_num_obds++];
3201                                 }
3202                                 p = strchr(token, ',');
3203                                 next = 0;
3204                                 if (p) {
3205                                         *p = 0;
3206                                         next = p+1;
3207                                 }
3208
3209                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
3210                                         ret = -E2BIG;
3211                                         goto err_free;
3212                                 }
3213
3214                                 strncpy(puuid->uuid, token,
3215                                         sizeof(puuid->uuid));
3216                         }
3217 err_free:
3218                         if (buf)
3219                                 free(buf);
3220                         break;
3221                 }
3222 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 18, 53, 0)
3223                 case 'p':
3224 #endif
3225                 case LFS_POOL_OPT:
3226                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
3227                                 fprintf(stderr,
3228                                         "Pool name %s is too long (max %d)\n",
3229                                         optarg, LOV_MAXPOOLNAME);
3230                                 ret = -1;
3231                                 goto err;
3232                         }
3233                         /*
3234                          * We do check for empty pool because empty pool
3235                          * is used to find V1 LOV attributes
3236                          */
3237                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
3238                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
3239                         param.fp_exclude_pool = !!neg_opt;
3240                         param.fp_check_pool = 1;
3241                         break;
3242 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 14, 53, 0)
3243                 case 'p': /* want this for --pool, to match getstripe/find */
3244                         fprintf(stderr,
3245                                 "warning: -p deprecated, use --print0 or -0\n");
3246 #endif
3247                 case '0':
3248                         param.fp_zero_end = 1;
3249                         break;
3250                 case 'P': /* we always print, this option is a no-op */
3251                         break;
3252                 case LFS_PROJID_OPT:
3253                         rc = name2projid(&param.fp_projid, optarg);
3254                         if (rc) {
3255                                 param.fp_projid = strtoul(optarg, &endptr, 10);
3256                                 if (*endptr != '\0') {
3257                                         fprintf(stderr,
3258                                                 "Invalid project ID: %s",
3259                                                 optarg);
3260                                         ret = -1;
3261                                         goto err;
3262                                 }
3263                         }
3264                         param.fp_exclude_projid = !!neg_opt;
3265                         param.fp_check_projid = 1;
3266                         break;
3267                 case 's':
3268                         if (optarg[0] == '+') {
3269                                 param.fp_size_sign = -1;
3270                                 optarg++;
3271                         } else if (optarg[0] == '-') {
3272                                 param.fp_size_sign =  1;
3273                                 optarg++;
3274                         }
3275
3276                         ret = llapi_parse_size(optarg, &param.fp_size,
3277                                                &param.fp_size_units, 0);
3278                         if (ret) {
3279                                 fprintf(stderr, "error: bad file size '%s'\n",
3280                                         optarg);
3281                                 goto err;
3282                         }
3283                         param.fp_check_size = 1;
3284                         param.fp_exclude_size = !!neg_opt;
3285                         break;
3286                 case 'S':
3287                         if (optarg[0] == '+') {
3288                                 param.fp_stripe_size_sign = -1;
3289                                 optarg++;
3290                         } else if (optarg[0] == '-') {
3291                                 param.fp_stripe_size_sign =  1;
3292                                 optarg++;
3293                         }
3294
3295                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
3296                                                &param.fp_stripe_size_units, 0);
3297                         if (ret) {
3298                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
3299                                         optarg);
3300                                 goto err;
3301                         }
3302                         param.fp_check_stripe_size = 1;
3303                         param.fp_exclude_stripe_size = !!neg_opt;
3304                         break;
3305                 case 't':
3306                         param.fp_exclude_type = !!neg_opt;
3307                         switch (optarg[0]) {
3308                         case 'b':
3309                                 param.fp_type = S_IFBLK;
3310                                 break;
3311                         case 'c':
3312                                 param.fp_type = S_IFCHR;
3313                                 break;
3314                         case 'd':
3315                                 param.fp_type = S_IFDIR;
3316                                 break;
3317                         case 'f':
3318                                 param.fp_type = S_IFREG;
3319                                 break;
3320                         case 'l':
3321                                 param.fp_type = S_IFLNK;
3322                                 break;
3323                         case 'p':
3324                                 param.fp_type = S_IFIFO;
3325                                 break;
3326                         case 's':
3327                                 param.fp_type = S_IFSOCK;
3328                                 break;
3329                         default:
3330                                 fprintf(stderr, "error: %s: bad type '%s'\n",
3331                                         argv[0], optarg);
3332                                 ret = CMD_HELP;
3333                                 goto err;
3334                         };
3335                         break;
3336                 case 'T':
3337                         if (optarg[0] == '+') {
3338                                 param.fp_mdt_count_sign = -1;
3339                                 optarg++;
3340                         } else if (optarg[0] == '-') {
3341                                 param.fp_mdt_count_sign =  1;
3342                                 optarg++;
3343                         }
3344
3345                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
3346                         if (*endptr != '\0') {
3347                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
3348                                         optarg);
3349                                 ret = -1;
3350                                 goto err;
3351                         }
3352                         param.fp_check_mdt_count = 1;
3353                         param.fp_exclude_mdt_count = !!neg_opt;
3354                         break;
3355                 default:
3356                         ret = CMD_HELP;
3357                         goto err;
3358                 };
3359         }
3360
3361         if (pathstart == -1) {
3362                 fprintf(stderr, "error: %s: no filename|pathname\n",
3363                         argv[0]);
3364                 ret = CMD_HELP;
3365                 goto err;
3366         } else if (pathend == -1) {
3367                 /* no options */
3368                 pathend = argc;
3369         }
3370
3371         do {
3372                 rc = llapi_find(argv[pathstart], &param);
3373                 if (rc != 0 && ret == 0)
3374                         ret = rc;
3375         } while (++pathstart < pathend);
3376
3377         if (ret)
3378                 fprintf(stderr, "error: %s failed for %s.\n",
3379                         argv[0], argv[optind - 1]);
3380 err:
3381         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
3382                 free(param.fp_obd_uuid);
3383
3384         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
3385                 free(param.fp_mdt_uuid);
3386
3387         return ret;
3388 }
3389
3390 static int lfs_getstripe_internal(int argc, char **argv,
3391                                   struct find_param *param)
3392 {
3393         struct option long_opts[] = {
3394 /* find { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
3395         { .val = LFS_COMP_COUNT_OPT,
3396                         .name = "comp-count",   .has_arg = no_argument },
3397         { .val = LFS_COMP_COUNT_OPT,
3398                 .name = "component-count",      .has_arg = no_argument },
3399         { .val = LFS_COMP_FLAGS_OPT,
3400                         .name = "comp-flags",   .has_arg = optional_argument },
3401         { .val = LFS_COMP_FLAGS_OPT,
3402                 .name = "component-flags",      .has_arg = optional_argument },
3403         { .val = LFS_COMP_START_OPT,
3404                         .name = "comp-start",   .has_arg = optional_argument },
3405         { .val = LFS_COMP_START_OPT,
3406                 .name = "component-start",      .has_arg = optional_argument },
3407         { .val = 'c',   .name = "stripe-count", .has_arg = no_argument },
3408         { .val = 'c',   .name = "stripe_count", .has_arg = no_argument },
3409 /* find { .val = 'C',   .name = "ctime",        .has_arg = required_argument }*/
3410         { .val = 'd',   .name = "directory",    .has_arg = no_argument },
3411         { .val = 'D',   .name = "default",      .has_arg = no_argument },
3412         { .val = 'E',   .name = "comp-end",     .has_arg = optional_argument },
3413         { .val = 'E',   .name = "component-end", .has_arg = optional_argument },
3414         { .val = 'F',   .name = "fid",          .has_arg = no_argument },
3415         { .val = 'g',   .name = "generation",   .has_arg = no_argument },
3416 /* find { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
3417 /* dirstripe { .val = 'H', .name = "mdt-hash",  .has_arg = required_argument }*/
3418         { .val = 'i',   .name = "stripe-index", .has_arg = no_argument },
3419         { .val = 'i',   .name = "stripe_index", .has_arg = no_argument },
3420         { .val = 'I',   .name = "comp-id",      .has_arg = optional_argument },
3421         { .val = 'I',   .name = "component-id", .has_arg = optional_argument },
3422         { .val = 'L',   .name = "layout",       .has_arg = no_argument },
3423         { .val = 'm',   .name = "mdt",          .has_arg = no_argument },
3424         { .val = 'm',   .name = "mdt-index",    .has_arg = no_argument },
3425         { .val = 'm',   .name = "mdt_index",    .has_arg = no_argument },
3426 /* find { .val = 'M',   .name = "mtime",        .has_arg = required_argument }*/
3427 /* find { .val = 'n',   .name = "name",         .has_arg = required_argument }*/
3428         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
3429         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
3430         { .val = 'p',   .name = "pool",         .has_arg = no_argument },
3431 /* find { .val = 'P',   .name = "print",        .has_arg = no_argument }, */
3432         { .val = 'q',   .name = "quiet",        .has_arg = no_argument },
3433         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
3434         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
3435         { .val = 'S',   .name = "stripe-size",  .has_arg = no_argument },
3436         { .val = 'S',   .name = "stripe_size",  .has_arg = no_argument },
3437 /* find { .val = 't',   .name = "type",         .has_arg = required_argument }*/
3438 /* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
3439 /* find { .val = 'u',   .name = "uid",          .has_arg = required_argument }*/
3440 /* find { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
3441         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
3442         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
3443         { .name = NULL } };
3444         int c, rc;
3445         char *end, *tmp;
3446
3447         while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
3448                                 long_opts, NULL)) != -1) {
3449                 switch (c) {
3450                 case 'c':
3451                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3452                                 param->fp_verbose |= VERBOSE_COUNT;
3453                                 param->fp_max_depth = 0;
3454                         }
3455                         break;
3456                 case LFS_COMP_COUNT_OPT:
3457                         param->fp_verbose |= VERBOSE_COMP_COUNT;
3458                         param->fp_max_depth = 0;
3459                         break;
3460                 case LFS_COMP_FLAGS_OPT:
3461                         if (optarg != NULL) {
3462                                 rc = comp_str2flags(optarg,
3463                                                     &param->fp_comp_flags,
3464                                                     &param->fp_comp_neg_flags);
3465                                 if (rc != 0) {
3466                                         fprintf(stderr, "error: %s bad "
3467                                                 "component flags '%s'.\n",
3468                                                 argv[0], optarg);
3469                                         return CMD_HELP;
3470                                 }
3471                                 param->fp_check_comp_flags = 1;
3472                         } else {
3473                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
3474                                 param->fp_max_depth = 0;
3475                         }
3476                         break;
3477                 case LFS_COMP_START_OPT:
3478                         if (optarg != NULL) {
3479                                 tmp = optarg;
3480                                 if (tmp[0] == '+') {
3481                                         param->fp_comp_start_sign = -1;
3482                                         tmp++;
3483                                 } else if (tmp[0] == '-') {
3484                                         param->fp_comp_start_sign = 1;
3485                                         tmp++;
3486                                 }
3487                                 rc = llapi_parse_size(tmp,
3488                                                 &param->fp_comp_start,
3489                                                 &param->fp_comp_start_units, 0);
3490                                 if (rc != 0) {
3491                                         fprintf(stderr, "error: %s bad "
3492                                                 "component start '%s'.\n",
3493                                                 argv[0], tmp);
3494                                         return CMD_HELP;
3495                                 } else {
3496                                         param->fp_check_comp_start = 1;
3497                                 }
3498                         } else {
3499                                 param->fp_verbose |= VERBOSE_COMP_START;
3500                                 param->fp_max_depth = 0;
3501                         }
3502                         break;
3503                 case 'd':
3504                         param->fp_max_depth = 0;
3505                         break;
3506                 case 'D':
3507                         param->fp_get_default_lmv = 1;
3508                         break;
3509                 case 'E':
3510                         if (optarg != NULL) {
3511                                 tmp = optarg;
3512                                 if (tmp[0] == '+') {
3513                                         param->fp_comp_end_sign = -1;
3514                                         tmp++;
3515                                 } else if (tmp[0] == '-') {
3516                                         param->fp_comp_end_sign = 1;
3517                                         tmp++;
3518                                 }
3519
3520                                 if (arg_is_eof(tmp)) {
3521                                         param->fp_comp_end = LUSTRE_EOF;
3522                                         param->fp_comp_end_units = 1;
3523                                         rc = 0;
3524                                 } else {
3525                                         rc = llapi_parse_size(tmp,
3526                                                 &param->fp_comp_end,
3527                                                 &param->fp_comp_end_units, 0);
3528                                 }
3529                                 if (rc != 0) {
3530                                         fprintf(stderr, "error: %s bad "
3531                                                 "component end '%s'.\n",
3532                                                 argv[0], tmp);
3533                                         return CMD_HELP;
3534                                 }
3535                                 param->fp_check_comp_end = 1;
3536                         } else {
3537                                 param->fp_verbose |= VERBOSE_COMP_END;
3538                                 param->fp_max_depth = 0;
3539                         }
3540                         break;
3541                 case 'F':
3542                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3543                                 param->fp_verbose |= VERBOSE_DFID;
3544                                 param->fp_max_depth = 0;
3545                         }
3546                         break;
3547                 case 'g':
3548                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3549                                 param->fp_verbose |= VERBOSE_GENERATION;
3550                                 param->fp_max_depth = 0;
3551                         }
3552                         break;
3553                 case 'i':
3554                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3555                                 param->fp_verbose |= VERBOSE_OFFSET;
3556                                 param->fp_max_depth = 0;
3557                         }
3558                         break;
3559                 case 'I':
3560                         if (optarg != NULL) {
3561                                 param->fp_comp_id = strtoul(optarg, &end, 0);
3562                                 if (*end != '\0' || param->fp_comp_id == 0 ||
3563                                     param->fp_comp_id > LCME_ID_MAX) {
3564                                         fprintf(stderr, "error: %s bad "
3565                                                 "component id '%s'\n",
3566                                                 argv[0], optarg);
3567                                         return CMD_HELP;
3568                                 } else {
3569                                         param->fp_check_comp_id = 1;
3570                                 }
3571                         } else {
3572                                 param->fp_max_depth = 0;
3573                                 param->fp_verbose |= VERBOSE_COMP_ID;
3574                         }
3575                         break;
3576                 case 'L':
3577                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3578                                 param->fp_verbose |= VERBOSE_LAYOUT;
3579                                 param->fp_max_depth = 0;
3580                         }
3581                         break;
3582 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3583                 case 'M':
3584                         fprintf(stderr, "warning: '-M' deprecated"
3585                                 ", use '--mdt-index' or '-m' instead\n");
3586 #endif
3587                 case 'm':
3588                         if (!(param->fp_verbose & VERBOSE_DETAIL))
3589                                 param->fp_max_depth = 0;
3590                         param->fp_verbose |= VERBOSE_MDTINDEX;
3591                         break;
3592                 case 'O':
3593                         if (param->fp_obd_uuid) {
3594                                 fprintf(stderr,
3595                                         "error: %s: only one obduuid allowed",
3596                                         argv[0]);
3597                                 return CMD_HELP;
3598                         }
3599                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
3600                         break;
3601                 case 'p':
3602                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3603                                 param->fp_verbose |= VERBOSE_POOL;
3604                                 param->fp_max_depth = 0;
3605                         }
3606                         break;
3607                 case 'q':
3608                         param->fp_quiet++;
3609                         break;
3610                 case 'r':
3611                         param->fp_recursive = 1;
3612                         break;
3613                 case 'R':
3614                         param->fp_raw = 1;
3615                         break;
3616                 case 'S':
3617                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3618                                 param->fp_verbose |= VERBOSE_SIZE;
3619                                 param->fp_max_depth = 0;
3620                         }
3621                         break;
3622                 case 'v':
3623                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
3624                         break;
3625                 case 'y':
3626                         param->fp_yaml = 1;
3627                         break;
3628                 default:
3629                         return CMD_HELP;
3630                 }
3631         }
3632
3633         if (optind >= argc)
3634                 return CMD_HELP;
3635
3636         if (param->fp_recursive)
3637                 param->fp_max_depth = -1;
3638         else if (param->fp_verbose & VERBOSE_DETAIL)
3639                 param->fp_max_depth = 1;
3640
3641         if (!param->fp_verbose)
3642                 param->fp_verbose = VERBOSE_DEFAULT;
3643         if (param->fp_quiet)
3644                 param->fp_verbose = VERBOSE_OBJID;
3645
3646         do {
3647                 rc = llapi_getstripe(argv[optind], param);
3648         } while (++optind < argc && !rc);
3649
3650         if (rc)
3651                 fprintf(stderr, "error: %s failed for %s.\n",
3652                         argv[0], argv[optind - 1]);
3653         return rc;
3654 }
3655
3656 static int lfs_tgts(int argc, char **argv)
3657 {
3658         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3659         struct find_param param;
3660         int index = 0, rc=0;
3661
3662         if (argc > 2)
3663                 return CMD_HELP;
3664
3665         if (argc == 2 && !realpath(argv[1], path)) {
3666                 rc = -errno;
3667                 fprintf(stderr, "error: invalid path '%s': %s\n",
3668                         argv[1], strerror(-rc));
3669                 return rc;
3670         }
3671
3672         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
3673                 /* Check if we have a mount point */
3674                 if (mntdir[0] == '\0')
3675                         continue;
3676
3677                 memset(&param, 0, sizeof(param));
3678                 if (!strcmp(argv[0], "mdts"))
3679                         param.fp_get_lmv = 1;
3680
3681                 rc = llapi_ostlist(mntdir, &param);
3682                 if (rc) {
3683                         fprintf(stderr, "error: %s: failed on %s\n",
3684                                 argv[0], mntdir);
3685                 }
3686                 if (path[0] != '\0')
3687                         break;
3688                 memset(mntdir, 0, PATH_MAX);
3689         }
3690
3691         return rc;
3692 }
3693
3694 static int lfs_getstripe(int argc, char **argv)
3695 {
3696         struct find_param param = { 0 };
3697
3698         param.fp_max_depth = 1;
3699         return lfs_getstripe_internal(argc, argv, &param);
3700 }
3701
3702 /* functions */
3703 static int lfs_getdirstripe(int argc, char **argv)
3704 {
3705         struct find_param param = { 0 };
3706         struct option long_opts[] = {
3707         { .val = 'c',   .name = "mdt-count",    .has_arg = no_argument },
3708         { .val = 'D',   .name = "default",      .has_arg = no_argument },
3709         { .val = 'H',   .name = "mdt-hash",     .has_arg = no_argument },
3710         { .val = 'i',   .name = "mdt-index",    .has_arg = no_argument },
3711         { .val = 'm',   .name = "mdt-index",    .has_arg = no_argument },
3712         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
3713         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
3714         { .val = 'T',   .name = "mdt-count",    .has_arg = no_argument },
3715         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
3716         { .name = NULL } };
3717         int c, rc;
3718
3719         param.fp_get_lmv = 1;
3720
3721         while ((c = getopt_long(argc, argv,
3722                                 "cDHimO:rtTy", long_opts, NULL)) != -1)
3723         {
3724                 switch (c) {
3725                 case 'c':
3726                 case 'T':
3727                         param.fp_verbose |= VERBOSE_COUNT;
3728                         break;
3729                 case 'D':
3730                         param.fp_get_default_lmv = 1;
3731                         break;
3732                 case 'i':
3733                 case 'm':
3734                         param.fp_verbose |= VERBOSE_OFFSET;
3735                         break;
3736 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3737                 case 't':
3738                         fprintf(stderr, "warning: '-t' deprecated, "
3739                                 "use '--mdt-hash' or '-H' instead\n");
3740 #endif
3741                 case 'H':
3742                         param.fp_verbose |= VERBOSE_HASH_TYPE;
3743                         break;
3744                 case 'O':
3745                         if (param.fp_obd_uuid) {
3746                                 fprintf(stderr,
3747                                         "error: %s: only one obduuid allowed",
3748                                         argv[0]);
3749                                 return CMD_HELP;
3750                         }
3751                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
3752                         break;
3753                 case 'r':
3754                         param.fp_recursive = 1;
3755                         break;
3756                 case 'y':
3757                         param.fp_yaml = 1;
3758                         break;
3759                 default:
3760                         return CMD_HELP;
3761                 }
3762         }
3763
3764         if (optind >= argc)
3765                 return CMD_HELP;
3766
3767         if (param.fp_recursive)
3768                 param.fp_max_depth = -1;
3769
3770         if (!param.fp_verbose)
3771                 param.fp_verbose = VERBOSE_DEFAULT;
3772
3773         do {
3774                 rc = llapi_getstripe(argv[optind], &param);
3775         } while (++optind < argc && !rc);
3776
3777         if (rc)
3778                 fprintf(stderr, "error: %s failed for %s.\n",
3779                         argv[0], argv[optind - 1]);
3780         return rc;
3781 }
3782
3783 /* functions */
3784 static int lfs_setdirstripe(int argc, char **argv)
3785 {
3786         char                    *dname;
3787         int                     result;
3788         struct lfs_setstripe_args        lsa;
3789         struct llapi_stripe_param       *param = NULL;
3790         __u32                   mdts[LMV_MAX_STRIPE_COUNT] = { 0 };
3791         char                    *end;
3792         int                     c;
3793         char                    *mode_opt = NULL;
3794         bool                    default_stripe = false;
3795         mode_t                  mode = S_IRWXU | S_IRWXG | S_IRWXO;
3796         mode_t                  previous_mode = 0;
3797         bool                    delete = false;
3798
3799         struct option long_opts[] = {
3800         { .val = 'c',   .name = "count",        .has_arg = required_argument },
3801         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
3802         { .val = 'd',   .name = "delete",       .has_arg = no_argument },
3803         { .val = 'D',   .name = "default",      .has_arg = no_argument },
3804         { .val = 'D',   .name = "default_stripe", .has_arg = no_argument },
3805         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
3806         { .val = 'i',   .name = "mdt-index",    .has_arg = required_argument },
3807 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3808         { .val = 'i',   .name = "index",        .has_arg = required_argument },
3809 #endif
3810         { .val = 'o',   .name = "mode",         .has_arg = required_argument },
3811 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3812         { .val = 't',   .name = "hash-type",    .has_arg = required_argument },
3813 #endif
3814         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
3815         { .name = NULL } };
3816
3817         setstripe_args_init(&lsa);
3818
3819         while ((c = getopt_long(argc, argv, "c:dDi:H:m:o:t:T:", long_opts,
3820                                 NULL)) >= 0) {
3821                 switch (c) {
3822                 case 0:
3823                         /* Long options. */
3824                         break;
3825                 case 'c':
3826                 case 'T':
3827                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
3828                         if (*end != '\0') {
3829                                 fprintf(stderr,
3830                                         "%s %s: invalid stripe count '%s'\n",
3831                                         progname, argv[0], optarg);
3832                                 return CMD_HELP;
3833                         }
3834                         break;
3835                 case 'd':
3836                         delete = true;
3837                         default_stripe = true;
3838                         break;
3839                 case 'D':
3840                         default_stripe = true;
3841                         break;
3842 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3843                 case 't':
3844                         fprintf(stderr, "warning: '--hash-type' and '-t' "
3845                               "deprecated, use '--mdt-hash' or '-H' instead\n");
3846 #endif
3847                 case 'H':
3848                         lsa.lsa_pattern = check_hashtype(optarg);
3849                         if (lsa.lsa_pattern == 0) {
3850                                 fprintf(stderr,
3851                                         "%s %s: bad stripe hash type '%s'\n",
3852                                         progname, argv[0], optarg);
3853                                 return CMD_HELP;
3854                         }
3855                         break;
3856                 case 'i':
3857 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3858                         if (strcmp(argv[optind - 1], "--index") == 0)
3859                                 fprintf(stderr,
3860                                         "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
3861                                         progname, argv[0]);
3862 #endif
3863                         lsa.lsa_nr_tgts = parse_targets(mdts,
3864                                                 sizeof(mdts) / sizeof(__u32),
3865                                                 lsa.lsa_nr_tgts, optarg);
3866                         if (lsa.lsa_nr_tgts < 0) {
3867                                 fprintf(stderr,
3868                                         "%s %s: invalid MDT target(s) '%s'\n",
3869                                         progname, argv[0], optarg);
3870                                 return CMD_HELP;
3871                         }
3872
3873                         lsa.lsa_tgts = mdts;
3874                         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
3875                                 lsa.lsa_stripe_off = mdts[0];
3876                         break;
3877 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 16, 53, 0)
3878                 case 'm':
3879                         fprintf(stderr, "warning: '-m' is deprecated, "
3880                                 "use '--mode' or '-o' instead\n");
3881 #endif
3882                 case 'o':
3883                         mode_opt = optarg;
3884                         break;
3885                 default:
3886                         fprintf(stderr, "%s %s: unrecognized option '%s'\n",
3887                                 progname, argv[0], argv[optind - 1]);
3888                         return CMD_HELP;
3889                 }
3890         }
3891
3892         if (optind == argc) {
3893                 fprintf(stderr, "%s %s: DIR must be specified\n",
3894                         progname, argv[0]);
3895                 return CMD_HELP;
3896         }
3897
3898         if (!delete && lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT &&
3899             lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT) {
3900                 fprintf(stderr,
3901                         "%s %s: stripe offset and count must be specified\n",
3902                         progname, argv[0]);
3903                 return CMD_HELP;
3904         }
3905
3906         if (delete &&
3907             (lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
3908              lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)) {
3909                 fprintf(stderr,
3910                         "%s %s: cannot specify -d with -c or -i options\n",
3911                         progname, argv[0]);
3912                 return CMD_HELP;
3913         }
3914
3915         if (mode_opt != NULL) {
3916                 mode = strtoul(mode_opt, &end, 8);
3917                 if (*end != '\0') {
3918                         fprintf(stderr,
3919                                 "%s %s: bad MODE '%s'\n",
3920                                 progname, argv[0], mode_opt);
3921                         return CMD_HELP;
3922                 }
3923                 previous_mode = umask(0);
3924         }
3925
3926         /* initialize stripe parameters */
3927         param = calloc(1, offsetof(typeof(*param), lsp_osts[lsa.lsa_nr_tgts]));
3928         if (param == NULL) {
3929                 fprintf(stderr,
3930                         "%s %s: cannot allocate memory for parameters: %s\n",
3931                         progname, argv[0], strerror(ENOMEM));
3932                 return CMD_HELP;
3933         }
3934
3935         if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
3936                 param->lsp_stripe_count = lsa.lsa_stripe_count;
3937         if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
3938                 param->lsp_stripe_offset = -1;
3939         else
3940                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
3941         if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
3942                 param->lsp_stripe_pattern = lsa.lsa_pattern;
3943         else
3944                 param->lsp_stripe_pattern = LMV_HASH_TYPE_FNV_1A_64;
3945         param->lsp_pool = lsa.lsa_pool_name;
3946         param->lsp_is_specific = false;
3947         if (lsa.lsa_nr_tgts > 1) {
3948                 if (lsa.lsa_stripe_count > 0 &&
3949                     lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
3950                     lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
3951                         fprintf(stderr, "error: %s: stripe count %lld doesn't "
3952                                 "match the number of MDTs: %d\n",
3953                                 argv[0], lsa.lsa_stripe_count, lsa.lsa_nr_tgts);
3954                         free(param);
3955                         return CMD_HELP;
3956                 }
3957
3958                 param->lsp_is_specific = true;
3959                 param->lsp_stripe_count = lsa.lsa_nr_tgts;
3960                 memcpy(param->lsp_tgts, mdts, sizeof(*mdts) * lsa.lsa_nr_tgts);
3961         }
3962
3963         dname = argv[optind];
3964         do {
3965                 if (default_stripe)
3966                         result = llapi_dir_set_default_lmv(dname, param);
3967                 else
3968                         result = llapi_dir_create_param(dname, mode, param);
3969
3970                 if (result) {
3971                         fprintf(stderr,
3972                                 "%s setdirstripe: cannot create stripe dir '%s': %s\n",
3973                                 progname, dname, strerror(-result));
3974                         break;
3975                 }
3976                 dname = argv[++optind];
3977         } while (dname != NULL);
3978
3979         if (mode_opt != NULL)
3980                 umask(previous_mode);
3981
3982         free(param);
3983         return result;
3984 }
3985
3986 /* functions */
3987 static int lfs_rmentry(int argc, char **argv)
3988 {
3989         char *dname;
3990         int   index;
3991         int   result = 0;
3992
3993         if (argc <= 1) {
3994                 fprintf(stderr, "error: %s: missing dirname\n",
3995                         argv[0]);
3996                 return CMD_HELP;
3997         }
3998
3999         index = 1;
4000         dname = argv[index];
4001         while (dname != NULL) {
4002                 result = llapi_direntry_remove(dname);
4003                 if (result) {
4004                         fprintf(stderr, "error: %s: remove dir entry '%s' "
4005                                 "failed\n", argv[0], dname);
4006                         break;
4007                 }
4008                 dname = argv[++index];
4009         }
4010         return result;
4011 }
4012
4013 static int lfs_mv(int argc, char **argv)
4014 {
4015         struct  find_param param = {
4016                 .fp_max_depth = -1,
4017                 .fp_mdt_index = -1,
4018         };
4019         char   *end;
4020         int     c;
4021         int     rc = 0;
4022         struct option long_opts[] = {
4023         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
4024         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
4025         { .name = NULL } };
4026
4027         while ((c = getopt_long(argc, argv, "m:M:v", long_opts, NULL)) != -1) {
4028                 switch (c) {
4029 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
4030                 case 'M':
4031                         fprintf(stderr, "warning: '-M' deprecated"
4032                                 ", use '--mdt-index' or '-m' instead\n");
4033 #endif
4034                 case 'm':
4035                         param.fp_mdt_index = strtoul(optarg, &end, 0);
4036                         if (*end != '\0') {
4037                                 fprintf(stderr, "%s: invalid MDT index'%s'\n",
4038                                         argv[0], optarg);
4039                                 return CMD_HELP;
4040                         }
4041                         break;
4042                 case 'v':
4043                         param.fp_verbose = VERBOSE_DETAIL;
4044                         break;
4045                 default:
4046                         fprintf(stderr, "error: %s: unrecognized option '%s'\n",
4047                                 argv[0], argv[optind - 1]);
4048                         return CMD_HELP;
4049                 }
4050         }
4051
4052         if (param.fp_mdt_index == -1) {
4053                 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
4054                 return CMD_HELP;
4055         }
4056
4057         if (optind >= argc) {
4058                 fprintf(stderr, "%s: missing operand path\n", argv[0]);
4059                 return CMD_HELP;
4060         }
4061
4062         param.fp_migrate = 1;
4063         rc = llapi_migrate_mdt(argv[optind], &param);
4064         if (rc != 0)
4065                 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
4066                         argv[0], argv[optind], param.fp_mdt_index,
4067                         strerror(-rc));
4068         return rc;
4069 }
4070
4071 static int lfs_osts(int argc, char **argv)
4072 {
4073         return lfs_tgts(argc, argv);
4074 }
4075
4076 static int lfs_mdts(int argc, char **argv)
4077 {
4078         return lfs_tgts(argc, argv);
4079 }
4080
4081 #define COOK(value)                                                     \
4082 ({                                                                      \
4083         int radix = 0;                                                  \
4084         while (value > 1024) {                                          \
4085                 value /= 1024;                                          \
4086                 radix++;                                                \
4087         }                                                               \
4088         radix;                                                          \
4089 })
4090 #define UUF     "%-20s"
4091 #define CSF     "%11s"
4092 #define CDF     "%11llu"
4093 #define HDF     "%8.1f%c"
4094 #define RSF     "%4s"
4095 #define RDF     "%3d%%"
4096
4097 enum mntdf_flags {
4098         MNTDF_INODES    = 0x0001,
4099         MNTDF_COOKED    = 0x0002,
4100         MNTDF_LAZY      = 0x0004,
4101         MNTDF_VERBOSE   = 0x0008,
4102 };
4103
4104 static int showdf(char *mntdir, struct obd_statfs *stat,
4105                   char *uuid, enum mntdf_flags flags,
4106                   char *type, int index, int rc)
4107 {
4108         long long avail, used, total;
4109         double ratio = 0;
4110         char *suffix = "KMGTPEZY";
4111         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
4112         char tbuf[3 * sizeof(__u64)];
4113         char ubuf[3 * sizeof(__u64)];
4114         char abuf[3 * sizeof(__u64)];
4115         char rbuf[3 * sizeof(__u64)];
4116
4117         if (!uuid || !stat)
4118                 return -EINVAL;
4119
4120         switch (rc) {
4121         case 0:
4122                 if (flags & MNTDF_INODES) {
4123                         avail = stat->os_ffree;
4124                         used = stat->os_files - stat->os_ffree;
4125                         total = stat->os_files;
4126                 } else {
4127                         int shift = flags & MNTDF_COOKED ? 0 : 10;
4128
4129                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
4130                         used  = ((stat->os_blocks - stat->os_bfree) *
4131                                  stat->os_bsize) >> shift;
4132                         total = (stat->os_blocks * stat->os_bsize) >> shift;
4133                 }
4134
4135                 if ((used + avail) > 0)
4136                         ratio = (double)used / (double)(used + avail);
4137
4138                 if (flags & MNTDF_COOKED) {
4139                         int i;
4140                         double cook_val;
4141
4142                         cook_val = (double)total;
4143                         i = COOK(cook_val);
4144                         if (i > 0)
4145                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
4146                                          suffix[i - 1]);
4147                         else
4148                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
4149
4150                         cook_val = (double)used;
4151                         i = COOK(cook_val);
4152                         if (i > 0)
4153                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
4154                                          suffix[i - 1]);
4155                         else
4156                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
4157
4158                         cook_val = (double)avail;
4159                         i = COOK(cook_val);
4160                         if (i > 0)
4161                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
4162                                          suffix[i - 1]);
4163                         else
4164                                 snprintf(abuf, sizeof(abuf), CDF, avail);
4165                 } else {
4166                         snprintf(tbuf, sizeof(tbuf), CDF, total);
4167                         snprintf(ubuf, sizeof(tbuf), CDF, used);
4168                         snprintf(abuf, sizeof(tbuf), CDF, avail);
4169                 }
4170
4171                 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
4172                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
4173                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
4174                 if (type)
4175                         printf("[%s:%d]", type, index);
4176
4177                 if (stat->os_state) {
4178                         /*
4179                          * Each character represents the matching
4180                          * OS_STATE_* bit.
4181                          */
4182                         const char state_names[] = "DRSI";
4183                         __u32      state;
4184                         __u32      i;
4185
4186                         printf(" ");
4187                         for (i = 0, state = stat->os_state;
4188                              state && i < sizeof(state_names); i++) {
4189                                 if (!(state & (1 << i)))
4190                                         continue;
4191                                 printf("%c", state_names[i]);
4192                                 state ^= 1 << i;
4193                         }
4194                 }
4195
4196                 printf("\n");
4197                 break;
4198         case -ENODATA:
4199                 printf(UUF": inactive device\n", uuid);
4200                 break;
4201         default:
4202                 printf(UUF": %s\n", uuid, strerror(-rc));
4203                 break;
4204         }
4205
4206         return 0;
4207 }
4208
4209 struct ll_stat_type {
4210         int   st_op;
4211         char *st_name;
4212 };
4213
4214 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
4215 {
4216         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
4217         struct obd_uuid uuid_buf;
4218         char *poolname = NULL;
4219         struct ll_stat_type types[] = {
4220                 { .st_op = LL_STATFS_LMV,       .st_name = "MDT" },
4221                 { .st_op = LL_STATFS_LOV,       .st_name = "OST" },
4222                 { .st_name = NULL } };
4223         struct ll_stat_type *tp;
4224         __u64 ost_ffree = 0;
4225         __u32 index;
4226         __u32 type;
4227         int fd;
4228         int rc = 0;
4229         int rc2;
4230
4231         if (pool) {
4232                 poolname = strchr(pool, '.');
4233                 if (poolname != NULL) {
4234                         if (strncmp(fsname, pool, strlen(fsname))) {
4235                                 fprintf(stderr, "filesystem name incorrect\n");
4236                                 return -ENODEV;
4237                         }
4238                         poolname++;
4239                 } else
4240                         poolname = pool;
4241         }
4242
4243         fd = open(mntdir, O_RDONLY);
4244         if (fd < 0) {
4245                 rc = -errno;
4246                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
4247                         strerror(errno));
4248                 return rc;
4249         }
4250
4251         if (flags & MNTDF_INODES)
4252                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
4253                        "UUID", "Inodes", "IUsed", "IFree",
4254                        "IUse%", "Mounted on");
4255         else
4256                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
4257                        "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
4258                        "Used", "Available", "Use%", "Mounted on");
4259
4260         for (tp = types; tp->st_name != NULL; tp++) {
4261                 for (index = 0; ; index++) {
4262                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
4263                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
4264                         type = flags & MNTDF_LAZY ?
4265                                 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
4266                         rc2 = llapi_obd_fstatfs(fd, type, index,
4267                                                &stat_buf, &uuid_buf);
4268                         if (rc2 == -ENODEV)
4269                                 break;
4270                         if (rc2 == -EAGAIN)
4271                                 continue;
4272                         if (rc2 == -ENODATA) { /* Inactive device, OK. */
4273                                 if (!(flags & MNTDF_VERBOSE))
4274                                         continue;
4275                         } else if (rc2 < 0 && rc == 0) {
4276                                 rc = rc2;
4277                         }
4278
4279                         if (poolname && tp->st_op == LL_STATFS_LOV &&
4280                             llapi_search_ost(fsname, poolname,
4281                                              obd_uuid2str(&uuid_buf)) != 1)
4282                                 continue;
4283
4284                         /* the llapi_obd_statfs() call may have returned with
4285                          * an error, but if it filled in uuid_buf we will at
4286                          * lease use that to print out a message for that OBD.
4287                          * If we didn't get anything in the uuid_buf, then fill
4288                          * it in so that we can print an error message. */
4289                         if (uuid_buf.uuid[0] == '\0')
4290                                 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
4291                                          "%s%04x", tp->st_name, index);
4292                         showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
4293                                flags, tp->st_name, index, rc2);
4294
4295                         if (rc2 == 0) {
4296                                 if (tp->st_op == LL_STATFS_LMV) {
4297                                         sum.os_ffree += stat_buf.os_ffree;
4298                                         sum.os_files += stat_buf.os_files;
4299                                 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
4300                                         sum.os_blocks += stat_buf.os_blocks *
4301                                                 stat_buf.os_bsize;
4302                                         sum.os_bfree  += stat_buf.os_bfree *
4303                                                 stat_buf.os_bsize;
4304                                         sum.os_bavail += stat_buf.os_bavail *
4305                                                 stat_buf.os_bsize;
4306                                         ost_ffree += stat_buf.os_ffree;
4307                                 }
4308                         }
4309                 }
4310         }
4311
4312         close(fd);
4313
4314         /* If we don't have as many objects free on the OST as inodes
4315          * on the MDS, we reduce the total number of inodes to
4316          * compensate, so that the "inodes in use" number is correct.
4317          * Matches ll_statfs_internal() so the results are consistent. */
4318         if (ost_ffree < sum.os_ffree) {
4319                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
4320                 sum.os_ffree = ost_ffree;
4321         }
4322         printf("\n");
4323         showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
4324         printf("\n");
4325
4326         return rc;
4327 }
4328
4329 static int lfs_df(int argc, char **argv)
4330 {
4331         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
4332         enum mntdf_flags flags = 0;
4333         int c, rc = 0, index = 0;
4334         char fsname[PATH_MAX] = "", *pool_name = NULL;
4335         struct option long_opts[] = {
4336         { .val = 'h',   .name = "human-readable",
4337                                                 .has_arg = no_argument },
4338         { .val = 'i',   .name = "inodes",       .has_arg = no_argument },
4339         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
4340         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
4341         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
4342         { .name = NULL} };
4343
4344         while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
4345                 switch (c) {
4346                 case 'h':
4347                         flags |= MNTDF_COOKED;
4348                         break;
4349                 case 'i':
4350                         flags |= MNTDF_INODES;
4351                         break;
4352                 case 'l':
4353                         flags |= MNTDF_LAZY;
4354                         break;
4355                 case 'p':
4356                         pool_name = optarg;
4357                         break;
4358                 case 'v':
4359                         flags |= MNTDF_VERBOSE;
4360                         break;
4361                 default:
4362                         return CMD_HELP;
4363                 }
4364         }
4365         if (optind < argc && !realpath(argv[optind], path)) {
4366                 rc = -errno;
4367                 fprintf(stderr, "error: invalid path '%s': %s\n",
4368                         argv[optind], strerror(-rc));
4369                 return rc;
4370         }
4371
4372         while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
4373                 /* Check if we have a mount point */
4374                 if (mntdir[0] == '\0')
4375                         continue;
4376
4377                 rc = mntdf(mntdir, fsname, pool_name, flags);
4378                 if (rc || path[0] != '\0')
4379                         break;
4380                 fsname[0] = '\0'; /* avoid matching in next loop */
4381                 mntdir[0] = '\0'; /* avoid matching in next loop */
4382         }
4383
4384         return rc;
4385 }
4386
4387 static int lfs_getname(int argc, char **argv)
4388 {
4389         char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
4390         int rc = 0, index = 0, c;
4391         char buf[sizeof(struct obd_uuid)];
4392
4393         while ((c = getopt(argc, argv, "h")) != -1)
4394                 return CMD_HELP;
4395
4396         if (optind == argc) { /* no paths specified, get all paths. */
4397                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
4398                         rc = llapi_getname(mntdir, buf, sizeof(buf));
4399                         if (rc < 0) {
4400                                 fprintf(stderr,
4401                                         "cannot get name for `%s': %s\n",
4402                                         mntdir, strerror(-rc));
4403                                 break;
4404                         }
4405
4406                         printf("%s %s\n", buf, mntdir);
4407
4408                         path[0] = fsname[0] = mntdir[0] = 0;
4409                 }
4410         } else { /* paths specified, only attempt to search these. */
4411                 for (; optind < argc; optind++) {
4412                         rc = llapi_getname(argv[optind], buf, sizeof(buf));
4413                         if (rc < 0) {
4414                                 fprintf(stderr,
4415                                         "cannot get name for `%s': %s\n",
4416                                         argv[optind], strerror(-rc));
4417                                 break;
4418                         }
4419
4420                         printf("%s %s\n", buf, argv[optind]);
4421                 }
4422         }
4423         return rc;
4424 }
4425
4426 static int lfs_check(int argc, char **argv)
4427 {
4428         int rc;
4429         char mntdir[PATH_MAX] = {'\0'};
4430         int num_types = 1;
4431         char *obd_types[2];
4432         char obd_type1[4];
4433         char obd_type2[4];
4434
4435         if (argc != 2) {
4436                 fprintf(stderr, "%s check: server type must be specified\n",
4437                         progname);
4438                 return CMD_HELP;
4439         }
4440
4441         obd_types[0] = obd_type1;
4442         obd_types[1] = obd_type2;
4443
4444         if (strcmp(argv[1], "osts") == 0) {
4445                 strcpy(obd_types[0], "osc");
4446         } else if (strcmp(argv[1], "mds") == 0) {
4447                 strcpy(obd_types[0], "mdc");
4448         } else if (strcmp(argv[1], "servers") == 0) {
4449                 num_types = 2;
4450                 strcpy(obd_types[0], "osc");
4451                 strcpy(obd_types[1], "mdc");
4452         } else {
4453                 fprintf(stderr, "%s check: unrecognized option '%s'\n",
4454                         progname, argv[1]);
4455                 return CMD_HELP;
4456         }
4457
4458         rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
4459         if (rc < 0 || mntdir[0] == '\0') {
4460                 fprintf(stderr,
4461                         "%s check: cannot find mounted Lustre filesystem: %s\n",
4462                         progname, (rc < 0) ? strerror(-rc) : strerror(ENODEV));
4463                 return rc;
4464         }
4465
4466         rc = llapi_target_check(num_types, obd_types, mntdir);
4467         if (rc)
4468                 fprintf(stderr, "%s check: cannot check target '%s': %s\n",
4469                         progname, argv[1], strerror(-rc));
4470
4471         return rc;
4472
4473 }
4474
4475 #ifdef HAVE_SYS_QUOTA_H
4476 #define ARG2INT(nr, str, msg)                                           \
4477 do {                                                                    \
4478         char *endp;                                                     \
4479         nr = strtol(str, &endp, 0);                                     \
4480         if (*endp != '\0') {                                            \
4481                 fprintf(stderr, "%s: bad %s '%s'\n",                    \
4482                         progname, msg, str);                            \
4483                 return CMD_HELP;                                        \
4484         }                                                               \
4485 } while (0)
4486
4487 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
4488
4489 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
4490  * returns the value or ULONG_MAX on integer overflow or incorrect format
4491  * Notes:
4492  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
4493  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
4494  *        3. empty integer value is interpreted as 0
4495  */
4496 static unsigned long str2sec(const char* timestr)
4497 {
4498         const char spec[] = "smhdw";
4499         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
4500         unsigned long val = 0;
4501         char *tail;
4502
4503         if (strpbrk(timestr, spec) == NULL) {
4504                 /* no specifiers inside the time string,
4505                    should treat it as an integer value */
4506                 val = strtoul(timestr, &tail, 10);
4507                 return *tail ? ULONG_MAX : val;
4508         }
4509
4510         /* format string is XXwXXdXXhXXmXXs */
4511         while (*timestr) {
4512                 unsigned long v;
4513                 int ind;
4514                 char* ptr;
4515
4516                 v = strtoul(timestr, &tail, 10);
4517                 if (v == ULONG_MAX || *tail == '\0')
4518                         /* value too large (ULONG_MAX or more)
4519                            or missing specifier */
4520                         goto error;
4521
4522                 ptr = strchr(spec, *tail);
4523                 if (ptr == NULL)
4524                         /* unknown specifier */
4525                         goto error;
4526
4527                 ind = ptr - spec;
4528
4529                 /* check if product will overflow the type */
4530                 if (!(v < ULONG_MAX / mult[ind]))
4531                         goto error;
4532
4533                 ADD_OVERFLOW(val, mult[ind] * v);
4534                 if (val == ULONG_MAX)
4535                         goto error;
4536
4537                 timestr = tail + 1;
4538         }
4539
4540         return val;
4541
4542 error:
4543         return ULONG_MAX;
4544 }
4545
4546 #define ARG2ULL(nr, str, def_units)                                     \
4547 do {                                                                    \
4548         unsigned long long limit, units = def_units;                    \
4549         int rc;                                                         \
4550                                                                         \
4551         rc = llapi_parse_size(str, &limit, &units, 1);                  \
4552         if (rc < 0) {                                                   \
4553                 fprintf(stderr, "%s: invalid limit '%s'\n",             \
4554                         progname, str);                                 \
4555                 return CMD_HELP;                                        \
4556         }                                                               \
4557         nr = limit;                                                     \
4558 } while (0)
4559
4560 static inline int has_times_option(int argc, char **argv)
4561 {
4562         int i;
4563
4564         for (i = 1; i < argc; i++)
4565                 if (!strcmp(argv[i], "-t"))
4566                         return 1;
4567
4568         return 0;
4569 }
4570
4571 int lfs_setquota_times(int argc, char **argv)
4572 {
4573         int c, rc;
4574         struct if_quotactl qctl;
4575         char *mnt, *obd_type = (char *)qctl.obd_type;
4576         struct obd_dqblk *dqb = &qctl.qc_dqblk;
4577         struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
4578         struct option long_opts[] = {
4579         { .val = 'b',   .name = "block-grace",  .has_arg = required_argument },
4580         { .val = 'g',   .name = "group",        .has_arg = no_argument },
4581         { .val = 'i',   .name = "inode-grace",  .has_arg = required_argument },
4582         { .val = 'p',   .name = "projid",       .has_arg = no_argument },
4583         { .val = 't',   .name = "times",        .has_arg = no_argument },
4584         { .val = 'u',   .name = "user",         .has_arg = no_argument },
4585         { .name = NULL } };
4586         int qtype;
4587
4588         memset(&qctl, 0, sizeof(qctl));
4589         qctl.qc_cmd  = LUSTRE_Q_SETINFO;
4590         qctl.qc_type = ALLQUOTA;
4591
4592         while ((c = getopt_long(argc, argv, "b:gi:ptu",
4593                                 long_opts, NULL)) != -1) {
4594                 switch (c) {
4595                 case 'u':
4596                         qtype = USRQUOTA;
4597                         goto quota_type;
4598                 case 'g':
4599                         qtype = GRPQUOTA;
4600                         goto quota_type;
4601                 case 'p':
4602                         qtype = PRJQUOTA;
4603 quota_type:
4604                         if (qctl.qc_type != ALLQUOTA) {
4605                                 fprintf(stderr, "error: -u/g/p can't be used "
4606                                                 "more than once\n");
4607                                 return CMD_HELP;
4608                         }
4609                         qctl.qc_type = qtype;
4610                         break;
4611                 case 'b':
4612                         if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
4613                                 fprintf(stderr, "error: bad block-grace: %s\n",
4614                                         optarg);
4615                                 return CMD_HELP;
4616                         }
4617                         dqb->dqb_valid |= QIF_BTIME;
4618                         break;
4619                 case 'i':
4620                         if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
4621                                 fprintf(stderr, "error: bad inode-grace: %s\n",
4622                                         optarg);
4623                                 return CMD_HELP;
4624                         }
4625                         dqb->dqb_valid |= QIF_ITIME;
4626                         break;
4627                 case 't': /* Yes, of course! */
4628                         break;
4629                 default: /* getopt prints error message for us when opterr != 0 */
4630                         return CMD_HELP;
4631                 }
4632         }
4633
4634         if (qctl.qc_type == ALLQUOTA) {
4635                 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
4636                 return CMD_HELP;
4637         }
4638
4639         if (optind != argc - 1) {
4640                 fprintf(stderr, "error: unexpected parameters encountered\n");
4641                 return CMD_HELP;
4642         }
4643
4644         mnt = argv[optind];
4645         rc = llapi_quotactl(mnt, &qctl);
4646         if (rc) {
4647                 if (*obd_type)
4648                         fprintf(stderr, "%s %s ", obd_type,
4649                                 obd_uuid2str(&qctl.obd_uuid));
4650                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
4651                 return rc;
4652         }
4653
4654         return 0;
4655 }
4656
4657 #define BSLIMIT (1 << 0)
4658 #define BHLIMIT (1 << 1)
4659 #define ISLIMIT (1 << 2)
4660 #define IHLIMIT (1 << 3)
4661
4662 int lfs_setquota(int argc, char **argv)
4663 {
4664         int c, rc;
4665         struct if_quotactl qctl;
4666         char *mnt, *obd_type = (char *)qctl.obd_type;
4667         struct obd_dqblk *dqb = &qctl.qc_dqblk;
4668         struct option long_opts[] = {
4669         { .val = 'b',   .name = "block-softlimit",
4670                                                 .has_arg = required_argument },
4671         { .val = 'B',   .name = "block-hardlimit",
4672                                                 .has_arg = required_argument },
4673         { .val = 'g',   .name = "group",        .has_arg = required_argument },
4674         { .val = 'i',   .name = "inode-softlimit",
4675                                                 .has_arg = required_argument },
4676         { .val = 'I',   .name = "inode-hardlimit",
4677                                                 .has_arg = required_argument },
4678         { .val = 'p',   .name = "projid",       .has_arg = required_argument },
4679         { .val = 'u',   .name = "user",         .has_arg = required_argument },
4680         { .name = NULL } };
4681         unsigned limit_mask = 0;
4682         char *endptr;
4683         int qtype;
4684
4685         if (has_times_option(argc, argv))
4686                 return lfs_setquota_times(argc, argv);
4687
4688         memset(&qctl, 0, sizeof(qctl));
4689         qctl.qc_cmd  = LUSTRE_Q_SETQUOTA;
4690         qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
4691                                   * so it can be used as a marker that qc_type
4692                                   * isn't reinitialized from command line */
4693
4694         while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
4695                 long_opts, NULL)) != -1) {
4696                 switch (c) {
4697                 case 'u':
4698                         qtype = USRQUOTA;
4699                         rc = name2uid(&qctl.qc_id, optarg);
4700                         goto quota_type;
4701                 case 'g':
4702                         qtype = GRPQUOTA;
4703                         rc = name2gid(&qctl.qc_id, optarg);
4704                         goto quota_type;
4705                 case 'p':
4706                         qtype = PRJQUOTA;
4707                         rc = name2projid(&qctl.qc_id, optarg);
4708 quota_type:
4709                         if (qctl.qc_type != ALLQUOTA) {
4710                                 fprintf(stderr,
4711                                         "%s setquota: only one of -u, -g or -p may be specified\n",
4712                                         progname);
4713                                 return CMD_HELP;
4714                         }
4715                         qctl.qc_type = qtype;
4716                         if (rc) {
4717                                 qctl.qc_id = strtoul(optarg, &endptr, 10);
4718                                 if (*endptr != '\0') {
4719                                         fprintf(stderr,
4720                                                 "%s setquota: invalid id '%s'\n",
4721                                                 progname, optarg);
4722                                         return -1;
4723                                 }
4724                         }
4725                         break;
4726                 case 'b':
4727                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
4728                         dqb->dqb_bsoftlimit >>= 10;
4729                         limit_mask |= BSLIMIT;
4730                         if (dqb->dqb_bsoftlimit &&
4731                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
4732                                 fprintf(stderr,
4733                                         "%s setquota: warning: block softlimit '%llu' smaller than minimum qunit size\n"
4734                                         "See '%s help setquota' or Lustre manual for details\n",
4735                                         progname, dqb->dqb_bsoftlimit,
4736                                         progname);
4737                         break;
4738                 case 'B':
4739                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
4740                         dqb->dqb_bhardlimit >>= 10;
4741                         limit_mask |= BHLIMIT;
4742                         if (dqb->dqb_bhardlimit &&
4743                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
4744                                 fprintf(stderr,
4745                                         "%s setquota: warning: block hardlimit '%llu' smaller than minimum qunit size\n"
4746                                         "See '%s help setquota' or Lustre manual for details\n",
4747                                         progname, dqb->dqb_bhardlimit,
4748                                         progname);
4749                         break;
4750                 case 'i':
4751                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
4752                         limit_mask |= ISLIMIT;
4753                         if (dqb->dqb_isoftlimit &&
4754                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
4755                                 fprintf(stderr,
4756                                         "%s setquota: warning: inode softlimit '%llu' smaller than minimum qunit size\n"
4757                                         "See '%s help setquota' or Lustre manual for details\n",
4758                                         progname, dqb->dqb_isoftlimit,
4759                                         progname);
4760                         break;
4761                 case 'I':
4762                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
4763                         limit_mask |= IHLIMIT;
4764                         if (dqb->dqb_ihardlimit &&
4765                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
4766                                 fprintf(stderr,
4767                                         "%s setquota: warning: inode hardlimit '%llu' smaller than minimum qunit size\n"
4768                                         "See '%s help setquota' or Lustre manual for details\n",
4769                                         progname, dqb->dqb_ihardlimit,
4770                                         progname);
4771                         break;
4772                 default:
4773                         fprintf(stderr,
4774                                 "%s setquota: unrecognized option '%s'\n",
4775                                 progname, argv[optind - 1]);
4776                         return CMD_HELP;
4777                 }
4778         }
4779
4780         if (qctl.qc_type == ALLQUOTA) {
4781                 fprintf(stderr,
4782                         "%s setquota: either -u or -g must be specified\n",
4783                         progname);
4784                 return CMD_HELP;
4785         }
4786
4787         if (limit_mask == 0) {
4788                 fprintf(stderr,
4789                         "%s setquota: at least one limit must be specified\n",
4790                         progname);
4791                 return CMD_HELP;
4792         }
4793
4794         if (optind != argc - 1) {
4795                 fprintf(stderr,
4796                         "%s setquota: filesystem not specified or unexpected argument '%s'\n",
4797                         progname, argv[optind]);
4798                 return CMD_HELP;
4799         }
4800
4801         mnt = argv[optind];
4802
4803         if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
4804             (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
4805                 /* sigh, we can't just set blimits/ilimits */
4806                 struct if_quotactl tmp_qctl = {.qc_cmd  = LUSTRE_Q_GETQUOTA,
4807                                                .qc_type = qctl.qc_type,
4808                                                .qc_id   = qctl.qc_id};
4809
4810                 rc = llapi_quotactl(mnt, &tmp_qctl);
4811                 if (rc < 0)
4812                         return rc;
4813
4814                 if (!(limit_mask & BHLIMIT))
4815                         dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
4816                 if (!(limit_mask & BSLIMIT))
4817                         dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
4818                 if (!(limit_mask & IHLIMIT))
4819                         dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
4820                 if (!(limit_mask & ISLIMIT))
4821                         dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
4822
4823                 /* Keep grace times if we have got no softlimit arguments */
4824                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
4825                         dqb->dqb_valid |= QIF_BTIME;
4826                         dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
4827                 }
4828
4829                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
4830                         dqb->dqb_valid |= QIF_ITIME;
4831                         dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
4832                 }
4833         }
4834
4835         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
4836         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
4837
4838         rc = llapi_quotactl(mnt, &qctl);
4839         if (rc) {
4840                 if (*obd_type)
4841                         fprintf(stderr,
4842                                 "%s setquota: cannot quotactl '%s' '%s': %s",
4843                                 progname, obd_type,
4844                                 obd_uuid2str(&qctl.obd_uuid), strerror(-rc));
4845                 return rc;
4846         }
4847
4848         return 0;
4849 }
4850
4851 /* Converts seconds value into format string
4852  * result is returned in buf
4853  * Notes:
4854  *        1. result is in descenting order: 1w2d3h4m5s
4855  *        2. zero fields are not filled (except for p. 3): 5d1s
4856  *        3. zero seconds value is presented as "0s"
4857  */
4858 static char * __sec2str(time_t seconds, char *buf)
4859 {
4860         const char spec[] = "smhdw";
4861         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
4862         unsigned long c;
4863         char *tail = buf;
4864         int i;
4865
4866         for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
4867                 c = seconds / mult[i];
4868
4869                 if (c > 0 || (i == 0 && buf == tail))
4870                         tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
4871
4872                 seconds %= mult[i];
4873         }
4874
4875         return tail;
4876 }
4877
4878 static void sec2str(time_t seconds, char *buf, int rc)
4879 {
4880         char *tail = buf;
4881
4882         if (rc)
4883                 *tail++ = '[';
4884
4885         tail = __sec2str(seconds, tail);
4886
4887         if (rc && tail - buf < 39) {
4888                 *tail++ = ']';
4889                 *tail++ = 0;
4890         }
4891 }
4892
4893 static void diff2str(time_t seconds, char *buf, time_t now)
4894 {
4895
4896         buf[0] = 0;
4897         if (!seconds)
4898                 return;
4899         if (seconds <= now) {
4900                 strcpy(buf, "none");
4901                 return;
4902         }
4903         __sec2str(seconds - now, buf);
4904 }
4905
4906 static void print_quota_title(char *name, struct if_quotactl *qctl,
4907                               bool human_readable)
4908 {
4909         printf("Disk quotas for %s %s (%cid %u):\n",
4910                qtype_name(qctl->qc_type), name,
4911                *qtype_name(qctl->qc_type), qctl->qc_id);
4912         printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
4913                "Filesystem", human_readable ? "used" : "kbytes",
4914                "quota", "limit", "grace",
4915                "files", "quota", "limit", "grace");
4916 }
4917
4918 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
4919 {
4920         if (!h) {
4921                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
4922         } else {
4923                 if (num >> 40)
4924                         snprintf(buf, buflen, "%5.4gP",
4925                                  (double)num / ((__u64)1 << 40));
4926                 else if (num >> 30)
4927                         snprintf(buf, buflen, "%5.4gT",
4928                                  (double)num / (1 << 30));
4929                 else if (num >> 20)
4930                         snprintf(buf, buflen, "%5.4gG",
4931                                  (double)num / (1 << 20));
4932                 else if (num >> 10)
4933                         snprintf(buf, buflen, "%5.4gM",
4934                                  (double)num / (1 << 10));
4935                 else
4936                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
4937         }
4938 }
4939
4940 #define STRBUF_LEN      32
4941 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
4942                         int rc, bool h)
4943 {
4944         time_t now;
4945
4946         time(&now);
4947
4948         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
4949                 int bover = 0, iover = 0;
4950                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
4951                 char numbuf[3][STRBUF_LEN];
4952                 char timebuf[40];
4953                 char strbuf[STRBUF_LEN];
4954
4955                 if (dqb->dqb_bhardlimit &&
4956                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
4957                         bover = 1;
4958                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
4959                         if (dqb->dqb_btime > now) {
4960                                 bover = 2;
4961                         } else {
4962                                 bover = 3;
4963                         }
4964                 }
4965
4966                 if (dqb->dqb_ihardlimit &&
4967                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
4968                         iover = 1;
4969                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
4970                         if (dqb->dqb_itime > now) {
4971                                 iover = 2;
4972                         } else {
4973                                 iover = 3;
4974                         }
4975                 }
4976
4977
4978                 if (strlen(mnt) > 15)
4979                         printf("%s\n%15s", mnt, "");
4980                 else
4981                         printf("%15s", mnt);
4982
4983                 if (bover)
4984                         diff2str(dqb->dqb_btime, timebuf, now);
4985
4986                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
4987                            strbuf, sizeof(strbuf), h);
4988                 if (rc == -EREMOTEIO)
4989                         sprintf(numbuf[0], "%s*", strbuf);
4990                 else
4991                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
4992                                 "%s" : "[%s]", strbuf);
4993
4994                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
4995                 if (type == QC_GENERAL)
4996                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4997                                 "%s" : "[%s]", strbuf);
4998                 else
4999                         sprintf(numbuf[1], "%s", "-");
5000
5001                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
5002                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
5003                         "%s" : "[%s]", strbuf);
5004
5005                 printf(" %7s%c %6s %7s %7s",
5006                        numbuf[0], bover ? '*' : ' ', numbuf[1],
5007                        numbuf[2], bover > 1 ? timebuf : "-");
5008
5009                 if (iover)
5010                         diff2str(dqb->dqb_itime, timebuf, now);
5011
5012                 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
5013                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
5014
5015                 if (type == QC_GENERAL)
5016                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
5017                                 "%ju" : "[%ju]",
5018                                 (uintmax_t)dqb->dqb_isoftlimit);
5019                 else
5020                         sprintf(numbuf[1], "%s", "-");
5021
5022                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
5023                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
5024
5025                 if (type != QC_OSTIDX)
5026                         printf(" %7s%c %6s %7s %7s",
5027                                numbuf[0], iover ? '*' : ' ', numbuf[1],
5028                                numbuf[2], iover > 1 ? timebuf : "-");
5029                 else
5030                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
5031                 printf("\n");
5032
5033         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
5034                    qctl->qc_cmd == Q_GETOINFO) {
5035                 char bgtimebuf[40];
5036                 char igtimebuf[40];
5037
5038                 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
5039                 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
5040                 printf("Block grace time: %s; Inode grace time: %s\n",
5041                        bgtimebuf, igtimebuf);
5042         }
5043 }
5044
5045 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
5046                            bool h, __u64 *total)
5047 {
5048         int rc = 0, rc1 = 0, count = 0;
5049         __u32 valid = qctl->qc_valid;
5050
5051         rc = llapi_get_obd_count(mnt, &count, is_mdt);
5052         if (rc) {
5053                 fprintf(stderr, "can not get %s count: %s\n",
5054                         is_mdt ? "mdt": "ost", strerror(-rc));
5055                 return rc;
5056         }
5057
5058         for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
5059                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
5060                 rc = llapi_quotactl(mnt, qctl);
5061                 if (rc) {
5062                         /* It is remote client case. */
5063                         if (rc == -EOPNOTSUPP) {
5064                                 rc = 0;
5065                                 goto out;
5066                         }
5067
5068                         if (!rc1)
5069                                 rc1 = rc;
5070                         fprintf(stderr, "quotactl %s%d failed.\n",
5071                                 is_mdt ? "mdt": "ost", qctl->qc_idx);
5072                         continue;
5073                 }
5074
5075                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
5076                             qctl->qc_valid, 0, h);
5077                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
5078                                    qctl->qc_dqblk.dqb_bhardlimit;
5079         }
5080 out:
5081         qctl->qc_valid = valid;
5082         return rc ? : rc1;
5083 }
5084
5085 static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
5086                            int verbose, int quiet, bool human_readable)
5087 {
5088         int rc1 = 0, rc2 = 0, rc3 = 0;
5089         char *obd_type = (char *)qctl->obd_type;
5090         char *obd_uuid = (char *)qctl->obd_uuid.uuid;
5091         __u64 total_ialloc = 0, total_balloc = 0;
5092         int inacc;
5093
5094         rc1 = llapi_quotactl(mnt, qctl);
5095         if (rc1 < 0) {
5096                 switch (rc1) {
5097                 case -ESRCH:
5098                         fprintf(stderr, "%s quotas are not enabled.\n",
5099                                 qtype_name(qctl->qc_type));
5100                         goto out;
5101                 case -EPERM:
5102                         fprintf(stderr, "Permission denied.\n");
5103                 case -ENODEV:
5104                 case -ENOENT:
5105                         /* We already got error message. */
5106                         goto out;
5107                 default:
5108                         fprintf(stderr, "Unexpected quotactl error: %s\n",
5109                                 strerror(-rc1));
5110                 }
5111         }
5112
5113         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
5114                 print_quota_title(name, qctl, human_readable);
5115
5116         if (rc1 && *obd_type)
5117                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
5118
5119         if (qctl->qc_valid != QC_GENERAL)
5120                 mnt = "";
5121
5122         inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA) &&
5123                 ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
5124                  (QIF_LIMITS|QIF_USAGE));
5125
5126         print_quota(mnt, qctl, QC_GENERAL, rc1, human_readable);
5127
5128         if (qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO &&
5129             verbose) {
5130                 char strbuf[STRBUF_LEN];
5131
5132                 rc2 = print_obd_quota(mnt, qctl, 1, human_readable,
5133                                       &total_ialloc);
5134                 rc3 = print_obd_quota(mnt, qctl, 0, human_readable,
5135                                       &total_balloc);
5136                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
5137                            human_readable);
5138                 printf("Total allocated inode limit: %ju, total "
5139                        "allocated block limit: %s\n", (uintmax_t)total_ialloc,
5140                        strbuf);
5141         }
5142
5143         if (rc1 || rc2 || rc3 || inacc)
5144                 printf("Some errors happened when getting quota info. "
5145                        "Some devices may be not working or deactivated. "
5146                        "The data in \"[]\" is inaccurate.\n");
5147 out:
5148         return rc1;
5149
5150 }
5151
5152 static int lfs_project(int argc, char **argv)
5153 {
5154         int ret = 0, err = 0, c, i;
5155         struct project_handle_control phc = { 0 };
5156         enum lfs_project_ops_t op;
5157
5158         phc.newline = true;
5159         phc.assign_projid = false;
5160         /* default action */
5161         op = LFS_PROJECT_LIST;
5162
5163         while ((c = getopt(argc, argv, "p:cCsdkr0")) != -1) {
5164                 switch (c) {
5165                 case 'c':
5166                         if (op != LFS_PROJECT_LIST) {
5167                                 fprintf(stderr,
5168                                         "%s: cannot specify '-c' '-C' '-s' together\n",
5169                                         progname);
5170                                 return CMD_HELP;
5171                         }
5172
5173                         op = LFS_PROJECT_CHECK;
5174                         break;
5175                 case 'C':
5176                         if (op != LFS_PROJECT_LIST) {
5177                                 fprintf(stderr,
5178                                         "%s: cannot specify '-c' '-C' '-s' together\n",
5179                                         progname);
5180                                 return CMD_HELP;
5181                         }
5182
5183                         op = LFS_PROJECT_CLEAR;
5184                         break;
5185                 case 's':
5186                         if (op != LFS_PROJECT_LIST) {
5187                                 fprintf(stderr,
5188                                         "%s: cannot specify '-c' '-C' '-s' together\n",
5189                                         progname);
5190                                 return CMD_HELP;
5191                         }
5192
5193                         phc.set_inherit = true;
5194                         op = LFS_PROJECT_SET;
5195                         break;
5196                 case 'd':
5197                         phc.dironly = true;
5198                         break;
5199                 case 'k':
5200                         phc.keep_projid = true;
5201                         break;
5202                 case 'r':
5203                         phc.recursive = true;
5204                         break;
5205                 case 'p':
5206                         phc.projid = strtoul(optarg, NULL, 0);
5207                         phc.assign_projid = true;
5208
5209                         break;
5210                 case '0':
5211                         phc.newline = false;
5212                         break;
5213                 default:
5214                         fprintf(stderr, "%s: invalid option '%c'\n",
5215                                 progname, optopt);
5216                         return CMD_HELP;
5217                 }
5218         }
5219
5220         if (phc.assign_projid && op == LFS_PROJECT_LIST) {
5221                 op = LFS_PROJECT_SET;
5222                 phc.set_projid = true;
5223         } else if (phc.assign_projid && op == LFS_PROJECT_SET) {
5224                 phc.set_projid = true;
5225         }
5226
5227         switch (op) {
5228         case LFS_PROJECT_CHECK:
5229                 if (phc.keep_projid) {
5230                         fprintf(stderr,
5231                                 "%s: '-k' is useless together with '-c'\n",
5232                                 progname);
5233                         return CMD_HELP;
5234                 }
5235                 break;
5236         case LFS_PROJECT_CLEAR:
5237                 if (!phc.newline) {
5238                         fprintf(stderr,
5239                                 "%s: '-0' is useless together with '-C'\n",
5240                                 progname);
5241                         return CMD_HELP;
5242                 }
5243                 if (phc.assign_projid) {
5244                         fprintf(stderr,
5245                                 "%s: '-p' is useless together with '-C'\n",
5246                                 progname);
5247                         return CMD_HELP;
5248                 }
5249                 break;
5250         case LFS_PROJECT_SET:
5251                 if (!phc.newline) {
5252                         fprintf(stderr,
5253                                 "%s: '-0' is useless together with '-s'\n",
5254                                 progname);
5255                         return CMD_HELP;
5256                 }
5257                 if (phc.keep_projid) {
5258                         fprintf(stderr,
5259                                 "%s: '-k' is useless together with '-s'\n",
5260                                 progname);
5261                         return CMD_HELP;
5262                 }
5263                 break;
5264         default:
5265                 if (!phc.newline) {
5266                         fprintf(stderr,
5267                                 "%s: '-0' is useless for list operations\n",
5268                                 progname);
5269                         return CMD_HELP;
5270                 }
5271                 break;
5272         }
5273
5274         argv += optind;
5275         argc -= optind;
5276         if (argc == 0) {
5277                 fprintf(stderr, "%s: missing file or directory target(s)\n",
5278                         progname);
5279                 return CMD_HELP;
5280         }
5281
5282         for (i = 0; i < argc; i++) {
5283                 switch (op) {
5284                 case LFS_PROJECT_CHECK:
5285                         err = lfs_project_check(argv[i], &phc);
5286                         break;
5287                 case LFS_PROJECT_LIST:
5288                         err = lfs_project_list(argv[i], &phc);
5289                         break;
5290                 case LFS_PROJECT_CLEAR:
5291                         err = lfs_project_clear(argv[i], &phc);
5292                         break;
5293                 case LFS_PROJECT_SET:
5294                         err = lfs_project_set(argv[i], &phc);
5295                         break;
5296                 default:
5297                         break;
5298                 }
5299                 if (err && !ret)
5300                         ret = err;
5301         }
5302
5303         return ret;
5304 }
5305
5306 static int lfs_quota(int argc, char **argv)
5307 {
5308         int c;
5309         char *mnt, *name = NULL;
5310         struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
5311                                     .qc_type = ALLQUOTA };
5312         char *obd_uuid = (char *)qctl.obd_uuid.uuid;
5313         int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
5314         char *endptr;
5315         __u32 valid = QC_GENERAL, idx = 0;
5316         bool human_readable = false;
5317         int qtype;
5318
5319         while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
5320                 switch (c) {
5321                 case 'u':
5322                         qtype = USRQUOTA;
5323                         goto quota_type;
5324                 case 'g':
5325                         qtype = GRPQUOTA;
5326                         goto quota_type;
5327                 case 'p':
5328                         qtype = PRJQUOTA;
5329 quota_type:
5330                         if (qctl.qc_type != ALLQUOTA) {
5331                                 fprintf(stderr,
5332                                         "%s quota: only one of -u, -g, or -p may be specified\n",
5333                                         progname);
5334                                 return CMD_HELP;
5335                         }
5336                         qctl.qc_type = qtype;
5337                         break;
5338                 case 't':
5339                         qctl.qc_cmd = LUSTRE_Q_GETINFO;
5340                         break;
5341                 case 'o':
5342                         valid = qctl.qc_valid = QC_UUID;
5343                         strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
5344                         break;
5345                 case 'i':
5346                         valid = qctl.qc_valid = QC_MDTIDX;
5347                         idx = qctl.qc_idx = atoi(optarg);
5348                         if (idx == 0 && *optarg != '0') {
5349                                 fprintf(stderr,
5350                                         "%s quota: invalid MDT index '%s'\n",
5351                                         progname, optarg);
5352                                 return CMD_HELP;
5353                         }
5354                         break;
5355                 case 'I':
5356                         valid = qctl.qc_valid = QC_OSTIDX;
5357                         idx = qctl.qc_idx = atoi(optarg);
5358                         if (idx == 0 && *optarg != '0') {
5359                                 fprintf(stderr,
5360                                         "%s quota: invalid OST index '%s'\n",
5361                                         progname, optarg);
5362                                 return CMD_HELP;
5363                         }
5364                         break;
5365                 case 'v':
5366                         verbose = 1;
5367                         break;
5368                 case 'q':
5369                         quiet = 1;
5370                         break;
5371                 case 'h':
5372                         human_readable = true;
5373                         break;
5374                 default:
5375                         fprintf(stderr, "%s quota: unrecognized option '%s'\n",
5376                                 progname, argv[optind - 1]);
5377                         return CMD_HELP;
5378                 }
5379         }
5380
5381         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
5382         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
5383             optind == argc - 1) {
5384
5385                 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
5386                 qctl.qc_valid = valid;
5387                 qctl.qc_idx = idx;
5388
5389                 for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) {
5390                         qctl.qc_type = qtype;
5391                         if (qtype == USRQUOTA) {
5392                                 qctl.qc_id = geteuid();
5393                                 rc = uid2name(&name, qctl.qc_id);
5394                         } else {
5395                                 qctl.qc_id = getegid();
5396                                 rc = gid2name(&name, qctl.qc_id);
5397                         }
5398                         if (rc)
5399                                 name = "<unknown>";
5400                         mnt = argv[optind];
5401                         rc1 = get_print_quota(mnt, name, &qctl, verbose, quiet,
5402                                               human_readable);
5403                         if (rc1 && !rc)
5404                                 rc = rc1;
5405                 }
5406         /* lfs quota -u username /path/to/lustre/mount */
5407         } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
5408                 /* options should be followed by u/g-name and mntpoint */
5409                 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
5410                         fprintf(stderr,
5411                                 "%s quota: name and mount point must be specified\n",
5412                                 progname);
5413                         return CMD_HELP;
5414                 }
5415
5416                 name = argv[optind++];
5417                 switch (qctl.qc_type) {
5418                 case USRQUOTA:
5419                         rc = name2uid(&qctl.qc_id, name);
5420                         break;
5421                 case GRPQUOTA:
5422                         rc = name2gid(&qctl.qc_id, name);
5423                         break;
5424                 case PRJQUOTA:
5425                         rc = name2projid(&qctl.qc_id, name);
5426                         break;
5427                 default:
5428                         rc = -ENOTSUP;
5429                         break;
5430                 }
5431                 if (rc) {
5432                         qctl.qc_id = strtoul(name, &endptr, 10);
5433                         if (*endptr != '\0') {
5434                                 fprintf(stderr, "%s quota: invalid id '%s'\n",
5435                                         progname, name);
5436                                 return CMD_HELP;
5437                         }
5438                 }
5439                 mnt = argv[optind];
5440                 rc = get_print_quota(mnt, name, &qctl, verbose, quiet,
5441                                      human_readable);
5442         } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
5443                 fprintf(stderr, "%s quota: missing quota info argument(s)\n",
5444                         progname);
5445                 return CMD_HELP;
5446         }
5447
5448         return rc;
5449 }
5450 #endif /* HAVE_SYS_QUOTA_H! */
5451
5452 static int flushctx_ioctl(char *mp)
5453 {
5454         int fd, rc;
5455
5456         fd = open(mp, O_RDONLY);
5457         if (fd == -1) {
5458                 fprintf(stderr, "flushctx: error open %s: %s\n",
5459                         mp, strerror(errno));
5460                 return -1;
5461         }
5462
5463         rc = ioctl(fd, LL_IOC_FLUSHCTX);
5464         if (rc == -1)
5465                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
5466                         mp, strerror(errno));
5467
5468         close(fd);
5469         return rc;
5470 }
5471
5472 static int lfs_flushctx(int argc, char **argv)
5473 {
5474         int     kdestroy = 0, c;
5475         char    mntdir[PATH_MAX] = {'\0'};
5476         int     index = 0;
5477         int     rc = 0;
5478
5479         while ((c = getopt(argc, argv, "k")) != -1) {
5480                 switch (c) {
5481                 case 'k':
5482                         kdestroy = 1;
5483                         break;
5484                 default:
5485                         fprintf(stderr, "error: %s: option '-%c' "
5486                                         "unrecognized\n", argv[0], c);
5487                         return CMD_HELP;
5488                 }
5489         }
5490
5491         if (kdestroy) {
5492             if ((rc = system("kdestroy > /dev/null")) != 0) {
5493                 rc = WEXITSTATUS(rc);
5494                 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
5495             }
5496         }
5497
5498         if (optind >= argc) {
5499                 /* flush for all mounted lustre fs. */
5500                 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
5501                         /* Check if we have a mount point */
5502                         if (mntdir[0] == '\0')
5503                                 continue;
5504
5505                         if (flushctx_ioctl(mntdir))
5506                                 rc = -1;
5507
5508                         mntdir[0] = '\0'; /* avoid matching in next loop */
5509                 }
5510         } else {
5511                 /* flush fs as specified */
5512                 while (optind < argc) {
5513                         if (flushctx_ioctl(argv[optind++]))
5514                                 rc = -1;
5515                 }
5516         }
5517         return rc;
5518 }
5519
5520 static int lfs_cp(int argc, char **argv)
5521 {
5522         fprintf(stderr, "remote client copy file(s).\n"
5523                 "obsolete, does not support it anymore.\n");
5524         return 0;
5525 }
5526
5527 static int lfs_ls(int argc, char **argv)
5528 {
5529         fprintf(stderr, "remote client lists directory contents.\n"
5530                 "obsolete, does not support it anymore.\n");
5531         return 0;
5532 }
5533
5534 static int lfs_changelog(int argc, char **argv)
5535 {
5536         void *changelog_priv;
5537         struct changelog_rec *rec;
5538         long long startrec = 0, endrec = 0;
5539         char *mdd;
5540         struct option long_opts[] = {
5541                 { .val = 'f', .name = "follow", .has_arg = no_argument },
5542                 { .name = NULL } };
5543         char short_opts[] = "f";
5544         int rc, follow = 0;
5545
5546         while ((rc = getopt_long(argc, argv, short_opts,
5547                 long_opts, NULL)) != -1) {
5548                 switch (rc) {
5549                 case 'f':
5550                         follow++;
5551                         break;
5552                 case '?':
5553                         return CMD_HELP;
5554                 default:
5555                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5556                                 argv[0], argv[optind - 1]);
5557                         return CMD_HELP;
5558                 }
5559         }
5560         if (optind >= argc)
5561                 return CMD_HELP;
5562
5563         mdd = argv[optind++];
5564         if (argc > optind)
5565                 startrec = strtoll(argv[optind++], NULL, 10);
5566         if (argc > optind)
5567                 endrec = strtoll(argv[optind++], NULL, 10);
5568
5569         rc = llapi_changelog_start(&changelog_priv,
5570                                    CHANGELOG_FLAG_BLOCK |
5571                                    CHANGELOG_FLAG_JOBID |
5572                                    CHANGELOG_FLAG_EXTRA_FLAGS |
5573                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
5574                                    mdd, startrec);
5575         if (rc < 0) {
5576                 fprintf(stderr, "Can't start changelog: %s\n",
5577                         strerror(errno = -rc));
5578                 return rc;
5579         }
5580
5581         rc = llapi_changelog_set_xflags(changelog_priv,
5582                                         CHANGELOG_EXTRA_FLAG_UIDGID |
5583                                         CHANGELOG_EXTRA_FLAG_NID |
5584                                         CHANGELOG_EXTRA_FLAG_OMODE);
5585         if (rc < 0) {
5586                 fprintf(stderr, "Can't set xflags for changelog: %s\n",
5587                         strerror(errno = -rc));
5588                 return rc;
5589         }
5590
5591         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
5592                 time_t secs;
5593                 struct tm ts;
5594
5595                 if (endrec && rec->cr_index > endrec) {
5596                         llapi_changelog_free(&rec);
5597                         break;
5598                 }
5599                 if (rec->cr_index < startrec) {
5600                         llapi_changelog_free(&rec);
5601                         continue;
5602                 }
5603
5604                 secs = rec->cr_time >> 30;
5605                 gmtime_r(&secs, &ts);
5606                 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
5607                        "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
5608                        changelog_type2str(rec->cr_type),
5609                        ts.tm_hour, ts.tm_min, ts.tm_sec,
5610                        (int)(rec->cr_time & ((1 << 30) - 1)),
5611                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
5612                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
5613
5614                 if (rec->cr_flags & CLF_JOBID) {
5615                         struct changelog_ext_jobid *jid =
5616                                 changelog_rec_jobid(rec);
5617
5618                         if (jid->cr_jobid[0] != '\0')
5619                                 printf(" j=%s", jid->cr_jobid);
5620                 }
5621
5622                 if (rec->cr_flags & CLF_EXTRA_FLAGS) {
5623                         struct changelog_ext_extra_flags *ef =
5624                                 changelog_rec_extra_flags(rec);
5625
5626                         printf(" ef=0x%llx", ef->cr_extra_flags);
5627
5628                         if (ef->cr_extra_flags & CLFE_UIDGID) {
5629                                 struct changelog_ext_uidgid *uidgid =
5630                                         changelog_rec_uidgid(rec);
5631
5632                                 printf(" u=%llu:%llu",
5633                                        uidgid->cr_uid, uidgid->cr_gid);
5634                         }
5635                         if (ef->cr_extra_flags & CLFE_NID) {
5636                                 struct changelog_ext_nid *nid =
5637                                         changelog_rec_nid(rec);
5638
5639                                 printf(" nid=%s",
5640                                        libcfs_nid2str(nid->cr_nid));
5641                         }
5642
5643                         if (ef->cr_extra_flags & CLFE_OPEN) {
5644                                 struct changelog_ext_openmode *omd =
5645                                         changelog_rec_openmode(rec);
5646                                 char mode[] = "---";
5647
5648                                 /* exec mode must be exclusive */
5649                                 if (omd->cr_openflags & MDS_FMODE_EXEC) {
5650                                         mode[2] = 'x';
5651                                 } else {
5652                                         if (omd->cr_openflags & FMODE_READ)
5653                                                 mode[0] = 'r';
5654                                         if (omd->cr_openflags &
5655                                             (FMODE_WRITE |
5656                                              MDS_OPEN_TRUNC |
5657                                              MDS_OPEN_APPEND))
5658                                                 mode[1] = 'w';
5659                                 }
5660
5661                                 if (strcmp(mode, "---") != 0)
5662                                         printf(" m=%s", mode);
5663
5664                         }
5665                 }
5666
5667                 if (rec->cr_namelen)
5668                         printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
5669                                rec->cr_namelen, changelog_rec_name(rec));
5670
5671                 if (rec->cr_flags & CLF_RENAME) {
5672                         struct changelog_ext_rename *rnm =
5673                                 changelog_rec_rename(rec);
5674
5675                         if (!fid_is_zero(&rnm->cr_sfid))
5676                                 printf(" s="DFID" sp="DFID" %.*s",
5677                                        PFID(&rnm->cr_sfid),
5678                                        PFID(&rnm->cr_spfid),
5679                                        (int)changelog_rec_snamelen(rec),
5680                                        changelog_rec_sname(rec));
5681                 }
5682                 printf("\n");
5683
5684                 llapi_changelog_free(&rec);
5685         }
5686
5687         llapi_changelog_fini(&changelog_priv);
5688
5689         if (rc < 0)
5690                 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
5691
5692         return (rc == 1 ? 0 : rc);
5693 }
5694
5695 static int lfs_changelog_clear(int argc, char **argv)
5696 {
5697         long long endrec;
5698         int rc;
5699
5700         if (argc != 4)
5701                 return CMD_HELP;
5702
5703         endrec = strtoll(argv[3], NULL, 10);
5704
5705         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
5706
5707         if (rc == -EINVAL)
5708                 fprintf(stderr, "%s: record out of range: %llu\n",
5709                         argv[0], endrec);
5710         else if (rc == -ENOENT)
5711                 fprintf(stderr, "%s: no changelog user: %s\n",
5712                         argv[0], argv[2]);
5713         else if (rc)
5714                 fprintf(stderr, "%s error: %s\n", argv[0],
5715                         strerror(-rc));
5716
5717         if (rc)
5718                 errno = -rc;
5719
5720         return rc;
5721 }
5722
5723 static int lfs_fid2path(int argc, char **argv)
5724 {
5725         struct option long_opts[] = {
5726                 { .val = 'c',   .name = "cur",  .has_arg = no_argument },
5727                 { .val = 'l',   .name = "link", .has_arg = required_argument },
5728                 { .val = 'r',   .name = "rec",  .has_arg = required_argument },
5729                 { .name = NULL } };
5730         char  short_opts[] = "cl:r:";
5731         char *device, *fid, *path;
5732         long long recno = -1;
5733         int linkno = -1;
5734         int lnktmp;
5735         int printcur = 0;
5736         int rc = 0;
5737
5738         while ((rc = getopt_long(argc, argv, short_opts,
5739                 long_opts, NULL)) != -1) {
5740                 switch (rc) {
5741                 case 'c':
5742                         printcur++;
5743                         break;
5744                 case 'l':
5745                         linkno = strtol(optarg, NULL, 10);
5746                         break;
5747                 case 'r':
5748                         recno = strtoll(optarg, NULL, 10);
5749                         break;
5750                 case '?':
5751                         return CMD_HELP;
5752                 default:
5753                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5754                                 argv[0], argv[optind - 1]);
5755                         return CMD_HELP;
5756                 }
5757         }
5758
5759         if (argc < 3)
5760                 return CMD_HELP;
5761
5762         device = argv[optind++];
5763         path = calloc(1, PATH_MAX);
5764         if (path == NULL) {
5765                 fprintf(stderr, "error: Not enough memory\n");
5766                 return -errno;
5767         }
5768
5769         rc = 0;
5770         while (optind < argc) {
5771                 fid = argv[optind++];
5772
5773                 lnktmp = (linkno >= 0) ? linkno : 0;
5774                 while (1) {
5775                         int oldtmp = lnktmp;
5776                         long long rectmp = recno;
5777                         int rc2;
5778                         rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
5779                                              &rectmp, &lnktmp);
5780                         if (rc2 < 0) {
5781                                 fprintf(stderr, "%s: error on FID %s: %s\n",
5782                                         argv[0], fid, strerror(errno = -rc2));
5783                                 if (rc == 0)
5784                                         rc = rc2;
5785                                 break;
5786                         }
5787
5788                         if (printcur)
5789                                 fprintf(stdout, "%lld ", rectmp);
5790                         if (device[0] == '/') {
5791                                 fprintf(stdout, "%s", device);
5792                                 if (device[strlen(device) - 1] != '/')
5793                                         fprintf(stdout, "/");
5794                         } else if (path[0] == '\0') {
5795                                 fprintf(stdout, "/");
5796                         }
5797                         fprintf(stdout, "%s\n", path);
5798
5799                         if (linkno >= 0)
5800                                 /* specified linkno */
5801                                 break;
5802                         if (oldtmp == lnktmp)
5803                                 /* no more links */
5804                                 break;
5805                 }
5806         }
5807
5808         free(path);
5809         return rc;
5810 }
5811
5812 static int lfs_path2fid(int argc, char **argv)
5813 {
5814         struct option long_opts[] = {
5815                 { .val = 'p', .name = "parents", .has_arg = no_argument },
5816                 { .name = NULL } };
5817         char            **path;
5818         const char        short_opts[] = "p";
5819         const char       *sep = "";
5820         struct lu_fid     fid;
5821         int               rc = 0;
5822         bool              show_parents = false;
5823
5824         while ((rc = getopt_long(argc, argv, short_opts,
5825                                  long_opts, NULL)) != -1) {
5826                 switch (rc) {
5827                 case 'p':
5828                         show_parents = true;
5829                         break;
5830                 default:
5831                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5832                                 argv[0], argv[optind - 1]);
5833                         return CMD_HELP;
5834                 }
5835         }
5836
5837         if (optind > argc - 1)
5838                 return CMD_HELP;
5839         else if (optind < argc - 1)
5840                 sep = ": ";
5841
5842         rc = 0;
5843         for (path = argv + optind; *path != NULL; path++) {
5844                 int err = 0;
5845                 if (!show_parents) {
5846                         err = llapi_path2fid(*path, &fid);
5847                         if (!err)
5848                                 printf("%s%s"DFID"\n",
5849                                        *sep != '\0' ? *path : "", sep,
5850                                        PFID(&fid));
5851                 } else {
5852                         char            name[NAME_MAX + 1];
5853                         unsigned int    linkno = 0;
5854
5855                         while ((err = llapi_path2parent(*path, linkno, &fid,
5856                                                 name, sizeof(name))) == 0) {
5857                                 if (*sep != '\0' && linkno == 0)
5858                                         printf("%s%s", *path, sep);
5859
5860                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
5861                                        PFID(&fid), name);
5862                                 linkno++;
5863                         }
5864
5865                         /* err == -ENODATA is end-of-loop */
5866                         if (linkno > 0 && err == -ENODATA) {
5867                                 printf("\n");
5868                                 err = 0;
5869                         }
5870                 }
5871
5872                 if (err) {
5873                         fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
5874                                 argv[0], show_parents ? "parent " : "", *path,
5875                                 strerror(-err));
5876                         if (rc == 0) {
5877                                 rc = err;
5878                                 errno = -err;
5879                         }
5880                 }
5881         }
5882
5883         return rc;
5884 }
5885
5886 static int lfs_data_version(int argc, char **argv)
5887 {
5888         char *path;
5889         __u64 data_version;
5890         int fd;
5891         int rc;
5892         int c;
5893         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
5894
5895         if (argc < 2)
5896                 return CMD_HELP;
5897
5898         while ((c = getopt(argc, argv, "nrw")) != -1) {
5899                 switch (c) {
5900                 case 'n':
5901                         data_version_flags = 0;
5902                         break;
5903                 case 'r':
5904                         data_version_flags |= LL_DV_RD_FLUSH;
5905                         break;
5906                 case 'w':
5907                         data_version_flags |= LL_DV_WR_FLUSH;
5908                         break;
5909                 default:
5910                         return CMD_HELP;
5911                 }
5912         }
5913         if (optind == argc)
5914                 return CMD_HELP;
5915
5916         path = argv[optind];
5917         fd = open(path, O_RDONLY);
5918         if (fd < 0)
5919                 err(errno, "cannot open file %s", path);
5920
5921         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
5922         if (rc < 0)
5923                 err(errno, "cannot get version for %s", path);
5924         else
5925                 printf("%ju" "\n", (uintmax_t)data_version);
5926
5927         close(fd);
5928         return rc;
5929 }
5930
5931 static int lfs_hsm_state(int argc, char **argv)
5932 {
5933         int rc;
5934         int i = 1;
5935         char *path;
5936         struct hsm_user_state hus;
5937
5938         if (argc < 2)
5939                 return CMD_HELP;
5940
5941         do {
5942                 path = argv[i];
5943
5944                 rc = llapi_hsm_state_get(path, &hus);
5945                 if (rc) {
5946                         fprintf(stderr, "can't get hsm state for %s: %s\n",
5947                                 path, strerror(errno = -rc));
5948                         return rc;
5949                 }
5950
5951                 /* Display path name and status flags */
5952                 printf("%s: (0x%08x)", path, hus.hus_states);
5953
5954                 if (hus.hus_states & HS_RELEASED)
5955                         printf(" released");
5956                 if (hus.hus_states & HS_EXISTS)
5957                         printf(" exists");
5958                 if (hus.hus_states & HS_DIRTY)
5959                         printf(" dirty");
5960                 if (hus.hus_states & HS_ARCHIVED)
5961                         printf(" archived");
5962                 /* Display user-settable flags */
5963                 if (hus.hus_states & HS_NORELEASE)
5964                         printf(" never_release");
5965                 if (hus.hus_states & HS_NOARCHIVE)
5966                         printf(" never_archive");
5967                 if (hus.hus_states & HS_LOST)
5968                         printf(" lost_from_hsm");
5969
5970                 if (hus.hus_archive_id != 0)
5971                         printf(", archive_id:%d", hus.hus_archive_id);
5972                 printf("\n");
5973
5974         } while (++i < argc);
5975
5976         return 0;
5977 }
5978
5979 #define LFS_HSM_SET   0
5980 #define LFS_HSM_CLEAR 1
5981
5982 /**
5983  * Generic function to set or clear HSM flags.
5984  * Used by hsm_set and hsm_clear.
5985  *
5986  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
5987  */
5988 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
5989 {
5990         struct option long_opts[] = {
5991         { .val = 'A',   .name = "archived",     .has_arg = no_argument },
5992         { .val = 'a',   .name = "noarchive",    .has_arg = no_argument },
5993         { .val = 'd',   .name = "dirty",        .has_arg = no_argument },
5994         { .val = 'e',   .name = "exists",       .has_arg = no_argument },
5995         { .val = 'l',   .name = "lost",         .has_arg = no_argument },
5996         { .val = 'r',   .name = "norelease",    .has_arg = no_argument },
5997         { .val = 'i',   .name = "archive-id",   .has_arg = required_argument },
5998         { .name = NULL } };
5999         char short_opts[] = "lraAdei:";
6000         __u64 mask = 0;
6001         int c, rc;
6002         char *path;
6003         __u32 archive_id = 0;
6004         char *end = NULL;
6005
6006         if (argc < 3)
6007                 return CMD_HELP;
6008
6009         while ((c = getopt_long(argc, argv, short_opts,
6010                                 long_opts, NULL)) != -1) {
6011                 switch (c) {
6012                 case 'l':
6013                         mask |= HS_LOST;
6014                         break;
6015                 case 'a':
6016                         mask |= HS_NOARCHIVE;
6017                         break;
6018                 case 'A':
6019                         mask |= HS_ARCHIVED;
6020                         break;
6021                 case 'r':
6022                         mask |= HS_NORELEASE;
6023                         break;
6024                 case 'd':
6025                         mask |= HS_DIRTY;
6026                         break;
6027                 case 'e':
6028                         mask |= HS_EXISTS;
6029                         break;
6030                 case 'i':
6031                         archive_id = strtol(optarg, &end, 10);
6032                         if (*end != '\0') {
6033                                 fprintf(stderr, "invalid archive_id: '%s'\n",
6034                                         end);
6035                                 return CMD_HELP;
6036                         }
6037                         break;
6038                 case '?':
6039                         return CMD_HELP;
6040                 default:
6041                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
6042                                 argv[0], argv[optind - 1]);
6043                         return CMD_HELP;
6044                 }
6045         }
6046
6047         /* User should have specified a flag */
6048         if (mask == 0)
6049                 return CMD_HELP;
6050
6051         while (optind < argc) {
6052
6053                 path = argv[optind];
6054
6055                 /* If mode == 0, this means we apply the mask. */
6056                 if (mode == LFS_HSM_SET)
6057                         rc = llapi_hsm_state_set(path, mask, 0, archive_id);
6058                 else
6059                         rc = llapi_hsm_state_set(path, 0, mask, 0);
6060
6061                 if (rc != 0) {
6062                         fprintf(stderr, "Can't change hsm flags for %s: %s\n",
6063                                 path, strerror(errno = -rc));
6064                         return rc;
6065                 }
6066                 optind++;
6067         }
6068
6069         return 0;
6070 }
6071
6072 static int lfs_hsm_action(int argc, char **argv)
6073 {
6074         int                              rc;
6075         int                              i = 1;
6076         char                            *path;
6077         struct hsm_current_action        hca;
6078         struct hsm_extent                he;
6079         enum hsm_user_action             hua;
6080         enum hsm_progress_states         hps;
6081
6082         if (argc < 2)
6083                 return CMD_HELP;
6084
6085         do {
6086                 path = argv[i];
6087
6088                 rc = llapi_hsm_current_action(path, &hca);
6089                 if (rc) {
6090                         fprintf(stderr, "can't get hsm action for %s: %s\n",
6091                                 path, strerror(errno = -rc));
6092                         return rc;
6093                 }
6094                 he = hca.hca_location;
6095                 hua = hca.hca_action;
6096                 hps = hca.hca_state;
6097
6098                 printf("%s: %s", path, hsm_user_action2name(hua));
6099
6100                 /* Skip file without action */
6101                 if (hca.hca_action == HUA_NONE) {
6102                         printf("\n");
6103                         continue;
6104                 }
6105
6106                 printf(" %s ", hsm_progress_state2name(hps));
6107
6108                 if ((hps == HPS_RUNNING) &&
6109                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
6110                         printf("(%llu bytes moved)\n",
6111                                (unsigned long long)he.length);
6112                 else if ((he.offset + he.length) == LUSTRE_EOF)
6113                         printf("(from %llu to EOF)\n",
6114                                (unsigned long long)he.offset);
6115                 else
6116                         printf("(from %llu to %llu)\n",
6117                                (unsigned long long)he.offset,
6118                                (unsigned long long)(he.offset + he.length));
6119
6120         } while (++i < argc);
6121
6122         return 0;
6123 }
6124
6125 static int lfs_hsm_set(int argc, char **argv)
6126 {
6127         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
6128 }
6129
6130 static int lfs_hsm_clear(int argc, char **argv)
6131 {
6132         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
6133 }
6134
6135 /**
6136  * Check file state and return its fid, to be used by lfs_hsm_request().
6137  *
6138  * \param[in]     file      Path to file to check
6139  * \param[in,out] fid       Pointer to allocated lu_fid struct.
6140  * \param[in,out] last_dev  Pointer to last device id used.
6141  *
6142  * \return 0 on success.
6143  */
6144 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
6145                                 dev_t *last_dev)
6146 {
6147         struct stat     st;
6148         int             rc;
6149
6150         rc = lstat(file, &st);
6151         if (rc) {
6152                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
6153                 return -errno;
6154         }
6155         /* Checking for regular file as archiving as posix copytool
6156          * rejects archiving files other than regular files
6157          */
6158         if (!S_ISREG(st.st_mode)) {
6159                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
6160                 return CMD_HELP;
6161         }
6162         /* A request should be ... */
6163         if (*last_dev != st.st_dev && *last_dev != 0) {
6164                 fprintf(stderr, "All files should be "
6165                         "on the same filesystem: %s\n", file);
6166                 return -EINVAL;
6167         }
6168         *last_dev = st.st_dev;
6169
6170         rc = llapi_path2fid(file, fid);
6171         if (rc) {
6172                 fprintf(stderr, "Cannot read FID of %s: %s\n",
6173                         file, strerror(-rc));
6174                 return rc;
6175         }
6176         return 0;
6177 }
6178
6179 /* Fill an HSM HUR item with a given file name.
6180  *
6181  * If mntpath is set, then the filename is actually a FID, and no
6182  * lookup on the filesystem will be performed.
6183  *
6184  * \param[in]  hur         the user request to fill
6185  * \param[in]  idx         index of the item inside the HUR to fill
6186  * \param[in]  mntpath     mountpoint of Lustre
6187  * \param[in]  fname       filename (if mtnpath is NULL)
6188  *                         or FID (if mntpath is set)
6189  * \param[in]  last_dev    pointer to last device id used
6190  *
6191  * \retval 0 on success
6192  * \retval CMD_HELP or a negative errno on error
6193  */
6194 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
6195                          const char *mntpath, const char *fname,
6196                          dev_t *last_dev)
6197 {
6198         struct hsm_user_item *hui = &hur->hur_user_item[idx];
6199         int rc;
6200
6201         hui->hui_extent.length = -1;
6202
6203         if (mntpath != NULL) {
6204                 if (*fname == '[')
6205                         fname++;
6206                 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
6207                 if (rc == 3) {
6208                         rc = 0;
6209                 } else {
6210                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
6211                                 fname);
6212                         rc = -EINVAL;
6213                 }
6214         } else {
6215                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
6216         }
6217
6218         if (rc == 0)
6219                 hur->hur_request.hr_itemcount++;
6220
6221         return rc;
6222 }
6223
6224 static int lfs_hsm_request(int argc, char **argv, int action)
6225 {
6226         struct option long_opts[] = {
6227         { .val = 'a',   .name = "archive",      .has_arg = required_argument },
6228         { .val = 'D',   .name = "data",         .has_arg = required_argument },
6229         { .val = 'l',   .name = "filelist",     .has_arg = required_argument },
6230         { .val = 'm',   .name = "mntpath",      .has_arg = required_argument },
6231         { .name = NULL } };
6232         dev_t                    last_dev = 0;
6233         char                     short_opts[] = "l:D:a:m:";
6234         struct hsm_user_request *hur, *oldhur;
6235         int                      c, i;
6236         size_t                   len;
6237         int                      nbfile;
6238         char                    *line = NULL;
6239         char                    *filelist = NULL;
6240         char                     fullpath[PATH_MAX];
6241         char                    *opaque = NULL;
6242         int                      opaque_len = 0;
6243         int                      archive_id = 0;
6244         FILE                    *fp;
6245         int                      nbfile_alloc = 0;
6246         char                    *some_file = NULL;
6247         char                    *mntpath = NULL;
6248         int                      rc;
6249
6250         if (argc < 2)
6251                 return CMD_HELP;
6252
6253         while ((c = getopt_long(argc, argv, short_opts,
6254                                 long_opts, NULL)) != -1) {
6255                 switch (c) {
6256                 case 'l':
6257                         filelist = optarg;
6258                         break;
6259                 case 'D':
6260                         opaque = optarg;
6261                         break;
6262                 case 'a':
6263                         if (action != HUA_ARCHIVE &&
6264                             action != HUA_REMOVE) {
6265                                 fprintf(stderr,
6266                                         "error: -a is supported only "
6267                                         "when archiving or removing\n");
6268                                 return CMD_HELP;
6269                         }
6270                         archive_id = atoi(optarg);
6271                         break;
6272                 case 'm':
6273                         if (some_file == NULL) {
6274                                 mntpath = optarg;
6275                                 some_file = strdup(optarg);
6276                         }
6277                         break;
6278                 case '?':
6279                         return CMD_HELP;
6280                 default:
6281                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
6282                                 argv[0], argv[optind - 1]);
6283                         return CMD_HELP;
6284                 }
6285         }
6286
6287         /* All remaining args are files, so we have at least nbfile */
6288         nbfile = argc - optind;
6289
6290         if ((nbfile == 0) && (filelist == NULL))
6291                 return CMD_HELP;
6292
6293         if (opaque != NULL)
6294                 opaque_len = strlen(opaque);
6295
6296         /* Alloc the request structure with enough place to store all files
6297          * from command line. */
6298         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
6299         if (hur == NULL) {
6300                 fprintf(stderr, "Cannot create the request: %s\n",
6301                         strerror(errno));
6302                 return errno;
6303         }
6304         nbfile_alloc = nbfile;
6305
6306         hur->hur_request.hr_action = action;
6307         hur->hur_request.hr_archive_id = archive_id;
6308         hur->hur_request.hr_flags = 0;
6309
6310         /* All remaining args are files, add them */
6311         if (nbfile != 0 && some_file == NULL)
6312                 some_file = strdup(argv[optind]);
6313
6314         for (i = 0; i < nbfile; i++) {
6315                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
6316                                    &last_dev);
6317                 if (rc)
6318                         goto out_free;
6319         }
6320
6321         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
6322
6323         /* If a filelist was specified, read the filelist from it. */
6324         if (filelist != NULL) {
6325                 fp = fopen(filelist, "r");
6326                 if (fp == NULL) {
6327                         fprintf(stderr, "Cannot read the file list %s: %s\n",
6328                                 filelist, strerror(errno));
6329                         rc = -errno;
6330                         goto out_free;
6331                 }
6332
6333                 while ((rc = getline(&line, &len, fp)) != -1) {
6334                         /* If allocated buffer was too small, get something
6335                          * larger */
6336                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
6337                                 ssize_t size;
6338
6339                                 nbfile_alloc = nbfile_alloc * 2 + 1;
6340                                 oldhur = hur;
6341                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
6342                                                                    opaque_len);
6343                                 if (hur == NULL) {
6344                                         fprintf(stderr, "hsm: cannot allocate "
6345                                                 "the request: %s\n",
6346                                                 strerror(errno));
6347                                         hur = oldhur;
6348                                         rc = -errno;
6349                                         fclose(fp);
6350                                         goto out_free;
6351                                 }
6352                                 size = hur_len(oldhur);
6353                                 if (size < 0) {
6354                                         fprintf(stderr, "hsm: cannot allocate "
6355                                                 "%u files + %u bytes data\n",
6356                                             oldhur->hur_request.hr_itemcount,
6357                                             oldhur->hur_request.hr_data_len);
6358                                         free(hur);
6359                                         hur = oldhur;
6360                                         rc = -E2BIG;
6361                                         fclose(fp);
6362                                         goto out_free;
6363                                 }
6364                                 memcpy(hur, oldhur, size);
6365                                 free(oldhur);
6366                         }
6367
6368                         /* Chop CR */
6369                         if (line[strlen(line) - 1] == '\n')
6370                                 line[strlen(line) - 1] = '\0';
6371
6372                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
6373                                            mntpath, line, &last_dev);
6374                         if (rc) {
6375                                 fclose(fp);
6376                                 goto out_free;
6377                         }
6378
6379                         if (some_file == NULL) {
6380                                 some_file = line;
6381                                 line = NULL;
6382                         }
6383                 }
6384
6385                 rc = fclose(fp);
6386                 free(line);
6387         }
6388
6389         /* If a --data was used, add it to the request */
6390         hur->hur_request.hr_data_len = opaque_len;
6391         if (opaque != NULL)
6392                 memcpy(hur_data(hur), opaque, opaque_len);
6393
6394         /* Send the HSM request */
6395         if (realpath(some_file, fullpath) == NULL) {
6396                 fprintf(stderr, "Could not find path '%s': %s\n",
6397                         some_file, strerror(errno));
6398         }
6399         rc = llapi_hsm_request(fullpath, hur);
6400         if (rc) {
6401                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
6402                         some_file, strerror(-rc));
6403                 goto out_free;
6404         }
6405
6406 out_free:
6407         free(some_file);
6408         free(hur);
6409         return rc;
6410 }
6411
6412 static int lfs_hsm_archive(int argc, char **argv)
6413 {
6414         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
6415 }
6416
6417 static int lfs_hsm_restore(int argc, char **argv)
6418 {
6419         return lfs_hsm_request(argc, argv, HUA_RESTORE);
6420 }
6421
6422 static int lfs_hsm_release(int argc, char **argv)
6423 {
6424         return lfs_hsm_request(argc, argv, HUA_RELEASE);
6425 }
6426
6427 static int lfs_hsm_remove(int argc, char **argv)
6428 {
6429         return lfs_hsm_request(argc, argv, HUA_REMOVE);
6430 }
6431
6432 static int lfs_hsm_cancel(int argc, char **argv)
6433 {
6434         return lfs_hsm_request(argc, argv, HUA_CANCEL);
6435 }
6436
6437 static int lfs_swap_layouts(int argc, char **argv)
6438 {
6439         if (argc != 3)
6440                 return CMD_HELP;
6441
6442         return llapi_swap_layouts(argv[1], argv[2], 0, 0,
6443                                   SWAP_LAYOUTS_KEEP_MTIME |
6444                                   SWAP_LAYOUTS_KEEP_ATIME);
6445 }
6446
6447 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
6448
6449 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
6450
6451 int lfs_get_mode(const char *string)
6452 {
6453         enum lock_mode_user mode;
6454
6455         for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
6456                 if (lock_mode_names[mode] == NULL)
6457                         continue;
6458                 if (strcmp(string, lock_mode_names[mode]) == 0)
6459                         return mode;
6460         }
6461
6462         return -EINVAL;
6463 }
6464
6465 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
6466 {
6467         enum lu_ladvise_type advice;
6468
6469         for (advice = 0;
6470              advice < ARRAY_SIZE(ladvise_names); advice++) {
6471                 if (ladvise_names[advice] == NULL)
6472                         continue;
6473                 if (strcmp(string, ladvise_names[advice]) == 0)
6474                         return advice;
6475         }
6476
6477         return LU_LADVISE_INVALID;
6478 }
6479
6480 static int lfs_ladvise(int argc, char **argv)
6481 {
6482         struct option long_opts[] = {
6483         { .val = 'a',   .name = "advice",       .has_arg = required_argument },
6484         { .val = 'b',   .name = "background",   .has_arg = no_argument },
6485         { .val = 'e',   .name = "end",          .has_arg = required_argument },
6486         { .val = 'l',   .name = "length",       .has_arg = required_argument },
6487         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
6488         { .val = 's',   .name = "start",        .has_arg = required_argument },
6489         { .val = 'u',   .name = "unset",        .has_arg = no_argument },
6490         { .name = NULL } };
6491         char                     short_opts[] = "a:be:l:m:s:u";
6492         int                      c;
6493         int                      rc = 0;
6494         const char              *path;
6495         int                      fd;
6496         struct llapi_lu_ladvise  advice;
6497         enum lu_ladvise_type     advice_type = LU_LADVISE_INVALID;
6498         unsigned long long       start = 0;
6499         unsigned long long       end = LUSTRE_EOF;
6500         unsigned long long       length = 0;
6501         unsigned long long       size_units;
6502         unsigned long long       flags = 0;
6503         int                      mode = 0;
6504
6505         optind = 0;
6506         while ((c = getopt_long(argc, argv, short_opts,
6507                                 long_opts, NULL)) != -1) {
6508                 switch (c) {
6509                 case 'a':
6510                         advice_type = lfs_get_ladvice(optarg);
6511                         if (advice_type == LU_LADVISE_INVALID) {
6512                                 fprintf(stderr, "%s: invalid advice type "
6513                                         "'%s'\n", argv[0], optarg);
6514                                 fprintf(stderr, "Valid types:");
6515
6516                                 for (advice_type = 0;
6517                                      advice_type < ARRAY_SIZE(ladvise_names);
6518                                      advice_type++) {
6519                                         if (ladvise_names[advice_type] == NULL)
6520                                                 continue;
6521                                         fprintf(stderr, " %s",
6522                                                 ladvise_names[advice_type]);
6523                                 }
6524                                 fprintf(stderr, "\n");
6525
6526                                 return CMD_HELP;
6527                         }
6528                         break;
6529                 case 'b':
6530                         flags |= LF_ASYNC;
6531                         break;
6532                 case 'u':
6533                         flags |= LF_UNSET;
6534                         break;
6535                 case 'e':
6536                         size_units = 1;
6537                         rc = llapi_parse_size(optarg, &end,
6538                                               &size_units, 0);
6539                         if (rc) {
6540                                 fprintf(stderr, "%s: bad end offset '%s'\n",
6541                                         argv[0], optarg);
6542                                 return CMD_HELP;
6543                         }
6544                         break;
6545                 case 's':
6546                         size_units = 1;
6547                         rc = llapi_parse_size(optarg, &start,
6548                                               &size_units, 0);
6549                         if (rc) {
6550                                 fprintf(stderr, "%s: bad start offset "
6551                                         "'%s'\n", argv[0], optarg);
6552                                 return CMD_HELP;
6553                         }
6554                         break;
6555                 case 'l':
6556                         size_units = 1;
6557                         rc = llapi_parse_size(optarg, &length,
6558                                               &size_units, 0);
6559                         if (rc) {
6560                                 fprintf(stderr, "%s: bad length '%s'\n",
6561                                         argv[0], optarg);
6562                                 return CMD_HELP;
6563                         }
6564                         break;
6565                 case 'm':
6566                         mode = lfs_get_mode(optarg);
6567                         if (mode < 0) {
6568                                 fprintf(stderr, "%s: bad mode '%s', valid "
6569                                                  "modes are READ or WRITE\n",
6570                                         argv[0], optarg);
6571                                 return CMD_HELP;
6572                         }
6573                         break;
6574                 case '?':
6575                         return CMD_HELP;
6576                 default:
6577                         fprintf(stderr, "%s: option '%s' unrecognized\n",
6578                                 argv[0], argv[optind - 1]);
6579                         return CMD_HELP;
6580                 }
6581         }
6582
6583         if (advice_type == LU_LADVISE_INVALID) {
6584                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
6585                 fprintf(stderr, "Valid types:");
6586                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
6587                      advice_type++) {
6588                         if (ladvise_names[advice_type] == NULL)
6589                                 continue;
6590                         fprintf(stderr, " %s", ladvise_names[advice_type]);
6591                 }
6592                 fprintf(stderr, "\n");
6593                 return CMD_HELP;
6594         }
6595
6596         if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
6597                 fprintf(stderr, "%s: Lock no expand advice is a per file "
6598                                  "descriptor advice, so when called from lfs, "
6599                                  "it does nothing.\n", argv[0]);
6600                 return CMD_HELP;
6601         }
6602
6603         if (argc <= optind) {
6604                 fprintf(stderr, "%s: please give one or more file names\n",
6605                         argv[0]);
6606                 return CMD_HELP;
6607         }
6608
6609         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
6610                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
6611                         argv[0]);
6612                 return CMD_HELP;
6613         }
6614
6615         if (end == LUSTRE_EOF && length != 0)
6616                 end = start + length;
6617
6618         if (end <= start) {
6619                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
6620                         argv[0], start, end);
6621                 return CMD_HELP;
6622         }
6623
6624         if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
6625                 fprintf(stderr, "%s: mode is only valid with lockahead\n",
6626                         argv[0]);
6627                 return CMD_HELP;
6628         }
6629
6630         if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
6631                 fprintf(stderr, "%s: mode is required with lockahead\n",
6632                         argv[0]);
6633                 return CMD_HELP;
6634         }
6635
6636         while (optind < argc) {
6637                 int rc2;
6638
6639                 path = argv[optind++];
6640
6641                 fd = open(path, O_RDONLY);
6642                 if (fd < 0) {
6643                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
6644                                 argv[0], path, strerror(errno));
6645                         rc2 = -errno;
6646                         goto next;
6647                 }
6648
6649                 advice.lla_start = start;
6650                 advice.lla_end = end;
6651                 advice.lla_advice = advice_type;
6652                 advice.lla_value1 = 0;
6653                 advice.lla_value2 = 0;
6654                 advice.lla_value3 = 0;
6655                 advice.lla_value4 = 0;
6656                 if (advice_type == LU_LADVISE_LOCKAHEAD) {
6657                         advice.lla_lockahead_mode = mode;
6658                         advice.lla_peradvice_flags = flags;
6659                 }
6660
6661                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
6662                 close(fd);
6663                 if (rc2 < 0) {
6664                         fprintf(stderr, "%s: cannot give advice '%s' to file "
6665                                 "'%s': %s\n", argv[0],
6666                                 ladvise_names[advice_type],
6667                                 path, strerror(errno));
6668
6669                         goto next;
6670                 }
6671
6672 next:
6673                 if (rc == 0 && rc2 < 0)
6674                         rc = rc2;
6675         }
6676         return rc;
6677 }
6678
6679 /** The input string contains a comma delimited list of component ids and
6680  * ranges, for example "1,2-4,7".
6681  */
6682 static int parse_mirror_ids(__u16 *ids, int size, char *arg)
6683 {
6684         bool end_of_loop = false;
6685         char *ptr = NULL;
6686         int nr = 0;
6687         int rc;
6688
6689         if (arg == NULL)
6690                 return -EINVAL;
6691
6692         while (!end_of_loop) {
6693                 int start_index;
6694                 int end_index;
6695                 int i;
6696                 char *endptr = NULL;
6697
6698                 rc = -EINVAL;
6699                 ptr = strchrnul(arg, ',');
6700                 end_of_loop = *ptr == '\0';
6701                 *ptr = '\0';
6702
6703                 start_index = strtol(arg, &endptr, 0);
6704                 if (endptr == arg) /* no data at all */
6705                         break;
6706                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
6707                         break;
6708                 if (start_index < 0)
6709                         break;
6710
6711                 end_index = start_index;
6712                 if (*endptr == '-') {
6713                         end_index = strtol(endptr + 1, &endptr, 0);
6714                         if (*endptr != '\0')
6715                                 break;
6716                         if (end_index < start_index)
6717                                 break;
6718                 }
6719
6720                 for (i = start_index; i <= end_index && size > 0; i++) {
6721                         int j;
6722
6723                         /* remove duplicate */
6724                         for (j = 0; j < nr; j++) {
6725                                 if (ids[j] == i)
6726                                         break;
6727                         }
6728                         if (j == nr) { /* no duplicate */
6729                                 ids[nr++] = i;
6730                                 --size;
6731                         }
6732                 }
6733
6734                 if (size == 0 && i < end_index)
6735                         break;
6736
6737                 *ptr = ',';
6738                 arg = ++ptr;
6739                 rc = 0;
6740         }
6741         if (!end_of_loop && ptr != NULL)
6742                 *ptr = ',';
6743
6744         return rc < 0 ? rc : nr;
6745 }
6746
6747 /**
6748  * struct verify_mirror_id - Mirror id to be verified.
6749  * @mirror_id:   A specified mirror id.
6750  * @is_valid_id: @mirror_id is valid or not in the mirrored file.
6751  */
6752 struct verify_mirror_id {
6753         __u16 mirror_id;
6754         bool is_valid_id;
6755 };
6756
6757 /**
6758  * compare_mirror_ids() - Compare mirror ids.
6759  * @layout: Mirror component list.
6760  * @cbdata: Callback data in verify_mirror_id structure.
6761  *
6762  * This is a callback function called by llapi_layout_comp_iterate()
6763  * to compare the specified mirror id with the one in the current
6764  * component of @layout. If they are the same, then the specified
6765  * mirror id is valid.
6766  *
6767  * Return: a negative error code on failure or
6768  *         LLAPI_LAYOUT_ITER_CONT: Proceed iteration
6769  *         LLAPI_LAYOUT_ITER_STOP: Stop iteration
6770  */
6771 static inline
6772 int compare_mirror_ids(struct llapi_layout *layout, void *cbdata)
6773 {
6774         struct verify_mirror_id *mirror_id_cbdata =
6775                                  (struct verify_mirror_id *)cbdata;
6776         uint32_t mirror_id;
6777         int rc = 0;
6778
6779         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
6780         if (rc < 0) {
6781                 rc = -errno;
6782                 fprintf(stderr,
6783                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
6784                         progname, strerror(errno));
6785                 return rc;
6786         }
6787
6788         if (mirror_id_cbdata->mirror_id == mirror_id) {
6789                 mirror_id_cbdata->is_valid_id = true;
6790                 return LLAPI_LAYOUT_ITER_STOP;
6791         }
6792
6793         return LLAPI_LAYOUT_ITER_CONT;
6794 }
6795
6796 /**
6797  * verify_mirror_ids() - Verify specified mirror ids.
6798  * @fname:      Mirrored file name.
6799  * @mirror_ids: Specified mirror ids to be verified.
6800  * @ids_nr:     Number of specified mirror ids.
6801  *
6802  * This function verifies that specified @mirror_ids are valid
6803  * in the mirrored file @fname.
6804  *
6805  * Return: 0 on success or a negative error code on failure.
6806  */
6807 static inline
6808 int verify_mirror_ids(const char *fname, __u16 *mirror_ids, int ids_nr)
6809 {
6810         struct llapi_layout *layout = NULL;
6811         struct verify_mirror_id mirror_id_cbdata = { 0 };
6812         struct stat stbuf;
6813         uint32_t flr_state;
6814         int i;
6815         int fd;
6816         int rc = 0;
6817         int rc2 = 0;
6818
6819         if (ids_nr <= 0)
6820                 return -EINVAL;
6821
6822         if (stat(fname, &stbuf) < 0) {
6823                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
6824                         progname, fname, strerror(errno));
6825                 rc = -errno;
6826                 goto error;
6827         }
6828
6829         if (!S_ISREG(stbuf.st_mode)) {
6830                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
6831                         progname, fname);
6832                 rc = -EINVAL;
6833                 goto error;
6834         }
6835
6836         fd = open(fname, O_DIRECT | O_RDONLY);
6837         if (fd < 0) {
6838                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
6839                         progname, fname, strerror(errno));
6840                 rc = -errno;
6841                 goto error;
6842         }
6843
6844         rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
6845         if (rc < 0) {
6846                 fprintf(stderr, "%s: '%s' llapi_lease_get failed: %s.\n",
6847                         progname, fname, strerror(errno));
6848                 goto close_fd;
6849         }
6850
6851         layout = llapi_layout_get_by_fd(fd, 0);
6852         if (layout == NULL) {
6853                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
6854                         progname, fname, strerror(errno));
6855                 rc = -errno;
6856                 llapi_lease_put(fd);
6857                 goto close_fd;
6858         }
6859
6860         rc = llapi_layout_flags_get(layout, &flr_state);
6861         if (rc < 0) {
6862                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
6863                         progname, fname, strerror(errno));
6864                 rc = -errno;
6865                 goto free_layout;
6866         }
6867
6868         flr_state &= LCM_FL_FLR_MASK;
6869         switch (flr_state) {
6870         case LCM_FL_NOT_FLR:
6871                 rc = -EINVAL;
6872                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
6873                         progname, fname, lcm_flags_string(flr_state));
6874                 goto free_layout;
6875         default:
6876                 break;
6877         }
6878
6879         rc2 = 0;
6880         for (i = 0; i < ids_nr; i++) {
6881                 mirror_id_cbdata.mirror_id = mirror_ids[i];
6882                 mirror_id_cbdata.is_valid_id = false;
6883
6884                 rc = llapi_layout_comp_iterate(layout, compare_mirror_ids,
6885                                                &mirror_id_cbdata);
6886                 if (rc < 0) {
6887                         rc = -errno;
6888                         fprintf(stderr,
6889                                 "%s: '%s' failed to verify mirror id: %u.\n",
6890                                 progname, fname, mirror_ids[i]);
6891                         goto free_layout;
6892                 }
6893
6894                 if (!mirror_id_cbdata.is_valid_id) {
6895                         rc2 = -EINVAL;
6896                         fprintf(stderr,
6897                                 "%s: '%s' invalid specified mirror id: %u.\n",
6898                                 progname, fname, mirror_ids[i]);
6899                 }
6900         }
6901         rc = rc2;
6902
6903 free_layout:
6904         llapi_layout_free(layout);
6905         llapi_lease_put(fd);
6906 close_fd:
6907         close(fd);
6908 error:
6909         return rc;
6910 }
6911
6912 static inline
6913 int lfs_mirror_resync_file(const char *fname, struct ll_ioc_lease *ioc,
6914                            __u16 *mirror_ids, int ids_nr)
6915 {
6916         const char *progname = "lfs mirror resync";
6917         struct llapi_resync_comp comp_array[1024] = { { 0 } };
6918         struct llapi_layout *layout;
6919         struct stat stbuf;
6920         uint32_t flr_state;
6921         int comp_size = 0;
6922         int idx;
6923         int fd;
6924         int rc;
6925
6926         if (stat(fname, &stbuf) < 0) {
6927                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
6928                         progname, fname, strerror(errno));
6929                 rc = -errno;
6930                 goto error;
6931         }
6932         if (!S_ISREG(stbuf.st_mode)) {
6933                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
6934                         progname, fname);
6935                 rc = -EINVAL;
6936                 goto error;
6937         }
6938
6939         fd = open(fname, O_DIRECT | O_RDWR);
6940         if (fd < 0) {
6941                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
6942                         progname, fname, strerror(errno));
6943                 rc = -errno;
6944                 goto error;
6945         }
6946
6947         ioc->lil_mode = LL_LEASE_WRLCK;
6948         ioc->lil_flags = LL_LEASE_RESYNC;
6949         rc = llapi_lease_set(fd, ioc);
6950         if (rc < 0) {
6951                 fprintf(stderr, "%s: '%s' llapi_lease_set resync failed: "
6952                         "%s.\n", progname, fname, strerror(errno));
6953                 goto close_fd;
6954         }
6955
6956         layout = llapi_layout_get_by_fd(fd, 0);
6957         if (layout == NULL) {
6958                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
6959                         progname, fname, strerror(errno));
6960                 rc = -errno;
6961                 goto close_fd;
6962         }
6963
6964         rc = llapi_layout_flags_get(layout, &flr_state);
6965         if (rc) {
6966                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
6967                         progname, fname, strerror(errno));
6968                 rc = -errno;
6969                 goto close_fd;
6970         }
6971
6972         flr_state &= LCM_FL_FLR_MASK;
6973         switch (flr_state) {
6974         case LCM_FL_NOT_FLR:
6975                 rc = -EINVAL;
6976         case LCM_FL_RDONLY:
6977                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
6978                         progname, fname, lcm_flags_string(flr_state));
6979                 goto close_fd;
6980         default:
6981                 break;
6982         }
6983
6984         /* get stale component info */
6985         comp_size = llapi_mirror_find_stale(layout, comp_array,
6986                                             ARRAY_SIZE(comp_array),
6987                                             mirror_ids, ids_nr);
6988         if (comp_size < 0) {
6989                 rc = comp_size;
6990                 goto close_fd;
6991         }
6992
6993         idx = 0;
6994         while (idx < comp_size) {
6995                 ssize_t result;
6996                 uint64_t end;
6997                 __u16 mirror_id;
6998                 int i;
6999
7000                 rc = llapi_lease_check(fd);
7001                 if (rc != LL_LEASE_WRLCK) {
7002                         fprintf(stderr, "%s: '%s' lost lease lock.\n",
7003                                 progname, fname);
7004                         goto close_fd;
7005                 }
7006
7007                 mirror_id = comp_array[idx].lrc_mirror_id;
7008                 end = comp_array[idx].lrc_end;
7009
7010                 /* try to combine adjacent component */
7011                 for (i = idx + 1; i < comp_size; i++) {
7012                         if (mirror_id != comp_array[i].lrc_mirror_id ||
7013                             end != comp_array[i].lrc_start)
7014                                 break;
7015                         end = comp_array[i].lrc_end;
7016                 }
7017
7018                 result = llapi_mirror_resync_one(fd, layout, mirror_id,
7019                                                  comp_array[idx].lrc_start,
7020                                                  end);
7021                 if (result < 0) {
7022                         fprintf(stderr, "%s: '%s' llapi_mirror_resync_one: "
7023                                 "%ld.\n", progname, fname, result);
7024                         rc = result;
7025                         goto close_fd;
7026                 } else if (result > 0) {
7027                         int j;
7028
7029                         /* mark synced components */
7030                         for (j = idx; j < i; j++)
7031                                 comp_array[j].lrc_synced = true;
7032                 }
7033
7034                 idx = i;
7035         }
7036
7037         /* prepare ioc for lease put */
7038         ioc->lil_mode = LL_LEASE_UNLCK;
7039         ioc->lil_flags = LL_LEASE_RESYNC_DONE;
7040         ioc->lil_count = 0;
7041         for (idx = 0; idx < comp_size; idx++) {
7042                 if (comp_array[idx].lrc_synced) {
7043                         ioc->lil_ids[ioc->lil_count] = comp_array[idx].lrc_id;
7044                         ioc->lil_count++;
7045                 }
7046         }
7047
7048         llapi_layout_free(layout);
7049
7050         rc = llapi_lease_set(fd, ioc);
7051         if (rc <= 0) {
7052                 if (rc == 0) /* lost lease lock */
7053                         rc = -EBUSY;
7054                 fprintf(stderr, "%s: resync file '%s' failed: %s.\n",
7055                         progname, fname, strerror(errno));
7056                 goto close_fd;
7057         }
7058         /**
7059          * llapi_lease_set returns lease mode when it request to unlock
7060          * the lease lock
7061          */
7062         rc = 0;
7063
7064 close_fd:
7065         close(fd);
7066 error:
7067         return rc;
7068 }
7069
7070 static inline int lfs_mirror_resync(int argc, char **argv)
7071 {
7072         struct ll_ioc_lease *ioc = NULL;
7073         __u16 mirror_ids[128] = { 0 };
7074         int ids_nr = 0;
7075         int c;
7076         int rc = 0;
7077
7078         struct option long_opts[] = {
7079         { .val = 'o',   .name = "only",         .has_arg = required_argument },
7080         { .name = NULL } };
7081
7082         while ((c = getopt_long(argc, argv, "o:", long_opts, NULL)) >= 0) {
7083                 switch (c) {
7084                 case 'o':
7085                         rc = parse_mirror_ids(mirror_ids,
7086                                         sizeof(mirror_ids) / sizeof(__u16),
7087                                         optarg);
7088                         if (rc < 0) {
7089                                 fprintf(stderr,
7090                                         "%s: bad mirror ids '%s'.\n",
7091                                         argv[0], optarg);
7092                                 goto error;
7093                         }
7094                         ids_nr = rc;
7095                         break;
7096                 default:
7097                         fprintf(stderr, "%s: options '%s' unrecognized.\n",
7098                                 argv[0], argv[optind - 1]);
7099                         rc = -EINVAL;
7100                         goto error;
7101                 }
7102         }
7103
7104         if (argc == optind) {
7105                 fprintf(stderr, "%s: no file name given.\n", argv[0]);
7106                 rc = CMD_HELP;
7107                 goto error;
7108         }
7109
7110         if (ids_nr > 0 && argc > optind + 1) {
7111                 fprintf(stderr, "%s: option '--only' cannot be used upon "
7112                         "multiple files.\n", argv[0]);
7113                 rc = CMD_HELP;
7114                 goto error;
7115
7116         }
7117
7118         if (ids_nr > 0) {
7119                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
7120                 if (rc < 0)
7121                         goto error;
7122         }
7123
7124         /* set the lease on the file */
7125         ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
7126         if (ioc == NULL) {
7127                 fprintf(stderr, "%s: cannot alloc id array for ioc: %s.\n",
7128                         argv[0], strerror(errno));
7129                 rc = -errno;
7130                 goto error;
7131         }
7132
7133         for (; optind < argc; optind++) {
7134                 rc = lfs_mirror_resync_file(argv[optind], ioc,
7135                                             mirror_ids, ids_nr);
7136                 if (rc)
7137                         fprintf(stderr, "%s: resync file '%s' failed: %d\n",
7138                                 argv[0], argv[optind], rc);
7139                 /* ignore previous file's error, continue with next file */
7140
7141                 /* reset ioc */
7142                 memset(ioc, 0, sizeof(__u32) * 4096);
7143         }
7144
7145         free(ioc);
7146 error:
7147         return rc;
7148 }
7149
7150 /**
7151  * struct verify_chunk - Mirror chunk to be verified.
7152  * @chunk:        [start, end) of the chunk.
7153  * @mirror_count: Number of mirror ids in @mirror_id array.
7154  * @mirror_id:    Array of valid mirror ids that cover the chunk.
7155  */
7156 struct verify_chunk {
7157         struct lu_extent chunk;
7158         unsigned int mirror_count;
7159         __u16 mirror_id[LUSTRE_MIRROR_COUNT_MAX];
7160 };
7161
7162 /**
7163  * print_chunks() - Print chunk information.
7164  * @fname:       Mirrored file name.
7165  * @chunks:      Array of chunks.
7166  * @chunk_count: Number of chunks in @chunks array.
7167  *
7168  * This function prints [start, end) of each chunk in @chunks
7169  * for mirrored file @fname, and also prints the valid mirror ids
7170  * that cover the chunk.
7171  *
7172  * Return: void.
7173  */
7174 static inline
7175 void print_chunks(const char *fname, struct verify_chunk *chunks,
7176                   int chunk_count)
7177 {
7178         int i;
7179         int j;
7180
7181         fprintf(stdout, "Chunks to be verified in %s:\n", fname);
7182         for (i = 0; i < chunk_count; i++) {
7183                 fprintf(stdout, DEXT, PEXT(&chunks[i].chunk));
7184
7185                 if (chunks[i].mirror_count == 0)
7186                         fprintf(stdout, "\t[");
7187                 else {
7188                         fprintf(stdout, "\t[%u", chunks[i].mirror_id[0]);
7189                         for (j = 1; j < chunks[i].mirror_count; j++)
7190                                 fprintf(stdout, ", %u", chunks[i].mirror_id[j]);
7191                 }
7192                 fprintf(stdout, "]\t%u\n", chunks[i].mirror_count);
7193         }
7194         fprintf(stdout, "\n");
7195 }
7196
7197 /**
7198  * print_checksums() - Print CRC-32 checksum values.
7199  * @chunk: A chunk and its corresponding valid mirror ids.
7200  * @crc:   CRC-32 checksum values on the chunk for each valid mirror.
7201  *
7202  * This function prints CRC-32 checksum values on @chunk for
7203  * each valid mirror that covers it.
7204  *
7205  * Return: void.
7206  */
7207 static inline
7208 void print_checksums(struct verify_chunk *chunk, unsigned long *crc)
7209 {
7210         int i;
7211
7212         fprintf(stdout,
7213                 "CRC-32 checksum value for chunk "DEXT":\n",
7214                 PEXT(&chunk->chunk));
7215         for (i = 0; i < chunk->mirror_count; i++)
7216                 fprintf(stdout, "Mirror %u:\t%#lx\n",
7217                         chunk->mirror_id[i], crc[i]);
7218         fprintf(stdout, "\n");
7219 }
7220
7221 /**
7222  * filter_mirror_id() - Filter specified mirror ids.
7223  * @chunks:      Array of chunks.
7224  * @chunk_count: Number of chunks in @chunks array.
7225  * @mirror_ids:  Specified mirror ids to be verified.
7226  * @ids_nr:      Number of specified mirror ids.
7227  *
7228  * This function scans valid mirror ids that cover each chunk in @chunks
7229  * and filters specified mirror ids.
7230  *
7231  * Return: void.
7232  */
7233 static inline
7234 void filter_mirror_id(struct verify_chunk *chunks, int chunk_count,
7235                       __u16 *mirror_ids, int ids_nr)
7236 {
7237         int i;
7238         int j;
7239         int k;
7240         __u16 valid_id[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
7241         unsigned int valid_count = 0;
7242
7243         for (i = 0; i < chunk_count; i++) {
7244                 if (chunks[i].mirror_count == 0)
7245                         continue;
7246
7247                 valid_count = 0;
7248                 for (j = 0; j < ids_nr; j++) {
7249                         for (k = 0; k < chunks[i].mirror_count; k++) {
7250                                 if (chunks[i].mirror_id[k] == mirror_ids[j]) {
7251                                         valid_id[valid_count] = mirror_ids[j];
7252                                         valid_count++;
7253                                         break;
7254                                 }
7255                         }
7256                 }
7257
7258                 memcpy(chunks[i].mirror_id, valid_id,
7259                        sizeof(__u16) * valid_count);
7260                 chunks[i].mirror_count = valid_count;
7261         }
7262 }
7263
7264 /**
7265  * lfs_mirror_prepare_chunk() - Find mirror chunks to be verified.
7266  * @layout:      Mirror component list.
7267  * @chunks:      Array of chunks.
7268  * @chunks_size: Array size of @chunks.
7269  *
7270  * This function scans the components in @layout from offset 0 to LUSTRE_EOF
7271  * to find out chunk segments and store them in @chunks array.
7272  *
7273  * The @mirror_id array in each element of @chunks will store the valid
7274  * mirror ids that cover the chunk. If a mirror component covering the
7275  * chunk has LCME_FL_STALE or LCME_FL_OFFLINE flag, then the mirror id
7276  * will not be stored into the @mirror_id array, and the chunk for that
7277  * mirror will not be verified.
7278  *
7279  * The @mirror_count in each element of @chunks will store the number of
7280  * mirror ids in @mirror_id array. If @mirror_count is 0, it indicates the
7281  * chunk is invalid in all of the mirrors. And if @mirror_count is 1, it
7282  * indicates the chunk is valid in only one mirror. In both cases, the
7283  * chunk will not be verified.
7284  *
7285  * Here is an example:
7286  *
7287  *  0      1M     2M     3M     4M           EOF
7288  *  +------+-------------+--------------------+
7289  *  |      |             |      S             |       mirror1
7290  *  +------+------+------+------+-------------+
7291  *  |             |   S  |   S  |             |       mirror2
7292  *  +-------------+------+------+-------------+
7293  *
7294  * prepared @chunks array will contain 5 elements:
7295  * (([0, 1M), [1, 2], 2),
7296  *  ([1M, 2M), [1, 2], 2),
7297  *  ([2M, 3M), [1], 1),
7298  *  ([3M, 4M], [], 0),
7299  *  ([4M, EOF), [2], 1))
7300  *
7301  * Return: the actual array size of @chunks on success
7302  *         or a negative error code on failure.
7303  */
7304 static inline
7305 int lfs_mirror_prepare_chunk(struct llapi_layout *layout,
7306                              struct verify_chunk *chunks,
7307                              size_t chunks_size)
7308 {
7309         uint64_t start;
7310         uint64_t end;
7311         uint32_t mirror_id;
7312         uint32_t flags;
7313         int idx = 0;
7314         int i = 0;
7315         int rc = 0;
7316
7317         memset(chunks, 0, sizeof(*chunks) * chunks_size);
7318
7319         while (1) {
7320                 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
7321                 if (rc < 0) {
7322                         fprintf(stderr,
7323                                 "%s: move to the first layout component: %s.\n",
7324                                 progname, strerror(errno));
7325                         goto error;
7326                 }
7327
7328                 i = 0;
7329                 rc = 0;
7330                 chunks[idx].chunk.e_end = LUSTRE_EOF;
7331                 while (rc == 0) {
7332                         rc = llapi_layout_comp_extent_get(layout, &start, &end);
7333                         if (rc < 0) {
7334                                 fprintf(stderr,
7335                                         "%s: llapi_layout_comp_extent_get failed: %s.\n",
7336                                         progname, strerror(errno));
7337                                 goto error;
7338                         }
7339
7340                         if (start > chunks[idx].chunk.e_start ||
7341                             end <= chunks[idx].chunk.e_start)
7342                                 goto next;
7343
7344                         if (end < chunks[idx].chunk.e_end)
7345                                 chunks[idx].chunk.e_end = end;
7346
7347                         rc = llapi_layout_comp_flags_get(layout, &flags);
7348                         if (rc < 0) {
7349                                 fprintf(stderr,
7350                                         "%s: llapi_layout_comp_flags_get failed: %s.\n",
7351                                         progname, strerror(errno));
7352                                 goto error;
7353                         }
7354
7355                         if (flags & LCME_FL_STALE || flags & LCME_FL_OFFLINE)
7356                                 goto next;
7357
7358                         rc = llapi_layout_mirror_id_get(layout, &mirror_id);
7359                         if (rc < 0) {
7360                                 fprintf(stderr,
7361                                         "%s: llapi_layout_mirror_id_get failed: %s.\n",
7362                                         progname, strerror(errno));
7363                                 goto error;
7364                         }
7365
7366                         chunks[idx].mirror_id[i] = mirror_id;
7367                         i++;
7368                         if (i >= ARRAY_SIZE(chunks[idx].mirror_id)) {
7369                                 fprintf(stderr,
7370                                         "%s: mirror_id array is too small.\n",
7371                                         progname);
7372                                 rc = -EINVAL;
7373                                 goto error;
7374                         }
7375
7376                 next:
7377                         rc = llapi_layout_comp_use(layout,
7378                                                    LLAPI_LAYOUT_COMP_USE_NEXT);
7379                         if (rc < 0) {
7380                                 fprintf(stderr,
7381                                         "%s: move to the next layout component: %s.\n",
7382                                         progname, strerror(errno));
7383                                 goto error;
7384                         }
7385                 } /* loop through all components */
7386
7387                 chunks[idx].mirror_count = i;
7388
7389                 if (chunks[idx].chunk.e_end == LUSTRE_EOF)
7390                         break;
7391
7392                 idx++;
7393                 if (idx >= chunks_size) {
7394                         fprintf(stderr, "%s: chunks array is too small.\n",
7395                                 progname);
7396                         rc = -EINVAL;
7397                         goto error;
7398                 }
7399
7400                 chunks[idx].chunk.e_start = chunks[idx - 1].chunk.e_end;
7401         }
7402
7403 error:
7404         return rc < 0 ? rc : idx + 1;
7405 }
7406
7407 /**
7408  * lfs_mirror_verify_chunk() - Verify a chunk.
7409  * @fd:        File descriptor of the mirrored file.
7410  * @file_size: Size of the mirrored file.
7411  * @chunk:     A chunk and its corresponding valid mirror ids.
7412  * @verbose:   Verbose mode.
7413  *
7414  * This function verifies a @chunk contains exactly the same data
7415  * ammong the mirrors that cover it.
7416  *
7417  * If @verbose is specified, then the function will print where the
7418  * differences are if the data do not match. Otherwise, it will
7419  * just return an error in that case.
7420  *
7421  * Return: 0 on success or a negative error code on failure.
7422  */
7423 static inline
7424 int lfs_mirror_verify_chunk(int fd, size_t file_size,
7425                             struct verify_chunk *chunk, int verbose)
7426 {
7427         const size_t buflen = 4 * 1024 * 1024; /* 4M */
7428         void *buf;
7429         size_t page_size = sysconf(_SC_PAGESIZE);
7430         ssize_t bytes_read;
7431         ssize_t bytes_done;
7432         size_t count;
7433         off_t pos;
7434         unsigned long crc;
7435         unsigned long crc_array[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
7436         int i;
7437         int rc = 0;
7438
7439         if (file_size == 0)
7440                 return 0;
7441
7442         rc = posix_memalign(&buf, page_size, buflen);
7443         if (rc) /* error code is returned directly */
7444                 return -rc;
7445
7446         if (verbose > 1) {
7447                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
7448                         PEXT(&chunk->chunk));
7449                 for (i = 0; i < chunk->mirror_count; i++)
7450                         fprintf(stdout, " %u", chunk->mirror_id[i]);
7451                 fprintf(stdout, "\n");
7452         }
7453
7454         bytes_done = 0;
7455         count = MIN(chunk->chunk.e_end, file_size) - chunk->chunk.e_start;
7456         pos = chunk->chunk.e_start;
7457         while (bytes_done < count) {
7458                 /* compute initial CRC-32 checksum */
7459                 crc = crc32(0L, Z_NULL, 0);
7460                 memset(crc_array, 0, sizeof(crc_array));
7461
7462                 bytes_read = 0;
7463                 for (i = 0; i < chunk->mirror_count; i++) {
7464                         bytes_read = llapi_mirror_read(fd, chunk->mirror_id[i],
7465                                                        buf, buflen, pos);
7466                         if (bytes_read < 0) {
7467                                 rc = bytes_read;
7468                                 fprintf(stderr,
7469                                         "%s: failed to read data from mirror %u: %s.\n",
7470                                         progname, chunk->mirror_id[i],
7471                                         strerror(-rc));
7472                                 goto error;
7473                         }
7474
7475                         /* compute new CRC-32 checksum */
7476                         crc_array[i] = crc32(crc, buf, bytes_read);
7477                 }
7478
7479                 if (verbose)
7480                         print_checksums(chunk, crc_array);
7481
7482                 /* compare CRC-32 checksum values */
7483                 for (i = 1; i < chunk->mirror_count; i++) {
7484                         if (crc_array[i] != crc_array[0]) {
7485                                 rc = -EINVAL;
7486                                 if (!verbose)
7487                                         goto error;
7488
7489                                 fprintf(stderr,
7490                                         "%s: chunk "DEXT" has different checksum value on mirror %u and mirror %u.\n",
7491                                         progname, PEXT(&chunk->chunk),
7492                                         chunk->mirror_id[0],
7493                                         chunk->mirror_id[i]);
7494                         }
7495                 }
7496
7497                 pos += bytes_read;
7498                 bytes_done += bytes_read;
7499         }
7500
7501         if (verbose > 1 && rc == 0) {
7502                 fprintf(stdout, "Verifying chunk "DEXT" on mirror:",
7503                         PEXT(&chunk->chunk));
7504                 for (i = 0; i < chunk->mirror_count; i++)
7505                         fprintf(stdout, " %u", chunk->mirror_id[i]);
7506                 fprintf(stdout, " PASS\n\n");
7507         }
7508
7509 error:
7510         free(buf);
7511         return rc;
7512 }
7513
7514 /**
7515  * lfs_mirror_verify_file() - Verify a mirrored file.
7516  * @fname:      Mirrored file name.
7517  * @mirror_ids: Specified mirror ids to be verified.
7518  * @ids_nr:     Number of specified mirror ids.
7519  * @verbose:    Verbose mode.
7520  *
7521  * This function verifies that each SYNC mirror of a mirrored file
7522  * specified by @fname contains exactly the same data.
7523  *
7524  * If @mirror_ids is specified, then the function will verify the
7525  * mirrors specified by @mirror_ids contain exactly the same data.
7526  *
7527  * If @verbose is specified, then the function will print where the
7528  * differences are if the data do not match. Otherwise, it will
7529  * just return an error in that case.
7530  *
7531  * Return: 0 on success or a negative error code on failure.
7532  */
7533 static inline
7534 int lfs_mirror_verify_file(const char *fname, __u16 *mirror_ids, int ids_nr,
7535                            int verbose)
7536 {
7537         struct verify_chunk chunks_array[1024] = { };
7538         struct llapi_layout *layout = NULL;
7539         struct stat stbuf;
7540         uint32_t flr_state;
7541         int fd;
7542         int chunk_count = 0;
7543         int idx = 0;
7544         int rc = 0;
7545         int rc1 = 0;
7546         int rc2 = 0;
7547
7548         if (stat(fname, &stbuf) < 0) {
7549                 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
7550                         progname, fname, strerror(errno));
7551                 rc = -errno;
7552                 goto error;
7553         }
7554
7555         if (!S_ISREG(stbuf.st_mode)) {
7556                 fprintf(stderr, "%s: '%s' is not a regular file.\n",
7557                         progname, fname);
7558                 rc = -EINVAL;
7559                 goto error;
7560         }
7561
7562         if (stbuf.st_size == 0) {
7563                 if (verbose)
7564                         fprintf(stdout, "%s: '%s' file size is 0.\n",
7565                                 progname, fname);
7566                 rc = 0;
7567                 goto error;
7568         }
7569
7570         fd = open(fname, O_DIRECT | O_RDONLY);
7571         if (fd < 0) {
7572                 fprintf(stderr, "%s: cannot open '%s': %s.\n",
7573                         progname, fname, strerror(errno));
7574                 rc = -errno;
7575                 goto error;
7576         }
7577
7578         rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
7579         if (rc < 0) {
7580                 fprintf(stderr, "%s: '%s' llapi_lease_get failed: %s.\n",
7581                         progname, fname, strerror(errno));
7582                 goto close_fd;
7583         }
7584
7585         layout = llapi_layout_get_by_fd(fd, 0);
7586         if (layout == NULL) {
7587                 fprintf(stderr, "%s: '%s' llapi_layout_get_by_fd failed: %s.\n",
7588                         progname, fname, strerror(errno));
7589                 rc = -errno;
7590                 llapi_lease_put(fd);
7591                 goto close_fd;
7592         }
7593
7594         rc = llapi_layout_flags_get(layout, &flr_state);
7595         if (rc < 0) {
7596                 fprintf(stderr, "%s: '%s' llapi_layout_flags_get failed: %s.\n",
7597                         progname, fname, strerror(errno));
7598                 rc = -errno;
7599                 goto free_layout;
7600         }
7601
7602         flr_state &= LCM_FL_FLR_MASK;
7603         switch (flr_state) {
7604         case LCM_FL_NOT_FLR:
7605                 rc = -EINVAL;
7606                 fprintf(stderr, "%s: '%s' file state error: %s.\n",
7607                         progname, fname, lcm_flags_string(flr_state));
7608                 goto free_layout;
7609         default:
7610                 break;
7611         }
7612
7613         /* find out mirror chunks to be verified */
7614         chunk_count = lfs_mirror_prepare_chunk(layout, chunks_array,
7615                                                ARRAY_SIZE(chunks_array));
7616         if (chunk_count < 0) {
7617                 rc = chunk_count;
7618                 goto free_layout;
7619         }
7620
7621         if (ids_nr > 0)
7622                 /* filter specified mirror ids */
7623                 filter_mirror_id(chunks_array, chunk_count, mirror_ids, ids_nr);
7624
7625         if (verbose > 2)
7626                 print_chunks(fname, chunks_array, chunk_count);
7627
7628         for (idx = 0; idx < chunk_count; idx++) {
7629                 if (chunks_array[idx].chunk.e_start >= stbuf.st_size) {
7630                         if (verbose)
7631                                 fprintf(stdout,
7632                                         "%s: '%s' chunk "DEXT" exceeds file size %#llx: skipped\n",
7633                                         progname, fname,
7634                                         PEXT(&chunks_array[idx].chunk),
7635                                         (unsigned long long)stbuf.st_size);
7636                         break;
7637                 }
7638
7639                 if (chunks_array[idx].mirror_count == 0) {
7640                         fprintf(stderr,
7641                                 "%s: '%s' chunk "DEXT" is invalid in all of the mirrors: ",
7642                                 progname, fname,
7643                                 PEXT(&chunks_array[idx].chunk));
7644                         if (verbose) {
7645                                 fprintf(stderr, "skipped\n");
7646                                 continue;
7647                         }
7648                         rc = -EINVAL;
7649                         fprintf(stderr, "failed\n");
7650                         goto free_layout;
7651                 }
7652
7653                 if (chunks_array[idx].mirror_count == 1) {
7654                         if (verbose)
7655                                 fprintf(stdout,
7656                                         "%s: '%s' chunk "DEXT" is only valid in mirror %u: skipped\n",
7657                                         progname, fname,
7658                                         PEXT(&chunks_array[idx].chunk),
7659                                         chunks_array[idx].mirror_id[0]);
7660                         continue;
7661                 }
7662
7663                 rc = llapi_lease_check(fd);
7664                 if (rc != LL_LEASE_RDLCK) {
7665                         fprintf(stderr, "%s: '%s' lost lease lock.\n",
7666                                 progname, fname);
7667                         goto free_layout;
7668                 }
7669
7670                 /* verify one chunk */
7671                 rc1 = lfs_mirror_verify_chunk(fd, stbuf.st_size,
7672                                               &chunks_array[idx], verbose);
7673                 if (rc1 < 0) {
7674                         rc2 = rc1;
7675                         if (!verbose) {
7676                                 rc = rc1;
7677                                 goto free_layout;
7678                         }
7679                 }
7680         }
7681
7682         if (rc2 < 0)
7683                 rc = rc2;
7684
7685 free_layout:
7686         llapi_layout_free(layout);
7687         llapi_lease_put(fd);
7688 close_fd:
7689         close(fd);
7690 error:
7691         return rc;
7692 }
7693
7694 /**
7695  * lfs_mirror_verify() - Parse and execute lfs mirror verify command.
7696  * @argc: The count of lfs mirror verify command line arguments.
7697  * @argv: Array of strings for lfs mirror verify command line arguments.
7698  *
7699  * This function parses lfs mirror verify command and verifies the
7700  * specified mirrored file(s).
7701  *
7702  * Return: 0 on success or a negative error code on failure.
7703  */
7704 static inline int lfs_mirror_verify(int argc, char **argv)
7705 {
7706         __u16 mirror_ids[LUSTRE_MIRROR_COUNT_MAX] = { 0 };
7707         int ids_nr = 0;
7708         int c;
7709         int verbose = 0;
7710         int rc = 0;
7711         int rc1 = 0;
7712         char cmd[PATH_MAX];
7713
7714         struct option long_opts[] = {
7715         { .val = 'o',   .name = "only",         .has_arg = required_argument },
7716         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
7717         { .name = NULL } };
7718
7719         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
7720         progname = cmd;
7721         while ((c = getopt_long(argc, argv, "o:v", long_opts, NULL)) >= 0) {
7722                 switch (c) {
7723                 case 'o':
7724                         rc = parse_mirror_ids(mirror_ids,
7725                                               ARRAY_SIZE(mirror_ids),
7726                                               optarg);
7727                         if (rc < 0) {
7728                                 fprintf(stderr,
7729                                         "%s: bad mirror ids '%s'.\n",
7730                                         progname, optarg);
7731                                 goto error;
7732                         }
7733                         ids_nr = rc;
7734                         if (ids_nr < 2) {
7735                                 fprintf(stderr,
7736                                         "%s: at least 2 mirror ids needed with '--only' option.\n",
7737                                         progname);
7738                                 rc = CMD_HELP;
7739                                 goto error;
7740                         }
7741                         break;
7742                 case 'v':
7743                         verbose++;
7744                         break;
7745                 default:
7746                         fprintf(stderr, "%s: options '%s' unrecognized.\n",
7747                                 progname, argv[optind - 1]);
7748                         rc = -EINVAL;
7749                         goto error;
7750                 }
7751         }
7752
7753         if (argc == optind) {
7754                 fprintf(stderr, "%s: no file name given.\n", progname);
7755                 rc = CMD_HELP;
7756                 goto error;
7757         }
7758
7759         if (ids_nr > 0 && argc > optind + 1) {
7760                 fprintf(stderr,
7761                         "%s: '--only' cannot be used upon multiple files.\n",
7762                         progname);
7763                 rc = CMD_HELP;
7764                 goto error;
7765
7766         }
7767
7768         if (ids_nr > 0) {
7769                 rc = verify_mirror_ids(argv[optind], mirror_ids, ids_nr);
7770                 if (rc < 0)
7771                         goto error;
7772         }
7773
7774         rc = 0;
7775         for (; optind < argc; optind++) {
7776                 rc1 = lfs_mirror_verify_file(argv[optind], mirror_ids, ids_nr,
7777                                              verbose);
7778                 if (rc1 < 0)
7779                         rc = rc1;
7780         }
7781 error:
7782         return rc;
7783 }
7784
7785 /**
7786  * lfs_mirror() - Parse and execute lfs mirror commands.
7787  * @argc: The count of lfs mirror command line arguments.
7788  * @argv: Array of strings for lfs mirror command line arguments.
7789  *
7790  * This function parses lfs mirror commands and performs the
7791  * corresponding functions specified in mirror_cmdlist[].
7792  *
7793  * Return: 0 on success or an error code on failure.
7794  */
7795 static int lfs_mirror(int argc, char **argv)
7796 {
7797         char cmd[PATH_MAX];
7798         int rc = 0;
7799
7800         setlinebuf(stdout);
7801
7802         Parser_init("lfs-mirror > ", mirror_cmdlist);
7803
7804         snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
7805         progname = cmd;
7806         program_invocation_short_name = cmd;
7807         if (argc > 1)
7808                 rc = Parser_execarg(argc - 1, argv + 1, mirror_cmdlist);
7809         else
7810                 rc = Parser_commands();
7811
7812         return rc < 0 ? -rc : rc;
7813 }
7814
7815 /**
7816  * lfs_mirror_list_commands() - List lfs mirror commands.
7817  * @argc: The count of command line arguments.
7818  * @argv: Array of strings for command line arguments.
7819  *
7820  * This function lists lfs mirror commands defined in mirror_cmdlist[].
7821  *
7822  * Return: 0 on success.
7823  */
7824 static int lfs_mirror_list_commands(int argc, char **argv)
7825 {
7826         char buffer[81] = "";
7827
7828         Parser_list_commands(mirror_cmdlist, buffer, sizeof(buffer),
7829                              NULL, 0, 4);
7830
7831         return 0;
7832 }
7833
7834 static int lfs_list_commands(int argc, char **argv)
7835 {
7836         char buffer[81] = ""; /* 80 printable chars + terminating NUL */
7837
7838         Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
7839
7840         return 0;
7841 }
7842
7843 int main(int argc, char **argv)
7844 {
7845         int rc;
7846
7847         /* Ensure that liblustreapi constructor has run */
7848         if (!llapi_liblustreapi_initialized())
7849                 fprintf(stderr, "liblustreapi was not properly initialized\n");
7850
7851         setlinebuf(stdout);
7852         opterr = 0;
7853
7854         Parser_init("lfs > ", cmdlist);
7855
7856         progname = program_invocation_short_name; /* Used in error messages */
7857         if (argc > 1) {
7858                 llapi_set_command_name(argv[1]);
7859                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
7860                 llapi_clear_command_name();
7861         } else {
7862                 rc = Parser_commands();
7863         }
7864
7865         return rc < 0 ? -rc : rc;
7866 }
7867
7868 #ifdef _LUSTRE_IDL_H_
7869 /* Everything we need here should be included by lustreapi.h. */
7870 # error "lfs should not depend on lustre_idl.h"
7871 #endif /* _LUSTRE_IDL_H_ */