4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
57 #include <sys/types.h>
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 /* In case the MDT does not support creation of volatile files
759 * we should try to unlink it. */
760 (void)unlink(volatile_file);
762 /* Not-owner (root?) special case.
763 * Need to set owner/group of volatile file like original.
764 * This will allow to pass related check during layout_swap.
769 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
773 rc = fstat(fdv, &stv);
776 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
777 volatile_file, strerror(errno));
780 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
781 rc = fchown(fdv, st.st_uid, st.st_gid);
784 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
785 name, strerror(errno));
790 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
791 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
793 have_lease_rdlck = false;
794 fdv = -1; /* The volatile file is closed as we put the
795 * lease in non-blocking mode. */
798 /* Blocking mode (forced if servers do not support file lease).
799 * It is also the default mode, since we cannot distinguish
800 * between a broken lease and a server that does not support
801 * atomic swap/close (LU-6785) */
802 rc = migrate_block(fd, fdv, &st, buf_size, name);
806 if (have_lease_rdlck)
823 * Parse a string containing an OST index list into an array of integers.
825 * The input string contains a comma delimited list of individual
826 * indices and ranges, for example "1,2-4,7". Add the indices into the
827 * \a osts array and remove duplicates.
829 * \param[out] osts array to store indices in
830 * \param[in] size size of \a osts array
831 * \param[in] offset starting index in \a osts
832 * \param[in] arg string containing OST index list
834 * \retval positive number of indices in \a osts
835 * \retval -EINVAL unable to parse \a arg
837 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
841 int slots = size - offset;
849 while (!end_of_loop) {
857 ptr = strchrnul(arg, ',');
859 end_of_loop = *ptr == '\0';
862 start_index = strtol(arg, &endptr, 0);
863 if (endptr == arg) /* no data at all */
865 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
870 end_index = start_index;
871 if (*endptr == '-') {
872 end_index = strtol(endptr + 1, &endptr, 0);
875 if (end_index < start_index)
879 for (i = start_index; i <= end_index && slots > 0; i++) {
882 /* remove duplicate */
883 for (j = 0; j < offset; j++) {
887 if (j == offset) { /* no duplicate */
892 if (slots == 0 && i < end_index)
900 if (!end_of_loop && ptr != NULL)
903 return rc < 0 ? rc : nr;
907 static int lfs_setstripe(int argc, char **argv)
909 struct llapi_stripe_param *param = NULL;
910 struct find_param migrate_mdt_param = {
917 unsigned long long st_size;
918 int st_offset, st_count;
922 char *stripe_size_arg = NULL;
923 char *stripe_off_arg = NULL;
924 char *stripe_count_arg = NULL;
925 char *pool_name_arg = NULL;
926 char *mdt_idx_arg = NULL;
927 unsigned long long size_units = 1;
928 bool migrate_mode = false;
929 bool migration_block = false;
930 __u64 migration_flags = 0;
931 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
934 struct option long_opts[] = {
935 /* --block is only valid in migrate mode */
936 {"block", no_argument, 0, 'b'},
937 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
938 /* This formerly implied "stripe-count", but was explicitly
939 * made "stripe-count" for consistency with other options,
940 * and to separate it from "mdt-count" when DNE arrives. */
941 {"count", required_argument, 0, 'c'},
943 {"stripe-count", required_argument, 0, 'c'},
944 {"stripe_count", required_argument, 0, 'c'},
945 {"delete", no_argument, 0, 'd'},
946 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
947 /* This formerly implied "stripe-index", but was explicitly
948 * made "stripe-index" for consistency with other options,
949 * and to separate it from "mdt-index" when DNE arrives. */
950 {"index", required_argument, 0, 'i'},
952 {"stripe-index", required_argument, 0, 'i'},
953 {"stripe_index", required_argument, 0, 'i'},
954 {"mdt", required_argument, 0, 'm'},
955 {"mdt-index", required_argument, 0, 'm'},
956 {"mdt_index", required_argument, 0, 'm'},
957 /* --non-block is only valid in migrate mode */
958 {"non-block", no_argument, 0, 'n'},
959 {"ost", required_argument, 0, 'o'},
960 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
961 {"ost-list", required_argument, 0, 'o'},
962 {"ost_list", required_argument, 0, 'o'},
964 {"pool", required_argument, 0, 'p'},
965 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
966 /* This formerly implied "--stripe-size", but was confusing
967 * with "lfs find --size|-s", which means "file size", so use
968 * the consistent "--stripe-size|-S" for all commands. */
969 {"size", required_argument, 0, 's'},
971 {"stripe-size", required_argument, 0, 'S'},
972 {"stripe_size", required_argument, 0, 'S'},
973 /* --verbose is only valid in migrate mode */
974 {"verbose", no_argument, 0, 'v'},
982 if (strcmp(argv[0], "migrate") == 0)
985 while ((c = getopt_long(argc, argv, "bc:di:m:no:p:s:S:v",
986 long_opts, NULL)) >= 0) {
993 fprintf(stderr, "--block is valid only for"
997 migration_block = true;
1000 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1001 if (strcmp(argv[optind - 1], "--count") == 0)
1002 fprintf(stderr, "warning: '--count' deprecated"
1003 ", use '--stripe-count' instead\n");
1005 stripe_count_arg = optarg;
1008 /* delete the default striping pattern */
1012 nr_osts = parse_targets(osts,
1013 sizeof(osts) / sizeof(__u32),
1017 "error: %s: bad OST indices '%s'\n",
1022 if (st_offset == -1) /* first in the command line */
1023 st_offset = osts[0];
1026 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1027 if (strcmp(argv[optind - 1], "--index") == 0)
1028 fprintf(stderr, "warning: '--index' deprecated"
1029 ", use '--stripe-index' instead\n");
1031 stripe_off_arg = optarg;
1034 if (!migrate_mode) {
1035 fprintf(stderr, "--mdt-index is valid only for"
1039 mdt_idx_arg = optarg;
1042 if (!migrate_mode) {
1043 fprintf(stderr, "--non-block is valid only for"
1047 migration_flags |= MIGRATION_NONBLOCK;
1049 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1051 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1052 fprintf(stderr, "warning: '--size|-s' deprecated, "
1053 "use '--stripe-size|-S' instead\n");
1055 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1057 stripe_size_arg = optarg;
1060 pool_name_arg = optarg;
1063 if (!migrate_mode) {
1064 fprintf(stderr, "--verbose is valid only for"
1068 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1075 fname = argv[optind];
1078 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
1079 stripe_count_arg != NULL || pool_name_arg != NULL)) {
1080 fprintf(stderr, "error: %s: cannot specify -d with "
1081 "-s, -c, -o, or -p options\n",
1086 if (optind == argc) {
1087 fprintf(stderr, "error: %s: missing filename|dirname\n",
1092 if (mdt_idx_arg != NULL && optind > 3) {
1093 fprintf(stderr, "error: %s: cannot specify -m with other "
1094 "options\n", argv[0]);
1098 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1100 "error: %s: cannot specify --non-block and --block\n",
1105 if (pool_name_arg != NULL) {
1109 ptr = strchr(pool_name_arg, '.');
1111 ptr = pool_name_arg;
1113 if ((ptr - pool_name_arg) == 0) {
1114 fprintf(stderr, "error: %s: fsname is empty "
1115 "in pool name '%s'\n",
1116 argv[0], pool_name_arg);
1123 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1125 fprintf(stderr, "error: %s: poolname '%s' is "
1127 argv[0], pool_name_arg);
1129 } else if (rc == -2) {
1130 fprintf(stderr, "error: %s: pool name '%s' is too long "
1131 "(max is %d characters)\n",
1132 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1134 } else if (rc > 0) {
1135 fprintf(stderr, "error: %s: char '%c' not allowed in "
1137 argv[0], rc, pool_name_arg);
1142 /* get the stripe size */
1143 if (stripe_size_arg != NULL) {
1144 result = llapi_parse_size(stripe_size_arg, &st_size,
1147 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1148 argv[0], stripe_size_arg);
1152 /* get the stripe offset */
1153 if (stripe_off_arg != NULL) {
1154 st_offset = strtol(stripe_off_arg, &end, 0);
1156 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1157 argv[0], stripe_off_arg);
1161 /* get the stripe count */
1162 if (stripe_count_arg != NULL) {
1163 st_count = strtoul(stripe_count_arg, &end, 0);
1165 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1166 argv[0], stripe_count_arg);
1171 if (mdt_idx_arg != NULL) {
1172 /* initialize migrate mdt parameters */
1173 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1175 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1176 argv[0], mdt_idx_arg);
1179 migrate_mdt_param.fp_migrate = 1;
1181 /* initialize stripe parameters */
1182 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1183 if (param == NULL) {
1184 fprintf(stderr, "error: %s: run out of memory\n",
1189 param->lsp_stripe_size = st_size;
1190 param->lsp_stripe_offset = st_offset;
1191 param->lsp_stripe_count = st_count;
1192 param->lsp_stripe_pattern = 0;
1193 param->lsp_pool = pool_name_arg;
1194 param->lsp_is_specific = false;
1196 if (st_count > 0 && nr_osts != st_count) {
1197 fprintf(stderr, "error: %s: stripe count '%d' "
1198 "doesn't match the number of OSTs: %d\n"
1199 , argv[0], st_count, nr_osts);
1204 param->lsp_is_specific = true;
1205 param->lsp_stripe_count = nr_osts;
1206 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1210 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1211 if (!migrate_mode) {
1212 result = llapi_file_open_param(fname,
1219 } else if (mdt_idx_arg != NULL) {
1220 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1222 result = lfs_migrate(fname, migration_flags, param);
1225 /* Save the first error encountered. */
1228 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1229 argv[0], migrate_mode ? "migrate" : "create",
1231 pool_name_arg != NULL && result == EINVAL ?
1232 "OST not in pool?" : strerror(errno));
1241 static int lfs_poollist(int argc, char **argv)
1246 return llapi_poollist(argv[1]);
1249 static int set_time(time_t *time, time_t *set, char *str)
1256 else if (str[0] == '-')
1262 t = strtol(str, NULL, 0);
1263 if (*time < t * 24 * 60 * 60) {
1266 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1270 *set = *time - t * 24 * 60 * 60;
1277 static int name2id(unsigned int *id, char *name, int type)
1280 struct passwd *entry;
1282 if (!(entry = getpwnam(name))) {
1288 *id = entry->pw_uid;
1290 struct group *entry;
1292 if (!(entry = getgrnam(name))) {
1298 *id = entry->gr_gid;
1304 static int id2name(char **name, unsigned int id, int type)
1307 struct passwd *entry;
1309 if (!(entry = getpwuid(id))) {
1315 *name = entry->pw_name;
1317 struct group *entry;
1319 if (!(entry = getgrgid(id))) {
1325 *name = entry->gr_name;
1331 static int name2layout(__u32 *layout, char *name)
1336 for (ptr = name; ; ptr = NULL) {
1337 lyt = strtok(ptr, ",");
1340 if (strcmp(lyt, "released") == 0)
1341 *layout |= LOV_PATTERN_F_RELEASED;
1342 else if (strcmp(lyt, "raid0") == 0)
1343 *layout |= LOV_PATTERN_RAID0;
1350 #define FIND_POOL_OPT 3
1351 static int lfs_find(int argc, char **argv)
1356 struct find_param param = {
1360 struct option long_opts[] = {
1361 {"atime", required_argument, 0, 'A'},
1362 {"stripe-count", required_argument, 0, 'c'},
1363 {"stripe_count", required_argument, 0, 'c'},
1364 {"ctime", required_argument, 0, 'C'},
1365 {"maxdepth", required_argument, 0, 'D'},
1366 {"gid", required_argument, 0, 'g'},
1367 {"group", required_argument, 0, 'G'},
1368 {"stripe-index", required_argument, 0, 'i'},
1369 {"stripe_index", required_argument, 0, 'i'},
1370 {"layout", required_argument, 0, 'L'},
1371 {"mdt", required_argument, 0, 'm'},
1372 {"mdt-index", required_argument, 0, 'm'},
1373 {"mdt_index", required_argument, 0, 'm'},
1374 {"mtime", required_argument, 0, 'M'},
1375 {"name", required_argument, 0, 'n'},
1376 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1377 {"obd", required_argument, 0, 'O'},
1378 {"ost", required_argument, 0, 'O'},
1379 /* no short option for pool, p/P already used */
1380 {"pool", required_argument, 0, FIND_POOL_OPT},
1381 {"print0", no_argument, 0, 'p'},
1382 {"print", no_argument, 0, 'P'},
1383 {"size", required_argument, 0, 's'},
1384 {"stripe-size", required_argument, 0, 'S'},
1385 {"stripe_size", required_argument, 0, 'S'},
1386 {"type", required_argument, 0, 't'},
1387 {"uid", required_argument, 0, 'u'},
1388 {"user", required_argument, 0, 'U'},
1401 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1402 while ((c = getopt_long_only(argc, argv,
1403 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1404 long_opts, NULL)) >= 0) {
1409 /* '!' is part of option */
1410 /* when getopt_long_only() finds a string which is not
1411 * an option nor a known option argument it returns 1
1412 * in that case if we already have found pathstart and pathend
1413 * (i.e. we have the list of pathnames),
1414 * the only supported value is "!"
1416 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1417 if (!isoption && pathend != -1) {
1418 fprintf(stderr, "err: %s: filename|dirname must either "
1419 "precede options or follow options\n",
1424 if (!isoption && pathstart == -1)
1425 pathstart = optind - 1;
1426 if (isoption && pathstart != -1 && pathend == -1)
1427 pathend = optind - 2;
1433 /* unknown; opt is "!" or path component,
1434 * checking done above.
1436 if (strcmp(optarg, "!") == 0)
1440 xtime = ¶m.fp_atime;
1441 xsign = ¶m.fp_asign;
1442 param.fp_exclude_atime = !!neg_opt;
1443 /* no break, this falls through to 'C' for ctime */
1446 xtime = ¶m.fp_ctime;
1447 xsign = ¶m.fp_csign;
1448 param.fp_exclude_ctime = !!neg_opt;
1450 /* no break, this falls through to 'M' for mtime */
1453 xtime = ¶m.fp_mtime;
1454 xsign = ¶m.fp_msign;
1455 param.fp_exclude_mtime = !!neg_opt;
1457 rc = set_time(&t, xtime, optarg);
1458 if (rc == INT_MAX) {
1466 if (optarg[0] == '+') {
1467 param.fp_stripe_count_sign = -1;
1469 } else if (optarg[0] == '-') {
1470 param.fp_stripe_count_sign = 1;
1474 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1475 if (*endptr != '\0') {
1476 fprintf(stderr,"error: bad stripe_count '%s'\n",
1481 param.fp_check_stripe_count = 1;
1482 param.fp_exclude_stripe_count = !!neg_opt;
1485 param.fp_max_depth = strtol(optarg, 0, 0);
1489 rc = name2id(¶m.fp_gid, optarg, GROUP);
1491 param.fp_gid = strtoul(optarg, &endptr, 10);
1492 if (*endptr != '\0') {
1493 fprintf(stderr, "Group/GID: %s cannot "
1494 "be found.\n", optarg);
1499 param.fp_exclude_gid = !!neg_opt;
1500 param.fp_check_gid = 1;
1503 ret = name2layout(¶m.fp_layout, optarg);
1506 param.fp_exclude_layout = !!neg_opt;
1507 param.fp_check_layout = 1;
1511 rc = name2id(¶m.fp_uid, optarg, USER);
1513 param.fp_uid = strtoul(optarg, &endptr, 10);
1514 if (*endptr != '\0') {
1515 fprintf(stderr, "User/UID: %s cannot "
1516 "be found.\n", optarg);
1521 param.fp_exclude_uid = !!neg_opt;
1522 param.fp_check_uid = 1;
1525 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1527 "Pool name %s is too long"
1528 " (max is %d)\n", optarg,
1533 /* we do check for empty pool because empty pool
1534 * is used to find V1 lov attributes */
1535 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1536 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1537 param.fp_exclude_pool = !!neg_opt;
1538 param.fp_check_pool = 1;
1541 param.fp_pattern = (char *)optarg;
1542 param.fp_exclude_pattern = !!neg_opt;
1547 char *buf, *token, *next, *p;
1551 buf = strdup(optarg);
1557 param.fp_exclude_obd = !!neg_opt;
1560 while (token && *token) {
1561 token = strchr(token, ',');
1568 param.fp_exclude_mdt = !!neg_opt;
1569 param.fp_num_alloc_mdts += len;
1570 tmp = realloc(param.fp_mdt_uuid,
1571 param.fp_num_alloc_mdts *
1572 sizeof(*param.fp_mdt_uuid));
1578 param.fp_mdt_uuid = tmp;
1580 param.fp_exclude_obd = !!neg_opt;
1581 param.fp_num_alloc_obds += len;
1582 tmp = realloc(param.fp_obd_uuid,
1583 param.fp_num_alloc_obds *
1584 sizeof(*param.fp_obd_uuid));
1590 param.fp_obd_uuid = tmp;
1592 for (token = buf; token && *token; token = next) {
1593 struct obd_uuid *puuid;
1596 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1599 ¶m.fp_obd_uuid[param.fp_num_obds++];
1601 p = strchr(token, ',');
1608 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1613 strncpy(puuid->uuid, token,
1614 sizeof(puuid->uuid));
1622 param.fp_zero_end = 1;
1627 if (optarg[0] == '+') {
1628 param.fp_size_sign = -1;
1630 } else if (optarg[0] == '-') {
1631 param.fp_size_sign = 1;
1635 ret = llapi_parse_size(optarg, ¶m.fp_size,
1636 ¶m.fp_size_units, 0);
1638 fprintf(stderr, "error: bad file size '%s'\n",
1642 param.fp_check_size = 1;
1643 param.fp_exclude_size = !!neg_opt;
1646 if (optarg[0] == '+') {
1647 param.fp_stripe_size_sign = -1;
1649 } else if (optarg[0] == '-') {
1650 param.fp_stripe_size_sign = 1;
1654 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1655 ¶m.fp_stripe_size_units, 0);
1657 fprintf(stderr, "error: bad stripe_size '%s'\n",
1661 param.fp_check_stripe_size = 1;
1662 param.fp_exclude_stripe_size = !!neg_opt;
1665 param.fp_exclude_type = !!neg_opt;
1666 switch (optarg[0]) {
1668 param.fp_type = S_IFBLK;
1671 param.fp_type = S_IFCHR;
1674 param.fp_type = S_IFDIR;
1677 param.fp_type = S_IFREG;
1680 param.fp_type = S_IFLNK;
1683 param.fp_type = S_IFIFO;
1686 param.fp_type = S_IFSOCK;
1689 fprintf(stderr, "error: %s: bad type '%s'\n",
1701 if (pathstart == -1) {
1702 fprintf(stderr, "error: %s: no filename|pathname\n",
1706 } else if (pathend == -1) {
1712 rc = llapi_find(argv[pathstart], ¶m);
1713 if (rc != 0 && ret == 0)
1715 } while (++pathstart < pathend);
1718 fprintf(stderr, "error: %s failed for %s.\n",
1719 argv[0], argv[optind - 1]);
1721 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1722 free(param.fp_obd_uuid);
1724 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1725 free(param.fp_mdt_uuid);
1730 static int lfs_getstripe_internal(int argc, char **argv,
1731 struct find_param *param)
1733 struct option long_opts[] = {
1734 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1735 /* This formerly implied "stripe-count", but was explicitly
1736 * made "stripe-count" for consistency with other options,
1737 * and to separate it from "mdt-count" when DNE arrives. */
1738 {"count", no_argument, 0, 'c'},
1740 {"stripe-count", no_argument, 0, 'c'},
1741 {"stripe_count", no_argument, 0, 'c'},
1742 {"directory", no_argument, 0, 'd'},
1743 {"default", no_argument, 0, 'D'},
1744 {"fid", no_argument, 0, 'F'},
1745 {"generation", no_argument, 0, 'g'},
1746 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1747 /* This formerly implied "stripe-index", but was explicitly
1748 * made "stripe-index" for consistency with other options,
1749 * and to separate it from "mdt-index" when DNE arrives. */
1750 {"index", no_argument, 0, 'i'},
1752 {"stripe-index", no_argument, 0, 'i'},
1753 {"stripe_index", no_argument, 0, 'i'},
1754 {"layout", no_argument, 0, 'L'},
1755 {"mdt", no_argument, 0, 'm'},
1756 {"mdt-index", no_argument, 0, 'm'},
1757 {"mdt_index", no_argument, 0, 'm'},
1758 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1759 {"mdt-index", no_argument, 0, 'M'},
1760 {"mdt_index", no_argument, 0, 'M'},
1762 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1763 /* This formerly implied "stripe-index", but was confusing
1764 * with "file offset" (which will eventually be needed for
1765 * with different layouts by offset), so deprecate it. */
1766 {"offset", no_argument, 0, 'o'},
1768 {"obd", required_argument, 0, 'O'},
1769 {"ost", required_argument, 0, 'O'},
1770 {"pool", no_argument, 0, 'p'},
1771 {"quiet", no_argument, 0, 'q'},
1772 {"recursive", no_argument, 0, 'r'},
1773 {"raw", no_argument, 0, 'R'},
1774 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1775 /* This formerly implied "--stripe-size", but was confusing
1776 * with "lfs find --size|-s", which means "file size", so use
1777 * the consistent "--stripe-size|-S" for all commands. */
1778 {"size", no_argument, 0, 's'},
1780 {"stripe-size", no_argument, 0, 'S'},
1781 {"stripe_size", no_argument, 0, 'S'},
1782 {"verbose", no_argument, 0, 'v'},
1787 while ((c = getopt_long(argc, argv, "cdDFghiLmMoO:pqrRsSv",
1788 long_opts, NULL)) != -1) {
1791 if (param->fp_obd_uuid) {
1793 "error: %s: only one obduuid allowed",
1797 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1803 param->fp_max_depth = 0;
1806 param->fp_get_default_lmv = 1;
1809 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1810 param->fp_verbose |= VERBOSE_DFID;
1811 param->fp_max_depth = 0;
1815 param->fp_recursive = 1;
1818 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
1821 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1822 if (strcmp(argv[optind - 1], "--count") == 0)
1823 fprintf(stderr, "warning: '--count' deprecated,"
1824 " use '--stripe-count' instead\n");
1826 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1827 param->fp_verbose |= VERBOSE_COUNT;
1828 param->fp_max_depth = 0;
1831 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1833 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1834 fprintf(stderr, "warning: '--size|-s' deprecated, "
1835 "use '--stripe-size|-S' instead\n");
1837 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1839 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1840 param->fp_verbose |= VERBOSE_SIZE;
1841 param->fp_max_depth = 0;
1844 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1846 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1847 "use '--stripe-index|-i' instead\n");
1850 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1851 if (strcmp(argv[optind - 1], "--index") == 0)
1852 fprintf(stderr, "warning: '--index' deprecated"
1853 ", use '--stripe-index' instead\n");
1855 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1856 param->fp_verbose |= VERBOSE_OFFSET;
1857 param->fp_max_depth = 0;
1861 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1862 param->fp_verbose |= VERBOSE_POOL;
1863 param->fp_max_depth = 0;
1867 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1868 param->fp_verbose |= VERBOSE_GENERATION;
1869 param->fp_max_depth = 0;
1873 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1874 param->fp_verbose |= VERBOSE_LAYOUT;
1875 param->fp_max_depth = 0;
1878 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1880 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
1881 fprintf(stderr, "warning: '-M' deprecated"
1882 ", use '-m' instead\n");
1886 if (!(param->fp_verbose & VERBOSE_DETAIL))
1887 param->fp_max_depth = 0;
1888 param->fp_verbose |= VERBOSE_MDTINDEX;
1901 if (param->fp_recursive)
1902 param->fp_max_depth = -1;
1904 if (!param->fp_verbose)
1905 param->fp_verbose = VERBOSE_DEFAULT;
1906 if (param->fp_quiet)
1907 param->fp_verbose = VERBOSE_OBJID;
1910 rc = llapi_getstripe(argv[optind], param);
1911 } while (++optind < argc && !rc);
1914 fprintf(stderr, "error: %s failed for %s.\n",
1915 argv[0], argv[optind - 1]);
1919 static int lfs_tgts(int argc, char **argv)
1921 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1922 struct find_param param;
1923 int index = 0, rc=0;
1928 if (argc == 2 && !realpath(argv[1], path)) {
1930 fprintf(stderr, "error: invalid path '%s': %s\n",
1931 argv[1], strerror(-rc));
1935 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1936 /* Check if we have a mount point */
1937 if (mntdir[0] == '\0')
1940 memset(¶m, 0, sizeof(param));
1941 if (!strcmp(argv[0], "mdts"))
1942 param.fp_get_lmv = 1;
1944 rc = llapi_ostlist(mntdir, ¶m);
1946 fprintf(stderr, "error: %s: failed on %s\n",
1949 if (path[0] != '\0')
1951 memset(mntdir, 0, PATH_MAX);
1957 static int lfs_getstripe(int argc, char **argv)
1959 struct find_param param = { 0 };
1961 param.fp_max_depth = 1;
1962 return lfs_getstripe_internal(argc, argv, ¶m);
1966 static int lfs_getdirstripe(int argc, char **argv)
1968 struct find_param param = { 0 };
1970 param.fp_get_lmv = 1;
1971 return lfs_getstripe_internal(argc, argv, ¶m);
1975 static int lfs_setdirstripe(int argc, char **argv)
1979 unsigned int stripe_offset = -1;
1980 unsigned int stripe_count = 1;
1981 enum lmv_hash_type hash_type;
1984 char *stripe_offset_opt = NULL;
1985 char *stripe_count_opt = NULL;
1986 char *stripe_hash_opt = NULL;
1987 char *mode_opt = NULL;
1988 bool default_stripe = false;
1989 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
1990 mode_t previous_mode = 0;
1991 bool delete = false;
1993 struct option long_opts[] = {
1994 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1995 {"count", required_argument, 0, 'c'},
1997 {"mdt-count", required_argument, 0, 'c'},
1998 {"delete", no_argument, 0, 'd'},
1999 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2000 {"index", required_argument, 0, 'i'},
2002 {"mdt-index", required_argument, 0, 'i'},
2003 {"mode", required_argument, 0, 'm'},
2004 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2005 {"hash-type", required_argument, 0, 't'},
2007 {"mdt-hash", required_argument, 0, 't'},
2008 {"default_stripe", no_argument, 0, 'D'},
2012 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
2019 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2020 if (strcmp(argv[optind - 1], "--count") == 0)
2021 fprintf(stderr, "warning: '--count' deprecated"
2022 ", use '--mdt-count' instead\n");
2024 stripe_count_opt = optarg;
2028 default_stripe = true;
2031 default_stripe = true;
2034 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2035 if (strcmp(argv[optind - 1], "--index") == 0)
2036 fprintf(stderr, "warning: '--index' deprecated"
2037 ", use '--mdt-index' instead\n");
2039 stripe_offset_opt = optarg;
2045 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2046 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2047 fprintf(stderr, "warning: '--hash-type' "
2048 "deprecated, use '--mdt-hash' "
2051 stripe_hash_opt = optarg;
2054 fprintf(stderr, "error: %s: option '%s' "
2056 argv[0], argv[optind - 1]);
2061 if (optind == argc) {
2062 fprintf(stderr, "error: %s: missing dirname\n",
2067 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2068 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2073 if (stripe_offset_opt != NULL) {
2074 /* get the stripe offset */
2075 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2077 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2078 argv[0], stripe_offset_opt);
2084 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2085 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2086 " or -i options.\n", argv[0]);
2094 if (mode_opt != NULL) {
2095 mode = strtoul(mode_opt, &end, 8);
2097 fprintf(stderr, "error: %s: bad mode '%s'\n",
2101 previous_mode = umask(0);
2104 if (stripe_hash_opt == NULL ||
2105 strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
2106 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2107 } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
2108 hash_type = LMV_HASH_TYPE_ALL_CHARS;
2110 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
2111 argv[0], stripe_hash_opt);
2115 /* get the stripe count */
2116 if (stripe_count_opt != NULL) {
2117 stripe_count = strtoul(stripe_count_opt, &end, 0);
2119 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2120 argv[0], stripe_count_opt);
2125 dname = argv[optind];
2127 if (default_stripe) {
2128 result = llapi_dir_set_default_lmv_stripe(dname,
2129 stripe_offset, stripe_count,
2132 result = llapi_dir_create_pool(dname, mode,
2134 stripe_count, hash_type,
2139 fprintf(stderr, "error: %s: create stripe dir '%s' "
2140 "failed\n", argv[0], dname);
2143 dname = argv[++optind];
2144 } while (dname != NULL);
2146 if (mode_opt != NULL)
2147 umask(previous_mode);
2153 static int lfs_rmentry(int argc, char **argv)
2160 fprintf(stderr, "error: %s: missing dirname\n",
2166 dname = argv[index];
2167 while (dname != NULL) {
2168 result = llapi_direntry_remove(dname);
2170 fprintf(stderr, "error: %s: remove dir entry '%s' "
2171 "failed\n", argv[0], dname);
2174 dname = argv[++index];
2179 static int lfs_mv(int argc, char **argv)
2181 struct find_param param = {
2188 struct option long_opts[] = {
2189 {"mdt-index", required_argument, 0, 'M'},
2190 {"verbose", no_argument, 0, 'v'},
2194 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2197 param.fp_mdt_index = strtoul(optarg, &end, 0);
2199 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2206 param.fp_verbose = VERBOSE_DETAIL;
2210 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2211 argv[0], argv[optind - 1]);
2216 if (param.fp_mdt_index == -1) {
2217 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2221 if (optind >= argc) {
2222 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2226 param.fp_migrate = 1;
2227 rc = llapi_migrate_mdt(argv[optind], ¶m);
2229 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2230 argv[0], argv[optind], param.fp_mdt_index,
2235 static int lfs_osts(int argc, char **argv)
2237 return lfs_tgts(argc, argv);
2240 static int lfs_mdts(int argc, char **argv)
2242 return lfs_tgts(argc, argv);
2245 #define COOK(value) \
2248 while (value > 1024) { \
2256 #define CDF "%11llu"
2257 #define HDF "%8.1f%c"
2262 MNTDF_INODES = 0x0001,
2263 MNTDF_COOKED = 0x0002,
2264 MNTDF_LAZY = 0x0004,
2265 MNTDF_VERBOSE = 0x0008,
2268 static int showdf(char *mntdir, struct obd_statfs *stat,
2269 char *uuid, enum mntdf_flags flags,
2270 char *type, int index, int rc)
2272 long long avail, used, total;
2274 char *suffix = "KMGTPEZY";
2275 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2276 char tbuf[3 * sizeof(__u64)];
2277 char ubuf[3 * sizeof(__u64)];
2278 char abuf[3 * sizeof(__u64)];
2279 char rbuf[3 * sizeof(__u64)];
2286 if (flags & MNTDF_INODES) {
2287 avail = stat->os_ffree;
2288 used = stat->os_files - stat->os_ffree;
2289 total = stat->os_files;
2291 int shift = flags & MNTDF_COOKED ? 0 : 10;
2293 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2294 used = ((stat->os_blocks - stat->os_bfree) *
2295 stat->os_bsize) >> shift;
2296 total = (stat->os_blocks * stat->os_bsize) >> shift;
2299 if ((used + avail) > 0)
2300 ratio = (double)used / (double)(used + avail);
2302 if (flags & MNTDF_COOKED) {
2306 cook_val = (double)total;
2309 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
2312 snprintf(tbuf, sizeof(tbuf), CDF, total);
2314 cook_val = (double)used;
2317 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
2320 snprintf(ubuf, sizeof(ubuf), CDF, used);
2322 cook_val = (double)avail;
2325 snprintf(abuf, sizeof(abuf), HDF, cook_val,
2328 snprintf(abuf, sizeof(abuf), CDF, avail);
2330 snprintf(tbuf, sizeof(tbuf), CDF, total);
2331 snprintf(ubuf, sizeof(tbuf), CDF, used);
2332 snprintf(abuf, sizeof(tbuf), CDF, avail);
2335 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2336 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2337 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2339 printf("[%s:%d]\n", type, index);
2345 printf(UUF": inactive device\n", uuid);
2348 printf(UUF": %s\n", uuid, strerror(-rc));
2355 struct ll_stat_type {
2360 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
2362 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2363 struct obd_uuid uuid_buf;
2364 char *poolname = NULL;
2365 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2366 { LL_STATFS_LOV, "OST" },
2368 struct ll_stat_type *tp;
2369 __u64 ost_ffree = 0;
2377 poolname = strchr(pool, '.');
2378 if (poolname != NULL) {
2379 if (strncmp(fsname, pool, strlen(fsname))) {
2380 fprintf(stderr, "filesystem name incorrect\n");
2388 fd = open(mntdir, O_RDONLY);
2391 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
2396 if (flags & MNTDF_INODES)
2397 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2398 "UUID", "Inodes", "IUsed", "IFree",
2399 "IUse%", "Mounted on");
2401 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2402 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
2403 "Used", "Available", "Use%", "Mounted on");
2405 for (tp = types; tp->st_name != NULL; tp++) {
2406 for (index = 0; ; index++) {
2407 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2408 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2409 type = flags & MNTDF_LAZY ?
2410 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2411 rc2 = llapi_obd_fstatfs(fd, type, index,
2412 &stat_buf, &uuid_buf);
2417 if (rc2 == -ENODATA) { /* Inactive device, OK. */
2418 if (!(flags & MNTDF_VERBOSE))
2420 } else if (rc2 < 0 && rc == 0) {
2424 if (poolname && tp->st_op == LL_STATFS_LOV &&
2425 llapi_search_ost(fsname, poolname,
2426 obd_uuid2str(&uuid_buf)) != 1)
2429 /* the llapi_obd_statfs() call may have returned with
2430 * an error, but if it filled in uuid_buf we will at
2431 * lease use that to print out a message for that OBD.
2432 * If we didn't get anything in the uuid_buf, then fill
2433 * it in so that we can print an error message. */
2434 if (uuid_buf.uuid[0] == '\0')
2435 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
2436 "%s%04x", tp->st_name, index);
2437 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2438 flags, tp->st_name, index, rc2);
2441 if (tp->st_op == LL_STATFS_LMV) {
2442 sum.os_ffree += stat_buf.os_ffree;
2443 sum.os_files += stat_buf.os_files;
2444 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2445 sum.os_blocks += stat_buf.os_blocks *
2447 sum.os_bfree += stat_buf.os_bfree *
2449 sum.os_bavail += stat_buf.os_bavail *
2451 ost_ffree += stat_buf.os_ffree;
2459 /* If we don't have as many objects free on the OST as inodes
2460 * on the MDS, we reduce the total number of inodes to
2461 * compensate, so that the "inodes in use" number is correct.
2462 * Matches ll_statfs_internal() so the results are consistent. */
2463 if (ost_ffree < sum.os_ffree) {
2464 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2465 sum.os_ffree = ost_ffree;
2468 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
2474 static int lfs_df(int argc, char **argv)
2476 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2477 enum mntdf_flags flags = 0;
2478 int c, rc = 0, index = 0;
2479 char fsname[PATH_MAX] = "", *pool_name = NULL;
2480 struct option long_opts[] = {
2481 {"human-readable", 0, 0, 'h'},
2482 {"inodes", 0, 0, 'i'},
2483 {"lazy", 0, 0, 'l'},
2484 {"pool", required_argument, 0, 'p'},
2485 {"verbose", 0, 0, 'v'},
2489 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
2492 flags |= MNTDF_COOKED;
2495 flags |= MNTDF_INODES;
2498 flags |= MNTDF_LAZY;
2504 flags |= MNTDF_VERBOSE;
2510 if (optind < argc && !realpath(argv[optind], path)) {
2512 fprintf(stderr, "error: invalid path '%s': %s\n",
2513 argv[optind], strerror(-rc));
2517 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2518 /* Check if we have a mount point */
2519 if (mntdir[0] == '\0')
2522 rc = mntdf(mntdir, fsname, pool_name, flags);
2523 if (rc || path[0] != '\0')
2525 fsname[0] = '\0'; /* avoid matching in next loop */
2526 mntdir[0] = '\0'; /* avoid matching in next loop */
2532 static int lfs_getname(int argc, char **argv)
2534 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2535 int rc = 0, index = 0, c;
2536 char buf[sizeof(struct obd_uuid)];
2538 while ((c = getopt(argc, argv, "h")) != -1)
2541 if (optind == argc) { /* no paths specified, get all paths. */
2542 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2543 rc = llapi_getname(mntdir, buf, sizeof(buf));
2546 "cannot get name for `%s': %s\n",
2547 mntdir, strerror(-rc));
2551 printf("%s %s\n", buf, mntdir);
2553 path[0] = fsname[0] = mntdir[0] = 0;
2555 } else { /* paths specified, only attempt to search these. */
2556 for (; optind < argc; optind++) {
2557 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2560 "cannot get name for `%s': %s\n",
2561 argv[optind], strerror(-rc));
2565 printf("%s %s\n", buf, argv[optind]);
2571 static int lfs_check(int argc, char **argv)
2574 char mntdir[PATH_MAX] = {'\0'};
2583 obd_types[0] = obd_type1;
2584 obd_types[1] = obd_type2;
2586 if (strcmp(argv[1], "osts") == 0) {
2587 strcpy(obd_types[0], "osc");
2588 } else if (strcmp(argv[1], "mds") == 0) {
2589 strcpy(obd_types[0], "mdc");
2590 } else if (strcmp(argv[1], "servers") == 0) {
2592 strcpy(obd_types[0], "osc");
2593 strcpy(obd_types[1], "mdc");
2595 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2600 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2601 if (rc < 0 || mntdir[0] == '\0') {
2602 fprintf(stderr, "No suitable Lustre mount found\n");
2606 rc = llapi_target_check(num_types, obd_types, mntdir);
2608 fprintf(stderr, "error: %s: %s status failed\n",
2615 static int lfs_join(int argc, char **argv)
2617 fprintf(stderr, "join two lustre files into one.\n"
2618 "obsolete, HEAD does not support it anymore.\n");
2622 #ifdef HAVE_SYS_QUOTA_H
2623 #define ARG2INT(nr, str, msg) \
2626 nr = strtol(str, &endp, 0); \
2628 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2633 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2635 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2636 * returns the value or ULONG_MAX on integer overflow or incorrect format
2638 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2639 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2640 * 3. empty integer value is interpreted as 0
2642 static unsigned long str2sec(const char* timestr)
2644 const char spec[] = "smhdw";
2645 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2646 unsigned long val = 0;
2649 if (strpbrk(timestr, spec) == NULL) {
2650 /* no specifiers inside the time string,
2651 should treat it as an integer value */
2652 val = strtoul(timestr, &tail, 10);
2653 return *tail ? ULONG_MAX : val;
2656 /* format string is XXwXXdXXhXXmXXs */
2662 v = strtoul(timestr, &tail, 10);
2663 if (v == ULONG_MAX || *tail == '\0')
2664 /* value too large (ULONG_MAX or more)
2665 or missing specifier */
2668 ptr = strchr(spec, *tail);
2670 /* unknown specifier */
2675 /* check if product will overflow the type */
2676 if (!(v < ULONG_MAX / mult[ind]))
2679 ADD_OVERFLOW(val, mult[ind] * v);
2680 if (val == ULONG_MAX)
2692 #define ARG2ULL(nr, str, def_units) \
2694 unsigned long long limit, units = def_units; \
2697 rc = llapi_parse_size(str, &limit, &units, 1); \
2699 fprintf(stderr, "error: bad limit value %s\n", str); \
2705 static inline int has_times_option(int argc, char **argv)
2709 for (i = 1; i < argc; i++)
2710 if (!strcmp(argv[i], "-t"))
2716 int lfs_setquota_times(int argc, char **argv)
2719 struct if_quotactl qctl;
2720 char *mnt, *obd_type = (char *)qctl.obd_type;
2721 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2722 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2723 struct option long_opts[] = {
2724 {"block-grace", required_argument, 0, 'b'},
2725 {"group", no_argument, 0, 'g'},
2726 {"inode-grace", required_argument, 0, 'i'},
2727 {"times", no_argument, 0, 't'},
2728 {"user", no_argument, 0, 'u'},
2732 memset(&qctl, 0, sizeof(qctl));
2733 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2734 qctl.qc_type = UGQUOTA;
2736 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2740 if (qctl.qc_type != UGQUOTA) {
2741 fprintf(stderr, "error: -u and -g can't be used "
2742 "more than once\n");
2745 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2748 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2749 fprintf(stderr, "error: bad block-grace: %s\n",
2753 dqb->dqb_valid |= QIF_BTIME;
2756 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2757 fprintf(stderr, "error: bad inode-grace: %s\n",
2761 dqb->dqb_valid |= QIF_ITIME;
2763 case 't': /* Yes, of course! */
2765 default: /* getopt prints error message for us when opterr != 0 */
2770 if (qctl.qc_type == UGQUOTA) {
2771 fprintf(stderr, "error: neither -u nor -g specified\n");
2775 if (optind != argc - 1) {
2776 fprintf(stderr, "error: unexpected parameters encountered\n");
2781 rc = llapi_quotactl(mnt, &qctl);
2784 fprintf(stderr, "%s %s ", obd_type,
2785 obd_uuid2str(&qctl.obd_uuid));
2786 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2793 #define BSLIMIT (1 << 0)
2794 #define BHLIMIT (1 << 1)
2795 #define ISLIMIT (1 << 2)
2796 #define IHLIMIT (1 << 3)
2798 int lfs_setquota(int argc, char **argv)
2801 struct if_quotactl qctl;
2802 char *mnt, *obd_type = (char *)qctl.obd_type;
2803 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2804 struct option long_opts[] = {
2805 {"block-softlimit", required_argument, 0, 'b'},
2806 {"block-hardlimit", required_argument, 0, 'B'},
2807 {"group", required_argument, 0, 'g'},
2808 {"inode-softlimit", required_argument, 0, 'i'},
2809 {"inode-hardlimit", required_argument, 0, 'I'},
2810 {"user", required_argument, 0, 'u'},
2813 unsigned limit_mask = 0;
2816 if (has_times_option(argc, argv))
2817 return lfs_setquota_times(argc, argv);
2819 memset(&qctl, 0, sizeof(qctl));
2820 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2821 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2822 * so it can be used as a marker that qc_type
2823 * isn't reinitialized from command line */
2825 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2829 if (qctl.qc_type != UGQUOTA) {
2830 fprintf(stderr, "error: -u and -g can't be used"
2831 " more than once\n");
2834 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2835 rc = name2id(&qctl.qc_id, optarg,
2836 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2838 qctl.qc_id = strtoul(optarg, &endptr, 10);
2839 if (*endptr != '\0') {
2840 fprintf(stderr, "error: can't find id "
2841 "for name %s\n", optarg);
2847 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2848 dqb->dqb_bsoftlimit >>= 10;
2849 limit_mask |= BSLIMIT;
2850 if (dqb->dqb_bsoftlimit &&
2851 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2852 fprintf(stderr, "warning: block 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_bhardlimit, optarg, 1024);
2859 dqb->dqb_bhardlimit >>= 10;
2860 limit_mask |= BHLIMIT;
2861 if (dqb->dqb_bhardlimit &&
2862 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2863 fprintf(stderr, "warning: block hardlimit is "
2864 "smaller than the miminal qunit size, "
2865 "please see the help of setquota or "
2866 "Lustre manual for details.\n");
2869 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2870 limit_mask |= ISLIMIT;
2871 if (dqb->dqb_isoftlimit &&
2872 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2873 fprintf(stderr, "warning: inode softlimit is "
2874 "smaller than the miminal qunit size, "
2875 "please see the help of setquota or "
2876 "Lustre manual for details.\n");
2879 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2880 limit_mask |= IHLIMIT;
2881 if (dqb->dqb_ihardlimit &&
2882 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2883 fprintf(stderr, "warning: inode hardlimit is "
2884 "smaller than the miminal qunit size, "
2885 "please see the help of setquota or "
2886 "Lustre manual for details.\n");
2888 default: /* getopt prints error message for us when opterr != 0 */
2893 if (qctl.qc_type == UGQUOTA) {
2894 fprintf(stderr, "error: neither -u nor -g was specified\n");
2898 if (limit_mask == 0) {
2899 fprintf(stderr, "error: at least one limit must be specified\n");
2903 if (optind != argc - 1) {
2904 fprintf(stderr, "error: unexpected parameters encountered\n");
2910 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2911 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2912 /* sigh, we can't just set blimits/ilimits */
2913 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2914 .qc_type = qctl.qc_type,
2915 .qc_id = qctl.qc_id};
2917 rc = llapi_quotactl(mnt, &tmp_qctl);
2919 fprintf(stderr, "error: setquota failed while retrieving"
2920 " current quota settings (%s)\n",
2925 if (!(limit_mask & BHLIMIT))
2926 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2927 if (!(limit_mask & BSLIMIT))
2928 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2929 if (!(limit_mask & IHLIMIT))
2930 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2931 if (!(limit_mask & ISLIMIT))
2932 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2934 /* Keep grace times if we have got no softlimit arguments */
2935 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2936 dqb->dqb_valid |= QIF_BTIME;
2937 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2940 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2941 dqb->dqb_valid |= QIF_ITIME;
2942 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2946 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2947 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2949 rc = llapi_quotactl(mnt, &qctl);
2952 fprintf(stderr, "%s %s ", obd_type,
2953 obd_uuid2str(&qctl.obd_uuid));
2954 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2961 static inline char *type2name(int check_type)
2963 if (check_type == USRQUOTA)
2965 else if (check_type == GRPQUOTA)
2971 /* Converts seconds value into format string
2972 * result is returned in buf
2974 * 1. result is in descenting order: 1w2d3h4m5s
2975 * 2. zero fields are not filled (except for p. 3): 5d1s
2976 * 3. zero seconds value is presented as "0s"
2978 static char * __sec2str(time_t seconds, char *buf)
2980 const char spec[] = "smhdw";
2981 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2986 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2987 c = seconds / mult[i];
2989 if (c > 0 || (i == 0 && buf == tail))
2990 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2998 static void sec2str(time_t seconds, char *buf, int rc)
3005 tail = __sec2str(seconds, tail);
3007 if (rc && tail - buf < 39) {
3013 static void diff2str(time_t seconds, char *buf, time_t now)
3019 if (seconds <= now) {
3020 strcpy(buf, "none");
3023 __sec2str(seconds - now, buf);
3026 static void print_quota_title(char *name, struct if_quotactl *qctl,
3027 bool human_readable)
3029 printf("Disk quotas for %s %s (%cid %u):\n",
3030 type2name(qctl->qc_type), name,
3031 *type2name(qctl->qc_type), qctl->qc_id);
3032 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3033 "Filesystem", human_readable ? "used" : "kbytes",
3034 "quota", "limit", "grace",
3035 "files", "quota", "limit", "grace");
3038 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3041 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3044 snprintf(buf, buflen, "%5.4gP",
3045 (double)num / ((__u64)1 << 40));
3047 snprintf(buf, buflen, "%5.4gT",
3048 (double)num / (1 << 30));
3050 snprintf(buf, buflen, "%5.4gG",
3051 (double)num / (1 << 20));
3053 snprintf(buf, buflen, "%5.4gM",
3054 (double)num / (1 << 10));
3056 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3060 #define STRBUF_LEN 32
3061 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3068 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3069 int bover = 0, iover = 0;
3070 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3071 char numbuf[3][STRBUF_LEN];
3073 char strbuf[STRBUF_LEN];
3075 if (dqb->dqb_bhardlimit &&
3076 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3078 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3079 if (dqb->dqb_btime > now) {
3086 if (dqb->dqb_ihardlimit &&
3087 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3089 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3090 if (dqb->dqb_itime > now) {
3098 if (strlen(mnt) > 15)
3099 printf("%s\n%15s", mnt, "");
3101 printf("%15s", mnt);
3104 diff2str(dqb->dqb_btime, timebuf, now);
3106 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3107 strbuf, sizeof(strbuf), h);
3108 if (rc == -EREMOTEIO)
3109 sprintf(numbuf[0], "%s*", strbuf);
3111 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3112 "%s" : "[%s]", strbuf);
3114 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3115 if (type == QC_GENERAL)
3116 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3117 "%s" : "[%s]", strbuf);
3119 sprintf(numbuf[1], "%s", "-");
3121 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3122 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3123 "%s" : "[%s]", strbuf);
3125 printf(" %7s%c %6s %7s %7s",
3126 numbuf[0], bover ? '*' : ' ', numbuf[1],
3127 numbuf[2], bover > 1 ? timebuf : "-");
3130 diff2str(dqb->dqb_itime, timebuf, now);
3132 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3133 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3135 if (type == QC_GENERAL)
3136 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3138 (uintmax_t)dqb->dqb_isoftlimit);
3140 sprintf(numbuf[1], "%s", "-");
3142 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3143 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3145 if (type != QC_OSTIDX)
3146 printf(" %7s%c %6s %7s %7s",
3147 numbuf[0], iover ? '*' : ' ', numbuf[1],
3148 numbuf[2], iover > 1 ? timebuf : "-");
3150 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3153 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3154 qctl->qc_cmd == Q_GETOINFO) {
3158 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3159 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3160 printf("Block grace time: %s; Inode grace time: %s\n",
3161 bgtimebuf, igtimebuf);
3165 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3166 bool h, __u64 *total)
3168 int rc = 0, rc1 = 0, count = 0;
3169 __u32 valid = qctl->qc_valid;
3171 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3173 fprintf(stderr, "can not get %s count: %s\n",
3174 is_mdt ? "mdt": "ost", strerror(-rc));
3178 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3179 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3180 rc = llapi_quotactl(mnt, qctl);
3182 /* It is remote client case. */
3183 if (-rc == EOPNOTSUPP) {
3190 fprintf(stderr, "quotactl %s%d failed.\n",
3191 is_mdt ? "mdt": "ost", qctl->qc_idx);
3195 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3196 qctl->qc_valid, 0, h);
3197 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3198 qctl->qc_dqblk.dqb_bhardlimit;
3201 qctl->qc_valid = valid;
3205 static int lfs_quota(int argc, char **argv)
3208 char *mnt, *name = NULL;
3209 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3210 .qc_type = UGQUOTA };
3211 char *obd_type = (char *)qctl.obd_type;
3212 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3213 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
3214 verbose = 0, pass = 0, quiet = 0, inacc;
3216 __u32 valid = QC_GENERAL, idx = 0;
3217 __u64 total_ialloc = 0, total_balloc = 0;
3218 bool human_readable = false;
3220 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3223 if (qctl.qc_type != UGQUOTA) {
3224 fprintf(stderr, "error: use either -u or -g\n");
3227 qctl.qc_type = USRQUOTA;
3230 if (qctl.qc_type != UGQUOTA) {
3231 fprintf(stderr, "error: use either -u or -g\n");
3234 qctl.qc_type = GRPQUOTA;
3237 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3240 valid = qctl.qc_valid = QC_UUID;
3241 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3244 valid = qctl.qc_valid = QC_MDTIDX;
3245 idx = qctl.qc_idx = atoi(optarg);
3248 valid = qctl.qc_valid = QC_OSTIDX;
3249 idx = qctl.qc_idx = atoi(optarg);
3258 human_readable = true;
3261 fprintf(stderr, "error: %s: option '-%c' "
3262 "unrecognized\n", argv[0], c);
3267 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3268 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3269 optind == argc - 1) {
3271 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3272 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3273 qctl.qc_valid = valid;
3276 qctl.qc_type = USRQUOTA;
3277 qctl.qc_id = geteuid();
3279 qctl.qc_type = GRPQUOTA;
3280 qctl.qc_id = getegid();
3282 rc = id2name(&name, qctl.qc_id,
3283 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3286 /* lfs quota -u username /path/to/lustre/mount */
3287 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3288 /* options should be followed by u/g-name and mntpoint */
3289 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3290 fprintf(stderr, "error: missing quota argument(s)\n");
3294 name = argv[optind++];
3295 rc = name2id(&qctl.qc_id, name,
3296 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3298 qctl.qc_id = strtoul(name, &endptr, 10);
3299 if (*endptr != '\0') {
3300 fprintf(stderr, "error: can't find id for name "
3305 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3306 fprintf(stderr, "error: missing quota info argument(s)\n");
3312 rc1 = llapi_quotactl(mnt, &qctl);
3316 fprintf(stderr, "%s quotas are not enabled.\n",
3317 qctl.qc_type == USRQUOTA ? "user" : "group");
3320 fprintf(stderr, "Permission denied.\n");
3323 /* We already got error message. */
3326 fprintf(stderr, "Unexpected quotactl error: %s\n",
3331 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3332 print_quota_title(name, &qctl, human_readable);
3334 if (rc1 && *obd_type)
3335 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3337 if (qctl.qc_valid != QC_GENERAL)
3340 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3341 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3342 (QIF_LIMITS|QIF_USAGE));
3344 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3346 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3348 char strbuf[STRBUF_LEN];
3350 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3352 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3354 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
3356 printf("Total allocated inode limit: %ju, total "
3357 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
3361 if (rc1 || rc2 || rc3 || inacc)
3362 printf("Some errors happened when getting quota info. "
3363 "Some devices may be not working or deactivated. "
3364 "The data in \"[]\" is inaccurate.\n");
3372 #endif /* HAVE_SYS_QUOTA_H! */
3374 static int flushctx_ioctl(char *mp)
3378 fd = open(mp, O_RDONLY);
3380 fprintf(stderr, "flushctx: error open %s: %s\n",
3381 mp, strerror(errno));
3385 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3387 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3388 mp, strerror(errno));
3394 static int lfs_flushctx(int argc, char **argv)
3396 int kdestroy = 0, c;
3397 char mntdir[PATH_MAX] = {'\0'};
3401 while ((c = getopt(argc, argv, "k")) != -1) {
3407 fprintf(stderr, "error: %s: option '-%c' "
3408 "unrecognized\n", argv[0], c);
3414 if ((rc = system("kdestroy > /dev/null")) != 0) {
3415 rc = WEXITSTATUS(rc);
3416 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3420 if (optind >= argc) {
3421 /* flush for all mounted lustre fs. */
3422 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3423 /* Check if we have a mount point */
3424 if (mntdir[0] == '\0')
3427 if (flushctx_ioctl(mntdir))
3430 mntdir[0] = '\0'; /* avoid matching in next loop */
3433 /* flush fs as specified */
3434 while (optind < argc) {
3435 if (flushctx_ioctl(argv[optind++]))
3442 static int lfs_lsetfacl(int argc, char **argv)
3444 fprintf(stderr, "local client sets facl for remote client.\n"
3445 "obsolete, does not support it anymore.\n");
3449 static int lfs_lgetfacl(int argc, char **argv)
3451 fprintf(stderr, "local client gets facl for remote client.\n"
3452 "obsolete, does not support it anymore.\n");
3456 static int lfs_rsetfacl(int argc, char **argv)
3458 fprintf(stderr, "remote client sets facl for remote client.\n"
3459 "obsolete, does not support it anymore.\n");
3463 static int lfs_rgetfacl(int argc, char **argv)
3465 fprintf(stderr, "remote client gets facl for remote client.\n"
3466 "obsolete, does not support it anymore.\n");
3470 static int lfs_cp(int argc, char **argv)
3472 fprintf(stderr, "remote client copy file(s).\n"
3473 "obsolete, does not support it anymore.\n");
3477 static int lfs_ls(int argc, char **argv)
3479 fprintf(stderr, "remote client lists directory contents.\n"
3480 "obsolete, does not support it anymore.\n");
3484 static int lfs_changelog(int argc, char **argv)
3486 void *changelog_priv;
3487 struct changelog_rec *rec;
3488 long long startrec = 0, endrec = 0;
3490 struct option long_opts[] = {
3491 {"follow", no_argument, 0, 'f'},
3494 char short_opts[] = "f";
3497 while ((rc = getopt_long(argc, argv, short_opts,
3498 long_opts, NULL)) != -1) {
3506 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3507 argv[0], argv[optind - 1]);
3514 mdd = argv[optind++];
3516 startrec = strtoll(argv[optind++], NULL, 10);
3518 endrec = strtoll(argv[optind++], NULL, 10);
3520 rc = llapi_changelog_start(&changelog_priv,
3521 CHANGELOG_FLAG_BLOCK |
3522 CHANGELOG_FLAG_JOBID |
3523 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3526 fprintf(stderr, "Can't start changelog: %s\n",
3527 strerror(errno = -rc));
3531 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3535 if (endrec && rec->cr_index > endrec) {
3536 llapi_changelog_free(&rec);
3539 if (rec->cr_index < startrec) {
3540 llapi_changelog_free(&rec);
3544 secs = rec->cr_time >> 30;
3545 gmtime_r(&secs, &ts);
3546 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3547 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
3548 changelog_type2str(rec->cr_type),
3549 ts.tm_hour, ts.tm_min, ts.tm_sec,
3550 (int)(rec->cr_time & ((1<<30) - 1)),
3551 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3552 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3554 if (rec->cr_flags & CLF_JOBID) {
3555 struct changelog_ext_jobid *jid =
3556 changelog_rec_jobid(rec);
3558 if (jid->cr_jobid[0] != '\0')
3559 printf(" j=%s", jid->cr_jobid);
3562 if (rec->cr_namelen)
3563 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3564 rec->cr_namelen, changelog_rec_name(rec));
3566 if (rec->cr_flags & CLF_RENAME) {
3567 struct changelog_ext_rename *rnm =
3568 changelog_rec_rename(rec);
3570 if (!fid_is_zero(&rnm->cr_sfid))
3571 printf(" s="DFID" sp="DFID" %.*s",
3572 PFID(&rnm->cr_sfid),
3573 PFID(&rnm->cr_spfid),
3574 (int)changelog_rec_snamelen(rec),
3575 changelog_rec_sname(rec));
3579 llapi_changelog_free(&rec);
3582 llapi_changelog_fini(&changelog_priv);
3585 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3587 return (rc == 1 ? 0 : rc);
3590 static int lfs_changelog_clear(int argc, char **argv)
3598 endrec = strtoll(argv[3], NULL, 10);
3600 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3602 fprintf(stderr, "%s error: %s\n", argv[0],
3603 strerror(errno = -rc));
3607 static int lfs_fid2path(int argc, char **argv)
3609 struct option long_opts[] = {
3610 {"cur", no_argument, 0, 'c'},
3611 {"link", required_argument, 0, 'l'},
3612 {"rec", required_argument, 0, 'r'},
3615 char short_opts[] = "cl:r:";
3616 char *device, *fid, *path;
3617 long long recno = -1;
3623 while ((rc = getopt_long(argc, argv, short_opts,
3624 long_opts, NULL)) != -1) {
3630 linkno = strtol(optarg, NULL, 10);
3633 recno = strtoll(optarg, NULL, 10);
3638 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3639 argv[0], argv[optind - 1]);
3647 device = argv[optind++];
3648 path = calloc(1, PATH_MAX);
3650 fprintf(stderr, "error: Not enough memory\n");
3655 while (optind < argc) {
3656 fid = argv[optind++];
3658 lnktmp = (linkno >= 0) ? linkno : 0;
3660 int oldtmp = lnktmp;
3661 long long rectmp = recno;
3663 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3666 fprintf(stderr, "%s: error on FID %s: %s\n",
3667 argv[0], fid, strerror(errno = -rc2));
3674 fprintf(stdout, "%lld ", rectmp);
3675 if (device[0] == '/') {
3676 fprintf(stdout, "%s", device);
3677 if (device[strlen(device) - 1] != '/')
3678 fprintf(stdout, "/");
3679 } else if (path[0] == '\0') {
3680 fprintf(stdout, "/");
3682 fprintf(stdout, "%s\n", path);
3685 /* specified linkno */
3687 if (oldtmp == lnktmp)
3697 static int lfs_path2fid(int argc, char **argv)
3699 struct option long_opts[] = {
3700 {"parents", no_argument, 0, 'p'},
3704 const char short_opts[] = "p";
3705 const char *sep = "";
3708 bool show_parents = false;
3710 while ((rc = getopt_long(argc, argv, short_opts,
3711 long_opts, NULL)) != -1) {
3714 show_parents = true;
3717 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3718 argv[0], argv[optind - 1]);
3723 if (optind > argc - 1)
3725 else if (optind < argc - 1)
3729 for (path = argv + optind; *path != NULL; path++) {
3731 if (!show_parents) {
3732 err = llapi_path2fid(*path, &fid);
3734 printf("%s%s"DFID"\n",
3735 *sep != '\0' ? *path : "", sep,
3738 char name[NAME_MAX + 1];
3739 unsigned int linkno = 0;
3741 while ((err = llapi_path2parent(*path, linkno, &fid,
3742 name, sizeof(name))) == 0) {
3743 if (*sep != '\0' && linkno == 0)
3744 printf("%s%s", *path, sep);
3746 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3751 /* err == -ENODATA is end-of-loop */
3752 if (linkno > 0 && err == -ENODATA) {
3759 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3760 argv[0], show_parents ? "parent " : "", *path,
3772 static int lfs_data_version(int argc, char **argv)
3779 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3784 while ((c = getopt(argc, argv, "nrw")) != -1) {
3787 data_version_flags = 0;
3790 data_version_flags |= LL_DV_RD_FLUSH;
3793 data_version_flags |= LL_DV_WR_FLUSH;
3802 path = argv[optind];
3803 fd = open(path, O_RDONLY);
3805 err(errno, "cannot open file %s", path);
3807 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3809 err(errno, "cannot get version for %s", path);
3811 printf("%ju" "\n", (uintmax_t)data_version);
3817 static int lfs_hsm_state(int argc, char **argv)
3822 struct hsm_user_state hus;
3830 rc = llapi_hsm_state_get(path, &hus);
3832 fprintf(stderr, "can't get hsm state for %s: %s\n",
3833 path, strerror(errno = -rc));
3837 /* Display path name and status flags */
3838 printf("%s: (0x%08x)", path, hus.hus_states);
3840 if (hus.hus_states & HS_RELEASED)
3841 printf(" released");
3842 if (hus.hus_states & HS_EXISTS)
3844 if (hus.hus_states & HS_DIRTY)
3846 if (hus.hus_states & HS_ARCHIVED)
3847 printf(" archived");
3848 /* Display user-settable flags */
3849 if (hus.hus_states & HS_NORELEASE)
3850 printf(" never_release");
3851 if (hus.hus_states & HS_NOARCHIVE)
3852 printf(" never_archive");
3853 if (hus.hus_states & HS_LOST)
3854 printf(" lost_from_hsm");
3856 if (hus.hus_archive_id != 0)
3857 printf(", archive_id:%d", hus.hus_archive_id);
3860 } while (++i < argc);
3865 #define LFS_HSM_SET 0
3866 #define LFS_HSM_CLEAR 1
3869 * Generic function to set or clear HSM flags.
3870 * Used by hsm_set and hsm_clear.
3872 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3874 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3876 struct option long_opts[] = {
3877 {"lost", 0, 0, 'l'},
3878 {"norelease", 0, 0, 'r'},
3879 {"noarchive", 0, 0, 'a'},
3880 {"archived", 0, 0, 'A'},
3881 {"dirty", 0, 0, 'd'},
3882 {"exists", 0, 0, 'e'},
3885 char short_opts[] = "lraAde";
3893 while ((c = getopt_long(argc, argv, short_opts,
3894 long_opts, NULL)) != -1) {
3900 mask |= HS_NOARCHIVE;
3903 mask |= HS_ARCHIVED;
3906 mask |= HS_NORELEASE;
3917 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3918 argv[0], argv[optind - 1]);
3923 /* User should have specified a flag */
3927 while (optind < argc) {
3929 path = argv[optind];
3931 /* If mode == 0, this means we apply the mask. */
3932 if (mode == LFS_HSM_SET)
3933 rc = llapi_hsm_state_set(path, mask, 0, 0);
3935 rc = llapi_hsm_state_set(path, 0, mask, 0);
3938 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3939 path, strerror(errno = -rc));
3948 static int lfs_hsm_action(int argc, char **argv)
3953 struct hsm_current_action hca;
3954 struct hsm_extent he;
3955 enum hsm_user_action hua;
3956 enum hsm_progress_states hps;
3964 rc = llapi_hsm_current_action(path, &hca);
3966 fprintf(stderr, "can't get hsm action for %s: %s\n",
3967 path, strerror(errno = -rc));
3970 he = hca.hca_location;
3971 hua = hca.hca_action;
3972 hps = hca.hca_state;
3974 printf("%s: %s", path, hsm_user_action2name(hua));
3976 /* Skip file without action */
3977 if (hca.hca_action == HUA_NONE) {
3982 printf(" %s ", hsm_progress_state2name(hps));
3984 if ((hps == HPS_RUNNING) &&
3985 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3986 printf("(%llu bytes moved)\n",
3987 (unsigned long long)he.length);
3988 else if ((he.offset + he.length) == LUSTRE_EOF)
3989 printf("(from %llu to EOF)\n",
3990 (unsigned long long)he.offset);
3992 printf("(from %llu to %llu)\n",
3993 (unsigned long long)he.offset,
3994 (unsigned long long)(he.offset + he.length));
3996 } while (++i < argc);
4001 static int lfs_hsm_set(int argc, char **argv)
4003 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4006 static int lfs_hsm_clear(int argc, char **argv)
4008 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4012 * Check file state and return its fid, to be used by lfs_hsm_request().
4014 * \param[in] file Path to file to check
4015 * \param[in,out] fid Pointer to allocated lu_fid struct.
4016 * \param[in,out] last_dev Pointer to last device id used.
4018 * \return 0 on success.
4020 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4026 rc = lstat(file, &st);
4028 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4031 /* Checking for regular file as archiving as posix copytool
4032 * rejects archiving files other than regular files
4034 if (!S_ISREG(st.st_mode)) {
4035 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4038 /* A request should be ... */
4039 if (*last_dev != st.st_dev && *last_dev != 0) {
4040 fprintf(stderr, "All files should be "
4041 "on the same filesystem: %s\n", file);
4044 *last_dev = st.st_dev;
4046 rc = llapi_path2fid(file, fid);
4048 fprintf(stderr, "Cannot read FID of %s: %s\n",
4049 file, strerror(-rc));
4055 /* Fill an HSM HUR item with a given file name.
4057 * If mntpath is set, then the filename is actually a FID, and no
4058 * lookup on the filesystem will be performed.
4060 * \param[in] hur the user request to fill
4061 * \param[in] idx index of the item inside the HUR to fill
4062 * \param[in] mntpath mountpoint of Lustre
4063 * \param[in] fname filename (if mtnpath is NULL)
4064 * or FID (if mntpath is set)
4065 * \param[in] last_dev pointer to last device id used
4067 * \retval 0 on success
4068 * \retval CMD_HELP or a negative errno on error
4070 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4071 const char *mntpath, const char *fname,
4074 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4077 hui->hui_extent.length = -1;
4079 if (mntpath != NULL) {
4082 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4086 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4091 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4095 hur->hur_request.hr_itemcount++;
4100 static int lfs_hsm_request(int argc, char **argv, int action)
4102 struct option long_opts[] = {
4103 {"filelist", 1, 0, 'l'},
4104 {"data", 1, 0, 'D'},
4105 {"archive", 1, 0, 'a'},
4106 {"mntpath", 1, 0, 'm'},
4110 char short_opts[] = "l:D:a:m:";
4111 struct hsm_user_request *hur, *oldhur;
4116 char *filelist = NULL;
4117 char fullpath[PATH_MAX];
4118 char *opaque = NULL;
4122 int nbfile_alloc = 0;
4123 char *some_file = NULL;
4124 char *mntpath = NULL;
4130 while ((c = getopt_long(argc, argv, short_opts,
4131 long_opts, NULL)) != -1) {
4140 if (action != HUA_ARCHIVE &&
4141 action != HUA_REMOVE) {
4143 "error: -a is supported only "
4144 "when archiving or removing\n");
4147 archive_id = atoi(optarg);
4150 if (some_file == NULL) {
4152 some_file = strdup(optarg);
4158 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4159 argv[0], argv[optind - 1]);
4164 /* All remaining args are files, so we have at least nbfile */
4165 nbfile = argc - optind;
4167 if ((nbfile == 0) && (filelist == NULL))
4171 opaque_len = strlen(opaque);
4173 /* Alloc the request structure with enough place to store all files
4174 * from command line. */
4175 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4177 fprintf(stderr, "Cannot create the request: %s\n",
4181 nbfile_alloc = nbfile;
4183 hur->hur_request.hr_action = action;
4184 hur->hur_request.hr_archive_id = archive_id;
4185 hur->hur_request.hr_flags = 0;
4187 /* All remaining args are files, add them */
4188 if (nbfile != 0 && some_file == NULL)
4189 some_file = strdup(argv[optind]);
4191 for (i = 0; i < nbfile; i++) {
4192 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4198 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4200 /* If a filelist was specified, read the filelist from it. */
4201 if (filelist != NULL) {
4202 fp = fopen(filelist, "r");
4204 fprintf(stderr, "Cannot read the file list %s: %s\n",
4205 filelist, strerror(errno));
4210 while ((rc = getline(&line, &len, fp)) != -1) {
4211 /* If allocated buffer was too small, get something
4213 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4216 nbfile_alloc = nbfile_alloc * 2 + 1;
4218 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4221 fprintf(stderr, "hsm: cannot allocate "
4222 "the request: %s\n",
4229 size = hur_len(oldhur);
4231 fprintf(stderr, "hsm: cannot allocate "
4232 "%u files + %u bytes data\n",
4233 oldhur->hur_request.hr_itemcount,
4234 oldhur->hur_request.hr_data_len);
4241 memcpy(hur, oldhur, size);
4246 if (line[strlen(line) - 1] == '\n')
4247 line[strlen(line) - 1] = '\0';
4249 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4250 mntpath, line, &last_dev);
4256 if (some_file == NULL) {
4266 /* If a --data was used, add it to the request */
4267 hur->hur_request.hr_data_len = opaque_len;
4269 memcpy(hur_data(hur), opaque, opaque_len);
4271 /* Send the HSM request */
4272 if (realpath(some_file, fullpath) == NULL) {
4273 fprintf(stderr, "Could not find path '%s': %s\n",
4274 some_file, strerror(errno));
4276 rc = llapi_hsm_request(fullpath, hur);
4278 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4279 some_file, strerror(-rc));
4289 static int lfs_hsm_archive(int argc, char **argv)
4291 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4294 static int lfs_hsm_restore(int argc, char **argv)
4296 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4299 static int lfs_hsm_release(int argc, char **argv)
4301 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4304 static int lfs_hsm_remove(int argc, char **argv)
4306 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4309 static int lfs_hsm_cancel(int argc, char **argv)
4311 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4314 static int lfs_swap_layouts(int argc, char **argv)
4319 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4320 SWAP_LAYOUTS_KEEP_MTIME |
4321 SWAP_LAYOUTS_KEEP_ATIME);
4324 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
4326 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
4328 enum lu_ladvise_type advice;
4331 advice < ARRAY_SIZE(ladvise_names); advice++) {
4332 if (ladvise_names[advice] == NULL)
4334 if (strcmp(string, ladvise_names[advice]) == 0)
4338 return LU_LADVISE_INVALID;
4341 static int lfs_ladvise(int argc, char **argv)
4343 struct option long_opts[] = {
4344 {"advice", required_argument, 0, 'a'},
4345 {"background", no_argument, 0, 'b'},
4346 {"end", required_argument, 0, 'e'},
4347 {"start", required_argument, 0, 's'},
4348 {"length", required_argument, 0, 'l'},
4351 char short_opts[] = "a:be:l:s:";
4356 struct llapi_lu_ladvise advice;
4357 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
4358 unsigned long long start = 0;
4359 unsigned long long end = LUSTRE_EOF;
4360 unsigned long long length = 0;
4361 unsigned long long size_units;
4362 unsigned long long flags = 0;
4365 while ((c = getopt_long(argc, argv, short_opts,
4366 long_opts, NULL)) != -1) {
4369 advice_type = lfs_get_ladvice(optarg);
4370 if (advice_type == LU_LADVISE_INVALID) {
4371 fprintf(stderr, "%s: invalid advice type "
4372 "'%s'\n", argv[0], optarg);
4373 fprintf(stderr, "Valid types:");
4375 for (advice_type = 0;
4376 advice_type < ARRAY_SIZE(ladvise_names);
4378 if (ladvise_names[advice_type] == NULL)
4380 fprintf(stderr, " %s",
4381 ladvise_names[advice_type]);
4383 fprintf(stderr, "\n");
4393 rc = llapi_parse_size(optarg, &end,
4396 fprintf(stderr, "%s: bad end offset '%s'\n",
4403 rc = llapi_parse_size(optarg, &start,
4406 fprintf(stderr, "%s: bad start offset "
4407 "'%s'\n", argv[0], optarg);
4413 rc = llapi_parse_size(optarg, &length,
4416 fprintf(stderr, "%s: bad length '%s'\n",
4424 fprintf(stderr, "%s: option '%s' unrecognized\n",
4425 argv[0], argv[optind - 1]);
4430 if (advice_type == LU_LADVISE_INVALID) {
4431 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
4432 fprintf(stderr, "Valid types:");
4433 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
4435 if (ladvise_names[advice_type] == NULL)
4437 fprintf(stderr, " %s", ladvise_names[advice_type]);
4439 fprintf(stderr, "\n");
4443 if (argc <= optind) {
4444 fprintf(stderr, "%s: please give one or more file names\n",
4449 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
4450 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
4455 if (end == LUSTRE_EOF && length != 0)
4456 end = start + length;
4459 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
4460 argv[0], start, end);
4464 while (optind < argc) {
4467 path = argv[optind++];
4469 fd = open(path, O_RDONLY);
4471 fprintf(stderr, "%s: cannot open file '%s': %s\n",
4472 argv[0], path, strerror(errno));
4477 advice.lla_start = start;
4478 advice.lla_end = end;
4479 advice.lla_advice = advice_type;
4480 advice.lla_value1 = 0;
4481 advice.lla_value2 = 0;
4482 advice.lla_value3 = 0;
4483 advice.lla_value4 = 0;
4484 rc2 = llapi_ladvise(fd, flags, 1, &advice);
4487 fprintf(stderr, "%s: cannot give advice '%s' to file "
4488 "'%s': %s\n", argv[0],
4489 ladvise_names[advice_type],
4490 path, strerror(errno));
4493 if (rc == 0 && rc2 < 0)
4499 int main(int argc, char **argv)
4503 /* Ensure that liblustreapi constructor has run */
4504 if (!liblustreapi_initialized)
4505 fprintf(stderr, "liblustreapi was not properly initialized\n");
4509 Parser_init("lfs > ", cmdlist);
4511 progname = argv[0]; /* Used in error messages */
4513 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4515 rc = Parser_commands();
4518 return rc < 0 ? -rc : rc;
4521 #ifdef _LUSTRE_IDL_H_
4522 /* Everything we need here should be included by lustreapi.h. */
4523 # error "lfs should not depend on lustre_idl.h"
4524 #endif /* _LUSTRE_IDL_H_ */