4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
57 #include <sys/types.h>
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 <lustre_ver.h>
69 #include <lustre_param.h>
72 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
73 #endif /* !ARRAY_SIZE */
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);
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);
114 /* Setstripe and migrate share mostly the same parameters */
115 #define SSM_CMD_COMMON(cmd) \
116 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
117 " [--stripe-index|-i <start_ost_idx>]\n" \
118 " [--stripe-size|-S <stripe_size>]\n" \
119 " [--pool|-p <pool_name>]\n" \
120 " [--ost|-o <ost_indices>]\n" \
121 " [--component-end|-E <comp_end>]\n"
123 #define SSM_HELP_COMMON \
124 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
125 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
126 "\t respectively)\n" \
127 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
128 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
129 "\tpool_name: Name of OST pool to use (default none)\n" \
130 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
131 "\t Indices be specified in a format of:\n" \
132 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
134 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
135 "\t If --pool is set with --ost, then the OSTs\n" \
136 "\t must be the members of the pool." \
137 "\tcomp_end: Extent end of the component\n" \
138 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
139 "\t respectively, -1 for EOF), it must be aligned with\n"\
140 "\t the stripe_size\n"
142 #define SETSTRIPE_USAGE \
143 SSM_CMD_COMMON("setstripe") \
144 " <directory|filename>\n" \
147 #define MIGRATE_USAGE \
148 SSM_CMD_COMMON("migrate ") \
150 " [--non-block|-n]\n" \
154 "\tblock: Block file access during data migration (default)\n" \
155 "\tnon-block: Abort migrations if concurrent access is detected\n" \
157 #define SETDIRSTRIPE_USAGE \
158 " [--mdt-count|-c stripe_count>\n" \
159 " [--mdt-index|-i mdt_index]\n" \
160 " [--mdt-hash|-H mdt_hash]\n" \
161 " [--default|-D] [--mode|-m mode] <dir>\n" \
162 "\tstripe_count: stripe count of the striped directory\n" \
163 "\tmdt_index: MDT index of first stripe\n" \
164 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
165 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
166 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
167 "\tdefault_stripe: set default dirstripe of the directory\n" \
168 "\tmode: the mode of the directory\n"
170 static const char *progname;
171 static bool file_lease_supported = true;
173 /* all available commands */
174 command_t cmdlist[] = {
175 {"setstripe", lfs_setstripe, 0,
176 "Create a new file with a specific striping pattern or\n"
177 "set the default striping pattern on an existing directory or\n"
178 "delete the default striping pattern from an existing directory or\n"
179 "add layout component(s) to an existing composite file or\n"
180 "delete specified component(s) from an existing composite file\n\n"
181 "To delete default striping from an existing directory:\n"
182 "usage: setstripe -d <directory>\n"
184 "To delete component(s) from an existing composite file:\n"
185 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
186 " [--component-flags|-F <comp_flags>]\n"
188 "\tcomp_id: Unique component ID\n"
189 "\tcomp_flags: 'init' indicating all instantiated components\n"
190 "\t '^init' indicating all uninstantiated components\n"
191 "\t-I and -F can't be specified at the same time\n"
193 "To add component(s) to an existing composite file:\n"
194 SSM_CMD_COMMON("setstripe --component-add")
196 "To create a file with specified striping/composite layout:\n"
198 {"getstripe", lfs_getstripe, 0,
199 "To list the striping info for a given file or files in a\n"
200 "directory or recursively for all files in a directory tree.\n"
201 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
202 " [--stripe-count|-c] [--stripe-index|-i]\n"
203 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
204 " [--mdt|-m] [--recursive|-r] [--raw|-R] [--yaml|-y]\n"
205 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
206 " [--component-id|-I [comp_id]]\n"
207 " [--component-flags [comp_flags]]\n"
208 " [--component-count [comp_count]]\n"
209 " [--component-start [comp_start]]\n"
210 " [--component-end|-E [comp_end]]\n"
211 " <directory|filename> ..."},
212 {"setdirstripe", lfs_setdirstripe, 0,
213 "To create a striped directory on a specified MDT. This can only\n"
214 "be done on MDT0 with the right of administrator.\n"
215 "usage: setdirstripe [OPTION] <directory>\n"
217 {"getdirstripe", lfs_getdirstripe, 0,
218 "To list the striping info for a given directory\n"
219 "or recursively for all directories in a directory tree.\n"
220 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
221 " [--mdt-index|-i] [--mdt-hash|-t]\n"
222 " [--recursive|-r] [--yaml|-y]\n"
223 " [--default|-D] <dir> ..."},
224 {"mkdir", lfs_setdirstripe, 0,
225 "To create a striped directory on a specified MDT. This can only\n"
226 "be done on MDT0 with the right of administrator.\n"
227 "usage: mkdir [OPTION] <directory>\n"
229 {"rm_entry", lfs_rmentry, 0,
230 "To remove the name entry of the remote directory. Note: This\n"
231 "command will only delete the name entry, i.e. the remote directory\n"
232 "will become inaccessable after this command. This can only be done\n"
233 "by the administrator\n"
234 "usage: rm_entry <dir>\n"},
235 {"pool_list", lfs_poollist, 0,
236 "List pools or pool OSTs\n"
237 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
238 {"find", lfs_find, 0,
239 "find files matching given attributes recursively in directory tree.\n"
240 "usage: find <directory|filename> ...\n"
241 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
242 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
243 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
244 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
245 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
246 " [[!] --stripe-count|-c [+-]<stripes>]\n"
247 " [[!] --stripe-index|-i <index,...>]\n"
248 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
249 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
250 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
251 " [[!] --projid <projid>]\n"
252 " [[!] --layout|-L released,raid0]\n"
253 " [[!] --component-count [+-]<comp_cnt>]\n"
254 " [[!] --component-start [+-]N[kMGTPE]]\n"
255 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
256 " [[!] --component-flags <comp_flags>]\n"
257 " [[!] --mdt-count|-T [+-]<stripes>]\n"
258 " [[!] --mdt-hash|-H <hashtype>\n"
259 "\t !: used before an option indicates 'NOT' requested attribute\n"
260 "\t -: used before a value indicates 'AT MOST' requested value\n"
261 "\t +: used before a value indicates 'AT LEAST' requested value\n"
262 "\tmdt-hash: hash type of the striped directory.\n"
263 "\t fnv_1a_64 FNV-1a hash algorithm\n"
264 "\t all_char sum of characters % MDT_COUNT\n"},
265 {"check", lfs_check, 0,
266 "Display the status of MDS or OSTs (as specified in the command)\n"
267 "or all the servers (MDS and OSTs).\n"
268 "usage: check <osts|mds|servers>"},
269 {"osts", lfs_osts, 0, "list OSTs connected to client "
270 "[for specified path only]\n" "usage: osts [path]"},
271 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
272 "[for specified path only]\n" "usage: mdts [path]"},
274 "report filesystem disk space usage or inodes usage"
275 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
276 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
277 {"getname", lfs_getname, 0, "list instances and specified mount points "
278 "[for specified path only]\n"
279 "Usage: getname [-h]|[path ...] "},
280 #ifdef HAVE_SYS_QUOTA_H
281 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
282 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
283 " -b <block-softlimit> -B <block-hardlimit>\n"
284 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
285 " setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
286 " [--block-softlimit <block-softlimit>]\n"
287 " [--block-hardlimit <block-hardlimit>]\n"
288 " [--inode-softlimit <inode-softlimit>]\n"
289 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
290 " setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
291 " [--block-grace <block-grace>]\n"
292 " [--inode-grace <inode-grace>] <filesystem>\n"
293 " -b can be used instead of --block-softlimit/--block-grace\n"
294 " -B can be used instead of --block-hardlimit\n"
295 " -i can be used instead of --inode-softlimit/--inode-grace\n"
296 " -I can be used instead of --inode-hardlimit\n\n"
297 "Note: The total quota space will be split into many qunits and\n"
298 " balanced over all server targets, the minimal qunit size is\n"
299 " 1M bytes for block space and 1K inodes for inode space.\n\n"
300 " Quota space rebalancing process will stop when this mininum\n"
301 " value is reached. As a result, quota exceeded can be returned\n"
302 " while many targets still have 1MB or 1K inodes of spare\n"
304 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
305 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
307 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
308 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
310 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
311 "usage: flushctx [-k] [mountpoint...]"},
313 "Remote user copy files and directories.\n"
314 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
316 "Remote user list directory contents.\n"
317 "usage: ls [OPTION]... [FILE]..."},
318 {"changelog", lfs_changelog, 0,
319 "Show the metadata changes on an MDT."
320 "\nusage: changelog <mdtname> [startrec [endrec]]"},
321 {"changelog_clear", lfs_changelog_clear, 0,
322 "Indicate that old changelog records up to <endrec> are no longer of "
323 "interest to consumer <id>, allowing the system to free up space.\n"
324 "An <endrec> of 0 means all records.\n"
325 "usage: changelog_clear <mdtname> <id> <endrec>"},
326 {"fid2path", lfs_fid2path, 0,
327 "Resolve the full path(s) for given FID(s). For a specific hardlink "
328 "specify link number <linkno>.\n"
329 /* "For a historical link name, specify changelog record <recno>.\n" */
330 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
331 /* [ --rec <recno> ] */ },
332 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
333 "usage: path2fid [--parents] <path> ..."},
334 {"data_version", lfs_data_version, 0, "Display file data version for "
335 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
336 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
337 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
338 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
339 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
340 "[--archived] [--lost] <file> ..."},
341 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
343 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
344 "[--archived] [--lost] <file> ..."},
345 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
346 "given files.\n" "usage: hsm_action <file> ..."},
347 {"hsm_archive", lfs_hsm_archive, 0,
348 "Archive file to external storage.\n"
349 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
351 {"hsm_restore", lfs_hsm_restore, 0,
352 "Restore file from external storage.\n"
353 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
354 {"hsm_release", lfs_hsm_release, 0,
355 "Release files from Lustre.\n"
356 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
357 {"hsm_remove", lfs_hsm_remove, 0,
358 "Remove file copy from external storage.\n"
359 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
360 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
362 "Note: To remove files from the archive that have been deleted on\n"
363 "Lustre, set mntpath and optionally archive. In that case, all the\n"
364 "positional arguments and entries in the file list must be FIDs."
366 {"hsm_cancel", lfs_hsm_cancel, 0,
367 "Cancel requests related to specified files.\n"
368 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
369 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
370 "usage: swap_layouts <path1> <path2>"},
371 {"migrate", lfs_setstripe, 0,
372 "migrate a directory between MDTs.\n"
373 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
375 "\tmdt_idx: index of the destination MDT\n"
377 "migrate file objects from one OST "
378 "layout\nto another (may be not safe with concurent writes).\n"
380 "[--stripe-count|-c] <stripe_count>\n"
381 " [--stripe-index|-i] <start_ost_index>\n"
382 " [--stripe-size|-S] <stripe_size>\n"
383 " [--pool|-p] <pool_name>\n"
384 " [--ost-list|-o] <ost_indices>\n"
386 " [--non-block|-n]\n"
387 " <file|directory>\n"
388 "\tstripe_count: number of OSTs to stripe a file over\n"
389 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
390 "\tstripe_size: number of bytes to store before moving to the next OST\n"
391 "\tpool_name: name of the predefined pool of OSTs\n"
392 "\tost_indices: OSTs to stripe over, in order\n"
393 "\tblock: wait for the operation to return before continuing\n"
394 "\tnon-block: do not wait for the operation to return.\n"},
396 "To move directories between MDTs. This command is deprecated, "
397 "use \"migrate\" instead.\n"
398 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
400 {"ladvise", lfs_ladvise, 0,
401 "Provide servers with advice about access patterns for a file.\n"
402 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
403 " [--background|-b]\n"
404 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
406 {"help", Parser_help, 0, "help"},
407 {"exit", Parser_quit, 0, "quit"},
408 {"quit", Parser_quit, 0, "quit"},
409 {"--version", Parser_version, 0,
410 "output build version of the utility and exit"},
411 {"--list-commands", lfs_list_commands, 0,
412 "list commands supported by the utility and exit"},
417 #define MIGRATION_NONBLOCK 1
419 static int check_hashtype(const char *hashtype)
423 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
424 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
431 * Internal helper for migrate_copy_data(). Check lease and report error if
434 * \param[in] fd File descriptor on which to check the lease.
435 * \param[out] lease_broken Set to true if the lease was broken.
436 * \param[in] group_locked Whether a group lock was taken or not.
437 * \param[in] path Name of the file being processed, for error
440 * \retval 0 Migration can keep on going.
441 * \retval -errno Error occurred, abort migration.
443 static int check_lease(int fd, bool *lease_broken, bool group_locked,
448 if (!file_lease_supported)
451 rc = llapi_lease_check(fd);
453 return 0; /* llapi_check_lease returns > 0 on success. */
456 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
458 rc = rc ? rc : -EAGAIN;
460 fprintf(stderr, "%s: external attempt to access file '%s' "
461 "blocked until migration ends.\n", progname, path);
464 *lease_broken = true;
468 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
469 bool group_locked, const char *fname)
478 bool lease_broken = false;
480 /* Use a page-aligned buffer for direct I/O */
481 rc = posix_memalign(&buf, getpagesize(), buf_size);
486 /* read new data only if we have written all
487 * previously read data */
490 rc = check_lease(fd_src, &lease_broken,
491 group_locked, fname);
495 rsize = read(fd_src, buf, buf_size);
498 fprintf(stderr, "%s: %s: read failed: %s\n",
499 progname, fname, strerror(-rc));
509 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
513 "%s: %s: write failed on volatile: %s\n",
514 progname, fname, strerror(-rc));
524 fprintf(stderr, "%s: %s: fsync failed: %s\n",
525 progname, fname, strerror(-rc));
533 static int migrate_copy_timestamps(int fdv, const struct stat *st)
535 struct timeval tv[2] = {
536 {.tv_sec = st->st_atime},
537 {.tv_sec = st->st_mtime}
540 return futimes(fdv, tv);
543 static int migrate_block(int fd, int fdv, const struct stat *st,
544 size_t buf_size, const char *name)
551 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
553 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
554 progname, name, strerror(-rc));
562 /* The grouplock blocks all concurrent accesses to the file.
563 * It has to be taken after llapi_get_data_version as it would
565 rc = llapi_group_lock(fd, gid);
567 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
568 progname, name, strerror(-rc));
572 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
574 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
578 /* Make sure we keep original atime/mtime values */
579 rc = migrate_copy_timestamps(fdv, st);
581 fprintf(stderr, "%s: %s: timestamp copy failed\n",
587 * for a migration we need to check data version on file did
590 * Pass in gid=0 since we already own grouplock. */
591 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
592 SWAP_LAYOUTS_CHECK_DV1);
594 fprintf(stderr, "%s: %s: dataversion changed during copy, "
595 "migration aborted\n", progname, name);
598 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
599 name, strerror(-rc));
604 rc2 = llapi_group_unlock(fd, gid);
605 if (rc2 < 0 && rc == 0) {
606 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
607 progname, name, strerror(-rc2));
614 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
615 size_t buf_size, const char *name)
621 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
623 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
624 progname, name, strerror(-rc));
628 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
630 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
634 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
636 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
637 progname, name, strerror(-rc));
643 fprintf(stderr, "%s: %s: data version changed during "
649 /* Make sure we keep original atime/mtime values */
650 rc = migrate_copy_timestamps(fdv, st);
652 fprintf(stderr, "%s: %s: timestamp copy failed\n",
657 /* Atomically put lease, swap layouts and close.
658 * for a migration we need to check data version on file did
660 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
662 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
663 progname, name, strerror(-rc));
670 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
675 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
679 if (flags != 0 && comp_id != 0)
682 /* LCME_FL_INIT is the only supported flag in PFL */
684 if (flags & ~LCME_KNOWN_FLAGS) {
685 fprintf(stderr, "Invalid component flags %#x\n", flags);
688 } else if (comp_id > LCME_ID_MAX) {
689 fprintf(stderr, "Invalid component id %u\n", comp_id);
693 rc = llapi_layout_file_comp_del(fname, comp_id, flags);
695 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
696 comp_id, fname, strerror(errno));
700 static int lfs_component_add(char *fname, struct llapi_layout *layout)
707 rc = llapi_layout_file_comp_add(fname, layout);
709 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
710 fname, strerror(errno));
714 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
715 struct llapi_layout *layout)
723 fd = lstat(fname, &st);
724 if (fd == 0 && S_ISDIR(st.st_mode))
725 open_flags = O_DIRECTORY | O_RDONLY;
727 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
729 fprintf(stderr, "%s %s failed. %s\n",
730 S_ISDIR(st.st_mode) ?
731 "Set default composite layout to " :
732 "Create composite file",
733 fname, strerror(errno));
737 static int lfs_migrate(char *name, __u64 migration_flags,
738 struct llapi_stripe_param *param,
739 struct llapi_layout *layout)
743 char parent[PATH_MAX];
746 char volatile_file[sizeof(parent) +
747 LUSTRE_VOLATILE_HDR_LEN +
748 2 * sizeof(mdt_index) +
749 2 * sizeof(random_value) + 4];
752 struct lov_user_md *lum = NULL;
754 int buf_size = 1024 * 1024 * 4;
755 bool have_lease_rdlck = false;
759 /* find the right size for the IO and allocate the buffer */
760 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
761 lum = malloc(lum_size);
767 rc = llapi_file_get_stripe(name, lum);
768 /* failure can happen for many reasons and some may be not real errors
770 * in case of a real error, a later call will fail with better
771 * error management */
773 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
774 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
775 lum->lmm_stripe_size != 0)
776 buf_size = lum->lmm_stripe_size;
779 /* open file, direct io */
780 /* even if the file is only read, WR mode is nedeed to allow
781 * layout swap on fd */
782 fd = open(name, O_RDWR | O_DIRECT);
785 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
790 if (file_lease_supported) {
791 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
792 if (rc == -EOPNOTSUPP) {
793 /* Older servers do not support file lease.
794 * Disable related checks. This opens race conditions
795 * as explained in LU-4840 */
796 file_lease_supported = false;
798 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
799 progname, name, strerror(-rc));
802 have_lease_rdlck = true;
806 /* search for file directory pathname */
807 if (strlen(name) > sizeof(parent)-1) {
811 strncpy(parent, name, sizeof(parent));
812 ptr = strrchr(parent, '/');
814 if (getcwd(parent, sizeof(parent)) == NULL) {
825 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
827 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
828 progname, name, strerror(-rc));
833 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
834 mode_t open_mode = S_IRUSR | S_IWUSR;
836 random_value = random();
837 rc = snprintf(volatile_file, sizeof(volatile_file),
838 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
839 mdt_index, random_value);
840 if (rc >= sizeof(volatile_file)) {
845 /* create, open a volatile file, use caching (ie no directio) */
847 fdv = llapi_file_open_param(volatile_file, open_flags,
849 else if (layout != NULL)
850 fdv = lfs_component_create(volatile_file, open_flags,
854 } while (fdv == -EEXIST);
858 fprintf(stderr, "%s: %s: cannot create volatile file in"
860 progname, parent, strerror(-rc));
864 /* In case the MDT does not support creation of volatile files
865 * we should try to unlink it. */
866 (void)unlink(volatile_file);
868 /* Not-owner (root?) special case.
869 * Need to set owner/group of volatile file like original.
870 * This will allow to pass related check during layout_swap.
875 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
879 rc = fstat(fdv, &stv);
882 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
883 volatile_file, strerror(errno));
886 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
887 rc = fchown(fdv, st.st_uid, st.st_gid);
890 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
891 name, strerror(errno));
896 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
897 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
899 have_lease_rdlck = false;
900 fdv = -1; /* The volatile file is closed as we put the
901 * lease in non-blocking mode. */
904 /* Blocking mode (forced if servers do not support file lease).
905 * It is also the default mode, since we cannot distinguish
906 * between a broken lease and a server that does not support
907 * atomic swap/close (LU-6785) */
908 rc = migrate_block(fd, fdv, &st, buf_size, name);
912 if (have_lease_rdlck)
929 * Parse a string containing an OST index list into an array of integers.
931 * The input string contains a comma delimited list of individual
932 * indices and ranges, for example "1,2-4,7". Add the indices into the
933 * \a osts array and remove duplicates.
935 * \param[out] osts array to store indices in
936 * \param[in] size size of \a osts array
937 * \param[in] offset starting index in \a osts
938 * \param[in] arg string containing OST index list
940 * \retval positive number of indices in \a osts
941 * \retval -EINVAL unable to parse \a arg
943 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
947 int slots = size - offset;
955 while (!end_of_loop) {
963 ptr = strchrnul(arg, ',');
965 end_of_loop = *ptr == '\0';
968 start_index = strtol(arg, &endptr, 0);
969 if (endptr == arg) /* no data at all */
971 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
976 end_index = start_index;
977 if (*endptr == '-') {
978 end_index = strtol(endptr + 1, &endptr, 0);
981 if (end_index < start_index)
985 for (i = start_index; i <= end_index && slots > 0; i++) {
988 /* remove duplicate */
989 for (j = 0; j < offset; j++) {
993 if (j == offset) { /* no duplicate */
998 if (slots == 0 && i < end_index)
1006 if (!end_of_loop && ptr != NULL)
1009 return rc < 0 ? rc : nr;
1012 static int verify_pool_name(char *prog_name, char *pool_name)
1017 if (pool_name == NULL)
1020 ptr = strchr(pool_name, '.');
1024 if (ptr == pool_name) {
1025 fprintf(stderr, "error: %s: fsname is empty "
1026 "in pool name '%s'\n",
1027 prog_name, pool_name);
1033 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1035 fprintf(stderr, "error: %s: poolname '%s' is empty\n",
1036 prog_name, pool_name);
1038 } else if (rc == -2) {
1039 fprintf(stderr, "error: %s: pool name '%s' is too long "
1040 "(max is %d characters)\n",
1041 prog_name, pool_name, LOV_MAXPOOLNAME);
1043 } else if (rc > 0) {
1044 fprintf(stderr, "error: %s: char '%c' not allowed in "
1046 prog_name, rc, pool_name);
1052 struct lfs_setstripe_args {
1053 unsigned long long lsa_comp_end;
1054 unsigned long long lsa_stripe_size;
1055 int lsa_stripe_count;
1057 __u32 lsa_comp_flags;
1060 char *lsa_pool_name;
1063 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1065 memset(lsa, 0, sizeof(*lsa));
1066 lsa->lsa_stripe_off = -1;
1069 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1071 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1072 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1073 lsa->lsa_comp_end != 0);
1076 static int comp_args_to_layout(struct llapi_layout **composite,
1077 struct lfs_setstripe_args *lsa)
1079 struct llapi_layout *layout = *composite;
1080 uint64_t prev_end = 0;
1083 if (layout == NULL) {
1084 layout = llapi_layout_alloc();
1085 if (layout == NULL) {
1086 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1090 *composite = layout;
1094 /* Get current component extent, current component
1095 * must be the tail component. */
1096 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1098 fprintf(stderr, "Get comp extent failed. %s\n",
1103 rc = llapi_layout_comp_add(layout);
1105 fprintf(stderr, "Add component failed. %s\n",
1111 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1113 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1114 prev_end, lsa->lsa_comp_end, strerror(errno));
1118 if (lsa->lsa_stripe_size != 0) {
1119 rc = llapi_layout_stripe_size_set(layout,
1120 lsa->lsa_stripe_size);
1122 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1123 lsa->lsa_stripe_size, strerror(errno));
1128 if (lsa->lsa_stripe_count != 0) {
1129 rc = llapi_layout_stripe_count_set(layout,
1130 lsa->lsa_stripe_count == -1 ?
1132 lsa->lsa_stripe_count);
1134 fprintf(stderr, "Set stripe count %d failed. %s\n",
1135 lsa->lsa_stripe_count, strerror(errno));
1140 if (lsa->lsa_pool_name != NULL) {
1141 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1143 fprintf(stderr, "Set pool name: %s failed. %s\n",
1144 lsa->lsa_pool_name, strerror(errno));
1149 if (lsa->lsa_nr_osts > 0) {
1150 if (lsa->lsa_stripe_count > 0 &&
1151 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1152 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1153 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1156 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1157 rc = llapi_layout_ost_index_set(layout, i,
1162 } else if (lsa->lsa_stripe_off != -1) {
1163 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1166 fprintf(stderr, "Set ost index %d failed. %s\n",
1167 i, strerror(errno));
1174 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1175 * end of the last component in the existing file, and adjust the
1176 * first extent start of the components to be added accordingly. */
1177 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1179 struct llapi_layout *head;
1180 uint64_t start, end, stripe_size, prev_end = 0;
1186 head = llapi_layout_get_by_path(fname, 0);
1188 fprintf(stderr, "Read layout from %s failed. %s\n",
1189 fname, strerror(errno));
1193 /* Current component of 'head' should be tail of component list. */
1194 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1196 fprintf(stderr, "Get prev extent failed. %s\n",
1198 llapi_layout_free(head);
1202 llapi_layout_free(head);
1204 /* Make sure we use the first component of the layout to be added. */
1205 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1207 fprintf(stderr, "Move component cursor failed. %s\n",
1212 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1214 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1218 if (start > prev_end || end <= prev_end) {
1219 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1220 "adjacent with the existing file extent end: %lu\n",
1221 start, end, prev_end);
1225 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1227 fprintf(stderr, "Get stripe size failed. %s\n",
1232 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1233 (prev_end & (stripe_size - 1))) {
1234 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1235 stripe_size, prev_end);
1239 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1241 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1242 prev_end, end, strerror(errno));
1249 static inline bool comp_flags_is_neg(__u32 flags)
1251 return flags & LCME_FL_NEG;
1254 static inline void comp_flags_set_neg(__u32 *flags)
1256 *flags |= LCME_FL_NEG;
1259 static inline void comp_flags_clear_neg(__u32 *flags)
1261 *flags &= ~LCME_FL_NEG;
1264 static int comp_name2flags(__u32 *flags, char *name)
1267 __u32 neg_flags = 0;
1273 for (ptr = name; ; ptr = NULL) {
1274 char *flg = strtok(ptr, ",");
1277 if (strcmp(flg, "init") == 0)
1278 *flags |= LCME_FL_INIT;
1279 else if (strcmp(flg, "^init") == 0)
1280 neg_flags |= LCME_FL_INIT;
1285 if (*flags == 0 && neg_flags == 0)
1287 /* don't support mixed flags for now */
1288 if (*flags && neg_flags)
1293 comp_flags_set_neg(flags);
1311 static int lfs_setstripe(int argc, char **argv)
1313 struct lfs_setstripe_args lsa;
1314 struct llapi_stripe_param *param = NULL;
1315 struct find_param migrate_mdt_param = {
1325 char *mdt_idx_arg = NULL;
1326 unsigned long long size_units = 1;
1327 bool migrate_mode = false;
1328 bool migration_block = false;
1329 __u64 migration_flags = 0;
1330 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1331 int comp_del = 0, comp_set = 0;
1334 struct llapi_layout *layout = NULL;
1336 struct option long_opts[] = {
1337 /* --block is only valid in migrate mode */
1338 {"block", no_argument, 0, 'b'},
1339 {"comp-add", no_argument, 0, LFS_COMP_ADD_OPT},
1340 {"component-add", no_argument, 0, LFS_COMP_ADD_OPT},
1341 {"comp-del", no_argument, 0, LFS_COMP_DEL_OPT},
1342 {"component-del", no_argument, 0, LFS_COMP_DEL_OPT},
1343 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1344 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1345 {"comp-set", no_argument, 0, LFS_COMP_SET_OPT},
1346 {"component-set", no_argument, 0, LFS_COMP_SET_OPT},
1347 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1348 /* This formerly implied "stripe-count", but was explicitly
1349 * made "stripe-count" for consistency with other options,
1350 * and to separate it from "mdt-count" when DNE arrives. */
1351 {"count", required_argument, 0, 'c'},
1353 {"stripe-count", required_argument, 0, 'c'},
1354 {"stripe_count", required_argument, 0, 'c'},
1355 {"delete", no_argument, 0, 'd'},
1356 {"comp-end", required_argument, 0, 'E'},
1357 {"component-end", required_argument, 0, 'E'},
1358 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1359 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1360 /* This formerly implied "stripe-index", but was explicitly
1361 * made "stripe-index" for consistency with other options,
1362 * and to separate it from "mdt-index" when DNE arrives. */
1363 {"index", required_argument, 0, 'i'},
1365 {"stripe-index", required_argument, 0, 'i'},
1366 {"stripe_index", required_argument, 0, 'i'},
1367 {"comp-id", required_argument, 0, 'I'},
1368 {"component-id", required_argument, 0, 'I'},
1369 {"mdt", required_argument, 0, 'm'},
1370 {"mdt-index", required_argument, 0, 'm'},
1371 {"mdt_index", required_argument, 0, 'm'},
1372 /* --non-block is only valid in migrate mode */
1373 {"non-block", no_argument, 0, 'n'},
1374 {"ost", required_argument, 0, 'o'},
1375 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1376 {"ost-list", required_argument, 0, 'o'},
1377 {"ost_list", required_argument, 0, 'o'},
1379 {"pool", required_argument, 0, 'p'},
1380 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1381 /* This formerly implied "--stripe-size", but was confusing
1382 * with "lfs find --size|-s", which means "file size", so use
1383 * the consistent "--stripe-size|-S" for all commands. */
1384 {"size", required_argument, 0, 's'},
1386 {"stripe-size", required_argument, 0, 'S'},
1387 {"stripe_size", required_argument, 0, 'S'},
1388 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1389 /* --verbose is only valid in migrate mode */
1390 {"verbose", no_argument, 0, 'v'},
1394 setstripe_args_init(&lsa);
1396 if (strcmp(argv[0], "migrate") == 0)
1397 migrate_mode = true;
1399 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1400 long_opts, NULL)) >= 0) {
1405 case LFS_COMP_ADD_OPT:
1408 case LFS_COMP_DEL_OPT:
1411 case LFS_COMP_FLAGS_OPT:
1412 result = comp_name2flags(&lsa.lsa_comp_flags, optarg);
1414 fprintf(stderr, "error: %s: bad comp flags "
1415 "'%s'\n", argv[0], optarg);
1419 case LFS_COMP_SET_OPT:
1423 if (!migrate_mode) {
1424 fprintf(stderr, "--block is valid only for"
1428 migration_block = true;
1431 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1432 if (strcmp(argv[optind - 1], "--count") == 0)
1433 fprintf(stderr, "warning: '--count' deprecated"
1434 ", use '--stripe-count' instead\n");
1436 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1438 fprintf(stderr, "error: %s: bad stripe count "
1439 "'%s'\n", argv[0], optarg);
1444 /* delete the default striping pattern */
1448 if (lsa.lsa_comp_end != 0) {
1449 result = comp_args_to_layout(&layout, &lsa);
1453 setstripe_args_init(&lsa);
1456 if (!strncmp(optarg, "-1", strlen("-1")) ||
1457 !strncmp(optarg, "EOF", strlen("EOF")) ||
1458 !strncmp(optarg, "eof", strlen("eof"))) {
1459 lsa.lsa_comp_end = LUSTRE_EOF;
1461 result = llapi_parse_size(optarg,
1465 fprintf(stderr, "error: %s: "
1466 "bad component end '%s'\n",
1473 if (strcmp(argv[optind - 1], "--index") == 0)
1474 fprintf(stderr, "warning: '--index' deprecated"
1475 ", use '--stripe-index' instead\n");
1476 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1478 fprintf(stderr, "error: %s: bad stripe offset "
1479 "'%s'\n", argv[0], optarg);
1484 comp_id = strtoul(optarg, &end, 0);
1485 if (*end != '\0' || comp_id == 0) {
1486 fprintf(stderr, "error: %s: bad comp ID "
1487 "'%s'\n", argv[0], optarg);
1492 if (!migrate_mode) {
1493 fprintf(stderr, "--mdt-index is valid only for"
1497 mdt_idx_arg = optarg;
1500 if (!migrate_mode) {
1501 fprintf(stderr, "--non-block is valid only for"
1505 migration_flags |= MIGRATION_NONBLOCK;
1508 lsa.lsa_nr_osts = parse_targets(osts,
1509 sizeof(osts) / sizeof(__u32),
1510 lsa.lsa_nr_osts, optarg);
1511 if (lsa.lsa_nr_osts < 0) {
1513 "error: %s: bad OST indices '%s'\n",
1518 lsa.lsa_osts = osts;
1519 if (lsa.lsa_stripe_off == -1)
1520 lsa.lsa_stripe_off = osts[0];
1523 result = verify_pool_name(argv[0], optarg);
1526 lsa.lsa_pool_name = optarg;
1528 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1530 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1531 fprintf(stderr, "warning: '--size|-s' deprecated, "
1532 "use '--stripe-size|-S' instead\n");
1534 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1536 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1539 fprintf(stderr, "error: %s: bad stripe size "
1540 "'%s'\n", argv[0], optarg);
1545 if (!migrate_mode) {
1546 fprintf(stderr, "--verbose is valid only for"
1550 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1557 fname = argv[optind];
1559 if (lsa.lsa_comp_end != 0) {
1560 result = comp_args_to_layout(&layout, &lsa);
1565 if (optind == argc) {
1566 fprintf(stderr, "error: %s: missing filename|dirname\n",
1571 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1572 * altered by user space tool, so we don't need to support the
1573 * --component-set for this moment. */
1574 if (comp_set != 0) {
1575 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1580 if ((delete + comp_set + comp_del + comp_add) > 1) {
1581 fprintf(stderr, "error: %s: can't specify --component-set, "
1582 "--component-del, --component-add or -d together\n",
1587 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1588 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1589 fprintf(stderr, "error: %s: can't specify -d with "
1590 "-s, -c, -o, -p, -I, -F or -E options\n",
1595 if ((comp_set || comp_del) &&
1596 (setstripe_args_specified(&lsa) || layout != NULL)) {
1597 fprintf(stderr, "error: %s: can't specify --component-del or "
1598 "--component-set with -s, -c, -o, -p or -E options.\n",
1603 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1604 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1605 "--component-del option.\n", argv[0]);
1610 if (layout == NULL) {
1611 fprintf(stderr, "error: %s: -E option must be present"
1612 "in --component-add mode.\n", argv[0]);
1615 result = adjust_first_extent(fname, layout);
1620 if (mdt_idx_arg != NULL && optind > 3) {
1621 fprintf(stderr, "error: %s: cannot specify -m with other "
1622 "options\n", argv[0]);
1626 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1628 "error: %s: cannot specify --non-block and --block\n",
1633 /* support --component-id option for migrate later. */
1634 if (migrate_mode && comp_id != 0) {
1635 fprintf(stderr, "error: %s: -I isn't supported yet.\n",
1640 if (mdt_idx_arg != NULL) {
1641 /* initialize migrate mdt parameters */
1642 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1644 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1645 argv[0], mdt_idx_arg);
1648 migrate_mdt_param.fp_migrate = 1;
1649 } else if (layout == NULL) {
1650 /* initialize stripe parameters */
1651 param = calloc(1, offsetof(typeof(*param),
1652 lsp_osts[lsa.lsa_nr_osts]));
1653 if (param == NULL) {
1654 fprintf(stderr, "error: %s: %s\n", argv[0],
1659 param->lsp_stripe_size = lsa.lsa_stripe_size;
1660 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1661 param->lsp_stripe_count = lsa.lsa_stripe_count;
1662 param->lsp_stripe_pattern = 0;
1663 param->lsp_pool = lsa.lsa_pool_name;
1664 param->lsp_is_specific = false;
1665 if (lsa.lsa_nr_osts > 0) {
1666 if (lsa.lsa_stripe_count > 0 &&
1667 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1668 fprintf(stderr, "error: %s: stripe count '%d' "
1669 "doesn't match the number of OSTs: %d\n"
1670 , argv[0], lsa.lsa_stripe_count,
1676 param->lsp_is_specific = true;
1677 param->lsp_stripe_count = lsa.lsa_nr_osts;
1678 memcpy(param->lsp_osts, osts,
1679 sizeof(*osts) * lsa.lsa_nr_osts);
1683 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1685 if (mdt_idx_arg != NULL) {
1686 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1687 op = "migrate mdt objects of";
1688 } else if (migrate_mode) {
1689 result = lfs_migrate(fname, migration_flags, param,
1691 op = "migrate ost objects of";
1692 } else if (comp_set != 0) {
1693 result = lfs_component_set(fname, comp_id,
1694 lsa.lsa_comp_flags);
1695 op = "modify component flags of";
1696 } else if (comp_del != 0) {
1697 result = lfs_component_del(fname, comp_id,
1698 lsa.lsa_comp_flags);
1699 op = "delete component of";
1700 } else if (comp_add != 0) {
1701 result = lfs_component_add(fname, layout);
1702 op = "add component to";
1703 } else if (layout != NULL) {
1704 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1710 op = "create composite";
1712 result = llapi_file_open_param(fname,
1719 op = "create striped";
1722 /* Save the first error encountered. */
1725 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1727 lsa.lsa_pool_name != NULL && result == EINVAL ?
1728 "OST not in pool?" : strerror(errno));
1734 llapi_layout_free(layout);
1737 llapi_layout_free(layout);
1741 static int lfs_poollist(int argc, char **argv)
1746 return llapi_poollist(argv[1]);
1749 static int set_time(time_t *time, time_t *set, char *str)
1756 else if (str[0] == '-')
1762 t = strtol(str, NULL, 0);
1763 if (*time < t * 24 * 60 * 60) {
1766 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1770 *set = *time - t * 24 * 60 * 60;
1773 static int name2uid(unsigned int *id, const char *name)
1775 struct passwd *passwd;
1777 passwd = getpwnam(name);
1780 *id = passwd->pw_uid;
1785 static int name2gid(unsigned int *id, const char *name)
1787 struct group *group;
1789 group = getgrnam(name);
1792 *id = group->gr_gid;
1797 static inline int name2projid(unsigned int *id, const char *name)
1802 static int uid2name(char **name, unsigned int id)
1804 struct passwd *passwd;
1806 passwd = getpwuid(id);
1809 *name = passwd->pw_name;
1814 static inline int gid2name(char **name, unsigned int id)
1816 struct group *group;
1818 group = getgrgid(id);
1821 *name = group->gr_name;
1826 static int name2layout(__u32 *layout, char *name)
1831 for (ptr = name; ; ptr = NULL) {
1832 lyt = strtok(ptr, ",");
1835 if (strcmp(lyt, "released") == 0)
1836 *layout |= LOV_PATTERN_F_RELEASED;
1837 else if (strcmp(lyt, "raid0") == 0)
1838 *layout |= LOV_PATTERN_RAID0;
1845 static int lfs_find(int argc, char **argv)
1850 struct find_param param = {
1854 struct option long_opts[] = {
1855 {"atime", required_argument, 0, 'A'},
1856 {"comp-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1857 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1858 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1859 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1860 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
1861 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1862 {"stripe-count", required_argument, 0, 'c'},
1863 {"stripe_count", required_argument, 0, 'c'},
1864 {"ctime", required_argument, 0, 'C'},
1865 {"maxdepth", required_argument, 0, 'D'},
1866 {"comp-end", required_argument, 0, 'E'},
1867 {"component-end", required_argument, 0, 'E'},
1868 {"gid", required_argument, 0, 'g'},
1869 {"group", required_argument, 0, 'G'},
1870 {"mdt-hash", required_argument, 0, 'H'},
1871 {"stripe-index", required_argument, 0, 'i'},
1872 {"stripe_index", required_argument, 0, 'i'},
1873 /*{"component-id", required_argument, 0, 'I'},*/
1874 {"layout", required_argument, 0, 'L'},
1875 {"mdt", required_argument, 0, 'm'},
1876 {"mdt-index", required_argument, 0, 'm'},
1877 {"mdt_index", required_argument, 0, 'm'},
1878 {"mtime", required_argument, 0, 'M'},
1879 {"name", required_argument, 0, 'n'},
1880 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1881 {"obd", required_argument, 0, 'O'},
1882 {"ost", required_argument, 0, 'O'},
1883 /* no short option for pool, p/P already used */
1884 {"pool", required_argument, 0, LFS_POOL_OPT},
1885 {"print0", no_argument, 0, 'p'},
1886 {"print", no_argument, 0, 'P'},
1887 {"projid", required_argument, 0, LFS_PROJID_OPT},
1888 {"size", required_argument, 0, 's'},
1889 {"stripe-size", required_argument, 0, 'S'},
1890 {"stripe_size", required_argument, 0, 'S'},
1891 {"type", required_argument, 0, 't'},
1892 {"mdt-count", required_argument, 0, 'T'},
1893 {"uid", required_argument, 0, 'u'},
1894 {"user", required_argument, 0, 'U'},
1907 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1908 while ((c = getopt_long_only(argc, argv,
1909 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1910 long_opts, NULL)) >= 0) {
1915 /* '!' is part of option */
1916 /* when getopt_long_only() finds a string which is not
1917 * an option nor a known option argument it returns 1
1918 * in that case if we already have found pathstart and pathend
1919 * (i.e. we have the list of pathnames),
1920 * the only supported value is "!"
1922 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1923 if (!isoption && pathend != -1) {
1924 fprintf(stderr, "err: %s: filename|dirname must either "
1925 "precede options or follow options\n",
1930 if (!isoption && pathstart == -1)
1931 pathstart = optind - 1;
1932 if (isoption && pathstart != -1 && pathend == -1)
1933 pathend = optind - 2;
1939 /* unknown; opt is "!" or path component,
1940 * checking done above.
1942 if (strcmp(optarg, "!") == 0)
1946 xtime = ¶m.fp_atime;
1947 xsign = ¶m.fp_asign;
1948 param.fp_exclude_atime = !!neg_opt;
1949 /* no break, this falls through to 'C' for ctime */
1952 xtime = ¶m.fp_ctime;
1953 xsign = ¶m.fp_csign;
1954 param.fp_exclude_ctime = !!neg_opt;
1956 /* no break, this falls through to 'M' for mtime */
1959 xtime = ¶m.fp_mtime;
1960 xsign = ¶m.fp_msign;
1961 param.fp_exclude_mtime = !!neg_opt;
1963 rc = set_time(&t, xtime, optarg);
1964 if (rc == INT_MAX) {
1971 case LFS_COMP_COUNT_OPT:
1972 if (optarg[0] == '+') {
1973 param.fp_comp_count_sign = -1;
1975 } else if (optarg[0] == '-') {
1976 param.fp_comp_count_sign = 1;
1980 param.fp_comp_count = strtoul(optarg, &endptr, 0);
1981 if (*endptr != '\0') {
1982 fprintf(stderr, "error: bad component count "
1986 param.fp_check_comp_count = 1;
1987 param.fp_exclude_comp_count = !!neg_opt;
1989 case LFS_COMP_FLAGS_OPT:
1990 rc = comp_name2flags(¶m.fp_comp_flags, optarg);
1992 fprintf(stderr, "error: bad component flags "
1996 param.fp_check_comp_flags = 1;
1997 param.fp_exclude_comp_flags = !!neg_opt;
1999 case LFS_COMP_START_OPT:
2000 if (optarg[0] == '+') {
2001 param.fp_comp_start_sign = -1;
2003 } else if (optarg[0] == '-') {
2004 param.fp_comp_start_sign = 1;
2008 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2009 ¶m.fp_comp_start_units, 0);
2011 fprintf(stderr, "error: bad component start "
2015 param.fp_check_comp_start = 1;
2016 param.fp_exclude_comp_start = !!neg_opt;
2019 if (optarg[0] == '+') {
2020 param.fp_stripe_count_sign = -1;
2022 } else if (optarg[0] == '-') {
2023 param.fp_stripe_count_sign = 1;
2027 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2028 if (*endptr != '\0') {
2029 fprintf(stderr,"error: bad stripe_count '%s'\n",
2034 param.fp_check_stripe_count = 1;
2035 param.fp_exclude_stripe_count = !!neg_opt;
2038 param.fp_max_depth = strtol(optarg, 0, 0);
2041 if (optarg[0] == '+') {
2042 param.fp_comp_end_sign = -1;
2044 } else if (optarg[0] == '-') {
2045 param.fp_comp_end_sign = 1;
2049 rc = llapi_parse_size(optarg, ¶m.fp_comp_end,
2050 ¶m.fp_comp_end_units, 0);
2052 fprintf(stderr, "error: bad component end "
2056 param.fp_check_comp_end = 1;
2057 param.fp_exclude_comp_end = !!neg_opt;
2061 rc = name2gid(¶m.fp_gid, optarg);
2063 param.fp_gid = strtoul(optarg, &endptr, 10);
2064 if (*endptr != '\0') {
2065 fprintf(stderr, "Group/GID: %s cannot "
2066 "be found.\n", optarg);
2071 param.fp_exclude_gid = !!neg_opt;
2072 param.fp_check_gid = 1;
2075 param.fp_hash_type = check_hashtype(optarg);
2076 if (param.fp_hash_type == 0) {
2077 fprintf(stderr, "error: bad hash_type '%s'\n",
2082 param.fp_check_hash_type = 1;
2083 param.fp_exclude_hash_type = !!neg_opt;
2086 ret = name2layout(¶m.fp_layout, optarg);
2089 param.fp_exclude_layout = !!neg_opt;
2090 param.fp_check_layout = 1;
2094 rc = name2uid(¶m.fp_uid, optarg);
2096 param.fp_uid = strtoul(optarg, &endptr, 10);
2097 if (*endptr != '\0') {
2098 fprintf(stderr, "User/UID: %s cannot "
2099 "be found.\n", optarg);
2104 param.fp_exclude_uid = !!neg_opt;
2105 param.fp_check_uid = 1;
2108 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2110 "Pool name %s is too long"
2111 " (max is %d)\n", optarg,
2116 /* we do check for empty pool because empty pool
2117 * is used to find V1 lov attributes */
2118 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2119 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2120 param.fp_exclude_pool = !!neg_opt;
2121 param.fp_check_pool = 1;
2124 param.fp_pattern = (char *)optarg;
2125 param.fp_exclude_pattern = !!neg_opt;
2130 char *buf, *token, *next, *p;
2134 buf = strdup(optarg);
2140 param.fp_exclude_obd = !!neg_opt;
2143 while (token && *token) {
2144 token = strchr(token, ',');
2151 param.fp_exclude_mdt = !!neg_opt;
2152 param.fp_num_alloc_mdts += len;
2153 tmp = realloc(param.fp_mdt_uuid,
2154 param.fp_num_alloc_mdts *
2155 sizeof(*param.fp_mdt_uuid));
2161 param.fp_mdt_uuid = tmp;
2163 param.fp_exclude_obd = !!neg_opt;
2164 param.fp_num_alloc_obds += len;
2165 tmp = realloc(param.fp_obd_uuid,
2166 param.fp_num_alloc_obds *
2167 sizeof(*param.fp_obd_uuid));
2173 param.fp_obd_uuid = tmp;
2175 for (token = buf; token && *token; token = next) {
2176 struct obd_uuid *puuid;
2179 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2182 ¶m.fp_obd_uuid[param.fp_num_obds++];
2184 p = strchr(token, ',');
2191 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2196 strncpy(puuid->uuid, token,
2197 sizeof(puuid->uuid));
2205 param.fp_zero_end = 1;
2209 case LFS_PROJID_OPT:
2210 rc = name2projid(¶m.fp_projid, optarg);
2212 param.fp_projid = strtoul(optarg, &endptr, 10);
2213 if (*endptr != '\0') {
2215 "Invalid project ID: %s",
2221 param.fp_exclude_projid = !!neg_opt;
2222 param.fp_check_projid = 1;
2225 if (optarg[0] == '+') {
2226 param.fp_size_sign = -1;
2228 } else if (optarg[0] == '-') {
2229 param.fp_size_sign = 1;
2233 ret = llapi_parse_size(optarg, ¶m.fp_size,
2234 ¶m.fp_size_units, 0);
2236 fprintf(stderr, "error: bad file size '%s'\n",
2240 param.fp_check_size = 1;
2241 param.fp_exclude_size = !!neg_opt;
2244 if (optarg[0] == '+') {
2245 param.fp_stripe_size_sign = -1;
2247 } else if (optarg[0] == '-') {
2248 param.fp_stripe_size_sign = 1;
2252 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2253 ¶m.fp_stripe_size_units, 0);
2255 fprintf(stderr, "error: bad stripe_size '%s'\n",
2259 param.fp_check_stripe_size = 1;
2260 param.fp_exclude_stripe_size = !!neg_opt;
2263 param.fp_exclude_type = !!neg_opt;
2264 switch (optarg[0]) {
2266 param.fp_type = S_IFBLK;
2269 param.fp_type = S_IFCHR;
2272 param.fp_type = S_IFDIR;
2275 param.fp_type = S_IFREG;
2278 param.fp_type = S_IFLNK;
2281 param.fp_type = S_IFIFO;
2284 param.fp_type = S_IFSOCK;
2287 fprintf(stderr, "error: %s: bad type '%s'\n",
2294 if (optarg[0] == '+') {
2295 param.fp_mdt_count_sign = -1;
2297 } else if (optarg[0] == '-') {
2298 param.fp_mdt_count_sign = 1;
2302 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2303 if (*endptr != '\0') {
2304 fprintf(stderr, "error: bad mdt_count '%s'\n",
2309 param.fp_check_mdt_count = 1;
2310 param.fp_exclude_mdt_count = !!neg_opt;
2318 if (pathstart == -1) {
2319 fprintf(stderr, "error: %s: no filename|pathname\n",
2323 } else if (pathend == -1) {
2329 rc = llapi_find(argv[pathstart], ¶m);
2330 if (rc != 0 && ret == 0)
2332 } while (++pathstart < pathend);
2335 fprintf(stderr, "error: %s failed for %s.\n",
2336 argv[0], argv[optind - 1]);
2338 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2339 free(param.fp_obd_uuid);
2341 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2342 free(param.fp_mdt_uuid);
2347 static int lfs_getstripe_internal(int argc, char **argv,
2348 struct find_param *param)
2350 struct option long_opts[] = {
2351 {"comp-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2352 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2353 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2354 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2355 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
2356 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
2357 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2358 /* This formerly implied "stripe-count", but was explicitly
2359 * made "stripe-count" for consistency with other options,
2360 * and to separate it from "mdt-count" when DNE arrives. */
2361 {"count", no_argument, 0, 'c'},
2363 {"stripe-count", no_argument, 0, 'c'},
2364 {"stripe_count", no_argument, 0, 'c'},
2365 {"directory", no_argument, 0, 'd'},
2366 {"default", no_argument, 0, 'D'},
2367 {"comp-end", required_argument, 0, 'E'},
2368 {"component-end", required_argument, 0, 'E'},
2369 {"fid", no_argument, 0, 'F'},
2370 {"generation", no_argument, 0, 'g'},
2371 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
2372 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2373 /* This formerly implied "stripe-index", but was explicitly
2374 * made "stripe-index" for consistency with other options,
2375 * and to separate it from "mdt-index" when DNE arrives. */
2376 {"index", no_argument, 0, 'i'},
2378 {"stripe-index", no_argument, 0, 'i'},
2379 {"stripe_index", no_argument, 0, 'i'},
2380 {"comp-id", required_argument, 0, 'I'},
2381 {"component-id", required_argument, 0, 'I'},
2382 {"layout", no_argument, 0, 'L'},
2383 {"mdt", no_argument, 0, 'm'},
2384 {"mdt-index", no_argument, 0, 'm'},
2385 {"mdt_index", no_argument, 0, 'm'},
2386 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2387 {"mdt-index", no_argument, 0, 'M'},
2388 {"mdt_index", no_argument, 0, 'M'},
2390 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2391 /* This formerly implied "stripe-index", but was confusing
2392 * with "file offset" (which will eventually be needed for
2393 * with different layouts by offset), so deprecate it. */
2394 {"offset", no_argument, 0, 'o'},
2396 {"obd", required_argument, 0, 'O'},
2397 {"ost", required_argument, 0, 'O'},
2398 {"pool", no_argument, 0, 'p'},
2399 {"quiet", no_argument, 0, 'q'},
2400 {"recursive", no_argument, 0, 'r'},
2401 {"raw", no_argument, 0, 'R'},
2402 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2403 /* This formerly implied "--stripe-size", but was confusing
2404 * with "lfs find --size|-s", which means "file size", so use
2405 * the consistent "--stripe-size|-S" for all commands. */
2406 {"size", no_argument, 0, 's'},
2408 {"stripe-size", no_argument, 0, 'S'},
2409 {"stripe_size", no_argument, 0, 'S'},
2410 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
2411 {"verbose", no_argument, 0, 'v'},
2412 {"yaml", no_argument, 0, 'y'},
2418 while ((c = getopt_long(argc, argv, "cdDE:FghiI:LmMoO:pqrRsSvy",
2419 long_opts, NULL)) != -1) {
2422 if (strcmp(argv[optind - 1], "--count") == 0)
2423 fprintf(stderr, "warning: '--count' deprecated,"
2424 " use '--stripe-count' instead\n");
2425 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2426 param->fp_verbose |= VERBOSE_COUNT;
2427 param->fp_max_depth = 0;
2430 case LFS_COMP_COUNT_OPT:
2431 param->fp_verbose |= VERBOSE_COMP_COUNT;
2432 param->fp_max_depth = 0;
2434 case LFS_COMP_FLAGS_OPT:
2435 if (optarg != NULL) {
2436 rc = comp_name2flags(¶m->fp_comp_flags,
2439 param->fp_verbose |=
2441 param->fp_max_depth = 0;
2444 param->fp_check_comp_flags = 1;
2447 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2448 param->fp_max_depth = 0;
2451 case LFS_COMP_START_OPT:
2452 if (optarg != NULL) {
2454 if (tmp[0] == '+') {
2455 param->fp_comp_start_sign = 1;
2457 } else if (tmp[0] == '-') {
2458 param->fp_comp_start_sign = -1;
2461 rc = llapi_parse_size(tmp,
2462 ¶m->fp_comp_start,
2463 ¶m->fp_comp_start_units, 0);
2465 param->fp_verbose |= VERBOSE_COMP_START;
2466 param->fp_max_depth = 0;
2469 param->fp_check_comp_start = 1;
2472 param->fp_verbose |= VERBOSE_COMP_START;
2473 param->fp_max_depth = 0;
2477 param->fp_max_depth = 0;
2480 param->fp_get_default_lmv = 1;
2483 if (optarg != NULL) {
2485 if (tmp[0] == '+') {
2486 param->fp_comp_end_sign = 1;
2488 } else if (tmp[0] == '-') {
2489 param->fp_comp_end_sign = -1;
2492 rc = llapi_parse_size(tmp,
2493 ¶m->fp_comp_end,
2494 ¶m->fp_comp_end_units, 0);
2496 param->fp_verbose |= VERBOSE_COMP_END;
2497 param->fp_max_depth = 0;
2500 param->fp_check_comp_end = 1;
2503 param->fp_verbose |= VERBOSE_COMP_END;
2504 param->fp_max_depth = 0;
2508 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2509 param->fp_verbose |= VERBOSE_DFID;
2510 param->fp_max_depth = 0;
2514 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2515 param->fp_verbose |= VERBOSE_GENERATION;
2516 param->fp_max_depth = 0;
2519 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2521 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2522 "use '--stripe-index|-i' instead\n");
2525 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2526 if (strcmp(argv[optind - 1], "--index") == 0)
2527 fprintf(stderr, "warning: '--index' deprecated"
2528 ", use '--stripe-index' instead\n");
2530 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2531 param->fp_verbose |= VERBOSE_OFFSET;
2532 param->fp_max_depth = 0;
2536 if (optarg != NULL) {
2537 param->fp_comp_id = strtoul(optarg, &end, 0);
2539 param->fp_verbose |= VERBOSE_COMP_ID;
2540 param->fp_max_depth = 0;
2543 param->fp_check_comp_id = 1;
2546 param->fp_max_depth = 0;
2547 param->fp_verbose |= VERBOSE_COMP_ID;
2551 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2552 param->fp_verbose |= VERBOSE_LAYOUT;
2553 param->fp_max_depth = 0;
2556 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2558 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2559 fprintf(stderr, "warning: '-M' deprecated"
2560 ", use '-m' instead\n");
2564 if (!(param->fp_verbose & VERBOSE_DETAIL))
2565 param->fp_max_depth = 0;
2566 param->fp_verbose |= VERBOSE_MDTINDEX;
2569 if (param->fp_obd_uuid) {
2571 "error: %s: only one obduuid allowed",
2575 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2578 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2579 param->fp_verbose |= VERBOSE_POOL;
2580 param->fp_max_depth = 0;
2587 param->fp_recursive = 1;
2592 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2594 fprintf(stderr, "warning: '--size|-s' deprecated, "
2595 "use '--stripe-size|-S' instead\n");
2596 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2598 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2599 param->fp_verbose |= VERBOSE_SIZE;
2600 param->fp_max_depth = 0;
2604 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2617 if (param->fp_recursive)
2618 param->fp_max_depth = -1;
2619 else if (param->fp_verbose & VERBOSE_DETAIL)
2620 param->fp_max_depth = 1;
2622 if (!param->fp_verbose)
2623 param->fp_verbose = VERBOSE_DEFAULT;
2624 if (param->fp_quiet)
2625 param->fp_verbose = VERBOSE_OBJID;
2628 rc = llapi_getstripe(argv[optind], param);
2629 } while (++optind < argc && !rc);
2632 fprintf(stderr, "error: %s failed for %s.\n",
2633 argv[0], argv[optind - 1]);
2637 static int lfs_tgts(int argc, char **argv)
2639 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2640 struct find_param param;
2641 int index = 0, rc=0;
2646 if (argc == 2 && !realpath(argv[1], path)) {
2648 fprintf(stderr, "error: invalid path '%s': %s\n",
2649 argv[1], strerror(-rc));
2653 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2654 /* Check if we have a mount point */
2655 if (mntdir[0] == '\0')
2658 memset(¶m, 0, sizeof(param));
2659 if (!strcmp(argv[0], "mdts"))
2660 param.fp_get_lmv = 1;
2662 rc = llapi_ostlist(mntdir, ¶m);
2664 fprintf(stderr, "error: %s: failed on %s\n",
2667 if (path[0] != '\0')
2669 memset(mntdir, 0, PATH_MAX);
2675 static int lfs_getstripe(int argc, char **argv)
2677 struct find_param param = { 0 };
2679 param.fp_max_depth = 1;
2680 return lfs_getstripe_internal(argc, argv, ¶m);
2684 static int lfs_getdirstripe(int argc, char **argv)
2686 struct find_param param = { 0 };
2687 struct option long_opts[] = {
2688 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2689 {"mdt-count", no_argument, 0, 'c'},
2691 {"mdt-hash", no_argument, 0, 'H'},
2692 {"mdt-index", no_argument, 0, 'i'},
2693 {"recursive", no_argument, 0, 'r'},
2694 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2695 {"mdt-hash", no_argument, 0, 't'},
2697 {"default", no_argument, 0, 'D'},
2698 {"obd", required_argument, 0, 'O'},
2699 {"mdt-count", no_argument, 0, 'T'},
2700 {"yaml", no_argument, 0, 'y'},
2705 param.fp_get_lmv = 1;
2707 while ((c = getopt_long(argc, argv,
2708 "cDHiO:rtTy", long_opts, NULL)) != -1)
2712 if (param.fp_obd_uuid) {
2714 "error: %s: only one obduuid allowed",
2718 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2720 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2722 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2723 fprintf(stderr, "warning: '-c' deprecated"
2724 ", use '-T' instead\n");
2728 param.fp_verbose |= VERBOSE_COUNT;
2731 param.fp_verbose |= VERBOSE_OFFSET;
2733 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2737 param.fp_verbose |= VERBOSE_HASH_TYPE;
2740 param.fp_get_default_lmv = 1;
2743 param.fp_recursive = 1;
2756 if (param.fp_recursive)
2757 param.fp_max_depth = -1;
2759 if (!param.fp_verbose)
2760 param.fp_verbose = VERBOSE_DEFAULT;
2763 rc = llapi_getstripe(argv[optind], ¶m);
2764 } while (++optind < argc && !rc);
2767 fprintf(stderr, "error: %s failed for %s.\n",
2768 argv[0], argv[optind - 1]);
2773 static int lfs_setdirstripe(int argc, char **argv)
2777 unsigned int stripe_offset = -1;
2778 unsigned int stripe_count = 1;
2779 enum lmv_hash_type hash_type;
2782 char *stripe_offset_opt = NULL;
2783 char *stripe_count_opt = NULL;
2784 char *stripe_hash_opt = NULL;
2785 char *mode_opt = NULL;
2786 bool default_stripe = false;
2787 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2788 mode_t previous_mode = 0;
2789 bool delete = false;
2791 struct option long_opts[] = {
2792 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2793 {"count", required_argument, 0, 'c'},
2795 {"mdt-count", required_argument, 0, 'c'},
2796 {"delete", no_argument, 0, 'd'},
2797 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2798 {"index", required_argument, 0, 'i'},
2800 {"mdt-index", required_argument, 0, 'i'},
2801 {"mode", required_argument, 0, 'm'},
2802 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2803 {"hash-type", required_argument, 0, 't'},
2804 {"mdt-hash", required_argument, 0, 't'},
2806 {"mdt-hash", required_argument, 0, 'H'},
2807 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2808 {"default_stripe", no_argument, 0, 'D'},
2810 {"default", no_argument, 0, 'D'},
2814 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2821 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2822 if (strcmp(argv[optind - 1], "--count") == 0)
2823 fprintf(stderr, "warning: '--count' deprecated"
2824 ", use '--mdt-count' instead\n");
2826 stripe_count_opt = optarg;
2830 default_stripe = true;
2833 default_stripe = true;
2836 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2837 if (strcmp(argv[optind - 1], "--index") == 0)
2838 fprintf(stderr, "warning: '--index' deprecated"
2839 ", use '--mdt-index' instead\n");
2841 stripe_offset_opt = optarg;
2846 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2850 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2851 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2852 fprintf(stderr, "warning: '--hash-type' "
2853 "deprecated, use '--mdt-hash' "
2856 stripe_hash_opt = optarg;
2859 fprintf(stderr, "error: %s: option '%s' "
2861 argv[0], argv[optind - 1]);
2866 if (optind == argc) {
2867 fprintf(stderr, "error: %s: missing dirname\n",
2872 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2873 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2878 if (stripe_offset_opt != NULL) {
2879 /* get the stripe offset */
2880 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2882 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2883 argv[0], stripe_offset_opt);
2889 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2890 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2891 " or -i options.\n", argv[0]);
2899 if (mode_opt != NULL) {
2900 mode = strtoul(mode_opt, &end, 8);
2902 fprintf(stderr, "error: %s: bad mode '%s'\n",
2906 previous_mode = umask(0);
2909 if (stripe_hash_opt == NULL) {
2910 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2912 hash_type = check_hashtype(stripe_hash_opt);
2913 if (hash_type == 0) {
2915 "error: %s: bad stripe hash type '%s'\n",
2916 argv[0], stripe_hash_opt);
2921 /* get the stripe count */
2922 if (stripe_count_opt != NULL) {
2923 stripe_count = strtoul(stripe_count_opt, &end, 0);
2925 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2926 argv[0], stripe_count_opt);
2931 dname = argv[optind];
2933 if (default_stripe) {
2934 result = llapi_dir_set_default_lmv_stripe(dname,
2935 stripe_offset, stripe_count,
2938 result = llapi_dir_create_pool(dname, mode,
2940 stripe_count, hash_type,
2945 fprintf(stderr, "error: %s: create stripe dir '%s' "
2946 "failed\n", argv[0], dname);
2949 dname = argv[++optind];
2950 } while (dname != NULL);
2952 if (mode_opt != NULL)
2953 umask(previous_mode);
2959 static int lfs_rmentry(int argc, char **argv)
2966 fprintf(stderr, "error: %s: missing dirname\n",
2972 dname = argv[index];
2973 while (dname != NULL) {
2974 result = llapi_direntry_remove(dname);
2976 fprintf(stderr, "error: %s: remove dir entry '%s' "
2977 "failed\n", argv[0], dname);
2980 dname = argv[++index];
2985 static int lfs_mv(int argc, char **argv)
2987 struct find_param param = {
2994 struct option long_opts[] = {
2995 {"mdt-index", required_argument, 0, 'M'},
2996 {"verbose", no_argument, 0, 'v'},
3000 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3003 param.fp_mdt_index = strtoul(optarg, &end, 0);
3005 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3012 param.fp_verbose = VERBOSE_DETAIL;
3016 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3017 argv[0], argv[optind - 1]);
3022 if (param.fp_mdt_index == -1) {
3023 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3027 if (optind >= argc) {
3028 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3032 param.fp_migrate = 1;
3033 rc = llapi_migrate_mdt(argv[optind], ¶m);
3035 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3036 argv[0], argv[optind], param.fp_mdt_index,
3041 static int lfs_osts(int argc, char **argv)
3043 return lfs_tgts(argc, argv);
3046 static int lfs_mdts(int argc, char **argv)
3048 return lfs_tgts(argc, argv);
3051 #define COOK(value) \
3054 while (value > 1024) { \
3062 #define CDF "%11llu"
3063 #define HDF "%8.1f%c"
3068 MNTDF_INODES = 0x0001,
3069 MNTDF_COOKED = 0x0002,
3070 MNTDF_LAZY = 0x0004,
3071 MNTDF_VERBOSE = 0x0008,
3074 static int showdf(char *mntdir, struct obd_statfs *stat,
3075 char *uuid, enum mntdf_flags flags,
3076 char *type, int index, int rc)
3078 long long avail, used, total;
3080 char *suffix = "KMGTPEZY";
3081 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3082 char tbuf[3 * sizeof(__u64)];
3083 char ubuf[3 * sizeof(__u64)];
3084 char abuf[3 * sizeof(__u64)];
3085 char rbuf[3 * sizeof(__u64)];
3092 if (flags & MNTDF_INODES) {
3093 avail = stat->os_ffree;
3094 used = stat->os_files - stat->os_ffree;
3095 total = stat->os_files;
3097 int shift = flags & MNTDF_COOKED ? 0 : 10;
3099 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3100 used = ((stat->os_blocks - stat->os_bfree) *
3101 stat->os_bsize) >> shift;
3102 total = (stat->os_blocks * stat->os_bsize) >> shift;
3105 if ((used + avail) > 0)
3106 ratio = (double)used / (double)(used + avail);
3108 if (flags & MNTDF_COOKED) {
3112 cook_val = (double)total;
3115 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3118 snprintf(tbuf, sizeof(tbuf), CDF, total);
3120 cook_val = (double)used;
3123 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3126 snprintf(ubuf, sizeof(ubuf), CDF, used);
3128 cook_val = (double)avail;
3131 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3134 snprintf(abuf, sizeof(abuf), CDF, avail);
3136 snprintf(tbuf, sizeof(tbuf), CDF, total);
3137 snprintf(ubuf, sizeof(tbuf), CDF, used);
3138 snprintf(abuf, sizeof(tbuf), CDF, avail);
3141 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3142 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3143 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3145 printf("[%s:%d]", type, index);
3147 if (stat->os_state) {
3149 * Each character represents the matching
3152 const char state_names[] = "DRSI";
3157 for (i = 0, state = stat->os_state;
3158 state && i < sizeof(state_names); i++) {
3159 if (!(state & (1 << i)))
3161 printf("%c", state_names[i]);
3169 printf(UUF": inactive device\n", uuid);
3172 printf(UUF": %s\n", uuid, strerror(-rc));
3179 struct ll_stat_type {
3184 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3186 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3187 struct obd_uuid uuid_buf;
3188 char *poolname = NULL;
3189 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3190 { LL_STATFS_LOV, "OST" },
3192 struct ll_stat_type *tp;
3193 __u64 ost_ffree = 0;
3201 poolname = strchr(pool, '.');
3202 if (poolname != NULL) {
3203 if (strncmp(fsname, pool, strlen(fsname))) {
3204 fprintf(stderr, "filesystem name incorrect\n");
3212 fd = open(mntdir, O_RDONLY);
3215 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3220 if (flags & MNTDF_INODES)
3221 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3222 "UUID", "Inodes", "IUsed", "IFree",
3223 "IUse%", "Mounted on");
3225 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3226 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3227 "Used", "Available", "Use%", "Mounted on");
3229 for (tp = types; tp->st_name != NULL; tp++) {
3230 for (index = 0; ; index++) {
3231 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3232 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3233 type = flags & MNTDF_LAZY ?
3234 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3235 rc2 = llapi_obd_fstatfs(fd, type, index,
3236 &stat_buf, &uuid_buf);
3241 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3242 if (!(flags & MNTDF_VERBOSE))
3244 } else if (rc2 < 0 && rc == 0) {
3248 if (poolname && tp->st_op == LL_STATFS_LOV &&
3249 llapi_search_ost(fsname, poolname,
3250 obd_uuid2str(&uuid_buf)) != 1)
3253 /* the llapi_obd_statfs() call may have returned with
3254 * an error, but if it filled in uuid_buf we will at
3255 * lease use that to print out a message for that OBD.
3256 * If we didn't get anything in the uuid_buf, then fill
3257 * it in so that we can print an error message. */
3258 if (uuid_buf.uuid[0] == '\0')
3259 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3260 "%s%04x", tp->st_name, index);
3261 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3262 flags, tp->st_name, index, rc2);
3265 if (tp->st_op == LL_STATFS_LMV) {
3266 sum.os_ffree += stat_buf.os_ffree;
3267 sum.os_files += stat_buf.os_files;
3268 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3269 sum.os_blocks += stat_buf.os_blocks *
3271 sum.os_bfree += stat_buf.os_bfree *
3273 sum.os_bavail += stat_buf.os_bavail *
3275 ost_ffree += stat_buf.os_ffree;
3283 /* If we don't have as many objects free on the OST as inodes
3284 * on the MDS, we reduce the total number of inodes to
3285 * compensate, so that the "inodes in use" number is correct.
3286 * Matches ll_statfs_internal() so the results are consistent. */
3287 if (ost_ffree < sum.os_ffree) {
3288 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3289 sum.os_ffree = ost_ffree;
3292 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3298 static int lfs_df(int argc, char **argv)
3300 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3301 enum mntdf_flags flags = 0;
3302 int c, rc = 0, index = 0;
3303 char fsname[PATH_MAX] = "", *pool_name = NULL;
3304 struct option long_opts[] = {
3305 {"human-readable", 0, 0, 'h'},
3306 {"inodes", 0, 0, 'i'},
3307 {"lazy", 0, 0, 'l'},
3308 {"pool", required_argument, 0, 'p'},
3309 {"verbose", 0, 0, 'v'},
3313 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3316 flags |= MNTDF_COOKED;
3319 flags |= MNTDF_INODES;
3322 flags |= MNTDF_LAZY;
3328 flags |= MNTDF_VERBOSE;
3334 if (optind < argc && !realpath(argv[optind], path)) {
3336 fprintf(stderr, "error: invalid path '%s': %s\n",
3337 argv[optind], strerror(-rc));
3341 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3342 /* Check if we have a mount point */
3343 if (mntdir[0] == '\0')
3346 rc = mntdf(mntdir, fsname, pool_name, flags);
3347 if (rc || path[0] != '\0')
3349 fsname[0] = '\0'; /* avoid matching in next loop */
3350 mntdir[0] = '\0'; /* avoid matching in next loop */
3356 static int lfs_getname(int argc, char **argv)
3358 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3359 int rc = 0, index = 0, c;
3360 char buf[sizeof(struct obd_uuid)];
3362 while ((c = getopt(argc, argv, "h")) != -1)
3365 if (optind == argc) { /* no paths specified, get all paths. */
3366 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3367 rc = llapi_getname(mntdir, buf, sizeof(buf));
3370 "cannot get name for `%s': %s\n",
3371 mntdir, strerror(-rc));
3375 printf("%s %s\n", buf, mntdir);
3377 path[0] = fsname[0] = mntdir[0] = 0;
3379 } else { /* paths specified, only attempt to search these. */
3380 for (; optind < argc; optind++) {
3381 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3384 "cannot get name for `%s': %s\n",
3385 argv[optind], strerror(-rc));
3389 printf("%s %s\n", buf, argv[optind]);
3395 static int lfs_check(int argc, char **argv)
3398 char mntdir[PATH_MAX] = {'\0'};
3407 obd_types[0] = obd_type1;
3408 obd_types[1] = obd_type2;
3410 if (strcmp(argv[1], "osts") == 0) {
3411 strcpy(obd_types[0], "osc");
3412 } else if (strcmp(argv[1], "mds") == 0) {
3413 strcpy(obd_types[0], "mdc");
3414 } else if (strcmp(argv[1], "servers") == 0) {
3416 strcpy(obd_types[0], "osc");
3417 strcpy(obd_types[1], "mdc");
3419 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3424 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3425 if (rc < 0 || mntdir[0] == '\0') {
3426 fprintf(stderr, "No suitable Lustre mount found\n");
3430 rc = llapi_target_check(num_types, obd_types, mntdir);
3432 fprintf(stderr, "error: %s: %s status failed\n",
3439 #ifdef HAVE_SYS_QUOTA_H
3440 #define ARG2INT(nr, str, msg) \
3443 nr = strtol(str, &endp, 0); \
3445 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3450 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3452 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3453 * returns the value or ULONG_MAX on integer overflow or incorrect format
3455 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3456 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3457 * 3. empty integer value is interpreted as 0
3459 static unsigned long str2sec(const char* timestr)
3461 const char spec[] = "smhdw";
3462 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3463 unsigned long val = 0;
3466 if (strpbrk(timestr, spec) == NULL) {
3467 /* no specifiers inside the time string,
3468 should treat it as an integer value */
3469 val = strtoul(timestr, &tail, 10);
3470 return *tail ? ULONG_MAX : val;
3473 /* format string is XXwXXdXXhXXmXXs */
3479 v = strtoul(timestr, &tail, 10);
3480 if (v == ULONG_MAX || *tail == '\0')
3481 /* value too large (ULONG_MAX or more)
3482 or missing specifier */
3485 ptr = strchr(spec, *tail);
3487 /* unknown specifier */
3492 /* check if product will overflow the type */
3493 if (!(v < ULONG_MAX / mult[ind]))
3496 ADD_OVERFLOW(val, mult[ind] * v);
3497 if (val == ULONG_MAX)
3509 #define ARG2ULL(nr, str, def_units) \
3511 unsigned long long limit, units = def_units; \
3514 rc = llapi_parse_size(str, &limit, &units, 1); \
3516 fprintf(stderr, "error: bad limit value %s\n", str); \
3522 static inline int has_times_option(int argc, char **argv)
3526 for (i = 1; i < argc; i++)
3527 if (!strcmp(argv[i], "-t"))
3533 int lfs_setquota_times(int argc, char **argv)
3536 struct if_quotactl qctl;
3537 char *mnt, *obd_type = (char *)qctl.obd_type;
3538 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3539 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3540 struct option long_opts[] = {
3541 {"block-grace", required_argument, 0, 'b'},
3542 {"group", no_argument, 0, 'g'},
3543 {"inode-grace", required_argument, 0, 'i'},
3544 {"projid", no_argument, 0, 'p'},
3545 {"times", no_argument, 0, 't'},
3546 {"user", no_argument, 0, 'u'},
3551 memset(&qctl, 0, sizeof(qctl));
3552 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3553 qctl.qc_type = ALLQUOTA;
3555 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3556 long_opts, NULL)) != -1) {
3567 if (qctl.qc_type != ALLQUOTA) {
3568 fprintf(stderr, "error: -u/g/p can't be used "
3569 "more than once\n");
3572 qctl.qc_type = qtype;
3575 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3576 fprintf(stderr, "error: bad block-grace: %s\n",
3580 dqb->dqb_valid |= QIF_BTIME;
3583 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3584 fprintf(stderr, "error: bad inode-grace: %s\n",
3588 dqb->dqb_valid |= QIF_ITIME;
3590 case 't': /* Yes, of course! */
3592 default: /* getopt prints error message for us when opterr != 0 */
3597 if (qctl.qc_type == ALLQUOTA) {
3598 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3602 if (optind != argc - 1) {
3603 fprintf(stderr, "error: unexpected parameters encountered\n");
3608 rc = llapi_quotactl(mnt, &qctl);
3611 fprintf(stderr, "%s %s ", obd_type,
3612 obd_uuid2str(&qctl.obd_uuid));
3613 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3620 #define BSLIMIT (1 << 0)
3621 #define BHLIMIT (1 << 1)
3622 #define ISLIMIT (1 << 2)
3623 #define IHLIMIT (1 << 3)
3625 int lfs_setquota(int argc, char **argv)
3628 struct if_quotactl qctl;
3629 char *mnt, *obd_type = (char *)qctl.obd_type;
3630 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3631 struct option long_opts[] = {
3632 {"block-softlimit", required_argument, 0, 'b'},
3633 {"block-hardlimit", required_argument, 0, 'B'},
3634 {"group", required_argument, 0, 'g'},
3635 {"inode-softlimit", required_argument, 0, 'i'},
3636 {"inode-hardlimit", required_argument, 0, 'I'},
3637 {"user", required_argument, 0, 'u'},
3638 {"projid", required_argument, 0, 'p'},
3641 unsigned limit_mask = 0;
3645 if (has_times_option(argc, argv))
3646 return lfs_setquota_times(argc, argv);
3648 memset(&qctl, 0, sizeof(qctl));
3649 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3650 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3651 * so it can be used as a marker that qc_type
3652 * isn't reinitialized from command line */
3654 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3655 long_opts, NULL)) != -1) {
3659 rc = name2uid(&qctl.qc_id, optarg);
3663 rc = name2gid(&qctl.qc_id, optarg);
3667 rc = name2projid(&qctl.qc_id, optarg);
3669 if (qctl.qc_type != ALLQUOTA) {
3670 fprintf(stderr, "error: -u and -g can't be used"
3671 " more than once\n");
3674 qctl.qc_type = qtype;
3676 qctl.qc_id = strtoul(optarg, &endptr, 10);
3677 if (*endptr != '\0') {
3678 fprintf(stderr, "error: can't find id "
3679 "for name %s\n", optarg);
3685 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3686 dqb->dqb_bsoftlimit >>= 10;
3687 limit_mask |= BSLIMIT;
3688 if (dqb->dqb_bsoftlimit &&
3689 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3690 fprintf(stderr, "warning: block softlimit is "
3691 "smaller than the miminal qunit size, "
3692 "please see the help of setquota or "
3693 "Lustre manual for details.\n");
3696 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3697 dqb->dqb_bhardlimit >>= 10;
3698 limit_mask |= BHLIMIT;
3699 if (dqb->dqb_bhardlimit &&
3700 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3701 fprintf(stderr, "warning: block hardlimit is "
3702 "smaller than the miminal qunit size, "
3703 "please see the help of setquota or "
3704 "Lustre manual for details.\n");
3707 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3708 limit_mask |= ISLIMIT;
3709 if (dqb->dqb_isoftlimit &&
3710 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3711 fprintf(stderr, "warning: inode softlimit is "
3712 "smaller than the miminal qunit size, "
3713 "please see the help of setquota or "
3714 "Lustre manual for details.\n");
3717 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3718 limit_mask |= IHLIMIT;
3719 if (dqb->dqb_ihardlimit &&
3720 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3721 fprintf(stderr, "warning: inode hardlimit is "
3722 "smaller than the miminal qunit size, "
3723 "please see the help of setquota or "
3724 "Lustre manual for details.\n");
3726 default: /* getopt prints error message for us when opterr != 0 */
3731 if (qctl.qc_type == ALLQUOTA) {
3732 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3736 if (limit_mask == 0) {
3737 fprintf(stderr, "error: at least one limit must be specified\n");
3741 if (optind != argc - 1) {
3742 fprintf(stderr, "error: unexpected parameters encountered\n");
3748 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3749 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3750 /* sigh, we can't just set blimits/ilimits */
3751 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3752 .qc_type = qctl.qc_type,
3753 .qc_id = qctl.qc_id};
3755 rc = llapi_quotactl(mnt, &tmp_qctl);
3757 fprintf(stderr, "error: setquota failed while retrieving"
3758 " current quota settings (%s)\n",
3763 if (!(limit_mask & BHLIMIT))
3764 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3765 if (!(limit_mask & BSLIMIT))
3766 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3767 if (!(limit_mask & IHLIMIT))
3768 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3769 if (!(limit_mask & ISLIMIT))
3770 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3772 /* Keep grace times if we have got no softlimit arguments */
3773 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3774 dqb->dqb_valid |= QIF_BTIME;
3775 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3778 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3779 dqb->dqb_valid |= QIF_ITIME;
3780 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3784 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3785 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3787 rc = llapi_quotactl(mnt, &qctl);
3790 fprintf(stderr, "%s %s ", obd_type,
3791 obd_uuid2str(&qctl.obd_uuid));
3792 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3799 /* Converts seconds value into format string
3800 * result is returned in buf
3802 * 1. result is in descenting order: 1w2d3h4m5s
3803 * 2. zero fields are not filled (except for p. 3): 5d1s
3804 * 3. zero seconds value is presented as "0s"
3806 static char * __sec2str(time_t seconds, char *buf)
3808 const char spec[] = "smhdw";
3809 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3814 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3815 c = seconds / mult[i];
3817 if (c > 0 || (i == 0 && buf == tail))
3818 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3826 static void sec2str(time_t seconds, char *buf, int rc)
3833 tail = __sec2str(seconds, tail);
3835 if (rc && tail - buf < 39) {
3841 static void diff2str(time_t seconds, char *buf, time_t now)
3847 if (seconds <= now) {
3848 strcpy(buf, "none");
3851 __sec2str(seconds - now, buf);
3854 static void print_quota_title(char *name, struct if_quotactl *qctl,
3855 bool human_readable)
3857 printf("Disk quotas for %s %s (%cid %u):\n",
3858 qtype_name(qctl->qc_type), name,
3859 *qtype_name(qctl->qc_type), qctl->qc_id);
3860 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3861 "Filesystem", human_readable ? "used" : "kbytes",
3862 "quota", "limit", "grace",
3863 "files", "quota", "limit", "grace");
3866 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3869 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3872 snprintf(buf, buflen, "%5.4gP",
3873 (double)num / ((__u64)1 << 40));
3875 snprintf(buf, buflen, "%5.4gT",
3876 (double)num / (1 << 30));
3878 snprintf(buf, buflen, "%5.4gG",
3879 (double)num / (1 << 20));
3881 snprintf(buf, buflen, "%5.4gM",
3882 (double)num / (1 << 10));
3884 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3888 #define STRBUF_LEN 32
3889 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3896 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3897 int bover = 0, iover = 0;
3898 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3899 char numbuf[3][STRBUF_LEN];
3901 char strbuf[STRBUF_LEN];
3903 if (dqb->dqb_bhardlimit &&
3904 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3906 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3907 if (dqb->dqb_btime > now) {
3914 if (dqb->dqb_ihardlimit &&
3915 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3917 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3918 if (dqb->dqb_itime > now) {
3926 if (strlen(mnt) > 15)
3927 printf("%s\n%15s", mnt, "");
3929 printf("%15s", mnt);
3932 diff2str(dqb->dqb_btime, timebuf, now);
3934 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3935 strbuf, sizeof(strbuf), h);
3936 if (rc == -EREMOTEIO)
3937 sprintf(numbuf[0], "%s*", strbuf);
3939 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3940 "%s" : "[%s]", strbuf);
3942 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3943 if (type == QC_GENERAL)
3944 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3945 "%s" : "[%s]", strbuf);
3947 sprintf(numbuf[1], "%s", "-");
3949 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3950 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3951 "%s" : "[%s]", strbuf);
3953 printf(" %7s%c %6s %7s %7s",
3954 numbuf[0], bover ? '*' : ' ', numbuf[1],
3955 numbuf[2], bover > 1 ? timebuf : "-");
3958 diff2str(dqb->dqb_itime, timebuf, now);
3960 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3961 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3963 if (type == QC_GENERAL)
3964 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3966 (uintmax_t)dqb->dqb_isoftlimit);
3968 sprintf(numbuf[1], "%s", "-");
3970 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3971 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3973 if (type != QC_OSTIDX)
3974 printf(" %7s%c %6s %7s %7s",
3975 numbuf[0], iover ? '*' : ' ', numbuf[1],
3976 numbuf[2], iover > 1 ? timebuf : "-");
3978 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3981 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3982 qctl->qc_cmd == Q_GETOINFO) {
3986 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3987 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3988 printf("Block grace time: %s; Inode grace time: %s\n",
3989 bgtimebuf, igtimebuf);
3993 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3994 bool h, __u64 *total)
3996 int rc = 0, rc1 = 0, count = 0;
3997 __u32 valid = qctl->qc_valid;
3999 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4001 fprintf(stderr, "can not get %s count: %s\n",
4002 is_mdt ? "mdt": "ost", strerror(-rc));
4006 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4007 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4008 rc = llapi_quotactl(mnt, qctl);
4010 /* It is remote client case. */
4011 if (rc == -EOPNOTSUPP) {
4018 fprintf(stderr, "quotactl %s%d failed.\n",
4019 is_mdt ? "mdt": "ost", qctl->qc_idx);
4023 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4024 qctl->qc_valid, 0, h);
4025 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4026 qctl->qc_dqblk.dqb_bhardlimit;
4029 qctl->qc_valid = valid;
4033 static int lfs_quota(int argc, char **argv)
4036 char *mnt, *name = NULL;
4037 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4038 .qc_type = ALLQUOTA };
4039 char *obd_type = (char *)qctl.obd_type;
4040 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4041 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4042 verbose = 0, pass = 0, quiet = 0, inacc;
4044 __u32 valid = QC_GENERAL, idx = 0;
4045 __u64 total_ialloc = 0, total_balloc = 0;
4046 bool human_readable = false;
4049 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4060 if (qctl.qc_type != ALLQUOTA) {
4061 fprintf(stderr, "error: use either -u or -g\n");
4064 qctl.qc_type = qtype;
4067 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4070 valid = qctl.qc_valid = QC_UUID;
4071 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4074 valid = qctl.qc_valid = QC_MDTIDX;
4075 idx = qctl.qc_idx = atoi(optarg);
4078 valid = qctl.qc_valid = QC_OSTIDX;
4079 idx = qctl.qc_idx = atoi(optarg);
4088 human_readable = true;
4091 fprintf(stderr, "error: %s: option '-%c' "
4092 "unrecognized\n", argv[0], c);
4097 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4098 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4099 optind == argc - 1) {
4101 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4102 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4103 qctl.qc_valid = valid;
4105 qctl.qc_type = pass;
4106 switch (qctl.qc_type) {
4108 qctl.qc_id = geteuid();
4109 rc = uid2name(&name, qctl.qc_id);
4112 qctl.qc_id = getegid();
4113 rc = gid2name(&name, qctl.qc_id);
4122 /* lfs quota -u username /path/to/lustre/mount */
4123 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4124 /* options should be followed by u/g-name and mntpoint */
4125 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4126 fprintf(stderr, "error: missing quota argument(s)\n");
4130 name = argv[optind++];
4131 switch (qctl.qc_type) {
4133 rc = name2uid(&qctl.qc_id, name);
4136 rc = name2gid(&qctl.qc_id, name);
4139 rc = name2projid(&qctl.qc_id, name);
4146 qctl.qc_id = strtoul(name, &endptr, 10);
4147 if (*endptr != '\0') {
4148 fprintf(stderr, "error: can't find id for name: %s\n",
4153 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4154 fprintf(stderr, "error: missing quota info argument(s)\n");
4159 rc1 = llapi_quotactl(mnt, &qctl);
4163 fprintf(stderr, "%s quotas are not enabled.\n",
4164 qtype_name(qctl.qc_type));
4167 fprintf(stderr, "Permission denied.\n");
4170 /* We already got error message. */
4173 fprintf(stderr, "Unexpected quotactl error: %s\n",
4178 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4179 print_quota_title(name, &qctl, human_readable);
4181 if (rc1 && *obd_type)
4182 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4184 if (qctl.qc_valid != QC_GENERAL)
4187 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4188 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4189 (QIF_LIMITS|QIF_USAGE));
4191 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4193 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4195 char strbuf[STRBUF_LEN];
4197 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4199 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4201 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4203 printf("Total allocated inode limit: %ju, total "
4204 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4208 if (rc1 || rc2 || rc3 || inacc)
4209 printf("Some errors happened when getting quota info. "
4210 "Some devices may be not working or deactivated. "
4211 "The data in \"[]\" is inaccurate.\n");
4214 if (pass > 0 && pass < LL_MAXQUOTAS)
4219 #endif /* HAVE_SYS_QUOTA_H! */
4221 static int flushctx_ioctl(char *mp)
4225 fd = open(mp, O_RDONLY);
4227 fprintf(stderr, "flushctx: error open %s: %s\n",
4228 mp, strerror(errno));
4232 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4234 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4235 mp, strerror(errno));
4241 static int lfs_flushctx(int argc, char **argv)
4243 int kdestroy = 0, c;
4244 char mntdir[PATH_MAX] = {'\0'};
4248 while ((c = getopt(argc, argv, "k")) != -1) {
4254 fprintf(stderr, "error: %s: option '-%c' "
4255 "unrecognized\n", argv[0], c);
4261 if ((rc = system("kdestroy > /dev/null")) != 0) {
4262 rc = WEXITSTATUS(rc);
4263 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4267 if (optind >= argc) {
4268 /* flush for all mounted lustre fs. */
4269 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4270 /* Check if we have a mount point */
4271 if (mntdir[0] == '\0')
4274 if (flushctx_ioctl(mntdir))
4277 mntdir[0] = '\0'; /* avoid matching in next loop */
4280 /* flush fs as specified */
4281 while (optind < argc) {
4282 if (flushctx_ioctl(argv[optind++]))
4289 static int lfs_cp(int argc, char **argv)
4291 fprintf(stderr, "remote client copy file(s).\n"
4292 "obsolete, does not support it anymore.\n");
4296 static int lfs_ls(int argc, char **argv)
4298 fprintf(stderr, "remote client lists directory contents.\n"
4299 "obsolete, does not support it anymore.\n");
4303 static int lfs_changelog(int argc, char **argv)
4305 void *changelog_priv;
4306 struct changelog_rec *rec;
4307 long long startrec = 0, endrec = 0;
4309 struct option long_opts[] = {
4310 {"follow", no_argument, 0, 'f'},
4313 char short_opts[] = "f";
4316 while ((rc = getopt_long(argc, argv, short_opts,
4317 long_opts, NULL)) != -1) {
4325 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4326 argv[0], argv[optind - 1]);
4333 mdd = argv[optind++];
4335 startrec = strtoll(argv[optind++], NULL, 10);
4337 endrec = strtoll(argv[optind++], NULL, 10);
4339 rc = llapi_changelog_start(&changelog_priv,
4340 CHANGELOG_FLAG_BLOCK |
4341 CHANGELOG_FLAG_JOBID |
4342 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4345 fprintf(stderr, "Can't start changelog: %s\n",
4346 strerror(errno = -rc));
4350 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4354 if (endrec && rec->cr_index > endrec) {
4355 llapi_changelog_free(&rec);
4358 if (rec->cr_index < startrec) {
4359 llapi_changelog_free(&rec);
4363 secs = rec->cr_time >> 30;
4364 gmtime_r(&secs, &ts);
4365 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4366 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4367 changelog_type2str(rec->cr_type),
4368 ts.tm_hour, ts.tm_min, ts.tm_sec,
4369 (int)(rec->cr_time & ((1 << 30) - 1)),
4370 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4371 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4373 if (rec->cr_flags & CLF_JOBID) {
4374 struct changelog_ext_jobid *jid =
4375 changelog_rec_jobid(rec);
4377 if (jid->cr_jobid[0] != '\0')
4378 printf(" j=%s", jid->cr_jobid);
4381 if (rec->cr_namelen)
4382 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4383 rec->cr_namelen, changelog_rec_name(rec));
4385 if (rec->cr_flags & CLF_RENAME) {
4386 struct changelog_ext_rename *rnm =
4387 changelog_rec_rename(rec);
4389 if (!fid_is_zero(&rnm->cr_sfid))
4390 printf(" s="DFID" sp="DFID" %.*s",
4391 PFID(&rnm->cr_sfid),
4392 PFID(&rnm->cr_spfid),
4393 (int)changelog_rec_snamelen(rec),
4394 changelog_rec_sname(rec));
4398 llapi_changelog_free(&rec);
4401 llapi_changelog_fini(&changelog_priv);
4404 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4406 return (rc == 1 ? 0 : rc);
4409 static int lfs_changelog_clear(int argc, char **argv)
4417 endrec = strtoll(argv[3], NULL, 10);
4419 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4422 fprintf(stderr, "%s: record out of range: %llu\n",
4424 else if (rc == -ENOENT)
4425 fprintf(stderr, "%s: no changelog user: %s\n",
4428 fprintf(stderr, "%s error: %s\n", argv[0],
4437 static int lfs_fid2path(int argc, char **argv)
4439 struct option long_opts[] = {
4440 {"cur", no_argument, 0, 'c'},
4441 {"link", required_argument, 0, 'l'},
4442 {"rec", required_argument, 0, 'r'},
4445 char short_opts[] = "cl:r:";
4446 char *device, *fid, *path;
4447 long long recno = -1;
4453 while ((rc = getopt_long(argc, argv, short_opts,
4454 long_opts, NULL)) != -1) {
4460 linkno = strtol(optarg, NULL, 10);
4463 recno = strtoll(optarg, NULL, 10);
4468 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4469 argv[0], argv[optind - 1]);
4477 device = argv[optind++];
4478 path = calloc(1, PATH_MAX);
4480 fprintf(stderr, "error: Not enough memory\n");
4485 while (optind < argc) {
4486 fid = argv[optind++];
4488 lnktmp = (linkno >= 0) ? linkno : 0;
4490 int oldtmp = lnktmp;
4491 long long rectmp = recno;
4493 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4496 fprintf(stderr, "%s: error on FID %s: %s\n",
4497 argv[0], fid, strerror(errno = -rc2));
4504 fprintf(stdout, "%lld ", rectmp);
4505 if (device[0] == '/') {
4506 fprintf(stdout, "%s", device);
4507 if (device[strlen(device) - 1] != '/')
4508 fprintf(stdout, "/");
4509 } else if (path[0] == '\0') {
4510 fprintf(stdout, "/");
4512 fprintf(stdout, "%s\n", path);
4515 /* specified linkno */
4517 if (oldtmp == lnktmp)
4527 static int lfs_path2fid(int argc, char **argv)
4529 struct option long_opts[] = {
4530 {"parents", no_argument, 0, 'p'},
4534 const char short_opts[] = "p";
4535 const char *sep = "";
4538 bool show_parents = false;
4540 while ((rc = getopt_long(argc, argv, short_opts,
4541 long_opts, NULL)) != -1) {
4544 show_parents = true;
4547 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4548 argv[0], argv[optind - 1]);
4553 if (optind > argc - 1)
4555 else if (optind < argc - 1)
4559 for (path = argv + optind; *path != NULL; path++) {
4561 if (!show_parents) {
4562 err = llapi_path2fid(*path, &fid);
4564 printf("%s%s"DFID"\n",
4565 *sep != '\0' ? *path : "", sep,
4568 char name[NAME_MAX + 1];
4569 unsigned int linkno = 0;
4571 while ((err = llapi_path2parent(*path, linkno, &fid,
4572 name, sizeof(name))) == 0) {
4573 if (*sep != '\0' && linkno == 0)
4574 printf("%s%s", *path, sep);
4576 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4581 /* err == -ENODATA is end-of-loop */
4582 if (linkno > 0 && err == -ENODATA) {
4589 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4590 argv[0], show_parents ? "parent " : "", *path,
4602 static int lfs_data_version(int argc, char **argv)
4609 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4614 while ((c = getopt(argc, argv, "nrw")) != -1) {
4617 data_version_flags = 0;
4620 data_version_flags |= LL_DV_RD_FLUSH;
4623 data_version_flags |= LL_DV_WR_FLUSH;
4632 path = argv[optind];
4633 fd = open(path, O_RDONLY);
4635 err(errno, "cannot open file %s", path);
4637 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4639 err(errno, "cannot get version for %s", path);
4641 printf("%ju" "\n", (uintmax_t)data_version);
4647 static int lfs_hsm_state(int argc, char **argv)
4652 struct hsm_user_state hus;
4660 rc = llapi_hsm_state_get(path, &hus);
4662 fprintf(stderr, "can't get hsm state for %s: %s\n",
4663 path, strerror(errno = -rc));
4667 /* Display path name and status flags */
4668 printf("%s: (0x%08x)", path, hus.hus_states);
4670 if (hus.hus_states & HS_RELEASED)
4671 printf(" released");
4672 if (hus.hus_states & HS_EXISTS)
4674 if (hus.hus_states & HS_DIRTY)
4676 if (hus.hus_states & HS_ARCHIVED)
4677 printf(" archived");
4678 /* Display user-settable flags */
4679 if (hus.hus_states & HS_NORELEASE)
4680 printf(" never_release");
4681 if (hus.hus_states & HS_NOARCHIVE)
4682 printf(" never_archive");
4683 if (hus.hus_states & HS_LOST)
4684 printf(" lost_from_hsm");
4686 if (hus.hus_archive_id != 0)
4687 printf(", archive_id:%d", hus.hus_archive_id);
4690 } while (++i < argc);
4695 #define LFS_HSM_SET 0
4696 #define LFS_HSM_CLEAR 1
4699 * Generic function to set or clear HSM flags.
4700 * Used by hsm_set and hsm_clear.
4702 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4704 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4706 struct option long_opts[] = {
4707 {"lost", 0, 0, 'l'},
4708 {"norelease", 0, 0, 'r'},
4709 {"noarchive", 0, 0, 'a'},
4710 {"archived", 0, 0, 'A'},
4711 {"dirty", 0, 0, 'd'},
4712 {"exists", 0, 0, 'e'},
4715 char short_opts[] = "lraAde";
4723 while ((c = getopt_long(argc, argv, short_opts,
4724 long_opts, NULL)) != -1) {
4730 mask |= HS_NOARCHIVE;
4733 mask |= HS_ARCHIVED;
4736 mask |= HS_NORELEASE;
4747 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4748 argv[0], argv[optind - 1]);
4753 /* User should have specified a flag */
4757 while (optind < argc) {
4759 path = argv[optind];
4761 /* If mode == 0, this means we apply the mask. */
4762 if (mode == LFS_HSM_SET)
4763 rc = llapi_hsm_state_set(path, mask, 0, 0);
4765 rc = llapi_hsm_state_set(path, 0, mask, 0);
4768 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4769 path, strerror(errno = -rc));
4778 static int lfs_hsm_action(int argc, char **argv)
4783 struct hsm_current_action hca;
4784 struct hsm_extent he;
4785 enum hsm_user_action hua;
4786 enum hsm_progress_states hps;
4794 rc = llapi_hsm_current_action(path, &hca);
4796 fprintf(stderr, "can't get hsm action for %s: %s\n",
4797 path, strerror(errno = -rc));
4800 he = hca.hca_location;
4801 hua = hca.hca_action;
4802 hps = hca.hca_state;
4804 printf("%s: %s", path, hsm_user_action2name(hua));
4806 /* Skip file without action */
4807 if (hca.hca_action == HUA_NONE) {
4812 printf(" %s ", hsm_progress_state2name(hps));
4814 if ((hps == HPS_RUNNING) &&
4815 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4816 printf("(%llu bytes moved)\n",
4817 (unsigned long long)he.length);
4818 else if ((he.offset + he.length) == LUSTRE_EOF)
4819 printf("(from %llu to EOF)\n",
4820 (unsigned long long)he.offset);
4822 printf("(from %llu to %llu)\n",
4823 (unsigned long long)he.offset,
4824 (unsigned long long)(he.offset + he.length));
4826 } while (++i < argc);
4831 static int lfs_hsm_set(int argc, char **argv)
4833 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4836 static int lfs_hsm_clear(int argc, char **argv)
4838 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4842 * Check file state and return its fid, to be used by lfs_hsm_request().
4844 * \param[in] file Path to file to check
4845 * \param[in,out] fid Pointer to allocated lu_fid struct.
4846 * \param[in,out] last_dev Pointer to last device id used.
4848 * \return 0 on success.
4850 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4856 rc = lstat(file, &st);
4858 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4861 /* Checking for regular file as archiving as posix copytool
4862 * rejects archiving files other than regular files
4864 if (!S_ISREG(st.st_mode)) {
4865 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4868 /* A request should be ... */
4869 if (*last_dev != st.st_dev && *last_dev != 0) {
4870 fprintf(stderr, "All files should be "
4871 "on the same filesystem: %s\n", file);
4874 *last_dev = st.st_dev;
4876 rc = llapi_path2fid(file, fid);
4878 fprintf(stderr, "Cannot read FID of %s: %s\n",
4879 file, strerror(-rc));
4885 /* Fill an HSM HUR item with a given file name.
4887 * If mntpath is set, then the filename is actually a FID, and no
4888 * lookup on the filesystem will be performed.
4890 * \param[in] hur the user request to fill
4891 * \param[in] idx index of the item inside the HUR to fill
4892 * \param[in] mntpath mountpoint of Lustre
4893 * \param[in] fname filename (if mtnpath is NULL)
4894 * or FID (if mntpath is set)
4895 * \param[in] last_dev pointer to last device id used
4897 * \retval 0 on success
4898 * \retval CMD_HELP or a negative errno on error
4900 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4901 const char *mntpath, const char *fname,
4904 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4907 hui->hui_extent.length = -1;
4909 if (mntpath != NULL) {
4912 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4916 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4921 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4925 hur->hur_request.hr_itemcount++;
4930 static int lfs_hsm_request(int argc, char **argv, int action)
4932 struct option long_opts[] = {
4933 {"filelist", 1, 0, 'l'},
4934 {"data", 1, 0, 'D'},
4935 {"archive", 1, 0, 'a'},
4936 {"mntpath", 1, 0, 'm'},
4940 char short_opts[] = "l:D:a:m:";
4941 struct hsm_user_request *hur, *oldhur;
4946 char *filelist = NULL;
4947 char fullpath[PATH_MAX];
4948 char *opaque = NULL;
4952 int nbfile_alloc = 0;
4953 char *some_file = NULL;
4954 char *mntpath = NULL;
4960 while ((c = getopt_long(argc, argv, short_opts,
4961 long_opts, NULL)) != -1) {
4970 if (action != HUA_ARCHIVE &&
4971 action != HUA_REMOVE) {
4973 "error: -a is supported only "
4974 "when archiving or removing\n");
4977 archive_id = atoi(optarg);
4980 if (some_file == NULL) {
4982 some_file = strdup(optarg);
4988 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4989 argv[0], argv[optind - 1]);
4994 /* All remaining args are files, so we have at least nbfile */
4995 nbfile = argc - optind;
4997 if ((nbfile == 0) && (filelist == NULL))
5001 opaque_len = strlen(opaque);
5003 /* Alloc the request structure with enough place to store all files
5004 * from command line. */
5005 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5007 fprintf(stderr, "Cannot create the request: %s\n",
5011 nbfile_alloc = nbfile;
5013 hur->hur_request.hr_action = action;
5014 hur->hur_request.hr_archive_id = archive_id;
5015 hur->hur_request.hr_flags = 0;
5017 /* All remaining args are files, add them */
5018 if (nbfile != 0 && some_file == NULL)
5019 some_file = strdup(argv[optind]);
5021 for (i = 0; i < nbfile; i++) {
5022 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5028 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5030 /* If a filelist was specified, read the filelist from it. */
5031 if (filelist != NULL) {
5032 fp = fopen(filelist, "r");
5034 fprintf(stderr, "Cannot read the file list %s: %s\n",
5035 filelist, strerror(errno));
5040 while ((rc = getline(&line, &len, fp)) != -1) {
5041 /* If allocated buffer was too small, get something
5043 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5046 nbfile_alloc = nbfile_alloc * 2 + 1;
5048 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5051 fprintf(stderr, "hsm: cannot allocate "
5052 "the request: %s\n",
5059 size = hur_len(oldhur);
5061 fprintf(stderr, "hsm: cannot allocate "
5062 "%u files + %u bytes data\n",
5063 oldhur->hur_request.hr_itemcount,
5064 oldhur->hur_request.hr_data_len);
5071 memcpy(hur, oldhur, size);
5076 if (line[strlen(line) - 1] == '\n')
5077 line[strlen(line) - 1] = '\0';
5079 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5080 mntpath, line, &last_dev);
5086 if (some_file == NULL) {
5096 /* If a --data was used, add it to the request */
5097 hur->hur_request.hr_data_len = opaque_len;
5099 memcpy(hur_data(hur), opaque, opaque_len);
5101 /* Send the HSM request */
5102 if (realpath(some_file, fullpath) == NULL) {
5103 fprintf(stderr, "Could not find path '%s': %s\n",
5104 some_file, strerror(errno));
5106 rc = llapi_hsm_request(fullpath, hur);
5108 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5109 some_file, strerror(-rc));
5119 static int lfs_hsm_archive(int argc, char **argv)
5121 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5124 static int lfs_hsm_restore(int argc, char **argv)
5126 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5129 static int lfs_hsm_release(int argc, char **argv)
5131 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5134 static int lfs_hsm_remove(int argc, char **argv)
5136 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5139 static int lfs_hsm_cancel(int argc, char **argv)
5141 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5144 static int lfs_swap_layouts(int argc, char **argv)
5149 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5150 SWAP_LAYOUTS_KEEP_MTIME |
5151 SWAP_LAYOUTS_KEEP_ATIME);
5154 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5156 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5158 enum lu_ladvise_type advice;
5161 advice < ARRAY_SIZE(ladvise_names); advice++) {
5162 if (ladvise_names[advice] == NULL)
5164 if (strcmp(string, ladvise_names[advice]) == 0)
5168 return LU_LADVISE_INVALID;
5171 static int lfs_ladvise(int argc, char **argv)
5173 struct option long_opts[] = {
5174 {"advice", required_argument, 0, 'a'},
5175 {"background", no_argument, 0, 'b'},
5176 {"end", required_argument, 0, 'e'},
5177 {"start", required_argument, 0, 's'},
5178 {"length", required_argument, 0, 'l'},
5181 char short_opts[] = "a:be:l:s:";
5186 struct llapi_lu_ladvise advice;
5187 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5188 unsigned long long start = 0;
5189 unsigned long long end = LUSTRE_EOF;
5190 unsigned long long length = 0;
5191 unsigned long long size_units;
5192 unsigned long long flags = 0;
5195 while ((c = getopt_long(argc, argv, short_opts,
5196 long_opts, NULL)) != -1) {
5199 advice_type = lfs_get_ladvice(optarg);
5200 if (advice_type == LU_LADVISE_INVALID) {
5201 fprintf(stderr, "%s: invalid advice type "
5202 "'%s'\n", argv[0], optarg);
5203 fprintf(stderr, "Valid types:");
5205 for (advice_type = 0;
5206 advice_type < ARRAY_SIZE(ladvise_names);
5208 if (ladvise_names[advice_type] == NULL)
5210 fprintf(stderr, " %s",
5211 ladvise_names[advice_type]);
5213 fprintf(stderr, "\n");
5223 rc = llapi_parse_size(optarg, &end,
5226 fprintf(stderr, "%s: bad end offset '%s'\n",
5233 rc = llapi_parse_size(optarg, &start,
5236 fprintf(stderr, "%s: bad start offset "
5237 "'%s'\n", argv[0], optarg);
5243 rc = llapi_parse_size(optarg, &length,
5246 fprintf(stderr, "%s: bad length '%s'\n",
5254 fprintf(stderr, "%s: option '%s' unrecognized\n",
5255 argv[0], argv[optind - 1]);
5260 if (advice_type == LU_LADVISE_INVALID) {
5261 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5262 fprintf(stderr, "Valid types:");
5263 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5265 if (ladvise_names[advice_type] == NULL)
5267 fprintf(stderr, " %s", ladvise_names[advice_type]);
5269 fprintf(stderr, "\n");
5273 if (argc <= optind) {
5274 fprintf(stderr, "%s: please give one or more file names\n",
5279 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5280 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5285 if (end == LUSTRE_EOF && length != 0)
5286 end = start + length;
5289 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5290 argv[0], start, end);
5294 while (optind < argc) {
5297 path = argv[optind++];
5299 fd = open(path, O_RDONLY);
5301 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5302 argv[0], path, strerror(errno));
5307 advice.lla_start = start;
5308 advice.lla_end = end;
5309 advice.lla_advice = advice_type;
5310 advice.lla_value1 = 0;
5311 advice.lla_value2 = 0;
5312 advice.lla_value3 = 0;
5313 advice.lla_value4 = 0;
5314 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5317 fprintf(stderr, "%s: cannot give advice '%s' to file "
5318 "'%s': %s\n", argv[0],
5319 ladvise_names[advice_type],
5320 path, strerror(errno));
5323 if (rc == 0 && rc2 < 0)
5329 static int lfs_list_commands(int argc, char **argv)
5331 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5333 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5338 int main(int argc, char **argv)
5342 /* Ensure that liblustreapi constructor has run */
5343 if (!liblustreapi_initialized)
5344 fprintf(stderr, "liblustreapi was not properly initialized\n");
5348 Parser_init("lfs > ", cmdlist);
5350 progname = argv[0]; /* Used in error messages */
5352 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5354 rc = Parser_commands();
5357 return rc < 0 ? -rc : rc;
5360 #ifdef _LUSTRE_IDL_H_
5361 /* Everything we need here should be included by lustreapi.h. */
5362 # error "lfs should not depend on lustre_idl.h"
5363 #endif /* _LUSTRE_IDL_H_ */