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