4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
57 #include <sys/types.h>
63 #ifdef HAVE_SYS_QUOTA_H
64 # include <sys/quota.h>
67 #include <libcfs/util/string.h>
68 #include <libcfs/util/ioctl.h>
69 #include <libcfs/util/parser.h>
70 #include <lustre/lustreapi.h>
71 #include <lustre_ver.h>
72 #include <lustre_param.h>
75 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
76 #endif /* !ARRAY_SIZE */
79 static int lfs_setstripe(int argc, char **argv);
80 static int lfs_find(int argc, char **argv);
81 static int lfs_getstripe(int argc, char **argv);
82 static int lfs_getdirstripe(int argc, char **argv);
83 static int lfs_setdirstripe(int argc, char **argv);
84 static int lfs_rmentry(int argc, char **argv);
85 static int lfs_osts(int argc, char **argv);
86 static int lfs_mdts(int argc, char **argv);
87 static int lfs_df(int argc, char **argv);
88 static int lfs_getname(int argc, char **argv);
89 static int lfs_check(int argc, char **argv);
90 #ifdef HAVE_SYS_QUOTA_H
91 static int lfs_setquota(int argc, char **argv);
92 static int lfs_quota(int argc, char **argv);
94 static int lfs_flushctx(int argc, char **argv);
95 static int lfs_join(int argc, char **argv);
96 static int lfs_lsetfacl(int argc, char **argv);
97 static int lfs_lgetfacl(int argc, char **argv);
98 static int lfs_rsetfacl(int argc, char **argv);
99 static int lfs_rgetfacl(int argc, char **argv);
100 static int lfs_cp(int argc, char **argv);
101 static int lfs_ls(int argc, char **argv);
102 static int lfs_poollist(int argc, char **argv);
103 static int lfs_changelog(int argc, char **argv);
104 static int lfs_changelog_clear(int argc, char **argv);
105 static int lfs_fid2path(int argc, char **argv);
106 static int lfs_path2fid(int argc, char **argv);
107 static int lfs_data_version(int argc, char **argv);
108 static int lfs_hsm_state(int argc, char **argv);
109 static int lfs_hsm_set(int argc, char **argv);
110 static int lfs_hsm_clear(int argc, char **argv);
111 static int lfs_hsm_action(int argc, char **argv);
112 static int lfs_hsm_archive(int argc, char **argv);
113 static int lfs_hsm_restore(int argc, char **argv);
114 static int lfs_hsm_release(int argc, char **argv);
115 static int lfs_hsm_remove(int argc, char **argv);
116 static int lfs_hsm_cancel(int argc, char **argv);
117 static int lfs_swap_layouts(int argc, char **argv);
118 static int lfs_mv(int argc, char **argv);
119 static int lfs_ladvise(int argc, char **argv);
121 /* Setstripe and migrate share mostly the same parameters */
122 #define SSM_CMD_COMMON(cmd) \
123 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
124 " [--stripe-index|-i <start_ost_idx>]\n" \
125 " [--stripe-size|-S <stripe_size>]\n" \
126 " [--pool|-p <pool_name>]\n" \
127 " [--ost|-o <ost_indices>]\n"
129 #define SSM_HELP_COMMON \
130 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
131 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
132 "\t respectively)\n" \
133 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
134 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
135 "\tpool_name: Name of OST pool to use (default none)\n" \
136 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
137 "\t Indices be specified in a format of:\n" \
138 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
140 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
141 "\t If --pool is set with --ost, then the OSTs\n" \
142 "\t must be the members of the pool."
144 #define SETSTRIPE_USAGE \
145 SSM_CMD_COMMON("setstripe") \
146 " <directory|filename>\n" \
149 #define MIGRATE_USAGE \
150 SSM_CMD_COMMON("migrate ") \
152 " [--non-block|-n]\n" \
156 "\tblock: Block file access during data migration (default)\n" \
157 "\tnon-block: Abort migrations if concurrent access is detected\n" \
159 #define SETDIRSTRIPE_USAGE \
160 " [--mdt-count|-c stripe_count>\n" \
161 " [--mdt-index|-i mdt_index]\n" \
162 " [--mdt-hash|-t mdt_hash]\n" \
163 " [--default|-D] [--mode|-m mode] <dir>\n" \
164 "\tstripe_count: stripe count of the striped directory\n" \
165 "\tmdt_index: MDT index of first stripe\n" \
166 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
167 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
168 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
169 "\tdefault_stripe: set default dirstripe of the directory\n" \
170 "\tmode: the mode of the directory\n"
172 static const char *progname;
173 static bool file_lease_supported = true;
175 /* all available commands */
176 command_t cmdlist[] = {
177 {"setstripe", lfs_setstripe, 0,
178 "Create a new file with a specific striping pattern or\n"
179 "set the default striping pattern on an existing directory or\n"
180 "delete the default striping pattern from an existing directory\n"
181 "usage: setstripe -d <directory> (to delete default striping)\n"\
184 {"getstripe", lfs_getstripe, 0,
185 "To list the striping info for a given file or files in a\n"
186 "directory or recursively for all files in a directory tree.\n"
187 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
188 " [--stripe-count|-c] [--stripe-index|-i]\n"
189 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
190 " [--mdt|-m] [--recursive|-r] [--raw|-R]\n"
191 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
192 " <directory|filename> ..."},
193 {"setdirstripe", lfs_setdirstripe, 0,
194 "To create a striped directory on a specified MDT. This can only\n"
195 "be done on MDT0 with the right of administrator.\n"
196 "usage: setdirstripe [OPTION] <directory>\n"
198 {"getdirstripe", lfs_getdirstripe, 0,
199 "To list the striping info for a given directory\n"
200 "or recursively for all directories in a directory tree.\n"
201 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
202 " [--mdt-index|-i] [--mdt-hash|-t]\n"
203 " [--recursive|-r] [--default|-D] <dir> ..."},
204 {"mkdir", lfs_setdirstripe, 0,
205 "To create a striped directory on a specified MDT. This can only\n"
206 "be done on MDT0 with the right of administrator.\n"
207 "usage: mkdir [OPTION] <directory>\n"
209 {"rm_entry", lfs_rmentry, 0,
210 "To remove the name entry of the remote directory. Note: This\n"
211 "command will only delete the name entry, i.e. the remote directory\n"
212 "will become inaccessable after this command. This can only be done\n"
213 "by the administrator\n"
214 "usage: rm_entry <dir>\n"},
215 {"pool_list", lfs_poollist, 0,
216 "List pools or pool OSTs\n"
217 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
218 {"find", lfs_find, 0,
219 "find files matching given attributes recursively in directory tree.\n"
220 "usage: find <directory|filename> ...\n"
221 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
222 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
223 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
224 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
225 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
226 " [[!] --stripe-count|-c [+-]<stripes>]\n"
227 " [[!] --stripe-index|-i <index,...>]\n"
228 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
229 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
230 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
231 " [[!] --layout|-L released,raid0]\n"
232 "\t !: used before an option indicates 'NOT' requested attribute\n"
233 "\t -: used before a value indicates 'AT MOST' requested value\n"
234 "\t +: used before a value indicates 'AT LEAST' requested value\n"},
235 {"check", lfs_check, 0,
236 "Display the status of MDS or OSTs (as specified in the command)\n"
237 "or all the servers (MDS and OSTs).\n"
238 "usage: check <osts|mds|servers>"},
239 {"join", lfs_join, 0,
240 "join two lustre files into one.\n"
241 "obsolete, HEAD does not support it anymore.\n"},
242 {"osts", lfs_osts, 0, "list OSTs connected to client "
243 "[for specified path only]\n" "usage: osts [path]"},
244 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
245 "[for specified path only]\n" "usage: mdts [path]"},
247 "report filesystem disk space usage or inodes usage"
248 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
249 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
250 {"getname", lfs_getname, 0, "list instances and specified mount points "
251 "[for specified path only]\n"
252 "Usage: getname [-h]|[path ...] "},
253 #ifdef HAVE_SYS_QUOTA_H
254 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
255 "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
256 " -b <block-softlimit> -B <block-hardlimit>\n"
257 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
258 " setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
259 " [--block-softlimit <block-softlimit>]\n"
260 " [--block-hardlimit <block-hardlimit>]\n"
261 " [--inode-softlimit <inode-softlimit>]\n"
262 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
263 " setquota [-t] <-u|--user|-g|--group>\n"
264 " [--block-grace <block-grace>]\n"
265 " [--inode-grace <inode-grace>] <filesystem>\n"
266 " -b can be used instead of --block-softlimit/--block-grace\n"
267 " -B can be used instead of --block-hardlimit\n"
268 " -i can be used instead of --inode-softlimit/--inode-grace\n"
269 " -I can be used instead of --inode-hardlimit\n\n"
270 "Note: The total quota space will be split into many qunits and\n"
271 " balanced over all server targets, the minimal qunit size is\n"
272 " 1M bytes for block space and 1K inodes for inode space.\n\n"
273 " Quota space rebalancing process will stop when this mininum\n"
274 " value is reached. As a result, quota exceeded can be returned\n"
275 " while many targets still have 1MB or 1K inodes of spare\n"
277 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
278 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
280 " [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
281 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
283 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
284 "usage: flushctx [-k] [mountpoint...]"},
285 {"lsetfacl", lfs_lsetfacl, 0,
286 "Remote user setfacl for user/group on the same remote client.\n"
287 "usage: lsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
288 {"lgetfacl", lfs_lgetfacl, 0,
289 "Remote user getfacl for user/group on the same remote client.\n"
290 "usage: lgetfacl [-dRLPvh] file ..."},
291 {"rsetfacl", lfs_rsetfacl, 0,
292 "Remote user setfacl for user/group on other clients.\n"
293 "usage: rsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
294 {"rgetfacl", lfs_rgetfacl, 0,
295 "Remote user getfacl for user/group on other clients.\n"
296 "usage: rgetfacl [-dRLPvh] file ..."},
298 "Remote user copy files and directories.\n"
299 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
301 "Remote user list directory contents.\n"
302 "usage: ls [OPTION]... [FILE]..."},
303 {"changelog", lfs_changelog, 0,
304 "Show the metadata changes on an MDT."
305 "\nusage: changelog <mdtname> [startrec [endrec]]"},
306 {"changelog_clear", lfs_changelog_clear, 0,
307 "Indicate that old changelog records up to <endrec> are no longer of "
308 "interest to consumer <id>, allowing the system to free up space.\n"
309 "An <endrec> of 0 means all records.\n"
310 "usage: changelog_clear <mdtname> <id> <endrec>"},
311 {"fid2path", lfs_fid2path, 0,
312 "Resolve the full path(s) for given FID(s). For a specific hardlink "
313 "specify link number <linkno>.\n"
314 /* "For a historical link name, specify changelog record <recno>.\n" */
315 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
316 /* [ --rec <recno> ] */ },
317 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
318 "usage: path2fid [--parents] <path> ..."},
319 {"data_version", lfs_data_version, 0, "Display file data version for "
320 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
321 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
322 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
323 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
324 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
325 "[--archived] [--lost] <file> ..."},
326 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
328 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
329 "[--archived] [--lost] <file> ..."},
330 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
331 "given files.\n" "usage: hsm_action <file> ..."},
332 {"hsm_archive", lfs_hsm_archive, 0,
333 "Archive file to external storage.\n"
334 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
336 {"hsm_restore", lfs_hsm_restore, 0,
337 "Restore file from external storage.\n"
338 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
339 {"hsm_release", lfs_hsm_release, 0,
340 "Release files from Lustre.\n"
341 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
342 {"hsm_remove", lfs_hsm_remove, 0,
343 "Remove file copy from external storage.\n"
344 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
345 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
347 "Note: To remove files from the archive that have been deleted on\n"
348 "Lustre, set mntpath and optionally archive. In that case, all the\n"
349 "positional arguments and entries in the file list must be FIDs."
351 {"hsm_cancel", lfs_hsm_cancel, 0,
352 "Cancel requests related to specified files.\n"
353 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
354 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
355 "usage: swap_layouts <path1> <path2>"},
356 {"migrate", lfs_setstripe, 0,
357 "migrate a directory between MDTs.\n"
358 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
360 "\tmdt_idx: index of the destination MDT\n"
362 "migrate file objects from one OST "
363 "layout\nto another (may be not safe with concurent writes).\n"
365 "[--stripe-count|-c] <stripe_count>\n"
366 " [--stripe-index|-i] <start_ost_index>\n"
367 " [--stripe-size|-S] <stripe_size>\n"
368 " [--pool|-p] <pool_name>\n"
369 " [--ost-list|-o] <ost_indices>\n"
371 " [--non-block|-n]\n"
372 " <file|directory>\n"
373 "\tstripe_count: number of OSTs to stripe a file over\n"
374 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
375 "\tstripe_size: number of bytes to store before moving to the next OST\n"
376 "\tpool_name: name of the predefined pool of OSTs\n"
377 "\tost_indices: OSTs to stripe over, in order\n"
378 "\tblock: wait for the operation to return before continuing\n"
379 "\tnon-block: do not wait for the operation to return.\n"},
381 "To move directories between MDTs. This command is deprecated, "
382 "use \"migrate\" instead.\n"
383 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
385 {"ladvise", lfs_ladvise, 0,
386 "Provide servers with advice about access patterns for a file.\n"
387 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
388 " [--background|-b]\n"
389 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
391 {"help", Parser_help, 0, "help"},
392 {"exit", Parser_quit, 0, "quit"},
393 {"quit", Parser_quit, 0, "quit"},
394 {"--version", Parser_version, 0,
395 "output build version of the utility and exit"},
400 #define MIGRATION_NONBLOCK 1
403 * Internal helper for migrate_copy_data(). Check lease and report error if
406 * \param[in] fd File descriptor on which to check the lease.
407 * \param[out] lease_broken Set to true if the lease was broken.
408 * \param[in] group_locked Whether a group lock was taken or not.
409 * \param[in] path Name of the file being processed, for error
412 * \retval 0 Migration can keep on going.
413 * \retval -errno Error occurred, abort migration.
415 static int check_lease(int fd, bool *lease_broken, bool group_locked,
420 if (!file_lease_supported)
423 rc = llapi_lease_check(fd);
425 return 0; /* llapi_check_lease returns > 0 on success. */
428 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
430 rc = rc ? rc : -EAGAIN;
432 fprintf(stderr, "%s: external attempt to access file '%s' "
433 "blocked until migration ends.\n", progname, path);
436 *lease_broken = true;
440 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
441 bool group_locked, const char *fname)
450 bool lease_broken = false;
452 /* Use a page-aligned buffer for direct I/O */
453 rc = posix_memalign(&buf, getpagesize(), buf_size);
458 /* read new data only if we have written all
459 * previously read data */
462 rc = check_lease(fd_src, &lease_broken,
463 group_locked, fname);
467 rsize = read(fd_src, buf, buf_size);
470 fprintf(stderr, "%s: %s: read failed: %s\n",
471 progname, fname, strerror(-rc));
481 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
485 "%s: %s: write failed on volatile: %s\n",
486 progname, fname, strerror(-rc));
496 fprintf(stderr, "%s: %s: fsync failed: %s\n",
497 progname, fname, strerror(-rc));
505 static int migrate_copy_timestamps(int fdv, const struct stat *st)
507 struct timeval tv[2] = {
508 {.tv_sec = st->st_atime},
509 {.tv_sec = st->st_mtime}
512 return futimes(fdv, tv);
515 static int migrate_block(int fd, int fdv, const struct stat *st,
516 size_t buf_size, const char *name)
523 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
525 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
526 progname, name, strerror(-rc));
534 /* The grouplock blocks all concurrent accesses to the file.
535 * It has to be taken after llapi_get_data_version as it would
537 rc = llapi_group_lock(fd, gid);
539 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
540 progname, name, strerror(-rc));
544 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
546 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
550 /* Make sure we keep original atime/mtime values */
551 rc = migrate_copy_timestamps(fdv, st);
553 fprintf(stderr, "%s: %s: timestamp copy failed\n",
559 * for a migration we need to check data version on file did
562 * Pass in gid=0 since we already own grouplock. */
563 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
564 SWAP_LAYOUTS_CHECK_DV1);
566 fprintf(stderr, "%s: %s: dataversion changed during copy, "
567 "migration aborted\n", progname, name);
570 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
571 name, strerror(-rc));
576 rc2 = llapi_group_unlock(fd, gid);
577 if (rc2 < 0 && rc == 0) {
578 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
579 progname, name, strerror(-rc2));
586 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
587 size_t buf_size, const char *name)
593 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
595 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
596 progname, name, strerror(-rc));
600 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
602 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
606 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
608 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
609 progname, name, strerror(-rc));
615 fprintf(stderr, "%s: %s: data version changed during "
621 /* Make sure we keep original atime/mtime values */
622 rc = migrate_copy_timestamps(fdv, st);
624 fprintf(stderr, "%s: %s: timestamp copy failed\n",
629 /* Atomically put lease, swap layouts and close.
630 * for a migration we need to check data version on file did
632 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
634 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
635 progname, name, strerror(-rc));
642 static int lfs_migrate(char *name, __u64 migration_flags,
643 struct llapi_stripe_param *param)
647 char parent[PATH_MAX];
650 char volatile_file[sizeof(parent) +
651 LUSTRE_VOLATILE_HDR_LEN +
652 2 * sizeof(mdt_index) +
653 2 * sizeof(random_value) + 4];
656 struct lov_user_md *lum = NULL;
659 bool have_lease_rdlck = false;
663 /* find the right size for the IO and allocate the buffer */
664 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
665 lum = malloc(lum_size);
671 rc = llapi_file_get_stripe(name, lum);
672 /* failure can happen for many reasons and some may be not real errors
674 * in case of a real error, a later call will fail with better
675 * error management */
677 buf_size = 1024 * 1024;
679 buf_size = lum->lmm_stripe_size;
681 /* open file, direct io */
682 /* even if the file is only read, WR mode is nedeed to allow
683 * layout swap on fd */
684 fd = open(name, O_RDWR | O_DIRECT);
687 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
692 if (file_lease_supported) {
693 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
694 if (rc == -EOPNOTSUPP) {
695 /* Older servers do not support file lease.
696 * Disable related checks. This opens race conditions
697 * as explained in LU-4840 */
698 file_lease_supported = false;
700 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
701 progname, name, strerror(-rc));
704 have_lease_rdlck = true;
708 /* search for file directory pathname */
709 if (strlen(name) > sizeof(parent)-1) {
713 strncpy(parent, name, sizeof(parent));
714 ptr = strrchr(parent, '/');
716 if (getcwd(parent, sizeof(parent)) == NULL) {
727 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
729 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
730 progname, name, strerror(-rc));
735 random_value = random();
736 rc = snprintf(volatile_file, sizeof(volatile_file),
737 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
738 mdt_index, random_value);
739 if (rc >= sizeof(volatile_file)) {
744 /* create, open a volatile file, use caching (ie no directio) */
745 fdv = llapi_file_open_param(volatile_file,
746 O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW,
747 S_IRUSR | S_IWUSR, param);
748 } while (fdv == -EEXIST);
752 fprintf(stderr, "%s: %s: cannot create volatile file in"
754 progname, parent, strerror(-rc));
758 /* In case the MDT does not support creation of volatile files
759 * we should try to unlink it. */
760 (void)unlink(volatile_file);
762 /* Not-owner (root?) special case.
763 * Need to set owner/group of volatile file like original.
764 * This will allow to pass related check during layout_swap.
769 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
773 rc = fstat(fdv, &stv);
776 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
777 volatile_file, strerror(errno));
780 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
781 rc = fchown(fdv, st.st_uid, st.st_gid);
784 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
785 name, strerror(errno));
790 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
791 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
793 have_lease_rdlck = false;
794 fdv = -1; /* The volatile file is closed as we put the
795 * lease in non-blocking mode. */
798 /* Blocking mode (forced if servers do not support file lease).
799 * It is also the default mode, since we cannot distinguish
800 * between a broken lease and a server that does not support
801 * atomic swap/close (LU-6785) */
802 rc = migrate_block(fd, fdv, &st, buf_size, name);
806 if (have_lease_rdlck)
823 * Parse a string containing an OST index list into an array of integers.
825 * The input string contains a comma delimited list of individual
826 * indices and ranges, for example "1,2-4,7". Add the indices into the
827 * \a osts array and remove duplicates.
829 * \param[out] osts array to store indices in
830 * \param[in] size size of \a osts array
831 * \param[in] offset starting index in \a osts
832 * \param[in] arg string containing OST index list
834 * \retval positive number of indices in \a osts
835 * \retval -EINVAL unable to parse \a arg
837 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
841 int slots = size - offset;
849 while (!end_of_loop) {
857 ptr = strchrnul(arg, ',');
859 end_of_loop = *ptr == '\0';
862 start_index = strtol(arg, &endptr, 0);
863 if (endptr == arg) /* no data at all */
865 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
870 end_index = start_index;
871 if (*endptr == '-') {
872 end_index = strtol(endptr + 1, &endptr, 0);
875 if (end_index < start_index)
879 for (i = start_index; i <= end_index && slots > 0; i++) {
882 /* remove duplicate */
883 for (j = 0; j < offset; j++) {
887 if (j == offset) { /* no duplicate */
892 if (slots == 0 && i < end_index)
900 if (!end_of_loop && ptr != NULL)
903 return rc < 0 ? rc : nr;
907 static int lfs_setstripe(int argc, char **argv)
909 struct llapi_stripe_param *param = NULL;
910 struct find_param migrate_mdt_param = {
917 unsigned long long st_size;
918 int st_offset, st_count;
922 char *stripe_size_arg = NULL;
923 char *stripe_off_arg = NULL;
924 char *stripe_count_arg = NULL;
925 char *pool_name_arg = NULL;
926 char *mdt_idx_arg = NULL;
927 unsigned long long size_units = 1;
928 bool migrate_mode = false;
929 bool migration_block = false;
930 __u64 migration_flags = 0;
931 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
934 struct option long_opts[] = {
935 /* --block is only valid in migrate mode */
936 {"block", no_argument, 0, 'b'},
937 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
938 /* This formerly implied "stripe-count", but was explicitly
939 * made "stripe-count" for consistency with other options,
940 * and to separate it from "mdt-count" when DNE arrives. */
941 {"count", required_argument, 0, 'c'},
943 {"stripe-count", required_argument, 0, 'c'},
944 {"stripe_count", required_argument, 0, 'c'},
945 {"delete", no_argument, 0, 'd'},
946 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
947 /* This formerly implied "stripe-index", but was explicitly
948 * made "stripe-index" for consistency with other options,
949 * and to separate it from "mdt-index" when DNE arrives. */
950 {"index", required_argument, 0, 'i'},
952 {"stripe-index", required_argument, 0, 'i'},
953 {"stripe_index", required_argument, 0, 'i'},
954 {"mdt", required_argument, 0, 'm'},
955 {"mdt-index", required_argument, 0, 'm'},
956 {"mdt_index", required_argument, 0, 'm'},
957 /* --non-block is only valid in migrate mode */
958 {"non-block", no_argument, 0, 'n'},
959 {"ost", required_argument, 0, 'o'},
960 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
961 {"ost-list", required_argument, 0, 'o'},
962 {"ost_list", required_argument, 0, 'o'},
964 {"pool", required_argument, 0, 'p'},
965 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
966 /* This formerly implied "--stripe-size", but was confusing
967 * with "lfs find --size|-s", which means "file size", so use
968 * the consistent "--stripe-size|-S" for all commands. */
969 {"size", required_argument, 0, 's'},
971 {"stripe-size", required_argument, 0, 'S'},
972 {"stripe_size", required_argument, 0, 'S'},
973 /* --verbose is only valid in migrate mode */
974 {"verbose", no_argument, 0, 'v'},
982 if (strcmp(argv[0], "migrate") == 0)
985 while ((c = getopt_long(argc, argv, "bc:di:m:no:p:s:S:v",
986 long_opts, NULL)) >= 0) {
993 fprintf(stderr, "--block is valid only for"
997 migration_block = true;
1000 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1001 if (strcmp(argv[optind - 1], "--count") == 0)
1002 fprintf(stderr, "warning: '--count' deprecated"
1003 ", use '--stripe-count' instead\n");
1005 stripe_count_arg = optarg;
1008 /* delete the default striping pattern */
1012 nr_osts = parse_targets(osts,
1013 sizeof(osts) / sizeof(__u32),
1017 "error: %s: bad OST indices '%s'\n",
1022 if (st_offset == -1) /* first in the command line */
1023 st_offset = osts[0];
1026 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1027 if (strcmp(argv[optind - 1], "--index") == 0)
1028 fprintf(stderr, "warning: '--index' deprecated"
1029 ", use '--stripe-index' instead\n");
1031 stripe_off_arg = optarg;
1034 if (!migrate_mode) {
1035 fprintf(stderr, "--mdt-index is valid only for"
1039 mdt_idx_arg = optarg;
1042 if (!migrate_mode) {
1043 fprintf(stderr, "--non-block is valid only for"
1047 migration_flags |= MIGRATION_NONBLOCK;
1049 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1051 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1052 fprintf(stderr, "warning: '--size|-s' deprecated, "
1053 "use '--stripe-size|-S' instead\n");
1055 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1057 stripe_size_arg = optarg;
1060 pool_name_arg = optarg;
1063 if (!migrate_mode) {
1064 fprintf(stderr, "--verbose is valid only for"
1068 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1075 fname = argv[optind];
1078 (stripe_size_arg != NULL || stripe_off_arg != NULL ||
1079 stripe_count_arg != NULL || pool_name_arg != NULL)) {
1080 fprintf(stderr, "error: %s: cannot specify -d with "
1081 "-s, -c, -o, or -p options\n",
1086 if (optind == argc) {
1087 fprintf(stderr, "error: %s: missing filename|dirname\n",
1092 if (mdt_idx_arg != NULL && optind > 3) {
1093 fprintf(stderr, "error: %s: cannot specify -m with other "
1094 "options\n", argv[0]);
1098 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1100 "error: %s: cannot specify --non-block and --block\n",
1105 if (pool_name_arg != NULL) {
1109 ptr = strchr(pool_name_arg, '.');
1111 ptr = pool_name_arg;
1113 if ((ptr - pool_name_arg) == 0) {
1114 fprintf(stderr, "error: %s: fsname is empty "
1115 "in pool name '%s'\n",
1116 argv[0], pool_name_arg);
1123 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1125 fprintf(stderr, "error: %s: poolname '%s' is "
1127 argv[0], pool_name_arg);
1129 } else if (rc == -2) {
1130 fprintf(stderr, "error: %s: pool name '%s' is too long "
1131 "(max is %d characters)\n",
1132 argv[0], pool_name_arg, LOV_MAXPOOLNAME);
1134 } else if (rc > 0) {
1135 fprintf(stderr, "error: %s: char '%c' not allowed in "
1137 argv[0], rc, pool_name_arg);
1142 /* get the stripe size */
1143 if (stripe_size_arg != NULL) {
1144 result = llapi_parse_size(stripe_size_arg, &st_size,
1147 fprintf(stderr, "error: %s: bad stripe size '%s'\n",
1148 argv[0], stripe_size_arg);
1152 /* get the stripe offset */
1153 if (stripe_off_arg != NULL) {
1154 st_offset = strtol(stripe_off_arg, &end, 0);
1156 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1157 argv[0], stripe_off_arg);
1161 /* get the stripe count */
1162 if (stripe_count_arg != NULL) {
1163 st_count = strtoul(stripe_count_arg, &end, 0);
1165 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1166 argv[0], stripe_count_arg);
1171 if (mdt_idx_arg != NULL) {
1172 /* initialize migrate mdt parameters */
1173 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1175 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1176 argv[0], mdt_idx_arg);
1179 migrate_mdt_param.fp_migrate = 1;
1181 /* initialize stripe parameters */
1182 param = calloc(1, offsetof(typeof(*param), lsp_osts[nr_osts]));
1183 if (param == NULL) {
1184 fprintf(stderr, "error: %s: run out of memory\n",
1189 param->lsp_stripe_size = st_size;
1190 param->lsp_stripe_offset = st_offset;
1191 param->lsp_stripe_count = st_count;
1192 param->lsp_stripe_pattern = 0;
1193 param->lsp_pool = pool_name_arg;
1194 param->lsp_is_specific = false;
1196 if (st_count > 0 && nr_osts != st_count) {
1197 fprintf(stderr, "error: %s: stripe count '%d' "
1198 "doesn't match the number of OSTs: %d\n"
1199 , argv[0], st_count, nr_osts);
1204 param->lsp_is_specific = true;
1205 param->lsp_stripe_count = nr_osts;
1206 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1210 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1211 if (!migrate_mode) {
1212 result = llapi_file_open_param(fname,
1219 } else if (mdt_idx_arg != NULL) {
1220 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1222 result = lfs_migrate(fname, migration_flags, param);
1225 /* Save the first error encountered. */
1228 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1229 argv[0], migrate_mode ? "migrate" : "create",
1231 pool_name_arg != NULL && result == EINVAL ?
1232 "OST not in pool?" : strerror(errno));
1241 static int lfs_poollist(int argc, char **argv)
1246 return llapi_poollist(argv[1]);
1249 static int set_time(time_t *time, time_t *set, char *str)
1256 else if (str[0] == '-')
1262 t = strtol(str, NULL, 0);
1263 if (*time < t * 24 * 60 * 60) {
1266 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1270 *set = *time - t * 24 * 60 * 60;
1277 static int name2id(unsigned int *id, char *name, int type)
1280 struct passwd *entry;
1282 if (!(entry = getpwnam(name))) {
1288 *id = entry->pw_uid;
1290 struct group *entry;
1292 if (!(entry = getgrnam(name))) {
1298 *id = entry->gr_gid;
1304 static int id2name(char **name, unsigned int id, int type)
1307 struct passwd *entry;
1309 if (!(entry = getpwuid(id))) {
1315 *name = entry->pw_name;
1317 struct group *entry;
1319 if (!(entry = getgrgid(id))) {
1325 *name = entry->gr_name;
1331 static int name2layout(__u32 *layout, char *name)
1336 for (ptr = name; ; ptr = NULL) {
1337 lyt = strtok(ptr, ",");
1340 if (strcmp(lyt, "released") == 0)
1341 *layout |= LOV_PATTERN_F_RELEASED;
1342 else if (strcmp(lyt, "raid0") == 0)
1343 *layout |= LOV_PATTERN_RAID0;
1350 #define FIND_POOL_OPT 3
1351 static int lfs_find(int argc, char **argv)
1356 struct find_param param = {
1360 struct option long_opts[] = {
1361 {"atime", required_argument, 0, 'A'},
1362 {"stripe-count", required_argument, 0, 'c'},
1363 {"stripe_count", required_argument, 0, 'c'},
1364 {"ctime", required_argument, 0, 'C'},
1365 {"maxdepth", required_argument, 0, 'D'},
1366 {"gid", required_argument, 0, 'g'},
1367 {"group", required_argument, 0, 'G'},
1368 {"stripe-index", required_argument, 0, 'i'},
1369 {"stripe_index", required_argument, 0, 'i'},
1370 {"layout", required_argument, 0, 'L'},
1371 {"mdt", required_argument, 0, 'm'},
1372 {"mdt-index", required_argument, 0, 'm'},
1373 {"mdt_index", required_argument, 0, 'm'},
1374 {"mtime", required_argument, 0, 'M'},
1375 {"name", required_argument, 0, 'n'},
1376 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1377 {"obd", required_argument, 0, 'O'},
1378 {"ost", required_argument, 0, 'O'},
1379 /* no short option for pool, p/P already used */
1380 {"pool", required_argument, 0, FIND_POOL_OPT},
1381 {"print0", no_argument, 0, 'p'},
1382 {"print", no_argument, 0, 'P'},
1383 {"size", required_argument, 0, 's'},
1384 {"stripe-size", required_argument, 0, 'S'},
1385 {"stripe_size", required_argument, 0, 'S'},
1386 {"type", required_argument, 0, 't'},
1387 {"uid", required_argument, 0, 'u'},
1388 {"user", required_argument, 0, 'U'},
1401 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1402 while ((c = getopt_long_only(argc, argv,
1403 "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1404 long_opts, NULL)) >= 0) {
1409 /* '!' is part of option */
1410 /* when getopt_long_only() finds a string which is not
1411 * an option nor a known option argument it returns 1
1412 * in that case if we already have found pathstart and pathend
1413 * (i.e. we have the list of pathnames),
1414 * the only supported value is "!"
1416 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1417 if (!isoption && pathend != -1) {
1418 fprintf(stderr, "err: %s: filename|dirname must either "
1419 "precede options or follow options\n",
1424 if (!isoption && pathstart == -1)
1425 pathstart = optind - 1;
1426 if (isoption && pathstart != -1 && pathend == -1)
1427 pathend = optind - 2;
1433 /* unknown; opt is "!" or path component,
1434 * checking done above.
1436 if (strcmp(optarg, "!") == 0)
1440 xtime = ¶m.fp_atime;
1441 xsign = ¶m.fp_asign;
1442 param.fp_exclude_atime = !!neg_opt;
1443 /* no break, this falls through to 'C' for ctime */
1446 xtime = ¶m.fp_ctime;
1447 xsign = ¶m.fp_csign;
1448 param.fp_exclude_ctime = !!neg_opt;
1450 /* no break, this falls through to 'M' for mtime */
1453 xtime = ¶m.fp_mtime;
1454 xsign = ¶m.fp_msign;
1455 param.fp_exclude_mtime = !!neg_opt;
1457 rc = set_time(&t, xtime, optarg);
1458 if (rc == INT_MAX) {
1466 if (optarg[0] == '+') {
1467 param.fp_stripe_count_sign = -1;
1469 } else if (optarg[0] == '-') {
1470 param.fp_stripe_count_sign = 1;
1474 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1475 if (*endptr != '\0') {
1476 fprintf(stderr,"error: bad stripe_count '%s'\n",
1481 param.fp_check_stripe_count = 1;
1482 param.fp_exclude_stripe_count = !!neg_opt;
1485 param.fp_max_depth = strtol(optarg, 0, 0);
1489 rc = name2id(¶m.fp_gid, optarg, GROUP);
1491 param.fp_gid = strtoul(optarg, &endptr, 10);
1492 if (*endptr != '\0') {
1493 fprintf(stderr, "Group/GID: %s cannot "
1494 "be found.\n", optarg);
1499 param.fp_exclude_gid = !!neg_opt;
1500 param.fp_check_gid = 1;
1503 ret = name2layout(¶m.fp_layout, optarg);
1506 param.fp_exclude_layout = !!neg_opt;
1507 param.fp_check_layout = 1;
1511 rc = name2id(¶m.fp_uid, optarg, USER);
1513 param.fp_uid = strtoul(optarg, &endptr, 10);
1514 if (*endptr != '\0') {
1515 fprintf(stderr, "User/UID: %s cannot "
1516 "be found.\n", optarg);
1521 param.fp_exclude_uid = !!neg_opt;
1522 param.fp_check_uid = 1;
1525 if (strlen(optarg) > LOV_MAXPOOLNAME) {
1527 "Pool name %s is too long"
1528 " (max is %d)\n", optarg,
1533 /* we do check for empty pool because empty pool
1534 * is used to find V1 lov attributes */
1535 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1536 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1537 param.fp_exclude_pool = !!neg_opt;
1538 param.fp_check_pool = 1;
1541 param.fp_pattern = (char *)optarg;
1542 param.fp_exclude_pattern = !!neg_opt;
1547 char *buf, *token, *next, *p;
1551 buf = strdup(optarg);
1557 param.fp_exclude_obd = !!neg_opt;
1560 while (token && *token) {
1561 token = strchr(token, ',');
1568 param.fp_exclude_mdt = !!neg_opt;
1569 param.fp_num_alloc_mdts += len;
1570 tmp = realloc(param.fp_mdt_uuid,
1571 param.fp_num_alloc_mdts *
1572 sizeof(*param.fp_mdt_uuid));
1578 param.fp_mdt_uuid = tmp;
1580 param.fp_exclude_obd = !!neg_opt;
1581 param.fp_num_alloc_obds += len;
1582 tmp = realloc(param.fp_obd_uuid,
1583 param.fp_num_alloc_obds *
1584 sizeof(*param.fp_obd_uuid));
1590 param.fp_obd_uuid = tmp;
1592 for (token = buf; token && *token; token = next) {
1593 struct obd_uuid *puuid;
1596 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
1599 ¶m.fp_obd_uuid[param.fp_num_obds++];
1601 p = strchr(token, ',');
1608 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1613 strncpy(puuid->uuid, token,
1614 sizeof(puuid->uuid));
1622 param.fp_zero_end = 1;
1627 if (optarg[0] == '+') {
1628 param.fp_size_sign = -1;
1630 } else if (optarg[0] == '-') {
1631 param.fp_size_sign = 1;
1635 ret = llapi_parse_size(optarg, ¶m.fp_size,
1636 ¶m.fp_size_units, 0);
1638 fprintf(stderr, "error: bad file size '%s'\n",
1642 param.fp_check_size = 1;
1643 param.fp_exclude_size = !!neg_opt;
1646 if (optarg[0] == '+') {
1647 param.fp_stripe_size_sign = -1;
1649 } else if (optarg[0] == '-') {
1650 param.fp_stripe_size_sign = 1;
1654 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
1655 ¶m.fp_stripe_size_units, 0);
1657 fprintf(stderr, "error: bad stripe_size '%s'\n",
1661 param.fp_check_stripe_size = 1;
1662 param.fp_exclude_stripe_size = !!neg_opt;
1665 param.fp_exclude_type = !!neg_opt;
1666 switch (optarg[0]) {
1668 param.fp_type = S_IFBLK;
1671 param.fp_type = S_IFCHR;
1674 param.fp_type = S_IFDIR;
1677 param.fp_type = S_IFREG;
1680 param.fp_type = S_IFLNK;
1683 param.fp_type = S_IFIFO;
1686 param.fp_type = S_IFSOCK;
1689 fprintf(stderr, "error: %s: bad type '%s'\n",
1701 if (pathstart == -1) {
1702 fprintf(stderr, "error: %s: no filename|pathname\n",
1706 } else if (pathend == -1) {
1712 rc = llapi_find(argv[pathstart], ¶m);
1713 if (rc != 0 && ret == 0)
1715 } while (++pathstart < pathend);
1718 fprintf(stderr, "error: %s failed for %s.\n",
1719 argv[0], argv[optind - 1]);
1721 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1722 free(param.fp_obd_uuid);
1724 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1725 free(param.fp_mdt_uuid);
1730 static int lfs_getstripe_internal(int argc, char **argv,
1731 struct find_param *param)
1733 struct option long_opts[] = {
1734 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1735 /* This formerly implied "stripe-count", but was explicitly
1736 * made "stripe-count" for consistency with other options,
1737 * and to separate it from "mdt-count" when DNE arrives. */
1738 {"count", no_argument, 0, 'c'},
1740 {"stripe-count", no_argument, 0, 'c'},
1741 {"stripe_count", no_argument, 0, 'c'},
1742 {"directory", no_argument, 0, 'd'},
1743 {"default", no_argument, 0, 'D'},
1744 {"fid", no_argument, 0, 'F'},
1745 {"generation", no_argument, 0, 'g'},
1746 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1747 /* This formerly implied "stripe-index", but was explicitly
1748 * made "stripe-index" for consistency with other options,
1749 * and to separate it from "mdt-index" when DNE arrives. */
1750 {"index", no_argument, 0, 'i'},
1752 {"stripe-index", no_argument, 0, 'i'},
1753 {"stripe_index", no_argument, 0, 'i'},
1754 {"layout", no_argument, 0, 'L'},
1755 {"mdt", no_argument, 0, 'm'},
1756 {"mdt-index", no_argument, 0, 'm'},
1757 {"mdt_index", no_argument, 0, 'm'},
1758 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1759 {"mdt-index", no_argument, 0, 'M'},
1760 {"mdt_index", no_argument, 0, 'M'},
1762 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1763 /* This formerly implied "stripe-index", but was confusing
1764 * with "file offset" (which will eventually be needed for
1765 * with different layouts by offset), so deprecate it. */
1766 {"offset", no_argument, 0, 'o'},
1768 {"obd", required_argument, 0, 'O'},
1769 {"ost", required_argument, 0, 'O'},
1770 {"pool", no_argument, 0, 'p'},
1771 {"quiet", no_argument, 0, 'q'},
1772 {"recursive", no_argument, 0, 'r'},
1773 {"raw", no_argument, 0, 'R'},
1774 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1775 /* This formerly implied "--stripe-size", but was confusing
1776 * with "lfs find --size|-s", which means "file size", so use
1777 * the consistent "--stripe-size|-S" for all commands. */
1778 {"size", no_argument, 0, 's'},
1780 {"stripe-size", no_argument, 0, 'S'},
1781 {"stripe_size", no_argument, 0, 'S'},
1782 {"verbose", no_argument, 0, 'v'},
1787 while ((c = getopt_long(argc, argv, "cdDFghiLmMoO:pqrRsSv",
1788 long_opts, NULL)) != -1) {
1791 if (param->fp_obd_uuid) {
1793 "error: %s: only one obduuid allowed",
1797 param->fp_obd_uuid = (struct obd_uuid *)optarg;
1803 param->fp_max_depth = 0;
1806 param->fp_get_default_lmv = 1;
1809 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1810 param->fp_verbose |= VERBOSE_DFID;
1811 param->fp_max_depth = 0;
1815 param->fp_recursive = 1;
1818 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
1821 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1822 if (strcmp(argv[optind - 1], "--count") == 0)
1823 fprintf(stderr, "warning: '--count' deprecated,"
1824 " use '--stripe-count' instead\n");
1826 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1827 param->fp_verbose |= VERBOSE_COUNT;
1828 param->fp_max_depth = 0;
1831 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1833 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1834 fprintf(stderr, "warning: '--size|-s' deprecated, "
1835 "use '--stripe-size|-S' instead\n");
1837 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1839 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1840 param->fp_verbose |= VERBOSE_SIZE;
1841 param->fp_max_depth = 0;
1844 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1846 fprintf(stderr, "warning: '--offset|-o' deprecated, "
1847 "use '--stripe-index|-i' instead\n");
1850 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1851 if (strcmp(argv[optind - 1], "--index") == 0)
1852 fprintf(stderr, "warning: '--index' deprecated"
1853 ", use '--stripe-index' instead\n");
1855 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1856 param->fp_verbose |= VERBOSE_OFFSET;
1857 param->fp_max_depth = 0;
1861 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1862 param->fp_verbose |= VERBOSE_POOL;
1863 param->fp_max_depth = 0;
1867 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1868 param->fp_verbose |= VERBOSE_GENERATION;
1869 param->fp_max_depth = 0;
1873 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1874 param->fp_verbose |= VERBOSE_LAYOUT;
1875 param->fp_max_depth = 0;
1878 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1880 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
1881 fprintf(stderr, "warning: '-M' deprecated"
1882 ", use '-m' instead\n");
1886 if (!(param->fp_verbose & VERBOSE_DETAIL))
1887 param->fp_max_depth = 0;
1888 param->fp_verbose |= VERBOSE_MDTINDEX;
1901 if (param->fp_recursive)
1902 param->fp_max_depth = -1;
1904 if (!param->fp_verbose)
1905 param->fp_verbose = VERBOSE_DEFAULT;
1906 if (param->fp_quiet)
1907 param->fp_verbose = VERBOSE_OBJID;
1910 rc = llapi_getstripe(argv[optind], param);
1911 } while (++optind < argc && !rc);
1914 fprintf(stderr, "error: %s failed for %s.\n",
1915 argv[0], argv[optind - 1]);
1919 static int lfs_tgts(int argc, char **argv)
1921 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1922 struct find_param param;
1923 int index = 0, rc=0;
1928 if (argc == 2 && !realpath(argv[1], path)) {
1930 fprintf(stderr, "error: invalid path '%s': %s\n",
1931 argv[1], strerror(-rc));
1935 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1936 /* Check if we have a mount point */
1937 if (mntdir[0] == '\0')
1940 memset(¶m, 0, sizeof(param));
1941 if (!strcmp(argv[0], "mdts"))
1942 param.fp_get_lmv = 1;
1944 rc = llapi_ostlist(mntdir, ¶m);
1946 fprintf(stderr, "error: %s: failed on %s\n",
1949 if (path[0] != '\0')
1951 memset(mntdir, 0, PATH_MAX);
1957 static int lfs_getstripe(int argc, char **argv)
1959 struct find_param param = { 0 };
1961 param.fp_max_depth = 1;
1962 return lfs_getstripe_internal(argc, argv, ¶m);
1966 static int lfs_getdirstripe(int argc, char **argv)
1968 struct find_param param = { 0 };
1969 struct option long_opts[] = {
1970 {"mdt-count", no_argument, 0, 'c'},
1971 {"mdt-index", no_argument, 0, 'i'},
1972 {"recursive", no_argument, 0, 'r'},
1973 {"mdt-hash", no_argument, 0, 't'},
1974 {"default", no_argument, 0, 'D'},
1975 {"obd", required_argument, 0, 'O'},
1980 param.fp_get_lmv = 1;
1982 while ((c = getopt_long(argc, argv, "cirtDO:", long_opts, NULL)) != -1)
1986 if (param.fp_obd_uuid) {
1988 "error: %s: only one obduuid allowed",
1992 param.fp_obd_uuid = (struct obd_uuid *)optarg;
1995 param.fp_verbose |= VERBOSE_COUNT;
1998 param.fp_verbose |= VERBOSE_OFFSET;
2001 param.fp_verbose |= VERBOSE_HASH_TYPE;
2004 param.fp_get_default_lmv = 1;
2007 param.fp_recursive = 1;
2017 if (param.fp_recursive)
2018 param.fp_max_depth = -1;
2020 if (!param.fp_verbose)
2021 param.fp_verbose = VERBOSE_DEFAULT;
2024 rc = llapi_getstripe(argv[optind], ¶m);
2025 } while (++optind < argc && !rc);
2028 fprintf(stderr, "error: %s failed for %s.\n",
2029 argv[0], argv[optind - 1]);
2034 static int lfs_setdirstripe(int argc, char **argv)
2038 unsigned int stripe_offset = -1;
2039 unsigned int stripe_count = 1;
2040 enum lmv_hash_type hash_type;
2043 char *stripe_offset_opt = NULL;
2044 char *stripe_count_opt = NULL;
2045 char *stripe_hash_opt = NULL;
2046 char *mode_opt = NULL;
2047 bool default_stripe = false;
2048 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2049 mode_t previous_mode = 0;
2050 bool delete = false;
2052 struct option long_opts[] = {
2053 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2054 {"count", required_argument, 0, 'c'},
2056 {"mdt-count", required_argument, 0, 'c'},
2057 {"delete", no_argument, 0, 'd'},
2058 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2059 {"index", required_argument, 0, 'i'},
2061 {"mdt-index", required_argument, 0, 'i'},
2062 {"mode", required_argument, 0, 'm'},
2063 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2064 {"hash-type", required_argument, 0, 't'},
2066 {"mdt-hash", required_argument, 0, 't'},
2067 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2068 {"default_stripe", no_argument, 0, 'D'},
2070 {"default", no_argument, 0, 'D'},
2074 while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
2081 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2082 if (strcmp(argv[optind - 1], "--count") == 0)
2083 fprintf(stderr, "warning: '--count' deprecated"
2084 ", use '--mdt-count' instead\n");
2086 stripe_count_opt = optarg;
2090 default_stripe = true;
2093 default_stripe = true;
2096 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2097 if (strcmp(argv[optind - 1], "--index") == 0)
2098 fprintf(stderr, "warning: '--index' deprecated"
2099 ", use '--mdt-index' instead\n");
2101 stripe_offset_opt = optarg;
2107 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2108 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2109 fprintf(stderr, "warning: '--hash-type' "
2110 "deprecated, use '--mdt-hash' "
2113 stripe_hash_opt = optarg;
2116 fprintf(stderr, "error: %s: option '%s' "
2118 argv[0], argv[optind - 1]);
2123 if (optind == argc) {
2124 fprintf(stderr, "error: %s: missing dirname\n",
2129 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2130 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2135 if (stripe_offset_opt != NULL) {
2136 /* get the stripe offset */
2137 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2139 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2140 argv[0], stripe_offset_opt);
2146 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2147 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2148 " or -i options.\n", argv[0]);
2156 if (mode_opt != NULL) {
2157 mode = strtoul(mode_opt, &end, 8);
2159 fprintf(stderr, "error: %s: bad mode '%s'\n",
2163 previous_mode = umask(0);
2166 if (stripe_hash_opt == NULL) {
2167 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2171 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
2172 if (strcmp(stripe_hash_opt, mdt_hash_name[i]) == 0)
2175 if (i == LMV_HASH_TYPE_MAX) {
2177 "error: %s: bad stripe hash type '%s'\n",
2178 argv[0], stripe_hash_opt);
2185 /* get the stripe count */
2186 if (stripe_count_opt != NULL) {
2187 stripe_count = strtoul(stripe_count_opt, &end, 0);
2189 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2190 argv[0], stripe_count_opt);
2195 dname = argv[optind];
2197 if (default_stripe) {
2198 result = llapi_dir_set_default_lmv_stripe(dname,
2199 stripe_offset, stripe_count,
2202 result = llapi_dir_create_pool(dname, mode,
2204 stripe_count, hash_type,
2209 fprintf(stderr, "error: %s: create stripe dir '%s' "
2210 "failed\n", argv[0], dname);
2213 dname = argv[++optind];
2214 } while (dname != NULL);
2216 if (mode_opt != NULL)
2217 umask(previous_mode);
2223 static int lfs_rmentry(int argc, char **argv)
2230 fprintf(stderr, "error: %s: missing dirname\n",
2236 dname = argv[index];
2237 while (dname != NULL) {
2238 result = llapi_direntry_remove(dname);
2240 fprintf(stderr, "error: %s: remove dir entry '%s' "
2241 "failed\n", argv[0], dname);
2244 dname = argv[++index];
2249 static int lfs_mv(int argc, char **argv)
2251 struct find_param param = {
2258 struct option long_opts[] = {
2259 {"mdt-index", required_argument, 0, 'M'},
2260 {"verbose", no_argument, 0, 'v'},
2264 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2267 param.fp_mdt_index = strtoul(optarg, &end, 0);
2269 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2276 param.fp_verbose = VERBOSE_DETAIL;
2280 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2281 argv[0], argv[optind - 1]);
2286 if (param.fp_mdt_index == -1) {
2287 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2291 if (optind >= argc) {
2292 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2296 param.fp_migrate = 1;
2297 rc = llapi_migrate_mdt(argv[optind], ¶m);
2299 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2300 argv[0], argv[optind], param.fp_mdt_index,
2305 static int lfs_osts(int argc, char **argv)
2307 return lfs_tgts(argc, argv);
2310 static int lfs_mdts(int argc, char **argv)
2312 return lfs_tgts(argc, argv);
2315 #define COOK(value) \
2318 while (value > 1024) { \
2326 #define CDF "%11llu"
2327 #define HDF "%8.1f%c"
2332 MNTDF_INODES = 0x0001,
2333 MNTDF_COOKED = 0x0002,
2334 MNTDF_LAZY = 0x0004,
2335 MNTDF_VERBOSE = 0x0008,
2338 static int showdf(char *mntdir, struct obd_statfs *stat,
2339 char *uuid, enum mntdf_flags flags,
2340 char *type, int index, int rc)
2342 long long avail, used, total;
2344 char *suffix = "KMGTPEZY";
2345 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2346 char tbuf[3 * sizeof(__u64)];
2347 char ubuf[3 * sizeof(__u64)];
2348 char abuf[3 * sizeof(__u64)];
2349 char rbuf[3 * sizeof(__u64)];
2356 if (flags & MNTDF_INODES) {
2357 avail = stat->os_ffree;
2358 used = stat->os_files - stat->os_ffree;
2359 total = stat->os_files;
2361 int shift = flags & MNTDF_COOKED ? 0 : 10;
2363 avail = (stat->os_bavail * stat->os_bsize) >> shift;
2364 used = ((stat->os_blocks - stat->os_bfree) *
2365 stat->os_bsize) >> shift;
2366 total = (stat->os_blocks * stat->os_bsize) >> shift;
2369 if ((used + avail) > 0)
2370 ratio = (double)used / (double)(used + avail);
2372 if (flags & MNTDF_COOKED) {
2376 cook_val = (double)total;
2379 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
2382 snprintf(tbuf, sizeof(tbuf), CDF, total);
2384 cook_val = (double)used;
2387 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
2390 snprintf(ubuf, sizeof(ubuf), CDF, used);
2392 cook_val = (double)avail;
2395 snprintf(abuf, sizeof(abuf), HDF, cook_val,
2398 snprintf(abuf, sizeof(abuf), CDF, avail);
2400 snprintf(tbuf, sizeof(tbuf), CDF, total);
2401 snprintf(ubuf, sizeof(tbuf), CDF, used);
2402 snprintf(abuf, sizeof(tbuf), CDF, avail);
2405 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2406 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2407 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2409 printf("[%s:%d]\n", type, index);
2415 printf(UUF": inactive device\n", uuid);
2418 printf(UUF": %s\n", uuid, strerror(-rc));
2425 struct ll_stat_type {
2430 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
2432 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2433 struct obd_uuid uuid_buf;
2434 char *poolname = NULL;
2435 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2436 { LL_STATFS_LOV, "OST" },
2438 struct ll_stat_type *tp;
2439 __u64 ost_ffree = 0;
2447 poolname = strchr(pool, '.');
2448 if (poolname != NULL) {
2449 if (strncmp(fsname, pool, strlen(fsname))) {
2450 fprintf(stderr, "filesystem name incorrect\n");
2458 fd = open(mntdir, O_RDONLY);
2461 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
2466 if (flags & MNTDF_INODES)
2467 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2468 "UUID", "Inodes", "IUsed", "IFree",
2469 "IUse%", "Mounted on");
2471 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2472 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
2473 "Used", "Available", "Use%", "Mounted on");
2475 for (tp = types; tp->st_name != NULL; tp++) {
2476 for (index = 0; ; index++) {
2477 memset(&stat_buf, 0, sizeof(struct obd_statfs));
2478 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2479 type = flags & MNTDF_LAZY ?
2480 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2481 rc2 = llapi_obd_fstatfs(fd, type, index,
2482 &stat_buf, &uuid_buf);
2487 if (rc2 == -ENODATA) { /* Inactive device, OK. */
2488 if (!(flags & MNTDF_VERBOSE))
2490 } else if (rc2 < 0 && rc == 0) {
2494 if (poolname && tp->st_op == LL_STATFS_LOV &&
2495 llapi_search_ost(fsname, poolname,
2496 obd_uuid2str(&uuid_buf)) != 1)
2499 /* the llapi_obd_statfs() call may have returned with
2500 * an error, but if it filled in uuid_buf we will at
2501 * lease use that to print out a message for that OBD.
2502 * If we didn't get anything in the uuid_buf, then fill
2503 * it in so that we can print an error message. */
2504 if (uuid_buf.uuid[0] == '\0')
2505 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
2506 "%s%04x", tp->st_name, index);
2507 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2508 flags, tp->st_name, index, rc2);
2511 if (tp->st_op == LL_STATFS_LMV) {
2512 sum.os_ffree += stat_buf.os_ffree;
2513 sum.os_files += stat_buf.os_files;
2514 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2515 sum.os_blocks += stat_buf.os_blocks *
2517 sum.os_bfree += stat_buf.os_bfree *
2519 sum.os_bavail += stat_buf.os_bavail *
2521 ost_ffree += stat_buf.os_ffree;
2529 /* If we don't have as many objects free on the OST as inodes
2530 * on the MDS, we reduce the total number of inodes to
2531 * compensate, so that the "inodes in use" number is correct.
2532 * Matches ll_statfs_internal() so the results are consistent. */
2533 if (ost_ffree < sum.os_ffree) {
2534 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2535 sum.os_ffree = ost_ffree;
2538 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
2544 static int lfs_df(int argc, char **argv)
2546 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2547 enum mntdf_flags flags = 0;
2548 int c, rc = 0, index = 0;
2549 char fsname[PATH_MAX] = "", *pool_name = NULL;
2550 struct option long_opts[] = {
2551 {"human-readable", 0, 0, 'h'},
2552 {"inodes", 0, 0, 'i'},
2553 {"lazy", 0, 0, 'l'},
2554 {"pool", required_argument, 0, 'p'},
2555 {"verbose", 0, 0, 'v'},
2559 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
2562 flags |= MNTDF_COOKED;
2565 flags |= MNTDF_INODES;
2568 flags |= MNTDF_LAZY;
2574 flags |= MNTDF_VERBOSE;
2580 if (optind < argc && !realpath(argv[optind], path)) {
2582 fprintf(stderr, "error: invalid path '%s': %s\n",
2583 argv[optind], strerror(-rc));
2587 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2588 /* Check if we have a mount point */
2589 if (mntdir[0] == '\0')
2592 rc = mntdf(mntdir, fsname, pool_name, flags);
2593 if (rc || path[0] != '\0')
2595 fsname[0] = '\0'; /* avoid matching in next loop */
2596 mntdir[0] = '\0'; /* avoid matching in next loop */
2602 static int lfs_getname(int argc, char **argv)
2604 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2605 int rc = 0, index = 0, c;
2606 char buf[sizeof(struct obd_uuid)];
2608 while ((c = getopt(argc, argv, "h")) != -1)
2611 if (optind == argc) { /* no paths specified, get all paths. */
2612 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2613 rc = llapi_getname(mntdir, buf, sizeof(buf));
2616 "cannot get name for `%s': %s\n",
2617 mntdir, strerror(-rc));
2621 printf("%s %s\n", buf, mntdir);
2623 path[0] = fsname[0] = mntdir[0] = 0;
2625 } else { /* paths specified, only attempt to search these. */
2626 for (; optind < argc; optind++) {
2627 rc = llapi_getname(argv[optind], buf, sizeof(buf));
2630 "cannot get name for `%s': %s\n",
2631 argv[optind], strerror(-rc));
2635 printf("%s %s\n", buf, argv[optind]);
2641 static int lfs_check(int argc, char **argv)
2644 char mntdir[PATH_MAX] = {'\0'};
2653 obd_types[0] = obd_type1;
2654 obd_types[1] = obd_type2;
2656 if (strcmp(argv[1], "osts") == 0) {
2657 strcpy(obd_types[0], "osc");
2658 } else if (strcmp(argv[1], "mds") == 0) {
2659 strcpy(obd_types[0], "mdc");
2660 } else if (strcmp(argv[1], "servers") == 0) {
2662 strcpy(obd_types[0], "osc");
2663 strcpy(obd_types[1], "mdc");
2665 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2670 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2671 if (rc < 0 || mntdir[0] == '\0') {
2672 fprintf(stderr, "No suitable Lustre mount found\n");
2676 rc = llapi_target_check(num_types, obd_types, mntdir);
2678 fprintf(stderr, "error: %s: %s status failed\n",
2685 static int lfs_join(int argc, char **argv)
2687 fprintf(stderr, "join two lustre files into one.\n"
2688 "obsolete, HEAD does not support it anymore.\n");
2692 #ifdef HAVE_SYS_QUOTA_H
2693 #define ARG2INT(nr, str, msg) \
2696 nr = strtol(str, &endp, 0); \
2698 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
2703 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2705 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2706 * returns the value or ULONG_MAX on integer overflow or incorrect format
2708 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2709 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2710 * 3. empty integer value is interpreted as 0
2712 static unsigned long str2sec(const char* timestr)
2714 const char spec[] = "smhdw";
2715 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2716 unsigned long val = 0;
2719 if (strpbrk(timestr, spec) == NULL) {
2720 /* no specifiers inside the time string,
2721 should treat it as an integer value */
2722 val = strtoul(timestr, &tail, 10);
2723 return *tail ? ULONG_MAX : val;
2726 /* format string is XXwXXdXXhXXmXXs */
2732 v = strtoul(timestr, &tail, 10);
2733 if (v == ULONG_MAX || *tail == '\0')
2734 /* value too large (ULONG_MAX or more)
2735 or missing specifier */
2738 ptr = strchr(spec, *tail);
2740 /* unknown specifier */
2745 /* check if product will overflow the type */
2746 if (!(v < ULONG_MAX / mult[ind]))
2749 ADD_OVERFLOW(val, mult[ind] * v);
2750 if (val == ULONG_MAX)
2762 #define ARG2ULL(nr, str, def_units) \
2764 unsigned long long limit, units = def_units; \
2767 rc = llapi_parse_size(str, &limit, &units, 1); \
2769 fprintf(stderr, "error: bad limit value %s\n", str); \
2775 static inline int has_times_option(int argc, char **argv)
2779 for (i = 1; i < argc; i++)
2780 if (!strcmp(argv[i], "-t"))
2786 int lfs_setquota_times(int argc, char **argv)
2789 struct if_quotactl qctl;
2790 char *mnt, *obd_type = (char *)qctl.obd_type;
2791 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2792 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2793 struct option long_opts[] = {
2794 {"block-grace", required_argument, 0, 'b'},
2795 {"group", no_argument, 0, 'g'},
2796 {"inode-grace", required_argument, 0, 'i'},
2797 {"times", no_argument, 0, 't'},
2798 {"user", no_argument, 0, 'u'},
2802 memset(&qctl, 0, sizeof(qctl));
2803 qctl.qc_cmd = LUSTRE_Q_SETINFO;
2804 qctl.qc_type = UGQUOTA;
2806 while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2810 if (qctl.qc_type != UGQUOTA) {
2811 fprintf(stderr, "error: -u and -g can't be used "
2812 "more than once\n");
2815 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2818 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2819 fprintf(stderr, "error: bad block-grace: %s\n",
2823 dqb->dqb_valid |= QIF_BTIME;
2826 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2827 fprintf(stderr, "error: bad inode-grace: %s\n",
2831 dqb->dqb_valid |= QIF_ITIME;
2833 case 't': /* Yes, of course! */
2835 default: /* getopt prints error message for us when opterr != 0 */
2840 if (qctl.qc_type == UGQUOTA) {
2841 fprintf(stderr, "error: neither -u nor -g specified\n");
2845 if (optind != argc - 1) {
2846 fprintf(stderr, "error: unexpected parameters encountered\n");
2851 rc = llapi_quotactl(mnt, &qctl);
2854 fprintf(stderr, "%s %s ", obd_type,
2855 obd_uuid2str(&qctl.obd_uuid));
2856 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2863 #define BSLIMIT (1 << 0)
2864 #define BHLIMIT (1 << 1)
2865 #define ISLIMIT (1 << 2)
2866 #define IHLIMIT (1 << 3)
2868 int lfs_setquota(int argc, char **argv)
2871 struct if_quotactl qctl;
2872 char *mnt, *obd_type = (char *)qctl.obd_type;
2873 struct obd_dqblk *dqb = &qctl.qc_dqblk;
2874 struct option long_opts[] = {
2875 {"block-softlimit", required_argument, 0, 'b'},
2876 {"block-hardlimit", required_argument, 0, 'B'},
2877 {"group", required_argument, 0, 'g'},
2878 {"inode-softlimit", required_argument, 0, 'i'},
2879 {"inode-hardlimit", required_argument, 0, 'I'},
2880 {"user", required_argument, 0, 'u'},
2883 unsigned limit_mask = 0;
2886 if (has_times_option(argc, argv))
2887 return lfs_setquota_times(argc, argv);
2889 memset(&qctl, 0, sizeof(qctl));
2890 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
2891 qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2892 * so it can be used as a marker that qc_type
2893 * isn't reinitialized from command line */
2895 while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2899 if (qctl.qc_type != UGQUOTA) {
2900 fprintf(stderr, "error: -u and -g can't be used"
2901 " more than once\n");
2904 qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2905 rc = name2id(&qctl.qc_id, optarg,
2906 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2908 qctl.qc_id = strtoul(optarg, &endptr, 10);
2909 if (*endptr != '\0') {
2910 fprintf(stderr, "error: can't find id "
2911 "for name %s\n", optarg);
2917 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2918 dqb->dqb_bsoftlimit >>= 10;
2919 limit_mask |= BSLIMIT;
2920 if (dqb->dqb_bsoftlimit &&
2921 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2922 fprintf(stderr, "warning: block softlimit is "
2923 "smaller than the miminal qunit size, "
2924 "please see the help of setquota or "
2925 "Lustre manual for details.\n");
2928 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2929 dqb->dqb_bhardlimit >>= 10;
2930 limit_mask |= BHLIMIT;
2931 if (dqb->dqb_bhardlimit &&
2932 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2933 fprintf(stderr, "warning: block hardlimit is "
2934 "smaller than the miminal qunit size, "
2935 "please see the help of setquota or "
2936 "Lustre manual for details.\n");
2939 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2940 limit_mask |= ISLIMIT;
2941 if (dqb->dqb_isoftlimit &&
2942 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2943 fprintf(stderr, "warning: inode softlimit is "
2944 "smaller than the miminal qunit size, "
2945 "please see the help of setquota or "
2946 "Lustre manual for details.\n");
2949 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2950 limit_mask |= IHLIMIT;
2951 if (dqb->dqb_ihardlimit &&
2952 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2953 fprintf(stderr, "warning: inode hardlimit is "
2954 "smaller than the miminal qunit size, "
2955 "please see the help of setquota or "
2956 "Lustre manual for details.\n");
2958 default: /* getopt prints error message for us when opterr != 0 */
2963 if (qctl.qc_type == UGQUOTA) {
2964 fprintf(stderr, "error: neither -u nor -g was specified\n");
2968 if (limit_mask == 0) {
2969 fprintf(stderr, "error: at least one limit must be specified\n");
2973 if (optind != argc - 1) {
2974 fprintf(stderr, "error: unexpected parameters encountered\n");
2980 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2981 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2982 /* sigh, we can't just set blimits/ilimits */
2983 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
2984 .qc_type = qctl.qc_type,
2985 .qc_id = qctl.qc_id};
2987 rc = llapi_quotactl(mnt, &tmp_qctl);
2989 fprintf(stderr, "error: setquota failed while retrieving"
2990 " current quota settings (%s)\n",
2995 if (!(limit_mask & BHLIMIT))
2996 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2997 if (!(limit_mask & BSLIMIT))
2998 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2999 if (!(limit_mask & IHLIMIT))
3000 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3001 if (!(limit_mask & ISLIMIT))
3002 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3004 /* Keep grace times if we have got no softlimit arguments */
3005 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3006 dqb->dqb_valid |= QIF_BTIME;
3007 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3010 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3011 dqb->dqb_valid |= QIF_ITIME;
3012 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3016 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3017 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3019 rc = llapi_quotactl(mnt, &qctl);
3022 fprintf(stderr, "%s %s ", obd_type,
3023 obd_uuid2str(&qctl.obd_uuid));
3024 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3031 static inline char *type2name(int check_type)
3033 if (check_type == USRQUOTA)
3035 else if (check_type == GRPQUOTA)
3041 /* Converts seconds value into format string
3042 * result is returned in buf
3044 * 1. result is in descenting order: 1w2d3h4m5s
3045 * 2. zero fields are not filled (except for p. 3): 5d1s
3046 * 3. zero seconds value is presented as "0s"
3048 static char * __sec2str(time_t seconds, char *buf)
3050 const char spec[] = "smhdw";
3051 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3056 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3057 c = seconds / mult[i];
3059 if (c > 0 || (i == 0 && buf == tail))
3060 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3068 static void sec2str(time_t seconds, char *buf, int rc)
3075 tail = __sec2str(seconds, tail);
3077 if (rc && tail - buf < 39) {
3083 static void diff2str(time_t seconds, char *buf, time_t now)
3089 if (seconds <= now) {
3090 strcpy(buf, "none");
3093 __sec2str(seconds - now, buf);
3096 static void print_quota_title(char *name, struct if_quotactl *qctl,
3097 bool human_readable)
3099 printf("Disk quotas for %s %s (%cid %u):\n",
3100 type2name(qctl->qc_type), name,
3101 *type2name(qctl->qc_type), qctl->qc_id);
3102 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3103 "Filesystem", human_readable ? "used" : "kbytes",
3104 "quota", "limit", "grace",
3105 "files", "quota", "limit", "grace");
3108 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3111 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3114 snprintf(buf, buflen, "%5.4gP",
3115 (double)num / ((__u64)1 << 40));
3117 snprintf(buf, buflen, "%5.4gT",
3118 (double)num / (1 << 30));
3120 snprintf(buf, buflen, "%5.4gG",
3121 (double)num / (1 << 20));
3123 snprintf(buf, buflen, "%5.4gM",
3124 (double)num / (1 << 10));
3126 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3130 #define STRBUF_LEN 32
3131 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3138 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3139 int bover = 0, iover = 0;
3140 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3141 char numbuf[3][STRBUF_LEN];
3143 char strbuf[STRBUF_LEN];
3145 if (dqb->dqb_bhardlimit &&
3146 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3148 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3149 if (dqb->dqb_btime > now) {
3156 if (dqb->dqb_ihardlimit &&
3157 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3159 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3160 if (dqb->dqb_itime > now) {
3168 if (strlen(mnt) > 15)
3169 printf("%s\n%15s", mnt, "");
3171 printf("%15s", mnt);
3174 diff2str(dqb->dqb_btime, timebuf, now);
3176 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3177 strbuf, sizeof(strbuf), h);
3178 if (rc == -EREMOTEIO)
3179 sprintf(numbuf[0], "%s*", strbuf);
3181 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3182 "%s" : "[%s]", strbuf);
3184 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3185 if (type == QC_GENERAL)
3186 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3187 "%s" : "[%s]", strbuf);
3189 sprintf(numbuf[1], "%s", "-");
3191 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3192 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3193 "%s" : "[%s]", strbuf);
3195 printf(" %7s%c %6s %7s %7s",
3196 numbuf[0], bover ? '*' : ' ', numbuf[1],
3197 numbuf[2], bover > 1 ? timebuf : "-");
3200 diff2str(dqb->dqb_itime, timebuf, now);
3202 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3203 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3205 if (type == QC_GENERAL)
3206 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3208 (uintmax_t)dqb->dqb_isoftlimit);
3210 sprintf(numbuf[1], "%s", "-");
3212 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3213 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3215 if (type != QC_OSTIDX)
3216 printf(" %7s%c %6s %7s %7s",
3217 numbuf[0], iover ? '*' : ' ', numbuf[1],
3218 numbuf[2], iover > 1 ? timebuf : "-");
3220 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3223 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3224 qctl->qc_cmd == Q_GETOINFO) {
3228 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3229 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3230 printf("Block grace time: %s; Inode grace time: %s\n",
3231 bgtimebuf, igtimebuf);
3235 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3236 bool h, __u64 *total)
3238 int rc = 0, rc1 = 0, count = 0;
3239 __u32 valid = qctl->qc_valid;
3241 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3243 fprintf(stderr, "can not get %s count: %s\n",
3244 is_mdt ? "mdt": "ost", strerror(-rc));
3248 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3249 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3250 rc = llapi_quotactl(mnt, qctl);
3252 /* It is remote client case. */
3253 if (-rc == EOPNOTSUPP) {
3260 fprintf(stderr, "quotactl %s%d failed.\n",
3261 is_mdt ? "mdt": "ost", qctl->qc_idx);
3265 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3266 qctl->qc_valid, 0, h);
3267 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3268 qctl->qc_dqblk.dqb_bhardlimit;
3271 qctl->qc_valid = valid;
3275 static int lfs_quota(int argc, char **argv)
3278 char *mnt, *name = NULL;
3279 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3280 .qc_type = UGQUOTA };
3281 char *obd_type = (char *)qctl.obd_type;
3282 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3283 int rc, rc1 = 0, rc2 = 0, rc3 = 0,
3284 verbose = 0, pass = 0, quiet = 0, inacc;
3286 __u32 valid = QC_GENERAL, idx = 0;
3287 __u64 total_ialloc = 0, total_balloc = 0;
3288 bool human_readable = false;
3290 while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
3293 if (qctl.qc_type != UGQUOTA) {
3294 fprintf(stderr, "error: use either -u or -g\n");
3297 qctl.qc_type = USRQUOTA;
3300 if (qctl.qc_type != UGQUOTA) {
3301 fprintf(stderr, "error: use either -u or -g\n");
3304 qctl.qc_type = GRPQUOTA;
3307 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3310 valid = qctl.qc_valid = QC_UUID;
3311 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3314 valid = qctl.qc_valid = QC_MDTIDX;
3315 idx = qctl.qc_idx = atoi(optarg);
3318 valid = qctl.qc_valid = QC_OSTIDX;
3319 idx = qctl.qc_idx = atoi(optarg);
3328 human_readable = true;
3331 fprintf(stderr, "error: %s: option '-%c' "
3332 "unrecognized\n", argv[0], c);
3337 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3338 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3339 optind == argc - 1) {
3341 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3342 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3343 qctl.qc_valid = valid;
3346 qctl.qc_type = USRQUOTA;
3347 qctl.qc_id = geteuid();
3349 qctl.qc_type = GRPQUOTA;
3350 qctl.qc_id = getegid();
3352 rc = id2name(&name, qctl.qc_id,
3353 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3356 /* lfs quota -u username /path/to/lustre/mount */
3357 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3358 /* options should be followed by u/g-name and mntpoint */
3359 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3360 fprintf(stderr, "error: missing quota argument(s)\n");
3364 name = argv[optind++];
3365 rc = name2id(&qctl.qc_id, name,
3366 (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3368 qctl.qc_id = strtoul(name, &endptr, 10);
3369 if (*endptr != '\0') {
3370 fprintf(stderr, "error: can't find id for name "
3375 } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3376 fprintf(stderr, "error: missing quota info argument(s)\n");
3382 rc1 = llapi_quotactl(mnt, &qctl);
3386 fprintf(stderr, "%s quotas are not enabled.\n",
3387 qctl.qc_type == USRQUOTA ? "user" : "group");
3390 fprintf(stderr, "Permission denied.\n");
3393 /* We already got error message. */
3396 fprintf(stderr, "Unexpected quotactl error: %s\n",
3401 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3402 print_quota_title(name, &qctl, human_readable);
3404 if (rc1 && *obd_type)
3405 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3407 if (qctl.qc_valid != QC_GENERAL)
3410 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3411 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3412 (QIF_LIMITS|QIF_USAGE));
3414 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3416 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3418 char strbuf[STRBUF_LEN];
3420 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3422 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3424 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
3426 printf("Total allocated inode limit: %ju, total "
3427 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
3431 if (rc1 || rc2 || rc3 || inacc)
3432 printf("Some errors happened when getting quota info. "
3433 "Some devices may be not working or deactivated. "
3434 "The data in \"[]\" is inaccurate.\n");
3442 #endif /* HAVE_SYS_QUOTA_H! */
3444 static int flushctx_ioctl(char *mp)
3448 fd = open(mp, O_RDONLY);
3450 fprintf(stderr, "flushctx: error open %s: %s\n",
3451 mp, strerror(errno));
3455 rc = ioctl(fd, LL_IOC_FLUSHCTX);
3457 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3458 mp, strerror(errno));
3464 static int lfs_flushctx(int argc, char **argv)
3466 int kdestroy = 0, c;
3467 char mntdir[PATH_MAX] = {'\0'};
3471 while ((c = getopt(argc, argv, "k")) != -1) {
3477 fprintf(stderr, "error: %s: option '-%c' "
3478 "unrecognized\n", argv[0], c);
3484 if ((rc = system("kdestroy > /dev/null")) != 0) {
3485 rc = WEXITSTATUS(rc);
3486 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3490 if (optind >= argc) {
3491 /* flush for all mounted lustre fs. */
3492 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3493 /* Check if we have a mount point */
3494 if (mntdir[0] == '\0')
3497 if (flushctx_ioctl(mntdir))
3500 mntdir[0] = '\0'; /* avoid matching in next loop */
3503 /* flush fs as specified */
3504 while (optind < argc) {
3505 if (flushctx_ioctl(argv[optind++]))
3512 static int lfs_lsetfacl(int argc, char **argv)
3514 fprintf(stderr, "local client sets facl for remote client.\n"
3515 "obsolete, does not support it anymore.\n");
3519 static int lfs_lgetfacl(int argc, char **argv)
3521 fprintf(stderr, "local client gets facl for remote client.\n"
3522 "obsolete, does not support it anymore.\n");
3526 static int lfs_rsetfacl(int argc, char **argv)
3528 fprintf(stderr, "remote client sets facl for remote client.\n"
3529 "obsolete, does not support it anymore.\n");
3533 static int lfs_rgetfacl(int argc, char **argv)
3535 fprintf(stderr, "remote client gets facl for remote client.\n"
3536 "obsolete, does not support it anymore.\n");
3540 static int lfs_cp(int argc, char **argv)
3542 fprintf(stderr, "remote client copy file(s).\n"
3543 "obsolete, does not support it anymore.\n");
3547 static int lfs_ls(int argc, char **argv)
3549 fprintf(stderr, "remote client lists directory contents.\n"
3550 "obsolete, does not support it anymore.\n");
3554 static int lfs_changelog(int argc, char **argv)
3556 void *changelog_priv;
3557 struct changelog_rec *rec;
3558 long long startrec = 0, endrec = 0;
3560 struct option long_opts[] = {
3561 {"follow", no_argument, 0, 'f'},
3564 char short_opts[] = "f";
3567 while ((rc = getopt_long(argc, argv, short_opts,
3568 long_opts, NULL)) != -1) {
3576 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3577 argv[0], argv[optind - 1]);
3584 mdd = argv[optind++];
3586 startrec = strtoll(argv[optind++], NULL, 10);
3588 endrec = strtoll(argv[optind++], NULL, 10);
3590 rc = llapi_changelog_start(&changelog_priv,
3591 CHANGELOG_FLAG_BLOCK |
3592 CHANGELOG_FLAG_JOBID |
3593 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3596 fprintf(stderr, "Can't start changelog: %s\n",
3597 strerror(errno = -rc));
3601 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3605 if (endrec && rec->cr_index > endrec) {
3606 llapi_changelog_free(&rec);
3609 if (rec->cr_index < startrec) {
3610 llapi_changelog_free(&rec);
3614 secs = rec->cr_time >> 30;
3615 gmtime_r(&secs, &ts);
3616 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3617 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
3618 changelog_type2str(rec->cr_type),
3619 ts.tm_hour, ts.tm_min, ts.tm_sec,
3620 (int)(rec->cr_time & ((1<<30) - 1)),
3621 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3622 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3624 if (rec->cr_flags & CLF_JOBID) {
3625 struct changelog_ext_jobid *jid =
3626 changelog_rec_jobid(rec);
3628 if (jid->cr_jobid[0] != '\0')
3629 printf(" j=%s", jid->cr_jobid);
3632 if (rec->cr_namelen)
3633 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3634 rec->cr_namelen, changelog_rec_name(rec));
3636 if (rec->cr_flags & CLF_RENAME) {
3637 struct changelog_ext_rename *rnm =
3638 changelog_rec_rename(rec);
3640 if (!fid_is_zero(&rnm->cr_sfid))
3641 printf(" s="DFID" sp="DFID" %.*s",
3642 PFID(&rnm->cr_sfid),
3643 PFID(&rnm->cr_spfid),
3644 (int)changelog_rec_snamelen(rec),
3645 changelog_rec_sname(rec));
3649 llapi_changelog_free(&rec);
3652 llapi_changelog_fini(&changelog_priv);
3655 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3657 return (rc == 1 ? 0 : rc);
3660 static int lfs_changelog_clear(int argc, char **argv)
3668 endrec = strtoll(argv[3], NULL, 10);
3670 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3672 fprintf(stderr, "%s error: %s\n", argv[0],
3673 strerror(errno = -rc));
3677 static int lfs_fid2path(int argc, char **argv)
3679 struct option long_opts[] = {
3680 {"cur", no_argument, 0, 'c'},
3681 {"link", required_argument, 0, 'l'},
3682 {"rec", required_argument, 0, 'r'},
3685 char short_opts[] = "cl:r:";
3686 char *device, *fid, *path;
3687 long long recno = -1;
3693 while ((rc = getopt_long(argc, argv, short_opts,
3694 long_opts, NULL)) != -1) {
3700 linkno = strtol(optarg, NULL, 10);
3703 recno = strtoll(optarg, NULL, 10);
3708 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3709 argv[0], argv[optind - 1]);
3717 device = argv[optind++];
3718 path = calloc(1, PATH_MAX);
3720 fprintf(stderr, "error: Not enough memory\n");
3725 while (optind < argc) {
3726 fid = argv[optind++];
3728 lnktmp = (linkno >= 0) ? linkno : 0;
3730 int oldtmp = lnktmp;
3731 long long rectmp = recno;
3733 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3736 fprintf(stderr, "%s: error on FID %s: %s\n",
3737 argv[0], fid, strerror(errno = -rc2));
3744 fprintf(stdout, "%lld ", rectmp);
3745 if (device[0] == '/') {
3746 fprintf(stdout, "%s", device);
3747 if (device[strlen(device) - 1] != '/')
3748 fprintf(stdout, "/");
3749 } else if (path[0] == '\0') {
3750 fprintf(stdout, "/");
3752 fprintf(stdout, "%s\n", path);
3755 /* specified linkno */
3757 if (oldtmp == lnktmp)
3767 static int lfs_path2fid(int argc, char **argv)
3769 struct option long_opts[] = {
3770 {"parents", no_argument, 0, 'p'},
3774 const char short_opts[] = "p";
3775 const char *sep = "";
3778 bool show_parents = false;
3780 while ((rc = getopt_long(argc, argv, short_opts,
3781 long_opts, NULL)) != -1) {
3784 show_parents = true;
3787 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3788 argv[0], argv[optind - 1]);
3793 if (optind > argc - 1)
3795 else if (optind < argc - 1)
3799 for (path = argv + optind; *path != NULL; path++) {
3801 if (!show_parents) {
3802 err = llapi_path2fid(*path, &fid);
3804 printf("%s%s"DFID"\n",
3805 *sep != '\0' ? *path : "", sep,
3808 char name[NAME_MAX + 1];
3809 unsigned int linkno = 0;
3811 while ((err = llapi_path2parent(*path, linkno, &fid,
3812 name, sizeof(name))) == 0) {
3813 if (*sep != '\0' && linkno == 0)
3814 printf("%s%s", *path, sep);
3816 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3821 /* err == -ENODATA is end-of-loop */
3822 if (linkno > 0 && err == -ENODATA) {
3829 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3830 argv[0], show_parents ? "parent " : "", *path,
3842 static int lfs_data_version(int argc, char **argv)
3849 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3854 while ((c = getopt(argc, argv, "nrw")) != -1) {
3857 data_version_flags = 0;
3860 data_version_flags |= LL_DV_RD_FLUSH;
3863 data_version_flags |= LL_DV_WR_FLUSH;
3872 path = argv[optind];
3873 fd = open(path, O_RDONLY);
3875 err(errno, "cannot open file %s", path);
3877 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3879 err(errno, "cannot get version for %s", path);
3881 printf("%ju" "\n", (uintmax_t)data_version);
3887 static int lfs_hsm_state(int argc, char **argv)
3892 struct hsm_user_state hus;
3900 rc = llapi_hsm_state_get(path, &hus);
3902 fprintf(stderr, "can't get hsm state for %s: %s\n",
3903 path, strerror(errno = -rc));
3907 /* Display path name and status flags */
3908 printf("%s: (0x%08x)", path, hus.hus_states);
3910 if (hus.hus_states & HS_RELEASED)
3911 printf(" released");
3912 if (hus.hus_states & HS_EXISTS)
3914 if (hus.hus_states & HS_DIRTY)
3916 if (hus.hus_states & HS_ARCHIVED)
3917 printf(" archived");
3918 /* Display user-settable flags */
3919 if (hus.hus_states & HS_NORELEASE)
3920 printf(" never_release");
3921 if (hus.hus_states & HS_NOARCHIVE)
3922 printf(" never_archive");
3923 if (hus.hus_states & HS_LOST)
3924 printf(" lost_from_hsm");
3926 if (hus.hus_archive_id != 0)
3927 printf(", archive_id:%d", hus.hus_archive_id);
3930 } while (++i < argc);
3935 #define LFS_HSM_SET 0
3936 #define LFS_HSM_CLEAR 1
3939 * Generic function to set or clear HSM flags.
3940 * Used by hsm_set and hsm_clear.
3942 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3944 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3946 struct option long_opts[] = {
3947 {"lost", 0, 0, 'l'},
3948 {"norelease", 0, 0, 'r'},
3949 {"noarchive", 0, 0, 'a'},
3950 {"archived", 0, 0, 'A'},
3951 {"dirty", 0, 0, 'd'},
3952 {"exists", 0, 0, 'e'},
3955 char short_opts[] = "lraAde";
3963 while ((c = getopt_long(argc, argv, short_opts,
3964 long_opts, NULL)) != -1) {
3970 mask |= HS_NOARCHIVE;
3973 mask |= HS_ARCHIVED;
3976 mask |= HS_NORELEASE;
3987 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3988 argv[0], argv[optind - 1]);
3993 /* User should have specified a flag */
3997 while (optind < argc) {
3999 path = argv[optind];
4001 /* If mode == 0, this means we apply the mask. */
4002 if (mode == LFS_HSM_SET)
4003 rc = llapi_hsm_state_set(path, mask, 0, 0);
4005 rc = llapi_hsm_state_set(path, 0, mask, 0);
4008 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4009 path, strerror(errno = -rc));
4018 static int lfs_hsm_action(int argc, char **argv)
4023 struct hsm_current_action hca;
4024 struct hsm_extent he;
4025 enum hsm_user_action hua;
4026 enum hsm_progress_states hps;
4034 rc = llapi_hsm_current_action(path, &hca);
4036 fprintf(stderr, "can't get hsm action for %s: %s\n",
4037 path, strerror(errno = -rc));
4040 he = hca.hca_location;
4041 hua = hca.hca_action;
4042 hps = hca.hca_state;
4044 printf("%s: %s", path, hsm_user_action2name(hua));
4046 /* Skip file without action */
4047 if (hca.hca_action == HUA_NONE) {
4052 printf(" %s ", hsm_progress_state2name(hps));
4054 if ((hps == HPS_RUNNING) &&
4055 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4056 printf("(%llu bytes moved)\n",
4057 (unsigned long long)he.length);
4058 else if ((he.offset + he.length) == LUSTRE_EOF)
4059 printf("(from %llu to EOF)\n",
4060 (unsigned long long)he.offset);
4062 printf("(from %llu to %llu)\n",
4063 (unsigned long long)he.offset,
4064 (unsigned long long)(he.offset + he.length));
4066 } while (++i < argc);
4071 static int lfs_hsm_set(int argc, char **argv)
4073 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4076 static int lfs_hsm_clear(int argc, char **argv)
4078 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4082 * Check file state and return its fid, to be used by lfs_hsm_request().
4084 * \param[in] file Path to file to check
4085 * \param[in,out] fid Pointer to allocated lu_fid struct.
4086 * \param[in,out] last_dev Pointer to last device id used.
4088 * \return 0 on success.
4090 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4096 rc = lstat(file, &st);
4098 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4101 /* Checking for regular file as archiving as posix copytool
4102 * rejects archiving files other than regular files
4104 if (!S_ISREG(st.st_mode)) {
4105 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4108 /* A request should be ... */
4109 if (*last_dev != st.st_dev && *last_dev != 0) {
4110 fprintf(stderr, "All files should be "
4111 "on the same filesystem: %s\n", file);
4114 *last_dev = st.st_dev;
4116 rc = llapi_path2fid(file, fid);
4118 fprintf(stderr, "Cannot read FID of %s: %s\n",
4119 file, strerror(-rc));
4125 /* Fill an HSM HUR item with a given file name.
4127 * If mntpath is set, then the filename is actually a FID, and no
4128 * lookup on the filesystem will be performed.
4130 * \param[in] hur the user request to fill
4131 * \param[in] idx index of the item inside the HUR to fill
4132 * \param[in] mntpath mountpoint of Lustre
4133 * \param[in] fname filename (if mtnpath is NULL)
4134 * or FID (if mntpath is set)
4135 * \param[in] last_dev pointer to last device id used
4137 * \retval 0 on success
4138 * \retval CMD_HELP or a negative errno on error
4140 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4141 const char *mntpath, const char *fname,
4144 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4147 hui->hui_extent.length = -1;
4149 if (mntpath != NULL) {
4152 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4156 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4161 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4165 hur->hur_request.hr_itemcount++;
4170 static int lfs_hsm_request(int argc, char **argv, int action)
4172 struct option long_opts[] = {
4173 {"filelist", 1, 0, 'l'},
4174 {"data", 1, 0, 'D'},
4175 {"archive", 1, 0, 'a'},
4176 {"mntpath", 1, 0, 'm'},
4180 char short_opts[] = "l:D:a:m:";
4181 struct hsm_user_request *hur, *oldhur;
4186 char *filelist = NULL;
4187 char fullpath[PATH_MAX];
4188 char *opaque = NULL;
4192 int nbfile_alloc = 0;
4193 char *some_file = NULL;
4194 char *mntpath = NULL;
4200 while ((c = getopt_long(argc, argv, short_opts,
4201 long_opts, NULL)) != -1) {
4210 if (action != HUA_ARCHIVE &&
4211 action != HUA_REMOVE) {
4213 "error: -a is supported only "
4214 "when archiving or removing\n");
4217 archive_id = atoi(optarg);
4220 if (some_file == NULL) {
4222 some_file = strdup(optarg);
4228 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4229 argv[0], argv[optind - 1]);
4234 /* All remaining args are files, so we have at least nbfile */
4235 nbfile = argc - optind;
4237 if ((nbfile == 0) && (filelist == NULL))
4241 opaque_len = strlen(opaque);
4243 /* Alloc the request structure with enough place to store all files
4244 * from command line. */
4245 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4247 fprintf(stderr, "Cannot create the request: %s\n",
4251 nbfile_alloc = nbfile;
4253 hur->hur_request.hr_action = action;
4254 hur->hur_request.hr_archive_id = archive_id;
4255 hur->hur_request.hr_flags = 0;
4257 /* All remaining args are files, add them */
4258 if (nbfile != 0 && some_file == NULL)
4259 some_file = strdup(argv[optind]);
4261 for (i = 0; i < nbfile; i++) {
4262 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4268 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4270 /* If a filelist was specified, read the filelist from it. */
4271 if (filelist != NULL) {
4272 fp = fopen(filelist, "r");
4274 fprintf(stderr, "Cannot read the file list %s: %s\n",
4275 filelist, strerror(errno));
4280 while ((rc = getline(&line, &len, fp)) != -1) {
4281 /* If allocated buffer was too small, get something
4283 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4286 nbfile_alloc = nbfile_alloc * 2 + 1;
4288 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4291 fprintf(stderr, "hsm: cannot allocate "
4292 "the request: %s\n",
4299 size = hur_len(oldhur);
4301 fprintf(stderr, "hsm: cannot allocate "
4302 "%u files + %u bytes data\n",
4303 oldhur->hur_request.hr_itemcount,
4304 oldhur->hur_request.hr_data_len);
4311 memcpy(hur, oldhur, size);
4316 if (line[strlen(line) - 1] == '\n')
4317 line[strlen(line) - 1] = '\0';
4319 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4320 mntpath, line, &last_dev);
4326 if (some_file == NULL) {
4336 /* If a --data was used, add it to the request */
4337 hur->hur_request.hr_data_len = opaque_len;
4339 memcpy(hur_data(hur), opaque, opaque_len);
4341 /* Send the HSM request */
4342 if (realpath(some_file, fullpath) == NULL) {
4343 fprintf(stderr, "Could not find path '%s': %s\n",
4344 some_file, strerror(errno));
4346 rc = llapi_hsm_request(fullpath, hur);
4348 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4349 some_file, strerror(-rc));
4359 static int lfs_hsm_archive(int argc, char **argv)
4361 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4364 static int lfs_hsm_restore(int argc, char **argv)
4366 return lfs_hsm_request(argc, argv, HUA_RESTORE);
4369 static int lfs_hsm_release(int argc, char **argv)
4371 return lfs_hsm_request(argc, argv, HUA_RELEASE);
4374 static int lfs_hsm_remove(int argc, char **argv)
4376 return lfs_hsm_request(argc, argv, HUA_REMOVE);
4379 static int lfs_hsm_cancel(int argc, char **argv)
4381 return lfs_hsm_request(argc, argv, HUA_CANCEL);
4384 static int lfs_swap_layouts(int argc, char **argv)
4389 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4390 SWAP_LAYOUTS_KEEP_MTIME |
4391 SWAP_LAYOUTS_KEEP_ATIME);
4394 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
4396 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
4398 enum lu_ladvise_type advice;
4401 advice < ARRAY_SIZE(ladvise_names); advice++) {
4402 if (ladvise_names[advice] == NULL)
4404 if (strcmp(string, ladvise_names[advice]) == 0)
4408 return LU_LADVISE_INVALID;
4411 static int lfs_ladvise(int argc, char **argv)
4413 struct option long_opts[] = {
4414 {"advice", required_argument, 0, 'a'},
4415 {"background", no_argument, 0, 'b'},
4416 {"end", required_argument, 0, 'e'},
4417 {"start", required_argument, 0, 's'},
4418 {"length", required_argument, 0, 'l'},
4421 char short_opts[] = "a:be:l:s:";
4426 struct llapi_lu_ladvise advice;
4427 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
4428 unsigned long long start = 0;
4429 unsigned long long end = LUSTRE_EOF;
4430 unsigned long long length = 0;
4431 unsigned long long size_units;
4432 unsigned long long flags = 0;
4435 while ((c = getopt_long(argc, argv, short_opts,
4436 long_opts, NULL)) != -1) {
4439 advice_type = lfs_get_ladvice(optarg);
4440 if (advice_type == LU_LADVISE_INVALID) {
4441 fprintf(stderr, "%s: invalid advice type "
4442 "'%s'\n", argv[0], optarg);
4443 fprintf(stderr, "Valid types:");
4445 for (advice_type = 0;
4446 advice_type < ARRAY_SIZE(ladvise_names);
4448 if (ladvise_names[advice_type] == NULL)
4450 fprintf(stderr, " %s",
4451 ladvise_names[advice_type]);
4453 fprintf(stderr, "\n");
4463 rc = llapi_parse_size(optarg, &end,
4466 fprintf(stderr, "%s: bad end offset '%s'\n",
4473 rc = llapi_parse_size(optarg, &start,
4476 fprintf(stderr, "%s: bad start offset "
4477 "'%s'\n", argv[0], optarg);
4483 rc = llapi_parse_size(optarg, &length,
4486 fprintf(stderr, "%s: bad length '%s'\n",
4494 fprintf(stderr, "%s: option '%s' unrecognized\n",
4495 argv[0], argv[optind - 1]);
4500 if (advice_type == LU_LADVISE_INVALID) {
4501 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
4502 fprintf(stderr, "Valid types:");
4503 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
4505 if (ladvise_names[advice_type] == NULL)
4507 fprintf(stderr, " %s", ladvise_names[advice_type]);
4509 fprintf(stderr, "\n");
4513 if (argc <= optind) {
4514 fprintf(stderr, "%s: please give one or more file names\n",
4519 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
4520 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
4525 if (end == LUSTRE_EOF && length != 0)
4526 end = start + length;
4529 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
4530 argv[0], start, end);
4534 while (optind < argc) {
4537 path = argv[optind++];
4539 fd = open(path, O_RDONLY);
4541 fprintf(stderr, "%s: cannot open file '%s': %s\n",
4542 argv[0], path, strerror(errno));
4547 advice.lla_start = start;
4548 advice.lla_end = end;
4549 advice.lla_advice = advice_type;
4550 advice.lla_value1 = 0;
4551 advice.lla_value2 = 0;
4552 advice.lla_value3 = 0;
4553 advice.lla_value4 = 0;
4554 rc2 = llapi_ladvise(fd, flags, 1, &advice);
4557 fprintf(stderr, "%s: cannot give advice '%s' to file "
4558 "'%s': %s\n", argv[0],
4559 ladvise_names[advice_type],
4560 path, strerror(errno));
4563 if (rc == 0 && rc2 < 0)
4569 int main(int argc, char **argv)
4573 /* Ensure that liblustreapi constructor has run */
4574 if (!liblustreapi_initialized)
4575 fprintf(stderr, "liblustreapi was not properly initialized\n");
4579 Parser_init("lfs > ", cmdlist);
4581 progname = argv[0]; /* Used in error messages */
4583 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4585 rc = Parser_commands();
4588 return rc < 0 ? -rc : rc;
4591 #ifdef _LUSTRE_IDL_H_
4592 /* Everything we need here should be included by lustreapi.h. */
4593 # error "lfs should not depend on lustre_idl.h"
4594 #endif /* _LUSTRE_IDL_H_ */