Whamcloud - gitweb
026e36e5c853d576d05b4e21b655ae1a52ff74c3
[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, 2016, 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 <getopt.h>
47 #include <string.h>
48 #include <mntent.h>
49 #include <unistd.h>
50 #include <errno.h>
51 #include <err.h>
52 #include <pwd.h>
53 #include <grp.h>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
56 #include <sys/time.h>
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <fcntl.h>
60 #include <dirent.h>
61 #include <time.h>
62 #include <ctype.h>
63
64 #include <libcfs/util/string.h>
65 #include <libcfs/util/ioctl.h>
66 #include <libcfs/util/parser.h>
67 #include <lustre/lustreapi.h>
68 #include <linux/lustre/lustre_ver.h>
69 #include <linux/lustre/lustre_param.h>
70
71 #ifndef ARRAY_SIZE
72 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
73 #endif /* !ARRAY_SIZE */
74
75 /* all functions */
76 static int lfs_setstripe(int argc, char **argv);
77 static int lfs_find(int argc, char **argv);
78 static int lfs_getstripe(int argc, char **argv);
79 static int lfs_getdirstripe(int argc, char **argv);
80 static int lfs_setdirstripe(int argc, char **argv);
81 static int lfs_rmentry(int argc, char **argv);
82 static int lfs_osts(int argc, char **argv);
83 static int lfs_mdts(int argc, char **argv);
84 static int lfs_df(int argc, char **argv);
85 static int lfs_getname(int argc, char **argv);
86 static int lfs_check(int argc, char **argv);
87 #ifdef HAVE_SYS_QUOTA_H
88 static int lfs_setquota(int argc, char **argv);
89 static int lfs_quota(int argc, char **argv);
90 #endif
91 static int lfs_flushctx(int argc, char **argv);
92 static int lfs_cp(int argc, char **argv);
93 static int lfs_ls(int argc, char **argv);
94 static int lfs_poollist(int argc, char **argv);
95 static int lfs_changelog(int argc, char **argv);
96 static int lfs_changelog_clear(int argc, char **argv);
97 static int lfs_fid2path(int argc, char **argv);
98 static int lfs_path2fid(int argc, char **argv);
99 static int lfs_data_version(int argc, char **argv);
100 static int lfs_hsm_state(int argc, char **argv);
101 static int lfs_hsm_set(int argc, char **argv);
102 static int lfs_hsm_clear(int argc, char **argv);
103 static int lfs_hsm_action(int argc, char **argv);
104 static int lfs_hsm_archive(int argc, char **argv);
105 static int lfs_hsm_restore(int argc, char **argv);
106 static int lfs_hsm_release(int argc, char **argv);
107 static int lfs_hsm_remove(int argc, char **argv);
108 static int lfs_hsm_cancel(int argc, char **argv);
109 static int lfs_swap_layouts(int argc, char **argv);
110 static int lfs_mv(int argc, char **argv);
111 static int lfs_ladvise(int argc, char **argv);
112 static int lfs_list_commands(int argc, char **argv);
113
114 /* Setstripe and migrate share mostly the same parameters */
115 #define SSM_CMD_COMMON(cmd) \
116         "usage: "cmd" [--component-end|-E <comp_end>]\n"                \
117         "                 [--stripe-count|-c <stripe_count>]\n"         \
118         "                 [--stripe-index|-i <start_ost_idx>]\n"        \
119         "                 [--stripe-size|-S <stripe_size>]\n"           \
120         "                 [--layout|-L <pattern>]\n"            \
121         "                 [--pool|-p <pool_name>]\n"                    \
122         "                 [--ost|-o <ost_indices>]\n"
123
124 #define SSM_HELP_COMMON \
125         "\tstripe_count: Number of OSTs to stripe over (0=fs default, -1 all)\n" \
126         "\tstart_ost_idx: OST index of first stripe (-1=default round robin)\n"\
127         "\tstripe_size:  Number of bytes on each OST (0=fs default)\n" \
128         "\t              Can be specified with K, M or G (for KB, MB, GB\n" \
129         "\t              respectively)\n"                               \
130         "\tpool_name:    Name of OST pool to use (default none)\n"      \
131         "\tlayout:       stripe pattern type: raid0, mdt (default raid0)\n"\
132         "\tost_indices:  List of OST indices, can be repeated multiple times\n"\
133         "\t              Indices be specified in a format of:\n"        \
134         "\t                -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n"        \
135         "\t              Or:\n"                                         \
136         "\t                -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n"  \
137         "\t              If --pool is set with --ost, then the OSTs\n"  \
138         "\t              must be the members of the pool.\n"            \
139         "\tcomp_end:     Extent end of component, start after previous end.\n"\
140         "\t              Can be specified with K, M or G (for KB, MB, GB\n" \
141         "\t              respectively, -1 for EOF). Must be a multiple of\n"\
142         "\t              stripe_size.\n"
143
144
145 #define MIGRATE_USAGE                                                   \
146         SSM_CMD_COMMON("migrate  ")                                     \
147         "                 [--block|-b]\n"                               \
148         "                 [--non-block|-n]\n"                           \
149         "                 <filename>\n"                                 \
150         SSM_HELP_COMMON                                                 \
151         "\n"                                                            \
152         "\tblock:        Block file access during data migration (default)\n" \
153         "\tnon-block:    Abort migrations if concurrent access is detected\n" \
154
155 #define SETDIRSTRIPE_USAGE                                      \
156         "               [--mdt-count|-c stripe_count>\n"        \
157         "               [--mdt-index|-i mdt_index]\n"           \
158         "               [--mdt-hash|-H mdt_hash]\n"             \
159         "               [--default|-D] [--mode|-m mode] <dir>\n"        \
160         "\tstripe_count: stripe count of the striped directory\n"       \
161         "\tmdt_index: MDT index of first stripe\n"                      \
162         "\tmdt_hash:  hash type of the striped directory. mdt types:\n" \
163         "       fnv_1a_64 FNV-1a hash algorithm (default)\n"            \
164         "       all_char  sum of characters % MDT_COUNT (not recommended)\n" \
165         "\tdefault_stripe: set default dirstripe of the directory\n"    \
166         "\tmode: the mode of the directory\n"
167
168 static const char       *progname;
169 static bool              file_lease_supported = true;
170
171 /* all available commands */
172 command_t cmdlist[] = {
173         {"setstripe", lfs_setstripe, 0,
174          "To create a file with specified striping/composite layout, or\n"
175          "create/replace the default layout on an existing directory:\n"
176          SSM_CMD_COMMON("setstripe")
177          "                 <directory|filename>\n"
178          " or\n"
179          "To add component(s) to an existing composite file:\n"
180          SSM_CMD_COMMON("setstripe --component-add")
181          SSM_HELP_COMMON
182          "To totally delete the default striping from an existing directory:\n"
183          "usage: setstripe -d <directory>\n"
184          " or\n"
185          "To delete the last component(s) from an existing composite file\n"
186          "(note that this will also delete any data in those components):\n"
187          "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
188          "                               [--component-flags|-F <comp_flags>]\n"
189          "                               <filename>\n"
190          "\tcomp_id:     Unique component ID to delete\n"
191          "\tcomp_flags:  'init' indicating all instantiated components\n"
192          "\t             '^init' indicating all uninstantiated components\n"
193          "\t-I and -F cannot be specified at the same time\n"},
194         {"getstripe", lfs_getstripe, 0,
195          "To list the striping info for a given file or files in a\n"
196          "directory or recursively for all files in a directory tree.\n"
197          "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
198          "                 [--stripe-count|-c] [--stripe-index|-i]\n"
199          "                 [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
200          "                 [--mdt|-m] [--recursive|-r] [--raw|-R] [--yaml|-y]\n"
201          "                 [--layout|-L] [--fid|-F] [--generation|-g]\n"
202          "                 [--component-id[=comp_id]|-I[comp_id]]\n"
203          "                 [--component-flags[=comp_flags]]\n"
204          "                 [--component-count]\n"
205          "                 [--component-start[=[+-]comp_start]]\n"
206          "                 [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
207          "                 <directory|filename> ..."},
208         {"setdirstripe", lfs_setdirstripe, 0,
209          "To create a striped directory on a specified MDT. This can only\n"
210          "be done on MDT0 with the right of administrator.\n"
211          "usage: setdirstripe [OPTION] <directory>\n"
212          SETDIRSTRIPE_USAGE},
213         {"getdirstripe", lfs_getdirstripe, 0,
214          "To list the striping info for a given directory\n"
215          "or recursively for all directories in a directory tree.\n"
216          "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
217          "                    [--mdt-index|-i] [--mdt-hash|-t]\n"
218          "                    [--recursive|-r] [--yaml|-y]\n"
219          "                    [--default|-D] <dir> ..."},
220         {"mkdir", lfs_setdirstripe, 0,
221          "To create a striped directory on a specified MDT. This can only\n"
222          "be done on MDT0 with the right of administrator.\n"
223          "usage: mkdir [OPTION] <directory>\n"
224          SETDIRSTRIPE_USAGE},
225         {"rm_entry", lfs_rmentry, 0,
226          "To remove the name entry of the remote directory. Note: This\n"
227          "command will only delete the name entry, i.e. the remote directory\n"
228          "will become inaccessable after this command. This can only be done\n"
229          "by the administrator\n"
230          "usage: rm_entry <dir>\n"},
231         {"pool_list", lfs_poollist, 0,
232          "List pools or pool OSTs\n"
233          "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
234         {"find", lfs_find, 0,
235          "find files matching given attributes recursively in directory tree.\n"
236          "usage: find <directory|filename> ...\n"
237          "     [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
238          "     [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
239          "     [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
240          "     [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
241          "     [[!] --size|-s [+-]N[bkMGTPE]]\n"
242          "     [[!] --stripe-count|-c [+-]<stripes>]\n"
243          "     [[!] --stripe-index|-i <index,...>]\n"
244          "     [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
245          "     [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
246          "     [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
247          "     [[!] --projid <projid>]\n"
248          "     [[!] --layout|-L released,raid0,mdt]\n"
249          "     [[!] --component-count [+-]<comp_cnt>]\n"
250          "     [[!] --component-start [+-]N[kMGTPE]]\n"
251          "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
252          "     [[!] --component-flags <comp_flags>]\n"
253          "     [[!] --mdt-count|-T [+-]<stripes>]\n"
254          "     [[!] --mdt-hash|-H <hashtype>\n"
255          "\t !: used before an option indicates 'NOT' requested attribute\n"
256          "\t -: used before a value indicates less than requested value\n"
257          "\t +: used before a value indicates more than requested value\n"
258          "\tmdt-hash:   hash type of the striped directory.\n"
259          "\t            fnv_1a_64 FNV-1a hash algorithm\n"
260          "\t            all_char  sum of characters % MDT_COUNT\n"},
261         {"check", lfs_check, 0,
262          "Display the status of MDS or OSTs (as specified in the command)\n"
263          "or all the servers (MDS and OSTs).\n"
264          "usage: check <osts|mds|servers>"},
265         {"osts", lfs_osts, 0, "list OSTs connected to client "
266          "[for specified path only]\n" "usage: osts [path]"},
267         {"mdts", lfs_mdts, 0, "list MDTs connected to client "
268          "[for specified path only]\n" "usage: mdts [path]"},
269         {"df", lfs_df, 0,
270          "report filesystem disk space usage or inodes usage"
271          "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
272          "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
273         {"getname", lfs_getname, 0, "list instances and specified mount points "
274          "[for specified path only]\n"
275          "Usage: getname [-h]|[path ...] "},
276 #ifdef HAVE_SYS_QUOTA_H
277         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
278          "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
279          "                -b <block-softlimit> -B <block-hardlimit>\n"
280          "                -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
281          "       setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
282          "                [--block-softlimit <block-softlimit>]\n"
283          "                [--block-hardlimit <block-hardlimit>]\n"
284          "                [--inode-softlimit <inode-softlimit>]\n"
285          "                [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
286          "       setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
287          "                [--block-grace <block-grace>]\n"
288          "                [--inode-grace <inode-grace>] <filesystem>\n"
289          "       -b can be used instead of --block-softlimit/--block-grace\n"
290          "       -B can be used instead of --block-hardlimit\n"
291          "       -i can be used instead of --inode-softlimit/--inode-grace\n"
292          "       -I can be used instead of --inode-hardlimit\n\n"
293          "Note: The total quota space will be split into many qunits and\n"
294          "      balanced over all server targets, the minimal qunit size is\n"
295          "      1M bytes for block space and 1K inodes for inode space.\n\n"
296          "      Quota space rebalancing process will stop when this mininum\n"
297          "      value is reached. As a result, quota exceeded can be returned\n"
298          "      while many targets still have 1MB or 1K inodes of spare\n"
299          "      quota space."},
300         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
301          "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
302                        "<ost_idx>]\n"
303          "             [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
304          "       quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
305 #endif
306         {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
307          "usage: flushctx [-k] [mountpoint...]"},
308         {"cp", lfs_cp, 0,
309          "Remote user copy files and directories.\n"
310          "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
311         {"ls", lfs_ls, 0,
312          "Remote user list directory contents.\n"
313          "usage: ls [OPTION]... [FILE]..."},
314         {"changelog", lfs_changelog, 0,
315          "Show the metadata changes on an MDT."
316          "\nusage: changelog <mdtname> [startrec [endrec]]"},
317         {"changelog_clear", lfs_changelog_clear, 0,
318          "Indicate that old changelog records up to <endrec> are no longer of "
319          "interest to consumer <id>, allowing the system to free up space.\n"
320          "An <endrec> of 0 means all records.\n"
321          "usage: changelog_clear <mdtname> <id> <endrec>"},
322         {"fid2path", lfs_fid2path, 0,
323          "Resolve the full path(s) for given FID(s). For a specific hardlink "
324          "specify link number <linkno>.\n"
325         /* "For a historical link name, specify changelog record <recno>.\n" */
326          "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
327                 /* [ --rec <recno> ] */ },
328         {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
329          "usage: path2fid [--parents] <path> ..."},
330         {"data_version", lfs_data_version, 0, "Display file data version for "
331          "a given path.\n" "usage: data_version -[n|r|w] <path>"},
332         {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
333          "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
334         {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
335          "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
336          "[--archived] [--lost] <file> ..."},
337         {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
338          "files.\n"
339          "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
340          "[--archived] [--lost] <file> ..."},
341         {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
342          "given files.\n" "usage: hsm_action <file> ..."},
343         {"hsm_archive", lfs_hsm_archive, 0,
344          "Archive file to external storage.\n"
345          "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
346          "<file> ..."},
347         {"hsm_restore", lfs_hsm_restore, 0,
348          "Restore file from external storage.\n"
349          "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
350         {"hsm_release", lfs_hsm_release, 0,
351          "Release files from Lustre.\n"
352          "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
353         {"hsm_remove", lfs_hsm_remove, 0,
354          "Remove file copy from external storage.\n"
355          "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
356          "                  [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
357          "\n"
358          "Note: To remove files from the archive that have been deleted on\n"
359          "Lustre, set mntpath and optionally archive. In that case, all the\n"
360          "positional arguments and entries in the file list must be FIDs."
361         },
362         {"hsm_cancel", lfs_hsm_cancel, 0,
363          "Cancel requests related to specified files.\n"
364          "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
365         {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
366          "usage: swap_layouts <path1> <path2>"},
367         {"migrate", lfs_setstripe, 0,
368          "migrate a directory between MDTs.\n"
369          "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
370          "<directory>\n"
371          "\tmdt_idx:      index of the destination MDT\n"
372          "\n"
373          "migrate file objects from one OST "
374          "layout\nto another (may be not safe with concurent writes).\n"
375          "usage: migrate  "
376          "[--stripe-count|-c] <stripe_count>\n"
377          "              [--stripe-index|-i] <start_ost_index>\n"
378          "              [--stripe-size|-S] <stripe_size>\n"
379          "              [--pool|-p] <pool_name>\n"
380          "              [--ost-list|-o] <ost_indices>\n"
381          "              [--block|-b]\n"
382          "              [--non-block|-n]\n"
383          "              <file|directory>\n"
384          "\tstripe_count:     number of OSTs to stripe a file over\n"
385          "\tstripe_ost_index: index of the first OST to stripe a file over\n"
386          "\tstripe_size:      number of bytes to store before moving to the next OST\n"
387          "\tpool_name:        name of the predefined pool of OSTs\n"
388          "\tost_indices:      OSTs to stripe over, in order\n"
389          "\tblock:            wait for the operation to return before continuing\n"
390          "\tnon-block:        do not wait for the operation to return.\n"},
391         {"mv", lfs_mv, 0,
392          "To move directories between MDTs. This command is deprecated, "
393          "use \"migrate\" instead.\n"
394          "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
395          "[--verbose|-v]\n"},
396         {"ladvise", lfs_ladvise, 0,
397          "Provide servers with advice about access patterns for a file.\n"
398          "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
399          "               [--background|-b] [--unset|-u]\n\n"
400          "               {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
401          "               {[--mode|-m [READ,WRITE]}\n"
402          "               <file> ...\n"},
403         {"help", Parser_help, 0, "help"},
404         {"exit", Parser_quit, 0, "quit"},
405         {"quit", Parser_quit, 0, "quit"},
406         {"--version", Parser_version, 0,
407          "output build version of the utility and exit"},
408         {"--list-commands", lfs_list_commands, 0,
409          "list commands supported by the utility and exit"},
410         { 0, 0, 0, NULL }
411 };
412
413
414 #define MIGRATION_NONBLOCK      1
415
416 static int check_hashtype(const char *hashtype)
417 {
418         int i;
419
420         for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
421                 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
422                         return i;
423
424         return 0;
425 }
426
427 /**
428  * Internal helper for migrate_copy_data(). Check lease and report error if
429  * need be.
430  *
431  * \param[in]  fd           File descriptor on which to check the lease.
432  * \param[out] lease_broken Set to true if the lease was broken.
433  * \param[in]  group_locked Whether a group lock was taken or not.
434  * \param[in]  path         Name of the file being processed, for error
435  *                          reporting
436  *
437  * \retval 0       Migration can keep on going.
438  * \retval -errno  Error occurred, abort migration.
439  */
440 static int check_lease(int fd, bool *lease_broken, bool group_locked,
441                        const char *path)
442 {
443         int rc;
444
445         if (!file_lease_supported)
446                 return 0;
447
448         rc = llapi_lease_check(fd);
449         if (rc > 0)
450                 return 0; /* llapi_check_lease returns > 0 on success. */
451
452         if (!group_locked) {
453                 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
454                         progname, path);
455                 rc = rc ? rc : -EAGAIN;
456         } else {
457                 fprintf(stderr, "%s: external attempt to access file '%s' "
458                         "blocked until migration ends.\n", progname, path);
459                 rc = 0;
460         }
461         *lease_broken = true;
462         return rc;
463 }
464
465 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
466                              bool group_locked, const char *fname)
467 {
468         void    *buf = NULL;
469         ssize_t  rsize = -1;
470         ssize_t  wsize = 0;
471         size_t   rpos = 0;
472         size_t   wpos = 0;
473         off_t    bufoff = 0;
474         int      rc;
475         bool     lease_broken = false;
476
477         /* Use a page-aligned buffer for direct I/O */
478         rc = posix_memalign(&buf, getpagesize(), buf_size);
479         if (rc != 0)
480                 return -rc;
481
482         while (1) {
483                 /* read new data only if we have written all
484                  * previously read data */
485                 if (wpos == rpos) {
486                         if (!lease_broken) {
487                                 rc = check_lease(fd_src, &lease_broken,
488                                                  group_locked, fname);
489                                 if (rc < 0)
490                                         goto out;
491                         }
492                         rsize = read(fd_src, buf, buf_size);
493                         if (rsize < 0) {
494                                 rc = -errno;
495                                 fprintf(stderr, "%s: %s: read failed: %s\n",
496                                         progname, fname, strerror(-rc));
497                                 goto out;
498                         }
499                         rpos += rsize;
500                         bufoff = 0;
501                 }
502                 /* eof ? */
503                 if (rsize == 0)
504                         break;
505
506                 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
507                 if (wsize < 0) {
508                         rc = -errno;
509                         fprintf(stderr,
510                                 "%s: %s: write failed on volatile: %s\n",
511                                 progname, fname, strerror(-rc));
512                         goto out;
513                 }
514                 wpos += wsize;
515                 bufoff += wsize;
516         }
517
518         rc = fsync(fd_dst);
519         if (rc < 0) {
520                 rc = -errno;
521                 fprintf(stderr, "%s: %s: fsync failed: %s\n",
522                         progname, fname, strerror(-rc));
523         }
524
525 out:
526         free(buf);
527         return rc;
528 }
529
530 static int migrate_copy_timestamps(int fdv, const struct stat *st)
531 {
532         struct timeval  tv[2] = {
533                 {.tv_sec = st->st_atime},
534                 {.tv_sec = st->st_mtime}
535         };
536
537         return futimes(fdv, tv);
538 }
539
540 static int migrate_block(int fd, int fdv, const struct stat *st,
541                          size_t buf_size, const char *name)
542 {
543         __u64   dv1;
544         int     gid;
545         int     rc;
546         int     rc2;
547
548         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
549         if (rc < 0) {
550                 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
551                         progname, name, strerror(-rc));
552                 return rc;
553         }
554
555         do
556                 gid = random();
557         while (gid == 0);
558
559         /* The grouplock blocks all concurrent accesses to the file.
560          * It has to be taken after llapi_get_data_version as it would
561          * block it too. */
562         rc = llapi_group_lock(fd, gid);
563         if (rc < 0) {
564                 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
565                         progname, name, strerror(-rc));
566                 return rc;
567         }
568
569         rc = migrate_copy_data(fd, fdv, buf_size, true, name);
570         if (rc < 0) {
571                 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
572                 goto out_unlock;
573         }
574
575         /* Make sure we keep original atime/mtime values */
576         rc = migrate_copy_timestamps(fdv, st);
577         if (rc < 0) {
578                 fprintf(stderr, "%s: %s: timestamp copy failed\n",
579                         progname, name);
580                 goto out_unlock;
581         }
582
583         /* swap layouts
584          * for a migration we need to check data version on file did
585          * not change.
586          *
587          * Pass in gid=0 since we already own grouplock. */
588         rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
589                                            SWAP_LAYOUTS_CHECK_DV1);
590         if (rc == -EAGAIN) {
591                 fprintf(stderr, "%s: %s: dataversion changed during copy, "
592                         "migration aborted\n", progname, name);
593                 goto out_unlock;
594         } else if (rc < 0) {
595                 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
596                         name, strerror(-rc));
597                 goto out_unlock;
598         }
599
600 out_unlock:
601         rc2 = llapi_group_unlock(fd, gid);
602         if (rc2 < 0 && rc == 0) {
603                 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
604                         progname, name, strerror(-rc2));
605                 rc = rc2;
606         }
607
608         return rc;
609 }
610
611 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
612                             size_t buf_size, const char *name)
613 {
614         __u64   dv1;
615         __u64   dv2;
616         int     rc;
617
618         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
619         if (rc < 0) {
620                 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
621                         progname, name, strerror(-rc));
622                 return rc;
623         }
624
625         rc = migrate_copy_data(fd, fdv, buf_size, false, name);
626         if (rc < 0) {
627                 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
628                 return rc;
629         }
630
631         rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
632         if (rc != 0) {
633                 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
634                         progname, name, strerror(-rc));
635                 return rc;
636         }
637
638         if (dv1 != dv2) {
639                 rc = -EAGAIN;
640                 fprintf(stderr, "%s: %s: data version changed during "
641                                 "migration\n",
642                         progname, name);
643                 return rc;
644         }
645
646         /* Make sure we keep original atime/mtime values */
647         rc = migrate_copy_timestamps(fdv, st);
648         if (rc < 0) {
649                 fprintf(stderr, "%s: %s: timestamp copy failed\n",
650                         progname, name);
651                 return rc;
652         }
653
654         /* Atomically put lease, swap layouts and close.
655          * for a migration we need to check data version on file did
656          * not change. */
657         rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
658         if (rc < 0) {
659                 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
660                         progname, name, strerror(-rc));
661                 return rc;
662         }
663
664         return 0;
665 }
666
667 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
668 {
669         return -ENOTSUP;
670 }
671
672 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
673 {
674         int     rc = 0;
675
676         if (flags != 0 && comp_id != 0)
677                 return -EINVAL;
678
679         /* LCME_FL_INIT is the only supported flag in PFL */
680         if (flags != 0) {
681                 if (flags & ~LCME_KNOWN_FLAGS) {
682                         fprintf(stderr, "Invalid component flags %#x\n", flags);
683                         return -EINVAL;
684                 }
685         } else if (comp_id > LCME_ID_MAX) {
686                 fprintf(stderr, "Invalid component id %u\n", comp_id);
687                 return -EINVAL;
688         }
689
690         rc = llapi_layout_file_comp_del(fname, comp_id, flags);
691         if (rc)
692                 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
693                         comp_id, fname, strerror(errno));
694         return rc;
695 }
696
697 static int lfs_component_add(char *fname, struct llapi_layout *layout)
698 {
699         int     rc;
700
701         if (layout == NULL)
702                 return -EINVAL;
703
704         rc = llapi_layout_file_comp_add(fname, layout);
705         if (rc)
706                 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
707                         fname, strerror(errno));
708         return rc;
709 }
710
711 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
712                                 struct llapi_layout *layout)
713 {
714         struct stat     st;
715         int     fd;
716
717         if (layout == NULL)
718                 return -EINVAL;
719
720         fd = lstat(fname, &st);
721         if (fd == 0 && S_ISDIR(st.st_mode))
722                 open_flags = O_DIRECTORY | O_RDONLY;
723
724         fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
725         if (fd < 0)
726                 fprintf(stderr, "%s: cannot %s '%s': %s\n", progname,
727                         S_ISDIR(st.st_mode) ?
728                                 "set default composite layout for" :
729                                 "create composite file",
730                         fname, strerror(errno));
731         return fd;
732 }
733
734 static int lfs_migrate(char *name, __u64 migration_flags,
735                        struct llapi_stripe_param *param,
736                        struct llapi_layout *layout)
737 {
738         int                      fd = -1;
739         int                      fdv = -1;
740         char                     parent[PATH_MAX];
741         int                      mdt_index;
742         int                      random_value;
743         char                     volatile_file[sizeof(parent) +
744                                                LUSTRE_VOLATILE_HDR_LEN +
745                                                2 * sizeof(mdt_index) +
746                                                2 * sizeof(random_value) + 4];
747         char                    *ptr;
748         int                      rc;
749         struct lov_user_md      *lum = NULL;
750         int                      lum_size;
751         int                      buf_size = 1024 * 1024 * 4;
752         bool                     have_lease_rdlck = false;
753         struct stat              st;
754         struct stat              stv;
755
756         /* find the right size for the IO and allocate the buffer */
757         lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
758         lum = malloc(lum_size);
759         if (lum == NULL) {
760                 rc = -ENOMEM;
761                 goto free;
762         }
763
764         rc = llapi_file_get_stripe(name, lum);
765         /* failure can happen for many reasons and some may be not real errors
766          * (eg: no stripe)
767          * in case of a real error, a later call will fail with better
768          * error management */
769         if (rc == 0) {
770                 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
771                      lum->lmm_magic == LOV_USER_MAGIC_V3) &&
772                     lum->lmm_stripe_size != 0)
773                         buf_size = lum->lmm_stripe_size;
774         }
775
776         /* open file, direct io */
777         /* even if the file is only read, WR mode is nedeed to allow
778          * layout swap on fd */
779         fd = open(name, O_RDWR | O_DIRECT);
780         if (fd == -1) {
781                 rc = -errno;
782                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, name,
783                         strerror(-rc));
784                 goto free;
785         }
786
787         if (file_lease_supported) {
788                 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
789                 if (rc == -EOPNOTSUPP) {
790                         /* Older servers do not support file lease.
791                          * Disable related checks. This opens race conditions
792                          * as explained in LU-4840 */
793                         file_lease_supported = false;
794                 } else if (rc < 0) {
795                         fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
796                                 progname, name, strerror(-rc));
797                         goto error;
798                 } else {
799                         have_lease_rdlck = true;
800                 }
801         }
802
803         /* search for file directory pathname */
804         if (strlen(name) > sizeof(parent)-1) {
805                 rc = -E2BIG;
806                 goto error;
807         }
808         strncpy(parent, name, sizeof(parent));
809         ptr = strrchr(parent, '/');
810         if (ptr == NULL) {
811                 if (getcwd(parent, sizeof(parent)) == NULL) {
812                         rc = -errno;
813                         goto error;
814                 }
815         } else {
816                 if (ptr == parent)
817                         strcpy(parent, "/");
818                 else
819                         *ptr = '\0';
820         }
821
822         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
823         if (rc < 0) {
824                 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
825                         progname, name, strerror(-rc));
826                 goto error;
827         }
828
829         do {
830                 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
831                 mode_t open_mode = S_IRUSR | S_IWUSR;
832
833                 random_value = random();
834                 rc = snprintf(volatile_file, sizeof(volatile_file),
835                               "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
836                               mdt_index, random_value);
837                 if (rc >= sizeof(volatile_file)) {
838                         rc = -E2BIG;
839                         goto error;
840                 }
841
842                 /* create, open a volatile file, use caching (ie no directio) */
843                 if (param != NULL)
844                         fdv = llapi_file_open_param(volatile_file, open_flags,
845                                                     open_mode, param);
846                 else if (layout != NULL)
847                         fdv = lfs_component_create(volatile_file, open_flags,
848                                                    open_mode, layout);
849                 else
850                         fdv = -EINVAL;
851         } while (fdv == -EEXIST);
852
853         if (fdv < 0) {
854                 rc = fdv;
855                 fprintf(stderr, "%s: %s: cannot create volatile file in"
856                                 " directory: %s\n",
857                         progname, parent, strerror(-rc));
858                 goto error;
859         }
860
861         /* In case the MDT does not support creation of volatile files
862          * we should try to unlink it. */
863         (void)unlink(volatile_file);
864
865         /* Not-owner (root?) special case.
866          * Need to set owner/group of volatile file like original.
867          * This will allow to pass related check during layout_swap.
868          */
869         rc = fstat(fd, &st);
870         if (rc != 0) {
871                 rc = -errno;
872                 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
873                         strerror(errno));
874                 goto error;
875         }
876         rc = fstat(fdv, &stv);
877         if (rc != 0) {
878                 rc = -errno;
879                 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
880                         volatile_file, strerror(errno));
881                 goto error;
882         }
883         if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
884                 rc = fchown(fdv, st.st_uid, st.st_gid);
885                 if (rc != 0) {
886                         rc = -errno;
887                         fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
888                                 name, strerror(errno));
889                         goto error;
890                 }
891         }
892
893         if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
894                 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
895                 if (rc == 0) {
896                         have_lease_rdlck = false;
897                         fdv = -1; /* The volatile file is closed as we put the
898                                    * lease in non-blocking mode. */
899                 }
900         } else {
901                 /* Blocking mode (forced if servers do not support file lease).
902                  * It is also the default mode, since we cannot distinguish
903                  * between a broken lease and a server that does not support
904                  * atomic swap/close (LU-6785) */
905                 rc = migrate_block(fd, fdv, &st, buf_size, name);
906         }
907
908 error:
909         if (have_lease_rdlck)
910                 llapi_lease_put(fd);
911
912         if (fd >= 0)
913                 close(fd);
914
915         if (fdv >= 0)
916                 close(fdv);
917
918 free:
919         if (lum)
920                 free(lum);
921
922         return rc;
923 }
924
925 /**
926  * Parse a string containing an OST index list into an array of integers.
927  *
928  * The input string contains a comma delimited list of individual
929  * indices and ranges, for example "1,2-4,7". Add the indices into the
930  * \a osts array and remove duplicates.
931  *
932  * \param[out] osts    array to store indices in
933  * \param[in] size     size of \a osts array
934  * \param[in] offset   starting index in \a osts
935  * \param[in] arg      string containing OST index list
936  *
937  * \retval positive    number of indices in \a osts
938  * \retval -EINVAL     unable to parse \a arg
939  */
940 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
941 {
942         int rc;
943         int nr = offset;
944         int slots = size - offset;
945         char *ptr = NULL;
946         bool end_of_loop;
947
948         if (arg == NULL)
949                 return -EINVAL;
950
951         end_of_loop = false;
952         while (!end_of_loop) {
953                 int start_index;
954                 int end_index;
955                 int i;
956                 char *endptr = NULL;
957
958                 rc = -EINVAL;
959
960                 ptr = strchrnul(arg, ',');
961
962                 end_of_loop = *ptr == '\0';
963                 *ptr = '\0';
964
965                 start_index = strtol(arg, &endptr, 0);
966                 if (endptr == arg) /* no data at all */
967                         break;
968                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
969                         break;
970                 if (start_index < 0)
971                         break;
972
973                 end_index = start_index;
974                 if (*endptr == '-') {
975                         end_index = strtol(endptr + 1, &endptr, 0);
976                         if (*endptr != '\0')
977                                 break;
978                         if (end_index < start_index)
979                                 break;
980                 }
981
982                 for (i = start_index; i <= end_index && slots > 0; i++) {
983                         int j;
984
985                         /* remove duplicate */
986                         for (j = 0; j < offset; j++) {
987                                 if (osts[j] == i)
988                                         break;
989                         }
990                         if (j == offset) { /* no duplicate */
991                                 osts[nr++] = i;
992                                 --slots;
993                         }
994                 }
995                 if (slots == 0 && i < end_index)
996                         break;
997
998                 *ptr = ',';
999                 arg = ++ptr;
1000                 offset = nr;
1001                 rc = 0;
1002         }
1003         if (!end_of_loop && ptr != NULL)
1004                 *ptr = ',';
1005
1006         return rc < 0 ? rc : nr;
1007 }
1008
1009 struct lfs_setstripe_args {
1010         unsigned long long       lsa_comp_end;
1011         unsigned long long       lsa_stripe_size;
1012         int                      lsa_stripe_count;
1013         int                      lsa_stripe_off;
1014         __u32                    lsa_comp_flags;
1015         int                      lsa_nr_osts;
1016         int                      lsa_pattern;
1017         __u32                   *lsa_osts;
1018         char                    *lsa_pool_name;
1019 };
1020
1021 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1022 {
1023         memset(lsa, 0, sizeof(*lsa));
1024         lsa->lsa_stripe_off = -1;
1025 }
1026
1027 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1028 {
1029         return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1030                 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1031                 lsa->lsa_comp_end != 0 || lsa->lsa_pattern != 0);
1032 }
1033
1034 static int comp_args_to_layout(struct llapi_layout **composite,
1035                                struct lfs_setstripe_args *lsa)
1036 {
1037         struct llapi_layout *layout = *composite;
1038         uint64_t prev_end = 0;
1039         int i = 0, rc;
1040
1041         if (layout == NULL) {
1042                 layout = llapi_layout_alloc();
1043                 if (layout == NULL) {
1044                         fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1045                                 strerror(errno));
1046                         return -ENOMEM;
1047                 }
1048                 *composite = layout;
1049         } else {
1050                 uint64_t start;
1051
1052                 /* Get current component extent, current component
1053                  * must be the tail component. */
1054                 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1055                 if (rc) {
1056                         fprintf(stderr, "Get comp extent failed. %s\n",
1057                                 strerror(errno));
1058                         return rc;
1059                 }
1060
1061                 rc = llapi_layout_comp_add(layout);
1062                 if (rc) {
1063                         fprintf(stderr, "Add component failed. %s\n",
1064                                 strerror(errno));
1065                         return rc;
1066                 }
1067         }
1068
1069         rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1070         if (rc) {
1071                 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1072                         prev_end, lsa->lsa_comp_end, strerror(errno));
1073                 return rc;
1074         }
1075
1076         /* Data-on-MDT component setting */
1077         if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
1078                 /* In case of Data-on-MDT patterns the only extra option
1079                  * applicable is stripe size option. */
1080                 if (lsa->lsa_stripe_count) {
1081                         fprintf(stderr, "Option 'stripe-count' can't be "
1082                                 "specified with Data-on-MDT component: %i\n",
1083                                 lsa->lsa_stripe_count);
1084                         return -EINVAL;
1085                 }
1086                 if (lsa->lsa_stripe_size) {
1087                         fprintf(stderr, "Option 'stripe-size' can't be "
1088                                 "specified with Data-on-MDT component: %llu\n",
1089                                 lsa->lsa_stripe_size);
1090                         return -EINVAL;
1091                 }
1092                 if (lsa->lsa_nr_osts != 0) {
1093                         fprintf(stderr, "Option 'ost-list' can't be specified "
1094                                 "with Data-on-MDT component: '%i'\n",
1095                                 lsa->lsa_nr_osts);
1096                         return -EINVAL;
1097                 }
1098                 if (lsa->lsa_stripe_off != -1) {
1099                         fprintf(stderr, "Option 'stripe-offset' can't be "
1100                                 "specified with Data-on-MDT component: %i\n",
1101                                 lsa->lsa_stripe_off);
1102                         return -EINVAL;
1103                 }
1104                 if (lsa->lsa_pool_name != 0) {
1105                         fprintf(stderr, "Option 'pool' can't be specified "
1106                                 "with Data-on-MDT component: '%s'\n",
1107                                 lsa->lsa_pool_name);
1108                         return -EINVAL;
1109                 }
1110
1111                 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
1112                 if (rc) {
1113                         fprintf(stderr, "Set stripe pattern %#x failed. %s\n",
1114                                 lsa->lsa_pattern, strerror(errno));
1115                         return rc;
1116                 }
1117                 /* Data-on-MDT component has always single stripe up to end */
1118                 lsa->lsa_stripe_size = lsa->lsa_comp_end;
1119         }
1120
1121         if (lsa->lsa_stripe_size != 0) {
1122                 rc = llapi_layout_stripe_size_set(layout,
1123                                                   lsa->lsa_stripe_size);
1124                 if (rc) {
1125                         fprintf(stderr, "Set stripe size %llu failed. %s\n",
1126                                 lsa->lsa_stripe_size, strerror(errno));
1127                         return rc;
1128                 }
1129         }
1130
1131         if (lsa->lsa_stripe_count != 0) {
1132                 rc = llapi_layout_stripe_count_set(layout,
1133                                                    lsa->lsa_stripe_count == -1 ?
1134                                                    LLAPI_LAYOUT_WIDE :
1135                                                    lsa->lsa_stripe_count);
1136                 if (rc) {
1137                         fprintf(stderr, "Set stripe count %d failed. %s\n",
1138                                 lsa->lsa_stripe_count, strerror(errno));
1139                         return rc;
1140                 }
1141         }
1142
1143         if (lsa->lsa_pool_name != NULL) {
1144                 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1145                 if (rc) {
1146                         fprintf(stderr, "Set pool name: %s failed. %s\n",
1147                                 lsa->lsa_pool_name, strerror(errno));
1148                         return rc;
1149                 }
1150         }
1151
1152         if (lsa->lsa_nr_osts > 0) {
1153                 if (lsa->lsa_stripe_count > 0 &&
1154                     lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1155                         fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1156                                 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1157                         return -EINVAL;
1158                 }
1159                 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1160                         rc = llapi_layout_ost_index_set(layout, i,
1161                                                         lsa->lsa_osts[i]);
1162                         if (rc)
1163                                 break;
1164                 }
1165         } else if (lsa->lsa_stripe_off != -1) {
1166                 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1167         }
1168         if (rc) {
1169                 fprintf(stderr, "Set ost index %d failed. %s\n",
1170                         i, strerror(errno));
1171                 return rc;
1172         }
1173
1174         return 0;
1175 }
1176
1177 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1178  * end of the last component in the existing file, and adjust the
1179  * first extent start of the components to be added accordingly. */
1180 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1181 {
1182         struct llapi_layout *head;
1183         uint64_t start, end, stripe_size, prev_end = 0;
1184         int rc;
1185
1186         if (layout == NULL)
1187                 return -EINVAL;
1188
1189         errno = 0;
1190         head = llapi_layout_get_by_path(fname, 0);
1191         if (head == NULL) {
1192                 fprintf(stderr, "Read layout from %s failed. %s\n",
1193                         fname, strerror(errno));
1194                 return -EINVAL;
1195         } else if (errno == ENODATA) {
1196                 /* file without LOVEA, this component-add will be turned
1197                  * into a component-create. */
1198                 llapi_layout_free(head);
1199                 return -ENODATA;
1200         } else if (!llapi_layout_is_composite(head)) {
1201                 fprintf(stderr, "'%s' isn't a composite file.\n",
1202                         fname);
1203                 llapi_layout_free(head);
1204                 return -EINVAL;
1205         }
1206
1207         rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1208         if (rc) {
1209                 fprintf(stderr, "Get prev extent failed. %s\n",
1210                         strerror(errno));
1211                 llapi_layout_free(head);
1212                 return rc;
1213         }
1214
1215         llapi_layout_free(head);
1216
1217         /* Make sure we use the first component of the layout to be added. */
1218         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1219         if (rc < 0) {
1220                 fprintf(stderr, "Move component cursor failed. %s\n",
1221                         strerror(errno));
1222                 return rc;
1223         }
1224
1225         rc = llapi_layout_comp_extent_get(layout, &start, &end);
1226         if (rc) {
1227                 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1228                 return rc;
1229         }
1230
1231         if (start > prev_end || end <= prev_end) {
1232                 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1233                         "adjacent with the existing file extent end: %lu\n",
1234                         start, end, prev_end);
1235                 return -EINVAL;
1236         }
1237
1238         rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1239         if (rc) {
1240                 fprintf(stderr, "Get stripe size failed. %s\n",
1241                         strerror(errno));
1242                 return rc;
1243         }
1244
1245         if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1246             (prev_end & (stripe_size - 1))) {
1247                 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1248                         stripe_size, prev_end);
1249                 return -EINVAL;
1250         }
1251
1252         rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1253         if (rc) {
1254                 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1255                         prev_end, end, strerror(errno));
1256                 return rc;
1257         }
1258
1259         return 0;
1260 }
1261
1262 static inline bool comp_flags_is_neg(__u32 flags)
1263 {
1264         return flags & LCME_FL_NEG;
1265 }
1266
1267 static inline void comp_flags_set_neg(__u32 *flags)
1268 {
1269         *flags |= LCME_FL_NEG;
1270 }
1271
1272 static inline void comp_flags_clear_neg(__u32 *flags)
1273 {
1274         *flags &= ~LCME_FL_NEG;
1275 }
1276
1277 static int comp_str2flags(__u32 *flags, char *string)
1278 {
1279         char *name;
1280         __u32 neg_flags = 0;
1281
1282         if (string == NULL)
1283                 return -EINVAL;
1284
1285         *flags = 0;
1286         for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1287                 bool found = false;
1288                 int i;
1289
1290                 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1291                         __u32 comp_flag = comp_flags_table[i].cfn_flag;
1292                         const char *comp_name = comp_flags_table[i].cfn_name;
1293
1294                         if (strcmp(name, comp_name) == 0) {
1295                                 *flags |= comp_flag;
1296                                 found = true;
1297                         } else if (strncmp(name, "^", 1) == 0 &&
1298                                    strcmp(name + 1, comp_name) == 0) {
1299                                 neg_flags |= comp_flag;
1300                                 found = true;
1301                         }
1302                 }
1303                 if (!found) {
1304                         llapi_printf(LLAPI_MSG_ERROR,
1305                                      "%s: component flag '%s' not supported\n",
1306                                      progname, name);
1307                         return -EINVAL;
1308                 }
1309         }
1310
1311         if (*flags == 0 && neg_flags == 0)
1312                 return -EINVAL;
1313         /* don't support mixed flags for now */
1314         if (*flags && neg_flags)
1315                 return -EINVAL;
1316
1317         if (neg_flags) {
1318                 *flags = neg_flags;
1319                 comp_flags_set_neg(flags);
1320         }
1321
1322         return 0;
1323 }
1324
1325 static inline bool arg_is_eof(char *arg)
1326 {
1327         return !strncmp(arg, "-1", strlen("-1")) ||
1328                !strncmp(arg, "EOF", strlen("EOF")) ||
1329                !strncmp(arg, "eof", strlen("eof"));
1330 }
1331
1332 enum {
1333         LFS_POOL_OPT = 3,
1334         LFS_COMP_COUNT_OPT,
1335         LFS_COMP_START_OPT,
1336         LFS_COMP_FLAGS_OPT,
1337         LFS_COMP_DEL_OPT,
1338         LFS_COMP_SET_OPT,
1339         LFS_COMP_ADD_OPT,
1340         LFS_PROJID_OPT,
1341 };
1342
1343 /* functions */
1344 static int lfs_setstripe(int argc, char **argv)
1345 {
1346         struct lfs_setstripe_args        lsa;
1347         struct llapi_stripe_param       *param = NULL;
1348         struct find_param                migrate_mdt_param = {
1349                 .fp_max_depth = -1,
1350                 .fp_mdt_index = -1,
1351         };
1352         char                            *fname;
1353         int                              result;
1354         int                              result2 = 0;
1355         char                            *end;
1356         int                              c;
1357         int                              delete = 0;
1358         char                            *mdt_idx_arg = NULL;
1359         unsigned long long               size_units = 1;
1360         bool                             migrate_mode = false;
1361         bool                             migration_block = false;
1362         __u64                            migration_flags = 0;
1363         __u32                            osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1364         int                              comp_del = 0, comp_set = 0;
1365         int                              comp_add = 0;
1366         __u32                            comp_id = 0;
1367         struct llapi_layout             *layout = NULL;
1368
1369         struct option long_opts[] = {
1370                 /* --block is only valid in migrate mode */
1371         { .val = 'b',   .name = "block",        .has_arg = no_argument},
1372         { .val = LFS_COMP_ADD_OPT,
1373                         .name = "comp-add",     .has_arg = no_argument},
1374         { .val = LFS_COMP_ADD_OPT,
1375                         .name = "component-add",
1376                                                 .has_arg = no_argument},
1377         { .val = LFS_COMP_DEL_OPT,
1378                         .name = "comp-del",     .has_arg = no_argument},
1379         { .val = LFS_COMP_DEL_OPT,
1380                         .name = "component-del",
1381                                                 .has_arg = no_argument},
1382         { .val = LFS_COMP_FLAGS_OPT,
1383                         .name = "comp-flags",   .has_arg = required_argument},
1384         { .val = LFS_COMP_FLAGS_OPT,
1385                         .name = "component-flags",
1386                                                 .has_arg = required_argument},
1387         { .val = LFS_COMP_SET_OPT,
1388                         .name = "comp-set",     .has_arg = no_argument},
1389         { .val = LFS_COMP_SET_OPT,
1390                         .name = "component-set",
1391                                                 .has_arg = no_argument},
1392         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument},
1393         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument},
1394         { .val = 'd',   .name = "delete",       .has_arg = no_argument},
1395         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument},
1396         { .val = 'E',   .name = "component-end",
1397                                                 .has_arg = required_argument},
1398         /* dirstripe {"mdt-hash",     required_argument, 0, 'H'}, */
1399         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument},
1400         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument},
1401         { .val = 'I',   .name = "comp-id",      .has_arg = required_argument},
1402         { .val = 'I',   .name = "component-id", .has_arg = required_argument},
1403         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
1404         { .val = 'm',   .name = "mdt",          .has_arg = required_argument},
1405         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument},
1406         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument},
1407         /* --non-block is only valid in migrate mode */
1408         { .val = 'n',   .name = "non-block",    .has_arg = no_argument},
1409         { .val = 'o',   .name = "ost",          .has_arg = required_argument},
1410 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1411         { .val = 'o',   .name = "ost-list",     .has_arg = required_argument },
1412         { .val = 'o',   .name = "ost_list",     .has_arg = required_argument },
1413 #endif
1414         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
1415         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
1416         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
1417         /* dirstripe {"mdt-count",    required_argument, 0, 'T'}, */
1418         /* --verbose is only valid in migrate mode */
1419         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
1420         { .val = LFS_COMP_ADD_OPT,
1421                         .name = "component-add",
1422                                                 .has_arg = no_argument },
1423         { .val = LFS_COMP_DEL_OPT,
1424                         .name = "component-del",
1425                                                 .has_arg = no_argument },
1426         { .val = LFS_COMP_FLAGS_OPT,
1427                         .name = "component-flags",
1428                                                 .has_arg = required_argument },
1429         { .val = LFS_COMP_SET_OPT,
1430                         .name = "component-set",
1431                                                 .has_arg = no_argument },
1432         { .name = NULL } };
1433
1434         setstripe_args_init(&lsa);
1435
1436         if (strcmp(argv[0], "migrate") == 0)
1437                 migrate_mode = true;
1438
1439         while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:L:s:S:v",
1440                                 long_opts, NULL)) >= 0) {
1441                 switch (c) {
1442                 case 0:
1443                         /* Long options. */
1444                         break;
1445                 case LFS_COMP_ADD_OPT:
1446                         comp_add = 1;
1447                         break;
1448                 case LFS_COMP_DEL_OPT:
1449                         comp_del = 1;
1450                         break;
1451                 case LFS_COMP_FLAGS_OPT:
1452                         result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
1453                         if (result != 0)
1454                                 goto usage_error;
1455                         break;
1456                 case LFS_COMP_SET_OPT:
1457                         comp_set = 1;
1458                         break;
1459                 case 'b':
1460                         if (!migrate_mode) {
1461                                 fprintf(stderr,
1462                                         "%s %s: -b|--block valid only for migrate command\n",
1463                                         progname, argv[0]);
1464                                 goto usage_error;
1465                         }
1466                         migration_block = true;
1467                         break;
1468                 case 'c':
1469                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1470                         if (*end != '\0') {
1471                                 fprintf(stderr,
1472                                         "%s %s: invalid stripe count '%s'\n",
1473                                         progname, argv[0], optarg);
1474                                 goto usage_error;
1475                         }
1476                         break;
1477                 case 'd':
1478                         /* delete the default striping pattern */
1479                         delete = 1;
1480                         break;
1481                 case 'E':
1482                         if (lsa.lsa_comp_end != 0) {
1483                                 result = comp_args_to_layout(&layout, &lsa);
1484                                 if (result) {
1485                                         fprintf(stderr,
1486                                                 "%s %s: invalid layout\n",
1487                                                 progname, argv[0]);
1488                                         goto usage_error;
1489                                 }
1490
1491                                 setstripe_args_init(&lsa);
1492                         }
1493
1494                         if (arg_is_eof(optarg)) {
1495                                 lsa.lsa_comp_end = LUSTRE_EOF;
1496                         } else {
1497                                 result = llapi_parse_size(optarg,
1498                                                         &lsa.lsa_comp_end,
1499                                                         &size_units, 0);
1500                                 if (result) {
1501                                         fprintf(stderr,
1502                                                 "%s %s: invalid component end '%s'\n",
1503                                                 progname, argv[0], optarg);
1504                                         goto usage_error;
1505                                 }
1506                         }
1507                         break;
1508                 case 'i':
1509                         lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1510                         if (*end != '\0') {
1511                                 fprintf(stderr,
1512                                         "%s %s: invalid stripe offset '%s'\n",
1513                                         progname, argv[0], optarg);
1514                                 goto usage_error;
1515                         }
1516                         break;
1517                 case 'I':
1518                         comp_id = strtoul(optarg, &end, 0);
1519                         if (*end != '\0' || comp_id == 0 ||
1520                             comp_id > LCME_ID_MAX) {
1521                                 fprintf(stderr,
1522                                         "%s %s: invalid component ID '%s'\n",
1523                                         progname, argv[0], optarg);
1524                                 goto usage_error;
1525                         }
1526                         break;
1527                 case 'L':
1528                         if (strcmp(argv[optind - 1], "mdt") == 0) {
1529                                 /* Can be only the first component */
1530                                 if (layout != NULL) {
1531                                         result = -EINVAL;
1532                                         fprintf(stderr, "error: 'mdt' layout "
1533                                                 "can be only the first one\n");
1534                                         goto error;
1535                                 }
1536                                 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
1537                                         result = -EFBIG;
1538                                         fprintf(stderr, "error: 'mdt' layout "
1539                                                 "size is too big\n");
1540                                         goto error;
1541                                 }
1542                                 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
1543                         } else if (strcmp(argv[optind - 1], "raid0") != 0) {
1544                                 result = -EINVAL;
1545                                 fprintf(stderr, "error: layout '%s' is "
1546                                         "unknown, supported layouts are: "
1547                                         "'mdt', 'raid0'\n", argv[optind]);
1548                                 goto error;
1549                         }
1550                         break;
1551                 case 'm':
1552                         if (!migrate_mode) {
1553                                 fprintf(stderr,
1554                                         "%s %s: -m|--mdt-index valid only for migrate command\n",
1555                                         progname, argv[0]);
1556                                 goto usage_error;
1557                         }
1558                         mdt_idx_arg = optarg;
1559                         break;
1560                 case 'n':
1561                         if (!migrate_mode) {
1562                                 fprintf(stderr,
1563                                         "%s %s: -n|--non-block valid only for migrate command\n",
1564                                         progname, argv[0]);
1565                                 goto usage_error;
1566                         }
1567                         migration_flags |= MIGRATION_NONBLOCK;
1568                         break;
1569                 case 'o':
1570                         lsa.lsa_nr_osts = parse_targets(osts,
1571                                                 sizeof(osts) / sizeof(__u32),
1572                                                 lsa.lsa_nr_osts, optarg);
1573                         if (lsa.lsa_nr_osts < 0) {
1574                                 fprintf(stderr,
1575                                         "%s %s: invalid OST target(s) '%s'\n",
1576                                         progname, argv[0], optarg);
1577                                 goto usage_error;
1578                         }
1579
1580                         lsa.lsa_osts = osts;
1581                         if (lsa.lsa_stripe_off == -1)
1582                                 lsa.lsa_stripe_off = osts[0];
1583                         break;
1584                 case 'p':
1585                         if (optarg == NULL)
1586                                 goto usage_error;
1587                         lsa.lsa_pool_name = optarg;
1588                         break;
1589                 case 'S':
1590                         result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1591                                                   &size_units, 0);
1592                         if (result) {
1593                                 fprintf(stderr,
1594                                         "%s %s: invalid stripe size '%s'\n",
1595                                         progname, argv[0], optarg);
1596                                 goto usage_error;
1597                         }
1598                         break;
1599                 case 'v':
1600                         if (!migrate_mode) {
1601                                 fprintf(stderr,
1602                                         "%s %s: -v|--verbose valid only for migrate command\n",
1603                                         progname, argv[0]);
1604                                 goto usage_error;
1605                         }
1606                         migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1607                         break;
1608                 default:
1609                         fprintf(stderr, "%s %s: unrecognized option '%s'\n",
1610                                 progname, argv[0], argv[optind - 1]);
1611                         goto usage_error;
1612                 }
1613         }
1614
1615         fname = argv[optind];
1616
1617         if (lsa.lsa_comp_end != 0) {
1618                 result = comp_args_to_layout(&layout, &lsa);
1619                 if (result) {
1620                         fprintf(stderr, "%s %s: invalid component layout\n",
1621                                 progname, argv[0]);
1622                         goto usage_error;
1623                 }
1624         }
1625
1626         if (optind == argc) {
1627                 fprintf(stderr, "%s %s: FILE must be specified\n",
1628                         progname, argv[0]);
1629                 goto usage_error;
1630         }
1631
1632         /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1633          * altered by user space tool, so we don't need to support the
1634          * --component-set for this moment. */
1635         if (comp_set != 0) {
1636                 fprintf(stderr, "%s %s: --component-set not supported\n",
1637                         progname, argv[0]);
1638                 goto usage_error;
1639         }
1640
1641         if ((delete + comp_set + comp_del + comp_add) > 1) {
1642                 fprintf(stderr,
1643                         "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
1644                         progname, argv[0]);
1645                 goto usage_error;
1646         }
1647
1648         if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1649                        lsa.lsa_comp_flags != 0 || layout != NULL)) {
1650                 fprintf(stderr,
1651                         "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
1652                         progname, argv[0]);
1653                 goto usage_error;
1654         }
1655
1656         if ((comp_set || comp_del) &&
1657             (setstripe_args_specified(&lsa) || layout != NULL)) {
1658                 fprintf(stderr,
1659                         "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
1660                         progname, argv[0]);
1661                 goto usage_error;
1662         }
1663
1664         if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1665                 fprintf(stderr,
1666                         "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
1667                         progname, argv[0]);
1668                 goto usage_error;
1669         }
1670
1671         if (comp_add || comp_del) {
1672                 struct stat st;
1673
1674                 result = lstat(fname, &st);
1675                 if (result == 0 && S_ISDIR(st.st_mode)) {
1676                         fprintf(stderr,
1677                                 "%s setstripe: cannot use --component-add or --component-del for directory\n",
1678                                 progname);
1679                         goto usage_error;
1680                 }
1681         }
1682
1683         if (comp_add) {
1684                 if (layout == NULL) {
1685                         fprintf(stderr,
1686                                 "%s %s: option -E must be specified with --component-add\n",
1687                                 progname, argv[0]);
1688                         goto usage_error;
1689                 }
1690                 result = adjust_first_extent(fname, layout);
1691                 if (result == -ENODATA)
1692                         comp_add = 0;
1693                 else if (result != 0)
1694                         goto error;
1695         }
1696
1697         if (mdt_idx_arg != NULL && optind > 3) {
1698                 fprintf(stderr,
1699                         "%s %s: option -m cannot be used with other options\n",
1700                         progname, argv[0]);
1701                 goto usage_error;
1702         }
1703
1704         if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1705                 fprintf(stderr,
1706                         "%s %s: options --non-block and --block are mutually exclusive\n",
1707                         progname, argv[0]);
1708                 goto usage_error;
1709         }
1710
1711         if (!comp_del && !comp_set && comp_id != 0) {
1712                 fprintf(stderr,
1713                         "%s %s: option -I can only be used with --component-del\n",
1714                         progname, argv[0]);
1715                 goto usage_error;
1716         }
1717
1718         if (mdt_idx_arg != NULL) {
1719                 /* initialize migrate mdt parameters */
1720                 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1721                 if (*end != '\0') {
1722                         fprintf(stderr, "%s %s: invalid MDT index '%s'\n",
1723                                 progname, argv[0], mdt_idx_arg);
1724                         goto usage_error;
1725                 }
1726                 migrate_mdt_param.fp_migrate = 1;
1727         } else if (layout == NULL) {
1728                 /* initialize stripe parameters */
1729                 param = calloc(1, offsetof(typeof(*param),
1730                                lsp_osts[lsa.lsa_nr_osts]));
1731                 if (param == NULL) {
1732                         fprintf(stderr,
1733                                 "%s %s: cannot allocate memory for parameters: %s\n",
1734                                 progname, argv[0], strerror(ENOMEM));
1735                         result = -ENOMEM;
1736                         goto error;
1737                 }
1738
1739                 param->lsp_stripe_size = lsa.lsa_stripe_size;
1740                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1741                 param->lsp_stripe_count = lsa.lsa_stripe_count;
1742                 param->lsp_pool = lsa.lsa_pool_name;
1743                 param->lsp_is_specific = false;
1744                 if (lsa.lsa_nr_osts > 0) {
1745                         if (lsa.lsa_stripe_count > 0 &&
1746                             lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1747                                 fprintf(stderr,
1748                                         "%s %s: stripe count '%d' does not match number of OSTs: %d\n",
1749                                         progname, argv[0], lsa.lsa_stripe_count,
1750                                         lsa.lsa_nr_osts);
1751                                 free(param);
1752                                 goto usage_error;
1753                         }
1754
1755                         param->lsp_is_specific = true;
1756                         param->lsp_stripe_count = lsa.lsa_nr_osts;
1757                         memcpy(param->lsp_osts, osts,
1758                                sizeof(*osts) * lsa.lsa_nr_osts);
1759                 }
1760         }
1761
1762         for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1763                 if (mdt_idx_arg != NULL) {
1764                         result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1765                 } else if (migrate_mode) {
1766                         result = lfs_migrate(fname, migration_flags, param,
1767                                              layout);
1768                 } else if (comp_set != 0) {
1769                         result = lfs_component_set(fname, comp_id,
1770                                                    lsa.lsa_comp_flags);
1771                 } else if (comp_del != 0) {
1772                         result = lfs_component_del(fname, comp_id,
1773                                                    lsa.lsa_comp_flags);
1774                 } else if (comp_add != 0) {
1775                         result = lfs_component_add(fname, layout);
1776                 } else if (layout != NULL) {
1777                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1778                                                       0644, layout);
1779                         if (result >= 0) {
1780                                 close(result);
1781                                 result = 0;
1782                         }
1783                 } else {
1784                         result = llapi_file_open_param(fname,
1785                                                        O_CREAT | O_WRONLY,
1786                                                        0644, param);
1787                         if (result >= 0) {
1788                                 close(result);
1789                                 result = 0;
1790                         }
1791                 }
1792                 if (result) {
1793                         /* Save the first error encountered. */
1794                         if (result2 == 0)
1795                                 result2 = result;
1796                         continue;
1797                 }
1798         }
1799
1800         free(param);
1801         llapi_layout_free(layout);
1802         return result2;
1803 usage_error:
1804         result = CMD_HELP;
1805 error:
1806         llapi_layout_free(layout);
1807         return result;
1808 }
1809
1810 static int lfs_poollist(int argc, char **argv)
1811 {
1812         if (argc != 2)
1813                 return CMD_HELP;
1814
1815         return llapi_poollist(argv[1]);
1816 }
1817
1818 static int set_time(time_t *time, time_t *set, char *str)
1819 {
1820         time_t t;
1821         int res = 0;
1822
1823         if (str[0] == '+')
1824                 res = 1;
1825         else if (str[0] == '-')
1826                 res = -1;
1827
1828         if (res)
1829                 str++;
1830
1831         t = strtol(str, NULL, 0);
1832         if (*time < t * 24 * 60 * 60) {
1833                 if (res)
1834                         str--;
1835                 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1836                 return INT_MAX;
1837         }
1838
1839         *set = *time - t * 24 * 60 * 60;
1840         return res;
1841 }
1842 static int name2uid(unsigned int *id, const char *name)
1843 {
1844         struct passwd *passwd;
1845
1846         passwd = getpwnam(name);
1847         if (passwd == NULL)
1848                 return -ENOENT;
1849         *id = passwd->pw_uid;
1850
1851         return 0;
1852 }
1853
1854 static int name2gid(unsigned int *id, const char *name)
1855 {
1856         struct group *group;
1857
1858         group = getgrnam(name);
1859         if (group == NULL)
1860                 return -ENOENT;
1861         *id = group->gr_gid;
1862
1863         return 0;
1864 }
1865
1866 static inline int name2projid(unsigned int *id, const char *name)
1867 {
1868         return -ENOTSUP;
1869 }
1870
1871 static int uid2name(char **name, unsigned int id)
1872 {
1873         struct passwd *passwd;
1874
1875         passwd = getpwuid(id);
1876         if (passwd == NULL)
1877                 return -ENOENT;
1878         *name = passwd->pw_name;
1879
1880         return 0;
1881 }
1882
1883 static inline int gid2name(char **name, unsigned int id)
1884 {
1885         struct group *group;
1886
1887         group = getgrgid(id);
1888         if (group == NULL)
1889                 return -ENOENT;
1890         *name = group->gr_name;
1891
1892         return 0;
1893 }
1894
1895 static int name2layout(__u32 *layout, char *name)
1896 {
1897         char *ptr, *layout_name;
1898
1899         *layout = 0;
1900         for (ptr = name; ; ptr = NULL) {
1901                 layout_name = strtok(ptr, ",");
1902                 if (layout_name == NULL)
1903                         break;
1904                 if (strcmp(layout_name, "released") == 0)
1905                         *layout |= LOV_PATTERN_F_RELEASED;
1906                 else if (strcmp(layout_name, "raid0") == 0)
1907                         *layout |= LOV_PATTERN_RAID0;
1908                 else if (strcmp(layout_name, "mdt") == 0)
1909                         *layout |= LOV_PATTERN_MDT;
1910                 else
1911                         return -1;
1912         }
1913         return 0;
1914 }
1915
1916 static int lfs_find(int argc, char **argv)
1917 {
1918         int c, rc;
1919         int ret = 0;
1920         time_t t;
1921         struct find_param param = {
1922                 .fp_max_depth = -1,
1923                 .fp_quiet = 1,
1924         };
1925         struct option long_opts[] = {
1926         { .val = 'A',   .name = "atime",        .has_arg = required_argument },
1927         { .val = LFS_COMP_COUNT_OPT,
1928                         .name = "comp-count",   .has_arg = required_argument },
1929         { .val = LFS_COMP_COUNT_OPT,
1930                         .name = "component-count",
1931                                                 .has_arg = required_argument },
1932         { .val = LFS_COMP_FLAGS_OPT,
1933                         .name = "comp-flags",   .has_arg = required_argument },
1934         { .val = LFS_COMP_FLAGS_OPT,
1935                         .name = "component-flags",
1936                                                 .has_arg = required_argument },
1937         { .val = LFS_COMP_START_OPT,
1938                         .name = "comp-start",   .has_arg = required_argument },
1939         { .val = LFS_COMP_START_OPT,
1940                         .name = "component-start",
1941                                                 .has_arg = required_argument },
1942         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument },
1943         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument },
1944         { .val = 'C',   .name = "ctime",        .has_arg = required_argument },
1945         { .val = 'D',   .name = "maxdepth",     .has_arg = required_argument },
1946         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument },
1947         { .val = 'E',   .name = "component-end",
1948                                                 .has_arg = required_argument },
1949         { .val = 'g',   .name = "gid",          .has_arg = required_argument },
1950         { .val = 'G',   .name = "group",        .has_arg = required_argument },
1951         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
1952         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument },
1953         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument },
1954         /*{"component-id", required_argument, 0, 'I'},*/
1955         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
1956         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
1957         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
1958         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument },
1959         { .val = 'M',   .name = "mtime",        .has_arg = required_argument },
1960         { .val = 'n',   .name = "name",         .has_arg = required_argument },
1961      /* reserve {"or",           no_argument,     , 0, 'o'}, to match find(1) */
1962         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
1963         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
1964         /* no short option for pool, p/P already used */
1965         { .val = LFS_POOL_OPT,
1966                         .name = "pool",         .has_arg = required_argument },
1967         { .val = 'p',   .name = "print0",       .has_arg = no_argument },
1968         { .val = 'P',   .name = "print",        .has_arg = no_argument },
1969         { .val = LFS_PROJID_OPT,
1970                         .name = "projid",       .has_arg = required_argument },
1971         { .val = 's',   .name = "size",         .has_arg = required_argument },
1972         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
1973         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
1974         { .val = 't',   .name = "type",         .has_arg = required_argument },
1975         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
1976         { .val = 'u',   .name = "uid",          .has_arg = required_argument },
1977         { .val = 'U',   .name = "user",         .has_arg = required_argument },
1978         { .name = NULL } };
1979         int pathstart = -1;
1980         int pathend = -1;
1981         int neg_opt = 0;
1982         time_t *xtime;
1983         int *xsign;
1984         int isoption;
1985         char *endptr;
1986
1987         time(&t);
1988
1989         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1990         while ((c = getopt_long_only(argc, argv,
1991                         "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1992                         long_opts, NULL)) >= 0) {
1993                 xtime = NULL;
1994                 xsign = NULL;
1995                 if (neg_opt)
1996                         --neg_opt;
1997                 /* '!' is part of option */
1998                 /* when getopt_long_only() finds a string which is not
1999                  * an option nor a known option argument it returns 1
2000                  * in that case if we already have found pathstart and pathend
2001                  * (i.e. we have the list of pathnames),
2002                  * the only supported value is "!"
2003                  */
2004                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
2005                 if (!isoption && pathend != -1) {
2006                         fprintf(stderr, "err: %s: filename|dirname must either "
2007                                         "precede options or follow options\n",
2008                                         argv[0]);
2009                         ret = CMD_HELP;
2010                         goto err;
2011                 }
2012                 if (!isoption && pathstart == -1)
2013                         pathstart = optind - 1;
2014                 if (isoption && pathstart != -1 && pathend == -1)
2015                         pathend = optind - 2;
2016                 switch (c) {
2017                 case 0:
2018                         /* Long options. */
2019                         break;
2020                 case 1:
2021                         /* unknown; opt is "!" or path component,
2022                          * checking done above.
2023                          */
2024                         if (strcmp(optarg, "!") == 0)
2025                                 neg_opt = 2;
2026                         break;
2027                 case 'A':
2028                         xtime = &param.fp_atime;
2029                         xsign = &param.fp_asign;
2030                         param.fp_exclude_atime = !!neg_opt;
2031                         /* no break, this falls through to 'C' for ctime */
2032                 case 'C':
2033                         if (c == 'C') {
2034                                 xtime = &param.fp_ctime;
2035                                 xsign = &param.fp_csign;
2036                                 param.fp_exclude_ctime = !!neg_opt;
2037                         }
2038                         /* no break, this falls through to 'M' for mtime */
2039                 case 'M':
2040                         if (c == 'M') {
2041                                 xtime = &param.fp_mtime;
2042                                 xsign = &param.fp_msign;
2043                                 param.fp_exclude_mtime = !!neg_opt;
2044                         }
2045                         rc = set_time(&t, xtime, optarg);
2046                         if (rc == INT_MAX) {
2047                                 ret = -1;
2048                                 goto err;
2049                         }
2050                         if (rc)
2051                                 *xsign = rc;
2052                         break;
2053                 case LFS_COMP_COUNT_OPT:
2054                         if (optarg[0] == '+') {
2055                                 param.fp_comp_count_sign = -1;
2056                                 optarg++;
2057                         } else if (optarg[0] == '-') {
2058                                 param.fp_comp_count_sign =  1;
2059                                 optarg++;
2060                         }
2061
2062                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
2063                         if (*endptr != '\0') {
2064                                 fprintf(stderr, "error: bad component count "
2065                                         "'%s'\n", optarg);
2066                                 goto err;
2067                         }
2068                         param.fp_check_comp_count = 1;
2069                         param.fp_exclude_comp_count = !!neg_opt;
2070                         break;
2071                 case LFS_COMP_FLAGS_OPT:
2072                         rc = comp_str2flags(&param.fp_comp_flags, optarg);
2073                         if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2074                                 fprintf(stderr, "error: bad component flags "
2075                                         "'%s'\n", optarg);
2076                                 goto err;
2077                         }
2078                         param.fp_check_comp_flags = 1;
2079                         param.fp_exclude_comp_flags = !!neg_opt;
2080                         break;
2081                 case LFS_COMP_START_OPT:
2082                         if (optarg[0] == '+') {
2083                                 param.fp_comp_start_sign = -1;
2084                                 optarg++;
2085                         } else if (optarg[0] == '-') {
2086                                 param.fp_comp_start_sign =  1;
2087                                 optarg++;
2088                         }
2089
2090                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
2091                                               &param.fp_comp_start_units, 0);
2092                         if (rc) {
2093                                 fprintf(stderr, "error: bad component start "
2094                                         "'%s'\n", optarg);
2095                                 goto err;
2096                         }
2097                         param.fp_check_comp_start = 1;
2098                         param.fp_exclude_comp_start = !!neg_opt;
2099                         break;
2100                 case 'c':
2101                         if (optarg[0] == '+') {
2102                                 param.fp_stripe_count_sign = -1;
2103                                 optarg++;
2104                         } else if (optarg[0] == '-') {
2105                                 param.fp_stripe_count_sign =  1;
2106                                 optarg++;
2107                         }
2108
2109                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2110                         if (*endptr != '\0') {
2111                                 fprintf(stderr,"error: bad stripe_count '%s'\n",
2112                                         optarg);
2113                                 ret = -1;
2114                                 goto err;
2115                         }
2116                         param.fp_check_stripe_count = 1;
2117                         param.fp_exclude_stripe_count = !!neg_opt;
2118                         break;
2119                 case 'D':
2120                         param.fp_max_depth = strtol(optarg, 0, 0);
2121                         break;
2122                 case 'E':
2123                         if (optarg[0] == '+') {
2124                                 param.fp_comp_end_sign = -1;
2125                                 optarg++;
2126                         } else if (optarg[0] == '-') {
2127                                 param.fp_comp_end_sign =  1;
2128                                 optarg++;
2129                         }
2130
2131                         if (arg_is_eof(optarg)) {
2132                                 param.fp_comp_end = LUSTRE_EOF;
2133                                 param.fp_comp_end_units = 1;
2134                                 rc = 0;
2135                         } else {
2136                                 rc = llapi_parse_size(optarg,
2137                                                 &param.fp_comp_end,
2138                                                 &param.fp_comp_end_units, 0);
2139                         }
2140                         if (rc) {
2141                                 fprintf(stderr, "error: bad component end "
2142                                         "'%s'\n", optarg);
2143                                 goto err;
2144                         }
2145                         param.fp_check_comp_end = 1;
2146                         param.fp_exclude_comp_end = !!neg_opt;
2147                         break;
2148                 case 'g':
2149                 case 'G':
2150                         rc = name2gid(&param.fp_gid, optarg);
2151                         if (rc) {
2152                                 param.fp_gid = strtoul(optarg, &endptr, 10);
2153                                 if (*endptr != '\0') {
2154                                         fprintf(stderr, "Group/GID: %s cannot "
2155                                                 "be found.\n", optarg);
2156                                         ret = -1;
2157                                         goto err;
2158                                 }
2159                         }
2160                         param.fp_exclude_gid = !!neg_opt;
2161                         param.fp_check_gid = 1;
2162                         break;
2163                 case 'H':
2164                         param.fp_hash_type = check_hashtype(optarg);
2165                         if (param.fp_hash_type == 0) {
2166                                 fprintf(stderr, "error: bad hash_type '%s'\n",
2167                                         optarg);
2168                                 ret = -1;
2169                                 goto err;
2170                         }
2171                         param.fp_check_hash_type = 1;
2172                         param.fp_exclude_hash_type = !!neg_opt;
2173                         break;
2174                 case 'L':
2175                         ret = name2layout(&param.fp_layout, optarg);
2176                         if (ret)
2177                                 goto err;
2178                         param.fp_exclude_layout = !!neg_opt;
2179                         param.fp_check_layout = 1;
2180                         break;
2181                 case 'u':
2182                 case 'U':
2183                         rc = name2uid(&param.fp_uid, optarg);
2184                         if (rc) {
2185                                 param.fp_uid = strtoul(optarg, &endptr, 10);
2186                                 if (*endptr != '\0') {
2187                                         fprintf(stderr, "User/UID: %s cannot "
2188                                                 "be found.\n", optarg);
2189                                         ret = -1;
2190                                         goto err;
2191                                 }
2192                         }
2193                         param.fp_exclude_uid = !!neg_opt;
2194                         param.fp_check_uid = 1;
2195                         break;
2196                 case LFS_POOL_OPT:
2197                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
2198                                 fprintf(stderr,
2199                                         "Pool name %s is too long"
2200                                         " (max is %d)\n", optarg,
2201                                         LOV_MAXPOOLNAME);
2202                                 ret = -1;
2203                                 goto err;
2204                         }
2205                         /* we do check for empty pool because empty pool
2206                          * is used to find V1 lov attributes */
2207                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2208                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2209                         param.fp_exclude_pool = !!neg_opt;
2210                         param.fp_check_pool = 1;
2211                         break;
2212                 case 'n':
2213                         param.fp_pattern = (char *)optarg;
2214                         param.fp_exclude_pattern = !!neg_opt;
2215                         break;
2216                 case 'm':
2217                 case 'i':
2218                 case 'O': {
2219                         char *buf, *token, *next, *p;
2220                         int len = 1;
2221                         void *tmp;
2222
2223                         buf = strdup(optarg);
2224                         if (buf == NULL) {
2225                                 ret = -ENOMEM;
2226                                 goto err;
2227                         }
2228
2229                         param.fp_exclude_obd = !!neg_opt;
2230
2231                         token = buf;
2232                         while (token && *token) {
2233                                 token = strchr(token, ',');
2234                                 if (token) {
2235                                         len++;
2236                                         token++;
2237                                 }
2238                         }
2239                         if (c == 'm') {
2240                                 param.fp_exclude_mdt = !!neg_opt;
2241                                 param.fp_num_alloc_mdts += len;
2242                                 tmp = realloc(param.fp_mdt_uuid,
2243                                               param.fp_num_alloc_mdts *
2244                                               sizeof(*param.fp_mdt_uuid));
2245                                 if (tmp == NULL) {
2246                                         ret = -ENOMEM;
2247                                         goto err_free;
2248                                 }
2249
2250                                 param.fp_mdt_uuid = tmp;
2251                         } else {
2252                                 param.fp_exclude_obd = !!neg_opt;
2253                                 param.fp_num_alloc_obds += len;
2254                                 tmp = realloc(param.fp_obd_uuid,
2255                                               param.fp_num_alloc_obds *
2256                                               sizeof(*param.fp_obd_uuid));
2257                                 if (tmp == NULL) {
2258                                         ret = -ENOMEM;
2259                                         goto err_free;
2260                                 }
2261
2262                                 param.fp_obd_uuid = tmp;
2263                         }
2264                         for (token = buf; token && *token; token = next) {
2265                                 struct obd_uuid *puuid;
2266                                 if (c == 'm') {
2267                                         puuid =
2268                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
2269                                 } else {
2270                                         puuid =
2271                                         &param.fp_obd_uuid[param.fp_num_obds++];
2272                                 }
2273                                 p = strchr(token, ',');
2274                                 next = 0;
2275                                 if (p) {
2276                                         *p = 0;
2277                                         next = p+1;
2278                                 }
2279
2280                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2281                                         ret = -E2BIG;
2282                                         goto err_free;
2283                                 }
2284
2285                                 strncpy(puuid->uuid, token,
2286                                         sizeof(puuid->uuid));
2287                         }
2288 err_free:
2289                         if (buf)
2290                                 free(buf);
2291                         break;
2292                 }
2293                 case 'p':
2294                         param.fp_zero_end = 1;
2295                         break;
2296                 case 'P':
2297                         break;
2298                 case LFS_PROJID_OPT:
2299                         rc = name2projid(&param.fp_projid, optarg);
2300                         if (rc) {
2301                                 param.fp_projid = strtoul(optarg, &endptr, 10);
2302                                 if (*endptr != '\0') {
2303                                         fprintf(stderr,
2304                                                 "Invalid project ID: %s",
2305                                                 optarg);
2306                                         ret = -1;
2307                                         goto err;
2308                                 }
2309                         }
2310                         param.fp_exclude_projid = !!neg_opt;
2311                         param.fp_check_projid = 1;
2312                         break;
2313                 case 's':
2314                         if (optarg[0] == '+') {
2315                                 param.fp_size_sign = -1;
2316                                 optarg++;
2317                         } else if (optarg[0] == '-') {
2318                                 param.fp_size_sign =  1;
2319                                 optarg++;
2320                         }
2321
2322                         ret = llapi_parse_size(optarg, &param.fp_size,
2323                                                &param.fp_size_units, 0);
2324                         if (ret) {
2325                                 fprintf(stderr, "error: bad file size '%s'\n",
2326                                         optarg);
2327                                 goto err;
2328                         }
2329                         param.fp_check_size = 1;
2330                         param.fp_exclude_size = !!neg_opt;
2331                         break;
2332                 case 'S':
2333                         if (optarg[0] == '+') {
2334                                 param.fp_stripe_size_sign = -1;
2335                                 optarg++;
2336                         } else if (optarg[0] == '-') {
2337                                 param.fp_stripe_size_sign =  1;
2338                                 optarg++;
2339                         }
2340
2341                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
2342                                                &param.fp_stripe_size_units, 0);
2343                         if (ret) {
2344                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
2345                                         optarg);
2346                                 goto err;
2347                         }
2348                         param.fp_check_stripe_size = 1;
2349                         param.fp_exclude_stripe_size = !!neg_opt;
2350                         break;
2351                 case 't':
2352                         param.fp_exclude_type = !!neg_opt;
2353                         switch (optarg[0]) {
2354                         case 'b':
2355                                 param.fp_type = S_IFBLK;
2356                                 break;
2357                         case 'c':
2358                                 param.fp_type = S_IFCHR;
2359                                 break;
2360                         case 'd':
2361                                 param.fp_type = S_IFDIR;
2362                                 break;
2363                         case 'f':
2364                                 param.fp_type = S_IFREG;
2365                                 break;
2366                         case 'l':
2367                                 param.fp_type = S_IFLNK;
2368                                 break;
2369                         case 'p':
2370                                 param.fp_type = S_IFIFO;
2371                                 break;
2372                         case 's':
2373                                 param.fp_type = S_IFSOCK;
2374                                 break;
2375                         default:
2376                                 fprintf(stderr, "error: %s: bad type '%s'\n",
2377                                         argv[0], optarg);
2378                                 ret = CMD_HELP;
2379                                 goto err;
2380                         };
2381                         break;
2382                 case 'T':
2383                         if (optarg[0] == '+') {
2384                                 param.fp_mdt_count_sign = -1;
2385                                 optarg++;
2386                         } else if (optarg[0] == '-') {
2387                                 param.fp_mdt_count_sign =  1;
2388                                 optarg++;
2389                         }
2390
2391                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2392                         if (*endptr != '\0') {
2393                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
2394                                         optarg);
2395                                 ret = -1;
2396                                 goto err;
2397                         }
2398                         param.fp_check_mdt_count = 1;
2399                         param.fp_exclude_mdt_count = !!neg_opt;
2400                         break;
2401                 default:
2402                         ret = CMD_HELP;
2403                         goto err;
2404                 };
2405         }
2406
2407         if (pathstart == -1) {
2408                 fprintf(stderr, "error: %s: no filename|pathname\n",
2409                         argv[0]);
2410                 ret = CMD_HELP;
2411                 goto err;
2412         } else if (pathend == -1) {
2413                 /* no options */
2414                 pathend = argc;
2415         }
2416
2417         do {
2418                 rc = llapi_find(argv[pathstart], &param);
2419                 if (rc != 0 && ret == 0)
2420                         ret = rc;
2421         } while (++pathstart < pathend);
2422
2423         if (ret)
2424                 fprintf(stderr, "error: %s failed for %s.\n",
2425                         argv[0], argv[optind - 1]);
2426 err:
2427         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2428                 free(param.fp_obd_uuid);
2429
2430         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2431                 free(param.fp_mdt_uuid);
2432
2433         return ret;
2434 }
2435
2436 static int lfs_getstripe_internal(int argc, char **argv,
2437                                   struct find_param *param)
2438 {
2439         struct option long_opts[] = {
2440         { .val = LFS_COMP_COUNT_OPT,
2441                         .name = "comp-count",   .has_arg = no_argument },
2442         { .val = LFS_COMP_COUNT_OPT,
2443                 .name = "component-count",      .has_arg = no_argument },
2444         { .val = LFS_COMP_FLAGS_OPT,
2445                         .name = "comp-flags",   .has_arg = optional_argument },
2446         { .val = LFS_COMP_FLAGS_OPT,
2447                 .name = "component-flags",      .has_arg = optional_argument },
2448         { .val = LFS_COMP_START_OPT,
2449                         .name = "comp-start",   .has_arg = optional_argument },
2450         { .val = LFS_COMP_START_OPT,
2451                 .name = "component-start",      .has_arg = optional_argument },
2452 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2453         /* This formerly implied "stripe-count", but was explicitly
2454          * made "stripe-count" for consistency with other options,
2455          * and to separate it from "mdt-count" when DNE arrives. */
2456         { .val = 'c',   .name = "count",        .has_arg = no_argument },
2457 #endif
2458         { .val = 'c',   .name = "stripe-count", .has_arg = no_argument },
2459         { .val = 'c',   .name = "stripe_count", .has_arg = no_argument },
2460         { .val = 'd',   .name = "directory",    .has_arg = no_argument },
2461         { .val = 'D',   .name = "default",      .has_arg = no_argument },
2462         { .val = 'E',   .name = "comp-end",     .has_arg = optional_argument },
2463         { .val = 'E',   .name = "component-end",
2464                                                 .has_arg = optional_argument },
2465         { .val = 'F',   .name = "fid",          .has_arg = no_argument },
2466         { .val = 'g',   .name = "generation",   .has_arg = no_argument },
2467         /* dirstripe { .val = 'H',      .name = "mdt-hash",
2468          *             .has_arg = required_argument }, */
2469 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2470         /* This formerly implied "stripe-index", but was explicitly
2471          * made "stripe-index" for consistency with other options,
2472          * and to separate it from "mdt-index" when DNE arrives. */
2473         { .val = 'i',   .name = "index",        .has_arg = no_argument },
2474 #endif
2475         { .val = 'i',   .name = "stripe-index", .has_arg = no_argument },
2476         { .val = 'i',   .name = "stripe_index", .has_arg = no_argument },
2477         { .val = 'I',   .name = "comp-id",      .has_arg = optional_argument },
2478         { .val = 'I',   .name = "component-id", .has_arg = optional_argument },
2479         { .val = 'L',   .name = "layout",       .has_arg = no_argument },
2480         { .val = 'm',   .name = "mdt",          .has_arg = no_argument },
2481         { .val = 'm',   .name = "mdt-index",    .has_arg = no_argument },
2482         { .val = 'm',   .name = "mdt_index",    .has_arg = no_argument },
2483 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2484         { .val = 'M',   .name = "mdt-index",    .has_arg = no_argument },
2485         { .val = 'M',   .name = "mdt_index",    .has_arg = no_argument },
2486 #endif
2487 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2488         /* This formerly implied "stripe-index", but was confusing
2489          * with "file offset" (which will eventually be needed for
2490          * with different layouts by offset), so deprecate it. */
2491         { .val = 'o',   .name = "offset",       .has_arg = no_argument },
2492 #endif
2493         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
2494         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
2495         { .val = 'p',   .name = "pool",         .has_arg = no_argument },
2496         { .val = 'q',   .name = "quiet",        .has_arg = no_argument },
2497         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
2498         { .val = 'R',   .name = "raw",          .has_arg = no_argument },
2499 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2500         /* This formerly implied "--stripe-size", but was confusing
2501          * with "lfs find --size|-s", which means "file size", so use
2502          * the consistent "--stripe-size|-S" for all commands. */
2503         { .val = 's',   .name = "size",         .has_arg = no_argument },
2504 #endif
2505         { .val = 'S',   .name = "stripe-size",  .has_arg = no_argument },
2506         { .val = 'S',   .name = "stripe_size",  .has_arg = no_argument },
2507         /* dirstripe { .val = 'T',      .name = "mdt-count",
2508          *             .has_arg = required_argument }, */
2509         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
2510         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
2511         { .name = NULL } };
2512         int c, rc;
2513         char *end, *tmp;
2514
2515         while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2516                                 long_opts, NULL)) != -1) {
2517                 switch (c) {
2518                 case 'c':
2519                         if (strcmp(argv[optind - 1], "--count") == 0)
2520                                 fprintf(stderr, "warning: '--count' deprecated,"
2521                                         " use '--stripe-count' instead\n");
2522                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2523                                 param->fp_verbose |= VERBOSE_COUNT;
2524                                 param->fp_max_depth = 0;
2525                         }
2526                         break;
2527                 case LFS_COMP_COUNT_OPT:
2528                         param->fp_verbose |= VERBOSE_COMP_COUNT;
2529                         param->fp_max_depth = 0;
2530                         break;
2531                 case LFS_COMP_FLAGS_OPT:
2532                         if (optarg != NULL) {
2533                                 __u32 *flags = &param->fp_comp_flags;
2534                                 rc = comp_str2flags(flags, optarg);
2535                                 if (rc != 0) {
2536                                         fprintf(stderr, "error: %s bad "
2537                                                 "component flags '%s'.\n",
2538                                                 argv[0], optarg);
2539                                         return CMD_HELP;
2540                                 } else {
2541                                         param->fp_check_comp_flags = 1;
2542                                         param->fp_exclude_comp_flags =
2543                                                 comp_flags_is_neg(*flags);
2544                                         comp_flags_clear_neg(flags);
2545                                 }
2546                         } else {
2547                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2548                                 param->fp_max_depth = 0;
2549                         }
2550                         break;
2551                 case LFS_COMP_START_OPT:
2552                         if (optarg != NULL) {
2553                                 tmp = optarg;
2554                                 if (tmp[0] == '+') {
2555                                         param->fp_comp_start_sign = -1;
2556                                         tmp++;
2557                                 } else if (tmp[0] == '-') {
2558                                         param->fp_comp_start_sign = 1;
2559                                         tmp++;
2560                                 }
2561                                 rc = llapi_parse_size(tmp,
2562                                                 &param->fp_comp_start,
2563                                                 &param->fp_comp_start_units, 0);
2564                                 if (rc != 0) {
2565                                         fprintf(stderr, "error: %s bad "
2566                                                 "component start '%s'.\n",
2567                                                 argv[0], tmp);
2568                                         return CMD_HELP;
2569                                 } else {
2570                                         param->fp_check_comp_start = 1;
2571                                 }
2572                         } else {
2573                                 param->fp_verbose |= VERBOSE_COMP_START;
2574                                 param->fp_max_depth = 0;
2575                         }
2576                         break;
2577                 case 'd':
2578                         param->fp_max_depth = 0;
2579                         break;
2580                 case 'D':
2581                         param->fp_get_default_lmv = 1;
2582                         break;
2583                 case 'E':
2584                         if (optarg != NULL) {
2585                                 tmp = optarg;
2586                                 if (tmp[0] == '+') {
2587                                         param->fp_comp_end_sign = -1;
2588                                         tmp++;
2589                                 } else if (tmp[0] == '-') {
2590                                         param->fp_comp_end_sign = 1;
2591                                         tmp++;
2592                                 }
2593
2594                                 if (arg_is_eof(tmp)) {
2595                                         param->fp_comp_end = LUSTRE_EOF;
2596                                         param->fp_comp_end_units = 1;
2597                                         rc = 0;
2598                                 } else {
2599                                         rc = llapi_parse_size(tmp,
2600                                                 &param->fp_comp_end,
2601                                                 &param->fp_comp_end_units, 0);
2602                                 }
2603                                 if (rc != 0) {
2604                                         fprintf(stderr, "error: %s bad "
2605                                                 "component end '%s'.\n",
2606                                                 argv[0], tmp);
2607                                         return CMD_HELP;
2608                                 }
2609                                 param->fp_check_comp_end = 1;
2610                         } else {
2611                                 param->fp_verbose |= VERBOSE_COMP_END;
2612                                 param->fp_max_depth = 0;
2613                         }
2614                         break;
2615                 case 'F':
2616                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2617                                 param->fp_verbose |= VERBOSE_DFID;
2618                                 param->fp_max_depth = 0;
2619                         }
2620                         break;
2621                 case 'g':
2622                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2623                                 param->fp_verbose |= VERBOSE_GENERATION;
2624                                 param->fp_max_depth = 0;
2625                         }
2626                         break;
2627 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2628                 case 'o':
2629                         fprintf(stderr, "warning: '--offset|-o' deprecated, "
2630                                 "use '--stripe-index|-i' instead\n");
2631 #endif
2632                 case 'i':
2633 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2634                         if (strcmp(argv[optind - 1], "--index") == 0)
2635                                 fprintf(stderr, "warning: '--index' deprecated"
2636                                         ", use '--stripe-index' instead\n");
2637 #endif
2638                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2639                                 param->fp_verbose |= VERBOSE_OFFSET;
2640                                 param->fp_max_depth = 0;
2641                         }
2642                         break;
2643                 case 'I':
2644                         if (optarg != NULL) {
2645                                 param->fp_comp_id = strtoul(optarg, &end, 0);
2646                                 if (*end != '\0' || param->fp_comp_id == 0 ||
2647                                     param->fp_comp_id > LCME_ID_MAX) {
2648                                         fprintf(stderr, "error: %s bad "
2649                                                 "component id '%s'\n",
2650                                                 argv[0], optarg);
2651                                         return CMD_HELP;
2652                                 } else {
2653                                         param->fp_check_comp_id = 1;
2654                                 }
2655                         } else {
2656                                 param->fp_max_depth = 0;
2657                                 param->fp_verbose |= VERBOSE_COMP_ID;
2658                         }
2659                         break;
2660                 case 'L':
2661                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2662                                 param->fp_verbose |= VERBOSE_LAYOUT;
2663                                 param->fp_max_depth = 0;
2664                         }
2665                         break;
2666 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2667                 case 'M':
2668 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2669                         fprintf(stderr, "warning: '-M' deprecated"
2670                                 ", use '-m' instead\n");
2671 #endif
2672 #endif
2673                 case 'm':
2674                         if (!(param->fp_verbose & VERBOSE_DETAIL))
2675                                 param->fp_max_depth = 0;
2676                         param->fp_verbose |= VERBOSE_MDTINDEX;
2677                         break;
2678                 case 'O':
2679                         if (param->fp_obd_uuid) {
2680                                 fprintf(stderr,
2681                                         "error: %s: only one obduuid allowed",
2682                                         argv[0]);
2683                                 return CMD_HELP;
2684                         }
2685                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
2686                         break;
2687                 case 'p':
2688                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2689                                 param->fp_verbose |= VERBOSE_POOL;
2690                                 param->fp_max_depth = 0;
2691                         }
2692                         break;
2693                 case 'q':
2694                         param->fp_quiet++;
2695                         break;
2696                 case 'r':
2697                         param->fp_recursive = 1;
2698                         break;
2699                 case 'R':
2700                         param->fp_raw = 1;
2701                         break;
2702 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2703                 case 's':
2704                         fprintf(stderr, "warning: '--size|-s' deprecated, "
2705                                 "use '--stripe-size|-S' instead\n");
2706 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2707                 case 'S':
2708                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2709                                 param->fp_verbose |= VERBOSE_SIZE;
2710                                 param->fp_max_depth = 0;
2711                         }
2712                         break;
2713                 case 'v':
2714                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2715                         break;
2716                 case 'y':
2717                         param->fp_yaml = 1;
2718                         break;
2719                 default:
2720                         return CMD_HELP;
2721                 }
2722         }
2723
2724         if (optind >= argc)
2725                 return CMD_HELP;
2726
2727         if (param->fp_recursive)
2728                 param->fp_max_depth = -1;
2729         else if (param->fp_verbose & VERBOSE_DETAIL)
2730                 param->fp_max_depth = 1;
2731
2732         if (!param->fp_verbose)
2733                 param->fp_verbose = VERBOSE_DEFAULT;
2734         if (param->fp_quiet)
2735                 param->fp_verbose = VERBOSE_OBJID;
2736
2737         do {
2738                 rc = llapi_getstripe(argv[optind], param);
2739         } while (++optind < argc && !rc);
2740
2741         if (rc)
2742                 fprintf(stderr, "error: %s failed for %s.\n",
2743                         argv[0], argv[optind - 1]);
2744         return rc;
2745 }
2746
2747 static int lfs_tgts(int argc, char **argv)
2748 {
2749         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2750         struct find_param param;
2751         int index = 0, rc=0;
2752
2753         if (argc > 2)
2754                 return CMD_HELP;
2755
2756         if (argc == 2 && !realpath(argv[1], path)) {
2757                 rc = -errno;
2758                 fprintf(stderr, "error: invalid path '%s': %s\n",
2759                         argv[1], strerror(-rc));
2760                 return rc;
2761         }
2762
2763         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2764                 /* Check if we have a mount point */
2765                 if (mntdir[0] == '\0')
2766                         continue;
2767
2768                 memset(&param, 0, sizeof(param));
2769                 if (!strcmp(argv[0], "mdts"))
2770                         param.fp_get_lmv = 1;
2771
2772                 rc = llapi_ostlist(mntdir, &param);
2773                 if (rc) {
2774                         fprintf(stderr, "error: %s: failed on %s\n",
2775                                 argv[0], mntdir);
2776                 }
2777                 if (path[0] != '\0')
2778                         break;
2779                 memset(mntdir, 0, PATH_MAX);
2780         }
2781
2782         return rc;
2783 }
2784
2785 static int lfs_getstripe(int argc, char **argv)
2786 {
2787         struct find_param param = { 0 };
2788
2789         param.fp_max_depth = 1;
2790         return lfs_getstripe_internal(argc, argv, &param);
2791 }
2792
2793 /* functions */
2794 static int lfs_getdirstripe(int argc, char **argv)
2795 {
2796         struct find_param param = { 0 };
2797         struct option long_opts[] = {
2798 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2799         { .val = 'c',   .name = "mdt-count",    .has_arg = no_argument },
2800 #endif
2801         { .val = 'D',   .name = "default",      .has_arg = no_argument },
2802         { .val = 'H',   .name = "mdt-hash",     .has_arg = no_argument },
2803         { .val = 'i',   .name = "mdt-index",    .has_arg = no_argument },
2804         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
2805         { .val = 'r',   .name = "recursive",    .has_arg = no_argument },
2806 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2807         { .val = 't',   .name = "mdt-hash",     .has_arg = no_argument },
2808 #endif
2809         { .val = 'T',   .name = "mdt-count",    .has_arg = no_argument },
2810         { .val = 'y',   .name = "yaml",         .has_arg = no_argument },
2811         { .name = NULL } };
2812         int c, rc;
2813
2814         param.fp_get_lmv = 1;
2815
2816         while ((c = getopt_long(argc, argv,
2817                                 "cDHiO:rtTy", long_opts, NULL)) != -1)
2818         {
2819                 switch (c) {
2820                 case 'O':
2821                         if (param.fp_obd_uuid) {
2822                                 fprintf(stderr,
2823                                         "error: %s: only one obduuid allowed",
2824                                         argv[0]);
2825                                 return CMD_HELP;
2826                         }
2827                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
2828                         break;
2829 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2830                 case 'c':
2831 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2832                         fprintf(stderr, "warning: '-c' deprecated"
2833                                 ", use '-T' instead\n");
2834 #endif
2835 #endif
2836                 case 'T':
2837                         param.fp_verbose |= VERBOSE_COUNT;
2838                         break;
2839                 case 'i':
2840                         param.fp_verbose |= VERBOSE_OFFSET;
2841                         break;
2842 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2843                 case 't':
2844 #endif
2845                 case 'H':
2846                         param.fp_verbose |= VERBOSE_HASH_TYPE;
2847                         break;
2848                 case 'D':
2849                         param.fp_get_default_lmv = 1;
2850                         break;
2851                 case 'r':
2852                         param.fp_recursive = 1;
2853                         break;
2854                 case 'y':
2855                         param.fp_yaml = 1;
2856                         break;
2857                 default:
2858                         return CMD_HELP;
2859                 }
2860         }
2861
2862         if (optind >= argc)
2863                 return CMD_HELP;
2864
2865         if (param.fp_recursive)
2866                 param.fp_max_depth = -1;
2867
2868         if (!param.fp_verbose)
2869                 param.fp_verbose = VERBOSE_DEFAULT;
2870
2871         do {
2872                 rc = llapi_getstripe(argv[optind], &param);
2873         } while (++optind < argc && !rc);
2874
2875         if (rc)
2876                 fprintf(stderr, "error: %s failed for %s.\n",
2877                         argv[0], argv[optind - 1]);
2878         return rc;
2879 }
2880
2881 /* functions */
2882 static int lfs_setdirstripe(int argc, char **argv)
2883 {
2884         char                    *dname;
2885         int                     result;
2886         unsigned int            stripe_offset = -1;
2887         unsigned int            stripe_count = 1;
2888         enum lmv_hash_type      hash_type;
2889         char                    *end;
2890         int                     c;
2891         char                    *stripe_offset_opt = NULL;
2892         char                    *stripe_count_opt = NULL;
2893         char                    *stripe_hash_opt = NULL;
2894         char                    *mode_opt = NULL;
2895         bool                    default_stripe = false;
2896         mode_t                  mode = S_IRWXU | S_IRWXG | S_IRWXO;
2897         mode_t                  previous_mode = 0;
2898         bool                    delete = false;
2899
2900         struct option long_opts[] = {
2901 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2902         { .val = 'c',   .name = "count",        .has_arg = required_argument },
2903 #endif
2904         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
2905         { .val = 'd',   .name = "delete",       .has_arg = no_argument },
2906 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2907         { .val = 'i',   .name = "index",        .has_arg = required_argument },
2908 #endif
2909         { .val = 'i',   .name = "mdt-index",    .has_arg = required_argument },
2910         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
2911 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2912         { .val = 't',   .name = "hash-type",    .has_arg = required_argument },
2913         { .val = 't',   .name = "mdt-hash",     .has_arg = required_argument },
2914 #endif
2915                 {"mdt-hash",    required_argument, 0, 'H'},
2916 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2917         { .val = 'D',   .name = "default_stripe",
2918                                                 .has_arg = no_argument },
2919 #endif
2920         { .val = 'D',   .name = "default",      .has_arg = no_argument },
2921         { .name = NULL } };
2922
2923         while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2924                                 NULL)) >= 0) {
2925                 switch (c) {
2926                 case 0:
2927                         /* Long options. */
2928                         break;
2929                 case 'c':
2930 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2931                         if (strcmp(argv[optind - 1], "--count") == 0)
2932                                 fprintf(stderr,
2933                                         "%s %s: warning: '--count' deprecated, use '--mdt-count' instead\n",
2934                                         progname, argv[0]);
2935 #endif
2936                         stripe_count_opt = optarg;
2937                         break;
2938                 case 'd':
2939                         delete = true;
2940                         default_stripe = true;
2941                         break;
2942                 case 'D':
2943                         default_stripe = true;
2944                         break;
2945                 case 'i':
2946 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2947                         if (strcmp(argv[optind - 1], "--index") == 0)
2948                                 fprintf(stderr,
2949                                         "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
2950                                         progname, argv[0]);
2951 #endif
2952                         stripe_offset_opt = optarg;
2953                         break;
2954                 case 'm':
2955                         mode_opt = optarg;
2956                         break;
2957 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2958                 case 't':
2959 #endif
2960                 case 'H':
2961 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2962                         if (strcmp(argv[optind - 1], "--hash-type") == 0)
2963                                 fprintf(stderr,
2964                                         "%s %s: warning: '--hash-type' deprecated, use '--mdt-hash' instead\n",
2965                                         progname, argv[0]);
2966 #endif
2967                         stripe_hash_opt = optarg;
2968                         break;
2969                 default:
2970                         fprintf(stderr, "%s %s: unrecognized option '%s'\n",
2971                                 progname, argv[0], argv[optind - 1]);
2972                         return CMD_HELP;
2973                 }
2974         }
2975
2976         if (optind == argc) {
2977                 fprintf(stderr, "%s %s: DIR must be specified\n",
2978                         progname, argv[0]);
2979                 return CMD_HELP;
2980         }
2981
2982         if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2983                 fprintf(stderr,
2984                         "%s %s: stripe offset and count must be specified\n",
2985                         progname, argv[0]);
2986                 return CMD_HELP;
2987         }
2988
2989         if (stripe_offset_opt != NULL) {
2990                 /* get the stripe offset */
2991                 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2992                 if (*end != '\0') {
2993                         fprintf(stderr,
2994                                 "%s %s: bad stripe offset '%s'\n",
2995                                 progname, argv[0], stripe_offset_opt);
2996                         return CMD_HELP;
2997                 }
2998         }
2999
3000         if (delete) {
3001                 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
3002                         fprintf(stderr,
3003                                 "%s %s: cannot specify -d with -c or -i options\n",
3004                                 progname, argv[0]);
3005                         return CMD_HELP;
3006                 } else {
3007                         stripe_count = 0;
3008                 }
3009         }
3010
3011
3012         if (mode_opt != NULL) {
3013                 mode = strtoul(mode_opt, &end, 8);
3014                 if (*end != '\0') {
3015                         fprintf(stderr,
3016                                 "%s %s: bad MODE '%s'\n",
3017                                 progname, argv[0], mode_opt);
3018                         return CMD_HELP;
3019                 }
3020                 previous_mode = umask(0);
3021         }
3022
3023         if (stripe_hash_opt == NULL) {
3024                 hash_type = LMV_HASH_TYPE_FNV_1A_64;
3025         } else {
3026                 hash_type = check_hashtype(stripe_hash_opt);
3027                 if (hash_type == 0) {
3028                         fprintf(stderr, "%s %s: bad stripe hash type '%s'\n",
3029                                 progname, argv[0], stripe_hash_opt);
3030                         return CMD_HELP;
3031                 }
3032         }
3033
3034         /* get the stripe count */
3035         if (stripe_count_opt != NULL) {
3036                 stripe_count = strtoul(stripe_count_opt, &end, 0);
3037                 if (*end != '\0') {
3038                         fprintf(stderr,
3039                                 "%s %s: bad stripe count '%s'\n",
3040                                 progname, argv[0], stripe_count_opt);
3041                         return CMD_HELP;
3042                 }
3043         }
3044
3045         dname = argv[optind];
3046         do {
3047                 if (default_stripe) {
3048                         result = llapi_dir_set_default_lmv_stripe(dname,
3049                                                     stripe_offset, stripe_count,
3050                                                     hash_type, NULL);
3051                 } else {
3052                         result = llapi_dir_create_pool(dname, mode,
3053                                                        stripe_offset,
3054                                                        stripe_count, hash_type,
3055                                                        NULL);
3056                 }
3057
3058                 if (result) {
3059                         fprintf(stderr,
3060                                 "%s setdirstripe: cannot create stripe dir '%s': %s\n",
3061                                 progname, dname, strerror(-result));
3062                         break;
3063                 }
3064                 dname = argv[++optind];
3065         } while (dname != NULL);
3066
3067         if (mode_opt != NULL)
3068                 umask(previous_mode);
3069
3070         return result;
3071 }
3072
3073 /* functions */
3074 static int lfs_rmentry(int argc, char **argv)
3075 {
3076         char *dname;
3077         int   index;
3078         int   result = 0;
3079
3080         if (argc <= 1) {
3081                 fprintf(stderr, "error: %s: missing dirname\n",
3082                         argv[0]);
3083                 return CMD_HELP;
3084         }
3085
3086         index = 1;
3087         dname = argv[index];
3088         while (dname != NULL) {
3089                 result = llapi_direntry_remove(dname);
3090                 if (result) {
3091                         fprintf(stderr, "error: %s: remove dir entry '%s' "
3092                                 "failed\n", argv[0], dname);
3093                         break;
3094                 }
3095                 dname = argv[++index];
3096         }
3097         return result;
3098 }
3099
3100 static int lfs_mv(int argc, char **argv)
3101 {
3102         struct  find_param param = {
3103                 .fp_max_depth = -1,
3104                 .fp_mdt_index = -1,
3105         };
3106         char   *end;
3107         int     c;
3108         int     rc = 0;
3109         struct option long_opts[] = {
3110         { .val = 'M',   .name = "mdt-index",    .has_arg = required_argument },
3111         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
3112         { .name = NULL } };
3113
3114         while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3115                 switch (c) {
3116                 case 'M': {
3117                         param.fp_mdt_index = strtoul(optarg, &end, 0);
3118                         if (*end != '\0') {
3119                                 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3120                                         argv[0], optarg);
3121                                 return CMD_HELP;
3122                         }
3123                         break;
3124                 }
3125                 case 'v': {
3126                         param.fp_verbose = VERBOSE_DETAIL;
3127                         break;
3128                 }
3129                 default:
3130                         fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3131                                 argv[0], argv[optind - 1]);
3132                         return CMD_HELP;
3133                 }
3134         }
3135
3136         if (param.fp_mdt_index == -1) {
3137                 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3138                 return CMD_HELP;
3139         }
3140
3141         if (optind >= argc) {
3142                 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3143                 return CMD_HELP;
3144         }
3145
3146         param.fp_migrate = 1;
3147         rc = llapi_migrate_mdt(argv[optind], &param);
3148         if (rc != 0)
3149                 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3150                         argv[0], argv[optind], param.fp_mdt_index,
3151                         strerror(-rc));
3152         return rc;
3153 }
3154
3155 static int lfs_osts(int argc, char **argv)
3156 {
3157         return lfs_tgts(argc, argv);
3158 }
3159
3160 static int lfs_mdts(int argc, char **argv)
3161 {
3162         return lfs_tgts(argc, argv);
3163 }
3164
3165 #define COOK(value)                                                     \
3166 ({                                                                      \
3167         int radix = 0;                                                  \
3168         while (value > 1024) {                                          \
3169                 value /= 1024;                                          \
3170                 radix++;                                                \
3171         }                                                               \
3172         radix;                                                          \
3173 })
3174 #define UUF     "%-20s"
3175 #define CSF     "%11s"
3176 #define CDF     "%11llu"
3177 #define HDF     "%8.1f%c"
3178 #define RSF     "%4s"
3179 #define RDF     "%3d%%"
3180
3181 enum mntdf_flags {
3182         MNTDF_INODES    = 0x0001,
3183         MNTDF_COOKED    = 0x0002,
3184         MNTDF_LAZY      = 0x0004,
3185         MNTDF_VERBOSE   = 0x0008,
3186 };
3187
3188 static int showdf(char *mntdir, struct obd_statfs *stat,
3189                   char *uuid, enum mntdf_flags flags,
3190                   char *type, int index, int rc)
3191 {
3192         long long avail, used, total;
3193         double ratio = 0;
3194         char *suffix = "KMGTPEZY";
3195         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3196         char tbuf[3 * sizeof(__u64)];
3197         char ubuf[3 * sizeof(__u64)];
3198         char abuf[3 * sizeof(__u64)];
3199         char rbuf[3 * sizeof(__u64)];
3200
3201         if (!uuid || !stat)
3202                 return -EINVAL;
3203
3204         switch (rc) {
3205         case 0:
3206                 if (flags & MNTDF_INODES) {
3207                         avail = stat->os_ffree;
3208                         used = stat->os_files - stat->os_ffree;
3209                         total = stat->os_files;
3210                 } else {
3211                         int shift = flags & MNTDF_COOKED ? 0 : 10;
3212
3213                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
3214                         used  = ((stat->os_blocks - stat->os_bfree) *
3215                                  stat->os_bsize) >> shift;
3216                         total = (stat->os_blocks * stat->os_bsize) >> shift;
3217                 }
3218
3219                 if ((used + avail) > 0)
3220                         ratio = (double)used / (double)(used + avail);
3221
3222                 if (flags & MNTDF_COOKED) {
3223                         int i;
3224                         double cook_val;
3225
3226                         cook_val = (double)total;
3227                         i = COOK(cook_val);
3228                         if (i > 0)
3229                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3230                                          suffix[i - 1]);
3231                         else
3232                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
3233
3234                         cook_val = (double)used;
3235                         i = COOK(cook_val);
3236                         if (i > 0)
3237                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3238                                          suffix[i - 1]);
3239                         else
3240                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
3241
3242                         cook_val = (double)avail;
3243                         i = COOK(cook_val);
3244                         if (i > 0)
3245                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3246                                          suffix[i - 1]);
3247                         else
3248                                 snprintf(abuf, sizeof(abuf), CDF, avail);
3249                 } else {
3250                         snprintf(tbuf, sizeof(tbuf), CDF, total);
3251                         snprintf(ubuf, sizeof(tbuf), CDF, used);
3252                         snprintf(abuf, sizeof(tbuf), CDF, avail);
3253                 }
3254
3255                 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3256                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3257                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3258                 if (type)
3259                         printf("[%s:%d]", type, index);
3260
3261                 if (stat->os_state) {
3262                         /*
3263                          * Each character represents the matching
3264                          * OS_STATE_* bit.
3265                          */
3266                         const char state_names[] = "DRSI";
3267                         __u32      state;
3268                         __u32      i;
3269
3270                         printf(" ");
3271                         for (i = 0, state = stat->os_state;
3272                              state && i < sizeof(state_names); i++) {
3273                                 if (!(state & (1 << i)))
3274                                         continue;
3275                                 printf("%c", state_names[i]);
3276                                 state ^= 1 << i;
3277                         }
3278                 }
3279
3280                 printf("\n");
3281                 break;
3282         case -ENODATA:
3283                 printf(UUF": inactive device\n", uuid);
3284                 break;
3285         default:
3286                 printf(UUF": %s\n", uuid, strerror(-rc));
3287                 break;
3288         }
3289
3290         return 0;
3291 }
3292
3293 struct ll_stat_type {
3294         int   st_op;
3295         char *st_name;
3296 };
3297
3298 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3299 {
3300         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3301         struct obd_uuid uuid_buf;
3302         char *poolname = NULL;
3303         struct ll_stat_type types[] = {
3304                 { .st_op = LL_STATFS_LMV,       .st_name = "MDT" },
3305                 { .st_op = LL_STATFS_LOV,       .st_name = "OST" },
3306                 { .st_name = NULL } };
3307         struct ll_stat_type *tp;
3308         __u64 ost_ffree = 0;
3309         __u32 index;
3310         __u32 type;
3311         int fd;
3312         int rc = 0;
3313         int rc2;
3314
3315         if (pool) {
3316                 poolname = strchr(pool, '.');
3317                 if (poolname != NULL) {
3318                         if (strncmp(fsname, pool, strlen(fsname))) {
3319                                 fprintf(stderr, "filesystem name incorrect\n");
3320                                 return -ENODEV;
3321                         }
3322                         poolname++;
3323                 } else
3324                         poolname = pool;
3325         }
3326
3327         fd = open(mntdir, O_RDONLY);
3328         if (fd < 0) {
3329                 rc = -errno;
3330                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3331                         strerror(errno));
3332                 return rc;
3333         }
3334
3335         if (flags & MNTDF_INODES)
3336                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3337                        "UUID", "Inodes", "IUsed", "IFree",
3338                        "IUse%", "Mounted on");
3339         else
3340                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3341                        "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3342                        "Used", "Available", "Use%", "Mounted on");
3343
3344         for (tp = types; tp->st_name != NULL; tp++) {
3345                 for (index = 0; ; index++) {
3346