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_cp(int argc, char **argv);
96 static int lfs_ls(int argc, char **argv);
97 static int lfs_poollist(int argc, char **argv);
98 static int lfs_changelog(int argc, char **argv);
99 static int lfs_changelog_clear(int argc, char **argv);
100 static int lfs_fid2path(int argc, char **argv);
101 static int lfs_path2fid(int argc, char **argv);
102 static int lfs_data_version(int argc, char **argv);
103 static int lfs_hsm_state(int argc, char **argv);
104 static int lfs_hsm_set(int argc, char **argv);
105 static int lfs_hsm_clear(int argc, char **argv);
106 static int lfs_hsm_action(int argc, char **argv);
107 static int lfs_hsm_archive(int argc, char **argv);
108 static int lfs_hsm_restore(int argc, char **argv);
109 static int lfs_hsm_release(int argc, char **argv);
110 static int lfs_hsm_remove(int argc, char **argv);
111 static int lfs_hsm_cancel(int argc, char **argv);
112 static int lfs_swap_layouts(int argc, char **argv);
113 static int lfs_mv(int argc, char **argv);
114 static int lfs_ladvise(int argc, char **argv);
115 static int lfs_list_commands(int argc, char **argv);
117 /* Setstripe and migrate share mostly the same parameters */
118 #define SSM_CMD_COMMON(cmd) \
119 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
120 " [--stripe-index|-i <start_ost_idx>]\n" \
121 " [--stripe-size|-S <stripe_size>]\n" \
122 " [--pool|-p <pool_name>]\n" \
123 " [--ost|-o <ost_indices>]\n"
125 #define SSM_HELP_COMMON \
126 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
127 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
128 "\t respectively)\n" \
129 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
130 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
131 "\tpool_name: Name of OST pool to use (default none)\n" \
132 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
133 "\t Indices be specified in a format of:\n" \
134 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
136 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
137 "\t If --pool is set with --ost, then the OSTs\n" \
138 "\t must be the members of the pool."
140 #define SETSTRIPE_USAGE \
141 SSM_CMD_COMMON("setstripe") \
142 " <directory|filename>\n" \
145 #define MIGRATE_USAGE \
146 SSM_CMD_COMMON("migrate ") \
148 " [--non-block|-n]\n" \
152 "\tblock: Block file access during data migration (default)\n" \
153 "\tnon-block: Abort migrations if concurrent access is detected\n" \
155 #define SETDIRSTRIPE_USAGE \
156 " [--mdt-count|-c stripe_count>\n" \
157 " [--mdt-index|-i mdt_index]\n" \
158 " [--mdt-hash|-t mdt_hash]\n" \
159 " [--default|-D] [--mode|-m mode] <dir>\n" \
160 "\tstripe_count: stripe count of the striped directory\n" \
161 "\tmdt_index: MDT index of first stripe\n" \
162 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
163 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
164 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
165 "\tdefault_stripe: set default dirstripe of the directory\n" \
166 "\tmode: the mode of the directory\n"
168 static const char *progname;
169 static bool file_lease_supported = true;
171 /* all available commands */
172 command_t cmdlist[] = {
173 {"setstripe", lfs_setstripe, 0,
174 "Create a new file with a specific striping pattern or\n"
175 "set the default striping pattern on an existing directory or\n"
176 "delete the default striping pattern from an existing directory\n"
177 "usage: setstripe -d <directory> (to delete default striping)\n"\
180 {"getstripe", lfs_getstripe, 0,
181 "To list the striping info for a given file or files in a\n"
182 "directory or recursively for all files in a directory tree.\n"
183 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
184 " [--stripe-count|-c] [--stripe-index|-i]\n"
185 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
186 " [--mdt|-m] [--recursive|-r] [--raw|-R]\n"
187 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
188 " <directory|filename> ..."},
189 {"setdirstripe", lfs_setdirstripe, 0,
190 "To create a striped directory on a specified MDT. This can only\n"
191 "be done on MDT0 with the right of administrator.\n"
192 "usage: setdirstripe [OPTION] <directory>\n"
194 {"getdirstripe", lfs_getdirstripe, 0,
195 "To list the striping info for a given directory\n"
196 "or recursively for all directories in a directory tree.\n"
197 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
198 " [--mdt-index|-i] [--mdt-hash|-t]\n"
199 " [--recursive|-r] [--default|-D] <dir> ..."},
200 {"mkdir", lfs_setdirstripe, 0,
201 "To create a striped directory on a specified MDT. This can only\n"
202 "be done on MDT0 with the right of administrator.\n"
203 "usage: mkdir [OPTION] <directory>\n"
205 {"rm_entry", lfs_rmentry, 0,
206 "To remove the name entry of the remote directory. Note: This\n"
207 "command will only delete the name entry, i.e. the remote directory\n"
208 "will become inaccessable after this command. This can only be done\n"
209 "by the administrator\n"
210 "usage: rm_entry <dir>\n"},
211 {"pool_list", lfs_poollist, 0,
212 "List pools or pool OSTs\n"
213 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
214 {"find", lfs_find, 0,
215 "find files matching given attributes recursively in directory tree.\n"
216 "usage: find <directory|filename> ...\n"
217 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
218 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
219 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
220 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
221 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
222 " [[!] --stripe-count|-c [+-]<stripes>]\n"
223 " [[!] --stripe-index|-i <index,...>]\n"
224 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
225 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
226 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
227 " [[!] --layout|-L released,raid0]\n"
228 "\t !: used before an option indicates 'NOT' requested attribute\n"
229 "\t -: used before a value indicates 'AT MOST' requested value\n"
230 "\t +: used before a value indicates 'AT LEAST' requested value\n"},
231 {"check", lfs_check, 0,
232 "Display the status of MDS or OSTs (as specified in the command)\n"
233 "or all the servers (MDS and OSTs).\n"
234 "usage: check <osts|mds|servers>"},
235 {"osts", lfs_osts, 0, "list OSTs connected to client "
236 "[for specified path only]\n" "usage: osts [path]"},
237 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
238 "[for specified path only]\n" "usage: mdts [path]"},
240 "report filesystem disk space usage or inodes usage"
241 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
242 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
243 {"getname", lfs_getname, 0, "list instances and specified mount points "
244 "[for specified path only]\n"
245 "Usage: getname [-h]|[path ...] "},
246 #ifdef HAVE_SYS_QUOTA_H
247 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
248 "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
249 " -b <block-softlimit> -B <block-hardlimit>\n"
250 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
251 " setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
252 " [--block-softlimit <block-softlimit>]\n"
253 " [--block-hardlimit <block-hardlimit>]\n"
254 " [--inode-softlimit <inode-softlimit>]\n"
255 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
256 " setquota [-t] <-u|--user|-g|--group>\n"
257 " [--block-grace <block-grace>]\n"
258 " [--inode-grace <inode-grace>] <filesystem>\n"
259 " -b can be used instead of --block-softlimit/--block-grace\n"
260 " -B can be used instead of --block-hardlimit\n"
261 " -i can be used instead of --inode-softlimit/--inode-grace\n"
262 " -I can be used instead of --inode-hardlimit\n\n"
263 "Note: The total quota space will be split into many qunits and\n"
264 " balanced over all server targets, the minimal qunit size is\n"
265 " 1M bytes for block space and 1K inodes for inode space.\n\n"
266 " Quota space rebalancing process will stop when this mininum\n"
267 " value is reached. As a result, quota exceeded can be returned\n"
268 " while many targets still have 1MB or 1K inodes of spare\n"
270 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
271 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
273 " [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
274 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
276 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
277 "usage: flushctx [-k] [mountpoint...]"},
279 "Remote user copy files and directories.\n"
280 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
282 "Remote user list directory contents.\n"
283 "usage: ls [OPTION]... [FILE]..."},
284 {"changelog", lfs_changelog, 0,
285 "Show the metadata changes on an MDT."
286 "\nusage: changelog <mdtname> [startrec [endrec]]"},
287 {"changelog_clear", lfs_changelog_clear, 0,
288 "Indicate that old changelog records up to <endrec> are no longer of "
289 "interest to consumer <id>, allowing the system to free up space.\n"
290 "An <endrec> of 0 means all records.\n"
291 "usage: changelog_clear <mdtname> <id> <endrec>"},
292 {"fid2path", lfs_fid2path, 0,
293 "Resolve the full path(s) for given FID(s). For a specific hardlink "
294 "specify link number <linkno>.\n"
295 /* "For a historical link name, specify changelog record <recno>.\n" */
296 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
297 /* [ --rec <recno> ] */ },
298 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
299 "usage: path2fid [--parents] <path> ..."},
300 {"data_version", lfs_data_version, 0, "Display file data version for "
301 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
302 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
303 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
304 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
305 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
306 "[--archived] [--lost] <file> ..."},
307 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
309 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
310 "[--archived] [--lost] <file> ..."},
311 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
312 "given files.\n" "usage: hsm_action <file> ..."},
313 {"hsm_archive", lfs_hsm_archive, 0,
314 "Archive file to external storage.\n"
315 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
317 {"hsm_restore", lfs_hsm_restore, 0,
318 "Restore file from external storage.\n"
319 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
320 {"hsm_release", lfs_hsm_release, 0,
321 "Release files from Lustre.\n"
322 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
323 {"hsm_remove", lfs_hsm_remove, 0,
324 "Remove file copy from external storage.\n"
325 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
326 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
328 "Note: To remove files from the archive that have been deleted on\n"
329 "Lustre, set mntpath and optionally archive. In that case, all the\n"
330 "positional arguments and entries in the file list must be FIDs."
332 {"hsm_cancel", lfs_hsm_cancel, 0,
333 "Cancel requests related to specified files.\n"
334 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
335 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
336 "usage: swap_layouts <path1> <path2>"},
337 {"migrate", lfs_setstripe, 0,
338 "migrate a directory between MDTs.\n"
339 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
341 "\tmdt_idx: index of the destination MDT\n"
343 "migrate file objects from one OST "
344 "layout\nto another (may be not safe with concurent writes).\n"
346 "[--stripe-count|-c] <stripe_count>\n"
347 " [--stripe-index|-i] <start_ost_index>\n"
348 " [--stripe-size|-S] <stripe_size>\n"
349 " [--pool|-p] <pool_name>\n"
350 " [--ost-list|-o] <ost_indices>\n"
352 " [--non-block|-n]\n"
353 " <file|directory>\n"
354 "\tstripe_count: number of OSTs to stripe a file over\n"
355 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
356 "\tstripe_size: number of bytes to store before moving to the next OST\n"
357 "\tpool_name: name of the predefined pool of OSTs\n"
358 "\tost_indices: OSTs to stripe over, in order\n"
359 "\tblock: wait for the operation to return before continuing\n"
360 "\tnon-block: do not wait for the operation to return.\n"},
362 "To move directories between MDTs. This command is deprecated, "
363 "use \"migrate\" instead.\n"
364 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
366 {"ladvise", lfs_ladvise, 0,
367 "Provide servers with advice about access patterns for a file.\n"
368 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
369 " [--background|-b]\n"
370 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
372 {"help", Parser_help, 0, "help"},
373 {"exit", Parser_quit, 0, "quit"},
374 {"quit", Parser_quit, 0, "quit"},
375 {"--version", Parser_version, 0,
376 "output build version of the utility and exit"},
377 {"--list-commands", lfs_list_commands, 0,
378 "list commands supported by the utility and exit"},
383 #define MIGRATION_NONBLOCK 1
386 * Internal helper for migrate_copy_data(). Check lease and report error if
389 * \param[in] fd File descriptor on which to check the lease.
390 * \param[out] lease_broken Set to true if the lease was broken.
391 * \param[in] group_locked Whether a group lock was taken or not.
392 * \param[in] path Name of the file being processed, for error
395 * \retval 0 Migration can keep on going.
396 * \retval -errno Error occurred, abort migration.
398 static int check_lease(int fd, bool *lease_broken, bool group_locked,
403 if (!file_lease_supported)
406 rc = llapi_lease_check(fd);
408 return 0; /* llapi_check_lease returns > 0 on success. */
411 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
413 rc = rc ? rc : -EAGAIN;
415 fprintf(stderr, "%s: external attempt to access file '%s' "
416 "blocked until migration ends.\n", progname, path);
419 *lease_broken = true;
423 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
424 bool group_locked, const char *fname)
433 bool lease_broken = false;
435 /* Use a page-aligned buffer for direct I/O */
436 rc = posix_memalign(&buf, getpagesize(), buf_size);
441 /* read new data only if we have written all
442 * previously read data */
445 rc = check_lease(fd_src, &lease_broken,
446 group_locked, fname);
450 rsize = read(fd_src, buf, buf_size);
453 fprintf(stderr, "%s: %s: read failed: %s\n",
454 progname, fname, strerror(-rc));
464 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
468 "%s: %s: write failed on volatile: %s\n",
469 progname, fname, strerror(-rc));
479 fprintf(stderr, "%s: %s: fsync failed: %s\n",
480 progname, fname, strerror(-rc));
488 static int migrate_copy_timestamps(int fdv, const struct stat *st)
490 struct timeval tv[2] = {
491 {.tv_sec = st->st_atime},
492 {.tv_sec = st->st_mtime}
495 return futimes(fdv, tv);
498 static int migrate_block(int fd, int fdv, const struct stat *st,
499 size_t buf_size, const char *name)
506 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
508 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
509 progname, name, strerror(-rc));
517 /* The grouplock blocks all concurrent accesses to the file.
518 * It has to be taken after llapi_get_data_version as it would
520 rc = llapi_group_lock(fd, gid);
522 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
523 progname, name, strerror(-rc));
527 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
529 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
533 /* Make sure we keep original atime/mtime values */
534 rc = migrate_copy_timestamps(fdv, st);
536 fprintf(stderr, "%s: %s: timestamp copy failed\n",
542 * for a migration we need to check data version on file did
545 * Pass in gid=0 since we already own grouplock. */
546 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
547 SWAP_LAYOUTS_CHECK_DV1);
549 fprintf(stderr, "%s: %s: dataversion changed during copy, "
550 "migration aborted\n", progname, name);
553 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
554 name, strerror(-rc));
559 rc2 = llapi_group_unlock(fd, gid);
560 if (rc2 < 0 && rc == 0) {
561 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
562 progname, name, strerror(-rc2));
569 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
570 size_t buf_size, const char *name)
576 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
578 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
579 progname, name, strerror(-rc));
583 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
585 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
589 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
591 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
592 progname, name, strerror(-rc));
598 fprintf(stderr, "%s: %s: data version changed during "
604 /* Make sure we keep original atime/mtime values */
605 rc = migrate_copy_timestamps(fdv, st);
607 fprintf(stderr, "%s: %s: timestamp copy failed\n",
612 /* Atomically put lease, swap layouts and close.
613 * for a migration we need to check data version on file did
615 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
617 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
618 progname, name, strerror(-rc));
625 static int lfs_migrate(char *name, __u64 migration_flags,
626 struct llapi_stripe_param *param)
630 char parent[PATH_MAX];
633 char volatile_file[sizeof(parent) +
634 LUSTRE_VOLATILE_HDR_LEN +
635 2 * sizeof(mdt_index) +
636 2 * sizeof(random_value) + 4];
639 struct lov_user_md *lum = NULL;
642 bool have_lease_rdlck = false;
646 /* find the right size for the IO and allocate the buffer */
647 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
648 lum = malloc(lum_size);
654 rc = llapi_file_get_stripe(name, lum);
655 /* failure can happen for many reasons and some may be not real errors
657 * in case of a real error, a later call will fail with better
658 * error management */
660 buf_size = 1024 * 1024;
662 buf_size = lum->lmm_stripe_size;
664 /* open file, direct io */
665 /* even if the file is only read, WR mode is nedeed to allow
666 * layout swap on fd */
667 fd = open(name, O_RDWR | O_DIRECT);
670 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
675 if (file_lease_supported) {
676 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
677 if (rc == -EOPNOTSUPP) {
678 /* Older servers do not support file lease.
679 * Disable related checks. This opens race conditions
680 * as explained in LU-4840 */
681 file_lease_supported = false;
683 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
684 progname, name, strerror(-rc));
687 have_lease_rdlck = true;
691 /* search for file directory pathname */
692 if (strlen(name) > sizeof(parent)-1) {
696 strncpy(parent, name, sizeof(parent));
697 ptr = strrchr(parent, '/');
699 if (getcwd(parent, sizeof(parent)) == NULL) {
710 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
712 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
713 progname, name, strerror(-rc));
718 random_value = random();
719 rc = snprintf(volatile_file, sizeof(volatile_file),
720 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
721 mdt_index, random_value);
722 if (rc >= sizeof(volatile_file)) {
727 /* create, open a volatile file, use caching (ie no directio) */
728 fdv = llapi_file_open_param(volatile_file,
729 O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW,
730 S_IRUSR | S_IWUSR, param);
731 } while (fdv == -EEXIST);
735 fprintf(stderr, "%s: %s: cannot create volatile file in"
737 progname, parent, strerror(-rc));
741 /* In case the MDT does not support creation of volatile files
742 * we should try to unlink it. */
743 (void)unlink(volatile_file);
745 /* Not-owner (root?) special case.
746 * Need to set owner/group of volatile file like original.
747 * This will allow to pass related check during layout_swap.
752 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
756 rc = fstat(fdv, &stv);
759 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
760 volatile_file, strerror(errno));
763 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
764 rc = fchown(fdv, st.st_uid, st.st_gid);
767 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
768 name, strerror(errno));
773 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
774 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
776 have_lease_rdlck = false;
777 fdv = -1; /* The volatile file is closed as we put the
778 * lease in non-blocking mode. */
781 /* Blocking mode (forced if servers do not support file lease).
782 * It is also the default mode, since we cannot distinguish
783 * between a broken lease and a server that does not support
784 * atomic swap/close (LU-6785) */
785 rc = migrate_block(fd, fdv, &st, buf_size, name);
789 if (have_lease_rdlck)
806 * Parse a string containing an OST index list into an array of integers.
808 * The input string contains a comma delimited list of individual
809 * indices and ranges, for example "1,2-4,7". Add the indices into the
810 * \a osts array and remove duplicates.
812 * \param[out] osts array to store indices in
813 * \param[in] size size of \a osts array
814 * \param[in] offset starting index in \a osts
815 * \param[in] arg string containing OST index list
817 * \retval positive number of indices in \a osts
818 * \retval -EINVAL unable to parse \a arg
820 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
824 int slots = size - offset;
832 while (!end_of_loop) {
840 ptr = strchrnul(arg, ',');
842 end_of_loop = *ptr == '\0';
845 start_index = strtol(arg, &endptr, 0);
846 if (endptr == arg) /* no data at all */
848 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
853 end_index = start_index;
854 if (*endptr == '-') {
855 end_index = strtol(endptr + 1, &endptr, 0);
858 if (end_index < start_index)
862 for (i = start_index; i <= end_index && slots > 0; i++) {
865 /* remove duplicate */
866 for (j = 0; j < offset; j++) {
870 if (j == offset) { /* no duplicate */
875 if (slots == 0 && i < end_index)
883 if (!end_of_loop && ptr != NULL)
886 return rc < 0 ? rc : nr;
890 static int lfs_setstripe(int argc, char **argv)
892 struct llapi_stripe_param *param = NULL;
893 struct find_param migrate_mdt_param = {
900 unsigned long long st_size;
901 int st_offset, st_count;
905 char *stripe_size_arg = NULL;
906 char *stripe_off_arg = NULL;
907 char *stripe_count_arg = NULL;
908 char *pool_name_arg = NULL;
909 char *mdt_idx_arg = NULL;
910 unsigned long long size_units = 1;
911 bool migrate_mode = false;
912 bool migration_block = false;
913 __u64 migration_flags = 0;
914 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
917 struct option long_opts[] = {
918 /* --block is only valid in migrate mode */
919 {"block", no_argument, 0, 'b'},
920 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
921 /* This formerly implied "stripe-count", but was explicitly
922 * made "stripe-count" for consistency with other options,
923 * and to separate it from "mdt-count" when DNE arrives. */
924 {"count", required_argument, 0, 'c'},
926 {"stripe-count", required_argument, 0, 'c'},
927 {"stripe_count", required_argument, 0, 'c'},
928 {"delete", no_argument, 0, 'd'},
929 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
930 /* This formerly implied "stripe-index", but was explicitly
931 * made "stripe-index" for consistency with other options,
932 * and to separate it from "mdt-index" when DNE arrives. */
933 {"index", required_argument, 0, 'i'},
935 {"stripe-index", required_argument, 0, 'i'},
936 {"stripe_index", required_argument, 0, 'i'},
937 {"mdt", required_argument, 0, 'm'},
938 {"mdt-index", required_argument, 0, 'm'},
939 {"mdt_index", required_argument, 0, 'm'},
940 /* --non-block is only valid in migrate mode */
941 {"non-block", no_argument, 0, 'n'},
942 {"ost", required_argument, 0, 'o'},
943 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
944 {"ost-list", required_argument, 0, 'o'},
945 {"ost_list", required_argument, 0, 'o'},
947 {"pool", required_argument, 0, 'p'},
948 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
949 /* This formerly implied "--stripe-size", but was confusing
950 * with "lfs find --size|-s", which means "file size", so use
951 * the consistent "--stripe-size|-S" for all commands. */
952 {"size", required_argument, 0, 's'},
954 {"stripe-size", required_argument, 0, 'S'},
955 {"stripe_size", required_argument, 0, 'S'},
956 /* --verbose is only valid in migrate mode */
957 {"verbose", no_argument, 0, 'v'},
965 if (strcmp(argv[0], "migrate") == 0)
968 while ((c = getopt_long(argc, argv, "bc:di:m:no:p:s:S:v",
969 long_opts, NULL)) >= 0) {
976 fprintf(stderr, "--block is valid only for"
980 migration_block = true;
983 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
984 if (strcmp(argv[optind - 1], "--count") == 0)
985 fprintf(stderr, "warning: '--count' deprecated"
986 ", use '--stripe-count' instead\n");
988 stripe_count_arg = optarg;
991 /* delete the default striping pattern */
995 nr_osts = parse_targets(osts,
996 sizeof(osts) / sizeof(__u32),
1000 "error: %s: bad OST indices '%s'\n",
1005 if (st_offset == -1) /* first in the command line */
1006 st_offset = osts[0];
1009 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1010 if (strcmp(argv[optind - 1], "--index") == 0)
1011 fprintf(stderr, "warning: '--index' deprecated"
1012 ", use '--stripe-index' instead\n");
1014 stripe_off_arg = optarg;
1017 if (!migrate_mode) {
1018 fprintf(stderr, "--mdt-index is valid only for"
1022 mdt_idx_arg = optarg;
1025 if (!migrate_mode) {
1026 fprintf(stderr, "--non-block is valid only for"
1030 migration_flags |= MIGRATION_NONBLOCK;
1032 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1034 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1035 fprintf(stderr, "warning: '--size|-s' deprecated, "
1036 "use '--stripe-size|-S' instead\n");
1038 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1040 stripe_size_arg = optarg;
1043 pool_name_arg = optarg;
1046 if (!migrate_mode) {
1047 fprintf(stderr, "--verbose is valid only for"
1051 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1058 fname = argv[optind];
1061 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
1062 stripe_count_arg != NULL || pool_name_arg != NULL)) {
1063 fprintf(stderr, "error: %s: cannot specify -d with "
1064 "-s, -c, -o, or -p options\n",
1069 if (optind == argc) {
1070 fprintf(stderr, "error: %s: missing filename|dirname\n",
1075 if (mdt_idx_arg != NULL && optind > 3) {
1076 fprintf(stderr, "error: %s: cannot specify -m with other "
1077 "options\n", argv[0]);
1081 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1083 "error: %s: cannot specify --non-block and --block\n",
1088 if (pool_name_arg != NULL) {
1092 ptr = strchr(pool_name_arg, '.');
1094 ptr = pool_name_arg;
1096 if ((ptr - pool_name_arg) == 0) {
1097 fprintf(stderr, "error: %s: fsname is empty "
1098 "in pool name '%s'\n",
1099 argv[0], pool_name_arg);
1106 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1108 fprintf(stderr, "error: %s: poolname '%s' is "
1110 argv[0], pool_name_arg);
1112 } else if (rc == -2) {
1113 fprintf(stderr, "error: %s: pool name '%s' is too long "
1114 "(max is %d characters)\n",
1115 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1117 } else if (rc > 0) {
1118 fprintf(stderr, "error: %s: char '%c' not allowed in "
1120 argv[0], rc, pool_name_arg);
1125 /* get the stripe size */
1126 if (stripe_size_arg != NULL) {
1127 result = llapi_parse_size(stripe_size_arg, &st_size,
1130 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1131 argv[0], stripe_size_arg);
1135 /* get the stripe offset */
1136 if (stripe_off_arg != NULL) {
1137 st_offset = strtol(stripe_off_arg, &end, 0);
1139 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1140 argv[0], stripe_off_arg);
1144 /* get the stripe count */
1145 if (stripe_count_arg != NULL) {
1146 st_count = strtoul(stripe_count_arg, &end, 0);
1148 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1149 argv[0], stripe_count_arg);
1154 if (mdt_idx_arg != NULL) {
1155 /* initialize migrate mdt parameters */
1156 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1158 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1159 argv[0], mdt_idx_arg);
1162 migrate_mdt_param.fp_migrate = 1;
1164 /* initialize stripe parameters */
1165 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1166 if (param == NULL) {
1167 fprintf(stderr, "error: %s: run out of memory\n",
1172 param->lsp_stripe_size = st_size;
1173 param->lsp_stripe_offset = st_offset;
1174 param->lsp_stripe_count = st_count;
1175 param->lsp_stripe_pattern = 0;
1176 param->lsp_pool = pool_name_arg;
1177 param->lsp_is_specific = false;
1179 if (st_count > 0 && nr_osts != st_count) {
1180 fprintf(stderr, "error: %s: stripe count '%d' "
1181 "doesn't match the number of OSTs: %d\n"
1182 , argv[0], st_count, nr_osts);
1187 param->lsp_is_specific = true;
1188 param->lsp_stripe_count = nr_osts;
1189 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1193 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1194 if (!migrate_mode) {
1195 result = llapi_file_open_param(fname,
1202 } else if (mdt_idx_arg != NULL) {
1203 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1205 result = lfs_migrate(fname, migration_flags, param);
1208 /* Save the first error encountered. */
1211 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1212 argv[0], migrate_mode ? "migrate" : "create",
1214 pool_name_arg != NULL && result == EINVAL ?
1215 "OST not in pool?" : strerror(errno));
1224 static int lfs_poollist(int argc, char **argv)
1229 return llapi_poollist(argv[1]);
1232 static int set_time(time_t *time, time_t *set, char *str)
1239 else if (str[0] == '-')
1245 t = strtol(str, NULL, 0);
1246 if (*time < t * 24 * 60 * 60) {
1249 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1253 *set = *time - t * 24 * 60 * 60;
1260 static int name2id(unsigned int *id, char *name, int type)
1263 struct passwd *entry;
1265 if (!(entry = getpwnam(name))) {
1271 *id = entry->pw_uid;
1273 struct group *entry;
1275 if (!(entry = getgrnam(name))) {
1281 *id = entry->gr_gid;
1287 static int id2name(char **name, unsigned int id, int type)
1290 struct passwd *entry;
1292 if (!(entry = getpwuid(id))) {
1298 *name = entry->pw_name;
1300 struct group *entry;
1302 if (!(entry = getgrgid(id))) {
1308 *name = entry->gr_name;
1314 static int name2layout(__u32 *layout, char *name)
1319 for (ptr = name; ; ptr = NULL) {
1320 lyt = strtok(ptr, ",");
1323 if (strcmp(lyt, "released") == 0)
1324 *layout |= LOV_PATTERN_F_RELEASED;
1325 else if (strcmp(lyt, "raid0") == 0)
1326 *layout |= LOV_PATTERN_RAID0;
1333 #define FIND_POOL_OPT 3
1334 static int lfs_find(int argc, char **argv)
1339 struct find_param param = {
1343 struct option long_opts[] = {
1344 {"atime", required_argument, 0, 'A'},
1345 {"stripe-count", required_argument, 0, 'c'},
1346 {"stripe_count", required_argument, 0, 'c'},
1347 {"ctime", required_argument, 0, 'C'},
1348 {"maxdepth", required_argument, 0, 'D'},
1349 {"gid", required_argument, 0, 'g'},
1350 {"group", required_argument, 0, 'G'},
1351 {"stripe-index", required_argument, 0, 'i'},
1352 {"stripe_index", required_argument, 0, 'i'},
1353 {"layout", required_argument, 0, 'L'},
1354 {"mdt", required_argument, 0, 'm'},
1355 {"mdt-index", required_argument, 0, 'm'},
1356 {"mdt_index", required_argument, 0, 'm'},
1357 {"mtime", required_argument, 0, 'M'},
1358 {"name", required_argument, 0, 'n'},
1359 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1360 {"obd", required_argument, 0, 'O'},
1361 {"ost", required_argument, 0, 'O'},
1362 /* no short option for pool, p/P already used */
1363 {"pool", required_argument, 0, FIND_POOL_OPT},
1364 {"print0", no_argument, 0, 'p'},
1365 {"print", no_argument, 0, 'P'},
1366 {"size", required_argument, 0, 's'},
1367 {"stripe-size", required_argument, 0, 'S'},
1368 {"stripe_size", required_argument, 0, 'S'},
1369 {"type", required_argument, 0, 't'},
1370 {"uid", required_argument, 0, 'u'},
1371 {"user", required_argument, 0, 'U'},
1384 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1385 while ((c = getopt_long_only(argc, argv,
1386 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1387 long_opts, NULL)) >= 0) {
1392 /* '!' is part of option */
1393 /* when getopt_long_only() finds a string which is not
1394 * an option nor a known option argument it returns 1
1395 * in that case if we already have found pathstart and pathend
1396 * (i.e. we have the list of pathnames),
1397 * the only supported value is "!"
1399 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1400 if (!isoption && pathend != -1) {
1401 fprintf(stderr, "err: %s: filename|dirname must either "
1402 "precede options or follow options\n",
1407 if (!isoption && pathstart == -1)
1408 pathstart = optind - 1;
1409 if (isoption && pathstart != -1 && pathend == -1)
1410 pathend = optind - 2;
1416 /* unknown; opt is "!" or path component,
1417 * checking done above.
1419 if (strcmp(optarg, "!") == 0)
1423 xtime = ¶m.fp_atime;
1424 xsign = ¶m.fp_asign;
1425 param.fp_exclude_atime = !!neg_opt;
1426 /* no break, this falls through to 'C' for ctime */
1429 xtime = ¶m.fp_ctime;
1430 xsign = ¶m.fp_csign;
1431 param.fp_exclude_ctime = !!neg_opt;
1433 /* no break, this falls through to 'M' for mtime */
1436 xtime = ¶m.fp_mtime;
1437 xsign = ¶m.fp_msign;
1438 param.fp_exclude_mtime = !!neg_opt;
1440 rc = set_time(&t, xtime, optarg);
1441 if (rc == INT_MAX) {
1449 if (optarg[0] == '+') {
1450 param.fp_stripe_count_sign = -1;
1452 } else if (optarg[0] == '-') {
1453 param.fp_stripe_count_sign = 1;
1457 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1458 if (*endptr != '\0') {
1459 fprintf(stderr,"error: bad stripe_count '%s'\n",
1464 param.fp_check_stripe_count = 1;
1465 param.fp_exclude_stripe_count = !!neg_opt;
1468 param.fp_max_depth = strtol(optarg, 0, 0);
1472 rc = name2id(¶m.fp_gid, optarg, GROUP);
1474 param.fp_gid = strtoul(optarg, &endptr, 10);
1475 if (*endptr != '\0') {
1476 fprintf(stderr, "Group/GID: %s cannot "
1477 "be found.\n", optarg);
1482 param.fp_exclude_gid = !!neg_opt;
1483 param.fp_check_gid = 1;
1486 ret = name2layout(¶m.fp_layout, optarg);
1489 param.fp_exclude_layout = !!neg_opt;
1490 param.fp_check_layout = 1;
1494 rc = name2id(¶m.fp_uid, optarg, USER);
1496 param.fp_uid = strtoul(optarg, &endptr, 10);
1497 if (*endptr != '\0') {
1498 fprintf(stderr, "User/UID: %s cannot "
1499 "be found.\n", optarg);
1504 param.fp_exclude_uid = !!neg_opt;
1505 param.fp_check_uid = 1;
1508 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1510 "Pool name %s is too long"
1511 " (max is %d)\n", optarg,
1516 /* we do check for empty pool because empty pool
1517 * is used to find V1 lov attributes */
1518 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1519 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1520 param.fp_exclude_pool = !!neg_opt;
1521 param.fp_check_pool = 1;
1524 param.fp_pattern = (char *)optarg;
1525 param.fp_exclude_pattern = !!neg_opt;
1530 char *buf, *token, *next, *p;
1534 buf = strdup(optarg);
1540 param.fp_exclude_obd = !!neg_opt;
1543 while (token && *token) {
1544 token = strchr(token, ',');
1551 param.fp_exclude_mdt = !!neg_opt;
1552 param.fp_num_alloc_mdts += len;
1553 tmp = realloc(param.fp_mdt_uuid,
1554 param.fp_num_alloc_mdts *
1555 sizeof(*param.fp_mdt_uuid));
1561 param.fp_mdt_uuid = tmp;
1563 param.fp_exclude_obd = !!neg_opt;
1564 param.fp_num_alloc_obds += len;
1565 tmp = realloc(param.fp_obd_uuid,
1566 param.fp_num_alloc_obds *
1567 sizeof(*param.fp_obd_uuid));
1573 param.fp_obd_uuid = tmp;
1575 for (token = buf; token && *token; token = next) {
1576 struct obd_uuid *puuid;
1579 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1582 ¶m.fp_obd_uuid[param.fp_num_obds++];
1584 p = strchr(token, ',');
1591 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1596 strncpy(puuid->uuid, token,
1597 sizeof(puuid->uuid));
1605 param.fp_zero_end = 1;
1610 if (optarg[0] == '+') {
1611 param.fp_size_sign = -1;
1613 } else if (optarg[0] == '-') {
1614 param.fp_size_sign = 1;
1618 ret = llapi_parse_size(optarg, ¶m.fp_size,
1619 ¶m.fp_size_units, 0);
1621 fprintf(stderr, "error: bad file size '%s'\n",
1625 param.fp_check_size = 1;
1626 param.fp_exclude_size = !!neg_opt;
1629 if (optarg[0] == '+') {
1630 param.fp_stripe_size_sign = -1;
1632 } else if (optarg[0] == '-') {
1633 param.fp_stripe_size_sign = 1;
1637 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1638 ¶m.fp_stripe_size_units, 0);
1640 fprintf(stderr, "error: bad stripe_size '%s'\n",
1644 param.fp_check_stripe_size = 1;
1645 param.fp_exclude_stripe_size = !!neg_opt;
1648 param.fp_exclude_type = !!neg_opt;
1649 switch (optarg[0]) {
1651 param.fp_type = S_IFBLK;
1654 param.fp_type = S_IFCHR;
1657 param.fp_type = S_IFDIR;
1660 param.fp_type = S_IFREG;
1663 param.fp_type = S_IFLNK;
1666 param.fp_type = S_IFIFO;
1669 param.fp_type = S_IFSOCK;
1672 fprintf(stderr, "error: %s: bad type '%s'\n",
1684 if (pathstart == -1) {
1685 fprintf(stderr, "error: %s: no filename|pathname\n",
1689 } else if (pathend == -1) {
1695 rc = llapi_find(argv[pathstart], ¶m);
1696 if (rc != 0 && ret == 0)
1698 } while (++pathstart < pathend);
1701 fprintf(stderr, "error: %s failed for %s.\n",
1702 argv[0], argv[optind - 1]);
1704 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1705 free(param.fp_obd_uuid);
1707 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1708 free(param.fp_mdt_uuid);
1713 static int lfs_getstripe_internal(int argc, char **argv,
1714 struct find_param *param)
1716 struct option long_opts[] = {
1717 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1718 /* This formerly implied "stripe-count", but was explicitly
1719 * made "stripe-count" for consistency with other options,
1720 * and to separate it from "mdt-count" when DNE arrives. */
1721 {"count", no_argument, 0, 'c'},
1723 {"stripe-count", no_argument, 0, 'c'},
1724 {"stripe_count", no_argument, 0, 'c'},
1725 {"directory", no_argument, 0, 'd'},
1726 {"default", no_argument, 0, 'D'},
1727 {"fid", no_argument, 0, 'F'},
1728 {"generation", no_argument, 0, 'g'},
1729 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1730 /* This formerly implied "stripe-index", but was explicitly
1731 * made "stripe-index" for consistency with other options,
1732 * and to separate it from "mdt-index" when DNE arrives. */
1733 {"index", no_argument, 0, 'i'},
1735 {"stripe-index", no_argument, 0, 'i'},
1736 {"stripe_index", no_argument, 0, 'i'},
1737 {"layout", no_argument, 0, 'L'},
1738 {"mdt", no_argument, 0, 'm'},
1739 {"mdt-index", no_argument, 0, 'm'},
1740 {"mdt_index", no_argument, 0, 'm'},
1741 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1742 {"mdt-index", no_argument, 0, 'M'},
1743 {"mdt_index", no_argument, 0, 'M'},
1745 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1746 /* This formerly implied "stripe-index", but was confusing
1747 * with "file offset" (which will eventually be needed for
1748 * with different layouts by offset), so deprecate it. */
1749 {"offset", no_argument, 0, 'o'},
1751 {"obd", required_argument, 0, 'O'},
1752 {"ost", required_argument, 0, 'O'},
1753 {"pool", no_argument, 0, 'p'},
1754 {"quiet", no_argument, 0, 'q'},
1755 {"recursive", no_argument, 0, 'r'},
1756 {"raw", no_argument, 0, 'R'},
1757 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1758 /* This formerly implied "--stripe-size", but was confusing
1759 * with "lfs find --size|-s", which means "file size", so use
1760 * the consistent "--stripe-size|-S" for all commands. */
1761 {"size", no_argument, 0, 's'},
1763 {"stripe-size", no_argument, 0, 'S'},
1764 {"stripe_size", no_argument, 0, 'S'},
1765 {"verbose", no_argument, 0, 'v'},
1770 while ((c = getopt_long(argc, argv, "cdDFghiLmMoO:pqrRsSv",
1771 long_opts, NULL)) != -1) {
1774 if (param->fp_obd_uuid) {
1776 "error: %s: only one obduuid allowed",
1780 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1786 param->fp_max_depth = 0;
1789 param->fp_get_default_lmv = 1;
1792 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1793 param->fp_verbose |= VERBOSE_DFID;
1794 param->fp_max_depth = 0;
1798 param->fp_recursive = 1;
1801 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
1804 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1805 if (strcmp(argv[optind - 1], "--count") == 0)
1806 fprintf(stderr, "warning: '--count' deprecated,"
1807 " use '--stripe-count' instead\n");
1809 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1810 param->fp_verbose |= VERBOSE_COUNT;
1811 param->fp_max_depth = 0;
1814 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1816 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1817 fprintf(stderr, "warning: '--size|-s' deprecated, "
1818 "use '--stripe-size|-S' instead\n");
1820 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1822 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1823 param->fp_verbose |= VERBOSE_SIZE;
1824 param->fp_max_depth = 0;
1827 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1829 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1830 "use '--stripe-index|-i' instead\n");
1833 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1834 if (strcmp(argv[optind - 1], "--index") == 0)
1835 fprintf(stderr, "warning: '--index' deprecated"
1836 ", use '--stripe-index' instead\n");
1838 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1839 param->fp_verbose |= VERBOSE_OFFSET;
1840 param->fp_max_depth = 0;
1844 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1845 param->fp_verbose |= VERBOSE_POOL;
1846 param->fp_max_depth = 0;
1850 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1851 param->fp_verbose |= VERBOSE_GENERATION;
1852 param->fp_max_depth = 0;
1856 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1857 param->fp_verbose |= VERBOSE_LAYOUT;
1858 param->fp_max_depth = 0;
1861 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1863 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
1864 fprintf(stderr, "warning: '-M' deprecated"
1865 ", use '-m' instead\n");
1869 if (!(param->fp_verbose & VERBOSE_DETAIL))
1870 param->fp_max_depth = 0;
1871 param->fp_verbose |= VERBOSE_MDTINDEX;
1884 if (param->fp_recursive)
1885 param->fp_max_depth = -1;
1887 if (!param->fp_verbose)
1888 param->fp_verbose = VERBOSE_DEFAULT;
1889 if (param->fp_quiet)
1890 param->fp_verbose = VERBOSE_OBJID;
1893 rc = llapi_getstripe(argv[optind], param);
1894 } while (++optind < argc && !rc);
1897 fprintf(stderr, "error: %s failed for %s.\n",
1898 argv[0], argv[optind - 1]);
1902 static int lfs_tgts(int argc, char **argv)
1904 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1905 struct find_param param;
1906 int index = 0, rc=0;
1911 if (argc == 2 && !realpath(argv[1], path)) {
1913 fprintf(stderr, "error: invalid path '%s': %s\n",
1914 argv[1], strerror(-rc));
1918 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1919 /* Check if we have a mount point */
1920 if (mntdir[0] == '\0')
1923 memset(¶m, 0, sizeof(param));
1924 if (!strcmp(argv[0], "mdts"))
1925 param.fp_get_lmv = 1;
1927 rc = llapi_ostlist(mntdir, ¶m);
1929 fprintf(stderr, "error: %s: failed on %s\n",
1932 if (path[0] != '\0')
1934 memset(mntdir, 0, PATH_MAX);
1940 static int lfs_getstripe(int argc, char **argv)
1942 struct find_param param = { 0 };
1944 param.fp_max_depth = 1;
1945 return lfs_getstripe_internal(argc, argv, ¶m);
1949 static int lfs_getdirstripe(int argc, char **argv)
1951 struct find_param param = { 0 };
1952 struct option long_opts[] = {
1953 {"mdt-count", no_argument, 0, 'c'},
1954 {"mdt-index", no_argument, 0, 'i'},
1955 {"recursive", no_argument, 0, 'r'},
1956 {"mdt-hash", no_argument, 0, 't'},
1957 {"default", no_argument, 0, 'D'},
1958 {"obd", required_argument, 0, 'O'},
1963 param.fp_get_lmv = 1;
1965 while ((c = getopt_long(argc, argv, "cirtDO:", long_opts, NULL)) != -1)
1969 if (param.fp_obd_uuid) {
1971 "error: %s: only one obduuid allowed",
1975 param.fp_obd_uuid = (struct obd_uuid *)optarg;
1978 param.fp_verbose |= VERBOSE_COUNT;
1981 param.fp_verbose |= VERBOSE_OFFSET;
1984 param.fp_verbose |= VERBOSE_HASH_TYPE;
1987 param.fp_get_default_lmv = 1;
1990 param.fp_recursive = 1;
2000 if (param.fp_recursive)
2001 param.fp_max_depth = -1;
2003 if (!param.fp_verbose)
2004 param.fp_verbose = VERBOSE_DEFAULT;
2007 rc = llapi_getstripe(argv[optind], ¶m);
2008 } while (++optind < argc && !rc);
2011 fprintf(stderr, "error: %s failed for %s.\n",
2012 argv[0], argv[optind - 1]);
2017 static int lfs_setdirstripe(int argc, char **argv)
2021 unsigned int stripe_offset = -1;
2022 unsigned int stripe_count = 1;
2023 enum lmv_hash_type hash_type;
2026 char *stripe_offset_opt = NULL;
2027 char *stripe_count_opt = NULL;
2028 char *stripe_hash_opt = NULL;
2029 char *mode_opt = NULL;
2030 bool default_stripe = false;
2031 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2032 mode_t previous_mode = 0;
2033 bool delete = false;
2035 struct option long_opts[] = {
2036 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2037 {"count", required_argument, 0, 'c'},
2039 {"mdt-count", required_argument, 0, 'c'},
2040 {"delete", no_argument, 0, 'd'},
2041 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2042 {"index", required_argument, 0, 'i'},
2044 {"mdt-index", required_argument, 0, 'i'},
2045 {"mode", required_argument, 0, 'm'},
2046 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2047 {"hash-type", required_argument, 0, 't'},
2049 {"mdt-hash", required_argument, 0, 't'},
2050 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2051 {"default_stripe", no_argument, 0, 'D'},
2053 {"default", no_argument, 0, 'D'},
2057 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
2064 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2065 if (strcmp(argv[optind - 1], "--count") == 0)
2066 fprintf(stderr, "warning: '--count' deprecated"
2067 ", use '--mdt-count' instead\n");
2069 stripe_count_opt = optarg;
2073 default_stripe = true;
2076 default_stripe = true;
2079 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2080 if (strcmp(argv[optind - 1], "--index") == 0)
2081 fprintf(stderr, "warning: '--index' deprecated"
2082 ", use '--mdt-index' instead\n");
2084 stripe_offset_opt = optarg;
2090 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2091 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2092 fprintf(stderr, "warning: '--hash-type' "
2093 "deprecated, use '--mdt-hash' "
2096 stripe_hash_opt = optarg;
2099 fprintf(stderr, "error: %s: option '%s' "
2101 argv[0], argv[optind - 1]);
2106 if (optind == argc) {
2107 fprintf(stderr, "error: %s: missing dirname\n",
2112 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2113 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2118 if (stripe_offset_opt != NULL) {
2119 /* get the stripe offset */
2120 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2122 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2123 argv[0], stripe_offset_opt);
2129 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2130 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2131 " or -i options.\n", argv[0]);
2139 if (mode_opt != NULL) {
2140 mode = strtoul(mode_opt, &end, 8);
2142 fprintf(stderr, "error: %s: bad mode '%s'\n",
2146 previous_mode = umask(0);
2149 if (stripe_hash_opt == NULL) {
2150 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2154 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
2155 if (strcmp(stripe_hash_opt, mdt_hash_name[i]) == 0)
2158 if (i == LMV_HASH_TYPE_MAX) {
2160 "error: %s: bad stripe hash type '%s'\n",
2161 argv[0], stripe_hash_opt);
2168 /* get the stripe count */
2169 if (stripe_count_opt != NULL) {
2170 stripe_count = strtoul(stripe_count_opt, &end, 0);
2172 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2173 argv[0], stripe_count_opt);
2178 dname = argv[optind];
2180 if (default_stripe) {
2181 result = llapi_dir_set_default_lmv_stripe(dname,
2182 stripe_offset, stripe_count,
2185 result = llapi_dir_create_pool(dname, mode,
2187 stripe_count, hash_type,
2192 fprintf(stderr, "error: %s: create stripe dir '%s' "
2193 "failed\n", argv[0], dname);
2196 dname = argv[++optind];
2197 } while (dname != NULL);
2199 if (mode_opt != NULL)
2200 umask(previous_mode);
2206 static int lfs_rmentry(int argc, char **argv)
2213 fprintf(stderr, "error: %s: missing dirname\n",
2219 dname = argv[index];
2220 while (dname != NULL) {
2221 result = llapi_direntry_remove(dname);
2223 fprintf(stderr, "error: %s: remove dir entry '%s' "
2224 "failed\n", argv[0], dname);
2227 dname = argv[++index];
2232 static int lfs_mv(int argc, char **argv)
2234 struct find_param param = {
2241 struct option long_opts[] = {
2242 {"mdt-index", required_argument, 0, 'M'},
2243 {"verbose", no_argument, 0, 'v'},
2247 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2250 param.fp_mdt_index = strtoul(optarg, &end, 0);
2252 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2259 param.fp_verbose = VERBOSE_DETAIL;
2263 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2264 argv[0], argv[optind - 1]);
2269 if (param.fp_mdt_index == -1) {
2270 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2274 if (optind >= argc) {
2275 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2279 param.fp_migrate = 1;
2280 rc = llapi_migrate_mdt(argv[optind], ¶m);
2282 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2283 argv[0], argv[optind], param.fp_mdt_index,
2288 static int lfs_osts(int argc, char **argv)
2290 return lfs_tgts(argc, argv);
2293 static int lfs_mdts(int argc, char **argv)
2295 return lfs_tgts(argc, argv);
2298 #define COOK(value) \
2301 while (value > 1024) { \
2309 #define CDF "%11llu"
2310 #define HDF "%8.1f%c"
2315 MNTDF_INODES = 0x0001,
2316 MNTDF_COOKED = 0x0002,
2317 MNTDF_LAZY = 0x0004,
2318 MNTDF_VERBOSE = 0x0008,
2321 static int showdf(char *mntdir, struct obd_statfs *stat,
2322 char *uuid, enum mntdf_flags flags,
2323 char *type, int index, int rc)
2325 long long avail, used, total;
2327 char *suffix = "KMGTPEZY";
2328 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2329 char tbuf[3 * sizeof(__u64)];
2330 char ubuf[3 * sizeof(__u64)];
2331 char abuf[3 * sizeof(__u64)];
2332 char rbuf[3 * sizeof(__u64)];
2339 if (flags & MNTDF_INODES) {
2340 avail = stat->os_ffree;
2341 used = stat->os_files - stat->os_ffree;
2342 total = stat->os_files;
2344 int shift = flags & MNTDF_COOKED ? 0 : 10;
2346 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2347 used = ((stat->os_blocks - stat->os_bfree) *
2348 stat->os_bsize) >> shift;
2349 total = (stat->os_blocks * stat->os_bsize) >> shift;
2352 if ((used + avail) > 0)
2353 ratio = (double)used / (double)(used + avail);
2355 if (flags & MNTDF_COOKED) {
2359 cook_val = (double)total;
2362 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
2365 snprintf(tbuf, sizeof(tbuf), CDF, total);
2367 cook_val = (double)used;
2370 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
2373 snprintf(ubuf, sizeof(ubuf), CDF, used);
2375 cook_val = (double)avail;
2378 snprintf(abuf, sizeof(abuf), HDF, cook_val,
2381 snprintf(abuf, sizeof(abuf), CDF, avail);
2383 snprintf(tbuf, sizeof(tbuf), CDF, total);
2384 snprintf(ubuf, sizeof(tbuf), CDF, used);
2385 snprintf(abuf, sizeof(tbuf), CDF, avail);
2388 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2389 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2390 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2392 printf("[%s:%d]", type, index);
2394 if (stat->os_state) {
2396 * Each character represents the matching
2399 const char state_names[] = "DRSI";
2404 for (i = 0, state = stat->os_state;
2405 state && i < sizeof(state_names); i++) {
2406 if (!(state & (1 << i)))
2408 printf("%c", state_names[i]);
2416 printf(UUF": inactive device\n", uuid);
2419 printf(UUF": %s\n", uuid, strerror(-rc));
2426 struct ll_stat_type {
2431 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
2433 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2434 struct obd_uuid uuid_buf;
2435 char *poolname = NULL;
2436 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2437 { LL_STATFS_LOV, "OST" },
2439 struct ll_stat_type *tp;
2440 __u64 ost_ffree = 0;
2448 poolname = strchr(pool, '.');
2449 if (poolname != NULL) {
2450 if (strncmp(fsname, pool, strlen(fsname))) {
2451 fprintf(stderr, "filesystem name incorrect\n");
2459 fd = open(mntdir, O_RDONLY);
2462 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
2467 if (flags & MNTDF_INODES)
2468 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2469 "UUID", "Inodes", "IUsed", "IFree",
2470 "IUse%", "Mounted on");
2472 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2473 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
2474 "Used", "Available", "Use%", "Mounted on");
2476 for (tp = types; tp->st_name != NULL; tp++) {
2477 for (index = 0; ; index++) {
2478 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2479 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2480 type = flags & MNTDF_LAZY ?
2481 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2482 rc2 = llapi_obd_fstatfs(fd, type, index,
2483 &stat_buf, &uuid_buf);
2488 if (rc2 == -ENODATA) { /* Inactive device, OK. */
2489 if (!(flags & MNTDF_VERBOSE))
2491 } else if (rc2 < 0 && rc == 0) {
2495 if (poolname && tp->st_op == LL_STATFS_LOV &&
2496 llapi_search_ost(fsname, poolname,
2497 obd_uuid2str(&uuid_buf)) != 1)
2500 /* the llapi_obd_statfs() call may have returned with
2501 * an error, but if it filled in uuid_buf we will at
2502 * lease use that to print out a message for that OBD.
2503 * If we didn't get anything in the uuid_buf, then fill
2504 * it in so that we can print an error message. */
2505 if (uuid_buf.uuid[0] == '\0')
2506 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
2507 "%s%04x", tp->st_name, index);
2508 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2509 flags, tp->st_name, index, rc2);
2512 if (tp->st_op == LL_STATFS_LMV) {
2513 sum.os_ffree += stat_buf.os_ffree;
2514 sum.os_files += stat_buf.os_files;
2515 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2516 sum.os_blocks += stat_buf.os_blocks *
2518 sum.os_bfree += stat_buf.os_bfree *
2520 sum.os_bavail += stat_buf.os_bavail *
2522 ost_ffree += stat_buf.os_ffree;
2530 /* If we don't have as many objects free on the OST as inodes
2531 * on the MDS, we reduce the total number of inodes to
2532 * compensate, so that the "inodes in use" number is correct.
2533 * Matches ll_statfs_internal() so the results are consistent. */
2534 if (ost_ffree < sum.os_ffree) {
2535 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2536 sum.os_ffree = ost_ffree;
2539 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
2545 static int lfs_df(int argc, char **argv)
2547 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2548 enum mntdf_flags flags = 0;
2549 int c, rc = 0, index = 0;
2550 char fsname[PATH_MAX] = "", *pool_name = NULL;
2551 struct option long_opts[] = {
2552 {"human-readable", 0, 0, 'h'},
2553 {"inodes", 0, 0, 'i'},
2554 {"lazy", 0, 0, 'l'},
2555 {"pool", required_argument, 0, 'p'},
2556 {"verbose", 0, 0, 'v'},
2560 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
2563 flags |= MNTDF_COOKED;
2566 flags |= MNTDF_INODES;
2569 flags |= MNTDF_LAZY;
2575 flags |= MNTDF_VERBOSE;
2581 if (optind < argc && !realpath(argv[optind], path)) {
2583 fprintf(stderr, "error: invalid path '%s': %s\n",
2584 argv[optind], strerror(-rc));
2588 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2589 /* Check if we have a mount point */
2590 if (mntdir[0] == '\0')
2593 rc = mntdf(mntdir, fsname, pool_name, flags);
2594 if (rc || path[0] != '\0')
2596 fsname[0] = '\0'; /* avoid matching in next loop */
2597 mntdir[0] = '\0'; /* avoid matching in next loop */
2603 static int lfs_getname(int argc, char **argv)
2605 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2606 int rc = 0, index = 0, c;
2607 char buf[sizeof(struct obd_uuid)];
2609 while ((c = getopt(argc, argv, "h")) != -1)
2612 if (optind == argc) { /* no paths specified, get all paths. */
2613 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2614 rc = llapi_getname(mntdir, buf, sizeof(buf));
2617 "cannot get name for `%s': %s\n",
2618 mntdir, strerror(-rc));
2622 printf("%s %s\n", buf, mntdir);
2624 path[0] = fsname[0] = mntdir[0] = 0;
2626 } else { /* paths specified, only attempt to search these. */
2627 for (; optind < argc; optind++) {
2628 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2631 "cannot get name for `%s': %s\n",
2632 argv[optind], strerror(-rc));
2636 printf("%s %s\n", buf, argv[optind]);
2642 static int lfs_check(int argc, char **argv)
2645 char mntdir[PATH_MAX] = {'\0'};
2654 obd_types[0] = obd_type1;
2655 obd_types[1] = obd_type2;
2657 if (strcmp(argv[1], "osts") == 0) {
2658 strcpy(obd_types[0], "osc");
2659 } else if (strcmp(argv[1], "mds") == 0) {
2660 strcpy(obd_types[0], "mdc");
2661 } else if (strcmp(argv[1], "servers") == 0) {
2663 strcpy(obd_types[0], "osc");
2664 strcpy(obd_types[1], "mdc");
2666 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2671 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2672 if (rc < 0 || mntdir[0] == '\0') {
2673 fprintf(stderr, "No suitable Lustre mount found\n");
2677 rc = llapi_target_check(num_types, obd_types, mntdir);
2679 fprintf(stderr, "error: %s: %s status failed\n",
2686 #ifdef HAVE_SYS_QUOTA_H
2687 #define ARG2INT(nr, str, msg) \
2690 nr = strtol(str, &endp, 0); \
2692 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2697 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2699 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2700 * returns the value or ULONG_MAX on integer overflow or incorrect format
2702 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2703 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2704 * 3. empty integer value is interpreted as 0
2706 static unsigned long str2sec(const char* timestr)
2708 const char spec[] = "smhdw";
2709 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2710 unsigned long val = 0;
2713 if (strpbrk(timestr, spec) == NULL) {
2714 /* no specifiers inside the time string,
2715 should treat it as an integer value */
2716 val = strtoul(timestr, &tail, 10);
2717 return *tail ? ULONG_MAX : val;
2720 /* format string is XXwXXdXXhXXmXXs */
2726 v = strtoul(timestr, &tail, 10);
2727 if (v == ULONG_MAX || *tail == '\0')
2728 /* value too large (ULONG_MAX or more)
2729 or missing specifier */
2732 ptr = strchr(spec, *tail);
2734 /* unknown specifier */
2739 /* check if product will overflow the type */
2740 if (!(v < ULONG_MAX / mult[ind]))
2743 ADD_OVERFLOW(val, mult[ind] * v);
2744 if (val == ULONG_MAX)
2756 #define ARG2ULL(nr, str, def_units) \
2758 unsigned long long limit, units = def_units; \
2761 rc = llapi_parse_size(str, &limit, &units, 1); \
2763 fprintf(stderr, "error: bad limit value %s\n", str); \
2769 static inline int has_times_option(int argc, char **argv)
2773 for (i = 1; i < argc; i++)
2774 if (!strcmp(argv[i], "-t"))
2780 int lfs_setquota_times(int argc, char **argv)
2783 struct if_quotactl qctl;
2784 char *mnt, *obd_type = (char *)qctl.obd_type;
2785 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2786 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2787 struct option long_opts[] = {
2788 {"block-grace", required_argument, 0, 'b'},
2789 {"group", no_argument, 0, 'g'},
2790 {"inode-grace", required_argument, 0, 'i'},
2791 {"times", no_argument, 0, 't'},
2792 {"user", no_argument, 0, 'u'},
2796 memset(&qctl, 0, sizeof(qctl));
2797 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2798 qctl.qc_type = UGQUOTA;
2800 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2804 if (qctl.qc_type != UGQUOTA) {
2805 fprintf(stderr, "error: -u and -g can't be used "
2806 "more than once\n");
2809 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2812 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2813 fprintf(stderr, "error: bad block-grace: %s\n",
2817 dqb->dqb_valid |= QIF_BTIME;
2820 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2821 fprintf(stderr, "error: bad inode-grace: %s\n",
2825 dqb->dqb_valid |= QIF_ITIME;
2827 case 't': /* Yes, of course! */
2829 default: /* getopt prints error message for us when opterr != 0 */
2834 if (qctl.qc_type == UGQUOTA) {
2835 fprintf(stderr, "error: neither -u nor -g specified\n");
2839 if (optind != argc - 1) {
2840 fprintf(stderr, "error: unexpected parameters encountered\n");
2845 rc = llapi_quotactl(mnt, &qctl);
2848 fprintf(stderr, "%s %s ", obd_type,
2849 obd_uuid2str(&qctl.obd_uuid));
2850 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2857 #define BSLIMIT (1 << 0)
2858 #define BHLIMIT (1 << 1)
2859 #define ISLIMIT (1 << 2)
2860 #define IHLIMIT (1 << 3)
2862 int lfs_setquota(int argc, char **argv)
2865 struct if_quotactl qctl;
2866 char *mnt, *obd_type = (char *)qctl.obd_type;
2867 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2868 struct option long_opts[] = {
2869 {"block-softlimit", required_argument, 0, 'b'},
2870 {"block-hardlimit", required_argument, 0, 'B'},
2871 {"group", required_argument, 0, 'g'},
2872 {"inode-softlimit", required_argument, 0, 'i'},
2873 {"inode-hardlimit", required_argument, 0, 'I'},
2874 {"user", required_argument, 0, 'u'},
2877 unsigned limit_mask = 0;
2880 if (has_times_option(argc, argv))
2881 return lfs_setquota_times(argc, argv);
2883 memset(&qctl, 0, sizeof(qctl));
2884 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2885 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2886 * so it can be used as a marker that qc_type
2887 * isn't reinitialized from command line */
2889 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2893 if (qctl.qc_type != UGQUOTA) {
2894 fprintf(stderr, "error: -u and -g can't be used"
2895 " more than once\n");
2898 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2899 rc = name2id(&qctl.qc_id, optarg,
2900 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2902 qctl.qc_id = strtoul(optarg, &endptr, 10);
2903 if (*endptr != '\0') {
2904 fprintf(stderr, "error: can't find id "
2905 "for name %s\n", optarg);
2911 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2912 dqb->dqb_bsoftlimit >>= 10;
2913 limit_mask |= BSLIMIT;
2914 if (dqb->dqb_bsoftlimit &&
2915 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2916 fprintf(stderr, "warning: block softlimit is "
2917 "smaller than the miminal qunit size, "
2918 "please see the help of setquota or "
2919 "Lustre manual for details.\n");
2922 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2923 dqb->dqb_bhardlimit >>= 10;
2924 limit_mask |= BHLIMIT;
2925 if (dqb->dqb_bhardlimit &&
2926 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2927 fprintf(stderr, "warning: block hardlimit is "
2928 "smaller than the miminal qunit size, "
2929 "please see the help of setquota or "
2930 "Lustre manual for details.\n");
2933 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2934 limit_mask |= ISLIMIT;
2935 if (dqb->dqb_isoftlimit &&
2936 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2937 fprintf(stderr, "warning: inode softlimit is "
2938 "smaller than the miminal qunit size, "
2939 "please see the help of setquota or "
2940 "Lustre manual for details.\n");
2943 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2944 limit_mask |= IHLIMIT;
2945 if (dqb->dqb_ihardlimit &&
2946 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2947 fprintf(stderr, "warning: inode hardlimit is "
2948 "smaller than the miminal qunit size, "
2949 "please see the help of setquota or "
2950 "Lustre manual for details.\n");
2952 default: /* getopt prints error message for us when opterr != 0 */
2957 if (qctl.qc_type == UGQUOTA) {
2958 fprintf(stderr, "error: neither -u nor -g was specified\n");
2962 if (limit_mask == 0) {
2963 fprintf(stderr, "error: at least one limit must be specified\n");
2967 if (optind != argc - 1) {
2968 fprintf(stderr, "error: unexpected parameters encountered\n");
2974 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2975 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2976 /* sigh, we can't just set blimits/ilimits */
2977 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2978 .qc_type = qctl.qc_type,
2979 .qc_id = qctl.qc_id};
2981 rc = llapi_quotactl(mnt, &tmp_qctl);
2983 fprintf(stderr, "error: setquota failed while retrieving"
2984 " current quota settings (%s)\n",
2989 if (!(limit_mask & BHLIMIT))
2990 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2991 if (!(limit_mask & BSLIMIT))
2992 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2993 if (!(limit_mask & IHLIMIT))
2994 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2995 if (!(limit_mask & ISLIMIT))
2996 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2998 /* Keep grace times if we have got no softlimit arguments */
2999 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3000 dqb->dqb_valid |= QIF_BTIME;
3001 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3004 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3005 dqb->dqb_valid |= QIF_ITIME;
3006 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3010 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3011 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3013 rc = llapi_quotactl(mnt, &qctl);
3016 fprintf(stderr, "%s %s ", obd_type,
3017 obd_uuid2str(&qctl.obd_uuid));
3018 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3025 static inline char *type2name(int check_type)
3027 if (check_type == USRQUOTA)
3029 else if (check_type == GRPQUOTA)
3035 /* Converts seconds value into format string
3036 * result is returned in buf
3038 * 1. result is in descenting order: 1w2d3h4m5s
3039 * 2. zero fields are not filled (except for p. 3): 5d1s
3040 * 3. zero seconds value is presented as "0s"
3042 static char * __sec2str(time_t seconds, char *buf)
3044 const char spec[] = "smhdw";
3045 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3050 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3051 c = seconds / mult[i];
3053 if (c > 0 || (i == 0 && buf == tail))
3054 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3062 static void sec2str(time_t seconds, char *buf, int rc)
3069 tail = __sec2str(seconds, tail);
3071 if (rc && tail - buf < 39) {
3077 static void diff2str(time_t seconds, char *buf, time_t now)
3083 if (seconds <= now) {
3084 strcpy(buf, "none");
3087 __sec2str(seconds - now, buf);
3090 static void print_quota_title(char *name, struct if_quotactl *qctl,
3091 bool human_readable)
3093 printf("Disk quotas for %s %s (%cid %u):\n",
3094 type2name(qctl->qc_type), name,
3095 *type2name(qctl->qc_type), qctl->qc_id);
3096 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3097 "Filesystem", human_readable ? "used" : "kbytes",
3098 "quota", "limit", "grace",
3099 "files", "quota", "limit", "grace");
3102 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3105 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3108 snprintf(buf, buflen, "%5.4gP",
3109 (double)num / ((__u64)1 << 40));
3111 snprintf(buf, buflen, "%5.4gT",
3112 (double)num / (1 << 30));
3114 snprintf(buf, buflen, "%5.4gG",
3115 (double)num / (1 << 20));
3117 snprintf(buf, buflen, "%5.4gM",
3118 (double)num / (1 << 10));
3120 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3124 #define STRBUF_LEN 32
3125 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3132 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3133 int bover = 0, iover = 0;
3134 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3135 char numbuf[3][STRBUF_LEN];
3137 char strbuf[STRBUF_LEN];
3139 if (dqb->dqb_bhardlimit &&
3140 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3142 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3143 if (dqb->dqb_btime > now) {
3150 if (dqb->dqb_ihardlimit &&
3151 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3153 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3154 if (dqb->dqb_itime > now) {
3162 if (strlen(mnt) > 15)
3163 printf("%s\n%15s", mnt, "");
3165 printf("%15s", mnt);
3168 diff2str(dqb->dqb_btime, timebuf, now);
3170 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3171 strbuf, sizeof(strbuf), h);
3172 if (rc == -EREMOTEIO)
3173 sprintf(numbuf[0], "%s*", strbuf);
3175 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3176 "%s" : "[%s]", strbuf);
3178 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3179 if (type == QC_GENERAL)
3180 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3181 "%s" : "[%s]", strbuf);
3183 sprintf(numbuf[1], "%s", "-");
3185 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3186 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3187 "%s" : "[%s]", strbuf);
3189 printf(" %7s%c %6s %7s %7s",
3190 numbuf[0], bover ? '*' : ' ', numbuf[1],
3191 numbuf[2], bover > 1 ? timebuf : "-");
3194 diff2str(dqb->dqb_itime, timebuf, now);
3196 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3197 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3199 if (type == QC_GENERAL)
3200 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3202 (uintmax_t)dqb->dqb_isoftlimit);
3204 sprintf(numbuf[1], "%s", "-");
3206 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3207 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3209 if (type != QC_OSTIDX)
3210 printf(" %7s%c %6s %7s %7s",
3211 numbuf[0], iover ? '*' : ' ', numbuf[1],
3212 numbuf[2], iover > 1 ? timebuf : "-");
3214 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3217 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3218 qctl->qc_cmd == Q_GETOINFO) {
3222 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3223 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3224 printf("Block grace time: %s; Inode grace time: %s\n",
3225 bgtimebuf, igtimebuf);
3229 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3230 bool h, __u64 *total)
3232 int rc = 0, rc1 = 0, count = 0;
3233 __u32 valid = qctl->qc_valid;
3235 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3237 fprintf(stderr, "can not get %s count: %s\n",
3238 is_mdt ? "mdt": "ost", strerror(-rc));
3242 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3243 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3244 rc = llapi_quotactl(mnt, qctl);
3246 /* It is remote client case. */
3247 if (-rc == EOPNOTSUPP) {
3254 fprintf(stderr, "quotactl %s%d failed.\n",
3255 is_mdt ? "mdt": "ost", qctl->qc_idx);
3259 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3260 qctl->qc_valid, 0, h);
3261 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3262 qctl->qc_dqblk.dqb_bhardlimit;
3265 qctl->qc_valid = valid;
3269 static int lfs_quota(int argc, char **argv)
3272 char *mnt, *name = NULL;
3273 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3274 .qc_type = UGQUOTA };
3275 char *obd_type = (char *)qctl.obd_type;
3276 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3277 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
3278 verbose = 0, pass = 0, quiet = 0, inacc;
3280 __u32 valid = QC_GENERAL, idx = 0;
3281 __u64 total_ialloc = 0, total_balloc = 0;
3282 bool human_readable = false;
3284 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3287 if (qctl.qc_type != UGQUOTA) {
3288 fprintf(stderr, "error: use either -u or -g\n");
3291 qctl.qc_type = USRQUOTA;
3294 if (qctl.qc_type != UGQUOTA) {
3295 fprintf(stderr, "error: use either -u or -g\n");
3298 qctl.qc_type = GRPQUOTA;
3301 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3304 valid = qctl.qc_valid = QC_UUID;
3305 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3308 valid = qctl.qc_valid = QC_MDTIDX;
3309 idx = qctl.qc_idx = atoi(optarg);
3312 valid = qctl.qc_valid = QC_OSTIDX;
3313 idx = qctl.qc_idx = atoi(optarg);
3322 human_readable = true;
3325 fprintf(stderr, "error: %s: option '-%c' "
3326 "unrecognized\n", argv[0], c);
3331 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3332 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3333 optind == argc - 1) {
3335 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3336 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3337 qctl.qc_valid = valid;
3340 qctl.qc_type = USRQUOTA;
3341 qctl.qc_id = geteuid();
3343 qctl.qc_type = GRPQUOTA;
3344 qctl.qc_id = getegid();
3346 rc = id2name(&name, qctl.qc_id,
3347 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3350 /* lfs quota -u username /path/to/lustre/mount */
3351 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3352 /* options should be followed by u/g-name and mntpoint */
3353 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3354 fprintf(stderr, "error: missing quota argument(s)\n");
3358 name = argv[optind++];
3359 rc = name2id(&qctl.qc_id, name,
3360 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3362 qctl.qc_id = strtoul(name, &endptr, 10);
3363 if (*endptr != '\0') {
3364 fprintf(stderr, "error: can't find id for name "
3369 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3370 fprintf(stderr, "error: missing quota info argument(s)\n");
3376 rc1 = llapi_quotactl(mnt, &qctl);
3380 fprintf(stderr, "%s quotas are not enabled.\n",
3381 qctl.qc_type == USRQUOTA ? "user" : "group");
3384 fprintf(stderr, "Permission denied.\n");
3387 /* We already got error message. */
3390 fprintf(stderr, "Unexpected quotactl error: %s\n",
3395 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3396 print_quota_title(name, &qctl, human_readable);
3398 if (rc1 && *obd_type)
3399 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3401 if (qctl.qc_valid != QC_GENERAL)
3404 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3405 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3406 (QIF_LIMITS|QIF_USAGE));
3408 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3410 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3412 char strbuf[STRBUF_LEN];
3414 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3416 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3418 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
3420 printf("Total allocated inode limit: %ju, total "
3421 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
3425 if (rc1 || rc2 || rc3 || inacc)
3426 printf("Some errors happened when getting quota info. "
3427 "Some devices may be not working or deactivated. "
3428 "The data in \"[]\" is inaccurate.\n");
3436 #endif /* HAVE_SYS_QUOTA_H! */
3438 static int flushctx_ioctl(char *mp)
3442 fd = open(mp, O_RDONLY);
3444 fprintf(stderr, "flushctx: error open %s: %s\n",
3445 mp, strerror(errno));
3449 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3451 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3452 mp, strerror(errno));
3458 static int lfs_flushctx(int argc, char **argv)
3460 int kdestroy = 0, c;
3461 char mntdir[PATH_MAX] = {'\0'};
3465 while ((c = getopt(argc, argv, "k")) != -1) {
3471 fprintf(stderr, "error: %s: option '-%c' "
3472 "unrecognized\n", argv[0], c);
3478 if ((rc = system("kdestroy > /dev/null")) != 0) {
3479 rc = WEXITSTATUS(rc);
3480 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3484 if (optind >= argc) {
3485 /* flush for all mounted lustre fs. */
3486 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3487 /* Check if we have a mount point */
3488 if (mntdir[0] == '\0')
3491 if (flushctx_ioctl(mntdir))
3494 mntdir[0] = '\0'; /* avoid matching in next loop */
3497 /* flush fs as specified */
3498 while (optind < argc) {
3499 if (flushctx_ioctl(argv[optind++]))
3506 static int lfs_cp(int argc, char **argv)
3508 fprintf(stderr, "remote client copy file(s).\n"
3509 "obsolete, does not support it anymore.\n");
3513 static int lfs_ls(int argc, char **argv)
3515 fprintf(stderr, "remote client lists directory contents.\n"
3516 "obsolete, does not support it anymore.\n");
3520 static int lfs_changelog(int argc, char **argv)
3522 void *changelog_priv;
3523 struct changelog_rec *rec;
3524 long long startrec = 0, endrec = 0;
3526 struct option long_opts[] = {
3527 {"follow", no_argument, 0, 'f'},
3530 char short_opts[] = "f";
3533 while ((rc = getopt_long(argc, argv, short_opts,
3534 long_opts, NULL)) != -1) {
3542 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3543 argv[0], argv[optind - 1]);
3550 mdd = argv[optind++];
3552 startrec = strtoll(argv[optind++], NULL, 10);
3554 endrec = strtoll(argv[optind++], NULL, 10);
3556 rc = llapi_changelog_start(&changelog_priv,
3557 CHANGELOG_FLAG_BLOCK |
3558 CHANGELOG_FLAG_JOBID |
3559 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3562 fprintf(stderr, "Can't start changelog: %s\n",
3563 strerror(errno = -rc));
3567 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3571 if (endrec && rec->cr_index > endrec) {
3572 llapi_changelog_free(&rec);
3575 if (rec->cr_index < startrec) {
3576 llapi_changelog_free(&rec);
3580 secs = rec->cr_time >> 30;
3581 gmtime_r(&secs, &ts);
3582 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3583 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
3584 changelog_type2str(rec->cr_type),
3585 ts.tm_hour, ts.tm_min, ts.tm_sec,
3586 (int)(rec->cr_time & ((1<<30) - 1)),
3587 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3588 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3590 if (rec->cr_flags & CLF_JOBID) {
3591 struct changelog_ext_jobid *jid =
3592 changelog_rec_jobid(rec);
3594 if (jid->cr_jobid[0] != '\0')
3595 printf(" j=%s", jid->cr_jobid);
3598 if (rec->cr_namelen)
3599 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3600 rec->cr_namelen, changelog_rec_name(rec));
3602 if (rec->cr_flags & CLF_RENAME) {
3603 struct changelog_ext_rename *rnm =
3604 changelog_rec_rename(rec);
3606 if (!fid_is_zero(&rnm->cr_sfid))
3607 printf(" s="DFID" sp="DFID" %.*s",
3608 PFID(&rnm->cr_sfid),
3609 PFID(&rnm->cr_spfid),
3610 (int)changelog_rec_snamelen(rec),
3611 changelog_rec_sname(rec));
3615 llapi_changelog_free(&rec);
3618 llapi_changelog_fini(&changelog_priv);
3621 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3623 return (rc == 1 ? 0 : rc);
3626 static int lfs_changelog_clear(int argc, char **argv)
3634 endrec = strtoll(argv[3], NULL, 10);
3636 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3639 fprintf(stderr, "%s: record out of range: %llu\n",
3641 else if (rc == -ENOENT)
3642 fprintf(stderr, "%s: no changelog user: %s\n",
3645 fprintf(stderr, "%s error: %s\n", argv[0],
3654 static int lfs_fid2path(int argc, char **argv)
3656 struct option long_opts[] = {
3657 {"cur", no_argument, 0, 'c'},
3658 {"link", required_argument, 0, 'l'},
3659 {"rec", required_argument, 0, 'r'},
3662 char short_opts[] = "cl:r:";
3663 char *device, *fid, *path;
3664 long long recno = -1;
3670 while ((rc = getopt_long(argc, argv, short_opts,
3671 long_opts, NULL)) != -1) {
3677 linkno = strtol(optarg, NULL, 10);
3680 recno = strtoll(optarg, NULL, 10);
3685 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3686 argv[0], argv[optind - 1]);
3694 device = argv[optind++];
3695 path = calloc(1, PATH_MAX);
3697 fprintf(stderr, "error: Not enough memory\n");
3702 while (optind < argc) {
3703 fid = argv[optind++];
3705 lnktmp = (linkno >= 0) ? linkno : 0;
3707 int oldtmp = lnktmp;
3708 long long rectmp = recno;
3710 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3713 fprintf(stderr, "%s: error on FID %s: %s\n",
3714 argv[0], fid, strerror(errno = -rc2));
3721 fprintf(stdout, "%lld ", rectmp);
3722 if (device[0] == '/') {
3723 fprintf(stdout, "%s", device);
3724 if (device[strlen(device) - 1] != '/')
3725 fprintf(stdout, "/");
3726 } else if (path[0] == '\0') {
3727 fprintf(stdout, "/");
3729 fprintf(stdout, "%s\n", path);
3732 /* specified linkno */
3734 if (oldtmp == lnktmp)
3744 static int lfs_path2fid(int argc, char **argv)
3746 struct option long_opts[] = {
3747 {"parents", no_argument, 0, 'p'},
3751 const char short_opts[] = "p";
3752 const char *sep = "";
3755 bool show_parents = false;
3757 while ((rc = getopt_long(argc, argv, short_opts,
3758 long_opts, NULL)) != -1) {
3761 show_parents = true;
3764 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3765 argv[0], argv[optind - 1]);
3770 if (optind > argc - 1)
3772 else if (optind < argc - 1)
3776 for (path = argv + optind; *path != NULL; path++) {
3778 if (!show_parents) {
3779 err = llapi_path2fid(*path, &fid);
3781 printf("%s%s"DFID"\n",
3782 *sep != '\0' ? *path : "", sep,
3785 char name[NAME_MAX + 1];
3786 unsigned int linkno = 0;
3788 while ((err = llapi_path2parent(*path, linkno, &fid,
3789 name, sizeof(name))) == 0) {
3790 if (*sep != '\0' && linkno == 0)
3791 printf("%s%s", *path, sep);
3793 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3798 /* err == -ENODATA is end-of-loop */
3799 if (linkno > 0 && err == -ENODATA) {
3806 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3807 argv[0], show_parents ? "parent " : "", *path,
3819 static int lfs_data_version(int argc, char **argv)
3826 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3831 while ((c = getopt(argc, argv, "nrw")) != -1) {
3834 data_version_flags = 0;
3837 data_version_flags |= LL_DV_RD_FLUSH;
3840 data_version_flags |= LL_DV_WR_FLUSH;
3849 path = argv[optind];
3850 fd = open(path, O_RDONLY);
3852 err(errno, "cannot open file %s", path);
3854 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3856 err(errno, "cannot get version for %s", path);
3858 printf("%ju" "\n", (uintmax_t)data_version);
3864 static int lfs_hsm_state(int argc, char **argv)
3869 struct hsm_user_state hus;
3877 rc = llapi_hsm_state_get(path, &hus);
3879 fprintf(stderr, "can't get hsm state for %s: %s\n",
3880 path, strerror(errno = -rc));
3884 /* Display path name and status flags */
3885 printf("%s: (0x%08x)", path, hus.hus_states);
3887 if (hus.hus_states & HS_RELEASED)
3888 printf(" released");
3889 if (hus.hus_states & HS_EXISTS)
3891 if (hus.hus_states & HS_DIRTY)
3893 if (hus.hus_states & HS_ARCHIVED)
3894 printf(" archived");
3895 /* Display user-settable flags */
3896 if (hus.hus_states & HS_NORELEASE)
3897 printf(" never_release");
3898 if (hus.hus_states & HS_NOARCHIVE)
3899 printf(" never_archive");
3900 if (hus.hus_states & HS_LOST)
3901 printf(" lost_from_hsm");
3903 if (hus.hus_archive_id != 0)
3904 printf(", archive_id:%d", hus.hus_archive_id);
3907 } while (++i < argc);
3912 #define LFS_HSM_SET 0
3913 #define LFS_HSM_CLEAR 1
3916 * Generic function to set or clear HSM flags.
3917 * Used by hsm_set and hsm_clear.
3919 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3921 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3923 struct option long_opts[] = {
3924 {"lost", 0, 0, 'l'},
3925 {"norelease", 0, 0, 'r'},
3926 {"noarchive", 0, 0, 'a'},
3927 {"archived", 0, 0, 'A'},
3928 {"dirty", 0, 0, 'd'},
3929 {"exists", 0, 0, 'e'},
3932 char short_opts[] = "lraAde";
3940 while ((c = getopt_long(argc, argv, short_opts,
3941 long_opts, NULL)) != -1) {
3947 mask |= HS_NOARCHIVE;
3950 mask |= HS_ARCHIVED;
3953 mask |= HS_NORELEASE;
3964 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3965 argv[0], argv[optind - 1]);
3970 /* User should have specified a flag */
3974 while (optind < argc) {
3976 path = argv[optind];
3978 /* If mode == 0, this means we apply the mask. */
3979 if (mode == LFS_HSM_SET)
3980 rc = llapi_hsm_state_set(path, mask, 0, 0);
3982 rc = llapi_hsm_state_set(path, 0, mask, 0);
3985 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3986 path, strerror(errno = -rc));
3995 static int lfs_hsm_action(int argc, char **argv)
4000 struct hsm_current_action hca;
4001 struct hsm_extent he;
4002 enum hsm_user_action hua;
4003 enum hsm_progress_states hps;
4011 rc = llapi_hsm_current_action(path, &hca);
4013 fprintf(stderr, "can't get hsm action for %s: %s\n",
4014 path, strerror(errno = -rc));
4017 he = hca.hca_location;
4018 hua = hca.hca_action;
4019 hps = hca.hca_state;
4021 printf("%s: %s", path, hsm_user_action2name(hua));
4023 /* Skip file without action */
4024 if (hca.hca_action == HUA_NONE) {
4029 printf(" %s ", hsm_progress_state2name(hps));
4031 if ((hps == HPS_RUNNING) &&
4032 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4033 printf("(%llu bytes moved)\n",
4034 (unsigned long long)he.length);
4035 else if ((he.offset + he.length) == LUSTRE_EOF)
4036 printf("(from %llu to EOF)\n",
4037 (unsigned long long)he.offset);
4039 printf("(from %llu to %llu)\n",
4040 (unsigned long long)he.offset,
4041 (unsigned long long)(he.offset + he.length));
4043 } while (++i < argc);
4048 static int lfs_hsm_set(int argc, char **argv)
4050 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4053 static int lfs_hsm_clear(int argc, char **argv)
4055 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4059 * Check file state and return its fid, to be used by lfs_hsm_request().
4061 * \param[in] file Path to file to check
4062 * \param[in,out] fid Pointer to allocated lu_fid struct.
4063 * \param[in,out] last_dev Pointer to last device id used.
4065 * \return 0 on success.
4067 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4073 rc = lstat(file, &st);
4075 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4078 /* Checking for regular file as archiving as posix copytool
4079 * rejects archiving files other than regular files
4081 if (!S_ISREG(st.st_mode)) {
4082 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4085 /* A request should be ... */
4086 if (*last_dev != st.st_dev && *last_dev != 0) {
4087 fprintf(stderr, "All files should be "
4088 "on the same filesystem: %s\n", file);
4091 *last_dev = st.st_dev;
4093 rc = llapi_path2fid(file, fid);
4095 fprintf(stderr, "Cannot read FID of %s: %s\n",
4096 file, strerror(-rc));
4102 /* Fill an HSM HUR item with a given file name.
4104 * If mntpath is set, then the filename is actually a FID, and no
4105 * lookup on the filesystem will be performed.
4107 * \param[in] hur the user request to fill
4108 * \param[in] idx index of the item inside the HUR to fill
4109 * \param[in] mntpath mountpoint of Lustre
4110 * \param[in] fname filename (if mtnpath is NULL)
4111 * or FID (if mntpath is set)
4112 * \param[in] last_dev pointer to last device id used
4114 * \retval 0 on success
4115 * \retval CMD_HELP or a negative errno on error
4117 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4118 const char *mntpath, const char *fname,
4121 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4124 hui->hui_extent.length = -1;
4126 if (mntpath != NULL) {
4129 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4133 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4138 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4142 hur->hur_request.hr_itemcount++;
4147 static int lfs_hsm_request(int argc, char **argv, int action)
4149 struct option long_opts[] = {
4150 {"filelist", 1, 0, 'l'},
4151 {"data", 1, 0, 'D'},
4152 {"archive", 1, 0, 'a'},
4153 {"mntpath", 1, 0, 'm'},
4157 char short_opts[] = "l:D:a:m:";
4158 struct hsm_user_request *hur, *oldhur;
4163 char *filelist = NULL;
4164 char fullpath[PATH_MAX];
4165 char *opaque = NULL;
4169 int nbfile_alloc = 0;
4170 char *some_file = NULL;
4171 char *mntpath = NULL;
4177 while ((c = getopt_long(argc, argv, short_opts,
4178 long_opts, NULL)) != -1) {
4187 if (action != HUA_ARCHIVE &&
4188 action != HUA_REMOVE) {
4190 "error: -a is supported only "
4191 "when archiving or removing\n");
4194 archive_id = atoi(optarg);
4197 if (some_file == NULL) {
4199 some_file = strdup(optarg);
4205 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4206 argv[0], argv[optind - 1]);
4211 /* All remaining args are files, so we have at least nbfile */
4212 nbfile = argc - optind;
4214 if ((nbfile == 0) && (filelist == NULL))
4218 opaque_len = strlen(opaque);
4220 /* Alloc the request structure with enough place to store all files
4221 * from command line. */
4222 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4224 fprintf(stderr, "Cannot create the request: %s\n",
4228 nbfile_alloc = nbfile;
4230 hur->hur_request.hr_action = action;
4231 hur->hur_request.hr_archive_id = archive_id;
4232 hur->hur_request.hr_flags = 0;
4234 /* All remaining args are files, add them */
4235 if (nbfile != 0 && some_file == NULL)
4236 some_file = strdup(argv[optind]);
4238 for (i = 0; i < nbfile; i++) {
4239 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4245 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4247 /* If a filelist was specified, read the filelist from it. */
4248 if (filelist != NULL) {
4249 fp = fopen(filelist, "r");
4251 fprintf(stderr, "Cannot read the file list %s: %s\n",
4252 filelist, strerror(errno));
4257 while ((rc = getline(&line, &len, fp)) != -1) {
4258 /* If allocated buffer was too small, get something
4260 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4263 nbfile_alloc = nbfile_alloc * 2 + 1;
4265 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4268 fprintf(stderr, "hsm: cannot allocate "
4269 "the request: %s\n",
4276 size = hur_len(oldhur);
4278 fprintf(stderr, "hsm: cannot allocate "
4279 "%u files + %u bytes data\n",
4280 oldhur->hur_request.hr_itemcount,
4281 oldhur->hur_request.hr_data_len);
4288 memcpy(hur, oldhur, size);
4293 if (line[strlen(line) - 1] == '\n')
4294 line[strlen(line) - 1] = '\0';
4296 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4297 mntpath, line, &last_dev);
4303 if (some_file == NULL) {
4313 /* If a --data was used, add it to the request */
4314 hur->hur_request.hr_data_len = opaque_len;
4316 memcpy(hur_data(hur), opaque, opaque_len);
4318 /* Send the HSM request */
4319 if (realpath(some_file, fullpath) == NULL) {
4320 fprintf(stderr, "Could not find path '%s': %s\n",
4321 some_file, strerror(errno));
4323 rc = llapi_hsm_request(fullpath, hur);
4325 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4326 some_file, strerror(-rc));
4336 static int lfs_hsm_archive(int argc, char **argv)
4338 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4341 static int lfs_hsm_restore(int argc, char **argv)
4343 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4346 static int lfs_hsm_release(int argc, char **argv)
4348 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4351 static int lfs_hsm_remove(int argc, char **argv)
4353 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4356 static int lfs_hsm_cancel(int argc, char **argv)
4358 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4361 static int lfs_swap_layouts(int argc, char **argv)
4366 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4367 SWAP_LAYOUTS_KEEP_MTIME |
4368 SWAP_LAYOUTS_KEEP_ATIME);
4371 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
4373 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
4375 enum lu_ladvise_type advice;
4378 advice < ARRAY_SIZE(ladvise_names); advice++) {
4379 if (ladvise_names[advice] == NULL)
4381 if (strcmp(string, ladvise_names[advice]) == 0)
4385 return LU_LADVISE_INVALID;
4388 static int lfs_ladvise(int argc, char **argv)
4390 struct option long_opts[] = {
4391 {"advice", required_argument, 0, 'a'},
4392 {"background", no_argument, 0, 'b'},
4393 {"end", required_argument, 0, 'e'},
4394 {"start", required_argument, 0, 's'},
4395 {"length", required_argument, 0, 'l'},
4398 char short_opts[] = "a:be:l:s:";
4403 struct llapi_lu_ladvise advice;
4404 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
4405 unsigned long long start = 0;
4406 unsigned long long end = LUSTRE_EOF;
4407 unsigned long long length = 0;
4408 unsigned long long size_units;
4409 unsigned long long flags = 0;
4412 while ((c = getopt_long(argc, argv, short_opts,
4413 long_opts, NULL)) != -1) {
4416 advice_type = lfs_get_ladvice(optarg);
4417 if (advice_type == LU_LADVISE_INVALID) {
4418 fprintf(stderr, "%s: invalid advice type "
4419 "'%s'\n", argv[0], optarg);
4420 fprintf(stderr, "Valid types:");
4422 for (advice_type = 0;
4423 advice_type < ARRAY_SIZE(ladvise_names);
4425 if (ladvise_names[advice_type] == NULL)
4427 fprintf(stderr, " %s",
4428 ladvise_names[advice_type]);
4430 fprintf(stderr, "\n");
4440 rc = llapi_parse_size(optarg, &end,
4443 fprintf(stderr, "%s: bad end offset '%s'\n",
4450 rc = llapi_parse_size(optarg, &start,
4453 fprintf(stderr, "%s: bad start offset "
4454 "'%s'\n", argv[0], optarg);
4460 rc = llapi_parse_size(optarg, &length,
4463 fprintf(stderr, "%s: bad length '%s'\n",
4471 fprintf(stderr, "%s: option '%s' unrecognized\n",
4472 argv[0], argv[optind - 1]);
4477 if (advice_type == LU_LADVISE_INVALID) {
4478 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
4479 fprintf(stderr, "Valid types:");
4480 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
4482 if (ladvise_names[advice_type] == NULL)
4484 fprintf(stderr, " %s", ladvise_names[advice_type]);
4486 fprintf(stderr, "\n");
4490 if (argc <= optind) {
4491 fprintf(stderr, "%s: please give one or more file names\n",
4496 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
4497 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
4502 if (end == LUSTRE_EOF && length != 0)
4503 end = start + length;
4506 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
4507 argv[0], start, end);
4511 while (optind < argc) {
4514 path = argv[optind++];
4516 fd = open(path, O_RDONLY);
4518 fprintf(stderr, "%s: cannot open file '%s': %s\n",
4519 argv[0], path, strerror(errno));
4524 advice.lla_start = start;
4525 advice.lla_end = end;
4526 advice.lla_advice = advice_type;
4527 advice.lla_value1 = 0;
4528 advice.lla_value2 = 0;
4529 advice.lla_value3 = 0;
4530 advice.lla_value4 = 0;
4531 rc2 = llapi_ladvise(fd, flags, 1, &advice);
4534 fprintf(stderr, "%s: cannot give advice '%s' to file "
4535 "'%s': %s\n", argv[0],
4536 ladvise_names[advice_type],
4537 path, strerror(errno));
4540 if (rc == 0 && rc2 < 0)
4546 static int lfs_list_commands(int argc, char **argv)
4548 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
4550 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
4555 int main(int argc, char **argv)
4559 /* Ensure that liblustreapi constructor has run */
4560 if (!liblustreapi_initialized)
4561 fprintf(stderr, "liblustreapi was not properly initialized\n");
4565 Parser_init("lfs > ", cmdlist);
4567 progname = argv[0]; /* Used in error messages */
4569 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4571 rc = Parser_commands();
4574 return rc < 0 ? -rc : rc;
4577 #ifdef _LUSTRE_IDL_H_
4578 /* Everything we need here should be included by lustreapi.h. */
4579 # error "lfs should not depend on lustre_idl.h"
4580 #endif /* _LUSTRE_IDL_H_ */