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, 2015, 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>
63 #ifdef HAVE_SYS_QUOTA_H
64 # include <sys/quota.h>
67 #include <libcfs/util/string.h>
68 #include <libcfs/util/ioctl.h>
69 #include <libcfs/util/parser.h>
70 #include <lustre/lustreapi.h>
71 #include <lustre_ver.h>
72 #include <lustre_param.h>
75 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
76 #endif /* !ARRAY_SIZE */
79 static int lfs_setstripe(int argc, char **argv);
80 static int lfs_find(int argc, char **argv);
81 static int lfs_getstripe(int argc, char **argv);
82 static int lfs_getdirstripe(int argc, char **argv);
83 static int lfs_setdirstripe(int argc, char **argv);
84 static int lfs_rmentry(int argc, char **argv);
85 static int lfs_osts(int argc, char **argv);
86 static int lfs_mdts(int argc, char **argv);
87 static int lfs_df(int argc, char **argv);
88 static int lfs_getname(int argc, char **argv);
89 static int lfs_check(int argc, char **argv);
90 #ifdef HAVE_SYS_QUOTA_H
91 static int lfs_setquota(int argc, char **argv);
92 static int lfs_quota(int argc, char **argv);
94 static int lfs_flushctx(int argc, char **argv);
95 static int lfs_join(int argc, char **argv);
96 static int lfs_lsetfacl(int argc, char **argv);
97 static int lfs_lgetfacl(int argc, char **argv);
98 static int lfs_rsetfacl(int argc, char **argv);
99 static int lfs_rgetfacl(int argc, char **argv);
100 static int lfs_cp(int argc, char **argv);
101 static int lfs_ls(int argc, char **argv);
102 static int lfs_poollist(int argc, char **argv);
103 static int lfs_changelog(int argc, char **argv);
104 static int lfs_changelog_clear(int argc, char **argv);
105 static int lfs_fid2path(int argc, char **argv);
106 static int lfs_path2fid(int argc, char **argv);
107 static int lfs_data_version(int argc, char **argv);
108 static int lfs_hsm_state(int argc, char **argv);
109 static int lfs_hsm_set(int argc, char **argv);
110 static int lfs_hsm_clear(int argc, char **argv);
111 static int lfs_hsm_action(int argc, char **argv);
112 static int lfs_hsm_archive(int argc, char **argv);
113 static int lfs_hsm_restore(int argc, char **argv);
114 static int lfs_hsm_release(int argc, char **argv);
115 static int lfs_hsm_remove(int argc, char **argv);
116 static int lfs_hsm_cancel(int argc, char **argv);
117 static int lfs_swap_layouts(int argc, char **argv);
118 static int lfs_mv(int argc, char **argv);
119 static int lfs_ladvise(int argc, char **argv);
121 /* Setstripe and migrate share mostly the same parameters */
122 #define SSM_CMD_COMMON(cmd) \
123 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
124 " [--stripe-index|-i <start_ost_idx>]\n" \
125 " [--stripe-size|-S <stripe_size>]\n" \
126 " [--pool|-p <pool_name>]\n" \
127 " [--ost|-o <ost_indices>]\n"
129 #define SSM_HELP_COMMON \
130 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
131 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
132 "\t respectively)\n" \
133 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
134 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
135 "\tpool_name: Name of OST pool to use (default none)\n" \
136 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
137 "\t Indices be specified in a format of:\n" \
138 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
140 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
141 "\t If --pool is set with --ost, then the OSTs\n" \
142 "\t must be the members of the pool."
144 #define SETSTRIPE_USAGE \
145 SSM_CMD_COMMON("setstripe") \
146 " <directory|filename>\n" \
149 #define MIGRATE_USAGE \
150 SSM_CMD_COMMON("migrate ") \
152 " [--non-block|-n]\n" \
156 "\tblock: Block file access during data migration (default)\n" \
157 "\tnon-block: Abort migrations if concurrent access is detected\n" \
159 #define SETDIRSTRIPE_USAGE \
160 " [--mdt-count|-c stripe_count>\n" \
161 " [--mdt-index|-i mdt_index]\n" \
162 " [--mdt-hash|-t mdt_hash]\n" \
163 " [--default_stripe|-D] [--mode|-m mode] <dir>\n" \
164 "\tstripe_count: stripe count of the striped directory\n" \
165 "\tmdt_index: MDT index of first stripe\n" \
166 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
167 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
168 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
169 "\tdefault_stripe: set default dirstripe of the directory\n" \
170 "\tmode: the mode of the directory\n"
172 static const char *progname;
173 static bool file_lease_supported = true;
175 /* all available commands */
176 command_t cmdlist[] = {
177 {"setstripe", lfs_setstripe, 0,
178 "Create a new file with a specific striping pattern or\n"
179 "set the default striping pattern on an existing directory or\n"
180 "delete the default striping pattern from an existing directory\n"
181 "usage: setstripe -d <directory> (to delete default striping)\n"\
184 {"getstripe", lfs_getstripe, 0,
185 "To list the striping info for a given file or files in a\n"
186 "directory or recursively for all files in a directory tree.\n"
187 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
188 " [--stripe-count|-c] [--stripe-index|-i]\n"
189 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
190 " [--mdt|-m] [--recursive|-r] [--raw|-R]\n"
191 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
192 " <directory|filename> ..."},
193 {"setdirstripe", lfs_setdirstripe, 0,
194 "To create a striped directory on a specified MDT. This can only\n"
195 "be done on MDT0 with the right of administrator.\n"
196 "usage: setdirstripe [OPTION] <directory>\n"
198 {"getdirstripe", lfs_getdirstripe, 0,
199 "To list the striping info for a given directory\n"
200 "or recursively for all directories in a directory tree.\n"
201 "usage: getdirstripe [--obd|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
202 " [--count|-c ] [--index|-i ] [--raw|-R]\n"
203 " [--recursive | -r] [ --default_stripe | -D ] <dir> "},
204 {"mkdir", lfs_setdirstripe, 0,
205 "To create a striped directory on a specified MDT. This can only\n"
206 "be done on MDT0 with the right of administrator.\n"
207 "usage: mkdir [OPTION] <directory>\n"
209 {"rm_entry", lfs_rmentry, 0,
210 "To remove the name entry of the remote directory. Note: This\n"
211 "command will only delete the name entry, i.e. the remote directory\n"
212 "will become inaccessable after this command. This can only be done\n"
213 "by the administrator\n"
214 "usage: rm_entry <dir>\n"},
215 {"pool_list", lfs_poollist, 0,
216 "List pools or pool OSTs\n"
217 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
218 {"find", lfs_find, 0,
219 "find files matching given attributes recursively in directory tree.\n"
220 "usage: find <directory|filename> ...\n"
221 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
222 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
223 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
224 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
225 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
226 " [[!] --stripe-count|-c [+-]<stripes>]\n"
227 " [[!] --stripe-index|-i <index,...>]\n"
228 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
229 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
230 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
231 " [[!] --layout|-L released,raid0]\n"
232 "\t !: used before an option indicates 'NOT' requested attribute\n"
233 "\t -: used before a value indicates 'AT MOST' requested value\n"
234 "\t +: used before a value indicates 'AT LEAST' requested value\n"},
235 {"check", lfs_check, 0,
236 "Display the status of MDS or OSTs (as specified in the command)\n"
237 "or all the servers (MDS and OSTs).\n"
238 "usage: check <osts|mds|servers>"},
239 {"join", lfs_join, 0,
240 "join two lustre files into one.\n"
241 "obsolete, HEAD does not support it anymore.\n"},
242 {"osts", lfs_osts, 0, "list OSTs connected to client "
243 "[for specified path only]\n" "usage: osts [path]"},
244 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
245 "[for specified path only]\n" "usage: mdts [path]"},
247 "report filesystem disk space usage or inodes usage"
248 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
249 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
250 {"getname", lfs_getname, 0, "list instances and specified mount points "
251 "[for specified path only]\n"
252 "Usage: getname [-h]|[path ...] "},
253 #ifdef HAVE_SYS_QUOTA_H
254 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
255 "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
256 " -b <block-softlimit> -B <block-hardlimit>\n"
257 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
258 " setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
259 " [--block-softlimit <block-softlimit>]\n"
260 " [--block-hardlimit <block-hardlimit>]\n"
261 " [--inode-softlimit <inode-softlimit>]\n"
262 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
263 " setquota [-t] <-u|--user|-g|--group>\n"
264 " [--block-grace <block-grace>]\n"
265 " [--inode-grace <inode-grace>] <filesystem>\n"
266 " -b can be used instead of --block-softlimit/--block-grace\n"
267 " -B can be used instead of --block-hardlimit\n"
268 " -i can be used instead of --inode-softlimit/--inode-grace\n"
269 " -I can be used instead of --inode-hardlimit\n\n"
270 "Note: The total quota space will be split into many qunits and\n"
271 " balanced over all server targets, the minimal qunit size is\n"
272 " 1M bytes for block space and 1K inodes for inode space.\n\n"
273 " Quota space rebalancing process will stop when this mininum\n"
274 " value is reached. As a result, quota exceeded can be returned\n"
275 " while many targets still have 1MB or 1K inodes of spare\n"
277 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
278 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
280 " [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
281 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
283 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
284 "usage: flushctx [-k] [mountpoint...]"},
285 {"lsetfacl", lfs_lsetfacl, 0,
286 "Remote user setfacl for user/group on the same remote client.\n"
287 "usage: lsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
288 {"lgetfacl", lfs_lgetfacl, 0,
289 "Remote user getfacl for user/group on the same remote client.\n"
290 "usage: lgetfacl [-dRLPvh] file ..."},
291 {"rsetfacl", lfs_rsetfacl, 0,
292 "Remote user setfacl for user/group on other clients.\n"
293 "usage: rsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
294 {"rgetfacl", lfs_rgetfacl, 0,
295 "Remote user getfacl for user/group on other clients.\n"
296 "usage: rgetfacl [-dRLPvh] file ..."},
298 "Remote user copy files and directories.\n"
299 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
301 "Remote user list directory contents.\n"
302 "usage: ls [OPTION]... [FILE]..."},
303 {"changelog", lfs_changelog, 0,
304 "Show the metadata changes on an MDT."
305 "\nusage: changelog <mdtname> [startrec [endrec]]"},
306 {"changelog_clear", lfs_changelog_clear, 0,
307 "Indicate that old changelog records up to <endrec> are no longer of "
308 "interest to consumer <id>, allowing the system to free up space.\n"
309 "An <endrec> of 0 means all records.\n"
310 "usage: changelog_clear <mdtname> <id> <endrec>"},
311 {"fid2path", lfs_fid2path, 0,
312 "Resolve the full path(s) for given FID(s). For a specific hardlink "
313 "specify link number <linkno>.\n"
314 /* "For a historical link name, specify changelog record <recno>.\n" */
315 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
316 /* [ --rec <recno> ] */ },
317 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
318 "usage: path2fid [--parents] <path> ..."},
319 {"data_version", lfs_data_version, 0, "Display file data version for "
320 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
321 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
322 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
323 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
324 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
325 "[--archived] [--lost] <file> ..."},
326 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
328 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
329 "[--archived] [--lost] <file> ..."},
330 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
331 "given files.\n" "usage: hsm_action <file> ..."},
332 {"hsm_archive", lfs_hsm_archive, 0,
333 "Archive file to external storage.\n"
334 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
336 {"hsm_restore", lfs_hsm_restore, 0,
337 "Restore file from external storage.\n"
338 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
339 {"hsm_release", lfs_hsm_release, 0,
340 "Release files from Lustre.\n"
341 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
342 {"hsm_remove", lfs_hsm_remove, 0,
343 "Remove file copy from external storage.\n"
344 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
345 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
347 "Note: To remove files from the archive that have been deleted on\n"
348 "Lustre, set mntpath and optionally archive. In that case, all the\n"
349 "positional arguments and entries in the file list must be FIDs."
351 {"hsm_cancel", lfs_hsm_cancel, 0,
352 "Cancel requests related to specified files.\n"
353 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
354 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
355 "usage: swap_layouts <path1> <path2>"},
356 {"migrate", lfs_setstripe, 0,
357 "migrate a directory between MDTs.\n"
358 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
360 "\tmdt_idx: index of the destination MDT\n"
362 "migrate file objects from one OST "
363 "layout\nto another (may be not safe with concurent writes).\n"
365 "[--stripe-count|-c] <stripe_count>\n"
366 " [--stripe-index|-i] <start_ost_index>\n"
367 " [--stripe-size|-S] <stripe_size>\n"
368 " [--pool|-p] <pool_name>\n"
369 " [--ost-list|-o] <ost_indices>\n"
371 " [--non-block|-n]\n"
372 " <file|directory>\n"
373 "\tstripe_count: number of OSTs to stripe a file over\n"
374 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
375 "\tstripe_size: number of bytes to store before moving to the next OST\n"
376 "\tpool_name: name of the predefined pool of OSTs\n"
377 "\tost_indices: OSTs to stripe over, in order\n"
378 "\tblock: wait for the operation to return before continuing\n"
379 "\tnon-block: do not wait for the operation to return.\n"},
381 "To move directories between MDTs. This command is deprecated, "
382 "use \"migrate\" instead.\n"
383 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
385 {"ladvise", lfs_ladvise, 0,
386 "Provide servers with advice about access patterns for a file.\n"
387 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
388 " [--background|-b]\n"
389 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
391 {"help", Parser_help, 0, "help"},
392 {"exit", Parser_quit, 0, "quit"},
393 {"quit", Parser_quit, 0, "quit"},
394 {"--version", Parser_version, 0,
395 "output build version of the utility and exit"},
400 #define MIGRATION_NONBLOCK 1
403 * Internal helper for migrate_copy_data(). Check lease and report error if
406 * \param[in] fd File descriptor on which to check the lease.
407 * \param[out] lease_broken Set to true if the lease was broken.
408 * \param[in] group_locked Whether a group lock was taken or not.
409 * \param[in] path Name of the file being processed, for error
412 * \retval 0 Migration can keep on going.
413 * \retval -errno Error occurred, abort migration.
415 static int check_lease(int fd, bool *lease_broken, bool group_locked,
420 if (!file_lease_supported)
423 rc = llapi_lease_check(fd);
425 return 0; /* llapi_check_lease returns > 0 on success. */
428 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
430 rc = rc ? rc : -EAGAIN;
432 fprintf(stderr, "%s: external attempt to access file '%s' "
433 "blocked until migration ends.\n", progname, path);
436 *lease_broken = true;
440 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
441 bool group_locked, const char *fname)
450 bool lease_broken = false;
452 /* Use a page-aligned buffer for direct I/O */
453 rc = posix_memalign(&buf, getpagesize(), buf_size);
458 /* read new data only if we have written all
459 * previously read data */
462 rc = check_lease(fd_src, &lease_broken,
463 group_locked, fname);
467 rsize = read(fd_src, buf, buf_size);
470 fprintf(stderr, "%s: %s: read failed: %s\n",
471 progname, fname, strerror(-rc));
481 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
485 "%s: %s: write failed on volatile: %s\n",
486 progname, fname, strerror(-rc));
496 fprintf(stderr, "%s: %s: fsync failed: %s\n",
497 progname, fname, strerror(-rc));
505 static int migrate_copy_timestamps(int fdv, const struct stat *st)
507 struct timeval tv[2] = {
508 {.tv_sec = st->st_atime},
509 {.tv_sec = st->st_mtime}
512 return futimes(fdv, tv);
515 static int migrate_block(int fd, int fdv, const struct stat *st,
516 size_t buf_size, const char *name)
523 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
525 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
526 progname, name, strerror(-rc));
534 /* The grouplock blocks all concurrent accesses to the file.
535 * It has to be taken after llapi_get_data_version as it would
537 rc = llapi_group_lock(fd, gid);
539 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
540 progname, name, strerror(-rc));
544 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
546 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
550 /* Make sure we keep original atime/mtime values */
551 rc = migrate_copy_timestamps(fdv, st);
553 fprintf(stderr, "%s: %s: timestamp copy failed\n",
559 * for a migration we need to check data version on file did
562 * Pass in gid=0 since we already own grouplock. */
563 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
564 SWAP_LAYOUTS_CHECK_DV1);
566 fprintf(stderr, "%s: %s: dataversion changed during copy, "
567 "migration aborted\n", progname, name);
570 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
571 name, strerror(-rc));
576 rc2 = llapi_group_unlock(fd, gid);
577 if (rc2 < 0 && rc == 0) {
578 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
579 progname, name, strerror(-rc2));
586 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
587 size_t buf_size, const char *name)
593 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
595 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
596 progname, name, strerror(-rc));
600 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
602 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
606 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
608 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
609 progname, name, strerror(-rc));
615 fprintf(stderr, "%s: %s: data version changed during "
621 /* Make sure we keep original atime/mtime values */
622 rc = migrate_copy_timestamps(fdv, st);
624 fprintf(stderr, "%s: %s: timestamp copy failed\n",
629 /* Atomically put lease, swap layouts and close.
630 * for a migration we need to check data version on file did
632 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
634 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
635 progname, name, strerror(-rc));
642 static int lfs_migrate(char *name, __u64 migration_flags,
643 struct llapi_stripe_param *param)
647 char parent[PATH_MAX];
650 char volatile_file[sizeof(parent) +
651 LUSTRE_VOLATILE_HDR_LEN +
652 2 * sizeof(mdt_index) +
653 2 * sizeof(random_value) + 4];
656 struct lov_user_md *lum = NULL;
659 bool have_lease_rdlck = false;
663 /* find the right size for the IO and allocate the buffer */
664 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
665 lum = malloc(lum_size);
671 rc = llapi_file_get_stripe(name, lum);
672 /* failure can happen for many reasons and some may be not real errors
674 * in case of a real error, a later call will fail with better
675 * error management */
677 buf_size = 1024 * 1024;
679 buf_size = lum->lmm_stripe_size;
681 /* open file, direct io */
682 /* even if the file is only read, WR mode is nedeed to allow
683 * layout swap on fd */
684 fd = open(name, O_RDWR | O_DIRECT);
687 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
692 if (file_lease_supported) {
693 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
694 if (rc == -EOPNOTSUPP) {
695 /* Older servers do not support file lease.
696 * Disable related checks. This opens race conditions
697 * as explained in LU-4840 */
698 file_lease_supported = false;
700 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
701 progname, name, strerror(-rc));
704 have_lease_rdlck = true;
708 /* search for file directory pathname */
709 if (strlen(name) > sizeof(parent)-1) {
713 strncpy(parent, name, sizeof(parent));
714 ptr = strrchr(parent, '/');
716 if (getcwd(parent, sizeof(parent)) == NULL) {
727 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
729 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
730 progname, name, strerror(-rc));
735 random_value = random();
736 rc = snprintf(volatile_file, sizeof(volatile_file),
737 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
738 mdt_index, random_value);
739 if (rc >= sizeof(volatile_file)) {
744 /* create, open a volatile file, use caching (ie no directio) */
745 fdv = llapi_file_open_param(volatile_file,
746 O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW,
747 S_IRUSR | S_IWUSR, param);
748 } while (fdv == -EEXIST);
752 fprintf(stderr, "%s: %s: cannot create volatile file in"
754 progname, parent, strerror(-rc));
758 /* Not-owner (root?) special case.
759 * Need to set owner/group of volatile file like original.
760 * This will allow to pass related check during layout_swap.
765 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
769 rc = fstat(fdv, &stv);
772 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
773 volatile_file, strerror(errno));
776 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
777 rc = fchown(fdv, st.st_uid, st.st_gid);
780 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
781 name, strerror(errno));
786 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
787 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
789 have_lease_rdlck = false;
790 fdv = -1; /* The volatile file is closed as we put the
791 * lease in non-blocking mode. */
794 /* Blocking mode (forced if servers do not support file lease).
795 * It is also the default mode, since we cannot distinguish
796 * between a broken lease and a server that does not support
797 * atomic swap/close (LU-6785) */
798 rc = migrate_block(fd, fdv, &st, buf_size, name);
802 if (have_lease_rdlck)
819 * Parse a string containing an OST index list into an array of integers.
821 * The input string contains a comma delimited list of individual
822 * indices and ranges, for example "1,2-4,7". Add the indices into the
823 * \a osts array and remove duplicates.
825 * \param[out] osts array to store indices in
826 * \param[in] size size of \a osts array
827 * \param[in] offset starting index in \a osts
828 * \param[in] arg string containing OST index list
830 * \retval positive number of indices in \a osts
831 * \retval -EINVAL unable to parse \a arg
833 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
837 int slots = size - offset;
845 while (!end_of_loop) {
853 ptr = strchrnul(arg, ',');
855 end_of_loop = *ptr == '\0';
858 start_index = strtol(arg, &endptr, 0);
859 if (endptr == arg) /* no data at all */
861 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
866 end_index = start_index;
867 if (*endptr == '-') {
868 end_index = strtol(endptr + 1, &endptr, 0);
871 if (end_index < start_index)
875 for (i = start_index; i <= end_index && slots > 0; i++) {
878 /* remove duplicate */
879 for (j = 0; j < offset; j++) {
883 if (j == offset) { /* no duplicate */
888 if (slots == 0 && i < end_index)
896 if (!end_of_loop && ptr != NULL)
899 return rc < 0 ? rc : nr;
903 static int lfs_setstripe(int argc, char **argv)
905 struct llapi_stripe_param *param = NULL;
906 struct find_param migrate_mdt_param = {
913 unsigned long long st_size;
914 int st_offset, st_count;
918 char *stripe_size_arg = NULL;
919 char *stripe_off_arg = NULL;
920 char *stripe_count_arg = NULL;
921 char *pool_name_arg = NULL;
922 char *mdt_idx_arg = NULL;
923 unsigned long long size_units = 1;
924 bool migrate_mode = false;
925 bool migration_block = false;
926 __u64 migration_flags = 0;
927 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
930 struct option long_opts[] = {
931 /* --block is only valid in migrate mode */
932 {"block", no_argument, 0, 'b'},
933 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
934 /* This formerly implied "stripe-count", but was explicitly
935 * made "stripe-count" for consistency with other options,
936 * and to separate it from "mdt-count" when DNE arrives. */
937 {"count", required_argument, 0, 'c'},
939 {"stripe-count", required_argument, 0, 'c'},
940 {"stripe_count", required_argument, 0, 'c'},
941 {"delete", no_argument, 0, 'd'},
942 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
943 /* This formerly implied "stripe-index", but was explicitly
944 * made "stripe-index" for consistency with other options,
945 * and to separate it from "mdt-index" when DNE arrives. */
946 {"index", required_argument, 0, 'i'},
948 {"stripe-index", required_argument, 0, 'i'},
949 {"stripe_index", required_argument, 0, 'i'},
950 {"mdt", required_argument, 0, 'm'},
951 {"mdt-index", required_argument, 0, 'm'},
952 {"mdt_index", required_argument, 0, 'm'},
953 /* --non-block is only valid in migrate mode */
954 {"non-block", no_argument, 0, 'n'},
955 {"ost", required_argument, 0, 'o'},
956 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
957 {"ost-list", required_argument, 0, 'o'},
958 {"ost_list", required_argument, 0, 'o'},
960 {"pool", required_argument, 0, 'p'},
961 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
962 /* This formerly implied "--stripe-size", but was confusing
963 * with "lfs find --size|-s", which means "file size", so use
964 * the consistent "--stripe-size|-S" for all commands. */
965 {"size", required_argument, 0, 's'},
967 {"stripe-size", required_argument, 0, 'S'},
968 {"stripe_size", required_argument, 0, 'S'},
969 /* --verbose is only valid in migrate mode */
970 {"verbose", no_argument, 0, 'v'},
978 if (strcmp(argv[0], "migrate") == 0)
981 while ((c = getopt_long(argc, argv, "bc:di:m:no:p:s:S:v",
982 long_opts, NULL)) >= 0) {
989 fprintf(stderr, "--block is valid only for"
993 migration_block = true;
996 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
997 if (strcmp(argv[optind - 1], "--count") == 0)
998 fprintf(stderr, "warning: '--count' deprecated"
999 ", use '--stripe-count' instead\n");
1001 stripe_count_arg = optarg;
1004 /* delete the default striping pattern */
1008 nr_osts = parse_targets(osts,
1009 sizeof(osts) / sizeof(__u32),
1013 "error: %s: bad OST indices '%s'\n",
1018 if (st_offset == -1) /* first in the command line */
1019 st_offset = osts[0];
1022 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1023 if (strcmp(argv[optind - 1], "--index") == 0)
1024 fprintf(stderr, "warning: '--index' deprecated"
1025 ", use '--stripe-index' instead\n");
1027 stripe_off_arg = optarg;
1030 if (!migrate_mode) {
1031 fprintf(stderr, "--mdt-index is valid only for"
1035 mdt_idx_arg = optarg;
1038 if (!migrate_mode) {
1039 fprintf(stderr, "--non-block is valid only for"
1043 migration_flags |= MIGRATION_NONBLOCK;
1045 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1047 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1048 fprintf(stderr, "warning: '--size|-s' deprecated, "
1049 "use '--stripe-size|-S' instead\n");
1051 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1053 stripe_size_arg = optarg;
1056 pool_name_arg = optarg;
1059 if (!migrate_mode) {
1060 fprintf(stderr, "--verbose is valid only for"
1064 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1071 fname = argv[optind];
1074 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
1075 stripe_count_arg != NULL || pool_name_arg != NULL)) {
1076 fprintf(stderr, "error: %s: cannot specify -d with "
1077 "-s, -c, -o, or -p options\n",
1082 if (optind == argc) {
1083 fprintf(stderr, "error: %s: missing filename|dirname\n",
1088 if (mdt_idx_arg != NULL && optind > 3) {
1089 fprintf(stderr, "error: %s: cannot specify -m with other "
1090 "options\n", argv[0]);
1094 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1096 "error: %s: cannot specify --non-block and --block\n",
1101 if (pool_name_arg != NULL) {
1105 ptr = strchr(pool_name_arg, '.');
1107 ptr = pool_name_arg;
1109 if ((ptr - pool_name_arg) == 0) {
1110 fprintf(stderr, "error: %s: fsname is empty "
1111 "in pool name '%s'\n",
1112 argv[0], pool_name_arg);
1119 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1121 fprintf(stderr, "error: %s: poolname '%s' is "
1123 argv[0], pool_name_arg);
1125 } else if (rc == -2) {
1126 fprintf(stderr, "error: %s: pool name '%s' is too long "
1127 "(max is %d characters)\n",
1128 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1130 } else if (rc > 0) {
1131 fprintf(stderr, "error: %s: char '%c' not allowed in "
1133 argv[0], rc, pool_name_arg);
1138 /* get the stripe size */
1139 if (stripe_size_arg != NULL) {
1140 result = llapi_parse_size(stripe_size_arg, &st_size,
1143 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1144 argv[0], stripe_size_arg);
1148 /* get the stripe offset */
1149 if (stripe_off_arg != NULL) {
1150 st_offset = strtol(stripe_off_arg, &end, 0);
1152 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1153 argv[0], stripe_off_arg);
1157 /* get the stripe count */
1158 if (stripe_count_arg != NULL) {
1159 st_count = strtoul(stripe_count_arg, &end, 0);
1161 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1162 argv[0], stripe_count_arg);
1167 if (mdt_idx_arg != NULL) {
1168 /* initialize migrate mdt parameters */
1169 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1171 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1172 argv[0], mdt_idx_arg);
1175 migrate_mdt_param.fp_migrate = 1;
1177 /* initialize stripe parameters */
1178 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1179 if (param == NULL) {
1180 fprintf(stderr, "error: %s: run out of memory\n",
1185 param->lsp_stripe_size = st_size;
1186 param->lsp_stripe_offset = st_offset;
1187 param->lsp_stripe_count = st_count;
1188 param->lsp_stripe_pattern = 0;
1189 param->lsp_pool = pool_name_arg;
1190 param->lsp_is_specific = false;
1192 if (st_count > 0 && nr_osts != st_count) {
1193 fprintf(stderr, "error: %s: stripe count '%d' "
1194 "doesn't match the number of OSTs: %d\n"
1195 , argv[0], st_count, nr_osts);
1200 param->lsp_is_specific = true;
1201 param->lsp_stripe_count = nr_osts;
1202 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1206 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1207 if (!migrate_mode) {
1208 result = llapi_file_open_param(fname,
1215 } else if (mdt_idx_arg != NULL) {
1216 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1218 result = lfs_migrate(fname, migration_flags, param);
1221 /* Save the first error encountered. */
1224 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1225 argv[0], migrate_mode ? "migrate" : "create",
1227 pool_name_arg != NULL && result == EINVAL ?
1228 "OST not in pool?" : strerror(errno));
1237 static int lfs_poollist(int argc, char **argv)
1242 return llapi_poollist(argv[1]);
1245 static int set_time(time_t *time, time_t *set, char *str)
1252 else if (str[0] == '-')
1258 t = strtol(str, NULL, 0);
1259 if (*time < t * 24 * 60 * 60) {
1262 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1266 *set = *time - t * 24 * 60 * 60;
1273 static int name2id(unsigned int *id, char *name, int type)
1276 struct passwd *entry;
1278 if (!(entry = getpwnam(name))) {
1284 *id = entry->pw_uid;
1286 struct group *entry;
1288 if (!(entry = getgrnam(name))) {
1294 *id = entry->gr_gid;
1300 static int id2name(char **name, unsigned int id, int type)
1303 struct passwd *entry;
1305 if (!(entry = getpwuid(id))) {
1311 *name = entry->pw_name;
1313 struct group *entry;
1315 if (!(entry = getgrgid(id))) {
1321 *name = entry->gr_name;
1327 static int name2layout(__u32 *layout, char *name)
1332 for (ptr = name; ; ptr = NULL) {
1333 lyt = strtok(ptr, ",");
1336 if (strcmp(lyt, "released") == 0)
1337 *layout |= LOV_PATTERN_F_RELEASED;
1338 else if (strcmp(lyt, "raid0") == 0)
1339 *layout |= LOV_PATTERN_RAID0;
1346 #define FIND_POOL_OPT 3
1347 static int lfs_find(int argc, char **argv)
1352 struct find_param param = {
1356 struct option long_opts[] = {
1357 {"atime", required_argument, 0, 'A'},
1358 {"stripe-count", required_argument, 0, 'c'},
1359 {"stripe_count", required_argument, 0, 'c'},
1360 {"ctime", required_argument, 0, 'C'},
1361 {"maxdepth", required_argument, 0, 'D'},
1362 {"gid", required_argument, 0, 'g'},
1363 {"group", required_argument, 0, 'G'},
1364 {"stripe-index", required_argument, 0, 'i'},
1365 {"stripe_index", required_argument, 0, 'i'},
1366 {"layout", required_argument, 0, 'L'},
1367 {"mdt", required_argument, 0, 'm'},
1368 {"mdt-index", required_argument, 0, 'm'},
1369 {"mdt_index", required_argument, 0, 'm'},
1370 {"mtime", required_argument, 0, 'M'},
1371 {"name", required_argument, 0, 'n'},
1372 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1373 {"obd", required_argument, 0, 'O'},
1374 {"ost", required_argument, 0, 'O'},
1375 /* no short option for pool, p/P already used */
1376 {"pool", required_argument, 0, FIND_POOL_OPT},
1377 {"print0", no_argument, 0, 'p'},
1378 {"print", no_argument, 0, 'P'},
1379 {"size", required_argument, 0, 's'},
1380 {"stripe-size", required_argument, 0, 'S'},
1381 {"stripe_size", required_argument, 0, 'S'},
1382 {"type", required_argument, 0, 't'},
1383 {"uid", required_argument, 0, 'u'},
1384 {"user", required_argument, 0, 'U'},
1397 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1398 while ((c = getopt_long_only(argc, argv,
1399 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1400 long_opts, NULL)) >= 0) {
1405 /* '!' is part of option */
1406 /* when getopt_long_only() finds a string which is not
1407 * an option nor a known option argument it returns 1
1408 * in that case if we already have found pathstart and pathend
1409 * (i.e. we have the list of pathnames),
1410 * the only supported value is "!"
1412 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1413 if (!isoption && pathend != -1) {
1414 fprintf(stderr, "err: %s: filename|dirname must either "
1415 "precede options or follow options\n",
1420 if (!isoption && pathstart == -1)
1421 pathstart = optind - 1;
1422 if (isoption && pathstart != -1 && pathend == -1)
1423 pathend = optind - 2;
1429 /* unknown; opt is "!" or path component,
1430 * checking done above.
1432 if (strcmp(optarg, "!") == 0)
1436 xtime = ¶m.fp_atime;
1437 xsign = ¶m.fp_asign;
1438 param.fp_exclude_atime = !!neg_opt;
1439 /* no break, this falls through to 'C' for ctime */
1442 xtime = ¶m.fp_ctime;
1443 xsign = ¶m.fp_csign;
1444 param.fp_exclude_ctime = !!neg_opt;
1446 /* no break, this falls through to 'M' for mtime */
1449 xtime = ¶m.fp_mtime;
1450 xsign = ¶m.fp_msign;
1451 param.fp_exclude_mtime = !!neg_opt;
1453 rc = set_time(&t, xtime, optarg);
1454 if (rc == INT_MAX) {
1462 if (optarg[0] == '+') {
1463 param.fp_stripe_count_sign = -1;
1465 } else if (optarg[0] == '-') {
1466 param.fp_stripe_count_sign = 1;
1470 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1471 if (*endptr != '\0') {
1472 fprintf(stderr,"error: bad stripe_count '%s'\n",
1477 param.fp_check_stripe_count = 1;
1478 param.fp_exclude_stripe_count = !!neg_opt;
1481 param.fp_max_depth = strtol(optarg, 0, 0);
1485 rc = name2id(¶m.fp_gid, optarg, GROUP);
1487 param.fp_gid = strtoul(optarg, &endptr, 10);
1488 if (*endptr != '\0') {
1489 fprintf(stderr, "Group/GID: %s cannot "
1490 "be found.\n", optarg);
1495 param.fp_exclude_gid = !!neg_opt;
1496 param.fp_check_gid = 1;
1499 ret = name2layout(¶m.fp_layout, optarg);
1502 param.fp_exclude_layout = !!neg_opt;
1503 param.fp_check_layout = 1;
1507 rc = name2id(¶m.fp_uid, optarg, USER);
1509 param.fp_uid = strtoul(optarg, &endptr, 10);
1510 if (*endptr != '\0') {
1511 fprintf(stderr, "User/UID: %s cannot "
1512 "be found.\n", optarg);
1517 param.fp_exclude_uid = !!neg_opt;
1518 param.fp_check_uid = 1;
1521 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1523 "Pool name %s is too long"
1524 " (max is %d)\n", optarg,
1529 /* we do check for empty pool because empty pool
1530 * is used to find V1 lov attributes */
1531 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1532 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1533 param.fp_exclude_pool = !!neg_opt;
1534 param.fp_check_pool = 1;
1537 param.fp_pattern = (char *)optarg;
1538 param.fp_exclude_pattern = !!neg_opt;
1543 char *buf, *token, *next, *p;
1547 buf = strdup(optarg);
1553 param.fp_exclude_obd = !!neg_opt;
1556 while (token && *token) {
1557 token = strchr(token, ',');
1564 param.fp_exclude_mdt = !!neg_opt;
1565 param.fp_num_alloc_mdts += len;
1566 tmp = realloc(param.fp_mdt_uuid,
1567 param.fp_num_alloc_mdts *
1568 sizeof(*param.fp_mdt_uuid));
1574 param.fp_mdt_uuid = tmp;
1576 param.fp_exclude_obd = !!neg_opt;
1577 param.fp_num_alloc_obds += len;
1578 tmp = realloc(param.fp_obd_uuid,
1579 param.fp_num_alloc_obds *
1580 sizeof(*param.fp_obd_uuid));
1586 param.fp_obd_uuid = tmp;
1588 for (token = buf; token && *token; token = next) {
1589 struct obd_uuid *puuid;
1592 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1595 ¶m.fp_obd_uuid[param.fp_num_obds++];
1597 p = strchr(token, ',');
1604 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1609 strncpy(puuid->uuid, token,
1610 sizeof(puuid->uuid));
1618 param.fp_zero_end = 1;
1623 if (optarg[0] == '+') {
1624 param.fp_size_sign = -1;
1626 } else if (optarg[0] == '-') {
1627 param.fp_size_sign = 1;
1631 ret = llapi_parse_size(optarg, ¶m.fp_size,
1632 ¶m.fp_size_units, 0);
1634 fprintf(stderr, "error: bad file size '%s'\n",
1638 param.fp_check_size = 1;
1639 param.fp_exclude_size = !!neg_opt;
1642 if (optarg[0] == '+') {
1643 param.fp_stripe_size_sign = -1;
1645 } else if (optarg[0] == '-') {
1646 param.fp_stripe_size_sign = 1;
1650 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1651 ¶m.fp_stripe_size_units, 0);
1653 fprintf(stderr, "error: bad stripe_size '%s'\n",
1657 param.fp_check_stripe_size = 1;
1658 param.fp_exclude_stripe_size = !!neg_opt;
1661 param.fp_exclude_type = !!neg_opt;
1662 switch (optarg[0]) {
1664 param.fp_type = S_IFBLK;
1667 param.fp_type = S_IFCHR;
1670 param.fp_type = S_IFDIR;
1673 param.fp_type = S_IFREG;
1676 param.fp_type = S_IFLNK;
1679 param.fp_type = S_IFIFO;
1682 param.fp_type = S_IFSOCK;
1685 fprintf(stderr, "error: %s: bad type '%s'\n",
1697 if (pathstart == -1) {
1698 fprintf(stderr, "error: %s: no filename|pathname\n",
1702 } else if (pathend == -1) {
1708 rc = llapi_find(argv[pathstart], ¶m);
1709 if (rc != 0 && ret == 0)
1711 } while (++pathstart < pathend);
1714 fprintf(stderr, "error: %s failed for %s.\n",
1715 argv[0], argv[optind - 1]);
1717 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1718 free(param.fp_obd_uuid);
1720 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1721 free(param.fp_mdt_uuid);
1726 static int lfs_getstripe_internal(int argc, char **argv,
1727 struct find_param *param)
1729 struct option long_opts[] = {
1730 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1731 /* This formerly implied "stripe-count", but was explicitly
1732 * made "stripe-count" for consistency with other options,
1733 * and to separate it from "mdt-count" when DNE arrives. */
1734 {"count", no_argument, 0, 'c'},
1736 {"stripe-count", no_argument, 0, 'c'},
1737 {"stripe_count", no_argument, 0, 'c'},
1738 {"directory", no_argument, 0, 'd'},
1739 {"default", no_argument, 0, 'D'},
1740 {"fid", no_argument, 0, 'F'},
1741 {"generation", no_argument, 0, 'g'},
1742 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1743 /* This formerly implied "stripe-index", but was explicitly
1744 * made "stripe-index" for consistency with other options,
1745 * and to separate it from "mdt-index" when DNE arrives. */
1746 {"index", no_argument, 0, 'i'},
1748 {"stripe-index", no_argument, 0, 'i'},
1749 {"stripe_index", no_argument, 0, 'i'},
1750 {"layout", no_argument, 0, 'L'},
1751 {"mdt", no_argument, 0, 'm'},
1752 {"mdt-index", no_argument, 0, 'm'},
1753 {"mdt_index", no_argument, 0, 'm'},
1754 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1755 {"mdt-index", no_argument, 0, 'M'},
1756 {"mdt_index", no_argument, 0, 'M'},
1758 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1759 /* This formerly implied "stripe-index", but was confusing
1760 * with "file offset" (which will eventually be needed for
1761 * with different layouts by offset), so deprecate it. */
1762 {"offset", no_argument, 0, 'o'},
1764 {"obd", required_argument, 0, 'O'},
1765 {"ost", required_argument, 0, 'O'},
1766 {"pool", no_argument, 0, 'p'},
1767 {"quiet", no_argument, 0, 'q'},
1768 {"recursive", no_argument, 0, 'r'},
1769 {"raw", no_argument, 0, 'R'},
1770 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1771 /* This formerly implied "--stripe-size", but was confusing
1772 * with "lfs find --size|-s", which means "file size", so use
1773 * the consistent "--stripe-size|-S" for all commands. */
1774 {"size", no_argument, 0, 's'},
1776 {"stripe-size", no_argument, 0, 'S'},
1777 {"stripe_size", no_argument, 0, 'S'},
1778 {"verbose", no_argument, 0, 'v'},
1783 while ((c = getopt_long(argc, argv, "cdDFghiLmMoO:pqrRsSv",
1784 long_opts, NULL)) != -1) {
1787 if (param->fp_obd_uuid) {
1789 "error: %s: only one obduuid allowed",
1793 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1799 param->fp_max_depth = 0;
1802 param->fp_get_default_lmv = 1;
1805 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1806 param->fp_verbose |= VERBOSE_DFID;
1807 param->fp_max_depth = 0;
1811 param->fp_recursive = 1;
1814 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
1817 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1818 if (strcmp(argv[optind - 1], "--count") == 0)
1819 fprintf(stderr, "warning: '--count' deprecated,"
1820 " use '--stripe-count' instead\n");
1822 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1823 param->fp_verbose |= VERBOSE_COUNT;
1824 param->fp_max_depth = 0;
1827 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1829 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1830 fprintf(stderr, "warning: '--size|-s' deprecated, "
1831 "use '--stripe-size|-S' instead\n");
1833 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1835 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1836 param->fp_verbose |= VERBOSE_SIZE;
1837 param->fp_max_depth = 0;
1840 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1842 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1843 "use '--stripe-index|-i' instead\n");
1846 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1847 if (strcmp(argv[optind - 1], "--index") == 0)
1848 fprintf(stderr, "warning: '--index' deprecated"
1849 ", use '--stripe-index' instead\n");
1851 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1852 param->fp_verbose |= VERBOSE_OFFSET;
1853 param->fp_max_depth = 0;
1857 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1858 param->fp_verbose |= VERBOSE_POOL;
1859 param->fp_max_depth = 0;
1863 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1864 param->fp_verbose |= VERBOSE_GENERATION;
1865 param->fp_max_depth = 0;
1869 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1870 param->fp_verbose |= VERBOSE_LAYOUT;
1871 param->fp_max_depth = 0;
1874 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1876 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
1877 fprintf(stderr, "warning: '-M' deprecated"
1878 ", use '-m' instead\n");
1882 if (!(param->fp_verbose & VERBOSE_DETAIL))
1883 param->fp_max_depth = 0;
1884 param->fp_verbose |= VERBOSE_MDTINDEX;
1897 if (param->fp_recursive)
1898 param->fp_max_depth = -1;
1900 if (!param->fp_verbose)
1901 param->fp_verbose = VERBOSE_DEFAULT;
1902 if (param->fp_quiet)
1903 param->fp_verbose = VERBOSE_OBJID;
1906 rc = llapi_getstripe(argv[optind], param);
1907 } while (++optind < argc && !rc);
1910 fprintf(stderr, "error: %s failed for %s.\n",
1911 argv[0], argv[optind - 1]);
1915 static int lfs_tgts(int argc, char **argv)
1917 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1918 struct find_param param;
1919 int index = 0, rc=0;
1924 if (argc == 2 && !realpath(argv[1], path)) {
1926 fprintf(stderr, "error: invalid path '%s': %s\n",
1927 argv[1], strerror(-rc));
1931 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1932 /* Check if we have a mount point */
1933 if (mntdir[0] == '\0')
1936 memset(¶m, 0, sizeof(param));
1937 if (!strcmp(argv[0], "mdts"))
1938 param.fp_get_lmv = 1;
1940 rc = llapi_ostlist(mntdir, ¶m);
1942 fprintf(stderr, "error: %s: failed on %s\n",
1945 if (path[0] != '\0')
1947 memset(mntdir, 0, PATH_MAX);
1953 static int lfs_getstripe(int argc, char **argv)
1955 struct find_param param = { 0 };
1957 param.fp_max_depth = 1;
1958 return lfs_getstripe_internal(argc, argv, ¶m);
1962 static int lfs_getdirstripe(int argc, char **argv)
1964 struct find_param param = { 0 };
1966 param.fp_get_lmv = 1;
1967 return lfs_getstripe_internal(argc, argv, ¶m);
1971 static int lfs_setdirstripe(int argc, char **argv)
1975 unsigned int stripe_offset = -1;
1976 unsigned int stripe_count = 1;
1977 enum lmv_hash_type hash_type;
1980 char *stripe_offset_opt = NULL;
1981 char *stripe_count_opt = NULL;
1982 char *stripe_hash_opt = NULL;
1983 char *mode_opt = NULL;
1984 bool default_stripe = false;
1985 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1986 mode_t previous_mode = 0;
1987 bool delete = false;
1989 struct option long_opts[] = {
1990 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1991 {"count", required_argument, 0, 'c'},
1993 {"mdt-count", required_argument, 0, 'c'},
1994 {"delete", no_argument, 0, 'd'},
1995 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1996 {"index", required_argument, 0, 'i'},
1998 {"mdt-index", required_argument, 0, 'i'},
1999 {"mode", required_argument, 0, 'm'},
2000 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2001 {"hash-type", required_argument, 0, 't'},
2003 {"mdt-hash", required_argument, 0, 't'},
2004 {"default_stripe", no_argument, 0, 'D'},
2008 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
2015 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2016 if (strcmp(argv[optind - 1], "--count") == 0)
2017 fprintf(stderr, "warning: '--count' deprecated"
2018 ", use '--mdt-count' instead\n");
2020 stripe_count_opt = optarg;
2024 default_stripe = true;
2027 default_stripe = true;
2030 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2031 if (strcmp(argv[optind - 1], "--index") == 0)
2032 fprintf(stderr, "warning: '--index' deprecated"
2033 ", use '--mdt-index' instead\n");
2035 stripe_offset_opt = optarg;
2041 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2042 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2043 fprintf(stderr, "warning: '--hash-type' "
2044 "deprecated, use '--mdt-hash' "
2047 stripe_hash_opt = optarg;
2050 fprintf(stderr, "error: %s: option '%s' "
2052 argv[0], argv[optind - 1]);
2057 if (optind == argc) {
2058 fprintf(stderr, "error: %s: missing dirname\n",
2063 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2064 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2069 if (stripe_offset_opt != NULL) {
2070 /* get the stripe offset */
2071 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2073 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2074 argv[0], stripe_offset_opt);
2080 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2081 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2082 " or -i options.\n", argv[0]);
2090 if (mode_opt != NULL) {
2091 mode = strtoul(mode_opt, &end, 8);
2093 fprintf(stderr, "error: %s: bad mode '%s'\n",
2097 previous_mode = umask(0);
2100 if (stripe_hash_opt == NULL ||
2101 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
2102 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2103 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
2104 hash_type = LMV_HASH_TYPE_ALL_CHARS;
2106 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
2107 argv[0], stripe_hash_opt);
2111 /* get the stripe count */
2112 if (stripe_count_opt != NULL) {
2113 stripe_count = strtoul(stripe_count_opt, &end, 0);
2115 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2116 argv[0], stripe_count_opt);
2121 dname = argv[optind];
2123 if (default_stripe) {
2124 result = llapi_dir_set_default_lmv_stripe(dname,
2125 stripe_offset, stripe_count,
2128 result = llapi_dir_create_pool(dname, mode,
2130 stripe_count, hash_type,
2135 fprintf(stderr, "error: %s: create stripe dir '%s' "
2136 "failed\n", argv[0], dname);
2139 dname = argv[++optind];
2140 } while (dname != NULL);
2142 if (mode_opt != NULL)
2143 umask(previous_mode);
2149 static int lfs_rmentry(int argc, char **argv)
2156 fprintf(stderr, "error: %s: missing dirname\n",
2162 dname = argv[index];
2163 while (dname != NULL) {
2164 result = llapi_direntry_remove(dname);
2166 fprintf(stderr, "error: %s: remove dir entry '%s' "
2167 "failed\n", argv[0], dname);
2170 dname = argv[++index];
2175 static int lfs_mv(int argc, char **argv)
2177 struct find_param param = {
2184 struct option long_opts[] = {
2185 {"mdt-index", required_argument, 0, 'M'},
2186 {"verbose", no_argument, 0, 'v'},
2190 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2193 param.fp_mdt_index = strtoul(optarg, &end, 0);
2195 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2202 param.fp_verbose = VERBOSE_DETAIL;
2206 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2207 argv[0], argv[optind - 1]);
2212 if (param.fp_mdt_index == -1) {
2213 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2217 if (optind >= argc) {
2218 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2222 param.fp_migrate = 1;
2223 rc = llapi_migrate_mdt(argv[optind], ¶m);
2225 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2226 argv[0], argv[optind], param.fp_mdt_index,
2231 static int lfs_osts(int argc, char **argv)
2233 return lfs_tgts(argc, argv);
2236 static int lfs_mdts(int argc, char **argv)
2238 return lfs_tgts(argc, argv);
2241 #define COOK(value) \
2244 while (value > 1024) { \
2252 #define CDF "%11llu"
2253 #define HDF "%8.1f%c"
2257 static int showdf(char *mntdir, struct obd_statfs *stat,
2258 char *uuid, int ishow, int cooked,
2259 char *type, int index, int rc)
2261 long long avail, used, total;
2263 char *suffix = "KMGTPEZY";
2264 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2265 char tbuf[3 * sizeof(__u64)];
2266 char ubuf[3 * sizeof(__u64)];
2267 char abuf[3 * sizeof(__u64)];
2268 char rbuf[3 * sizeof(__u64)];
2276 avail = stat->os_ffree;
2277 used = stat->os_files - stat->os_ffree;
2278 total = stat->os_files;
2280 int shift = cooked ? 0 : 10;
2282 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2283 used = ((stat->os_blocks - stat->os_bfree) *
2284 stat->os_bsize) >> shift;
2285 total = (stat->os_blocks * stat->os_bsize) >> shift;
2288 if ((used + avail) > 0)
2289 ratio = (double)used / (double)(used + avail);
2295 cook_val = (double)total;
2298 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2300 sprintf(tbuf, CDF, total);
2302 cook_val = (double)used;
2305 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2307 sprintf(ubuf, CDF, used);
2309 cook_val = (double)avail;
2312 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2314 sprintf(abuf, CDF, avail);
2316 sprintf(tbuf, CDF, total);
2317 sprintf(ubuf, CDF, used);
2318 sprintf(abuf, CDF, avail);
2321 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2322 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2323 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2325 printf("[%s:%d]\n", type, index);
2331 printf(UUF": inactive device\n", uuid);
2334 printf(UUF": %s\n", uuid, strerror(-rc));
2341 struct ll_stat_type {
2346 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2347 int cooked, int lazy)
2349 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2350 struct obd_uuid uuid_buf;
2351 char *poolname = NULL;
2352 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2353 { LL_STATFS_LOV, "OST" },
2355 struct ll_stat_type *tp;
2356 __u64 ost_ffree = 0;
2364 poolname = strchr(pool, '.');
2365 if (poolname != NULL) {
2366 if (strncmp(fsname, pool, strlen(fsname))) {
2367 fprintf(stderr, "filesystem name incorrect\n");
2375 fd = open(mntdir, O_RDONLY);
2378 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
2384 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2385 "UUID", "Inodes", "IUsed", "IFree",
2386 "IUse%", "Mounted on");
2388 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2389 "UUID", cooked ? "bytes" : "1K-blocks",
2390 "Used", "Available", "Use%", "Mounted on");
2392 for (tp = types; tp->st_name != NULL; tp++) {
2393 for (index = 0; ; index++) {
2394 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2395 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2396 type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2397 rc2 = llapi_obd_fstatfs(fd, type, index,
2398 &stat_buf, &uuid_buf);
2401 else if (rc2 == -EAGAIN)
2403 else if (rc2 == -ENODATA)
2404 ; /* Inactive device, OK. */
2405 else if (rc2 < 0 && rc == 0)
2408 if (poolname && tp->st_op == LL_STATFS_LOV &&
2409 llapi_search_ost(fsname, poolname,
2410 obd_uuid2str(&uuid_buf)) != 1)
2413 /* the llapi_obd_statfs() call may have returned with
2414 * an error, but if it filled in uuid_buf we will at
2415 * lease use that to print out a message for that OBD.
2416 * If we didn't get anything in the uuid_buf, then fill
2417 * it in so that we can print an error message. */
2418 if (uuid_buf.uuid[0] == '\0')
2419 sprintf(uuid_buf.uuid, "%s%04x",
2420 tp->st_name, index);
2421 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2422 ishow, cooked, tp->st_name, index, rc2);
2425 if (tp->st_op == LL_STATFS_LMV) {
2426 sum.os_ffree += stat_buf.os_ffree;
2427 sum.os_files += stat_buf.os_files;
2428 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2429 sum.os_blocks += stat_buf.os_blocks *
2431 sum.os_bfree += stat_buf.os_bfree *
2433 sum.os_bavail += stat_buf.os_bavail *
2435 ost_ffree += stat_buf.os_ffree;
2443 /* If we don't have as many objects free on the OST as inodes
2444 * on the MDS, we reduce the total number of inodes to
2445 * compensate, so that the "inodes in use" number is correct.
2446 * Matches ll_statfs_internal() so the results are consistent. */
2447 if (ost_ffree < sum.os_ffree) {
2448 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2449 sum.os_ffree = ost_ffree;
2452 showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2458 static int lfs_df(int argc, char **argv)
2460 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2461 int ishow = 0, cooked = 0;
2463 int c, rc = 0, index = 0;
2464 char fsname[PATH_MAX] = "", *pool_name = NULL;
2465 struct option long_opts[] = {
2466 {"pool", required_argument, 0, 'p'},
2467 {"lazy", 0, 0, 'l'},
2471 while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2489 if (optind < argc && !realpath(argv[optind], path)) {
2491 fprintf(stderr, "error: invalid path '%s': %s\n",
2492 argv[optind], strerror(-rc));
2496 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2497 /* Check if we have a mount point */
2498 if (mntdir[0] == '\0')
2501 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2502 if (rc || path[0] != '\0')
2504 fsname[0] = '\0'; /* avoid matching in next loop */
2505 mntdir[0] = '\0'; /* avoid matching in next loop */
2511 static int lfs_getname(int argc, char **argv)
2513 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2514 int rc = 0, index = 0, c;
2515 char buf[sizeof(struct obd_uuid)];
2517 while ((c = getopt(argc, argv, "h")) != -1)
2520 if (optind == argc) { /* no paths specified, get all paths. */
2521 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2522 rc = llapi_getname(mntdir, buf, sizeof(buf));
2525 "cannot get name for `%s': %s\n",
2526 mntdir, strerror(-rc));
2530 printf("%s %s\n", buf, mntdir);
2532 path[0] = fsname[0] = mntdir[0] = 0;
2534 } else { /* paths specified, only attempt to search these. */
2535 for (; optind < argc; optind++) {
2536 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2539 "cannot get name for `%s': %s\n",
2540 argv[optind], strerror(-rc));
2544 printf("%s %s\n", buf, argv[optind]);
2550 static int lfs_check(int argc, char **argv)
2553 char mntdir[PATH_MAX] = {'\0'};
2562 obd_types[0] = obd_type1;
2563 obd_types[1] = obd_type2;
2565 if (strcmp(argv[1], "osts") == 0) {
2566 strcpy(obd_types[0], "osc");
2567 } else if (strcmp(argv[1], "mds") == 0) {
2568 strcpy(obd_types[0], "mdc");
2569 } else if (strcmp(argv[1], "servers") == 0) {
2571 strcpy(obd_types[0], "osc");
2572 strcpy(obd_types[1], "mdc");
2574 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2579 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2580 if (rc < 0 || mntdir[0] == '\0') {
2581 fprintf(stderr, "No suitable Lustre mount found\n");
2585 rc = llapi_target_check(num_types, obd_types, mntdir);
2587 fprintf(stderr, "error: %s: %s status failed\n",
2594 static int lfs_join(int argc, char **argv)
2596 fprintf(stderr, "join two lustre files into one.\n"
2597 "obsolete, HEAD does not support it anymore.\n");
2601 #ifdef HAVE_SYS_QUOTA_H
2602 #define ARG2INT(nr, str, msg) \
2605 nr = strtol(str, &endp, 0); \
2607 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2612 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2614 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2615 * returns the value or ULONG_MAX on integer overflow or incorrect format
2617 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2618 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2619 * 3. empty integer value is interpreted as 0
2621 static unsigned long str2sec(const char* timestr)
2623 const char spec[] = "smhdw";
2624 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2625 unsigned long val = 0;
2628 if (strpbrk(timestr, spec) == NULL) {
2629 /* no specifiers inside the time string,
2630 should treat it as an integer value */
2631 val = strtoul(timestr, &tail, 10);
2632 return *tail ? ULONG_MAX : val;
2635 /* format string is XXwXXdXXhXXmXXs */
2641 v = strtoul(timestr, &tail, 10);
2642 if (v == ULONG_MAX || *tail == '\0')
2643 /* value too large (ULONG_MAX or more)
2644 or missing specifier */
2647 ptr = strchr(spec, *tail);
2649 /* unknown specifier */
2654 /* check if product will overflow the type */
2655 if (!(v < ULONG_MAX / mult[ind]))
2658 ADD_OVERFLOW(val, mult[ind] * v);
2659 if (val == ULONG_MAX)
2671 #define ARG2ULL(nr, str, def_units) \
2673 unsigned long long limit, units = def_units; \
2676 rc = llapi_parse_size(str, &limit, &units, 1); \
2678 fprintf(stderr, "error: bad limit value %s\n", str); \
2684 static inline int has_times_option(int argc, char **argv)
2688 for (i = 1; i < argc; i++)
2689 if (!strcmp(argv[i], "-t"))
2695 int lfs_setquota_times(int argc, char **argv)
2698 struct if_quotactl qctl;
2699 char *mnt, *obd_type = (char *)qctl.obd_type;
2700 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2701 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2702 struct option long_opts[] = {
2703 {"block-grace", required_argument, 0, 'b'},
2704 {"group", no_argument, 0, 'g'},
2705 {"inode-grace", required_argument, 0, 'i'},
2706 {"times", no_argument, 0, 't'},
2707 {"user", no_argument, 0, 'u'},
2711 memset(&qctl, 0, sizeof(qctl));
2712 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2713 qctl.qc_type = UGQUOTA;
2715 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2719 if (qctl.qc_type != UGQUOTA) {
2720 fprintf(stderr, "error: -u and -g can't be used "
2721 "more than once\n");
2724 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2727 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2728 fprintf(stderr, "error: bad block-grace: %s\n",
2732 dqb->dqb_valid |= QIF_BTIME;
2735 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2736 fprintf(stderr, "error: bad inode-grace: %s\n",
2740 dqb->dqb_valid |= QIF_ITIME;
2742 case 't': /* Yes, of course! */
2744 default: /* getopt prints error message for us when opterr != 0 */
2749 if (qctl.qc_type == UGQUOTA) {
2750 fprintf(stderr, "error: neither -u nor -g specified\n");
2754 if (optind != argc - 1) {
2755 fprintf(stderr, "error: unexpected parameters encountered\n");
2760 rc = llapi_quotactl(mnt, &qctl);
2763 fprintf(stderr, "%s %s ", obd_type,
2764 obd_uuid2str(&qctl.obd_uuid));
2765 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2772 #define BSLIMIT (1 << 0)
2773 #define BHLIMIT (1 << 1)
2774 #define ISLIMIT (1 << 2)
2775 #define IHLIMIT (1 << 3)
2777 int lfs_setquota(int argc, char **argv)
2780 struct if_quotactl qctl;
2781 char *mnt, *obd_type = (char *)qctl.obd_type;
2782 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2783 struct option long_opts[] = {
2784 {"block-softlimit", required_argument, 0, 'b'},
2785 {"block-hardlimit", required_argument, 0, 'B'},
2786 {"group", required_argument, 0, 'g'},
2787 {"inode-softlimit", required_argument, 0, 'i'},
2788 {"inode-hardlimit", required_argument, 0, 'I'},
2789 {"user", required_argument, 0, 'u'},
2792 unsigned limit_mask = 0;
2795 if (has_times_option(argc, argv))
2796 return lfs_setquota_times(argc, argv);
2798 memset(&qctl, 0, sizeof(qctl));
2799 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2800 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2801 * so it can be used as a marker that qc_type
2802 * isn't reinitialized from command line */
2804 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2808 if (qctl.qc_type != UGQUOTA) {
2809 fprintf(stderr, "error: -u and -g can't be used"
2810 " more than once\n");
2813 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2814 rc = name2id(&qctl.qc_id, optarg,
2815 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2817 qctl.qc_id = strtoul(optarg, &endptr, 10);
2818 if (*endptr != '\0') {
2819 fprintf(stderr, "error: can't find id "
2820 "for name %s\n", optarg);
2826 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2827 dqb->dqb_bsoftlimit >>= 10;
2828 limit_mask |= BSLIMIT;
2829 if (dqb->dqb_bsoftlimit &&
2830 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2831 fprintf(stderr, "warning: block softlimit is "
2832 "smaller than the miminal qunit size, "
2833 "please see the help of setquota or "
2834 "Lustre manual for details.\n");
2837 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2838 dqb->dqb_bhardlimit >>= 10;
2839 limit_mask |= BHLIMIT;
2840 if (dqb->dqb_bhardlimit &&
2841 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2842 fprintf(stderr, "warning: block hardlimit is "
2843 "smaller than the miminal qunit size, "
2844 "please see the help of setquota or "
2845 "Lustre manual for details.\n");
2848 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2849 limit_mask |= ISLIMIT;
2850 if (dqb->dqb_isoftlimit &&
2851 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2852 fprintf(stderr, "warning: inode softlimit is "
2853 "smaller than the miminal qunit size, "
2854 "please see the help of setquota or "
2855 "Lustre manual for details.\n");
2858 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2859 limit_mask |= IHLIMIT;
2860 if (dqb->dqb_ihardlimit &&
2861 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2862 fprintf(stderr, "warning: inode hardlimit is "
2863 "smaller than the miminal qunit size, "
2864 "please see the help of setquota or "
2865 "Lustre manual for details.\n");
2867 default: /* getopt prints error message for us when opterr != 0 */
2872 if (qctl.qc_type == UGQUOTA) {
2873 fprintf(stderr, "error: neither -u nor -g was specified\n");
2877 if (limit_mask == 0) {
2878 fprintf(stderr, "error: at least one limit must be specified\n");
2882 if (optind != argc - 1) {
2883 fprintf(stderr, "error: unexpected parameters encountered\n");
2889 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2890 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2891 /* sigh, we can't just set blimits/ilimits */
2892 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2893 .qc_type = qctl.qc_type,
2894 .qc_id = qctl.qc_id};
2896 rc = llapi_quotactl(mnt, &tmp_qctl);
2898 fprintf(stderr, "error: setquota failed while retrieving"
2899 " current quota settings (%s)\n",
2904 if (!(limit_mask & BHLIMIT))
2905 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2906 if (!(limit_mask & BSLIMIT))
2907 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2908 if (!(limit_mask & IHLIMIT))
2909 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2910 if (!(limit_mask & ISLIMIT))
2911 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2913 /* Keep grace times if we have got no softlimit arguments */
2914 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2915 dqb->dqb_valid |= QIF_BTIME;
2916 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2919 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2920 dqb->dqb_valid |= QIF_ITIME;
2921 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2925 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2926 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2928 rc = llapi_quotactl(mnt, &qctl);
2931 fprintf(stderr, "%s %s ", obd_type,
2932 obd_uuid2str(&qctl.obd_uuid));
2933 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2940 static inline char *type2name(int check_type)
2942 if (check_type == USRQUOTA)
2944 else if (check_type == GRPQUOTA)
2950 /* Converts seconds value into format string
2951 * result is returned in buf
2953 * 1. result is in descenting order: 1w2d3h4m5s
2954 * 2. zero fields are not filled (except for p. 3): 5d1s
2955 * 3. zero seconds value is presented as "0s"
2957 static char * __sec2str(time_t seconds, char *buf)
2959 const char spec[] = "smhdw";
2960 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2965 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2966 c = seconds / mult[i];
2968 if (c > 0 || (i == 0 && buf == tail))
2969 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2977 static void sec2str(time_t seconds, char *buf, int rc)
2984 tail = __sec2str(seconds, tail);
2986 if (rc && tail - buf < 39) {
2992 static void diff2str(time_t seconds, char *buf, time_t now)
2998 if (seconds <= now) {
2999 strcpy(buf, "none");
3002 __sec2str(seconds - now, buf);
3005 static void print_quota_title(char *name, struct if_quotactl *qctl,
3006 bool human_readable)
3008 printf("Disk quotas for %s %s (%cid %u):\n",
3009 type2name(qctl->qc_type), name,
3010 *type2name(qctl->qc_type), qctl->qc_id);
3011 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3012 "Filesystem", human_readable ? "used" : "kbytes",
3013 "quota", "limit", "grace",
3014 "files", "quota", "limit", "grace");
3017 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3020 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3023 snprintf(buf, buflen, "%5.4gP",
3024 (double)num / ((__u64)1 << 40));
3026 snprintf(buf, buflen, "%5.4gT",
3027 (double)num / (1 << 30));
3029 snprintf(buf, buflen, "%5.4gG",
3030 (double)num / (1 << 20));
3032 snprintf(buf, buflen, "%5.4gM",
3033 (double)num / (1 << 10));
3035 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3039 #define STRBUF_LEN 32
3040 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3047 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3048 int bover = 0, iover = 0;
3049 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3050 char numbuf[3][STRBUF_LEN];
3052 char strbuf[STRBUF_LEN];
3054 if (dqb->dqb_bhardlimit &&
3055 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3057 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3058 if (dqb->dqb_btime > now) {
3065 if (dqb->dqb_ihardlimit &&
3066 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3068 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3069 if (dqb->dqb_itime > now) {
3077 if (strlen(mnt) > 15)
3078 printf("%s\n%15s", mnt, "");
3080 printf("%15s", mnt);
3083 diff2str(dqb->dqb_btime, timebuf, now);
3085 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3086 strbuf, sizeof(strbuf), h);
3087 if (rc == -EREMOTEIO)
3088 sprintf(numbuf[0], "%s*", strbuf);
3090 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3091 "%s" : "[%s]", strbuf);
3093 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3094 if (type == QC_GENERAL)
3095 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3096 "%s" : "[%s]", strbuf);
3098 sprintf(numbuf[1], "%s", "-");
3100 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3101 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3102 "%s" : "[%s]", strbuf);
3104 printf(" %7s%c %6s %7s %7s",
3105 numbuf[0], bover ? '*' : ' ', numbuf[1],
3106 numbuf[2], bover > 1 ? timebuf : "-");
3109 diff2str(dqb->dqb_itime, timebuf, now);
3111 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3112 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3114 if (type == QC_GENERAL)
3115 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3117 (uintmax_t)dqb->dqb_isoftlimit);
3119 sprintf(numbuf[1], "%s", "-");
3121 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3122 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3124 if (type != QC_OSTIDX)
3125 printf(" %7s%c %6s %7s %7s",
3126 numbuf[0], iover ? '*' : ' ', numbuf[1],
3127 numbuf[2], iover > 1 ? timebuf : "-");
3129 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3132 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3133 qctl->qc_cmd == Q_GETOINFO) {
3137 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3138 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3139 printf("Block grace time: %s; Inode grace time: %s\n",
3140 bgtimebuf, igtimebuf);
3144 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3145 bool h, __u64 *total)
3147 int rc = 0, rc1 = 0, count = 0;
3148 __u32 valid = qctl->qc_valid;
3150 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3152 fprintf(stderr, "can not get %s count: %s\n",
3153 is_mdt ? "mdt": "ost", strerror(-rc));
3157 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3158 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3159 rc = llapi_quotactl(mnt, qctl);
3161 /* It is remote client case. */
3162 if (-rc == EOPNOTSUPP) {
3169 fprintf(stderr, "quotactl %s%d failed.\n",
3170 is_mdt ? "mdt": "ost", qctl->qc_idx);
3174 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3175 qctl->qc_valid, 0, h);
3176 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3177 qctl->qc_dqblk.dqb_bhardlimit;
3180 qctl->qc_valid = valid;
3184 static int lfs_quota(int argc, char **argv)
3187 char *mnt, *name = NULL;
3188 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3189 .qc_type = UGQUOTA };
3190 char *obd_type = (char *)qctl.obd_type;
3191 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3192 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
3193 verbose = 0, pass = 0, quiet = 0, inacc;
3195 __u32 valid = QC_GENERAL, idx = 0;
3196 __u64 total_ialloc = 0, total_balloc = 0;
3197 bool human_readable = false;
3199 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3202 if (qctl.qc_type != UGQUOTA) {
3203 fprintf(stderr, "error: use either -u or -g\n");
3206 qctl.qc_type = USRQUOTA;
3209 if (qctl.qc_type != UGQUOTA) {
3210 fprintf(stderr, "error: use either -u or -g\n");
3213 qctl.qc_type = GRPQUOTA;
3216 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3219 valid = qctl.qc_valid = QC_UUID;
3220 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3223 valid = qctl.qc_valid = QC_MDTIDX;
3224 idx = qctl.qc_idx = atoi(optarg);
3227 valid = qctl.qc_valid = QC_OSTIDX;
3228 idx = qctl.qc_idx = atoi(optarg);
3237 human_readable = true;
3240 fprintf(stderr, "error: %s: option '-%c' "
3241 "unrecognized\n", argv[0], c);
3246 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3247 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3248 optind == argc - 1) {
3250 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3251 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3252 qctl.qc_valid = valid;
3255 qctl.qc_type = USRQUOTA;
3256 qctl.qc_id = geteuid();
3258 qctl.qc_type = GRPQUOTA;
3259 qctl.qc_id = getegid();
3261 rc = id2name(&name, qctl.qc_id,
3262 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3265 /* lfs quota -u username /path/to/lustre/mount */
3266 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3267 /* options should be followed by u/g-name and mntpoint */
3268 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3269 fprintf(stderr, "error: missing quota argument(s)\n");
3273 name = argv[optind++];
3274 rc = name2id(&qctl.qc_id, name,
3275 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3277 qctl.qc_id = strtoul(name, &endptr, 10);
3278 if (*endptr != '\0') {
3279 fprintf(stderr, "error: can't find id for name "
3284 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3285 fprintf(stderr, "error: missing quota info argument(s)\n");
3291 rc1 = llapi_quotactl(mnt, &qctl);
3295 fprintf(stderr, "%s quotas are not enabled.\n",
3296 qctl.qc_type == USRQUOTA ? "user" : "group");
3299 fprintf(stderr, "Permission denied.\n");
3302 /* We already got error message. */
3305 fprintf(stderr, "Unexpected quotactl error: %s\n",
3310 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3311 print_quota_title(name, &qctl, human_readable);
3313 if (rc1 && *obd_type)
3314 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3316 if (qctl.qc_valid != QC_GENERAL)
3319 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3320 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3321 (QIF_LIMITS|QIF_USAGE));
3323 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3325 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3327 char strbuf[STRBUF_LEN];
3329 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3331 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3333 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
3335 printf("Total allocated inode limit: %ju, total "
3336 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
3340 if (rc1 || rc2 || rc3 || inacc)
3341 printf("Some errors happened when getting quota info. "
3342 "Some devices may be not working or deactivated. "
3343 "The data in \"[]\" is inaccurate.\n");
3351 #endif /* HAVE_SYS_QUOTA_H! */
3353 static int flushctx_ioctl(char *mp)
3357 fd = open(mp, O_RDONLY);
3359 fprintf(stderr, "flushctx: error open %s: %s\n",
3360 mp, strerror(errno));
3364 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3366 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3367 mp, strerror(errno));
3373 static int lfs_flushctx(int argc, char **argv)
3375 int kdestroy = 0, c;
3376 char mntdir[PATH_MAX] = {'\0'};
3380 while ((c = getopt(argc, argv, "k")) != -1) {
3386 fprintf(stderr, "error: %s: option '-%c' "
3387 "unrecognized\n", argv[0], c);
3393 if ((rc = system("kdestroy > /dev/null")) != 0) {
3394 rc = WEXITSTATUS(rc);
3395 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3399 if (optind >= argc) {
3400 /* flush for all mounted lustre fs. */
3401 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3402 /* Check if we have a mount point */
3403 if (mntdir[0] == '\0')
3406 if (flushctx_ioctl(mntdir))
3409 mntdir[0] = '\0'; /* avoid matching in next loop */
3412 /* flush fs as specified */
3413 while (optind < argc) {
3414 if (flushctx_ioctl(argv[optind++]))
3421 static int lfs_lsetfacl(int argc, char **argv)
3423 fprintf(stderr, "local client sets facl for remote client.\n"
3424 "obsolete, does not support it anymore.\n");
3428 static int lfs_lgetfacl(int argc, char **argv)
3430 fprintf(stderr, "local client gets facl for remote client.\n"
3431 "obsolete, does not support it anymore.\n");
3435 static int lfs_rsetfacl(int argc, char **argv)
3437 fprintf(stderr, "remote client sets facl for remote client.\n"
3438 "obsolete, does not support it anymore.\n");
3442 static int lfs_rgetfacl(int argc, char **argv)
3444 fprintf(stderr, "remote client gets facl for remote client.\n"
3445 "obsolete, does not support it anymore.\n");
3449 static int lfs_cp(int argc, char **argv)
3451 fprintf(stderr, "remote client copy file(s).\n"
3452 "obsolete, does not support it anymore.\n");
3456 static int lfs_ls(int argc, char **argv)
3458 fprintf(stderr, "remote client lists directory contents.\n"
3459 "obsolete, does not support it anymore.\n");
3463 static int lfs_changelog(int argc, char **argv)
3465 void *changelog_priv;
3466 struct changelog_rec *rec;
3467 long long startrec = 0, endrec = 0;
3469 struct option long_opts[] = {
3470 {"follow", no_argument, 0, 'f'},
3473 char short_opts[] = "f";
3476 while ((rc = getopt_long(argc, argv, short_opts,
3477 long_opts, NULL)) != -1) {
3485 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3486 argv[0], argv[optind - 1]);
3493 mdd = argv[optind++];
3495 startrec = strtoll(argv[optind++], NULL, 10);
3497 endrec = strtoll(argv[optind++], NULL, 10);
3499 rc = llapi_changelog_start(&changelog_priv,
3500 CHANGELOG_FLAG_BLOCK |
3501 CHANGELOG_FLAG_JOBID |
3502 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3505 fprintf(stderr, "Can't start changelog: %s\n",
3506 strerror(errno = -rc));
3510 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3514 if (endrec && rec->cr_index > endrec) {
3515 llapi_changelog_free(&rec);
3518 if (rec->cr_index < startrec) {
3519 llapi_changelog_free(&rec);
3523 secs = rec->cr_time >> 30;
3524 gmtime_r(&secs, &ts);
3525 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3526 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
3527 changelog_type2str(rec->cr_type),
3528 ts.tm_hour, ts.tm_min, ts.tm_sec,
3529 (int)(rec->cr_time & ((1<<30) - 1)),
3530 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3531 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3533 if (rec->cr_flags & CLF_JOBID) {
3534 struct changelog_ext_jobid *jid =
3535 changelog_rec_jobid(rec);
3537 if (jid->cr_jobid[0] != '\0')
3538 printf(" j=%s", jid->cr_jobid);
3541 if (rec->cr_namelen)
3542 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3543 rec->cr_namelen, changelog_rec_name(rec));
3545 if (rec->cr_flags & CLF_RENAME) {
3546 struct changelog_ext_rename *rnm =
3547 changelog_rec_rename(rec);
3549 if (!fid_is_zero(&rnm->cr_sfid))
3550 printf(" s="DFID" sp="DFID" %.*s",
3551 PFID(&rnm->cr_sfid),
3552 PFID(&rnm->cr_spfid),
3553 (int)changelog_rec_snamelen(rec),
3554 changelog_rec_sname(rec));
3558 llapi_changelog_free(&rec);
3561 llapi_changelog_fini(&changelog_priv);
3564 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3566 return (rc == 1 ? 0 : rc);
3569 static int lfs_changelog_clear(int argc, char **argv)
3577 endrec = strtoll(argv[3], NULL, 10);
3579 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3581 fprintf(stderr, "%s error: %s\n", argv[0],
3582 strerror(errno = -rc));
3586 static int lfs_fid2path(int argc, char **argv)
3588 struct option long_opts[] = {
3589 {"cur", no_argument, 0, 'c'},
3590 {"link", required_argument, 0, 'l'},
3591 {"rec", required_argument, 0, 'r'},
3594 char short_opts[] = "cl:r:";
3595 char *device, *fid, *path;
3596 long long recno = -1;
3602 while ((rc = getopt_long(argc, argv, short_opts,
3603 long_opts, NULL)) != -1) {
3609 linkno = strtol(optarg, NULL, 10);
3612 recno = strtoll(optarg, NULL, 10);
3617 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3618 argv[0], argv[optind - 1]);
3626 device = argv[optind++];
3627 path = calloc(1, PATH_MAX);
3629 fprintf(stderr, "error: Not enough memory\n");
3634 while (optind < argc) {
3635 fid = argv[optind++];
3637 lnktmp = (linkno >= 0) ? linkno : 0;
3639 int oldtmp = lnktmp;
3640 long long rectmp = recno;
3642 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3645 fprintf(stderr, "%s: error on FID %s: %s\n",
3646 argv[0], fid, strerror(errno = -rc2));
3653 fprintf(stdout, "%lld ", rectmp);
3654 if (device[0] == '/') {
3655 fprintf(stdout, "%s", device);
3656 if (device[strlen(device) - 1] != '/')
3657 fprintf(stdout, "/");
3658 } else if (path[0] == '\0') {
3659 fprintf(stdout, "/");
3661 fprintf(stdout, "%s\n", path);
3664 /* specified linkno */
3666 if (oldtmp == lnktmp)
3676 static int lfs_path2fid(int argc, char **argv)
3678 struct option long_opts[] = {
3679 {"parents", no_argument, 0, 'p'},
3683 const char short_opts[] = "p";
3684 const char *sep = "";
3687 bool show_parents = false;
3689 while ((rc = getopt_long(argc, argv, short_opts,
3690 long_opts, NULL)) != -1) {
3693 show_parents = true;
3696 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3697 argv[0], argv[optind - 1]);
3702 if (optind > argc - 1)
3704 else if (optind < argc - 1)
3708 for (path = argv + optind; *path != NULL; path++) {
3710 if (!show_parents) {
3711 err = llapi_path2fid(*path, &fid);
3713 printf("%s%s"DFID"\n",
3714 *sep != '\0' ? *path : "", sep,
3717 char name[NAME_MAX + 1];
3718 unsigned int linkno = 0;
3720 while ((err = llapi_path2parent(*path, linkno, &fid,
3721 name, sizeof(name))) == 0) {
3722 if (*sep != '\0' && linkno == 0)
3723 printf("%s%s", *path, sep);
3725 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3730 /* err == -ENODATA is end-of-loop */
3731 if (linkno > 0 && err == -ENODATA) {
3738 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3739 argv[0], show_parents ? "parent " : "", *path,
3751 static int lfs_data_version(int argc, char **argv)
3758 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3763 while ((c = getopt(argc, argv, "nrw")) != -1) {
3766 data_version_flags = 0;
3769 data_version_flags |= LL_DV_RD_FLUSH;
3772 data_version_flags |= LL_DV_WR_FLUSH;
3781 path = argv[optind];
3782 fd = open(path, O_RDONLY);
3784 err(errno, "cannot open file %s", path);
3786 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3788 err(errno, "cannot get version for %s", path);
3790 printf("%ju" "\n", (uintmax_t)data_version);
3796 static int lfs_hsm_state(int argc, char **argv)
3801 struct hsm_user_state hus;
3809 rc = llapi_hsm_state_get(path, &hus);
3811 fprintf(stderr, "can't get hsm state for %s: %s\n",
3812 path, strerror(errno = -rc));
3816 /* Display path name and status flags */
3817 printf("%s: (0x%08x)", path, hus.hus_states);
3819 if (hus.hus_states & HS_RELEASED)
3820 printf(" released");
3821 if (hus.hus_states & HS_EXISTS)
3823 if (hus.hus_states & HS_DIRTY)
3825 if (hus.hus_states & HS_ARCHIVED)
3826 printf(" archived");
3827 /* Display user-settable flags */
3828 if (hus.hus_states & HS_NORELEASE)
3829 printf(" never_release");
3830 if (hus.hus_states & HS_NOARCHIVE)
3831 printf(" never_archive");
3832 if (hus.hus_states & HS_LOST)
3833 printf(" lost_from_hsm");
3835 if (hus.hus_archive_id != 0)
3836 printf(", archive_id:%d", hus.hus_archive_id);
3839 } while (++i < argc);
3844 #define LFS_HSM_SET 0
3845 #define LFS_HSM_CLEAR 1
3848 * Generic function to set or clear HSM flags.
3849 * Used by hsm_set and hsm_clear.
3851 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3853 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3855 struct option long_opts[] = {
3856 {"lost", 0, 0, 'l'},
3857 {"norelease", 0, 0, 'r'},
3858 {"noarchive", 0, 0, 'a'},
3859 {"archived", 0, 0, 'A'},
3860 {"dirty", 0, 0, 'd'},
3861 {"exists", 0, 0, 'e'},
3864 char short_opts[] = "lraAde";
3872 while ((c = getopt_long(argc, argv, short_opts,
3873 long_opts, NULL)) != -1) {
3879 mask |= HS_NOARCHIVE;
3882 mask |= HS_ARCHIVED;
3885 mask |= HS_NORELEASE;
3896 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3897 argv[0], argv[optind - 1]);
3902 /* User should have specified a flag */
3906 while (optind < argc) {
3908 path = argv[optind];
3910 /* If mode == 0, this means we apply the mask. */
3911 if (mode == LFS_HSM_SET)
3912 rc = llapi_hsm_state_set(path, mask, 0, 0);
3914 rc = llapi_hsm_state_set(path, 0, mask, 0);
3917 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3918 path, strerror(errno = -rc));
3927 static int lfs_hsm_action(int argc, char **argv)
3932 struct hsm_current_action hca;
3933 struct hsm_extent he;
3934 enum hsm_user_action hua;
3935 enum hsm_progress_states hps;
3943 rc = llapi_hsm_current_action(path, &hca);
3945 fprintf(stderr, "can't get hsm action for %s: %s\n",
3946 path, strerror(errno = -rc));
3949 he = hca.hca_location;
3950 hua = hca.hca_action;
3951 hps = hca.hca_state;
3953 printf("%s: %s", path, hsm_user_action2name(hua));
3955 /* Skip file without action */
3956 if (hca.hca_action == HUA_NONE) {
3961 printf(" %s ", hsm_progress_state2name(hps));
3963 if ((hps == HPS_RUNNING) &&
3964 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3965 printf("(%llu bytes moved)\n",
3966 (unsigned long long)he.length);
3967 else if ((he.offset + he.length) == LUSTRE_EOF)
3968 printf("(from %llu to EOF)\n",
3969 (unsigned long long)he.offset);
3971 printf("(from %llu to %llu)\n",
3972 (unsigned long long)he.offset,
3973 (unsigned long long)(he.offset + he.length));
3975 } while (++i < argc);
3980 static int lfs_hsm_set(int argc, char **argv)
3982 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3985 static int lfs_hsm_clear(int argc, char **argv)
3987 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3991 * Check file state and return its fid, to be used by lfs_hsm_request().
3993 * \param[in] file Path to file to check
3994 * \param[in,out] fid Pointer to allocated lu_fid struct.
3995 * \param[in,out] last_dev Pointer to last device id used.
3997 * \return 0 on success.
3999 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4005 rc = lstat(file, &st);
4007 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4010 /* Checking for regular file as archiving as posix copytool
4011 * rejects archiving files other than regular files
4013 if (!S_ISREG(st.st_mode)) {
4014 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4017 /* A request should be ... */
4018 if (*last_dev != st.st_dev && *last_dev != 0) {
4019 fprintf(stderr, "All files should be "
4020 "on the same filesystem: %s\n", file);
4023 *last_dev = st.st_dev;
4025 rc = llapi_path2fid(file, fid);
4027 fprintf(stderr, "Cannot read FID of %s: %s\n",
4028 file, strerror(-rc));
4034 /* Fill an HSM HUR item with a given file name.
4036 * If mntpath is set, then the filename is actually a FID, and no
4037 * lookup on the filesystem will be performed.
4039 * \param[in] hur the user request to fill
4040 * \param[in] idx index of the item inside the HUR to fill
4041 * \param[in] mntpath mountpoint of Lustre
4042 * \param[in] fname filename (if mtnpath is NULL)
4043 * or FID (if mntpath is set)
4044 * \param[in] last_dev pointer to last device id used
4046 * \retval 0 on success
4047 * \retval CMD_HELP or a negative errno on error
4049 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4050 const char *mntpath, const char *fname,
4053 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4056 hui->hui_extent.length = -1;
4058 if (mntpath != NULL) {
4061 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4065 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4070 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4074 hur->hur_request.hr_itemcount++;
4079 static int lfs_hsm_request(int argc, char **argv, int action)
4081 struct option long_opts[] = {
4082 {"filelist", 1, 0, 'l'},
4083 {"data", 1, 0, 'D'},
4084 {"archive", 1, 0, 'a'},
4085 {"mntpath", 1, 0, 'm'},
4089 char short_opts[] = "l:D:a:m:";
4090 struct hsm_user_request *hur, *oldhur;
4095 char *filelist = NULL;
4096 char fullpath[PATH_MAX];
4097 char *opaque = NULL;
4101 int nbfile_alloc = 0;
4102 char *some_file = NULL;
4103 char *mntpath = NULL;
4109 while ((c = getopt_long(argc, argv, short_opts,
4110 long_opts, NULL)) != -1) {
4119 if (action != HUA_ARCHIVE &&
4120 action != HUA_REMOVE) {
4122 "error: -a is supported only "
4123 "when archiving or removing\n");
4126 archive_id = atoi(optarg);
4129 if (some_file == NULL) {
4131 some_file = strdup(optarg);
4137 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4138 argv[0], argv[optind - 1]);
4143 /* All remaining args are files, so we have at least nbfile */
4144 nbfile = argc - optind;
4146 if ((nbfile == 0) && (filelist == NULL))
4150 opaque_len = strlen(opaque);
4152 /* Alloc the request structure with enough place to store all files
4153 * from command line. */
4154 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4156 fprintf(stderr, "Cannot create the request: %s\n",
4160 nbfile_alloc = nbfile;
4162 hur->hur_request.hr_action = action;
4163 hur->hur_request.hr_archive_id = archive_id;
4164 hur->hur_request.hr_flags = 0;
4166 /* All remaining args are files, add them */
4167 if (nbfile != 0 && some_file == NULL)
4168 some_file = strdup(argv[optind]);
4170 for (i = 0; i < nbfile; i++) {
4171 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4177 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4179 /* If a filelist was specified, read the filelist from it. */
4180 if (filelist != NULL) {
4181 fp = fopen(filelist, "r");
4183 fprintf(stderr, "Cannot read the file list %s: %s\n",
4184 filelist, strerror(errno));
4189 while ((rc = getline(&line, &len, fp)) != -1) {
4190 /* If allocated buffer was too small, get something
4192 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4195 nbfile_alloc = nbfile_alloc * 2 + 1;
4197 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4200 fprintf(stderr, "hsm: cannot allocate "
4201 "the request: %s\n",
4208 size = hur_len(oldhur);
4210 fprintf(stderr, "hsm: cannot allocate "
4211 "%u files + %u bytes data\n",
4212 oldhur->hur_request.hr_itemcount,
4213 oldhur->hur_request.hr_data_len);
4220 memcpy(hur, oldhur, size);
4225 if (line[strlen(line) - 1] == '\n')
4226 line[strlen(line) - 1] = '\0';
4228 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4229 mntpath, line, &last_dev);
4235 if (some_file == NULL) {
4245 /* If a --data was used, add it to the request */
4246 hur->hur_request.hr_data_len = opaque_len;
4248 memcpy(hur_data(hur), opaque, opaque_len);
4250 /* Send the HSM request */
4251 if (realpath(some_file, fullpath) == NULL) {
4252 fprintf(stderr, "Could not find path '%s': %s\n",
4253 some_file, strerror(errno));
4255 rc = llapi_hsm_request(fullpath, hur);
4257 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4258 some_file, strerror(-rc));
4268 static int lfs_hsm_archive(int argc, char **argv)
4270 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4273 static int lfs_hsm_restore(int argc, char **argv)
4275 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4278 static int lfs_hsm_release(int argc, char **argv)
4280 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4283 static int lfs_hsm_remove(int argc, char **argv)
4285 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4288 static int lfs_hsm_cancel(int argc, char **argv)
4290 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4293 static int lfs_swap_layouts(int argc, char **argv)
4298 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4299 SWAP_LAYOUTS_KEEP_MTIME |
4300 SWAP_LAYOUTS_KEEP_ATIME);
4303 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
4305 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
4307 enum lu_ladvise_type advice;
4310 advice < ARRAY_SIZE(ladvise_names); advice++) {
4311 if (ladvise_names[advice] == NULL)
4313 if (strcmp(string, ladvise_names[advice]) == 0)
4317 return LU_LADVISE_INVALID;
4320 static int lfs_ladvise(int argc, char **argv)
4322 struct option long_opts[] = {
4323 {"advice", required_argument, 0, 'a'},
4324 {"background", no_argument, 0, 'b'},
4325 {"end", required_argument, 0, 'e'},
4326 {"start", required_argument, 0, 's'},
4327 {"length", required_argument, 0, 'l'},
4330 char short_opts[] = "a:be:l:s:";
4335 struct llapi_lu_ladvise advice;
4336 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
4337 unsigned long long start = 0;
4338 unsigned long long end = LUSTRE_EOF;
4339 unsigned long long length = 0;
4340 unsigned long long size_units;
4341 unsigned long long flags = 0;
4344 while ((c = getopt_long(argc, argv, short_opts,
4345 long_opts, NULL)) != -1) {
4348 advice_type = lfs_get_ladvice(optarg);
4349 if (advice_type == LU_LADVISE_INVALID) {
4350 fprintf(stderr, "%s: invalid advice type "
4351 "'%s'\n", argv[0], optarg);
4352 fprintf(stderr, "Valid types:");
4354 for (advice_type = 0;
4355 advice_type < ARRAY_SIZE(ladvise_names);
4357 if (ladvise_names[advice_type] == NULL)
4359 fprintf(stderr, " %s",
4360 ladvise_names[advice_type]);
4362 fprintf(stderr, "\n");
4372 rc = llapi_parse_size(optarg, &end,
4375 fprintf(stderr, "%s: bad end offset '%s'\n",
4382 rc = llapi_parse_size(optarg, &start,
4385 fprintf(stderr, "%s: bad start offset "
4386 "'%s'\n", argv[0], optarg);
4392 rc = llapi_parse_size(optarg, &length,
4395 fprintf(stderr, "%s: bad length '%s'\n",
4403 fprintf(stderr, "%s: option '%s' unrecognized\n",
4404 argv[0], argv[optind - 1]);
4409 if (advice_type == LU_LADVISE_INVALID) {
4410 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
4411 fprintf(stderr, "Valid types:");
4412 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
4414 if (ladvise_names[advice_type] == NULL)
4416 fprintf(stderr, " %s", ladvise_names[advice_type]);
4418 fprintf(stderr, "\n");
4422 if (argc <= optind) {
4423 fprintf(stderr, "%s: please give one or more file names\n",
4428 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
4429 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
4434 if (end == LUSTRE_EOF && length != 0)
4435 end = start + length;
4438 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
4439 argv[0], start, end);
4443 while (optind < argc) {
4446 path = argv[optind++];
4448 fd = open(path, O_RDONLY);
4450 fprintf(stderr, "%s: cannot open file '%s': %s\n",
4451 argv[0], path, strerror(errno));
4456 advice.lla_start = start;
4457 advice.lla_end = end;
4458 advice.lla_advice = advice_type;
4459 advice.lla_value1 = 0;
4460 advice.lla_value2 = 0;
4461 advice.lla_value3 = 0;
4462 advice.lla_value4 = 0;
4463 rc2 = llapi_ladvise(fd, flags, 1, &advice);
4466 fprintf(stderr, "%s: cannot give advice '%s' to file "
4467 "'%s': %s\n", argv[0],
4468 ladvise_names[advice_type],
4469 path, strerror(errno));
4472 if (rc == 0 && rc2 < 0)
4478 int main(int argc, char **argv)
4482 /* Ensure that liblustreapi constructor has run */
4483 if (!liblustreapi_initialized)
4484 fprintf(stderr, "liblustreapi was not properly initialized\n");
4488 Parser_init("lfs > ", cmdlist);
4490 progname = argv[0]; /* Used in error messages */
4492 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4494 rc = Parser_commands();
4497 return rc < 0 ? -rc : rc;
4500 #ifdef _LUSTRE_IDL_H_
4501 /* Everything we need here should be included by lustreapi.h. */
4502 # error "lfs should not depend on lustre_idl.h"
4503 #endif /* _LUSTRE_IDL_H_ */