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