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