4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
57 #include <sys/types.h>
64 #include <libcfs/util/string.h>
65 #include <libcfs/util/ioctl.h>
66 #include <libcfs/util/parser.h>
67 #include <lustre/lustreapi.h>
68 #include <lustre_ver.h>
69 #include <linux/lustre_param.h>
72 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
73 #endif /* !ARRAY_SIZE */
76 static int lfs_setstripe(int argc, char **argv);
77 static int lfs_find(int argc, char **argv);
78 static int lfs_getstripe(int argc, char **argv);
79 static int lfs_getdirstripe(int argc, char **argv);
80 static int lfs_setdirstripe(int argc, char **argv);
81 static int lfs_rmentry(int argc, char **argv);
82 static int lfs_osts(int argc, char **argv);
83 static int lfs_mdts(int argc, char **argv);
84 static int lfs_df(int argc, char **argv);
85 static int lfs_getname(int argc, char **argv);
86 static int lfs_check(int argc, char **argv);
87 #ifdef HAVE_SYS_QUOTA_H
88 static int lfs_setquota(int argc, char **argv);
89 static int lfs_quota(int argc, char **argv);
91 static int lfs_flushctx(int argc, char **argv);
92 static int lfs_cp(int argc, char **argv);
93 static int lfs_ls(int argc, char **argv);
94 static int lfs_poollist(int argc, char **argv);
95 static int lfs_changelog(int argc, char **argv);
96 static int lfs_changelog_clear(int argc, char **argv);
97 static int lfs_fid2path(int argc, char **argv);
98 static int lfs_path2fid(int argc, char **argv);
99 static int lfs_data_version(int argc, char **argv);
100 static int lfs_hsm_state(int argc, char **argv);
101 static int lfs_hsm_set(int argc, char **argv);
102 static int lfs_hsm_clear(int argc, char **argv);
103 static int lfs_hsm_action(int argc, char **argv);
104 static int lfs_hsm_archive(int argc, char **argv);
105 static int lfs_hsm_restore(int argc, char **argv);
106 static int lfs_hsm_release(int argc, char **argv);
107 static int lfs_hsm_remove(int argc, char **argv);
108 static int lfs_hsm_cancel(int argc, char **argv);
109 static int lfs_swap_layouts(int argc, char **argv);
110 static int lfs_mv(int argc, char **argv);
111 static int lfs_ladvise(int argc, char **argv);
112 static int lfs_list_commands(int argc, char **argv);
114 /* Setstripe and migrate share mostly the same parameters */
115 #define SSM_CMD_COMMON(cmd) \
116 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
117 " [--stripe-index|-i <start_ost_idx>]\n" \
118 " [--stripe-size|-S <stripe_size>]\n" \
119 " [--pool|-p <pool_name>]\n" \
120 " [--ost|-o <ost_indices>]\n" \
121 " [--component-end|-E <comp_end>]\n"
123 #define SSM_HELP_COMMON \
124 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
125 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
126 "\t respectively)\n" \
127 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
128 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
129 "\tpool_name: Name of OST pool to use (default none)\n" \
130 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
131 "\t Indices be specified in a format of:\n" \
132 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
134 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
135 "\t If --pool is set with --ost, then the OSTs\n" \
136 "\t must be the members of the pool." \
137 "\tcomp_end: Extent end of the component\n" \
138 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
139 "\t respectively, -1 for EOF), it must be aligned with\n"\
140 "\t the stripe_size\n"
142 #define SETSTRIPE_USAGE \
143 SSM_CMD_COMMON("setstripe") \
144 " <directory|filename>\n" \
147 #define MIGRATE_USAGE \
148 SSM_CMD_COMMON("migrate ") \
150 " [--non-block|-n]\n" \
154 "\tblock: Block file access during data migration (default)\n" \
155 "\tnon-block: Abort migrations if concurrent access is detected\n" \
157 #define SETDIRSTRIPE_USAGE \
158 " [--mdt-count|-c stripe_count>\n" \
159 " [--mdt-index|-i mdt_index]\n" \
160 " [--mdt-hash|-H mdt_hash]\n" \
161 " [--default|-D] [--mode|-m mode] <dir>\n" \
162 "\tstripe_count: stripe count of the striped directory\n" \
163 "\tmdt_index: MDT index of first stripe\n" \
164 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
165 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
166 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
167 "\tdefault_stripe: set default dirstripe of the directory\n" \
168 "\tmode: the mode of the directory\n"
170 static const char *progname;
171 static bool file_lease_supported = true;
173 /* all available commands */
174 command_t cmdlist[] = {
175 {"setstripe", lfs_setstripe, 0,
176 "Create a new file with a specific striping pattern or\n"
177 "set the default striping pattern on an existing directory or\n"
178 "delete the default striping pattern from an existing directory or\n"
179 "add layout component(s) to an existing composite file or\n"
180 "delete specified component(s) from an existing composite file\n\n"
181 "To delete default striping from an existing directory:\n"
182 "usage: setstripe -d <directory>\n"
184 "To delete component(s) from an existing composite file:\n"
185 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
186 " [--component-flags|-F <comp_flags>]\n"
188 "\tcomp_id: Unique component ID\n"
189 "\tcomp_flags: 'init' indicating all instantiated components\n"
190 "\t '^init' indicating all uninstantiated components\n"
191 "\t-I and -F can't be specified at the same time\n"
193 "To add component(s) to an existing composite file:\n"
194 SSM_CMD_COMMON("setstripe --component-add")
196 "To create a file with specified striping/composite layout:\n"
198 {"getstripe", lfs_getstripe, 0,
199 "To list the striping info for a given file or files in a\n"
200 "directory or recursively for all files in a directory tree.\n"
201 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
202 " [--stripe-count|-c] [--stripe-index|-i]\n"
203 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
204 " [--mdt|-m] [--recursive|-r] [--raw|-R] [--yaml|-y]\n"
205 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
206 " [--component-id[=comp_id]|-I[comp_id]]\n"
207 " [--component-flags[=comp_flags]]\n"
208 " [--component-count]\n"
209 " [--component-start[=[+-]comp_start]]\n"
210 " [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
211 " <directory|filename> ..."},
212 {"setdirstripe", lfs_setdirstripe, 0,
213 "To create a striped directory on a specified MDT. This can only\n"
214 "be done on MDT0 with the right of administrator.\n"
215 "usage: setdirstripe [OPTION] <directory>\n"
217 {"getdirstripe", lfs_getdirstripe, 0,
218 "To list the striping info for a given directory\n"
219 "or recursively for all directories in a directory tree.\n"
220 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
221 " [--mdt-index|-i] [--mdt-hash|-t]\n"
222 " [--recursive|-r] [--yaml|-y]\n"
223 " [--default|-D] <dir> ..."},
224 {"mkdir", lfs_setdirstripe, 0,
225 "To create a striped directory on a specified MDT. This can only\n"
226 "be done on MDT0 with the right of administrator.\n"
227 "usage: mkdir [OPTION] <directory>\n"
229 {"rm_entry", lfs_rmentry, 0,
230 "To remove the name entry of the remote directory. Note: This\n"
231 "command will only delete the name entry, i.e. the remote directory\n"
232 "will become inaccessable after this command. This can only be done\n"
233 "by the administrator\n"
234 "usage: rm_entry <dir>\n"},
235 {"pool_list", lfs_poollist, 0,
236 "List pools or pool OSTs\n"
237 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
238 {"find", lfs_find, 0,
239 "find files matching given attributes recursively in directory tree.\n"
240 "usage: find <directory|filename> ...\n"
241 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
242 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
243 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
244 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
245 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
246 " [[!] --stripe-count|-c [+-]<stripes>]\n"
247 " [[!] --stripe-index|-i <index,...>]\n"
248 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
249 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
250 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
251 " [[!] --projid <projid>]\n"
252 " [[!] --layout|-L released,raid0]\n"
253 " [[!] --component-count [+-]<comp_cnt>]\n"
254 " [[!] --component-start [+-]N[kMGTPE]]\n"
255 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
256 " [[!] --component-flags <comp_flags>]\n"
257 " [[!] --mdt-count|-T [+-]<stripes>]\n"
258 " [[!] --mdt-hash|-H <hashtype>\n"
259 "\t !: used before an option indicates 'NOT' requested attribute\n"
260 "\t -: used before a value indicates less than requested value\n"
261 "\t +: used before a value indicates more than requested value\n"
262 "\tmdt-hash: hash type of the striped directory.\n"
263 "\t fnv_1a_64 FNV-1a hash algorithm\n"
264 "\t all_char sum of characters % MDT_COUNT\n"},
265 {"check", lfs_check, 0,
266 "Display the status of MDS or OSTs (as specified in the command)\n"
267 "or all the servers (MDS and OSTs).\n"
268 "usage: check <osts|mds|servers>"},
269 {"osts", lfs_osts, 0, "list OSTs connected to client "
270 "[for specified path only]\n" "usage: osts [path]"},
271 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
272 "[for specified path only]\n" "usage: mdts [path]"},
274 "report filesystem disk space usage or inodes usage"
275 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
276 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
277 {"getname", lfs_getname, 0, "list instances and specified mount points "
278 "[for specified path only]\n"
279 "Usage: getname [-h]|[path ...] "},
280 #ifdef HAVE_SYS_QUOTA_H
281 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
282 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
283 " -b <block-softlimit> -B <block-hardlimit>\n"
284 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
285 " setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
286 " [--block-softlimit <block-softlimit>]\n"
287 " [--block-hardlimit <block-hardlimit>]\n"
288 " [--inode-softlimit <inode-softlimit>]\n"
289 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
290 " setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
291 " [--block-grace <block-grace>]\n"
292 " [--inode-grace <inode-grace>] <filesystem>\n"
293 " -b can be used instead of --block-softlimit/--block-grace\n"
294 " -B can be used instead of --block-hardlimit\n"
295 " -i can be used instead of --inode-softlimit/--inode-grace\n"
296 " -I can be used instead of --inode-hardlimit\n\n"
297 "Note: The total quota space will be split into many qunits and\n"
298 " balanced over all server targets, the minimal qunit size is\n"
299 " 1M bytes for block space and 1K inodes for inode space.\n\n"
300 " Quota space rebalancing process will stop when this mininum\n"
301 " value is reached. As a result, quota exceeded can be returned\n"
302 " while many targets still have 1MB or 1K inodes of spare\n"
304 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
305 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
307 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
308 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
310 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
311 "usage: flushctx [-k] [mountpoint...]"},
313 "Remote user copy files and directories.\n"
314 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
316 "Remote user list directory contents.\n"
317 "usage: ls [OPTION]... [FILE]..."},
318 {"changelog", lfs_changelog, 0,
319 "Show the metadata changes on an MDT."
320 "\nusage: changelog <mdtname> [startrec [endrec]]"},
321 {"changelog_clear", lfs_changelog_clear, 0,
322 "Indicate that old changelog records up to <endrec> are no longer of "
323 "interest to consumer <id>, allowing the system to free up space.\n"
324 "An <endrec> of 0 means all records.\n"
325 "usage: changelog_clear <mdtname> <id> <endrec>"},
326 {"fid2path", lfs_fid2path, 0,
327 "Resolve the full path(s) for given FID(s). For a specific hardlink "
328 "specify link number <linkno>.\n"
329 /* "For a historical link name, specify changelog record <recno>.\n" */
330 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
331 /* [ --rec <recno> ] */ },
332 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
333 "usage: path2fid [--parents] <path> ..."},
334 {"data_version", lfs_data_version, 0, "Display file data version for "
335 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
336 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
337 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
338 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
339 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
340 "[--archived] [--lost] <file> ..."},
341 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
343 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
344 "[--archived] [--lost] <file> ..."},
345 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
346 "given files.\n" "usage: hsm_action <file> ..."},
347 {"hsm_archive", lfs_hsm_archive, 0,
348 "Archive file to external storage.\n"
349 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
351 {"hsm_restore", lfs_hsm_restore, 0,
352 "Restore file from external storage.\n"
353 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
354 {"hsm_release", lfs_hsm_release, 0,
355 "Release files from Lustre.\n"
356 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
357 {"hsm_remove", lfs_hsm_remove, 0,
358 "Remove file copy from external storage.\n"
359 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
360 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
362 "Note: To remove files from the archive that have been deleted on\n"
363 "Lustre, set mntpath and optionally archive. In that case, all the\n"
364 "positional arguments and entries in the file list must be FIDs."
366 {"hsm_cancel", lfs_hsm_cancel, 0,
367 "Cancel requests related to specified files.\n"
368 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
369 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
370 "usage: swap_layouts <path1> <path2>"},
371 {"migrate", lfs_setstripe, 0,
372 "migrate a directory between MDTs.\n"
373 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
375 "\tmdt_idx: index of the destination MDT\n"
377 "migrate file objects from one OST "
378 "layout\nto another (may be not safe with concurent writes).\n"
380 "[--stripe-count|-c] <stripe_count>\n"
381 " [--stripe-index|-i] <start_ost_index>\n"
382 " [--stripe-size|-S] <stripe_size>\n"
383 " [--pool|-p] <pool_name>\n"
384 " [--ost-list|-o] <ost_indices>\n"
386 " [--non-block|-n]\n"
387 " <file|directory>\n"
388 "\tstripe_count: number of OSTs to stripe a file over\n"
389 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
390 "\tstripe_size: number of bytes to store before moving to the next OST\n"
391 "\tpool_name: name of the predefined pool of OSTs\n"
392 "\tost_indices: OSTs to stripe over, in order\n"
393 "\tblock: wait for the operation to return before continuing\n"
394 "\tnon-block: do not wait for the operation to return.\n"},
396 "To move directories between MDTs. This command is deprecated, "
397 "use \"migrate\" instead.\n"
398 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
400 {"ladvise", lfs_ladvise, 0,
401 "Provide servers with advice about access patterns for a file.\n"
402 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
403 " [--background|-b]\n"
404 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
406 {"help", Parser_help, 0, "help"},
407 {"exit", Parser_quit, 0, "quit"},
408 {"quit", Parser_quit, 0, "quit"},
409 {"--version", Parser_version, 0,
410 "output build version of the utility and exit"},
411 {"--list-commands", lfs_list_commands, 0,
412 "list commands supported by the utility and exit"},
417 #define MIGRATION_NONBLOCK 1
419 static int check_hashtype(const char *hashtype)
423 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
424 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
431 * Internal helper for migrate_copy_data(). Check lease and report error if
434 * \param[in] fd File descriptor on which to check the lease.
435 * \param[out] lease_broken Set to true if the lease was broken.
436 * \param[in] group_locked Whether a group lock was taken or not.
437 * \param[in] path Name of the file being processed, for error
440 * \retval 0 Migration can keep on going.
441 * \retval -errno Error occurred, abort migration.
443 static int check_lease(int fd, bool *lease_broken, bool group_locked,
448 if (!file_lease_supported)
451 rc = llapi_lease_check(fd);
453 return 0; /* llapi_check_lease returns > 0 on success. */
456 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
458 rc = rc ? rc : -EAGAIN;
460 fprintf(stderr, "%s: external attempt to access file '%s' "
461 "blocked until migration ends.\n", progname, path);
464 *lease_broken = true;
468 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
469 bool group_locked, const char *fname)
478 bool lease_broken = false;
480 /* Use a page-aligned buffer for direct I/O */
481 rc = posix_memalign(&buf, getpagesize(), buf_size);
486 /* read new data only if we have written all
487 * previously read data */
490 rc = check_lease(fd_src, &lease_broken,
491 group_locked, fname);
495 rsize = read(fd_src, buf, buf_size);
498 fprintf(stderr, "%s: %s: read failed: %s\n",
499 progname, fname, strerror(-rc));
509 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
513 "%s: %s: write failed on volatile: %s\n",
514 progname, fname, strerror(-rc));
524 fprintf(stderr, "%s: %s: fsync failed: %s\n",
525 progname, fname, strerror(-rc));
533 static int migrate_copy_timestamps(int fdv, const struct stat *st)
535 struct timeval tv[2] = {
536 {.tv_sec = st->st_atime},
537 {.tv_sec = st->st_mtime}
540 return futimes(fdv, tv);
543 static int migrate_block(int fd, int fdv, const struct stat *st,
544 size_t buf_size, const char *name)
551 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
553 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
554 progname, name, strerror(-rc));
562 /* The grouplock blocks all concurrent accesses to the file.
563 * It has to be taken after llapi_get_data_version as it would
565 rc = llapi_group_lock(fd, gid);
567 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
568 progname, name, strerror(-rc));
572 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
574 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
578 /* Make sure we keep original atime/mtime values */
579 rc = migrate_copy_timestamps(fdv, st);
581 fprintf(stderr, "%s: %s: timestamp copy failed\n",
587 * for a migration we need to check data version on file did
590 * Pass in gid=0 since we already own grouplock. */
591 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
592 SWAP_LAYOUTS_CHECK_DV1);
594 fprintf(stderr, "%s: %s: dataversion changed during copy, "
595 "migration aborted\n", progname, name);
598 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
599 name, strerror(-rc));
604 rc2 = llapi_group_unlock(fd, gid);
605 if (rc2 < 0 && rc == 0) {
606 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
607 progname, name, strerror(-rc2));
614 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
615 size_t buf_size, const char *name)
621 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
623 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
624 progname, name, strerror(-rc));
628 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
630 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
634 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
636 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
637 progname, name, strerror(-rc));
643 fprintf(stderr, "%s: %s: data version changed during "
649 /* Make sure we keep original atime/mtime values */
650 rc = migrate_copy_timestamps(fdv, st);
652 fprintf(stderr, "%s: %s: timestamp copy failed\n",
657 /* Atomically put lease, swap layouts and close.
658 * for a migration we need to check data version on file did
660 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
662 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
663 progname, name, strerror(-rc));
670 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
675 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
679 if (flags != 0 && comp_id != 0)
682 /* LCME_FL_INIT is the only supported flag in PFL */
684 if (flags & ~LCME_KNOWN_FLAGS) {
685 fprintf(stderr, "Invalid component flags %#x\n", flags);
688 } else if (comp_id > LCME_ID_MAX) {
689 fprintf(stderr, "Invalid component id %u\n", comp_id);
693 rc = llapi_layout_file_comp_del(fname, comp_id, flags);
695 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
696 comp_id, fname, strerror(errno));
700 static int lfs_component_add(char *fname, struct llapi_layout *layout)
707 rc = llapi_layout_file_comp_add(fname, layout);
709 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
710 fname, strerror(errno));
714 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
715 struct llapi_layout *layout)
723 fd = lstat(fname, &st);
724 if (fd == 0 && S_ISDIR(st.st_mode))
725 open_flags = O_DIRECTORY | O_RDONLY;
727 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
729 fprintf(stderr, "%s %s failed. %s\n",
730 S_ISDIR(st.st_mode) ?
731 "Set default composite layout to " :
732 "Create composite file",
733 fname, strerror(errno));
737 static int lfs_migrate(char *name, __u64 migration_flags,
738 struct llapi_stripe_param *param,
739 struct llapi_layout *layout)
743 char parent[PATH_MAX];
746 char volatile_file[sizeof(parent) +
747 LUSTRE_VOLATILE_HDR_LEN +
748 2 * sizeof(mdt_index) +
749 2 * sizeof(random_value) + 4];
752 struct lov_user_md *lum = NULL;
754 int buf_size = 1024 * 1024 * 4;
755 bool have_lease_rdlck = false;
759 /* find the right size for the IO and allocate the buffer */
760 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
761 lum = malloc(lum_size);
767 rc = llapi_file_get_stripe(name, lum);
768 /* failure can happen for many reasons and some may be not real errors
770 * in case of a real error, a later call will fail with better
771 * error management */
773 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
774 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
775 lum->lmm_stripe_size != 0)
776 buf_size = lum->lmm_stripe_size;
779 /* open file, direct io */
780 /* even if the file is only read, WR mode is nedeed to allow
781 * layout swap on fd */
782 fd = open(name, O_RDWR | O_DIRECT);
785 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
790 if (file_lease_supported) {
791 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
792 if (rc == -EOPNOTSUPP) {
793 /* Older servers do not support file lease.
794 * Disable related checks. This opens race conditions
795 * as explained in LU-4840 */
796 file_lease_supported = false;
798 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
799 progname, name, strerror(-rc));
802 have_lease_rdlck = true;
806 /* search for file directory pathname */
807 if (strlen(name) > sizeof(parent)-1) {
811 strncpy(parent, name, sizeof(parent));
812 ptr = strrchr(parent, '/');
814 if (getcwd(parent, sizeof(parent)) == NULL) {
825 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
827 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
828 progname, name, strerror(-rc));
833 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
834 mode_t open_mode = S_IRUSR | S_IWUSR;
836 random_value = random();
837 rc = snprintf(volatile_file, sizeof(volatile_file),
838 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
839 mdt_index, random_value);
840 if (rc >= sizeof(volatile_file)) {
845 /* create, open a volatile file, use caching (ie no directio) */
847 fdv = llapi_file_open_param(volatile_file, open_flags,
849 else if (layout != NULL)
850 fdv = lfs_component_create(volatile_file, open_flags,
854 } while (fdv == -EEXIST);
858 fprintf(stderr, "%s: %s: cannot create volatile file in"
860 progname, parent, strerror(-rc));
864 /* In case the MDT does not support creation of volatile files
865 * we should try to unlink it. */
866 (void)unlink(volatile_file);
868 /* Not-owner (root?) special case.
869 * Need to set owner/group of volatile file like original.
870 * This will allow to pass related check during layout_swap.
875 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
879 rc = fstat(fdv, &stv);
882 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
883 volatile_file, strerror(errno));
886 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
887 rc = fchown(fdv, st.st_uid, st.st_gid);
890 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
891 name, strerror(errno));
896 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
897 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
899 have_lease_rdlck = false;
900 fdv = -1; /* The volatile file is closed as we put the
901 * lease in non-blocking mode. */
904 /* Blocking mode (forced if servers do not support file lease).
905 * It is also the default mode, since we cannot distinguish
906 * between a broken lease and a server that does not support
907 * atomic swap/close (LU-6785) */
908 rc = migrate_block(fd, fdv, &st, buf_size, name);
912 if (have_lease_rdlck)
929 * Parse a string containing an OST index list into an array of integers.
931 * The input string contains a comma delimited list of individual
932 * indices and ranges, for example "1,2-4,7". Add the indices into the
933 * \a osts array and remove duplicates.
935 * \param[out] osts array to store indices in
936 * \param[in] size size of \a osts array
937 * \param[in] offset starting index in \a osts
938 * \param[in] arg string containing OST index list
940 * \retval positive number of indices in \a osts
941 * \retval -EINVAL unable to parse \a arg
943 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
947 int slots = size - offset;
955 while (!end_of_loop) {
963 ptr = strchrnul(arg, ',');
965 end_of_loop = *ptr == '\0';
968 start_index = strtol(arg, &endptr, 0);
969 if (endptr == arg) /* no data at all */
971 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
976 end_index = start_index;
977 if (*endptr == '-') {
978 end_index = strtol(endptr + 1, &endptr, 0);
981 if (end_index < start_index)
985 for (i = start_index; i <= end_index && slots > 0; i++) {
988 /* remove duplicate */
989 for (j = 0; j < offset; j++) {
993 if (j == offset) { /* no duplicate */
998 if (slots == 0 && i < end_index)
1006 if (!end_of_loop && ptr != NULL)
1009 return rc < 0 ? rc : nr;
1012 static int verify_pool_name(char *prog_name, char *pool_name)
1016 if (pool_name == NULL)
1019 ptr = strchr(pool_name, '.');
1020 if (ptr != NULL && ptr == pool_name) {
1021 fprintf(stderr, "error: %s: fsname is empty in pool name '%s'\n",
1022 prog_name, pool_name);
1029 struct lfs_setstripe_args {
1030 unsigned long long lsa_comp_end;
1031 unsigned long long lsa_stripe_size;
1032 int lsa_stripe_count;
1034 __u32 lsa_comp_flags;
1037 char *lsa_pool_name;
1040 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1042 memset(lsa, 0, sizeof(*lsa));
1043 lsa->lsa_stripe_off = -1;
1046 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1048 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1049 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1050 lsa->lsa_comp_end != 0);
1053 static int comp_args_to_layout(struct llapi_layout **composite,
1054 struct lfs_setstripe_args *lsa)
1056 struct llapi_layout *layout = *composite;
1057 uint64_t prev_end = 0;
1060 if (layout == NULL) {
1061 layout = llapi_layout_alloc();
1062 if (layout == NULL) {
1063 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1067 *composite = layout;
1071 /* Get current component extent, current component
1072 * must be the tail component. */
1073 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1075 fprintf(stderr, "Get comp extent failed. %s\n",
1080 rc = llapi_layout_comp_add(layout);
1082 fprintf(stderr, "Add component failed. %s\n",
1088 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1090 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1091 prev_end, lsa->lsa_comp_end, strerror(errno));
1095 if (lsa->lsa_stripe_size != 0) {
1096 rc = llapi_layout_stripe_size_set(layout,
1097 lsa->lsa_stripe_size);
1099 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1100 lsa->lsa_stripe_size, strerror(errno));
1105 if (lsa->lsa_stripe_count != 0) {
1106 rc = llapi_layout_stripe_count_set(layout,
1107 lsa->lsa_stripe_count == -1 ?
1109 lsa->lsa_stripe_count);
1111 fprintf(stderr, "Set stripe count %d failed. %s\n",
1112 lsa->lsa_stripe_count, strerror(errno));
1117 if (lsa->lsa_pool_name != NULL) {
1118 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1120 fprintf(stderr, "Set pool name: %s failed. %s\n",
1121 lsa->lsa_pool_name, strerror(errno));
1126 if (lsa->lsa_nr_osts > 0) {
1127 if (lsa->lsa_stripe_count > 0 &&
1128 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1129 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1130 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1133 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1134 rc = llapi_layout_ost_index_set(layout, i,
1139 } else if (lsa->lsa_stripe_off != -1) {
1140 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1143 fprintf(stderr, "Set ost index %d failed. %s\n",
1144 i, strerror(errno));
1151 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1152 * end of the last component in the existing file, and adjust the
1153 * first extent start of the components to be added accordingly. */
1154 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1156 struct llapi_layout *head;
1157 uint64_t start, end, stripe_size, prev_end = 0;
1164 head = llapi_layout_get_by_path(fname, 0);
1166 fprintf(stderr, "Read layout from %s failed. %s\n",
1167 fname, strerror(errno));
1169 } else if (errno == ENODATA) {
1170 /* file without LOVEA, this component-add will be turned
1171 * into a component-create. */
1172 llapi_layout_free(head);
1175 /* Current component of 'head' should be tail of component
1176 * list by default, but we do an extra move cursor operation
1177 * here to test if the layout is non-composite. */
1178 rc = llapi_layout_comp_use(head, LLAPI_LAYOUT_COMP_USE_LAST);
1180 fprintf(stderr, "'%s' isn't a composite file?\n",
1182 llapi_layout_free(head);
1187 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1189 fprintf(stderr, "Get prev extent failed. %s\n",
1191 llapi_layout_free(head);
1195 llapi_layout_free(head);
1197 /* Make sure we use the first component of the layout to be added. */
1198 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1200 fprintf(stderr, "Move component cursor failed. %s\n",
1205 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1207 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1211 if (start > prev_end || end <= prev_end) {
1212 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1213 "adjacent with the existing file extent end: %lu\n",
1214 start, end, prev_end);
1218 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1220 fprintf(stderr, "Get stripe size failed. %s\n",
1225 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1226 (prev_end & (stripe_size - 1))) {
1227 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1228 stripe_size, prev_end);
1232 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1234 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1235 prev_end, end, strerror(errno));
1242 static inline bool comp_flags_is_neg(__u32 flags)
1244 return flags & LCME_FL_NEG;
1247 static inline void comp_flags_set_neg(__u32 *flags)
1249 *flags |= LCME_FL_NEG;
1252 static inline void comp_flags_clear_neg(__u32 *flags)
1254 *flags &= ~LCME_FL_NEG;
1257 static int comp_str2flags(__u32 *flags, char *string)
1260 __u32 neg_flags = 0;
1266 for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1270 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1271 __u32 comp_flag = comp_flags_table[i].cfn_flag;
1272 const char *comp_name = comp_flags_table[i].cfn_name;
1274 if (strcmp(name, comp_name) == 0) {
1275 *flags |= comp_flag;
1277 } else if (strncmp(name, "^", 1) == 0 &&
1278 strcmp(name + 1, comp_name) == 0) {
1279 neg_flags |= comp_flag;
1284 llapi_printf(LLAPI_MSG_ERROR, "Component flag "
1285 "'%s' is not supported.\n", name);
1290 if (*flags == 0 && neg_flags == 0)
1292 /* don't support mixed flags for now */
1293 if (*flags && neg_flags)
1298 comp_flags_set_neg(flags);
1304 static inline bool arg_is_eof(char *arg)
1306 return !strncmp(arg, "-1", strlen("-1")) ||
1307 !strncmp(arg, "EOF", strlen("EOF")) ||
1308 !strncmp(arg, "eof", strlen("eof"));
1323 static int lfs_setstripe(int argc, char **argv)
1325 struct lfs_setstripe_args lsa;
1326 struct llapi_stripe_param *param = NULL;
1327 struct find_param migrate_mdt_param = {
1337 char *mdt_idx_arg = NULL;
1338 unsigned long long size_units = 1;
1339 bool migrate_mode = false;
1340 bool migration_block = false;
1341 __u64 migration_flags = 0;
1342 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1343 int comp_del = 0, comp_set = 0;
1346 struct llapi_layout *layout = NULL;
1348 struct option long_opts[] = {
1349 /* --block is only valid in migrate mode */
1350 {"block", no_argument, 0, 'b'},
1351 {"comp-add", no_argument, 0, LFS_COMP_ADD_OPT},
1352 {"component-add", no_argument, 0, LFS_COMP_ADD_OPT},
1353 {"comp-del", no_argument, 0, LFS_COMP_DEL_OPT},
1354 {"component-del", no_argument, 0, LFS_COMP_DEL_OPT},
1355 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1356 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1357 {"comp-set", no_argument, 0, LFS_COMP_SET_OPT},
1358 {"component-set", no_argument, 0, LFS_COMP_SET_OPT},
1359 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1360 /* This formerly implied "stripe-count", but was explicitly
1361 * made "stripe-count" for consistency with other options,
1362 * and to separate it from "mdt-count" when DNE arrives. */
1363 {"count", required_argument, 0, 'c'},
1365 {"stripe-count", required_argument, 0, 'c'},
1366 {"stripe_count", required_argument, 0, 'c'},
1367 {"delete", no_argument, 0, 'd'},
1368 {"comp-end", required_argument, 0, 'E'},
1369 {"component-end", required_argument, 0, 'E'},
1370 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1371 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1372 /* This formerly implied "stripe-index", but was explicitly
1373 * made "stripe-index" for consistency with other options,
1374 * and to separate it from "mdt-index" when DNE arrives. */
1375 {"index", required_argument, 0, 'i'},
1377 {"stripe-index", required_argument, 0, 'i'},
1378 {"stripe_index", required_argument, 0, 'i'},
1379 {"comp-id", required_argument, 0, 'I'},
1380 {"component-id", required_argument, 0, 'I'},
1381 {"mdt", required_argument, 0, 'm'},
1382 {"mdt-index", required_argument, 0, 'm'},
1383 {"mdt_index", required_argument, 0, 'm'},
1384 /* --non-block is only valid in migrate mode */
1385 {"non-block", no_argument, 0, 'n'},
1386 {"ost", required_argument, 0, 'o'},
1387 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1388 {"ost-list", required_argument, 0, 'o'},
1389 {"ost_list", required_argument, 0, 'o'},
1391 {"pool", required_argument, 0, 'p'},
1392 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1393 /* This formerly implied "--stripe-size", but was confusing
1394 * with "lfs find --size|-s", which means "file size", so use
1395 * the consistent "--stripe-size|-S" for all commands. */
1396 {"size", required_argument, 0, 's'},
1398 {"stripe-size", required_argument, 0, 'S'},
1399 {"stripe_size", required_argument, 0, 'S'},
1400 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1401 /* --verbose is only valid in migrate mode */
1402 {"verbose", no_argument, 0, 'v'},
1406 setstripe_args_init(&lsa);
1408 if (strcmp(argv[0], "migrate") == 0)
1409 migrate_mode = true;
1411 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1412 long_opts, NULL)) >= 0) {
1417 case LFS_COMP_ADD_OPT:
1420 case LFS_COMP_DEL_OPT:
1423 case LFS_COMP_FLAGS_OPT:
1424 result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
1426 fprintf(stderr, "error: %s: bad comp flags "
1427 "'%s'\n", argv[0], optarg);
1431 case LFS_COMP_SET_OPT:
1435 if (!migrate_mode) {
1436 fprintf(stderr, "--block is valid only for"
1440 migration_block = true;
1443 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1444 if (strcmp(argv[optind - 1], "--count") == 0)
1445 fprintf(stderr, "warning: '--count' deprecated"
1446 ", use '--stripe-count' instead\n");
1448 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1450 fprintf(stderr, "error: %s: bad stripe count "
1451 "'%s'\n", argv[0], optarg);
1456 /* delete the default striping pattern */
1460 if (lsa.lsa_comp_end != 0) {
1461 result = comp_args_to_layout(&layout, &lsa);
1465 setstripe_args_init(&lsa);
1468 if (arg_is_eof(optarg)) {
1469 lsa.lsa_comp_end = LUSTRE_EOF;
1471 result = llapi_parse_size(optarg,
1475 fprintf(stderr, "error: %s: "
1476 "bad component end '%s'\n",
1483 if (strcmp(argv[optind - 1], "--index") == 0)
1484 fprintf(stderr, "warning: '--index' deprecated"
1485 ", use '--stripe-index' instead\n");
1486 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1488 fprintf(stderr, "error: %s: bad stripe offset "
1489 "'%s'\n", argv[0], optarg);
1494 comp_id = strtoul(optarg, &end, 0);
1495 if (*end != '\0' || comp_id == 0 ||
1496 comp_id > LCME_ID_MAX) {
1497 fprintf(stderr, "error: %s: bad comp ID "
1498 "'%s'\n", argv[0], optarg);
1503 if (!migrate_mode) {
1504 fprintf(stderr, "--mdt-index is valid only for"
1508 mdt_idx_arg = optarg;
1511 if (!migrate_mode) {
1512 fprintf(stderr, "--non-block is valid only for"
1516 migration_flags |= MIGRATION_NONBLOCK;
1519 lsa.lsa_nr_osts = parse_targets(osts,
1520 sizeof(osts) / sizeof(__u32),
1521 lsa.lsa_nr_osts, optarg);
1522 if (lsa.lsa_nr_osts < 0) {
1524 "error: %s: bad OST indices '%s'\n",
1529 lsa.lsa_osts = osts;
1530 if (lsa.lsa_stripe_off == -1)
1531 lsa.lsa_stripe_off = osts[0];
1534 result = verify_pool_name(argv[0], optarg);
1537 lsa.lsa_pool_name = optarg;
1539 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1541 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1542 fprintf(stderr, "warning: '--size|-s' deprecated, "
1543 "use '--stripe-size|-S' instead\n");
1545 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1547 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1550 fprintf(stderr, "error: %s: bad stripe size "
1551 "'%s'\n", argv[0], optarg);
1556 if (!migrate_mode) {
1557 fprintf(stderr, "--verbose is valid only for"
1561 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1568 fname = argv[optind];
1570 if (lsa.lsa_comp_end != 0) {
1571 result = comp_args_to_layout(&layout, &lsa);
1576 if (optind == argc) {
1577 fprintf(stderr, "error: %s: missing filename|dirname\n",
1582 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1583 * altered by user space tool, so we don't need to support the
1584 * --component-set for this moment. */
1585 if (comp_set != 0) {
1586 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1591 if ((delete + comp_set + comp_del + comp_add) > 1) {
1592 fprintf(stderr, "error: %s: can't specify --component-set, "
1593 "--component-del, --component-add or -d together\n",
1598 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1599 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1600 fprintf(stderr, "error: %s: can't specify -d with "
1601 "-s, -c, -o, -p, -I, -F or -E options\n",
1606 if ((comp_set || comp_del) &&
1607 (setstripe_args_specified(&lsa) || layout != NULL)) {
1608 fprintf(stderr, "error: %s: can't specify --component-del or "
1609 "--component-set with -s, -c, -o, -p or -E options.\n",
1614 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1615 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1616 "--component-del option.\n", argv[0]);
1620 if (comp_add || comp_del) {
1623 result = lstat(fname, &st);
1624 if (result == 0 && S_ISDIR(st.st_mode)) {
1625 fprintf(stderr, "error: %s: can't use --component-add "
1626 "or --component-del for directory.\n",
1633 if (layout == NULL) {
1634 fprintf(stderr, "error: %s: -E option must be present"
1635 "in --component-add mode.\n", argv[0]);
1638 result = adjust_first_extent(fname, layout);
1639 if (result == -ENODATA)
1641 else if (result != 0)
1645 if (mdt_idx_arg != NULL && optind > 3) {
1646 fprintf(stderr, "error: %s: cannot specify -m with other "
1647 "options\n", argv[0]);
1651 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1653 "error: %s: cannot specify --non-block and --block\n",
1658 if (!comp_del && !comp_set && comp_id != 0) {
1659 fprintf(stderr, "error: %s: -I can only be used with "
1660 "--component-del.\n", argv[0]);
1664 if (mdt_idx_arg != NULL) {
1665 /* initialize migrate mdt parameters */
1666 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1668 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1669 argv[0], mdt_idx_arg);
1672 migrate_mdt_param.fp_migrate = 1;
1673 } else if (layout == NULL) {
1674 /* initialize stripe parameters */
1675 param = calloc(1, offsetof(typeof(*param),
1676 lsp_osts[lsa.lsa_nr_osts]));
1677 if (param == NULL) {
1678 fprintf(stderr, "error: %s: %s\n", argv[0],
1683 param->lsp_stripe_size = lsa.lsa_stripe_size;
1684 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1685 param->lsp_stripe_count = lsa.lsa_stripe_count;
1686 param->lsp_stripe_pattern = 0;
1687 param->lsp_pool = lsa.lsa_pool_name;
1688 param->lsp_is_specific = false;
1689 if (lsa.lsa_nr_osts > 0) {
1690 if (lsa.lsa_stripe_count > 0 &&
1691 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1692 fprintf(stderr, "error: %s: stripe count '%d' "
1693 "doesn't match the number of OSTs: %d\n"
1694 , argv[0], lsa.lsa_stripe_count,
1700 param->lsp_is_specific = true;
1701 param->lsp_stripe_count = lsa.lsa_nr_osts;
1702 memcpy(param->lsp_osts, osts,
1703 sizeof(*osts) * lsa.lsa_nr_osts);
1707 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1709 if (mdt_idx_arg != NULL) {
1710 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1711 op = "migrate mdt objects of";
1712 } else if (migrate_mode) {
1713 result = lfs_migrate(fname, migration_flags, param,
1715 op = "migrate ost objects of";
1716 } else if (comp_set != 0) {
1717 result = lfs_component_set(fname, comp_id,
1718 lsa.lsa_comp_flags);
1719 op = "modify component flags of";
1720 } else if (comp_del != 0) {
1721 result = lfs_component_del(fname, comp_id,
1722 lsa.lsa_comp_flags);
1723 op = "delete component of";
1724 } else if (comp_add != 0) {
1725 result = lfs_component_add(fname, layout);
1726 op = "add component to";
1727 } else if (layout != NULL) {
1728 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1734 op = "create composite";
1736 result = llapi_file_open_param(fname,
1743 op = "create striped";
1746 /* Save the first error encountered. */
1749 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1751 lsa.lsa_pool_name != NULL && result == EINVAL ?
1752 "OST not in pool?" : strerror(errno));
1758 llapi_layout_free(layout);
1761 llapi_layout_free(layout);
1765 static int lfs_poollist(int argc, char **argv)
1770 return llapi_poollist(argv[1]);
1773 static int set_time(time_t *time, time_t *set, char *str)
1780 else if (str[0] == '-')
1786 t = strtol(str, NULL, 0);
1787 if (*time < t * 24 * 60 * 60) {
1790 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1794 *set = *time - t * 24 * 60 * 60;
1797 static int name2uid(unsigned int *id, const char *name)
1799 struct passwd *passwd;
1801 passwd = getpwnam(name);
1804 *id = passwd->pw_uid;
1809 static int name2gid(unsigned int *id, const char *name)
1811 struct group *group;
1813 group = getgrnam(name);
1816 *id = group->gr_gid;
1821 static inline int name2projid(unsigned int *id, const char *name)
1826 static int uid2name(char **name, unsigned int id)
1828 struct passwd *passwd;
1830 passwd = getpwuid(id);
1833 *name = passwd->pw_name;
1838 static inline int gid2name(char **name, unsigned int id)
1840 struct group *group;
1842 group = getgrgid(id);
1845 *name = group->gr_name;
1850 static int name2layout(__u32 *layout, char *name)
1855 for (ptr = name; ; ptr = NULL) {
1856 lyt = strtok(ptr, ",");
1859 if (strcmp(lyt, "released") == 0)
1860 *layout |= LOV_PATTERN_F_RELEASED;
1861 else if (strcmp(lyt, "raid0") == 0)
1862 *layout |= LOV_PATTERN_RAID0;
1869 static int lfs_find(int argc, char **argv)
1874 struct find_param param = {
1878 struct option long_opts[] = {
1879 {"atime", required_argument, 0, 'A'},
1880 {"comp-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1881 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1882 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1883 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1884 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
1885 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1886 {"stripe-count", required_argument, 0, 'c'},
1887 {"stripe_count", required_argument, 0, 'c'},
1888 {"ctime", required_argument, 0, 'C'},
1889 {"maxdepth", required_argument, 0, 'D'},
1890 {"comp-end", required_argument, 0, 'E'},
1891 {"component-end", required_argument, 0, 'E'},
1892 {"gid", required_argument, 0, 'g'},
1893 {"group", required_argument, 0, 'G'},
1894 {"mdt-hash", required_argument, 0, 'H'},
1895 {"stripe-index", required_argument, 0, 'i'},
1896 {"stripe_index", required_argument, 0, 'i'},
1897 /*{"component-id", required_argument, 0, 'I'},*/
1898 {"layout", required_argument, 0, 'L'},
1899 {"mdt", required_argument, 0, 'm'},
1900 {"mdt-index", required_argument, 0, 'm'},
1901 {"mdt_index", required_argument, 0, 'm'},
1902 {"mtime", required_argument, 0, 'M'},
1903 {"name", required_argument, 0, 'n'},
1904 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1905 {"obd", required_argument, 0, 'O'},
1906 {"ost", required_argument, 0, 'O'},
1907 /* no short option for pool, p/P already used */
1908 {"pool", required_argument, 0, LFS_POOL_OPT},
1909 {"print0", no_argument, 0, 'p'},
1910 {"print", no_argument, 0, 'P'},
1911 {"projid", required_argument, 0, LFS_PROJID_OPT},
1912 {"size", required_argument, 0, 's'},
1913 {"stripe-size", required_argument, 0, 'S'},
1914 {"stripe_size", required_argument, 0, 'S'},
1915 {"type", required_argument, 0, 't'},
1916 {"mdt-count", required_argument, 0, 'T'},
1917 {"uid", required_argument, 0, 'u'},
1918 {"user", required_argument, 0, 'U'},
1931 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1932 while ((c = getopt_long_only(argc, argv,
1933 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1934 long_opts, NULL)) >= 0) {
1939 /* '!' is part of option */
1940 /* when getopt_long_only() finds a string which is not
1941 * an option nor a known option argument it returns 1
1942 * in that case if we already have found pathstart and pathend
1943 * (i.e. we have the list of pathnames),
1944 * the only supported value is "!"
1946 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1947 if (!isoption && pathend != -1) {
1948 fprintf(stderr, "err: %s: filename|dirname must either "
1949 "precede options or follow options\n",
1954 if (!isoption && pathstart == -1)
1955 pathstart = optind - 1;
1956 if (isoption && pathstart != -1 && pathend == -1)
1957 pathend = optind - 2;
1963 /* unknown; opt is "!" or path component,
1964 * checking done above.
1966 if (strcmp(optarg, "!") == 0)
1970 xtime = ¶m.fp_atime;
1971 xsign = ¶m.fp_asign;
1972 param.fp_exclude_atime = !!neg_opt;
1973 /* no break, this falls through to 'C' for ctime */
1976 xtime = ¶m.fp_ctime;
1977 xsign = ¶m.fp_csign;
1978 param.fp_exclude_ctime = !!neg_opt;
1980 /* no break, this falls through to 'M' for mtime */
1983 xtime = ¶m.fp_mtime;
1984 xsign = ¶m.fp_msign;
1985 param.fp_exclude_mtime = !!neg_opt;
1987 rc = set_time(&t, xtime, optarg);
1988 if (rc == INT_MAX) {
1995 case LFS_COMP_COUNT_OPT:
1996 if (optarg[0] == '+') {
1997 param.fp_comp_count_sign = -1;
1999 } else if (optarg[0] == '-') {
2000 param.fp_comp_count_sign = 1;
2004 param.fp_comp_count = strtoul(optarg, &endptr, 0);
2005 if (*endptr != '\0') {
2006 fprintf(stderr, "error: bad component count "
2010 param.fp_check_comp_count = 1;
2011 param.fp_exclude_comp_count = !!neg_opt;
2013 case LFS_COMP_FLAGS_OPT:
2014 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
2015 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2016 fprintf(stderr, "error: bad component flags "
2020 param.fp_check_comp_flags = 1;
2021 param.fp_exclude_comp_flags = !!neg_opt;
2023 case LFS_COMP_START_OPT:
2024 if (optarg[0] == '+') {
2025 param.fp_comp_start_sign = -1;
2027 } else if (optarg[0] == '-') {
2028 param.fp_comp_start_sign = 1;
2032 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2033 ¶m.fp_comp_start_units, 0);
2035 fprintf(stderr, "error: bad component start "
2039 param.fp_check_comp_start = 1;
2040 param.fp_exclude_comp_start = !!neg_opt;
2043 if (optarg[0] == '+') {
2044 param.fp_stripe_count_sign = -1;
2046 } else if (optarg[0] == '-') {
2047 param.fp_stripe_count_sign = 1;
2051 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2052 if (*endptr != '\0') {
2053 fprintf(stderr,"error: bad stripe_count '%s'\n",
2058 param.fp_check_stripe_count = 1;
2059 param.fp_exclude_stripe_count = !!neg_opt;
2062 param.fp_max_depth = strtol(optarg, 0, 0);
2065 if (optarg[0] == '+') {
2066 param.fp_comp_end_sign = -1;
2068 } else if (optarg[0] == '-') {
2069 param.fp_comp_end_sign = 1;
2073 if (arg_is_eof(optarg)) {
2074 param.fp_comp_end = LUSTRE_EOF;
2075 param.fp_comp_end_units = 1;
2078 rc = llapi_parse_size(optarg,
2080 ¶m.fp_comp_end_units, 0);
2083 fprintf(stderr, "error: bad component end "
2087 param.fp_check_comp_end = 1;
2088 param.fp_exclude_comp_end = !!neg_opt;
2092 rc = name2gid(¶m.fp_gid, optarg);
2094 param.fp_gid = strtoul(optarg, &endptr, 10);
2095 if (*endptr != '\0') {
2096 fprintf(stderr, "Group/GID: %s cannot "
2097 "be found.\n", optarg);
2102 param.fp_exclude_gid = !!neg_opt;
2103 param.fp_check_gid = 1;
2106 param.fp_hash_type = check_hashtype(optarg);
2107 if (param.fp_hash_type == 0) {
2108 fprintf(stderr, "error: bad hash_type '%s'\n",
2113 param.fp_check_hash_type = 1;
2114 param.fp_exclude_hash_type = !!neg_opt;
2117 ret = name2layout(¶m.fp_layout, optarg);
2120 param.fp_exclude_layout = !!neg_opt;
2121 param.fp_check_layout = 1;
2125 rc = name2uid(¶m.fp_uid, optarg);
2127 param.fp_uid = strtoul(optarg, &endptr, 10);
2128 if (*endptr != '\0') {
2129 fprintf(stderr, "User/UID: %s cannot "
2130 "be found.\n", optarg);
2135 param.fp_exclude_uid = !!neg_opt;
2136 param.fp_check_uid = 1;
2139 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2141 "Pool name %s is too long"
2142 " (max is %d)\n", optarg,
2147 /* we do check for empty pool because empty pool
2148 * is used to find V1 lov attributes */
2149 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2150 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2151 param.fp_exclude_pool = !!neg_opt;
2152 param.fp_check_pool = 1;
2155 param.fp_pattern = (char *)optarg;
2156 param.fp_exclude_pattern = !!neg_opt;
2161 char *buf, *token, *next, *p;
2165 buf = strdup(optarg);
2171 param.fp_exclude_obd = !!neg_opt;
2174 while (token && *token) {
2175 token = strchr(token, ',');
2182 param.fp_exclude_mdt = !!neg_opt;
2183 param.fp_num_alloc_mdts += len;
2184 tmp = realloc(param.fp_mdt_uuid,
2185 param.fp_num_alloc_mdts *
2186 sizeof(*param.fp_mdt_uuid));
2192 param.fp_mdt_uuid = tmp;
2194 param.fp_exclude_obd = !!neg_opt;
2195 param.fp_num_alloc_obds += len;
2196 tmp = realloc(param.fp_obd_uuid,
2197 param.fp_num_alloc_obds *
2198 sizeof(*param.fp_obd_uuid));
2204 param.fp_obd_uuid = tmp;
2206 for (token = buf; token && *token; token = next) {
2207 struct obd_uuid *puuid;
2210 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2213 ¶m.fp_obd_uuid[param.fp_num_obds++];
2215 p = strchr(token, ',');
2222 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2227 strncpy(puuid->uuid, token,
2228 sizeof(puuid->uuid));
2236 param.fp_zero_end = 1;
2240 case LFS_PROJID_OPT:
2241 rc = name2projid(¶m.fp_projid, optarg);
2243 param.fp_projid = strtoul(optarg, &endptr, 10);
2244 if (*endptr != '\0') {
2246 "Invalid project ID: %s",
2252 param.fp_exclude_projid = !!neg_opt;
2253 param.fp_check_projid = 1;
2256 if (optarg[0] == '+') {
2257 param.fp_size_sign = -1;
2259 } else if (optarg[0] == '-') {
2260 param.fp_size_sign = 1;
2264 ret = llapi_parse_size(optarg, ¶m.fp_size,
2265 ¶m.fp_size_units, 0);
2267 fprintf(stderr, "error: bad file size '%s'\n",
2271 param.fp_check_size = 1;
2272 param.fp_exclude_size = !!neg_opt;
2275 if (optarg[0] == '+') {
2276 param.fp_stripe_size_sign = -1;
2278 } else if (optarg[0] == '-') {
2279 param.fp_stripe_size_sign = 1;
2283 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2284 ¶m.fp_stripe_size_units, 0);
2286 fprintf(stderr, "error: bad stripe_size '%s'\n",
2290 param.fp_check_stripe_size = 1;
2291 param.fp_exclude_stripe_size = !!neg_opt;
2294 param.fp_exclude_type = !!neg_opt;
2295 switch (optarg[0]) {
2297 param.fp_type = S_IFBLK;
2300 param.fp_type = S_IFCHR;
2303 param.fp_type = S_IFDIR;
2306 param.fp_type = S_IFREG;
2309 param.fp_type = S_IFLNK;
2312 param.fp_type = S_IFIFO;
2315 param.fp_type = S_IFSOCK;
2318 fprintf(stderr, "error: %s: bad type '%s'\n",
2325 if (optarg[0] == '+') {
2326 param.fp_mdt_count_sign = -1;
2328 } else if (optarg[0] == '-') {
2329 param.fp_mdt_count_sign = 1;
2333 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2334 if (*endptr != '\0') {
2335 fprintf(stderr, "error: bad mdt_count '%s'\n",
2340 param.fp_check_mdt_count = 1;
2341 param.fp_exclude_mdt_count = !!neg_opt;
2349 if (pathstart == -1) {
2350 fprintf(stderr, "error: %s: no filename|pathname\n",
2354 } else if (pathend == -1) {
2360 rc = llapi_find(argv[pathstart], ¶m);
2361 if (rc != 0 && ret == 0)
2363 } while (++pathstart < pathend);
2366 fprintf(stderr, "error: %s failed for %s.\n",
2367 argv[0], argv[optind - 1]);
2369 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2370 free(param.fp_obd_uuid);
2372 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2373 free(param.fp_mdt_uuid);
2378 static int lfs_getstripe_internal(int argc, char **argv,
2379 struct find_param *param)
2381 struct option long_opts[] = {
2382 {"comp-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2383 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2384 {"comp-flags", optional_argument, 0, LFS_COMP_FLAGS_OPT},
2385 {"component-flags", optional_argument, 0, LFS_COMP_FLAGS_OPT},
2386 {"comp-start", optional_argument, 0, LFS_COMP_START_OPT},
2387 {"component-start", optional_argument, 0, LFS_COMP_START_OPT},
2388 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2389 /* This formerly implied "stripe-count", but was explicitly
2390 * made "stripe-count" for consistency with other options,
2391 * and to separate it from "mdt-count" when DNE arrives. */
2392 {"count", no_argument, 0, 'c'},
2394 {"stripe-count", no_argument, 0, 'c'},
2395 {"stripe_count", no_argument, 0, 'c'},
2396 {"directory", no_argument, 0, 'd'},
2397 {"default", no_argument, 0, 'D'},
2398 {"comp-end", optional_argument, 0, 'E'},
2399 {"component-end", optional_argument, 0, 'E'},
2400 {"fid", no_argument, 0, 'F'},
2401 {"generation", no_argument, 0, 'g'},
2402 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
2403 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2404 /* This formerly implied "stripe-index", but was explicitly
2405 * made "stripe-index" for consistency with other options,
2406 * and to separate it from "mdt-index" when DNE arrives. */
2407 {"index", no_argument, 0, 'i'},
2409 {"stripe-index", no_argument, 0, 'i'},
2410 {"stripe_index", no_argument, 0, 'i'},
2411 {"comp-id", optional_argument, 0, 'I'},
2412 {"component-id", optional_argument, 0, 'I'},
2413 {"layout", no_argument, 0, 'L'},
2414 {"mdt", no_argument, 0, 'm'},
2415 {"mdt-index", no_argument, 0, 'm'},
2416 {"mdt_index", no_argument, 0, 'm'},
2417 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2418 {"mdt-index", no_argument, 0, 'M'},
2419 {"mdt_index", no_argument, 0, 'M'},
2421 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2422 /* This formerly implied "stripe-index", but was confusing
2423 * with "file offset" (which will eventually be needed for
2424 * with different layouts by offset), so deprecate it. */
2425 {"offset", no_argument, 0, 'o'},
2427 {"obd", required_argument, 0, 'O'},
2428 {"ost", required_argument, 0, 'O'},
2429 {"pool", no_argument, 0, 'p'},
2430 {"quiet", no_argument, 0, 'q'},
2431 {"recursive", no_argument, 0, 'r'},
2432 {"raw", no_argument, 0, 'R'},
2433 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2434 /* This formerly implied "--stripe-size", but was confusing
2435 * with "lfs find --size|-s", which means "file size", so use
2436 * the consistent "--stripe-size|-S" for all commands. */
2437 {"size", no_argument, 0, 's'},
2439 {"stripe-size", no_argument, 0, 'S'},
2440 {"stripe_size", no_argument, 0, 'S'},
2441 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
2442 {"verbose", no_argument, 0, 'v'},
2443 {"yaml", no_argument, 0, 'y'},
2449 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2450 long_opts, NULL)) != -1) {
2453 if (strcmp(argv[optind - 1], "--count") == 0)
2454 fprintf(stderr, "warning: '--count' deprecated,"
2455 " use '--stripe-count' instead\n");
2456 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2457 param->fp_verbose |= VERBOSE_COUNT;
2458 param->fp_max_depth = 0;
2461 case LFS_COMP_COUNT_OPT:
2462 param->fp_verbose |= VERBOSE_COMP_COUNT;
2463 param->fp_max_depth = 0;
2465 case LFS_COMP_FLAGS_OPT:
2466 if (optarg != NULL) {
2467 __u32 *flags = ¶m->fp_comp_flags;
2468 rc = comp_str2flags(flags, optarg);
2470 fprintf(stderr, "error: %s bad "
2471 "component flags '%s'.\n",
2475 param->fp_check_comp_flags = 1;
2476 param->fp_exclude_comp_flags =
2477 comp_flags_is_neg(*flags);
2478 comp_flags_clear_neg(flags);
2481 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2482 param->fp_max_depth = 0;
2485 case LFS_COMP_START_OPT:
2486 if (optarg != NULL) {
2488 if (tmp[0] == '+') {
2489 param->fp_comp_start_sign = -1;
2491 } else if (tmp[0] == '-') {
2492 param->fp_comp_start_sign = 1;
2495 rc = llapi_parse_size(tmp,
2496 ¶m->fp_comp_start,
2497 ¶m->fp_comp_start_units, 0);
2499 fprintf(stderr, "error: %s bad "
2500 "component start '%s'.\n",
2504 param->fp_check_comp_start = 1;
2507 param->fp_verbose |= VERBOSE_COMP_START;
2508 param->fp_max_depth = 0;
2512 param->fp_max_depth = 0;
2515 param->fp_get_default_lmv = 1;
2518 if (optarg != NULL) {
2520 if (tmp[0] == '+') {
2521 param->fp_comp_end_sign = -1;
2523 } else if (tmp[0] == '-') {
2524 param->fp_comp_end_sign = 1;
2528 if (arg_is_eof(tmp)) {
2529 param->fp_comp_end = LUSTRE_EOF;
2530 param->fp_comp_end_units = 1;
2533 rc = llapi_parse_size(tmp,
2534 ¶m->fp_comp_end,
2535 ¶m->fp_comp_end_units, 0);
2538 fprintf(stderr, "error: %s bad "
2539 "component end '%s'.\n",
2543 param->fp_check_comp_end = 1;
2545 param->fp_verbose |= VERBOSE_COMP_END;
2546 param->fp_max_depth = 0;
2550 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2551 param->fp_verbose |= VERBOSE_DFID;
2552 param->fp_max_depth = 0;
2556 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2557 param->fp_verbose |= VERBOSE_GENERATION;
2558 param->fp_max_depth = 0;
2561 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2563 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2564 "use '--stripe-index|-i' instead\n");
2567 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2568 if (strcmp(argv[optind - 1], "--index") == 0)
2569 fprintf(stderr, "warning: '--index' deprecated"
2570 ", use '--stripe-index' instead\n");
2572 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2573 param->fp_verbose |= VERBOSE_OFFSET;
2574 param->fp_max_depth = 0;
2578 if (optarg != NULL) {
2579 param->fp_comp_id = strtoul(optarg, &end, 0);
2580 if (*end != '\0' || param->fp_comp_id == 0 ||
2581 param->fp_comp_id > LCME_ID_MAX) {
2582 fprintf(stderr, "error: %s bad "
2583 "component id '%s'\n",
2587 param->fp_check_comp_id = 1;
2590 param->fp_max_depth = 0;
2591 param->fp_verbose |= VERBOSE_COMP_ID;
2595 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2596 param->fp_verbose |= VERBOSE_LAYOUT;
2597 param->fp_max_depth = 0;
2600 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2602 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2603 fprintf(stderr, "warning: '-M' deprecated"
2604 ", use '-m' instead\n");
2608 if (!(param->fp_verbose & VERBOSE_DETAIL))
2609 param->fp_max_depth = 0;
2610 param->fp_verbose |= VERBOSE_MDTINDEX;
2613 if (param->fp_obd_uuid) {
2615 "error: %s: only one obduuid allowed",
2619 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2622 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2623 param->fp_verbose |= VERBOSE_POOL;
2624 param->fp_max_depth = 0;
2631 param->fp_recursive = 1;
2636 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2638 fprintf(stderr, "warning: '--size|-s' deprecated, "
2639 "use '--stripe-size|-S' instead\n");
2640 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2642 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2643 param->fp_verbose |= VERBOSE_SIZE;
2644 param->fp_max_depth = 0;
2648 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2661 if (param->fp_recursive)
2662 param->fp_max_depth = -1;
2663 else if (param->fp_verbose & VERBOSE_DETAIL)
2664 param->fp_max_depth = 1;
2666 if (!param->fp_verbose)
2667 param->fp_verbose = VERBOSE_DEFAULT;
2668 if (param->fp_quiet)
2669 param->fp_verbose = VERBOSE_OBJID;
2672 rc = llapi_getstripe(argv[optind], param);
2673 } while (++optind < argc && !rc);
2676 fprintf(stderr, "error: %s failed for %s.\n",
2677 argv[0], argv[optind - 1]);
2681 static int lfs_tgts(int argc, char **argv)
2683 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2684 struct find_param param;
2685 int index = 0, rc=0;
2690 if (argc == 2 && !realpath(argv[1], path)) {
2692 fprintf(stderr, "error: invalid path '%s': %s\n",
2693 argv[1], strerror(-rc));
2697 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2698 /* Check if we have a mount point */
2699 if (mntdir[0] == '\0')
2702 memset(¶m, 0, sizeof(param));
2703 if (!strcmp(argv[0], "mdts"))
2704 param.fp_get_lmv = 1;
2706 rc = llapi_ostlist(mntdir, ¶m);
2708 fprintf(stderr, "error: %s: failed on %s\n",
2711 if (path[0] != '\0')
2713 memset(mntdir, 0, PATH_MAX);
2719 static int lfs_getstripe(int argc, char **argv)
2721 struct find_param param = { 0 };
2723 param.fp_max_depth = 1;
2724 return lfs_getstripe_internal(argc, argv, ¶m);
2728 static int lfs_getdirstripe(int argc, char **argv)
2730 struct find_param param = { 0 };
2731 struct option long_opts[] = {
2732 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2733 {"mdt-count", no_argument, 0, 'c'},
2735 {"mdt-hash", no_argument, 0, 'H'},
2736 {"mdt-index", no_argument, 0, 'i'},
2737 {"recursive", no_argument, 0, 'r'},
2738 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2739 {"mdt-hash", no_argument, 0, 't'},
2741 {"default", no_argument, 0, 'D'},
2742 {"obd", required_argument, 0, 'O'},
2743 {"mdt-count", no_argument, 0, 'T'},
2744 {"yaml", no_argument, 0, 'y'},
2749 param.fp_get_lmv = 1;
2751 while ((c = getopt_long(argc, argv,
2752 "cDHiO:rtTy", long_opts, NULL)) != -1)
2756 if (param.fp_obd_uuid) {
2758 "error: %s: only one obduuid allowed",
2762 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2764 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2766 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2767 fprintf(stderr, "warning: '-c' deprecated"
2768 ", use '-T' instead\n");
2772 param.fp_verbose |= VERBOSE_COUNT;
2775 param.fp_verbose |= VERBOSE_OFFSET;
2777 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2781 param.fp_verbose |= VERBOSE_HASH_TYPE;
2784 param.fp_get_default_lmv = 1;
2787 param.fp_recursive = 1;
2800 if (param.fp_recursive)
2801 param.fp_max_depth = -1;
2803 if (!param.fp_verbose)
2804 param.fp_verbose = VERBOSE_DEFAULT;
2807 rc = llapi_getstripe(argv[optind], ¶m);
2808 } while (++optind < argc && !rc);
2811 fprintf(stderr, "error: %s failed for %s.\n",
2812 argv[0], argv[optind - 1]);
2817 static int lfs_setdirstripe(int argc, char **argv)
2821 unsigned int stripe_offset = -1;
2822 unsigned int stripe_count = 1;
2823 enum lmv_hash_type hash_type;
2826 char *stripe_offset_opt = NULL;
2827 char *stripe_count_opt = NULL;
2828 char *stripe_hash_opt = NULL;
2829 char *mode_opt = NULL;
2830 bool default_stripe = false;
2831 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2832 mode_t previous_mode = 0;
2833 bool delete = false;
2835 struct option long_opts[] = {
2836 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2837 {"count", required_argument, 0, 'c'},
2839 {"mdt-count", required_argument, 0, 'c'},
2840 {"delete", no_argument, 0, 'd'},
2841 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2842 {"index", required_argument, 0, 'i'},
2844 {"mdt-index", required_argument, 0, 'i'},
2845 {"mode", required_argument, 0, 'm'},
2846 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2847 {"hash-type", required_argument, 0, 't'},
2848 {"mdt-hash", required_argument, 0, 't'},
2850 {"mdt-hash", required_argument, 0, 'H'},
2851 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2852 {"default_stripe", no_argument, 0, 'D'},
2854 {"default", no_argument, 0, 'D'},
2858 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2865 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2866 if (strcmp(argv[optind - 1], "--count") == 0)
2867 fprintf(stderr, "warning: '--count' deprecated"
2868 ", use '--mdt-count' instead\n");
2870 stripe_count_opt = optarg;
2874 default_stripe = true;
2877 default_stripe = true;
2880 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2881 if (strcmp(argv[optind - 1], "--index") == 0)
2882 fprintf(stderr, "warning: '--index' deprecated"
2883 ", use '--mdt-index' instead\n");
2885 stripe_offset_opt = optarg;
2890 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2894 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2895 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2896 fprintf(stderr, "warning: '--hash-type' "
2897 "deprecated, use '--mdt-hash' "
2900 stripe_hash_opt = optarg;
2903 fprintf(stderr, "error: %s: option '%s' "
2905 argv[0], argv[optind - 1]);
2910 if (optind == argc) {
2911 fprintf(stderr, "error: %s: missing dirname\n",
2916 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2917 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2922 if (stripe_offset_opt != NULL) {
2923 /* get the stripe offset */
2924 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2926 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2927 argv[0], stripe_offset_opt);
2933 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2934 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2935 " or -i options.\n", argv[0]);
2943 if (mode_opt != NULL) {
2944 mode = strtoul(mode_opt, &end, 8);
2946 fprintf(stderr, "error: %s: bad mode '%s'\n",
2950 previous_mode = umask(0);
2953 if (stripe_hash_opt == NULL) {
2954 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2956 hash_type = check_hashtype(stripe_hash_opt);
2957 if (hash_type == 0) {
2959 "error: %s: bad stripe hash type '%s'\n",
2960 argv[0], stripe_hash_opt);
2965 /* get the stripe count */
2966 if (stripe_count_opt != NULL) {
2967 stripe_count = strtoul(stripe_count_opt, &end, 0);
2969 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2970 argv[0], stripe_count_opt);
2975 dname = argv[optind];
2977 if (default_stripe) {
2978 result = llapi_dir_set_default_lmv_stripe(dname,
2979 stripe_offset, stripe_count,
2982 result = llapi_dir_create_pool(dname, mode,
2984 stripe_count, hash_type,
2989 fprintf(stderr, "error: %s: create stripe dir '%s' "
2990 "failed\n", argv[0], dname);
2993 dname = argv[++optind];
2994 } while (dname != NULL);
2996 if (mode_opt != NULL)
2997 umask(previous_mode);
3003 static int lfs_rmentry(int argc, char **argv)
3010 fprintf(stderr, "error: %s: missing dirname\n",
3016 dname = argv[index];
3017 while (dname != NULL) {
3018 result = llapi_direntry_remove(dname);
3020 fprintf(stderr, "error: %s: remove dir entry '%s' "
3021 "failed\n", argv[0], dname);
3024 dname = argv[++index];
3029 static int lfs_mv(int argc, char **argv)
3031 struct find_param param = {
3038 struct option long_opts[] = {
3039 {"mdt-index", required_argument, 0, 'M'},
3040 {"verbose", no_argument, 0, 'v'},
3044 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3047 param.fp_mdt_index = strtoul(optarg, &end, 0);
3049 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3056 param.fp_verbose = VERBOSE_DETAIL;
3060 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3061 argv[0], argv[optind - 1]);
3066 if (param.fp_mdt_index == -1) {
3067 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3071 if (optind >= argc) {
3072 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3076 param.fp_migrate = 1;
3077 rc = llapi_migrate_mdt(argv[optind], ¶m);
3079 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3080 argv[0], argv[optind], param.fp_mdt_index,
3085 static int lfs_osts(int argc, char **argv)
3087 return lfs_tgts(argc, argv);
3090 static int lfs_mdts(int argc, char **argv)
3092 return lfs_tgts(argc, argv);
3095 #define COOK(value) \
3098 while (value > 1024) { \
3106 #define CDF "%11llu"
3107 #define HDF "%8.1f%c"
3112 MNTDF_INODES = 0x0001,
3113 MNTDF_COOKED = 0x0002,
3114 MNTDF_LAZY = 0x0004,
3115 MNTDF_VERBOSE = 0x0008,
3118 static int showdf(char *mntdir, struct obd_statfs *stat,
3119 char *uuid, enum mntdf_flags flags,
3120 char *type, int index, int rc)
3122 long long avail, used, total;
3124 char *suffix = "KMGTPEZY";
3125 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3126 char tbuf[3 * sizeof(__u64)];
3127 char ubuf[3 * sizeof(__u64)];
3128 char abuf[3 * sizeof(__u64)];
3129 char rbuf[3 * sizeof(__u64)];
3136 if (flags & MNTDF_INODES) {
3137 avail = stat->os_ffree;
3138 used = stat->os_files - stat->os_ffree;
3139 total = stat->os_files;
3141 int shift = flags & MNTDF_COOKED ? 0 : 10;
3143 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3144 used = ((stat->os_blocks - stat->os_bfree) *
3145 stat->os_bsize) >> shift;
3146 total = (stat->os_blocks * stat->os_bsize) >> shift;
3149 if ((used + avail) > 0)
3150 ratio = (double)used / (double)(used + avail);
3152 if (flags & MNTDF_COOKED) {
3156 cook_val = (double)total;
3159 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3162 snprintf(tbuf, sizeof(tbuf), CDF, total);
3164 cook_val = (double)used;
3167 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3170 snprintf(ubuf, sizeof(ubuf), CDF, used);
3172 cook_val = (double)avail;
3175 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3178 snprintf(abuf, sizeof(abuf), CDF, avail);
3180 snprintf(tbuf, sizeof(tbuf), CDF, total);
3181 snprintf(ubuf, sizeof(tbuf), CDF, used);
3182 snprintf(abuf, sizeof(tbuf), CDF, avail);
3185 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3186 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3187 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3189 printf("[%s:%d]", type, index);
3191 if (stat->os_state) {
3193 * Each character represents the matching
3196 const char state_names[] = "DRSI";
3201 for (i = 0, state = stat->os_state;
3202 state && i < sizeof(state_names); i++) {
3203 if (!(state & (1 << i)))
3205 printf("%c", state_names[i]);
3213 printf(UUF": inactive device\n", uuid);
3216 printf(UUF": %s\n", uuid, strerror(-rc));
3223 struct ll_stat_type {
3228 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3230 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3231 struct obd_uuid uuid_buf;
3232 char *poolname = NULL;
3233 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3234 { LL_STATFS_LOV, "OST" },
3236 struct ll_stat_type *tp;
3237 __u64 ost_ffree = 0;
3245 poolname = strchr(pool, '.');
3246 if (poolname != NULL) {
3247 if (strncmp(fsname, pool, strlen(fsname))) {
3248 fprintf(stderr, "filesystem name incorrect\n");
3256 fd = open(mntdir, O_RDONLY);
3259 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3264 if (flags & MNTDF_INODES)
3265 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3266 "UUID", "Inodes", "IUsed", "IFree",
3267 "IUse%", "Mounted on");
3269 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3270 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3271 "Used", "Available", "Use%", "Mounted on");
3273 for (tp = types; tp->st_name != NULL; tp++) {
3274 for (index = 0; ; index++) {
3275 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3276 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3277 type = flags & MNTDF_LAZY ?
3278 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3279 rc2 = llapi_obd_fstatfs(fd, type, index,
3280 &stat_buf, &uuid_buf);
3285 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3286 if (!(flags & MNTDF_VERBOSE))
3288 } else if (rc2 < 0 && rc == 0) {
3292 if (poolname && tp->st_op == LL_STATFS_LOV &&
3293 llapi_search_ost(fsname, poolname,
3294 obd_uuid2str(&uuid_buf)) != 1)
3297 /* the llapi_obd_statfs() call may have returned with
3298 * an error, but if it filled in uuid_buf we will at
3299 * lease use that to print out a message for that OBD.
3300 * If we didn't get anything in the uuid_buf, then fill
3301 * it in so that we can print an error message. */
3302 if (uuid_buf.uuid[0] == '\0')
3303 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3304 "%s%04x", tp->st_name, index);
3305 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3306 flags, tp->st_name, index, rc2);
3309 if (tp->st_op == LL_STATFS_LMV) {
3310 sum.os_ffree += stat_buf.os_ffree;
3311 sum.os_files += stat_buf.os_files;
3312 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3313 sum.os_blocks += stat_buf.os_blocks *
3315 sum.os_bfree += stat_buf.os_bfree *
3317 sum.os_bavail += stat_buf.os_bavail *
3319 ost_ffree += stat_buf.os_ffree;
3327 /* If we don't have as many objects free on the OST as inodes
3328 * on the MDS, we reduce the total number of inodes to
3329 * compensate, so that the "inodes in use" number is correct.
3330 * Matches ll_statfs_internal() so the results are consistent. */
3331 if (ost_ffree < sum.os_ffree) {
3332 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3333 sum.os_ffree = ost_ffree;
3336 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3342 static int lfs_df(int argc, char **argv)
3344 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3345 enum mntdf_flags flags = 0;
3346 int c, rc = 0, index = 0;
3347 char fsname[PATH_MAX] = "", *pool_name = NULL;
3348 struct option long_opts[] = {
3349 {"human-readable", 0, 0, 'h'},
3350 {"inodes", 0, 0, 'i'},
3351 {"lazy", 0, 0, 'l'},
3352 {"pool", required_argument, 0, 'p'},
3353 {"verbose", 0, 0, 'v'},
3357 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3360 flags |= MNTDF_COOKED;
3363 flags |= MNTDF_INODES;
3366 flags |= MNTDF_LAZY;
3372 flags |= MNTDF_VERBOSE;
3378 if (optind < argc && !realpath(argv[optind], path)) {
3380 fprintf(stderr, "error: invalid path '%s': %s\n",
3381 argv[optind], strerror(-rc));
3385 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3386 /* Check if we have a mount point */
3387 if (mntdir[0] == '\0')
3390 rc = mntdf(mntdir, fsname, pool_name, flags);
3391 if (rc || path[0] != '\0')
3393 fsname[0] = '\0'; /* avoid matching in next loop */
3394 mntdir[0] = '\0'; /* avoid matching in next loop */
3400 static int lfs_getname(int argc, char **argv)
3402 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3403 int rc = 0, index = 0, c;
3404 char buf[sizeof(struct obd_uuid)];
3406 while ((c = getopt(argc, argv, "h")) != -1)
3409 if (optind == argc) { /* no paths specified, get all paths. */
3410 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3411 rc = llapi_getname(mntdir, buf, sizeof(buf));
3414 "cannot get name for `%s': %s\n",
3415 mntdir, strerror(-rc));
3419 printf("%s %s\n", buf, mntdir);
3421 path[0] = fsname[0] = mntdir[0] = 0;
3423 } else { /* paths specified, only attempt to search these. */
3424 for (; optind < argc; optind++) {
3425 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3428 "cannot get name for `%s': %s\n",
3429 argv[optind], strerror(-rc));
3433 printf("%s %s\n", buf, argv[optind]);
3439 static int lfs_check(int argc, char **argv)
3442 char mntdir[PATH_MAX] = {'\0'};
3451 obd_types[0] = obd_type1;
3452 obd_types[1] = obd_type2;
3454 if (strcmp(argv[1], "osts") == 0) {
3455 strcpy(obd_types[0], "osc");
3456 } else if (strcmp(argv[1], "mds") == 0) {
3457 strcpy(obd_types[0], "mdc");
3458 } else if (strcmp(argv[1], "servers") == 0) {
3460 strcpy(obd_types[0], "osc");
3461 strcpy(obd_types[1], "mdc");
3463 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3468 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3469 if (rc < 0 || mntdir[0] == '\0') {
3470 fprintf(stderr, "No suitable Lustre mount found\n");
3474 rc = llapi_target_check(num_types, obd_types, mntdir);
3476 fprintf(stderr, "error: %s: %s status failed\n",
3483 #ifdef HAVE_SYS_QUOTA_H
3484 #define ARG2INT(nr, str, msg) \
3487 nr = strtol(str, &endp, 0); \
3489 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3494 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3496 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3497 * returns the value or ULONG_MAX on integer overflow or incorrect format
3499 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3500 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3501 * 3. empty integer value is interpreted as 0
3503 static unsigned long str2sec(const char* timestr)
3505 const char spec[] = "smhdw";
3506 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3507 unsigned long val = 0;
3510 if (strpbrk(timestr, spec) == NULL) {
3511 /* no specifiers inside the time string,
3512 should treat it as an integer value */
3513 val = strtoul(timestr, &tail, 10);
3514 return *tail ? ULONG_MAX : val;
3517 /* format string is XXwXXdXXhXXmXXs */
3523 v = strtoul(timestr, &tail, 10);
3524 if (v == ULONG_MAX || *tail == '\0')
3525 /* value too large (ULONG_MAX or more)
3526 or missing specifier */
3529 ptr = strchr(spec, *tail);
3531 /* unknown specifier */
3536 /* check if product will overflow the type */
3537 if (!(v < ULONG_MAX / mult[ind]))
3540 ADD_OVERFLOW(val, mult[ind] * v);
3541 if (val == ULONG_MAX)
3553 #define ARG2ULL(nr, str, def_units) \
3555 unsigned long long limit, units = def_units; \
3558 rc = llapi_parse_size(str, &limit, &units, 1); \
3560 fprintf(stderr, "error: bad limit value %s\n", str); \
3566 static inline int has_times_option(int argc, char **argv)
3570 for (i = 1; i < argc; i++)
3571 if (!strcmp(argv[i], "-t"))
3577 int lfs_setquota_times(int argc, char **argv)
3580 struct if_quotactl qctl;
3581 char *mnt, *obd_type = (char *)qctl.obd_type;
3582 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3583 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3584 struct option long_opts[] = {
3585 {"block-grace", required_argument, 0, 'b'},
3586 {"group", no_argument, 0, 'g'},
3587 {"inode-grace", required_argument, 0, 'i'},
3588 {"projid", no_argument, 0, 'p'},
3589 {"times", no_argument, 0, 't'},
3590 {"user", no_argument, 0, 'u'},
3595 memset(&qctl, 0, sizeof(qctl));
3596 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3597 qctl.qc_type = ALLQUOTA;
3599 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3600 long_opts, NULL)) != -1) {
3611 if (qctl.qc_type != ALLQUOTA) {
3612 fprintf(stderr, "error: -u/g/p can't be used "
3613 "more than once\n");
3616 qctl.qc_type = qtype;
3619 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3620 fprintf(stderr, "error: bad block-grace: %s\n",
3624 dqb->dqb_valid |= QIF_BTIME;
3627 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3628 fprintf(stderr, "error: bad inode-grace: %s\n",
3632 dqb->dqb_valid |= QIF_ITIME;
3634 case 't': /* Yes, of course! */
3636 default: /* getopt prints error message for us when opterr != 0 */
3641 if (qctl.qc_type == ALLQUOTA) {
3642 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3646 if (optind != argc - 1) {
3647 fprintf(stderr, "error: unexpected parameters encountered\n");
3652 rc = llapi_quotactl(mnt, &qctl);
3655 fprintf(stderr, "%s %s ", obd_type,
3656 obd_uuid2str(&qctl.obd_uuid));
3657 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3664 #define BSLIMIT (1 << 0)
3665 #define BHLIMIT (1 << 1)
3666 #define ISLIMIT (1 << 2)
3667 #define IHLIMIT (1 << 3)
3669 int lfs_setquota(int argc, char **argv)
3672 struct if_quotactl qctl;
3673 char *mnt, *obd_type = (char *)qctl.obd_type;
3674 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3675 struct option long_opts[] = {
3676 {"block-softlimit", required_argument, 0, 'b'},
3677 {"block-hardlimit", required_argument, 0, 'B'},
3678 {"group", required_argument, 0, 'g'},
3679 {"inode-softlimit", required_argument, 0, 'i'},
3680 {"inode-hardlimit", required_argument, 0, 'I'},
3681 {"user", required_argument, 0, 'u'},
3682 {"projid", required_argument, 0, 'p'},
3685 unsigned limit_mask = 0;
3689 if (has_times_option(argc, argv))
3690 return lfs_setquota_times(argc, argv);
3692 memset(&qctl, 0, sizeof(qctl));
3693 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3694 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3695 * so it can be used as a marker that qc_type
3696 * isn't reinitialized from command line */
3698 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3699 long_opts, NULL)) != -1) {
3703 rc = name2uid(&qctl.qc_id, optarg);
3707 rc = name2gid(&qctl.qc_id, optarg);
3711 rc = name2projid(&qctl.qc_id, optarg);
3713 if (qctl.qc_type != ALLQUOTA) {
3714 fprintf(stderr, "error: -u and -g can't be used"
3715 " more than once\n");
3718 qctl.qc_type = qtype;
3720 qctl.qc_id = strtoul(optarg, &endptr, 10);
3721 if (*endptr != '\0') {
3722 fprintf(stderr, "error: can't find id "
3723 "for name %s\n", optarg);
3729 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3730 dqb->dqb_bsoftlimit >>= 10;
3731 limit_mask |= BSLIMIT;
3732 if (dqb->dqb_bsoftlimit &&
3733 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3734 fprintf(stderr, "warning: block softlimit is "
3735 "smaller than the miminal qunit size, "
3736 "please see the help of setquota or "
3737 "Lustre manual for details.\n");
3740 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3741 dqb->dqb_bhardlimit >>= 10;
3742 limit_mask |= BHLIMIT;
3743 if (dqb->dqb_bhardlimit &&
3744 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3745 fprintf(stderr, "warning: block hardlimit is "
3746 "smaller than the miminal qunit size, "
3747 "please see the help of setquota or "
3748 "Lustre manual for details.\n");
3751 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3752 limit_mask |= ISLIMIT;
3753 if (dqb->dqb_isoftlimit &&
3754 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3755 fprintf(stderr, "warning: inode softlimit is "
3756 "smaller than the miminal qunit size, "
3757 "please see the help of setquota or "
3758 "Lustre manual for details.\n");
3761 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3762 limit_mask |= IHLIMIT;
3763 if (dqb->dqb_ihardlimit &&
3764 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3765 fprintf(stderr, "warning: inode hardlimit is "
3766 "smaller than the miminal qunit size, "
3767 "please see the help of setquota or "
3768 "Lustre manual for details.\n");
3770 default: /* getopt prints error message for us when opterr != 0 */
3775 if (qctl.qc_type == ALLQUOTA) {
3776 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3780 if (limit_mask == 0) {
3781 fprintf(stderr, "error: at least one limit must be specified\n");
3785 if (optind != argc - 1) {
3786 fprintf(stderr, "error: unexpected parameters encountered\n");
3792 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3793 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3794 /* sigh, we can't just set blimits/ilimits */
3795 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3796 .qc_type = qctl.qc_type,
3797 .qc_id = qctl.qc_id};
3799 rc = llapi_quotactl(mnt, &tmp_qctl);
3801 fprintf(stderr, "error: setquota failed while retrieving"
3802 " current quota settings (%s)\n",
3807 if (!(limit_mask & BHLIMIT))
3808 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3809 if (!(limit_mask & BSLIMIT))
3810 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3811 if (!(limit_mask & IHLIMIT))
3812 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3813 if (!(limit_mask & ISLIMIT))
3814 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3816 /* Keep grace times if we have got no softlimit arguments */
3817 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3818 dqb->dqb_valid |= QIF_BTIME;
3819 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3822 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3823 dqb->dqb_valid |= QIF_ITIME;
3824 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3828 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3829 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3831 rc = llapi_quotactl(mnt, &qctl);
3834 fprintf(stderr, "%s %s ", obd_type,
3835 obd_uuid2str(&qctl.obd_uuid));
3836 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3843 /* Converts seconds value into format string
3844 * result is returned in buf
3846 * 1. result is in descenting order: 1w2d3h4m5s
3847 * 2. zero fields are not filled (except for p. 3): 5d1s
3848 * 3. zero seconds value is presented as "0s"
3850 static char * __sec2str(time_t seconds, char *buf)
3852 const char spec[] = "smhdw";
3853 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3858 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3859 c = seconds / mult[i];
3861 if (c > 0 || (i == 0 && buf == tail))
3862 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3870 static void sec2str(time_t seconds, char *buf, int rc)
3877 tail = __sec2str(seconds, tail);
3879 if (rc && tail - buf < 39) {
3885 static void diff2str(time_t seconds, char *buf, time_t now)
3891 if (seconds <= now) {
3892 strcpy(buf, "none");
3895 __sec2str(seconds - now, buf);
3898 static void print_quota_title(char *name, struct if_quotactl *qctl,
3899 bool human_readable)
3901 printf("Disk quotas for %s %s (%cid %u):\n",
3902 qtype_name(qctl->qc_type), name,
3903 *qtype_name(qctl->qc_type), qctl->qc_id);
3904 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3905 "Filesystem", human_readable ? "used" : "kbytes",
3906 "quota", "limit", "grace",
3907 "files", "quota", "limit", "grace");
3910 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3913 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3916 snprintf(buf, buflen, "%5.4gP",
3917 (double)num / ((__u64)1 << 40));
3919 snprintf(buf, buflen, "%5.4gT",
3920 (double)num / (1 << 30));
3922 snprintf(buf, buflen, "%5.4gG",
3923 (double)num / (1 << 20));
3925 snprintf(buf, buflen, "%5.4gM",
3926 (double)num / (1 << 10));
3928 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3932 #define STRBUF_LEN 32
3933 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3940 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3941 int bover = 0, iover = 0;
3942 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3943 char numbuf[3][STRBUF_LEN];
3945 char strbuf[STRBUF_LEN];
3947 if (dqb->dqb_bhardlimit &&
3948 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3950 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3951 if (dqb->dqb_btime > now) {
3958 if (dqb->dqb_ihardlimit &&
3959 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3961 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3962 if (dqb->dqb_itime > now) {
3970 if (strlen(mnt) > 15)
3971 printf("%s\n%15s", mnt, "");
3973 printf("%15s", mnt);
3976 diff2str(dqb->dqb_btime, timebuf, now);
3978 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3979 strbuf, sizeof(strbuf), h);
3980 if (rc == -EREMOTEIO)
3981 sprintf(numbuf[0], "%s*", strbuf);
3983 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3984 "%s" : "[%s]", strbuf);
3986 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3987 if (type == QC_GENERAL)
3988 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3989 "%s" : "[%s]", strbuf);
3991 sprintf(numbuf[1], "%s", "-");
3993 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3994 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3995 "%s" : "[%s]", strbuf);
3997 printf(" %7s%c %6s %7s %7s",
3998 numbuf[0], bover ? '*' : ' ', numbuf[1],
3999 numbuf[2], bover > 1 ? timebuf : "-");
4002 diff2str(dqb->dqb_itime, timebuf, now);
4004 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4005 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4007 if (type == QC_GENERAL)
4008 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4010 (uintmax_t)dqb->dqb_isoftlimit);
4012 sprintf(numbuf[1], "%s", "-");
4014 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4015 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4017 if (type != QC_OSTIDX)
4018 printf(" %7s%c %6s %7s %7s",
4019 numbuf[0], iover ? '*' : ' ', numbuf[1],
4020 numbuf[2], iover > 1 ? timebuf : "-");
4022 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4025 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4026 qctl->qc_cmd == Q_GETOINFO) {
4030 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4031 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4032 printf("Block grace time: %s; Inode grace time: %s\n",
4033 bgtimebuf, igtimebuf);
4037 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4038 bool h, __u64 *total)
4040 int rc = 0, rc1 = 0, count = 0;
4041 __u32 valid = qctl->qc_valid;
4043 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4045 fprintf(stderr, "can not get %s count: %s\n",
4046 is_mdt ? "mdt": "ost", strerror(-rc));
4050 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4051 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4052 rc = llapi_quotactl(mnt, qctl);
4054 /* It is remote client case. */
4055 if (rc == -EOPNOTSUPP) {
4062 fprintf(stderr, "quotactl %s%d failed.\n",
4063 is_mdt ? "mdt": "ost", qctl->qc_idx);
4067 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4068 qctl->qc_valid, 0, h);
4069 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4070 qctl->qc_dqblk.dqb_bhardlimit;
4073 qctl->qc_valid = valid;
4077 static int lfs_quota(int argc, char **argv)
4080 char *mnt, *name = NULL;
4081 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4082 .qc_type = ALLQUOTA };
4083 char *obd_type = (char *)qctl.obd_type;
4084 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4085 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4086 verbose = 0, pass = 0, quiet = 0, inacc;
4088 __u32 valid = QC_GENERAL, idx = 0;
4089 __u64 total_ialloc = 0, total_balloc = 0;
4090 bool human_readable = false;
4093 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4104 if (qctl.qc_type != ALLQUOTA) {
4105 fprintf(stderr, "error: use either -u or -g\n");
4108 qctl.qc_type = qtype;
4111 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4114 valid = qctl.qc_valid = QC_UUID;
4115 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4118 valid = qctl.qc_valid = QC_MDTIDX;
4119 idx = qctl.qc_idx = atoi(optarg);
4122 valid = qctl.qc_valid = QC_OSTIDX;
4123 idx = qctl.qc_idx = atoi(optarg);
4132 human_readable = true;
4135 fprintf(stderr, "error: %s: option '-%c' "
4136 "unrecognized\n", argv[0], c);
4141 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4142 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4143 optind == argc - 1) {
4145 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4146 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4147 qctl.qc_valid = valid;
4149 qctl.qc_type = pass;
4150 switch (qctl.qc_type) {
4152 qctl.qc_id = geteuid();
4153 rc = uid2name(&name, qctl.qc_id);
4156 qctl.qc_id = getegid();
4157 rc = gid2name(&name, qctl.qc_id);
4166 /* lfs quota -u username /path/to/lustre/mount */
4167 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4168 /* options should be followed by u/g-name and mntpoint */
4169 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4170 fprintf(stderr, "error: missing quota argument(s)\n");
4174 name = argv[optind++];
4175 switch (qctl.qc_type) {
4177 rc = name2uid(&qctl.qc_id, name);
4180 rc = name2gid(&qctl.qc_id, name);
4183 rc = name2projid(&qctl.qc_id, name);
4190 qctl.qc_id = strtoul(name, &endptr, 10);
4191 if (*endptr != '\0') {
4192 fprintf(stderr, "error: can't find id for name: %s\n",
4197 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4198 fprintf(stderr, "error: missing quota info argument(s)\n");
4203 rc1 = llapi_quotactl(mnt, &qctl);
4207 fprintf(stderr, "%s quotas are not enabled.\n",
4208 qtype_name(qctl.qc_type));
4211 fprintf(stderr, "Permission denied.\n");
4214 /* We already got error message. */
4217 fprintf(stderr, "Unexpected quotactl error: %s\n",
4222 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4223 print_quota_title(name, &qctl, human_readable);
4225 if (rc1 && *obd_type)
4226 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4228 if (qctl.qc_valid != QC_GENERAL)
4231 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4232 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4233 (QIF_LIMITS|QIF_USAGE));
4235 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4237 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4239 char strbuf[STRBUF_LEN];
4241 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4243 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4245 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4247 printf("Total allocated inode limit: %ju, total "
4248 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4252 if (rc1 || rc2 || rc3 || inacc)
4253 printf("Some errors happened when getting quota info. "
4254 "Some devices may be not working or deactivated. "
4255 "The data in \"[]\" is inaccurate.\n");
4258 if (pass > 0 && pass < LL_MAXQUOTAS)
4263 #endif /* HAVE_SYS_QUOTA_H! */
4265 static int flushctx_ioctl(char *mp)
4269 fd = open(mp, O_RDONLY);
4271 fprintf(stderr, "flushctx: error open %s: %s\n",
4272 mp, strerror(errno));
4276 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4278 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4279 mp, strerror(errno));
4285 static int lfs_flushctx(int argc, char **argv)
4287 int kdestroy = 0, c;
4288 char mntdir[PATH_MAX] = {'\0'};
4292 while ((c = getopt(argc, argv, "k")) != -1) {
4298 fprintf(stderr, "error: %s: option '-%c' "
4299 "unrecognized\n", argv[0], c);
4305 if ((rc = system("kdestroy > /dev/null")) != 0) {
4306 rc = WEXITSTATUS(rc);
4307 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4311 if (optind >= argc) {
4312 /* flush for all mounted lustre fs. */
4313 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4314 /* Check if we have a mount point */
4315 if (mntdir[0] == '\0')
4318 if (flushctx_ioctl(mntdir))
4321 mntdir[0] = '\0'; /* avoid matching in next loop */
4324 /* flush fs as specified */
4325 while (optind < argc) {
4326 if (flushctx_ioctl(argv[optind++]))
4333 static int lfs_cp(int argc, char **argv)
4335 fprintf(stderr, "remote client copy file(s).\n"
4336 "obsolete, does not support it anymore.\n");
4340 static int lfs_ls(int argc, char **argv)
4342 fprintf(stderr, "remote client lists directory contents.\n"
4343 "obsolete, does not support it anymore.\n");
4347 static int lfs_changelog(int argc, char **argv)
4349 void *changelog_priv;
4350 struct changelog_rec *rec;
4351 long long startrec = 0, endrec = 0;
4353 struct option long_opts[] = {
4354 {"follow", no_argument, 0, 'f'},
4357 char short_opts[] = "f";
4360 while ((rc = getopt_long(argc, argv, short_opts,
4361 long_opts, NULL)) != -1) {
4369 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4370 argv[0], argv[optind - 1]);
4377 mdd = argv[optind++];
4379 startrec = strtoll(argv[optind++], NULL, 10);
4381 endrec = strtoll(argv[optind++], NULL, 10);
4383 rc = llapi_changelog_start(&changelog_priv,
4384 CHANGELOG_FLAG_BLOCK |
4385 CHANGELOG_FLAG_JOBID |
4386 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4389 fprintf(stderr, "Can't start changelog: %s\n",
4390 strerror(errno = -rc));
4394 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4398 if (endrec && rec->cr_index > endrec) {
4399 llapi_changelog_free(&rec);
4402 if (rec->cr_index < startrec) {
4403 llapi_changelog_free(&rec);
4407 secs = rec->cr_time >> 30;
4408 gmtime_r(&secs, &ts);
4409 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4410 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4411 changelog_type2str(rec->cr_type),
4412 ts.tm_hour, ts.tm_min, ts.tm_sec,
4413 (int)(rec->cr_time & ((1 << 30) - 1)),
4414 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4415 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4417 if (rec->cr_flags & CLF_JOBID) {
4418 struct changelog_ext_jobid *jid =
4419 changelog_rec_jobid(rec);
4421 if (jid->cr_jobid[0] != '\0')
4422 printf(" j=%s", jid->cr_jobid);
4425 if (rec->cr_namelen)
4426 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4427 rec->cr_namelen, changelog_rec_name(rec));
4429 if (rec->cr_flags & CLF_RENAME) {
4430 struct changelog_ext_rename *rnm =
4431 changelog_rec_rename(rec);
4433 if (!fid_is_zero(&rnm->cr_sfid))
4434 printf(" s="DFID" sp="DFID" %.*s",
4435 PFID(&rnm->cr_sfid),
4436 PFID(&rnm->cr_spfid),
4437 (int)changelog_rec_snamelen(rec),
4438 changelog_rec_sname(rec));
4442 llapi_changelog_free(&rec);
4445 llapi_changelog_fini(&changelog_priv);
4448 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4450 return (rc == 1 ? 0 : rc);
4453 static int lfs_changelog_clear(int argc, char **argv)
4461 endrec = strtoll(argv[3], NULL, 10);
4463 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4466 fprintf(stderr, "%s: record out of range: %llu\n",
4468 else if (rc == -ENOENT)
4469 fprintf(stderr, "%s: no changelog user: %s\n",
4472 fprintf(stderr, "%s error: %s\n", argv[0],
4481 static int lfs_fid2path(int argc, char **argv)
4483 struct option long_opts[] = {
4484 {"cur", no_argument, 0, 'c'},
4485 {"link", required_argument, 0, 'l'},
4486 {"rec", required_argument, 0, 'r'},
4489 char short_opts[] = "cl:r:";
4490 char *device, *fid, *path;
4491 long long recno = -1;
4497 while ((rc = getopt_long(argc, argv, short_opts,
4498 long_opts, NULL)) != -1) {
4504 linkno = strtol(optarg, NULL, 10);
4507 recno = strtoll(optarg, NULL, 10);
4512 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4513 argv[0], argv[optind - 1]);
4521 device = argv[optind++];
4522 path = calloc(1, PATH_MAX);
4524 fprintf(stderr, "error: Not enough memory\n");
4529 while (optind < argc) {
4530 fid = argv[optind++];
4532 lnktmp = (linkno >= 0) ? linkno : 0;
4534 int oldtmp = lnktmp;
4535 long long rectmp = recno;
4537 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4540 fprintf(stderr, "%s: error on FID %s: %s\n",
4541 argv[0], fid, strerror(errno = -rc2));
4548 fprintf(stdout, "%lld ", rectmp);
4549 if (device[0] == '/') {
4550 fprintf(stdout, "%s", device);
4551 if (device[strlen(device) - 1] != '/')
4552 fprintf(stdout, "/");
4553 } else if (path[0] == '\0') {
4554 fprintf(stdout, "/");
4556 fprintf(stdout, "%s\n", path);
4559 /* specified linkno */
4561 if (oldtmp == lnktmp)
4571 static int lfs_path2fid(int argc, char **argv)
4573 struct option long_opts[] = {
4574 {"parents", no_argument, 0, 'p'},
4578 const char short_opts[] = "p";
4579 const char *sep = "";
4582 bool show_parents = false;
4584 while ((rc = getopt_long(argc, argv, short_opts,
4585 long_opts, NULL)) != -1) {
4588 show_parents = true;
4591 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4592 argv[0], argv[optind - 1]);
4597 if (optind > argc - 1)
4599 else if (optind < argc - 1)
4603 for (path = argv + optind; *path != NULL; path++) {
4605 if (!show_parents) {
4606 err = llapi_path2fid(*path, &fid);
4608 printf("%s%s"DFID"\n",
4609 *sep != '\0' ? *path : "", sep,
4612 char name[NAME_MAX + 1];
4613 unsigned int linkno = 0;
4615 while ((err = llapi_path2parent(*path, linkno, &fid,
4616 name, sizeof(name))) == 0) {
4617 if (*sep != '\0' && linkno == 0)
4618 printf("%s%s", *path, sep);
4620 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4625 /* err == -ENODATA is end-of-loop */
4626 if (linkno > 0 && err == -ENODATA) {
4633 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4634 argv[0], show_parents ? "parent " : "", *path,
4646 static int lfs_data_version(int argc, char **argv)
4653 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4658 while ((c = getopt(argc, argv, "nrw")) != -1) {
4661 data_version_flags = 0;
4664 data_version_flags |= LL_DV_RD_FLUSH;
4667 data_version_flags |= LL_DV_WR_FLUSH;
4676 path = argv[optind];
4677 fd = open(path, O_RDONLY);
4679 err(errno, "cannot open file %s", path);
4681 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4683 err(errno, "cannot get version for %s", path);
4685 printf("%ju" "\n", (uintmax_t)data_version);
4691 static int lfs_hsm_state(int argc, char **argv)
4696 struct hsm_user_state hus;
4704 rc = llapi_hsm_state_get(path, &hus);
4706 fprintf(stderr, "can't get hsm state for %s: %s\n",
4707 path, strerror(errno = -rc));
4711 /* Display path name and status flags */
4712 printf("%s: (0x%08x)", path, hus.hus_states);
4714 if (hus.hus_states & HS_RELEASED)
4715 printf(" released");
4716 if (hus.hus_states & HS_EXISTS)
4718 if (hus.hus_states & HS_DIRTY)
4720 if (hus.hus_states & HS_ARCHIVED)
4721 printf(" archived");
4722 /* Display user-settable flags */
4723 if (hus.hus_states & HS_NORELEASE)
4724 printf(" never_release");
4725 if (hus.hus_states & HS_NOARCHIVE)
4726 printf(" never_archive");
4727 if (hus.hus_states & HS_LOST)
4728 printf(" lost_from_hsm");
4730 if (hus.hus_archive_id != 0)
4731 printf(", archive_id:%d", hus.hus_archive_id);
4734 } while (++i < argc);
4739 #define LFS_HSM_SET 0
4740 #define LFS_HSM_CLEAR 1
4743 * Generic function to set or clear HSM flags.
4744 * Used by hsm_set and hsm_clear.
4746 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4748 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4750 struct option long_opts[] = {
4751 {"lost", 0, 0, 'l'},
4752 {"norelease", 0, 0, 'r'},
4753 {"noarchive", 0, 0, 'a'},
4754 {"archived", 0, 0, 'A'},
4755 {"dirty", 0, 0, 'd'},
4756 {"exists", 0, 0, 'e'},
4759 char short_opts[] = "lraAde";
4767 while ((c = getopt_long(argc, argv, short_opts,
4768 long_opts, NULL)) != -1) {
4774 mask |= HS_NOARCHIVE;
4777 mask |= HS_ARCHIVED;
4780 mask |= HS_NORELEASE;
4791 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4792 argv[0], argv[optind - 1]);
4797 /* User should have specified a flag */
4801 while (optind < argc) {
4803 path = argv[optind];
4805 /* If mode == 0, this means we apply the mask. */
4806 if (mode == LFS_HSM_SET)
4807 rc = llapi_hsm_state_set(path, mask, 0, 0);
4809 rc = llapi_hsm_state_set(path, 0, mask, 0);
4812 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4813 path, strerror(errno = -rc));
4822 static int lfs_hsm_action(int argc, char **argv)
4827 struct hsm_current_action hca;
4828 struct hsm_extent he;
4829 enum hsm_user_action hua;
4830 enum hsm_progress_states hps;
4838 rc = llapi_hsm_current_action(path, &hca);
4840 fprintf(stderr, "can't get hsm action for %s: %s\n",
4841 path, strerror(errno = -rc));
4844 he = hca.hca_location;
4845 hua = hca.hca_action;
4846 hps = hca.hca_state;
4848 printf("%s: %s", path, hsm_user_action2name(hua));
4850 /* Skip file without action */
4851 if (hca.hca_action == HUA_NONE) {
4856 printf(" %s ", hsm_progress_state2name(hps));
4858 if ((hps == HPS_RUNNING) &&
4859 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4860 printf("(%llu bytes moved)\n",
4861 (unsigned long long)he.length);
4862 else if ((he.offset + he.length) == LUSTRE_EOF)
4863 printf("(from %llu to EOF)\n",
4864 (unsigned long long)he.offset);
4866 printf("(from %llu to %llu)\n",
4867 (unsigned long long)he.offset,
4868 (unsigned long long)(he.offset + he.length));
4870 } while (++i < argc);
4875 static int lfs_hsm_set(int argc, char **argv)
4877 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4880 static int lfs_hsm_clear(int argc, char **argv)
4882 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4886 * Check file state and return its fid, to be used by lfs_hsm_request().
4888 * \param[in] file Path to file to check
4889 * \param[in,out] fid Pointer to allocated lu_fid struct.
4890 * \param[in,out] last_dev Pointer to last device id used.
4892 * \return 0 on success.
4894 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4900 rc = lstat(file, &st);
4902 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4905 /* Checking for regular file as archiving as posix copytool
4906 * rejects archiving files other than regular files
4908 if (!S_ISREG(st.st_mode)) {
4909 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4912 /* A request should be ... */
4913 if (*last_dev != st.st_dev && *last_dev != 0) {
4914 fprintf(stderr, "All files should be "
4915 "on the same filesystem: %s\n", file);
4918 *last_dev = st.st_dev;
4920 rc = llapi_path2fid(file, fid);
4922 fprintf(stderr, "Cannot read FID of %s: %s\n",
4923 file, strerror(-rc));
4929 /* Fill an HSM HUR item with a given file name.
4931 * If mntpath is set, then the filename is actually a FID, and no
4932 * lookup on the filesystem will be performed.
4934 * \param[in] hur the user request to fill
4935 * \param[in] idx index of the item inside the HUR to fill
4936 * \param[in] mntpath mountpoint of Lustre
4937 * \param[in] fname filename (if mtnpath is NULL)
4938 * or FID (if mntpath is set)
4939 * \param[in] last_dev pointer to last device id used
4941 * \retval 0 on success
4942 * \retval CMD_HELP or a negative errno on error
4944 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4945 const char *mntpath, const char *fname,
4948 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4951 hui->hui_extent.length = -1;
4953 if (mntpath != NULL) {
4956 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4960 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4965 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4969 hur->hur_request.hr_itemcount++;
4974 static int lfs_hsm_request(int argc, char **argv, int action)
4976 struct option long_opts[] = {
4977 {"filelist", 1, 0, 'l'},
4978 {"data", 1, 0, 'D'},
4979 {"archive", 1, 0, 'a'},
4980 {"mntpath", 1, 0, 'm'},
4984 char short_opts[] = "l:D:a:m:";
4985 struct hsm_user_request *hur, *oldhur;
4990 char *filelist = NULL;
4991 char fullpath[PATH_MAX];
4992 char *opaque = NULL;
4996 int nbfile_alloc = 0;
4997 char *some_file = NULL;
4998 char *mntpath = NULL;
5004 while ((c = getopt_long(argc, argv, short_opts,
5005 long_opts, NULL)) != -1) {
5014 if (action != HUA_ARCHIVE &&
5015 action != HUA_REMOVE) {
5017 "error: -a is supported only "
5018 "when archiving or removing\n");
5021 archive_id = atoi(optarg);
5024 if (some_file == NULL) {
5026 some_file = strdup(optarg);
5032 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5033 argv[0], argv[optind - 1]);
5038 /* All remaining args are files, so we have at least nbfile */
5039 nbfile = argc - optind;
5041 if ((nbfile == 0) && (filelist == NULL))
5045 opaque_len = strlen(opaque);
5047 /* Alloc the request structure with enough place to store all files
5048 * from command line. */
5049 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5051 fprintf(stderr, "Cannot create the request: %s\n",
5055 nbfile_alloc = nbfile;
5057 hur->hur_request.hr_action = action;
5058 hur->hur_request.hr_archive_id = archive_id;
5059 hur->hur_request.hr_flags = 0;
5061 /* All remaining args are files, add them */
5062 if (nbfile != 0 && some_file == NULL)
5063 some_file = strdup(argv[optind]);
5065 for (i = 0; i < nbfile; i++) {
5066 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5072 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5074 /* If a filelist was specified, read the filelist from it. */
5075 if (filelist != NULL) {
5076 fp = fopen(filelist, "r");
5078 fprintf(stderr, "Cannot read the file list %s: %s\n",
5079 filelist, strerror(errno));
5084 while ((rc = getline(&line, &len, fp)) != -1) {
5085 /* If allocated buffer was too small, get something
5087 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5090 nbfile_alloc = nbfile_alloc * 2 + 1;
5092 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5095 fprintf(stderr, "hsm: cannot allocate "
5096 "the request: %s\n",
5103 size = hur_len(oldhur);
5105 fprintf(stderr, "hsm: cannot allocate "
5106 "%u files + %u bytes data\n",
5107 oldhur->hur_request.hr_itemcount,
5108 oldhur->hur_request.hr_data_len);
5115 memcpy(hur, oldhur, size);
5120 if (line[strlen(line) - 1] == '\n')
5121 line[strlen(line) - 1] = '\0';
5123 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5124 mntpath, line, &last_dev);
5130 if (some_file == NULL) {
5140 /* If a --data was used, add it to the request */
5141 hur->hur_request.hr_data_len = opaque_len;
5143 memcpy(hur_data(hur), opaque, opaque_len);
5145 /* Send the HSM request */
5146 if (realpath(some_file, fullpath) == NULL) {
5147 fprintf(stderr, "Could not find path '%s': %s\n",
5148 some_file, strerror(errno));
5150 rc = llapi_hsm_request(fullpath, hur);
5152 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5153 some_file, strerror(-rc));
5163 static int lfs_hsm_archive(int argc, char **argv)
5165 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5168 static int lfs_hsm_restore(int argc, char **argv)
5170 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5173 static int lfs_hsm_release(int argc, char **argv)
5175 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5178 static int lfs_hsm_remove(int argc, char **argv)
5180 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5183 static int lfs_hsm_cancel(int argc, char **argv)
5185 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5188 static int lfs_swap_layouts(int argc, char **argv)
5193 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5194 SWAP_LAYOUTS_KEEP_MTIME |
5195 SWAP_LAYOUTS_KEEP_ATIME);
5198 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5200 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5202 enum lu_ladvise_type advice;
5205 advice < ARRAY_SIZE(ladvise_names); advice++) {
5206 if (ladvise_names[advice] == NULL)
5208 if (strcmp(string, ladvise_names[advice]) == 0)
5212 return LU_LADVISE_INVALID;
5215 static int lfs_ladvise(int argc, char **argv)
5217 struct option long_opts[] = {
5218 {"advice", required_argument, 0, 'a'},
5219 {"background", no_argument, 0, 'b'},
5220 {"end", required_argument, 0, 'e'},
5221 {"start", required_argument, 0, 's'},
5222 {"length", required_argument, 0, 'l'},
5225 char short_opts[] = "a:be:l:s:";
5230 struct llapi_lu_ladvise advice;
5231 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5232 unsigned long long start = 0;
5233 unsigned long long end = LUSTRE_EOF;
5234 unsigned long long length = 0;
5235 unsigned long long size_units;
5236 unsigned long long flags = 0;
5239 while ((c = getopt_long(argc, argv, short_opts,
5240 long_opts, NULL)) != -1) {
5243 advice_type = lfs_get_ladvice(optarg);
5244 if (advice_type == LU_LADVISE_INVALID) {
5245 fprintf(stderr, "%s: invalid advice type "
5246 "'%s'\n", argv[0], optarg);
5247 fprintf(stderr, "Valid types:");
5249 for (advice_type = 0;
5250 advice_type < ARRAY_SIZE(ladvise_names);
5252 if (ladvise_names[advice_type] == NULL)
5254 fprintf(stderr, " %s",
5255 ladvise_names[advice_type]);
5257 fprintf(stderr, "\n");
5267 rc = llapi_parse_size(optarg, &end,
5270 fprintf(stderr, "%s: bad end offset '%s'\n",
5277 rc = llapi_parse_size(optarg, &start,
5280 fprintf(stderr, "%s: bad start offset "
5281 "'%s'\n", argv[0], optarg);
5287 rc = llapi_parse_size(optarg, &length,
5290 fprintf(stderr, "%s: bad length '%s'\n",
5298 fprintf(stderr, "%s: option '%s' unrecognized\n",
5299 argv[0], argv[optind - 1]);
5304 if (advice_type == LU_LADVISE_INVALID) {
5305 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5306 fprintf(stderr, "Valid types:");
5307 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5309 if (ladvise_names[advice_type] == NULL)
5311 fprintf(stderr, " %s", ladvise_names[advice_type]);
5313 fprintf(stderr, "\n");
5317 if (argc <= optind) {
5318 fprintf(stderr, "%s: please give one or more file names\n",
5323 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5324 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5329 if (end == LUSTRE_EOF && length != 0)
5330 end = start + length;
5333 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5334 argv[0], start, end);
5338 while (optind < argc) {
5341 path = argv[optind++];
5343 fd = open(path, O_RDONLY);
5345 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5346 argv[0], path, strerror(errno));
5351 advice.lla_start = start;
5352 advice.lla_end = end;
5353 advice.lla_advice = advice_type;
5354 advice.lla_value1 = 0;
5355 advice.lla_value2 = 0;
5356 advice.lla_value3 = 0;
5357 advice.lla_value4 = 0;
5358 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5361 fprintf(stderr, "%s: cannot give advice '%s' to file "
5362 "'%s': %s\n", argv[0],
5363 ladvise_names[advice_type],
5364 path, strerror(errno));
5367 if (rc == 0 && rc2 < 0)
5373 static int lfs_list_commands(int argc, char **argv)
5375 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5377 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5382 int main(int argc, char **argv)
5386 /* Ensure that liblustreapi constructor has run */
5387 if (!liblustreapi_initialized)
5388 fprintf(stderr, "liblustreapi was not properly initialized\n");
5392 Parser_init("lfs > ", cmdlist);
5394 progname = argv[0]; /* Used in error messages */
5396 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5398 rc = Parser_commands();
5401 return rc < 0 ? -rc : rc;
5404 #ifdef _LUSTRE_IDL_H_
5405 /* Everything we need here should be included by lustreapi.h. */
5406 # error "lfs should not depend on lustre_idl.h"
5407 #endif /* _LUSTRE_IDL_H_ */