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 { .val = 'b', .name = "block", .has_arg = no_argument},
1351 { .val = LFS_COMP_ADD_OPT,
1352 .name = "comp-add", .has_arg = no_argument},
1353 { .val = LFS_COMP_ADD_OPT,
1354 .name = "component-add",
1355 .has_arg = no_argument},
1356 { .val = LFS_COMP_DEL_OPT,
1357 .name = "comp-del", .has_arg = no_argument},
1358 { .val = LFS_COMP_DEL_OPT,
1359 .name = "component-del",
1360 .has_arg = no_argument},
1361 { .val = LFS_COMP_FLAGS_OPT,
1362 .name = "comp-flags", .has_arg = required_argument},
1363 { .val = LFS_COMP_FLAGS_OPT,
1364 .name = "component-flags",
1365 .has_arg = required_argument},
1366 { .val = LFS_COMP_SET_OPT,
1367 .name = "comp-set", .has_arg = no_argument},
1368 { .val = LFS_COMP_SET_OPT,
1369 .name = "component-set",
1370 .has_arg = no_argument},
1371 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1372 /* This formerly implied "stripe-count", but was explicitly
1373 * made "stripe-count" for consistency with other options,
1374 * and to separate it from "mdt-count" when DNE arrives. */
1375 { .val = 'c', .name = "count", .has_arg = required_argument },
1377 { .val = 'c', .name = "stripe-count", .has_arg = required_argument},
1378 { .val = 'c', .name = "stripe_count", .has_arg = required_argument},
1379 { .val = 'd', .name = "delete", .has_arg = no_argument},
1380 { .val = 'E', .name = "comp-end", .has_arg = required_argument},
1381 { .val = 'E', .name = "component-end",
1382 .has_arg = required_argument},
1383 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1384 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1385 /* This formerly implied "stripe-index", but was explicitly
1386 * made "stripe-index" for consistency with other options,
1387 * and to separate it from "mdt-index" when DNE arrives. */
1388 { .val = 'i', .name = "index", .has_arg = required_argument },
1390 { .val = 'i', .name = "stripe-index", .has_arg = required_argument},
1391 { .val = 'i', .name = "stripe_index", .has_arg = required_argument},
1392 { .val = 'I', .name = "comp-id", .has_arg = required_argument},
1393 { .val = 'I', .name = "component-id", .has_arg = required_argument},
1394 { .val = 'm', .name = "mdt", .has_arg = required_argument},
1395 { .val = 'm', .name = "mdt-index", .has_arg = required_argument},
1396 { .val = 'm', .name = "mdt_index", .has_arg = required_argument},
1397 /* --non-block is only valid in migrate mode */
1398 { .val = 'n', .name = "non-block", .has_arg = no_argument},
1399 { .val = 'o', .name = "ost", .has_arg = required_argument},
1400 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1401 { .val = 'o', .name = "ost-list", .has_arg = required_argument },
1402 { .val = 'o', .name = "ost_list", .has_arg = required_argument },
1404 { .val = 'p', .name = "pool", .has_arg = required_argument },
1405 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1406 /* This formerly implied "--stripe-size", but was confusing
1407 * with "lfs find --size|-s", which means "file size", so use
1408 * the consistent "--stripe-size|-S" for all commands. */
1409 { .val = 's', .name = "size", .has_arg = required_argument },
1411 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1412 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1413 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1414 /* --verbose is only valid in migrate mode */
1415 { .val = 'v', .name = "verbose", .has_arg = no_argument },
1416 { .val = LFS_COMP_ADD_OPT,
1417 .name = "component-add",
1418 .has_arg = no_argument },
1419 { .val = LFS_COMP_DEL_OPT,
1420 .name = "component-del",
1421 .has_arg = no_argument },
1422 { .val = LFS_COMP_FLAGS_OPT,
1423 .name = "component-flags",
1424 .has_arg = required_argument },
1425 { .val = LFS_COMP_SET_OPT,
1426 .name = "component-set",
1427 .has_arg = no_argument },
1430 setstripe_args_init(&lsa);
1432 if (strcmp(argv[0], "migrate") == 0)
1433 migrate_mode = true;
1435 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1436 long_opts, NULL)) >= 0) {
1441 case LFS_COMP_ADD_OPT:
1444 case LFS_COMP_DEL_OPT:
1447 case LFS_COMP_FLAGS_OPT:
1448 result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
1450 fprintf(stderr, "error: %s: bad comp flags "
1451 "'%s'\n", argv[0], optarg);
1455 case LFS_COMP_SET_OPT:
1459 if (!migrate_mode) {
1460 fprintf(stderr, "--block is valid only for"
1464 migration_block = true;
1467 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1468 if (strcmp(argv[optind - 1], "--count") == 0)
1469 fprintf(stderr, "warning: '--count' deprecated"
1470 ", use '--stripe-count' instead\n");
1472 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1474 fprintf(stderr, "error: %s: bad stripe count "
1475 "'%s'\n", argv[0], optarg);
1480 /* delete the default striping pattern */
1484 if (lsa.lsa_comp_end != 0) {
1485 result = comp_args_to_layout(&layout, &lsa);
1489 setstripe_args_init(&lsa);
1492 if (arg_is_eof(optarg)) {
1493 lsa.lsa_comp_end = LUSTRE_EOF;
1495 result = llapi_parse_size(optarg,
1499 fprintf(stderr, "error: %s: "
1500 "bad component end '%s'\n",
1507 if (strcmp(argv[optind - 1], "--index") == 0)
1508 fprintf(stderr, "warning: '--index' deprecated"
1509 ", use '--stripe-index' instead\n");
1510 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1512 fprintf(stderr, "error: %s: bad stripe offset "
1513 "'%s'\n", argv[0], optarg);
1518 comp_id = strtoul(optarg, &end, 0);
1519 if (*end != '\0' || comp_id == 0 ||
1520 comp_id > LCME_ID_MAX) {
1521 fprintf(stderr, "error: %s: bad comp ID "
1522 "'%s'\n", argv[0], optarg);
1527 if (!migrate_mode) {
1528 fprintf(stderr, "--mdt-index is valid only for"
1532 mdt_idx_arg = optarg;
1535 if (!migrate_mode) {
1536 fprintf(stderr, "--non-block is valid only for"
1540 migration_flags |= MIGRATION_NONBLOCK;
1543 lsa.lsa_nr_osts = parse_targets(osts,
1544 sizeof(osts) / sizeof(__u32),
1545 lsa.lsa_nr_osts, optarg);
1546 if (lsa.lsa_nr_osts < 0) {
1548 "error: %s: bad OST indices '%s'\n",
1553 lsa.lsa_osts = osts;
1554 if (lsa.lsa_stripe_off == -1)
1555 lsa.lsa_stripe_off = osts[0];
1558 result = verify_pool_name(argv[0], optarg);
1561 lsa.lsa_pool_name = optarg;
1563 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1565 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1566 fprintf(stderr, "warning: '--size|-s' deprecated, "
1567 "use '--stripe-size|-S' instead\n");
1569 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1571 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1574 fprintf(stderr, "error: %s: bad stripe size "
1575 "'%s'\n", argv[0], optarg);
1580 if (!migrate_mode) {
1581 fprintf(stderr, "--verbose is valid only for"
1585 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1592 fname = argv[optind];
1594 if (lsa.lsa_comp_end != 0) {
1595 result = comp_args_to_layout(&layout, &lsa);
1600 if (optind == argc) {
1601 fprintf(stderr, "error: %s: missing filename|dirname\n",
1606 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1607 * altered by user space tool, so we don't need to support the
1608 * --component-set for this moment. */
1609 if (comp_set != 0) {
1610 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1615 if ((delete + comp_set + comp_del + comp_add) > 1) {
1616 fprintf(stderr, "error: %s: can't specify --component-set, "
1617 "--component-del, --component-add or -d together\n",
1622 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1623 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1624 fprintf(stderr, "error: %s: can't specify -d with "
1625 "-s, -c, -o, -p, -I, -F or -E options\n",
1630 if ((comp_set || comp_del) &&
1631 (setstripe_args_specified(&lsa) || layout != NULL)) {
1632 fprintf(stderr, "error: %s: can't specify --component-del or "
1633 "--component-set with -s, -c, -o, -p or -E options.\n",
1638 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1639 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1640 "--component-del option.\n", argv[0]);
1644 if (comp_add || comp_del) {
1647 result = lstat(fname, &st);
1648 if (result == 0 && S_ISDIR(st.st_mode)) {
1649 fprintf(stderr, "error: %s: can't use --component-add "
1650 "or --component-del for directory.\n",
1657 if (layout == NULL) {
1658 fprintf(stderr, "error: %s: -E option must be present"
1659 "in --component-add mode.\n", argv[0]);
1662 result = adjust_first_extent(fname, layout);
1663 if (result == -ENODATA)
1665 else if (result != 0)
1669 if (mdt_idx_arg != NULL && optind > 3) {
1670 fprintf(stderr, "error: %s: cannot specify -m with other "
1671 "options\n", argv[0]);
1675 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1677 "error: %s: cannot specify --non-block and --block\n",
1682 if (!comp_del && !comp_set && comp_id != 0) {
1683 fprintf(stderr, "error: %s: -I can only be used with "
1684 "--component-del.\n", argv[0]);
1688 if (mdt_idx_arg != NULL) {
1689 /* initialize migrate mdt parameters */
1690 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1692 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1693 argv[0], mdt_idx_arg);
1696 migrate_mdt_param.fp_migrate = 1;
1697 } else if (layout == NULL) {
1698 /* initialize stripe parameters */
1699 param = calloc(1, offsetof(typeof(*param),
1700 lsp_osts[lsa.lsa_nr_osts]));
1701 if (param == NULL) {
1702 fprintf(stderr, "error: %s: %s\n", argv[0],
1707 param->lsp_stripe_size = lsa.lsa_stripe_size;
1708 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1709 param->lsp_stripe_count = lsa.lsa_stripe_count;
1710 param->lsp_stripe_pattern = 0;
1711 param->lsp_pool = lsa.lsa_pool_name;
1712 param->lsp_is_specific = false;
1713 if (lsa.lsa_nr_osts > 0) {
1714 if (lsa.lsa_stripe_count > 0 &&
1715 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1716 fprintf(stderr, "error: %s: stripe count '%d' "
1717 "doesn't match the number of OSTs: %d\n"
1718 , argv[0], lsa.lsa_stripe_count,
1724 param->lsp_is_specific = true;
1725 param->lsp_stripe_count = lsa.lsa_nr_osts;
1726 memcpy(param->lsp_osts, osts,
1727 sizeof(*osts) * lsa.lsa_nr_osts);
1731 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1733 if (mdt_idx_arg != NULL) {
1734 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1735 op = "migrate mdt objects of";
1736 } else if (migrate_mode) {
1737 result = lfs_migrate(fname, migration_flags, param,
1739 op = "migrate ost objects of";
1740 } else if (comp_set != 0) {
1741 result = lfs_component_set(fname, comp_id,
1742 lsa.lsa_comp_flags);
1743 op = "modify component flags of";
1744 } else if (comp_del != 0) {
1745 result = lfs_component_del(fname, comp_id,
1746 lsa.lsa_comp_flags);
1747 op = "delete component of";
1748 } else if (comp_add != 0) {
1749 result = lfs_component_add(fname, layout);
1750 op = "add component to";
1751 } else if (layout != NULL) {
1752 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1758 op = "create composite";
1760 result = llapi_file_open_param(fname,
1767 op = "create striped";
1770 /* Save the first error encountered. */
1773 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1775 lsa.lsa_pool_name != NULL && result == EINVAL ?
1776 "OST not in pool?" : strerror(errno));
1782 llapi_layout_free(layout);
1785 llapi_layout_free(layout);
1789 static int lfs_poollist(int argc, char **argv)
1794 return llapi_poollist(argv[1]);
1797 static int set_time(time_t *time, time_t *set, char *str)
1804 else if (str[0] == '-')
1810 t = strtol(str, NULL, 0);
1811 if (*time < t * 24 * 60 * 60) {
1814 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1818 *set = *time - t * 24 * 60 * 60;
1821 static int name2uid(unsigned int *id, const char *name)
1823 struct passwd *passwd;
1825 passwd = getpwnam(name);
1828 *id = passwd->pw_uid;
1833 static int name2gid(unsigned int *id, const char *name)
1835 struct group *group;
1837 group = getgrnam(name);
1840 *id = group->gr_gid;
1845 static inline int name2projid(unsigned int *id, const char *name)
1850 static int uid2name(char **name, unsigned int id)
1852 struct passwd *passwd;
1854 passwd = getpwuid(id);
1857 *name = passwd->pw_name;
1862 static inline int gid2name(char **name, unsigned int id)
1864 struct group *group;
1866 group = getgrgid(id);
1869 *name = group->gr_name;
1874 static int name2layout(__u32 *layout, char *name)
1879 for (ptr = name; ; ptr = NULL) {
1880 lyt = strtok(ptr, ",");
1883 if (strcmp(lyt, "released") == 0)
1884 *layout |= LOV_PATTERN_F_RELEASED;
1885 else if (strcmp(lyt, "raid0") == 0)
1886 *layout |= LOV_PATTERN_RAID0;
1893 static int lfs_find(int argc, char **argv)
1898 struct find_param param = {
1902 struct option long_opts[] = {
1903 {"atime", required_argument, 0, 'A'},
1904 {"comp-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1905 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1906 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1907 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1908 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
1909 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1910 {"stripe-count", required_argument, 0, 'c'},
1911 {"stripe_count", required_argument, 0, 'c'},
1912 {"ctime", required_argument, 0, 'C'},
1913 {"maxdepth", required_argument, 0, 'D'},
1914 {"comp-end", required_argument, 0, 'E'},
1915 {"component-end", required_argument, 0, 'E'},
1916 {"gid", required_argument, 0, 'g'},
1917 {"group", required_argument, 0, 'G'},
1918 {"mdt-hash", required_argument, 0, 'H'},
1919 {"stripe-index", required_argument, 0, 'i'},
1920 {"stripe_index", required_argument, 0, 'i'},
1921 /*{"component-id", required_argument, 0, 'I'},*/
1922 {"layout", required_argument, 0, 'L'},
1923 {"mdt", required_argument, 0, 'm'},
1924 {"mdt-index", required_argument, 0, 'm'},
1925 {"mdt_index", required_argument, 0, 'm'},
1926 {"mtime", required_argument, 0, 'M'},
1927 {"name", required_argument, 0, 'n'},
1928 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1929 {"obd", required_argument, 0, 'O'},
1930 {"ost", required_argument, 0, 'O'},
1931 /* no short option for pool, p/P already used */
1932 {"pool", required_argument, 0, LFS_POOL_OPT},
1933 {"print0", no_argument, 0, 'p'},
1934 {"print", no_argument, 0, 'P'},
1935 {"projid", required_argument, 0, LFS_PROJID_OPT},
1936 {"size", required_argument, 0, 's'},
1937 {"stripe-size", required_argument, 0, 'S'},
1938 {"stripe_size", required_argument, 0, 'S'},
1939 {"type", required_argument, 0, 't'},
1940 {"mdt-count", required_argument, 0, 'T'},
1941 {"uid", required_argument, 0, 'u'},
1942 {"user", required_argument, 0, 'U'},
1955 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1956 while ((c = getopt_long_only(argc, argv,
1957 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1958 long_opts, NULL)) >= 0) {
1963 /* '!' is part of option */
1964 /* when getopt_long_only() finds a string which is not
1965 * an option nor a known option argument it returns 1
1966 * in that case if we already have found pathstart and pathend
1967 * (i.e. we have the list of pathnames),
1968 * the only supported value is "!"
1970 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1971 if (!isoption && pathend != -1) {
1972 fprintf(stderr, "err: %s: filename|dirname must either "
1973 "precede options or follow options\n",
1978 if (!isoption && pathstart == -1)
1979 pathstart = optind - 1;
1980 if (isoption && pathstart != -1 && pathend == -1)
1981 pathend = optind - 2;
1987 /* unknown; opt is "!" or path component,
1988 * checking done above.
1990 if (strcmp(optarg, "!") == 0)
1994 xtime = ¶m.fp_atime;
1995 xsign = ¶m.fp_asign;
1996 param.fp_exclude_atime = !!neg_opt;
1997 /* no break, this falls through to 'C' for ctime */
2000 xtime = ¶m.fp_ctime;
2001 xsign = ¶m.fp_csign;
2002 param.fp_exclude_ctime = !!neg_opt;
2004 /* no break, this falls through to 'M' for mtime */
2007 xtime = ¶m.fp_mtime;
2008 xsign = ¶m.fp_msign;
2009 param.fp_exclude_mtime = !!neg_opt;
2011 rc = set_time(&t, xtime, optarg);
2012 if (rc == INT_MAX) {
2019 case LFS_COMP_COUNT_OPT:
2020 if (optarg[0] == '+') {
2021 param.fp_comp_count_sign = -1;
2023 } else if (optarg[0] == '-') {
2024 param.fp_comp_count_sign = 1;
2028 param.fp_comp_count = strtoul(optarg, &endptr, 0);
2029 if (*endptr != '\0') {
2030 fprintf(stderr, "error: bad component count "
2034 param.fp_check_comp_count = 1;
2035 param.fp_exclude_comp_count = !!neg_opt;
2037 case LFS_COMP_FLAGS_OPT:
2038 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
2039 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2040 fprintf(stderr, "error: bad component flags "
2044 param.fp_check_comp_flags = 1;
2045 param.fp_exclude_comp_flags = !!neg_opt;
2047 case LFS_COMP_START_OPT:
2048 if (optarg[0] == '+') {
2049 param.fp_comp_start_sign = -1;
2051 } else if (optarg[0] == '-') {
2052 param.fp_comp_start_sign = 1;
2056 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2057 ¶m.fp_comp_start_units, 0);
2059 fprintf(stderr, "error: bad component start "
2063 param.fp_check_comp_start = 1;
2064 param.fp_exclude_comp_start = !!neg_opt;
2067 if (optarg[0] == '+') {
2068 param.fp_stripe_count_sign = -1;
2070 } else if (optarg[0] == '-') {
2071 param.fp_stripe_count_sign = 1;
2075 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2076 if (*endptr != '\0') {
2077 fprintf(stderr,"error: bad stripe_count '%s'\n",
2082 param.fp_check_stripe_count = 1;
2083 param.fp_exclude_stripe_count = !!neg_opt;
2086 param.fp_max_depth = strtol(optarg, 0, 0);
2089 if (optarg[0] == '+') {
2090 param.fp_comp_end_sign = -1;
2092 } else if (optarg[0] == '-') {
2093 param.fp_comp_end_sign = 1;
2097 if (arg_is_eof(optarg)) {
2098 param.fp_comp_end = LUSTRE_EOF;
2099 param.fp_comp_end_units = 1;
2102 rc = llapi_parse_size(optarg,
2104 ¶m.fp_comp_end_units, 0);
2107 fprintf(stderr, "error: bad component end "
2111 param.fp_check_comp_end = 1;
2112 param.fp_exclude_comp_end = !!neg_opt;
2116 rc = name2gid(¶m.fp_gid, optarg);
2118 param.fp_gid = strtoul(optarg, &endptr, 10);
2119 if (*endptr != '\0') {
2120 fprintf(stderr, "Group/GID: %s cannot "
2121 "be found.\n", optarg);
2126 param.fp_exclude_gid = !!neg_opt;
2127 param.fp_check_gid = 1;
2130 param.fp_hash_type = check_hashtype(optarg);
2131 if (param.fp_hash_type == 0) {
2132 fprintf(stderr, "error: bad hash_type '%s'\n",
2137 param.fp_check_hash_type = 1;
2138 param.fp_exclude_hash_type = !!neg_opt;
2141 ret = name2layout(¶m.fp_layout, optarg);
2144 param.fp_exclude_layout = !!neg_opt;
2145 param.fp_check_layout = 1;
2149 rc = name2uid(¶m.fp_uid, optarg);
2151 param.fp_uid = strtoul(optarg, &endptr, 10);
2152 if (*endptr != '\0') {
2153 fprintf(stderr, "User/UID: %s cannot "
2154 "be found.\n", optarg);
2159 param.fp_exclude_uid = !!neg_opt;
2160 param.fp_check_uid = 1;
2163 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2165 "Pool name %s is too long"
2166 " (max is %d)\n", optarg,
2171 /* we do check for empty pool because empty pool
2172 * is used to find V1 lov attributes */
2173 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2174 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2175 param.fp_exclude_pool = !!neg_opt;
2176 param.fp_check_pool = 1;
2179 param.fp_pattern = (char *)optarg;
2180 param.fp_exclude_pattern = !!neg_opt;
2185 char *buf, *token, *next, *p;
2189 buf = strdup(optarg);
2195 param.fp_exclude_obd = !!neg_opt;
2198 while (token && *token) {
2199 token = strchr(token, ',');
2206 param.fp_exclude_mdt = !!neg_opt;
2207 param.fp_num_alloc_mdts += len;
2208 tmp = realloc(param.fp_mdt_uuid,
2209 param.fp_num_alloc_mdts *
2210 sizeof(*param.fp_mdt_uuid));
2216 param.fp_mdt_uuid = tmp;
2218 param.fp_exclude_obd = !!neg_opt;
2219 param.fp_num_alloc_obds += len;
2220 tmp = realloc(param.fp_obd_uuid,
2221 param.fp_num_alloc_obds *
2222 sizeof(*param.fp_obd_uuid));
2228 param.fp_obd_uuid = tmp;
2230 for (token = buf; token && *token; token = next) {
2231 struct obd_uuid *puuid;
2234 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2237 ¶m.fp_obd_uuid[param.fp_num_obds++];
2239 p = strchr(token, ',');
2246 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2251 strncpy(puuid->uuid, token,
2252 sizeof(puuid->uuid));
2260 param.fp_zero_end = 1;
2264 case LFS_PROJID_OPT:
2265 rc = name2projid(¶m.fp_projid, optarg);
2267 param.fp_projid = strtoul(optarg, &endptr, 10);
2268 if (*endptr != '\0') {
2270 "Invalid project ID: %s",
2276 param.fp_exclude_projid = !!neg_opt;
2277 param.fp_check_projid = 1;
2280 if (optarg[0] == '+') {
2281 param.fp_size_sign = -1;
2283 } else if (optarg[0] == '-') {
2284 param.fp_size_sign = 1;
2288 ret = llapi_parse_size(optarg, ¶m.fp_size,
2289 ¶m.fp_size_units, 0);
2291 fprintf(stderr, "error: bad file size '%s'\n",
2295 param.fp_check_size = 1;
2296 param.fp_exclude_size = !!neg_opt;
2299 if (optarg[0] == '+') {
2300 param.fp_stripe_size_sign = -1;
2302 } else if (optarg[0] == '-') {
2303 param.fp_stripe_size_sign = 1;
2307 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2308 ¶m.fp_stripe_size_units, 0);
2310 fprintf(stderr, "error: bad stripe_size '%s'\n",
2314 param.fp_check_stripe_size = 1;
2315 param.fp_exclude_stripe_size = !!neg_opt;
2318 param.fp_exclude_type = !!neg_opt;
2319 switch (optarg[0]) {
2321 param.fp_type = S_IFBLK;
2324 param.fp_type = S_IFCHR;
2327 param.fp_type = S_IFDIR;
2330 param.fp_type = S_IFREG;
2333 param.fp_type = S_IFLNK;
2336 param.fp_type = S_IFIFO;
2339 param.fp_type = S_IFSOCK;
2342 fprintf(stderr, "error: %s: bad type '%s'\n",
2349 if (optarg[0] == '+') {
2350 param.fp_mdt_count_sign = -1;
2352 } else if (optarg[0] == '-') {
2353 param.fp_mdt_count_sign = 1;
2357 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2358 if (*endptr != '\0') {
2359 fprintf(stderr, "error: bad mdt_count '%s'\n",
2364 param.fp_check_mdt_count = 1;
2365 param.fp_exclude_mdt_count = !!neg_opt;
2373 if (pathstart == -1) {
2374 fprintf(stderr, "error: %s: no filename|pathname\n",
2378 } else if (pathend == -1) {
2384 rc = llapi_find(argv[pathstart], ¶m);
2385 if (rc != 0 && ret == 0)
2387 } while (++pathstart < pathend);
2390 fprintf(stderr, "error: %s failed for %s.\n",
2391 argv[0], argv[optind - 1]);
2393 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2394 free(param.fp_obd_uuid);
2396 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2397 free(param.fp_mdt_uuid);
2402 static int lfs_getstripe_internal(int argc, char **argv,
2403 struct find_param *param)
2405 struct option long_opts[] = {
2406 {"comp-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2407 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2408 {"comp-flags", optional_argument, 0, LFS_COMP_FLAGS_OPT},
2409 {"component-flags", optional_argument, 0, LFS_COMP_FLAGS_OPT},
2410 {"comp-start", optional_argument, 0, LFS_COMP_START_OPT},
2411 {"component-start", optional_argument, 0, LFS_COMP_START_OPT},
2412 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2413 /* This formerly implied "stripe-count", but was explicitly
2414 * made "stripe-count" for consistency with other options,
2415 * and to separate it from "mdt-count" when DNE arrives. */
2416 {"count", no_argument, 0, 'c'},
2418 {"stripe-count", no_argument, 0, 'c'},
2419 {"stripe_count", no_argument, 0, 'c'},
2420 {"directory", no_argument, 0, 'd'},
2421 {"default", no_argument, 0, 'D'},
2422 {"comp-end", optional_argument, 0, 'E'},
2423 {"component-end", optional_argument, 0, 'E'},
2424 {"fid", no_argument, 0, 'F'},
2425 {"generation", no_argument, 0, 'g'},
2426 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
2427 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2428 /* This formerly implied "stripe-index", but was explicitly
2429 * made "stripe-index" for consistency with other options,
2430 * and to separate it from "mdt-index" when DNE arrives. */
2431 {"index", no_argument, 0, 'i'},
2433 {"stripe-index", no_argument, 0, 'i'},
2434 {"stripe_index", no_argument, 0, 'i'},
2435 {"comp-id", optional_argument, 0, 'I'},
2436 {"component-id", optional_argument, 0, 'I'},
2437 {"layout", no_argument, 0, 'L'},
2438 {"mdt", no_argument, 0, 'm'},
2439 {"mdt-index", no_argument, 0, 'm'},
2440 {"mdt_index", no_argument, 0, 'm'},
2441 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2442 {"mdt-index", no_argument, 0, 'M'},
2443 {"mdt_index", no_argument, 0, 'M'},
2445 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2446 /* This formerly implied "stripe-index", but was confusing
2447 * with "file offset" (which will eventually be needed for
2448 * with different layouts by offset), so deprecate it. */
2449 {"offset", no_argument, 0, 'o'},
2451 {"obd", required_argument, 0, 'O'},
2452 {"ost", required_argument, 0, 'O'},
2453 {"pool", no_argument, 0, 'p'},
2454 {"quiet", no_argument, 0, 'q'},
2455 {"recursive", no_argument, 0, 'r'},
2456 {"raw", no_argument, 0, 'R'},
2457 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2458 /* This formerly implied "--stripe-size", but was confusing
2459 * with "lfs find --size|-s", which means "file size", so use
2460 * the consistent "--stripe-size|-S" for all commands. */
2461 {"size", no_argument, 0, 's'},
2463 {"stripe-size", no_argument, 0, 'S'},
2464 {"stripe_size", no_argument, 0, 'S'},
2465 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
2466 {"verbose", no_argument, 0, 'v'},
2467 {"yaml", no_argument, 0, 'y'},
2473 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2474 long_opts, NULL)) != -1) {
2477 if (strcmp(argv[optind - 1], "--count") == 0)
2478 fprintf(stderr, "warning: '--count' deprecated,"
2479 " use '--stripe-count' instead\n");
2480 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2481 param->fp_verbose |= VERBOSE_COUNT;
2482 param->fp_max_depth = 0;
2485 case LFS_COMP_COUNT_OPT:
2486 param->fp_verbose |= VERBOSE_COMP_COUNT;
2487 param->fp_max_depth = 0;
2489 case LFS_COMP_FLAGS_OPT:
2490 if (optarg != NULL) {
2491 __u32 *flags = ¶m->fp_comp_flags;
2492 rc = comp_str2flags(flags, optarg);
2494 fprintf(stderr, "error: %s bad "
2495 "component flags '%s'.\n",
2499 param->fp_check_comp_flags = 1;
2500 param->fp_exclude_comp_flags =
2501 comp_flags_is_neg(*flags);
2502 comp_flags_clear_neg(flags);
2505 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2506 param->fp_max_depth = 0;
2509 case LFS_COMP_START_OPT:
2510 if (optarg != NULL) {
2512 if (tmp[0] == '+') {
2513 param->fp_comp_start_sign = -1;
2515 } else if (tmp[0] == '-') {
2516 param->fp_comp_start_sign = 1;
2519 rc = llapi_parse_size(tmp,
2520 ¶m->fp_comp_start,
2521 ¶m->fp_comp_start_units, 0);
2523 fprintf(stderr, "error: %s bad "
2524 "component start '%s'.\n",
2528 param->fp_check_comp_start = 1;
2531 param->fp_verbose |= VERBOSE_COMP_START;
2532 param->fp_max_depth = 0;
2536 param->fp_max_depth = 0;
2539 param->fp_get_default_lmv = 1;
2542 if (optarg != NULL) {
2544 if (tmp[0] == '+') {
2545 param->fp_comp_end_sign = -1;
2547 } else if (tmp[0] == '-') {
2548 param->fp_comp_end_sign = 1;
2552 if (arg_is_eof(tmp)) {
2553 param->fp_comp_end = LUSTRE_EOF;
2554 param->fp_comp_end_units = 1;
2557 rc = llapi_parse_size(tmp,
2558 ¶m->fp_comp_end,
2559 ¶m->fp_comp_end_units, 0);
2562 fprintf(stderr, "error: %s bad "
2563 "component end '%s'.\n",
2567 param->fp_check_comp_end = 1;
2569 param->fp_verbose |= VERBOSE_COMP_END;
2570 param->fp_max_depth = 0;
2574 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2575 param->fp_verbose |= VERBOSE_DFID;
2576 param->fp_max_depth = 0;
2580 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2581 param->fp_verbose |= VERBOSE_GENERATION;
2582 param->fp_max_depth = 0;
2585 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2587 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2588 "use '--stripe-index|-i' instead\n");
2591 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2592 if (strcmp(argv[optind - 1], "--index") == 0)
2593 fprintf(stderr, "warning: '--index' deprecated"
2594 ", use '--stripe-index' instead\n");
2596 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2597 param->fp_verbose |= VERBOSE_OFFSET;
2598 param->fp_max_depth = 0;
2602 if (optarg != NULL) {
2603 param->fp_comp_id = strtoul(optarg, &end, 0);
2604 if (*end != '\0' || param->fp_comp_id == 0 ||
2605 param->fp_comp_id > LCME_ID_MAX) {
2606 fprintf(stderr, "error: %s bad "
2607 "component id '%s'\n",
2611 param->fp_check_comp_id = 1;
2614 param->fp_max_depth = 0;
2615 param->fp_verbose |= VERBOSE_COMP_ID;
2619 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2620 param->fp_verbose |= VERBOSE_LAYOUT;
2621 param->fp_max_depth = 0;
2624 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2626 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2627 fprintf(stderr, "warning: '-M' deprecated"
2628 ", use '-m' instead\n");
2632 if (!(param->fp_verbose & VERBOSE_DETAIL))
2633 param->fp_max_depth = 0;
2634 param->fp_verbose |= VERBOSE_MDTINDEX;
2637 if (param->fp_obd_uuid) {
2639 "error: %s: only one obduuid allowed",
2643 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2646 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2647 param->fp_verbose |= VERBOSE_POOL;
2648 param->fp_max_depth = 0;
2655 param->fp_recursive = 1;
2660 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2662 fprintf(stderr, "warning: '--size|-s' deprecated, "
2663 "use '--stripe-size|-S' instead\n");
2664 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2666 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2667 param->fp_verbose |= VERBOSE_SIZE;
2668 param->fp_max_depth = 0;
2672 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2685 if (param->fp_recursive)
2686 param->fp_max_depth = -1;
2687 else if (param->fp_verbose & VERBOSE_DETAIL)
2688 param->fp_max_depth = 1;
2690 if (!param->fp_verbose)
2691 param->fp_verbose = VERBOSE_DEFAULT;
2692 if (param->fp_quiet)
2693 param->fp_verbose = VERBOSE_OBJID;
2696 rc = llapi_getstripe(argv[optind], param);
2697 } while (++optind < argc && !rc);
2700 fprintf(stderr, "error: %s failed for %s.\n",
2701 argv[0], argv[optind - 1]);
2705 static int lfs_tgts(int argc, char **argv)
2707 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2708 struct find_param param;
2709 int index = 0, rc=0;
2714 if (argc == 2 && !realpath(argv[1], path)) {
2716 fprintf(stderr, "error: invalid path '%s': %s\n",
2717 argv[1], strerror(-rc));
2721 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2722 /* Check if we have a mount point */
2723 if (mntdir[0] == '\0')
2726 memset(¶m, 0, sizeof(param));
2727 if (!strcmp(argv[0], "mdts"))
2728 param.fp_get_lmv = 1;
2730 rc = llapi_ostlist(mntdir, ¶m);
2732 fprintf(stderr, "error: %s: failed on %s\n",
2735 if (path[0] != '\0')
2737 memset(mntdir, 0, PATH_MAX);
2743 static int lfs_getstripe(int argc, char **argv)
2745 struct find_param param = { 0 };
2747 param.fp_max_depth = 1;
2748 return lfs_getstripe_internal(argc, argv, ¶m);
2752 static int lfs_getdirstripe(int argc, char **argv)
2754 struct find_param param = { 0 };
2755 struct option long_opts[] = {
2756 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2757 {"mdt-count", no_argument, 0, 'c'},
2759 {"mdt-hash", no_argument, 0, 'H'},
2760 {"mdt-index", no_argument, 0, 'i'},
2761 {"recursive", no_argument, 0, 'r'},
2762 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2763 {"mdt-hash", no_argument, 0, 't'},
2765 {"default", no_argument, 0, 'D'},
2766 {"obd", required_argument, 0, 'O'},
2767 {"mdt-count", no_argument, 0, 'T'},
2768 {"yaml", no_argument, 0, 'y'},
2773 param.fp_get_lmv = 1;
2775 while ((c = getopt_long(argc, argv,
2776 "cDHiO:rtTy", long_opts, NULL)) != -1)
2780 if (param.fp_obd_uuid) {
2782 "error: %s: only one obduuid allowed",
2786 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2788 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2790 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2791 fprintf(stderr, "warning: '-c' deprecated"
2792 ", use '-T' instead\n");
2796 param.fp_verbose |= VERBOSE_COUNT;
2799 param.fp_verbose |= VERBOSE_OFFSET;
2801 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2805 param.fp_verbose |= VERBOSE_HASH_TYPE;
2808 param.fp_get_default_lmv = 1;
2811 param.fp_recursive = 1;
2824 if (param.fp_recursive)
2825 param.fp_max_depth = -1;
2827 if (!param.fp_verbose)
2828 param.fp_verbose = VERBOSE_DEFAULT;
2831 rc = llapi_getstripe(argv[optind], ¶m);
2832 } while (++optind < argc && !rc);
2835 fprintf(stderr, "error: %s failed for %s.\n",
2836 argv[0], argv[optind - 1]);
2841 static int lfs_setdirstripe(int argc, char **argv)
2845 unsigned int stripe_offset = -1;
2846 unsigned int stripe_count = 1;
2847 enum lmv_hash_type hash_type;
2850 char *stripe_offset_opt = NULL;
2851 char *stripe_count_opt = NULL;
2852 char *stripe_hash_opt = NULL;
2853 char *mode_opt = NULL;
2854 bool default_stripe = false;
2855 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2856 mode_t previous_mode = 0;
2857 bool delete = false;
2859 struct option long_opts[] = {
2860 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2861 { .val = 'c', .name = "count", .has_arg = required_argument },
2863 { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
2864 { .val = 'd', .name = "delete", .has_arg = no_argument },
2865 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2866 { .val = 'i', .name = "index", .has_arg = required_argument },
2868 { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
2869 { .val = 'm', .name = "mode", .has_arg = required_argument },
2870 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2871 { .val = 't', .name = "hash-type", .has_arg = required_argument },
2872 { .val = 't', .name = "mdt-hash", .has_arg = required_argument },
2874 {"mdt-hash", required_argument, 0, 'H'},
2875 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2876 { .val = 'D', .name = "default_stripe",
2877 .has_arg = no_argument },
2879 { .val = 'D', .name = "default", .has_arg = no_argument },
2882 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2889 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2890 if (strcmp(argv[optind - 1], "--count") == 0)
2891 fprintf(stderr, "warning: '--count' deprecated"
2892 ", use '--mdt-count' instead\n");
2894 stripe_count_opt = optarg;
2898 default_stripe = true;
2901 default_stripe = true;
2904 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2905 if (strcmp(argv[optind - 1], "--index") == 0)
2906 fprintf(stderr, "warning: '--index' deprecated"
2907 ", use '--mdt-index' instead\n");
2909 stripe_offset_opt = optarg;
2914 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2918 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2919 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2920 fprintf(stderr, "warning: '--hash-type' "
2921 "deprecated, use '--mdt-hash' "
2924 stripe_hash_opt = optarg;
2927 fprintf(stderr, "error: %s: option '%s' "
2929 argv[0], argv[optind - 1]);
2934 if (optind == argc) {
2935 fprintf(stderr, "error: %s: missing dirname\n",
2940 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2941 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2946 if (stripe_offset_opt != NULL) {
2947 /* get the stripe offset */
2948 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2950 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2951 argv[0], stripe_offset_opt);
2957 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2958 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2959 " or -i options.\n", argv[0]);
2967 if (mode_opt != NULL) {
2968 mode = strtoul(mode_opt, &end, 8);
2970 fprintf(stderr, "error: %s: bad mode '%s'\n",
2974 previous_mode = umask(0);
2977 if (stripe_hash_opt == NULL) {
2978 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2980 hash_type = check_hashtype(stripe_hash_opt);
2981 if (hash_type == 0) {
2983 "error: %s: bad stripe hash type '%s'\n",
2984 argv[0], stripe_hash_opt);
2989 /* get the stripe count */
2990 if (stripe_count_opt != NULL) {
2991 stripe_count = strtoul(stripe_count_opt, &end, 0);
2993 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2994 argv[0], stripe_count_opt);
2999 dname = argv[optind];
3001 if (default_stripe) {
3002 result = llapi_dir_set_default_lmv_stripe(dname,
3003 stripe_offset, stripe_count,
3006 result = llapi_dir_create_pool(dname, mode,
3008 stripe_count, hash_type,
3013 fprintf(stderr, "error: %s: create stripe dir '%s' "
3014 "failed\n", argv[0], dname);
3017 dname = argv[++optind];
3018 } while (dname != NULL);
3020 if (mode_opt != NULL)
3021 umask(previous_mode);
3027 static int lfs_rmentry(int argc, char **argv)
3034 fprintf(stderr, "error: %s: missing dirname\n",
3040 dname = argv[index];
3041 while (dname != NULL) {
3042 result = llapi_direntry_remove(dname);
3044 fprintf(stderr, "error: %s: remove dir entry '%s' "
3045 "failed\n", argv[0], dname);
3048 dname = argv[++index];
3053 static int lfs_mv(int argc, char **argv)
3055 struct find_param param = {
3062 struct option long_opts[] = {
3063 {"mdt-index", required_argument, 0, 'M'},
3064 {"verbose", no_argument, 0, 'v'},
3068 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3071 param.fp_mdt_index = strtoul(optarg, &end, 0);
3073 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3080 param.fp_verbose = VERBOSE_DETAIL;
3084 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3085 argv[0], argv[optind - 1]);
3090 if (param.fp_mdt_index == -1) {
3091 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3095 if (optind >= argc) {
3096 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3100 param.fp_migrate = 1;
3101 rc = llapi_migrate_mdt(argv[optind], ¶m);
3103 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3104 argv[0], argv[optind], param.fp_mdt_index,
3109 static int lfs_osts(int argc, char **argv)
3111 return lfs_tgts(argc, argv);
3114 static int lfs_mdts(int argc, char **argv)
3116 return lfs_tgts(argc, argv);
3119 #define COOK(value) \
3122 while (value > 1024) { \
3130 #define CDF "%11llu"
3131 #define HDF "%8.1f%c"
3136 MNTDF_INODES = 0x0001,
3137 MNTDF_COOKED = 0x0002,
3138 MNTDF_LAZY = 0x0004,
3139 MNTDF_VERBOSE = 0x0008,
3142 static int showdf(char *mntdir, struct obd_statfs *stat,
3143 char *uuid, enum mntdf_flags flags,
3144 char *type, int index, int rc)
3146 long long avail, used, total;
3148 char *suffix = "KMGTPEZY";
3149 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3150 char tbuf[3 * sizeof(__u64)];
3151 char ubuf[3 * sizeof(__u64)];
3152 char abuf[3 * sizeof(__u64)];
3153 char rbuf[3 * sizeof(__u64)];
3160 if (flags & MNTDF_INODES) {
3161 avail = stat->os_ffree;
3162 used = stat->os_files - stat->os_ffree;
3163 total = stat->os_files;
3165 int shift = flags & MNTDF_COOKED ? 0 : 10;
3167 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3168 used = ((stat->os_blocks - stat->os_bfree) *
3169 stat->os_bsize) >> shift;
3170 total = (stat->os_blocks * stat->os_bsize) >> shift;
3173 if ((used + avail) > 0)
3174 ratio = (double)used / (double)(used + avail);
3176 if (flags & MNTDF_COOKED) {
3180 cook_val = (double)total;
3183 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3186 snprintf(tbuf, sizeof(tbuf), CDF, total);
3188 cook_val = (double)used;
3191 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3194 snprintf(ubuf, sizeof(ubuf), CDF, used);
3196 cook_val = (double)avail;
3199 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3202 snprintf(abuf, sizeof(abuf), CDF, avail);
3204 snprintf(tbuf, sizeof(tbuf), CDF, total);
3205 snprintf(ubuf, sizeof(tbuf), CDF, used);
3206 snprintf(abuf, sizeof(tbuf), CDF, avail);
3209 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3210 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3211 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3213 printf("[%s:%d]", type, index);
3215 if (stat->os_state) {
3217 * Each character represents the matching
3220 const char state_names[] = "DRSI";
3225 for (i = 0, state = stat->os_state;
3226 state && i < sizeof(state_names); i++) {
3227 if (!(state & (1 << i)))
3229 printf("%c", state_names[i]);
3237 printf(UUF": inactive device\n", uuid);
3240 printf(UUF": %s\n", uuid, strerror(-rc));
3247 struct ll_stat_type {
3252 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3254 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3255 struct obd_uuid uuid_buf;
3256 char *poolname = NULL;
3257 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3258 { LL_STATFS_LOV, "OST" },
3260 struct ll_stat_type *tp;
3261 __u64 ost_ffree = 0;
3269 poolname = strchr(pool, '.');
3270 if (poolname != NULL) {
3271 if (strncmp(fsname, pool, strlen(fsname))) {
3272 fprintf(stderr, "filesystem name incorrect\n");
3280 fd = open(mntdir, O_RDONLY);
3283 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3288 if (flags & MNTDF_INODES)
3289 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3290 "UUID", "Inodes", "IUsed", "IFree",
3291 "IUse%", "Mounted on");
3293 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3294 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3295 "Used", "Available", "Use%", "Mounted on");
3297 for (tp = types; tp->st_name != NULL; tp++) {
3298 for (index = 0; ; index++) {
3299 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3300 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3301 type = flags & MNTDF_LAZY ?
3302 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3303 rc2 = llapi_obd_fstatfs(fd, type, index,
3304 &stat_buf, &uuid_buf);
3309 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3310 if (!(flags & MNTDF_VERBOSE))
3312 } else if (rc2 < 0 && rc == 0) {
3316 if (poolname && tp->st_op == LL_STATFS_LOV &&
3317 llapi_search_ost(fsname, poolname,
3318 obd_uuid2str(&uuid_buf)) != 1)
3321 /* the llapi_obd_statfs() call may have returned with
3322 * an error, but if it filled in uuid_buf we will at
3323 * lease use that to print out a message for that OBD.
3324 * If we didn't get anything in the uuid_buf, then fill
3325 * it in so that we can print an error message. */
3326 if (uuid_buf.uuid[0] == '\0')
3327 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3328 "%s%04x", tp->st_name, index);
3329 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3330 flags, tp->st_name, index, rc2);
3333 if (tp->st_op == LL_STATFS_LMV) {
3334 sum.os_ffree += stat_buf.os_ffree;
3335 sum.os_files += stat_buf.os_files;
3336 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3337 sum.os_blocks += stat_buf.os_blocks *
3339 sum.os_bfree += stat_buf.os_bfree *
3341 sum.os_bavail += stat_buf.os_bavail *
3343 ost_ffree += stat_buf.os_ffree;
3351 /* If we don't have as many objects free on the OST as inodes
3352 * on the MDS, we reduce the total number of inodes to
3353 * compensate, so that the "inodes in use" number is correct.
3354 * Matches ll_statfs_internal() so the results are consistent. */
3355 if (ost_ffree < sum.os_ffree) {
3356 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3357 sum.os_ffree = ost_ffree;
3360 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3366 static int lfs_df(int argc, char **argv)
3368 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3369 enum mntdf_flags flags = 0;
3370 int c, rc = 0, index = 0;
3371 char fsname[PATH_MAX] = "", *pool_name = NULL;
3372 struct option long_opts[] = {
3373 { .val = 'h', .name = "human-readable",
3374 .has_arg = no_argument },
3375 { .val = 'i', .name = "inodes", .has_arg = no_argument },
3376 { .val = 'l', .name = "lazy", .has_arg = no_argument },
3377 { .val = 'p', .name = "pool", .has_arg = required_argument },
3378 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3381 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3384 flags |= MNTDF_COOKED;
3387 flags |= MNTDF_INODES;
3390 flags |= MNTDF_LAZY;
3396 flags |= MNTDF_VERBOSE;
3402 if (optind < argc && !realpath(argv[optind], path)) {
3404 fprintf(stderr, "error: invalid path '%s': %s\n",
3405 argv[optind], strerror(-rc));
3409 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3410 /* Check if we have a mount point */
3411 if (mntdir[0] == '\0')
3414 rc = mntdf(mntdir, fsname, pool_name, flags);
3415 if (rc || path[0] != '\0')
3417 fsname[0] = '\0'; /* avoid matching in next loop */
3418 mntdir[0] = '\0'; /* avoid matching in next loop */
3424 static int lfs_getname(int argc, char **argv)
3426 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3427 int rc = 0, index = 0, c;
3428 char buf[sizeof(struct obd_uuid)];
3430 while ((c = getopt(argc, argv, "h")) != -1)
3433 if (optind == argc) { /* no paths specified, get all paths. */
3434 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3435 rc = llapi_getname(mntdir, buf, sizeof(buf));
3438 "cannot get name for `%s': %s\n",
3439 mntdir, strerror(-rc));
3443 printf("%s %s\n", buf, mntdir);
3445 path[0] = fsname[0] = mntdir[0] = 0;
3447 } else { /* paths specified, only attempt to search these. */
3448 for (; optind < argc; optind++) {
3449 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3452 "cannot get name for `%s': %s\n",
3453 argv[optind], strerror(-rc));
3457 printf("%s %s\n", buf, argv[optind]);
3463 static int lfs_check(int argc, char **argv)
3466 char mntdir[PATH_MAX] = {'\0'};
3475 obd_types[0] = obd_type1;
3476 obd_types[1] = obd_type2;
3478 if (strcmp(argv[1], "osts") == 0) {
3479 strcpy(obd_types[0], "osc");
3480 } else if (strcmp(argv[1], "mds") == 0) {
3481 strcpy(obd_types[0], "mdc");
3482 } else if (strcmp(argv[1], "servers") == 0) {
3484 strcpy(obd_types[0], "osc");
3485 strcpy(obd_types[1], "mdc");
3487 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3492 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3493 if (rc < 0 || mntdir[0] == '\0') {
3494 fprintf(stderr, "No suitable Lustre mount found\n");
3498 rc = llapi_target_check(num_types, obd_types, mntdir);
3500 fprintf(stderr, "error: %s: %s status failed\n",
3507 #ifdef HAVE_SYS_QUOTA_H
3508 #define ARG2INT(nr, str, msg) \
3511 nr = strtol(str, &endp, 0); \
3513 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3518 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3520 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3521 * returns the value or ULONG_MAX on integer overflow or incorrect format
3523 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3524 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3525 * 3. empty integer value is interpreted as 0
3527 static unsigned long str2sec(const char* timestr)
3529 const char spec[] = "smhdw";
3530 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3531 unsigned long val = 0;
3534 if (strpbrk(timestr, spec) == NULL) {
3535 /* no specifiers inside the time string,
3536 should treat it as an integer value */
3537 val = strtoul(timestr, &tail, 10);
3538 return *tail ? ULONG_MAX : val;
3541 /* format string is XXwXXdXXhXXmXXs */
3547 v = strtoul(timestr, &tail, 10);
3548 if (v == ULONG_MAX || *tail == '\0')
3549 /* value too large (ULONG_MAX or more)
3550 or missing specifier */
3553 ptr = strchr(spec, *tail);
3555 /* unknown specifier */
3560 /* check if product will overflow the type */
3561 if (!(v < ULONG_MAX / mult[ind]))
3564 ADD_OVERFLOW(val, mult[ind] * v);
3565 if (val == ULONG_MAX)
3577 #define ARG2ULL(nr, str, def_units) \
3579 unsigned long long limit, units = def_units; \
3582 rc = llapi_parse_size(str, &limit, &units, 1); \
3584 fprintf(stderr, "error: bad limit value %s\n", str); \
3590 static inline int has_times_option(int argc, char **argv)
3594 for (i = 1; i < argc; i++)
3595 if (!strcmp(argv[i], "-t"))
3601 int lfs_setquota_times(int argc, char **argv)
3604 struct if_quotactl qctl;
3605 char *mnt, *obd_type = (char *)qctl.obd_type;
3606 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3607 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3608 struct option long_opts[] = {
3609 { .val = 'b', .name = "block-grace", .has_arg = required_argument },
3610 { .val = 'g', .name = "group", .has_arg = no_argument },
3611 { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
3612 { .val = 'p', .name = "projid", .has_arg = no_argument },
3613 { .val = 't', .name = "times", .has_arg = no_argument },
3614 { .val = 'u', .name = "user", .has_arg = no_argument },
3618 memset(&qctl, 0, sizeof(qctl));
3619 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3620 qctl.qc_type = ALLQUOTA;
3622 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3623 long_opts, NULL)) != -1) {
3634 if (qctl.qc_type != ALLQUOTA) {
3635 fprintf(stderr, "error: -u/g/p can't be used "
3636 "more than once\n");
3639 qctl.qc_type = qtype;
3642 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3643 fprintf(stderr, "error: bad block-grace: %s\n",
3647 dqb->dqb_valid |= QIF_BTIME;
3650 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3651 fprintf(stderr, "error: bad inode-grace: %s\n",
3655 dqb->dqb_valid |= QIF_ITIME;
3657 case 't': /* Yes, of course! */
3659 default: /* getopt prints error message for us when opterr != 0 */
3664 if (qctl.qc_type == ALLQUOTA) {
3665 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3669 if (optind != argc - 1) {
3670 fprintf(stderr, "error: unexpected parameters encountered\n");
3675 rc = llapi_quotactl(mnt, &qctl);
3678 fprintf(stderr, "%s %s ", obd_type,
3679 obd_uuid2str(&qctl.obd_uuid));
3680 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3687 #define BSLIMIT (1 << 0)
3688 #define BHLIMIT (1 << 1)
3689 #define ISLIMIT (1 << 2)
3690 #define IHLIMIT (1 << 3)
3692 int lfs_setquota(int argc, char **argv)
3695 struct if_quotactl qctl;
3696 char *mnt, *obd_type = (char *)qctl.obd_type;
3697 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3698 struct option long_opts[] = {
3699 {"block-softlimit", required_argument, 0, 'b'},
3700 {"block-hardlimit", required_argument, 0, 'B'},
3701 {"group", required_argument, 0, 'g'},
3702 {"inode-softlimit", required_argument, 0, 'i'},
3703 {"inode-hardlimit", required_argument, 0, 'I'},
3704 {"user", required_argument, 0, 'u'},
3705 {"projid", required_argument, 0, 'p'},
3708 unsigned limit_mask = 0;
3712 if (has_times_option(argc, argv))
3713 return lfs_setquota_times(argc, argv);
3715 memset(&qctl, 0, sizeof(qctl));
3716 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3717 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3718 * so it can be used as a marker that qc_type
3719 * isn't reinitialized from command line */
3721 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3722 long_opts, NULL)) != -1) {
3726 rc = name2uid(&qctl.qc_id, optarg);
3730 rc = name2gid(&qctl.qc_id, optarg);
3734 rc = name2projid(&qctl.qc_id, optarg);
3736 if (qctl.qc_type != ALLQUOTA) {
3737 fprintf(stderr, "error: -u and -g can't be used"
3738 " more than once\n");
3741 qctl.qc_type = qtype;
3743 qctl.qc_id = strtoul(optarg, &endptr, 10);
3744 if (*endptr != '\0') {
3745 fprintf(stderr, "error: can't find id "
3746 "for name %s\n", optarg);
3752 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3753 dqb->dqb_bsoftlimit >>= 10;
3754 limit_mask |= BSLIMIT;
3755 if (dqb->dqb_bsoftlimit &&
3756 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3757 fprintf(stderr, "warning: block softlimit is "
3758 "smaller than the miminal qunit size, "
3759 "please see the help of setquota or "
3760 "Lustre manual for details.\n");
3763 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3764 dqb->dqb_bhardlimit >>= 10;
3765 limit_mask |= BHLIMIT;
3766 if (dqb->dqb_bhardlimit &&
3767 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3768 fprintf(stderr, "warning: block hardlimit is "
3769 "smaller than the miminal qunit size, "
3770 "please see the help of setquota or "
3771 "Lustre manual for details.\n");
3774 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3775 limit_mask |= ISLIMIT;
3776 if (dqb->dqb_isoftlimit &&
3777 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3778 fprintf(stderr, "warning: inode softlimit is "
3779 "smaller than the miminal qunit size, "
3780 "please see the help of setquota or "
3781 "Lustre manual for details.\n");
3784 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3785 limit_mask |= IHLIMIT;
3786 if (dqb->dqb_ihardlimit &&
3787 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3788 fprintf(stderr, "warning: inode hardlimit is "
3789 "smaller than the miminal qunit size, "
3790 "please see the help of setquota or "
3791 "Lustre manual for details.\n");
3793 default: /* getopt prints error message for us when opterr != 0 */
3798 if (qctl.qc_type == ALLQUOTA) {
3799 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3803 if (limit_mask == 0) {
3804 fprintf(stderr, "error: at least one limit must be specified\n");
3808 if (optind != argc - 1) {
3809 fprintf(stderr, "error: unexpected parameters encountered\n");
3815 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3816 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3817 /* sigh, we can't just set blimits/ilimits */
3818 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3819 .qc_type = qctl.qc_type,
3820 .qc_id = qctl.qc_id};
3822 rc = llapi_quotactl(mnt, &tmp_qctl);
3824 fprintf(stderr, "error: setquota failed while retrieving"
3825 " current quota settings (%s)\n",
3830 if (!(limit_mask & BHLIMIT))
3831 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3832 if (!(limit_mask & BSLIMIT))
3833 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3834 if (!(limit_mask & IHLIMIT))
3835 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3836 if (!(limit_mask & ISLIMIT))
3837 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3839 /* Keep grace times if we have got no softlimit arguments */
3840 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3841 dqb->dqb_valid |= QIF_BTIME;
3842 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3845 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3846 dqb->dqb_valid |= QIF_ITIME;
3847 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3851 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3852 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3854 rc = llapi_quotactl(mnt, &qctl);
3857 fprintf(stderr, "%s %s ", obd_type,
3858 obd_uuid2str(&qctl.obd_uuid));
3859 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3866 /* Converts seconds value into format string
3867 * result is returned in buf
3869 * 1. result is in descenting order: 1w2d3h4m5s
3870 * 2. zero fields are not filled (except for p. 3): 5d1s
3871 * 3. zero seconds value is presented as "0s"
3873 static char * __sec2str(time_t seconds, char *buf)
3875 const char spec[] = "smhdw";
3876 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3881 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3882 c = seconds / mult[i];
3884 if (c > 0 || (i == 0 && buf == tail))
3885 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3893 static void sec2str(time_t seconds, char *buf, int rc)
3900 tail = __sec2str(seconds, tail);
3902 if (rc && tail - buf < 39) {
3908 static void diff2str(time_t seconds, char *buf, time_t now)
3914 if (seconds <= now) {
3915 strcpy(buf, "none");
3918 __sec2str(seconds - now, buf);
3921 static void print_quota_title(char *name, struct if_quotactl *qctl,
3922 bool human_readable)
3924 printf("Disk quotas for %s %s (%cid %u):\n",
3925 qtype_name(qctl->qc_type), name,
3926 *qtype_name(qctl->qc_type), qctl->qc_id);
3927 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3928 "Filesystem", human_readable ? "used" : "kbytes",
3929 "quota", "limit", "grace",
3930 "files", "quota", "limit", "grace");
3933 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3936 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3939 snprintf(buf, buflen, "%5.4gP",
3940 (double)num / ((__u64)1 << 40));
3942 snprintf(buf, buflen, "%5.4gT",
3943 (double)num / (1 << 30));
3945 snprintf(buf, buflen, "%5.4gG",
3946 (double)num / (1 << 20));
3948 snprintf(buf, buflen, "%5.4gM",
3949 (double)num / (1 << 10));
3951 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3955 #define STRBUF_LEN 32
3956 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3963 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3964 int bover = 0, iover = 0;
3965 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3966 char numbuf[3][STRBUF_LEN];
3968 char strbuf[STRBUF_LEN];
3970 if (dqb->dqb_bhardlimit &&
3971 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3973 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3974 if (dqb->dqb_btime > now) {
3981 if (dqb->dqb_ihardlimit &&
3982 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3984 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3985 if (dqb->dqb_itime > now) {
3993 if (strlen(mnt) > 15)
3994 printf("%s\n%15s", mnt, "");
3996 printf("%15s", mnt);
3999 diff2str(dqb->dqb_btime, timebuf, now);
4001 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
4002 strbuf, sizeof(strbuf), h);
4003 if (rc == -EREMOTEIO)
4004 sprintf(numbuf[0], "%s*", strbuf);
4006 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
4007 "%s" : "[%s]", strbuf);
4009 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
4010 if (type == QC_GENERAL)
4011 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4012 "%s" : "[%s]", strbuf);
4014 sprintf(numbuf[1], "%s", "-");
4016 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4017 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4018 "%s" : "[%s]", strbuf);
4020 printf(" %7s%c %6s %7s %7s",
4021 numbuf[0], bover ? '*' : ' ', numbuf[1],
4022 numbuf[2], bover > 1 ? timebuf : "-");
4025 diff2str(dqb->dqb_itime, timebuf, now);
4027 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4028 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4030 if (type == QC_GENERAL)
4031 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4033 (uintmax_t)dqb->dqb_isoftlimit);
4035 sprintf(numbuf[1], "%s", "-");
4037 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4038 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4040 if (type != QC_OSTIDX)
4041 printf(" %7s%c %6s %7s %7s",
4042 numbuf[0], iover ? '*' : ' ', numbuf[1],
4043 numbuf[2], iover > 1 ? timebuf : "-");
4045 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4048 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4049 qctl->qc_cmd == Q_GETOINFO) {
4053 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4054 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4055 printf("Block grace time: %s; Inode grace time: %s\n",
4056 bgtimebuf, igtimebuf);
4060 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4061 bool h, __u64 *total)
4063 int rc = 0, rc1 = 0, count = 0;
4064 __u32 valid = qctl->qc_valid;
4066 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4068 fprintf(stderr, "can not get %s count: %s\n",
4069 is_mdt ? "mdt": "ost", strerror(-rc));
4073 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4074 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4075 rc = llapi_quotactl(mnt, qctl);
4077 /* It is remote client case. */
4078 if (rc == -EOPNOTSUPP) {
4085 fprintf(stderr, "quotactl %s%d failed.\n",
4086 is_mdt ? "mdt": "ost", qctl->qc_idx);
4090 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4091 qctl->qc_valid, 0, h);
4092 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4093 qctl->qc_dqblk.dqb_bhardlimit;
4096 qctl->qc_valid = valid;
4100 static int lfs_quota(int argc, char **argv)
4103 char *mnt, *name = NULL;
4104 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4105 .qc_type = ALLQUOTA };
4106 char *obd_type = (char *)qctl.obd_type;
4107 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4108 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4109 verbose = 0, pass = 0, quiet = 0, inacc;
4111 __u32 valid = QC_GENERAL, idx = 0;
4112 __u64 total_ialloc = 0, total_balloc = 0;
4113 bool human_readable = false;
4116 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4127 if (qctl.qc_type != ALLQUOTA) {
4128 fprintf(stderr, "error: use either -u or -g\n");
4131 qctl.qc_type = qtype;
4134 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4137 valid = qctl.qc_valid = QC_UUID;
4138 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4141 valid = qctl.qc_valid = QC_MDTIDX;
4142 idx = qctl.qc_idx = atoi(optarg);
4145 valid = qctl.qc_valid = QC_OSTIDX;
4146 idx = qctl.qc_idx = atoi(optarg);
4155 human_readable = true;
4158 fprintf(stderr, "error: %s: option '-%c' "
4159 "unrecognized\n", argv[0], c);
4164 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4165 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4166 optind == argc - 1) {
4168 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4169 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4170 qctl.qc_valid = valid;
4172 qctl.qc_type = pass;
4173 switch (qctl.qc_type) {
4175 qctl.qc_id = geteuid();
4176 rc = uid2name(&name, qctl.qc_id);
4179 qctl.qc_id = getegid();
4180 rc = gid2name(&name, qctl.qc_id);
4189 /* lfs quota -u username /path/to/lustre/mount */
4190 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4191 /* options should be followed by u/g-name and mntpoint */
4192 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4193 fprintf(stderr, "error: missing quota argument(s)\n");
4197 name = argv[optind++];
4198 switch (qctl.qc_type) {
4200 rc = name2uid(&qctl.qc_id, name);
4203 rc = name2gid(&qctl.qc_id, name);
4206 rc = name2projid(&qctl.qc_id, name);
4213 qctl.qc_id = strtoul(name, &endptr, 10);
4214 if (*endptr != '\0') {
4215 fprintf(stderr, "error: can't find id for name: %s\n",
4220 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4221 fprintf(stderr, "error: missing quota info argument(s)\n");
4226 rc1 = llapi_quotactl(mnt, &qctl);
4230 fprintf(stderr, "%s quotas are not enabled.\n",
4231 qtype_name(qctl.qc_type));
4234 fprintf(stderr, "Permission denied.\n");
4237 /* We already got error message. */
4240 fprintf(stderr, "Unexpected quotactl error: %s\n",
4245 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4246 print_quota_title(name, &qctl, human_readable);
4248 if (rc1 && *obd_type)
4249 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4251 if (qctl.qc_valid != QC_GENERAL)
4254 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4255 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4256 (QIF_LIMITS|QIF_USAGE));
4258 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4260 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4262 char strbuf[STRBUF_LEN];
4264 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4266 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4268 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4270 printf("Total allocated inode limit: %ju, total "
4271 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4275 if (rc1 || rc2 || rc3 || inacc)
4276 printf("Some errors happened when getting quota info. "
4277 "Some devices may be not working or deactivated. "
4278 "The data in \"[]\" is inaccurate.\n");
4281 if (pass > 0 && pass < LL_MAXQUOTAS)
4286 #endif /* HAVE_SYS_QUOTA_H! */
4288 static int flushctx_ioctl(char *mp)
4292 fd = open(mp, O_RDONLY);
4294 fprintf(stderr, "flushctx: error open %s: %s\n",
4295 mp, strerror(errno));
4299 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4301 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4302 mp, strerror(errno));
4308 static int lfs_flushctx(int argc, char **argv)
4310 int kdestroy = 0, c;
4311 char mntdir[PATH_MAX] = {'\0'};
4315 while ((c = getopt(argc, argv, "k")) != -1) {
4321 fprintf(stderr, "error: %s: option '-%c' "
4322 "unrecognized\n", argv[0], c);
4328 if ((rc = system("kdestroy > /dev/null")) != 0) {
4329 rc = WEXITSTATUS(rc);
4330 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4334 if (optind >= argc) {
4335 /* flush for all mounted lustre fs. */
4336 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4337 /* Check if we have a mount point */
4338 if (mntdir[0] == '\0')
4341 if (flushctx_ioctl(mntdir))
4344 mntdir[0] = '\0'; /* avoid matching in next loop */
4347 /* flush fs as specified */
4348 while (optind < argc) {
4349 if (flushctx_ioctl(argv[optind++]))
4356 static int lfs_cp(int argc, char **argv)
4358 fprintf(stderr, "remote client copy file(s).\n"
4359 "obsolete, does not support it anymore.\n");
4363 static int lfs_ls(int argc, char **argv)
4365 fprintf(stderr, "remote client lists directory contents.\n"
4366 "obsolete, does not support it anymore.\n");
4370 static int lfs_changelog(int argc, char **argv)
4372 void *changelog_priv;
4373 struct changelog_rec *rec;
4374 long long startrec = 0, endrec = 0;
4376 struct option long_opts[] = {
4377 {"follow", no_argument, 0, 'f'},
4380 char short_opts[] = "f";
4383 while ((rc = getopt_long(argc, argv, short_opts,
4384 long_opts, NULL)) != -1) {
4392 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4393 argv[0], argv[optind - 1]);
4400 mdd = argv[optind++];
4402 startrec = strtoll(argv[optind++], NULL, 10);
4404 endrec = strtoll(argv[optind++], NULL, 10);
4406 rc = llapi_changelog_start(&changelog_priv,
4407 CHANGELOG_FLAG_BLOCK |
4408 CHANGELOG_FLAG_JOBID |
4409 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4412 fprintf(stderr, "Can't start changelog: %s\n",
4413 strerror(errno = -rc));
4417 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4421 if (endrec && rec->cr_index > endrec) {
4422 llapi_changelog_free(&rec);
4425 if (rec->cr_index < startrec) {
4426 llapi_changelog_free(&rec);
4430 secs = rec->cr_time >> 30;
4431 gmtime_r(&secs, &ts);
4432 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4433 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4434 changelog_type2str(rec->cr_type),
4435 ts.tm_hour, ts.tm_min, ts.tm_sec,
4436 (int)(rec->cr_time & ((1 << 30) - 1)),
4437 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4438 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4440 if (rec->cr_flags & CLF_JOBID) {
4441 struct changelog_ext_jobid *jid =
4442 changelog_rec_jobid(rec);
4444 if (jid->cr_jobid[0] != '\0')
4445 printf(" j=%s", jid->cr_jobid);
4448 if (rec->cr_namelen)
4449 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4450 rec->cr_namelen, changelog_rec_name(rec));
4452 if (rec->cr_flags & CLF_RENAME) {
4453 struct changelog_ext_rename *rnm =
4454 changelog_rec_rename(rec);
4456 if (!fid_is_zero(&rnm->cr_sfid))
4457 printf(" s="DFID" sp="DFID" %.*s",
4458 PFID(&rnm->cr_sfid),
4459 PFID(&rnm->cr_spfid),
4460 (int)changelog_rec_snamelen(rec),
4461 changelog_rec_sname(rec));
4465 llapi_changelog_free(&rec);
4468 llapi_changelog_fini(&changelog_priv);
4471 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4473 return (rc == 1 ? 0 : rc);
4476 static int lfs_changelog_clear(int argc, char **argv)
4484 endrec = strtoll(argv[3], NULL, 10);
4486 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4489 fprintf(stderr, "%s: record out of range: %llu\n",
4491 else if (rc == -ENOENT)
4492 fprintf(stderr, "%s: no changelog user: %s\n",
4495 fprintf(stderr, "%s error: %s\n", argv[0],
4504 static int lfs_fid2path(int argc, char **argv)
4506 struct option long_opts[] = {
4507 { .val = 'c', .name = "cur", .has_arg = no_argument },
4508 { .val = 'l', .name = "link", .has_arg = required_argument },
4509 { .val = 'r', .name = "rec", .has_arg = required_argument },
4511 char short_opts[] = "cl:r:";
4512 char *device, *fid, *path;
4513 long long recno = -1;
4519 while ((rc = getopt_long(argc, argv, short_opts,
4520 long_opts, NULL)) != -1) {
4526 linkno = strtol(optarg, NULL, 10);
4529 recno = strtoll(optarg, NULL, 10);
4534 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4535 argv[0], argv[optind - 1]);
4543 device = argv[optind++];
4544 path = calloc(1, PATH_MAX);
4546 fprintf(stderr, "error: Not enough memory\n");
4551 while (optind < argc) {
4552 fid = argv[optind++];
4554 lnktmp = (linkno >= 0) ? linkno : 0;
4556 int oldtmp = lnktmp;
4557 long long rectmp = recno;
4559 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4562 fprintf(stderr, "%s: error on FID %s: %s\n",
4563 argv[0], fid, strerror(errno = -rc2));
4570 fprintf(stdout, "%lld ", rectmp);
4571 if (device[0] == '/') {
4572 fprintf(stdout, "%s", device);
4573 if (device[strlen(device) - 1] != '/')
4574 fprintf(stdout, "/");
4575 } else if (path[0] == '\0') {
4576 fprintf(stdout, "/");
4578 fprintf(stdout, "%s\n", path);
4581 /* specified linkno */
4583 if (oldtmp == lnktmp)
4593 static int lfs_path2fid(int argc, char **argv)
4595 struct option long_opts[] = {
4596 {"parents", no_argument, 0, 'p'},
4600 const char short_opts[] = "p";
4601 const char *sep = "";
4604 bool show_parents = false;
4606 while ((rc = getopt_long(argc, argv, short_opts,
4607 long_opts, NULL)) != -1) {
4610 show_parents = true;
4613 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4614 argv[0], argv[optind - 1]);
4619 if (optind > argc - 1)
4621 else if (optind < argc - 1)
4625 for (path = argv + optind; *path != NULL; path++) {
4627 if (!show_parents) {
4628 err = llapi_path2fid(*path, &fid);
4630 printf("%s%s"DFID"\n",
4631 *sep != '\0' ? *path : "", sep,
4634 char name[NAME_MAX + 1];
4635 unsigned int linkno = 0;
4637 while ((err = llapi_path2parent(*path, linkno, &fid,
4638 name, sizeof(name))) == 0) {
4639 if (*sep != '\0' && linkno == 0)
4640 printf("%s%s", *path, sep);
4642 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4647 /* err == -ENODATA is end-of-loop */
4648 if (linkno > 0 && err == -ENODATA) {
4655 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4656 argv[0], show_parents ? "parent " : "", *path,
4668 static int lfs_data_version(int argc, char **argv)
4675 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4680 while ((c = getopt(argc, argv, "nrw")) != -1) {
4683 data_version_flags = 0;
4686 data_version_flags |= LL_DV_RD_FLUSH;
4689 data_version_flags |= LL_DV_WR_FLUSH;
4698 path = argv[optind];
4699 fd = open(path, O_RDONLY);
4701 err(errno, "cannot open file %s", path);
4703 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4705 err(errno, "cannot get version for %s", path);
4707 printf("%ju" "\n", (uintmax_t)data_version);
4713 static int lfs_hsm_state(int argc, char **argv)
4718 struct hsm_user_state hus;
4726 rc = llapi_hsm_state_get(path, &hus);
4728 fprintf(stderr, "can't get hsm state for %s: %s\n",
4729 path, strerror(errno = -rc));
4733 /* Display path name and status flags */
4734 printf("%s: (0x%08x)", path, hus.hus_states);
4736 if (hus.hus_states & HS_RELEASED)
4737 printf(" released");
4738 if (hus.hus_states & HS_EXISTS)
4740 if (hus.hus_states & HS_DIRTY)
4742 if (hus.hus_states & HS_ARCHIVED)
4743 printf(" archived");
4744 /* Display user-settable flags */
4745 if (hus.hus_states & HS_NORELEASE)
4746 printf(" never_release");
4747 if (hus.hus_states & HS_NOARCHIVE)
4748 printf(" never_archive");
4749 if (hus.hus_states & HS_LOST)
4750 printf(" lost_from_hsm");
4752 if (hus.hus_archive_id != 0)
4753 printf(", archive_id:%d", hus.hus_archive_id);
4756 } while (++i < argc);
4761 #define LFS_HSM_SET 0
4762 #define LFS_HSM_CLEAR 1
4765 * Generic function to set or clear HSM flags.
4766 * Used by hsm_set and hsm_clear.
4768 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4770 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4772 struct option long_opts[] = {
4773 {"lost", 0, 0, 'l'},
4774 {"norelease", 0, 0, 'r'},
4775 {"noarchive", 0, 0, 'a'},
4776 {"archived", 0, 0, 'A'},
4777 {"dirty", 0, 0, 'd'},
4778 {"exists", 0, 0, 'e'},
4781 char short_opts[] = "lraAde";
4789 while ((c = getopt_long(argc, argv, short_opts,
4790 long_opts, NULL)) != -1) {
4796 mask |= HS_NOARCHIVE;
4799 mask |= HS_ARCHIVED;
4802 mask |= HS_NORELEASE;
4813 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4814 argv[0], argv[optind - 1]);
4819 /* User should have specified a flag */
4823 while (optind < argc) {
4825 path = argv[optind];
4827 /* If mode == 0, this means we apply the mask. */
4828 if (mode == LFS_HSM_SET)
4829 rc = llapi_hsm_state_set(path, mask, 0, 0);
4831 rc = llapi_hsm_state_set(path, 0, mask, 0);
4834 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4835 path, strerror(errno = -rc));
4844 static int lfs_hsm_action(int argc, char **argv)
4849 struct hsm_current_action hca;
4850 struct hsm_extent he;
4851 enum hsm_user_action hua;
4852 enum hsm_progress_states hps;
4860 rc = llapi_hsm_current_action(path, &hca);
4862 fprintf(stderr, "can't get hsm action for %s: %s\n",
4863 path, strerror(errno = -rc));
4866 he = hca.hca_location;
4867 hua = hca.hca_action;
4868 hps = hca.hca_state;
4870 printf("%s: %s", path, hsm_user_action2name(hua));
4872 /* Skip file without action */
4873 if (hca.hca_action == HUA_NONE) {
4878 printf(" %s ", hsm_progress_state2name(hps));
4880 if ((hps == HPS_RUNNING) &&
4881 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4882 printf("(%llu bytes moved)\n",
4883 (unsigned long long)he.length);
4884 else if ((he.offset + he.length) == LUSTRE_EOF)
4885 printf("(from %llu to EOF)\n",
4886 (unsigned long long)he.offset);
4888 printf("(from %llu to %llu)\n",
4889 (unsigned long long)he.offset,
4890 (unsigned long long)(he.offset + he.length));
4892 } while (++i < argc);
4897 static int lfs_hsm_set(int argc, char **argv)
4899 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4902 static int lfs_hsm_clear(int argc, char **argv)
4904 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4908 * Check file state and return its fid, to be used by lfs_hsm_request().
4910 * \param[in] file Path to file to check
4911 * \param[in,out] fid Pointer to allocated lu_fid struct.
4912 * \param[in,out] last_dev Pointer to last device id used.
4914 * \return 0 on success.
4916 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4922 rc = lstat(file, &st);
4924 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4927 /* Checking for regular file as archiving as posix copytool
4928 * rejects archiving files other than regular files
4930 if (!S_ISREG(st.st_mode)) {
4931 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4934 /* A request should be ... */
4935 if (*last_dev != st.st_dev && *last_dev != 0) {
4936 fprintf(stderr, "All files should be "
4937 "on the same filesystem: %s\n", file);
4940 *last_dev = st.st_dev;
4942 rc = llapi_path2fid(file, fid);
4944 fprintf(stderr, "Cannot read FID of %s: %s\n",
4945 file, strerror(-rc));
4951 /* Fill an HSM HUR item with a given file name.
4953 * If mntpath is set, then the filename is actually a FID, and no
4954 * lookup on the filesystem will be performed.
4956 * \param[in] hur the user request to fill
4957 * \param[in] idx index of the item inside the HUR to fill
4958 * \param[in] mntpath mountpoint of Lustre
4959 * \param[in] fname filename (if mtnpath is NULL)
4960 * or FID (if mntpath is set)
4961 * \param[in] last_dev pointer to last device id used
4963 * \retval 0 on success
4964 * \retval CMD_HELP or a negative errno on error
4966 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4967 const char *mntpath, const char *fname,
4970 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4973 hui->hui_extent.length = -1;
4975 if (mntpath != NULL) {
4978 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4982 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4987 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4991 hur->hur_request.hr_itemcount++;
4996 static int lfs_hsm_request(int argc, char **argv, int action)
4998 struct option long_opts[] = {
4999 {"filelist", 1, 0, 'l'},
5000 {"data", 1, 0, 'D'},
5001 {"archive", 1, 0, 'a'},
5002 {"mntpath", 1, 0, 'm'},
5006 char short_opts[] = "l:D:a:m:";
5007 struct hsm_user_request *hur, *oldhur;
5012 char *filelist = NULL;
5013 char fullpath[PATH_MAX];
5014 char *opaque = NULL;
5018 int nbfile_alloc = 0;
5019 char *some_file = NULL;
5020 char *mntpath = NULL;
5026 while ((c = getopt_long(argc, argv, short_opts,
5027 long_opts, NULL)) != -1) {
5036 if (action != HUA_ARCHIVE &&
5037 action != HUA_REMOVE) {
5039 "error: -a is supported only "
5040 "when archiving or removing\n");
5043 archive_id = atoi(optarg);
5046 if (some_file == NULL) {
5048 some_file = strdup(optarg);
5054 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5055 argv[0], argv[optind - 1]);
5060 /* All remaining args are files, so we have at least nbfile */
5061 nbfile = argc - optind;
5063 if ((nbfile == 0) && (filelist == NULL))
5067 opaque_len = strlen(opaque);
5069 /* Alloc the request structure with enough place to store all files
5070 * from command line. */
5071 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5073 fprintf(stderr, "Cannot create the request: %s\n",
5077 nbfile_alloc = nbfile;
5079 hur->hur_request.hr_action = action;
5080 hur->hur_request.hr_archive_id = archive_id;
5081 hur->hur_request.hr_flags = 0;
5083 /* All remaining args are files, add them */
5084 if (nbfile != 0 && some_file == NULL)
5085 some_file = strdup(argv[optind]);
5087 for (i = 0; i < nbfile; i++) {
5088 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5094 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5096 /* If a filelist was specified, read the filelist from it. */
5097 if (filelist != NULL) {
5098 fp = fopen(filelist, "r");
5100 fprintf(stderr, "Cannot read the file list %s: %s\n",
5101 filelist, strerror(errno));
5106 while ((rc = getline(&line, &len, fp)) != -1) {
5107 /* If allocated buffer was too small, get something
5109 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5112 nbfile_alloc = nbfile_alloc * 2 + 1;
5114 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5117 fprintf(stderr, "hsm: cannot allocate "
5118 "the request: %s\n",
5125 size = hur_len(oldhur);
5127 fprintf(stderr, "hsm: cannot allocate "
5128 "%u files + %u bytes data\n",
5129 oldhur->hur_request.hr_itemcount,
5130 oldhur->hur_request.hr_data_len);
5137 memcpy(hur, oldhur, size);
5142 if (line[strlen(line) - 1] == '\n')
5143 line[strlen(line) - 1] = '\0';
5145 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5146 mntpath, line, &last_dev);
5152 if (some_file == NULL) {
5162 /* If a --data was used, add it to the request */
5163 hur->hur_request.hr_data_len = opaque_len;
5165 memcpy(hur_data(hur), opaque, opaque_len);
5167 /* Send the HSM request */
5168 if (realpath(some_file, fullpath) == NULL) {
5169 fprintf(stderr, "Could not find path '%s': %s\n",
5170 some_file, strerror(errno));
5172 rc = llapi_hsm_request(fullpath, hur);
5174 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5175 some_file, strerror(-rc));
5185 static int lfs_hsm_archive(int argc, char **argv)
5187 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5190 static int lfs_hsm_restore(int argc, char **argv)
5192 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5195 static int lfs_hsm_release(int argc, char **argv)
5197 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5200 static int lfs_hsm_remove(int argc, char **argv)
5202 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5205 static int lfs_hsm_cancel(int argc, char **argv)
5207 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5210 static int lfs_swap_layouts(int argc, char **argv)
5215 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5216 SWAP_LAYOUTS_KEEP_MTIME |
5217 SWAP_LAYOUTS_KEEP_ATIME);
5220 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5222 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5224 enum lu_ladvise_type advice;
5227 advice < ARRAY_SIZE(ladvise_names); advice++) {
5228 if (ladvise_names[advice] == NULL)
5230 if (strcmp(string, ladvise_names[advice]) == 0)
5234 return LU_LADVISE_INVALID;
5237 static int lfs_ladvise(int argc, char **argv)
5239 struct option long_opts[] = {
5240 {"advice", required_argument, 0, 'a'},
5241 {"background", no_argument, 0, 'b'},
5242 {"end", required_argument, 0, 'e'},
5243 {"start", required_argument, 0, 's'},
5244 {"length", required_argument, 0, 'l'},
5247 char short_opts[] = "a:be:l:s:";
5252 struct llapi_lu_ladvise advice;
5253 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5254 unsigned long long start = 0;
5255 unsigned long long end = LUSTRE_EOF;
5256 unsigned long long length = 0;
5257 unsigned long long size_units;
5258 unsigned long long flags = 0;
5261 while ((c = getopt_long(argc, argv, short_opts,
5262 long_opts, NULL)) != -1) {
5265 advice_type = lfs_get_ladvice(optarg);
5266 if (advice_type == LU_LADVISE_INVALID) {
5267 fprintf(stderr, "%s: invalid advice type "
5268 "'%s'\n", argv[0], optarg);
5269 fprintf(stderr, "Valid types:");
5271 for (advice_type = 0;
5272 advice_type < ARRAY_SIZE(ladvise_names);
5274 if (ladvise_names[advice_type] == NULL)
5276 fprintf(stderr, " %s",
5277 ladvise_names[advice_type]);
5279 fprintf(stderr, "\n");
5289 rc = llapi_parse_size(optarg, &end,
5292 fprintf(stderr, "%s: bad end offset '%s'\n",
5299 rc = llapi_parse_size(optarg, &start,
5302 fprintf(stderr, "%s: bad start offset "
5303 "'%s'\n", argv[0], optarg);
5309 rc = llapi_parse_size(optarg, &length,
5312 fprintf(stderr, "%s: bad length '%s'\n",
5320 fprintf(stderr, "%s: option '%s' unrecognized\n",
5321 argv[0], argv[optind - 1]);
5326 if (advice_type == LU_LADVISE_INVALID) {
5327 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5328 fprintf(stderr, "Valid types:");
5329 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5331 if (ladvise_names[advice_type] == NULL)
5333 fprintf(stderr, " %s", ladvise_names[advice_type]);
5335 fprintf(stderr, "\n");
5339 if (argc <= optind) {
5340 fprintf(stderr, "%s: please give one or more file names\n",
5345 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5346 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5351 if (end == LUSTRE_EOF && length != 0)
5352 end = start + length;
5355 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5356 argv[0], start, end);
5360 while (optind < argc) {
5363 path = argv[optind++];
5365 fd = open(path, O_RDONLY);
5367 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5368 argv[0], path, strerror(errno));
5373 advice.lla_start = start;
5374 advice.lla_end = end;
5375 advice.lla_advice = advice_type;
5376 advice.lla_value1 = 0;
5377 advice.lla_value2 = 0;
5378 advice.lla_value3 = 0;
5379 advice.lla_value4 = 0;
5380 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5383 fprintf(stderr, "%s: cannot give advice '%s' to file "
5384 "'%s': %s\n", argv[0],
5385 ladvise_names[advice_type],
5386 path, strerror(errno));
5389 if (rc == 0 && rc2 < 0)
5395 static int lfs_list_commands(int argc, char **argv)
5397 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5399 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5404 int main(int argc, char **argv)
5408 /* Ensure that liblustreapi constructor has run */
5409 if (!liblustreapi_initialized)
5410 fprintf(stderr, "liblustreapi was not properly initialized\n");
5414 Parser_init("lfs > ", cmdlist);
5416 progname = argv[0]; /* Used in error messages */
5418 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5420 rc = Parser_commands();
5423 return rc < 0 ? -rc : rc;
5426 #ifdef _LUSTRE_IDL_H_
5427 /* Everything we need here should be included by lustreapi.h. */
5428 # error "lfs should not depend on lustre_idl.h"
5429 #endif /* _LUSTRE_IDL_H_ */