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