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 'AT MOST' requested value\n"
261 "\t +: used before a value indicates 'AT LEAST' 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;
1163 head = llapi_layout_get_by_path(fname, 0);
1165 fprintf(stderr, "Read layout from %s failed. %s\n",
1166 fname, strerror(errno));
1170 /* Current component of 'head' should be tail of component list by
1171 * default, but we do an extra move cursor operation here to test
1172 * if the layout is non-composite. */
1173 rc = llapi_layout_comp_use(head, LLAPI_LAYOUT_COMP_USE_LAST);
1175 fprintf(stderr, "'%s' isn't a composite file?\n", fname);
1176 llapi_layout_free(head);
1180 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1182 fprintf(stderr, "Get prev extent failed. %s\n",
1184 llapi_layout_free(head);
1188 llapi_layout_free(head);
1190 /* Make sure we use the first component of the layout to be added. */
1191 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1193 fprintf(stderr, "Move component cursor failed. %s\n",
1198 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1200 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1204 if (start > prev_end || end <= prev_end) {
1205 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1206 "adjacent with the existing file extent end: %lu\n",
1207 start, end, prev_end);
1211 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1213 fprintf(stderr, "Get stripe size failed. %s\n",
1218 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1219 (prev_end & (stripe_size - 1))) {
1220 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1221 stripe_size, prev_end);
1225 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1227 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1228 prev_end, end, strerror(errno));
1235 static inline bool comp_flags_is_neg(__u32 flags)
1237 return flags & LCME_FL_NEG;
1240 static inline void comp_flags_set_neg(__u32 *flags)
1242 *flags |= LCME_FL_NEG;
1245 static inline void comp_flags_clear_neg(__u32 *flags)
1247 *flags &= ~LCME_FL_NEG;
1250 static int comp_name2flags(__u32 *flags, char *name)
1253 __u32 neg_flags = 0;
1259 for (ptr = name; ; ptr = NULL) {
1260 char *flg = strtok(ptr, ",");
1263 if (strcmp(flg, "init") == 0)
1264 *flags |= LCME_FL_INIT;
1265 else if (strcmp(flg, "^init") == 0)
1266 neg_flags |= LCME_FL_INIT;
1271 if (*flags == 0 && neg_flags == 0)
1273 /* don't support mixed flags for now */
1274 if (*flags && neg_flags)
1279 comp_flags_set_neg(flags);
1285 static inline bool arg_is_eof(char *arg)
1287 return !strncmp(arg, "-1", strlen("-1")) ||
1288 !strncmp(arg, "EOF", strlen("EOF")) ||
1289 !strncmp(arg, "eof", strlen("eof"));
1304 static int lfs_setstripe(int argc, char **argv)
1306 struct lfs_setstripe_args lsa;
1307 struct llapi_stripe_param *param = NULL;
1308 struct find_param migrate_mdt_param = {
1318 char *mdt_idx_arg = NULL;
1319 unsigned long long size_units = 1;
1320 bool migrate_mode = false;
1321 bool migration_block = false;
1322 __u64 migration_flags = 0;
1323 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1324 int comp_del = 0, comp_set = 0;
1327 struct llapi_layout *layout = NULL;
1329 struct option long_opts[] = {
1330 /* --block is only valid in migrate mode */
1331 {"block", no_argument, 0, 'b'},
1332 {"comp-add", no_argument, 0, LFS_COMP_ADD_OPT},
1333 {"component-add", no_argument, 0, LFS_COMP_ADD_OPT},
1334 {"comp-del", no_argument, 0, LFS_COMP_DEL_OPT},
1335 {"component-del", no_argument, 0, LFS_COMP_DEL_OPT},
1336 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1337 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1338 {"comp-set", no_argument, 0, LFS_COMP_SET_OPT},
1339 {"component-set", no_argument, 0, LFS_COMP_SET_OPT},
1340 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1341 /* This formerly implied "stripe-count", but was explicitly
1342 * made "stripe-count" for consistency with other options,
1343 * and to separate it from "mdt-count" when DNE arrives. */
1344 {"count", required_argument, 0, 'c'},
1346 {"stripe-count", required_argument, 0, 'c'},
1347 {"stripe_count", required_argument, 0, 'c'},
1348 {"delete", no_argument, 0, 'd'},
1349 {"comp-end", required_argument, 0, 'E'},
1350 {"component-end", required_argument, 0, 'E'},
1351 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1352 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1353 /* This formerly implied "stripe-index", but was explicitly
1354 * made "stripe-index" for consistency with other options,
1355 * and to separate it from "mdt-index" when DNE arrives. */
1356 {"index", required_argument, 0, 'i'},
1358 {"stripe-index", required_argument, 0, 'i'},
1359 {"stripe_index", required_argument, 0, 'i'},
1360 {"comp-id", required_argument, 0, 'I'},
1361 {"component-id", required_argument, 0, 'I'},
1362 {"mdt", required_argument, 0, 'm'},
1363 {"mdt-index", required_argument, 0, 'm'},
1364 {"mdt_index", required_argument, 0, 'm'},
1365 /* --non-block is only valid in migrate mode */
1366 {"non-block", no_argument, 0, 'n'},
1367 {"ost", required_argument, 0, 'o'},
1368 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1369 {"ost-list", required_argument, 0, 'o'},
1370 {"ost_list", required_argument, 0, 'o'},
1372 {"pool", required_argument, 0, 'p'},
1373 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1374 /* This formerly implied "--stripe-size", but was confusing
1375 * with "lfs find --size|-s", which means "file size", so use
1376 * the consistent "--stripe-size|-S" for all commands. */
1377 {"size", required_argument, 0, 's'},
1379 {"stripe-size", required_argument, 0, 'S'},
1380 {"stripe_size", required_argument, 0, 'S'},
1381 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1382 /* --verbose is only valid in migrate mode */
1383 {"verbose", no_argument, 0, 'v'},
1387 setstripe_args_init(&lsa);
1389 if (strcmp(argv[0], "migrate") == 0)
1390 migrate_mode = true;
1392 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1393 long_opts, NULL)) >= 0) {
1398 case LFS_COMP_ADD_OPT:
1401 case LFS_COMP_DEL_OPT:
1404 case LFS_COMP_FLAGS_OPT:
1405 result = comp_name2flags(&lsa.lsa_comp_flags, optarg);
1407 fprintf(stderr, "error: %s: bad comp flags "
1408 "'%s'\n", argv[0], optarg);
1412 case LFS_COMP_SET_OPT:
1416 if (!migrate_mode) {
1417 fprintf(stderr, "--block is valid only for"
1421 migration_block = true;
1424 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1425 if (strcmp(argv[optind - 1], "--count") == 0)
1426 fprintf(stderr, "warning: '--count' deprecated"
1427 ", use '--stripe-count' instead\n");
1429 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1431 fprintf(stderr, "error: %s: bad stripe count "
1432 "'%s'\n", argv[0], optarg);
1437 /* delete the default striping pattern */
1441 if (lsa.lsa_comp_end != 0) {
1442 result = comp_args_to_layout(&layout, &lsa);
1446 setstripe_args_init(&lsa);
1449 if (arg_is_eof(optarg)) {
1450 lsa.lsa_comp_end = LUSTRE_EOF;
1452 result = llapi_parse_size(optarg,
1456 fprintf(stderr, "error: %s: "
1457 "bad component end '%s'\n",
1464 if (strcmp(argv[optind - 1], "--index") == 0)
1465 fprintf(stderr, "warning: '--index' deprecated"
1466 ", use '--stripe-index' instead\n");
1467 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1469 fprintf(stderr, "error: %s: bad stripe offset "
1470 "'%s'\n", argv[0], optarg);
1475 comp_id = strtoul(optarg, &end, 0);
1476 if (*end != '\0' || comp_id == 0 ||
1477 comp_id > LCME_ID_MAX) {
1478 fprintf(stderr, "error: %s: bad comp ID "
1479 "'%s'\n", argv[0], optarg);
1484 if (!migrate_mode) {
1485 fprintf(stderr, "--mdt-index is valid only for"
1489 mdt_idx_arg = optarg;
1492 if (!migrate_mode) {
1493 fprintf(stderr, "--non-block is valid only for"
1497 migration_flags |= MIGRATION_NONBLOCK;
1500 lsa.lsa_nr_osts = parse_targets(osts,
1501 sizeof(osts) / sizeof(__u32),
1502 lsa.lsa_nr_osts, optarg);
1503 if (lsa.lsa_nr_osts < 0) {
1505 "error: %s: bad OST indices '%s'\n",
1510 lsa.lsa_osts = osts;
1511 if (lsa.lsa_stripe_off == -1)
1512 lsa.lsa_stripe_off = osts[0];
1515 result = verify_pool_name(argv[0], optarg);
1518 lsa.lsa_pool_name = optarg;
1520 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1522 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1523 fprintf(stderr, "warning: '--size|-s' deprecated, "
1524 "use '--stripe-size|-S' instead\n");
1526 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1528 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1531 fprintf(stderr, "error: %s: bad stripe size "
1532 "'%s'\n", argv[0], optarg);
1537 if (!migrate_mode) {
1538 fprintf(stderr, "--verbose is valid only for"
1542 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1549 fname = argv[optind];
1551 if (lsa.lsa_comp_end != 0) {
1552 result = comp_args_to_layout(&layout, &lsa);
1557 if (optind == argc) {
1558 fprintf(stderr, "error: %s: missing filename|dirname\n",
1563 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1564 * altered by user space tool, so we don't need to support the
1565 * --component-set for this moment. */
1566 if (comp_set != 0) {
1567 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1572 if ((delete + comp_set + comp_del + comp_add) > 1) {
1573 fprintf(stderr, "error: %s: can't specify --component-set, "
1574 "--component-del, --component-add or -d together\n",
1579 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1580 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1581 fprintf(stderr, "error: %s: can't specify -d with "
1582 "-s, -c, -o, -p, -I, -F or -E options\n",
1587 if ((comp_set || comp_del) &&
1588 (setstripe_args_specified(&lsa) || layout != NULL)) {
1589 fprintf(stderr, "error: %s: can't specify --component-del or "
1590 "--component-set with -s, -c, -o, -p or -E options.\n",
1595 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1596 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1597 "--component-del option.\n", argv[0]);
1602 if (layout == NULL) {
1603 fprintf(stderr, "error: %s: -E option must be present"
1604 "in --component-add mode.\n", argv[0]);
1607 result = adjust_first_extent(fname, layout);
1612 if (mdt_idx_arg != NULL && optind > 3) {
1613 fprintf(stderr, "error: %s: cannot specify -m with other "
1614 "options\n", argv[0]);
1618 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1620 "error: %s: cannot specify --non-block and --block\n",
1625 if (!comp_del && !comp_set && comp_id != 0) {
1626 fprintf(stderr, "error: %s: -I can only be used with "
1627 "--component-del.\n", argv[0]);
1631 if (mdt_idx_arg != NULL) {
1632 /* initialize migrate mdt parameters */
1633 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1635 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1636 argv[0], mdt_idx_arg);
1639 migrate_mdt_param.fp_migrate = 1;
1640 } else if (layout == NULL) {
1641 /* initialize stripe parameters */
1642 param = calloc(1, offsetof(typeof(*param),
1643 lsp_osts[lsa.lsa_nr_osts]));
1644 if (param == NULL) {
1645 fprintf(stderr, "error: %s: %s\n", argv[0],
1650 param->lsp_stripe_size = lsa.lsa_stripe_size;
1651 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1652 param->lsp_stripe_count = lsa.lsa_stripe_count;
1653 param->lsp_stripe_pattern = 0;
1654 param->lsp_pool = lsa.lsa_pool_name;
1655 param->lsp_is_specific = false;
1656 if (lsa.lsa_nr_osts > 0) {
1657 if (lsa.lsa_stripe_count > 0 &&
1658 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1659 fprintf(stderr, "error: %s: stripe count '%d' "
1660 "doesn't match the number of OSTs: %d\n"
1661 , argv[0], lsa.lsa_stripe_count,
1667 param->lsp_is_specific = true;
1668 param->lsp_stripe_count = lsa.lsa_nr_osts;
1669 memcpy(param->lsp_osts, osts,
1670 sizeof(*osts) * lsa.lsa_nr_osts);
1674 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1676 if (mdt_idx_arg != NULL) {
1677 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1678 op = "migrate mdt objects of";
1679 } else if (migrate_mode) {
1680 result = lfs_migrate(fname, migration_flags, param,
1682 op = "migrate ost objects of";
1683 } else if (comp_set != 0) {
1684 result = lfs_component_set(fname, comp_id,
1685 lsa.lsa_comp_flags);
1686 op = "modify component flags of";
1687 } else if (comp_del != 0) {
1688 result = lfs_component_del(fname, comp_id,
1689 lsa.lsa_comp_flags);
1690 op = "delete component of";
1691 } else if (comp_add != 0) {
1692 result = lfs_component_add(fname, layout);
1693 op = "add component to";
1694 } else if (layout != NULL) {
1695 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1701 op = "create composite";
1703 result = llapi_file_open_param(fname,
1710 op = "create striped";
1713 /* Save the first error encountered. */
1716 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1718 lsa.lsa_pool_name != NULL && result == EINVAL ?
1719 "OST not in pool?" : strerror(errno));
1725 llapi_layout_free(layout);
1728 llapi_layout_free(layout);
1732 static int lfs_poollist(int argc, char **argv)
1737 return llapi_poollist(argv[1]);
1740 static int set_time(time_t *time, time_t *set, char *str)
1747 else if (str[0] == '-')
1753 t = strtol(str, NULL, 0);
1754 if (*time < t * 24 * 60 * 60) {
1757 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1761 *set = *time - t * 24 * 60 * 60;
1764 static int name2uid(unsigned int *id, const char *name)
1766 struct passwd *passwd;
1768 passwd = getpwnam(name);
1771 *id = passwd->pw_uid;
1776 static int name2gid(unsigned int *id, const char *name)
1778 struct group *group;
1780 group = getgrnam(name);
1783 *id = group->gr_gid;
1788 static inline int name2projid(unsigned int *id, const char *name)
1793 static int uid2name(char **name, unsigned int id)
1795 struct passwd *passwd;
1797 passwd = getpwuid(id);
1800 *name = passwd->pw_name;
1805 static inline int gid2name(char **name, unsigned int id)
1807 struct group *group;
1809 group = getgrgid(id);
1812 *name = group->gr_name;
1817 static int name2layout(__u32 *layout, char *name)
1822 for (ptr = name; ; ptr = NULL) {
1823 lyt = strtok(ptr, ",");
1826 if (strcmp(lyt, "released") == 0)
1827 *layout |= LOV_PATTERN_F_RELEASED;
1828 else if (strcmp(lyt, "raid0") == 0)
1829 *layout |= LOV_PATTERN_RAID0;
1836 static int lfs_find(int argc, char **argv)
1841 struct find_param param = {
1845 struct option long_opts[] = {
1846 {"atime", required_argument, 0, 'A'},
1847 {"comp-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1848 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1849 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1850 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1851 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
1852 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1853 {"stripe-count", required_argument, 0, 'c'},
1854 {"stripe_count", required_argument, 0, 'c'},
1855 {"ctime", required_argument, 0, 'C'},
1856 {"maxdepth", required_argument, 0, 'D'},
1857 {"comp-end", required_argument, 0, 'E'},
1858 {"component-end", required_argument, 0, 'E'},
1859 {"gid", required_argument, 0, 'g'},
1860 {"group", required_argument, 0, 'G'},
1861 {"mdt-hash", required_argument, 0, 'H'},
1862 {"stripe-index", required_argument, 0, 'i'},
1863 {"stripe_index", required_argument, 0, 'i'},
1864 /*{"component-id", required_argument, 0, 'I'},*/
1865 {"layout", required_argument, 0, 'L'},
1866 {"mdt", required_argument, 0, 'm'},
1867 {"mdt-index", required_argument, 0, 'm'},
1868 {"mdt_index", required_argument, 0, 'm'},
1869 {"mtime", required_argument, 0, 'M'},
1870 {"name", required_argument, 0, 'n'},
1871 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1872 {"obd", required_argument, 0, 'O'},
1873 {"ost", required_argument, 0, 'O'},
1874 /* no short option for pool, p/P already used */
1875 {"pool", required_argument, 0, LFS_POOL_OPT},
1876 {"print0", no_argument, 0, 'p'},
1877 {"print", no_argument, 0, 'P'},
1878 {"projid", required_argument, 0, LFS_PROJID_OPT},
1879 {"size", required_argument, 0, 's'},
1880 {"stripe-size", required_argument, 0, 'S'},
1881 {"stripe_size", required_argument, 0, 'S'},
1882 {"type", required_argument, 0, 't'},
1883 {"mdt-count", required_argument, 0, 'T'},
1884 {"uid", required_argument, 0, 'u'},
1885 {"user", required_argument, 0, 'U'},
1898 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1899 while ((c = getopt_long_only(argc, argv,
1900 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1901 long_opts, NULL)) >= 0) {
1906 /* '!' is part of option */
1907 /* when getopt_long_only() finds a string which is not
1908 * an option nor a known option argument it returns 1
1909 * in that case if we already have found pathstart and pathend
1910 * (i.e. we have the list of pathnames),
1911 * the only supported value is "!"
1913 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1914 if (!isoption && pathend != -1) {
1915 fprintf(stderr, "err: %s: filename|dirname must either "
1916 "precede options or follow options\n",
1921 if (!isoption && pathstart == -1)
1922 pathstart = optind - 1;
1923 if (isoption && pathstart != -1 && pathend == -1)
1924 pathend = optind - 2;
1930 /* unknown; opt is "!" or path component,
1931 * checking done above.
1933 if (strcmp(optarg, "!") == 0)
1937 xtime = ¶m.fp_atime;
1938 xsign = ¶m.fp_asign;
1939 param.fp_exclude_atime = !!neg_opt;
1940 /* no break, this falls through to 'C' for ctime */
1943 xtime = ¶m.fp_ctime;
1944 xsign = ¶m.fp_csign;
1945 param.fp_exclude_ctime = !!neg_opt;
1947 /* no break, this falls through to 'M' for mtime */
1950 xtime = ¶m.fp_mtime;
1951 xsign = ¶m.fp_msign;
1952 param.fp_exclude_mtime = !!neg_opt;
1954 rc = set_time(&t, xtime, optarg);
1955 if (rc == INT_MAX) {
1962 case LFS_COMP_COUNT_OPT:
1963 if (optarg[0] == '+') {
1964 param.fp_comp_count_sign = -1;
1966 } else if (optarg[0] == '-') {
1967 param.fp_comp_count_sign = 1;
1971 param.fp_comp_count = strtoul(optarg, &endptr, 0);
1972 if (*endptr != '\0') {
1973 fprintf(stderr, "error: bad component count "
1977 param.fp_check_comp_count = 1;
1978 param.fp_exclude_comp_count = !!neg_opt;
1980 case LFS_COMP_FLAGS_OPT:
1981 rc = comp_name2flags(¶m.fp_comp_flags, optarg);
1982 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
1983 fprintf(stderr, "error: bad component flags "
1987 param.fp_check_comp_flags = 1;
1988 param.fp_exclude_comp_flags = !!neg_opt;
1990 case LFS_COMP_START_OPT:
1991 if (optarg[0] == '+') {
1992 param.fp_comp_start_sign = -1;
1994 } else if (optarg[0] == '-') {
1995 param.fp_comp_start_sign = 1;
1999 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2000 ¶m.fp_comp_start_units, 0);
2002 fprintf(stderr, "error: bad component start "
2006 param.fp_check_comp_start = 1;
2007 param.fp_exclude_comp_start = !!neg_opt;
2010 if (optarg[0] == '+') {
2011 param.fp_stripe_count_sign = -1;
2013 } else if (optarg[0] == '-') {
2014 param.fp_stripe_count_sign = 1;
2018 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2019 if (*endptr != '\0') {
2020 fprintf(stderr,"error: bad stripe_count '%s'\n",
2025 param.fp_check_stripe_count = 1;
2026 param.fp_exclude_stripe_count = !!neg_opt;
2029 param.fp_max_depth = strtol(optarg, 0, 0);
2032 if (optarg[0] == '+') {
2033 param.fp_comp_end_sign = -1;
2035 } else if (optarg[0] == '-') {
2036 param.fp_comp_end_sign = 1;
2040 if (arg_is_eof(optarg)) {
2041 param.fp_comp_end = LUSTRE_EOF;
2042 param.fp_comp_end_units = 1;
2045 rc = llapi_parse_size(optarg,
2047 ¶m.fp_comp_end_units, 0);
2050 fprintf(stderr, "error: bad component end "
2054 param.fp_check_comp_end = 1;
2055 param.fp_exclude_comp_end = !!neg_opt;
2059 rc = name2gid(¶m.fp_gid, optarg);
2061 param.fp_gid = strtoul(optarg, &endptr, 10);
2062 if (*endptr != '\0') {
2063 fprintf(stderr, "Group/GID: %s cannot "
2064 "be found.\n", optarg);
2069 param.fp_exclude_gid = !!neg_opt;
2070 param.fp_check_gid = 1;
2073 param.fp_hash_type = check_hashtype(optarg);
2074 if (param.fp_hash_type == 0) {
2075 fprintf(stderr, "error: bad hash_type '%s'\n",
2080 param.fp_check_hash_type = 1;
2081 param.fp_exclude_hash_type = !!neg_opt;
2084 ret = name2layout(¶m.fp_layout, optarg);
2087 param.fp_exclude_layout = !!neg_opt;
2088 param.fp_check_layout = 1;
2092 rc = name2uid(¶m.fp_uid, optarg);
2094 param.fp_uid = strtoul(optarg, &endptr, 10);
2095 if (*endptr != '\0') {
2096 fprintf(stderr, "User/UID: %s cannot "
2097 "be found.\n", optarg);
2102 param.fp_exclude_uid = !!neg_opt;
2103 param.fp_check_uid = 1;
2106 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2108 "Pool name %s is too long"
2109 " (max is %d)\n", optarg,
2114 /* we do check for empty pool because empty pool
2115 * is used to find V1 lov attributes */
2116 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2117 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2118 param.fp_exclude_pool = !!neg_opt;
2119 param.fp_check_pool = 1;
2122 param.fp_pattern = (char *)optarg;
2123 param.fp_exclude_pattern = !!neg_opt;
2128 char *buf, *token, *next, *p;
2132 buf = strdup(optarg);
2138 param.fp_exclude_obd = !!neg_opt;
2141 while (token && *token) {
2142 token = strchr(token, ',');
2149 param.fp_exclude_mdt = !!neg_opt;
2150 param.fp_num_alloc_mdts += len;
2151 tmp = realloc(param.fp_mdt_uuid,
2152 param.fp_num_alloc_mdts *
2153 sizeof(*param.fp_mdt_uuid));
2159 param.fp_mdt_uuid = tmp;
2161 param.fp_exclude_obd = !!neg_opt;
2162 param.fp_num_alloc_obds += len;
2163 tmp = realloc(param.fp_obd_uuid,
2164 param.fp_num_alloc_obds *
2165 sizeof(*param.fp_obd_uuid));
2171 param.fp_obd_uuid = tmp;
2173 for (token = buf; token && *token; token = next) {
2174 struct obd_uuid *puuid;
2177 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2180 ¶m.fp_obd_uuid[param.fp_num_obds++];
2182 p = strchr(token, ',');
2189 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2194 strncpy(puuid->uuid, token,
2195 sizeof(puuid->uuid));
2203 param.fp_zero_end = 1;
2207 case LFS_PROJID_OPT:
2208 rc = name2projid(¶m.fp_projid, optarg);
2210 param.fp_projid = strtoul(optarg, &endptr, 10);
2211 if (*endptr != '\0') {
2213 "Invalid project ID: %s",
2219 param.fp_exclude_projid = !!neg_opt;
2220 param.fp_check_projid = 1;
2223 if (optarg[0] == '+') {
2224 param.fp_size_sign = -1;
2226 } else if (optarg[0] == '-') {
2227 param.fp_size_sign = 1;
2231 ret = llapi_parse_size(optarg, ¶m.fp_size,
2232 ¶m.fp_size_units, 0);
2234 fprintf(stderr, "error: bad file size '%s'\n",
2238 param.fp_check_size = 1;
2239 param.fp_exclude_size = !!neg_opt;
2242 if (optarg[0] == '+') {
2243 param.fp_stripe_size_sign = -1;
2245 } else if (optarg[0] == '-') {
2246 param.fp_stripe_size_sign = 1;
2250 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2251 ¶m.fp_stripe_size_units, 0);
2253 fprintf(stderr, "error: bad stripe_size '%s'\n",
2257 param.fp_check_stripe_size = 1;
2258 param.fp_exclude_stripe_size = !!neg_opt;
2261 param.fp_exclude_type = !!neg_opt;
2262 switch (optarg[0]) {
2264 param.fp_type = S_IFBLK;
2267 param.fp_type = S_IFCHR;
2270 param.fp_type = S_IFDIR;
2273 param.fp_type = S_IFREG;
2276 param.fp_type = S_IFLNK;
2279 param.fp_type = S_IFIFO;
2282 param.fp_type = S_IFSOCK;
2285 fprintf(stderr, "error: %s: bad type '%s'\n",
2292 if (optarg[0] == '+') {
2293 param.fp_mdt_count_sign = -1;
2295 } else if (optarg[0] == '-') {
2296 param.fp_mdt_count_sign = 1;
2300 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2301 if (*endptr != '\0') {
2302 fprintf(stderr, "error: bad mdt_count '%s'\n",
2307 param.fp_check_mdt_count = 1;
2308 param.fp_exclude_mdt_count = !!neg_opt;
2316 if (pathstart == -1) {
2317 fprintf(stderr, "error: %s: no filename|pathname\n",
2321 } else if (pathend == -1) {
2327 rc = llapi_find(argv[pathstart], ¶m);
2328 if (rc != 0 && ret == 0)
2330 } while (++pathstart < pathend);
2333 fprintf(stderr, "error: %s failed for %s.\n",
2334 argv[0], argv[optind - 1]);
2336 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2337 free(param.fp_obd_uuid);
2339 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2340 free(param.fp_mdt_uuid);
2345 static int lfs_getstripe_internal(int argc, char **argv,
2346 struct find_param *param)
2348 struct option long_opts[] = {
2349 {"comp-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2350 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2351 {"comp-flags", optional_argument, 0, LFS_COMP_FLAGS_OPT},
2352 {"component-flags", optional_argument, 0, LFS_COMP_FLAGS_OPT},
2353 {"comp-start", optional_argument, 0, LFS_COMP_START_OPT},
2354 {"component-start", optional_argument, 0, LFS_COMP_START_OPT},
2355 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2356 /* This formerly implied "stripe-count", but was explicitly
2357 * made "stripe-count" for consistency with other options,
2358 * and to separate it from "mdt-count" when DNE arrives. */
2359 {"count", no_argument, 0, 'c'},
2361 {"stripe-count", no_argument, 0, 'c'},
2362 {"stripe_count", no_argument, 0, 'c'},
2363 {"directory", no_argument, 0, 'd'},
2364 {"default", no_argument, 0, 'D'},
2365 {"comp-end", optional_argument, 0, 'E'},
2366 {"component-end", optional_argument, 0, 'E'},
2367 {"fid", no_argument, 0, 'F'},
2368 {"generation", no_argument, 0, 'g'},
2369 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
2370 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2371 /* This formerly implied "stripe-index", but was explicitly
2372 * made "stripe-index" for consistency with other options,
2373 * and to separate it from "mdt-index" when DNE arrives. */
2374 {"index", no_argument, 0, 'i'},
2376 {"stripe-index", no_argument, 0, 'i'},
2377 {"stripe_index", no_argument, 0, 'i'},
2378 {"comp-id", optional_argument, 0, 'I'},
2379 {"component-id", optional_argument, 0, 'I'},
2380 {"layout", no_argument, 0, 'L'},
2381 {"mdt", no_argument, 0, 'm'},
2382 {"mdt-index", no_argument, 0, 'm'},
2383 {"mdt_index", no_argument, 0, 'm'},
2384 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2385 {"mdt-index", no_argument, 0, 'M'},
2386 {"mdt_index", no_argument, 0, 'M'},
2388 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2389 /* This formerly implied "stripe-index", but was confusing
2390 * with "file offset" (which will eventually be needed for
2391 * with different layouts by offset), so deprecate it. */
2392 {"offset", no_argument, 0, 'o'},
2394 {"obd", required_argument, 0, 'O'},
2395 {"ost", required_argument, 0, 'O'},
2396 {"pool", no_argument, 0, 'p'},
2397 {"quiet", no_argument, 0, 'q'},
2398 {"recursive", no_argument, 0, 'r'},
2399 {"raw", no_argument, 0, 'R'},
2400 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2401 /* This formerly implied "--stripe-size", but was confusing
2402 * with "lfs find --size|-s", which means "file size", so use
2403 * the consistent "--stripe-size|-S" for all commands. */
2404 {"size", no_argument, 0, 's'},
2406 {"stripe-size", no_argument, 0, 'S'},
2407 {"stripe_size", no_argument, 0, 'S'},
2408 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
2409 {"verbose", no_argument, 0, 'v'},
2410 {"yaml", no_argument, 0, 'y'},
2416 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2417 long_opts, NULL)) != -1) {
2420 if (strcmp(argv[optind - 1], "--count") == 0)
2421 fprintf(stderr, "warning: '--count' deprecated,"
2422 " use '--stripe-count' instead\n");
2423 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2424 param->fp_verbose |= VERBOSE_COUNT;
2425 param->fp_max_depth = 0;
2428 case LFS_COMP_COUNT_OPT:
2429 param->fp_verbose |= VERBOSE_COMP_COUNT;
2430 param->fp_max_depth = 0;
2432 case LFS_COMP_FLAGS_OPT:
2433 if (optarg != NULL) {
2434 __u32 *flags = ¶m->fp_comp_flags;
2435 rc = comp_name2flags(flags, optarg);
2437 fprintf(stderr, "error: %s bad "
2438 "component flags '%s'.\n",
2442 param->fp_check_comp_flags = 1;
2443 param->fp_exclude_comp_flags =
2444 comp_flags_is_neg(*flags);
2445 comp_flags_clear_neg(flags);
2448 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2449 param->fp_max_depth = 0;
2452 case LFS_COMP_START_OPT:
2453 if (optarg != NULL) {
2455 if (tmp[0] == '+') {
2456 param->fp_comp_start_sign = -1;
2458 } else if (tmp[0] == '-') {
2459 param->fp_comp_start_sign = 1;
2462 rc = llapi_parse_size(tmp,
2463 ¶m->fp_comp_start,
2464 ¶m->fp_comp_start_units, 0);
2466 fprintf(stderr, "error: %s bad "
2467 "component start '%s'.\n",
2471 param->fp_check_comp_start = 1;
2474 param->fp_verbose |= VERBOSE_COMP_START;
2475 param->fp_max_depth = 0;
2479 param->fp_max_depth = 0;
2482 param->fp_get_default_lmv = 1;
2485 if (optarg != NULL) {
2487 if (tmp[0] == '+') {
2488 param->fp_comp_end_sign = -1;
2490 } else if (tmp[0] == '-') {
2491 param->fp_comp_end_sign = 1;
2495 if (arg_is_eof(tmp)) {
2496 param->fp_comp_end = LUSTRE_EOF;
2497 param->fp_comp_end_units = 1;
2500 rc = llapi_parse_size(tmp,
2501 ¶m->fp_comp_end,
2502 ¶m->fp_comp_end_units, 0);
2505 fprintf(stderr, "error: %s bad "
2506 "component end '%s'.\n",
2510 param->fp_check_comp_end = 1;
2512 param->fp_verbose |= VERBOSE_COMP_END;
2513 param->fp_max_depth = 0;
2517 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2518 param->fp_verbose |= VERBOSE_DFID;
2519 param->fp_max_depth = 0;
2523 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2524 param->fp_verbose |= VERBOSE_GENERATION;
2525 param->fp_max_depth = 0;
2528 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2530 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2531 "use '--stripe-index|-i' instead\n");
2534 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2535 if (strcmp(argv[optind - 1], "--index") == 0)
2536 fprintf(stderr, "warning: '--index' deprecated"
2537 ", use '--stripe-index' instead\n");
2539 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2540 param->fp_verbose |= VERBOSE_OFFSET;
2541 param->fp_max_depth = 0;
2545 if (optarg != NULL) {
2546 param->fp_comp_id = strtoul(optarg, &end, 0);
2547 if (*end != '\0' || param->fp_comp_id == 0 ||
2548 param->fp_comp_id > LCME_ID_MAX) {
2549 fprintf(stderr, "error: %s bad "
2550 "component id '%s'\n",
2554 param->fp_check_comp_id = 1;
2557 param->fp_max_depth = 0;
2558 param->fp_verbose |= VERBOSE_COMP_ID;
2562 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2563 param->fp_verbose |= VERBOSE_LAYOUT;
2564 param->fp_max_depth = 0;
2567 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2569 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2570 fprintf(stderr, "warning: '-M' deprecated"
2571 ", use '-m' instead\n");
2575 if (!(param->fp_verbose & VERBOSE_DETAIL))
2576 param->fp_max_depth = 0;
2577 param->fp_verbose |= VERBOSE_MDTINDEX;
2580 if (param->fp_obd_uuid) {
2582 "error: %s: only one obduuid allowed",
2586 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2589 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2590 param->fp_verbose |= VERBOSE_POOL;
2591 param->fp_max_depth = 0;
2598 param->fp_recursive = 1;
2603 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2605 fprintf(stderr, "warning: '--size|-s' deprecated, "
2606 "use '--stripe-size|-S' instead\n");
2607 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2609 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2610 param->fp_verbose |= VERBOSE_SIZE;
2611 param->fp_max_depth = 0;
2615 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2628 if (param->fp_recursive)
2629 param->fp_max_depth = -1;
2630 else if (param->fp_verbose & VERBOSE_DETAIL)
2631 param->fp_max_depth = 1;
2633 if (!param->fp_verbose)
2634 param->fp_verbose = VERBOSE_DEFAULT;
2635 if (param->fp_quiet)
2636 param->fp_verbose = VERBOSE_OBJID;
2639 rc = llapi_getstripe(argv[optind], param);
2640 } while (++optind < argc && !rc);
2643 fprintf(stderr, "error: %s failed for %s.\n",
2644 argv[0], argv[optind - 1]);
2648 static int lfs_tgts(int argc, char **argv)
2650 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2651 struct find_param param;
2652 int index = 0, rc=0;
2657 if (argc == 2 && !realpath(argv[1], path)) {
2659 fprintf(stderr, "error: invalid path '%s': %s\n",
2660 argv[1], strerror(-rc));
2664 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2665 /* Check if we have a mount point */
2666 if (mntdir[0] == '\0')
2669 memset(¶m, 0, sizeof(param));
2670 if (!strcmp(argv[0], "mdts"))
2671 param.fp_get_lmv = 1;
2673 rc = llapi_ostlist(mntdir, ¶m);
2675 fprintf(stderr, "error: %s: failed on %s\n",
2678 if (path[0] != '\0')
2680 memset(mntdir, 0, PATH_MAX);
2686 static int lfs_getstripe(int argc, char **argv)
2688 struct find_param param = { 0 };
2690 param.fp_max_depth = 1;
2691 return lfs_getstripe_internal(argc, argv, ¶m);
2695 static int lfs_getdirstripe(int argc, char **argv)
2697 struct find_param param = { 0 };
2698 struct option long_opts[] = {
2699 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2700 {"mdt-count", no_argument, 0, 'c'},
2702 {"mdt-hash", no_argument, 0, 'H'},
2703 {"mdt-index", no_argument, 0, 'i'},
2704 {"recursive", no_argument, 0, 'r'},
2705 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2706 {"mdt-hash", no_argument, 0, 't'},
2708 {"default", no_argument, 0, 'D'},
2709 {"obd", required_argument, 0, 'O'},
2710 {"mdt-count", no_argument, 0, 'T'},
2711 {"yaml", no_argument, 0, 'y'},
2716 param.fp_get_lmv = 1;
2718 while ((c = getopt_long(argc, argv,
2719 "cDHiO:rtTy", long_opts, NULL)) != -1)
2723 if (param.fp_obd_uuid) {
2725 "error: %s: only one obduuid allowed",
2729 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2731 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2733 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2734 fprintf(stderr, "warning: '-c' deprecated"
2735 ", use '-T' instead\n");
2739 param.fp_verbose |= VERBOSE_COUNT;
2742 param.fp_verbose |= VERBOSE_OFFSET;
2744 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2748 param.fp_verbose |= VERBOSE_HASH_TYPE;
2751 param.fp_get_default_lmv = 1;
2754 param.fp_recursive = 1;
2767 if (param.fp_recursive)
2768 param.fp_max_depth = -1;
2770 if (!param.fp_verbose)
2771 param.fp_verbose = VERBOSE_DEFAULT;
2774 rc = llapi_getstripe(argv[optind], ¶m);
2775 } while (++optind < argc && !rc);
2778 fprintf(stderr, "error: %s failed for %s.\n",
2779 argv[0], argv[optind - 1]);
2784 static int lfs_setdirstripe(int argc, char **argv)
2788 unsigned int stripe_offset = -1;
2789 unsigned int stripe_count = 1;
2790 enum lmv_hash_type hash_type;
2793 char *stripe_offset_opt = NULL;
2794 char *stripe_count_opt = NULL;
2795 char *stripe_hash_opt = NULL;
2796 char *mode_opt = NULL;
2797 bool default_stripe = false;
2798 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2799 mode_t previous_mode = 0;
2800 bool delete = false;
2802 struct option long_opts[] = {
2803 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2804 {"count", required_argument, 0, 'c'},
2806 {"mdt-count", required_argument, 0, 'c'},
2807 {"delete", no_argument, 0, 'd'},
2808 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2809 {"index", required_argument, 0, 'i'},
2811 {"mdt-index", required_argument, 0, 'i'},
2812 {"mode", required_argument, 0, 'm'},
2813 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2814 {"hash-type", required_argument, 0, 't'},
2815 {"mdt-hash", required_argument, 0, 't'},
2817 {"mdt-hash", required_argument, 0, 'H'},
2818 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2819 {"default_stripe", no_argument, 0, 'D'},
2821 {"default", no_argument, 0, 'D'},
2825 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2832 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2833 if (strcmp(argv[optind - 1], "--count") == 0)
2834 fprintf(stderr, "warning: '--count' deprecated"
2835 ", use '--mdt-count' instead\n");
2837 stripe_count_opt = optarg;
2841 default_stripe = true;
2844 default_stripe = true;
2847 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2848 if (strcmp(argv[optind - 1], "--index") == 0)
2849 fprintf(stderr, "warning: '--index' deprecated"
2850 ", use '--mdt-index' instead\n");
2852 stripe_offset_opt = optarg;
2857 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2861 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2862 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2863 fprintf(stderr, "warning: '--hash-type' "
2864 "deprecated, use '--mdt-hash' "
2867 stripe_hash_opt = optarg;
2870 fprintf(stderr, "error: %s: option '%s' "
2872 argv[0], argv[optind - 1]);
2877 if (optind == argc) {
2878 fprintf(stderr, "error: %s: missing dirname\n",
2883 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2884 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2889 if (stripe_offset_opt != NULL) {
2890 /* get the stripe offset */
2891 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2893 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2894 argv[0], stripe_offset_opt);
2900 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2901 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2902 " or -i options.\n", argv[0]);
2910 if (mode_opt != NULL) {
2911 mode = strtoul(mode_opt, &end, 8);
2913 fprintf(stderr, "error: %s: bad mode '%s'\n",
2917 previous_mode = umask(0);
2920 if (stripe_hash_opt == NULL) {
2921 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2923 hash_type = check_hashtype(stripe_hash_opt);
2924 if (hash_type == 0) {
2926 "error: %s: bad stripe hash type '%s'\n",
2927 argv[0], stripe_hash_opt);
2932 /* get the stripe count */
2933 if (stripe_count_opt != NULL) {
2934 stripe_count = strtoul(stripe_count_opt, &end, 0);
2936 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2937 argv[0], stripe_count_opt);
2942 dname = argv[optind];
2944 if (default_stripe) {
2945 result = llapi_dir_set_default_lmv_stripe(dname,
2946 stripe_offset, stripe_count,
2949 result = llapi_dir_create_pool(dname, mode,
2951 stripe_count, hash_type,
2956 fprintf(stderr, "error: %s: create stripe dir '%s' "
2957 "failed\n", argv[0], dname);
2960 dname = argv[++optind];
2961 } while (dname != NULL);
2963 if (mode_opt != NULL)
2964 umask(previous_mode);
2970 static int lfs_rmentry(int argc, char **argv)
2977 fprintf(stderr, "error: %s: missing dirname\n",
2983 dname = argv[index];
2984 while (dname != NULL) {
2985 result = llapi_direntry_remove(dname);
2987 fprintf(stderr, "error: %s: remove dir entry '%s' "
2988 "failed\n", argv[0], dname);
2991 dname = argv[++index];
2996 static int lfs_mv(int argc, char **argv)
2998 struct find_param param = {
3005 struct option long_opts[] = {
3006 {"mdt-index", required_argument, 0, 'M'},
3007 {"verbose", no_argument, 0, 'v'},
3011 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3014 param.fp_mdt_index = strtoul(optarg, &end, 0);
3016 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3023 param.fp_verbose = VERBOSE_DETAIL;
3027 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3028 argv[0], argv[optind - 1]);
3033 if (param.fp_mdt_index == -1) {
3034 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3038 if (optind >= argc) {
3039 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3043 param.fp_migrate = 1;
3044 rc = llapi_migrate_mdt(argv[optind], ¶m);
3046 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3047 argv[0], argv[optind], param.fp_mdt_index,
3052 static int lfs_osts(int argc, char **argv)
3054 return lfs_tgts(argc, argv);
3057 static int lfs_mdts(int argc, char **argv)
3059 return lfs_tgts(argc, argv);
3062 #define COOK(value) \
3065 while (value > 1024) { \
3073 #define CDF "%11llu"
3074 #define HDF "%8.1f%c"
3079 MNTDF_INODES = 0x0001,
3080 MNTDF_COOKED = 0x0002,
3081 MNTDF_LAZY = 0x0004,
3082 MNTDF_VERBOSE = 0x0008,
3085 static int showdf(char *mntdir, struct obd_statfs *stat,
3086 char *uuid, enum mntdf_flags flags,
3087 char *type, int index, int rc)
3089 long long avail, used, total;
3091 char *suffix = "KMGTPEZY";
3092 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3093 char tbuf[3 * sizeof(__u64)];
3094 char ubuf[3 * sizeof(__u64)];
3095 char abuf[3 * sizeof(__u64)];
3096 char rbuf[3 * sizeof(__u64)];
3103 if (flags & MNTDF_INODES) {
3104 avail = stat->os_ffree;
3105 used = stat->os_files - stat->os_ffree;
3106 total = stat->os_files;
3108 int shift = flags & MNTDF_COOKED ? 0 : 10;
3110 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3111 used = ((stat->os_blocks - stat->os_bfree) *
3112 stat->os_bsize) >> shift;
3113 total = (stat->os_blocks * stat->os_bsize) >> shift;
3116 if ((used + avail) > 0)
3117 ratio = (double)used / (double)(used + avail);
3119 if (flags & MNTDF_COOKED) {
3123 cook_val = (double)total;
3126 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3129 snprintf(tbuf, sizeof(tbuf), CDF, total);
3131 cook_val = (double)used;
3134 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3137 snprintf(ubuf, sizeof(ubuf), CDF, used);
3139 cook_val = (double)avail;
3142 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3145 snprintf(abuf, sizeof(abuf), CDF, avail);
3147 snprintf(tbuf, sizeof(tbuf), CDF, total);
3148 snprintf(ubuf, sizeof(tbuf), CDF, used);
3149 snprintf(abuf, sizeof(tbuf), CDF, avail);
3152 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3153 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3154 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3156 printf("[%s:%d]", type, index);
3158 if (stat->os_state) {
3160 * Each character represents the matching
3163 const char state_names[] = "DRSI";
3168 for (i = 0, state = stat->os_state;
3169 state && i < sizeof(state_names); i++) {
3170 if (!(state & (1 << i)))
3172 printf("%c", state_names[i]);
3180 printf(UUF": inactive device\n", uuid);
3183 printf(UUF": %s\n", uuid, strerror(-rc));
3190 struct ll_stat_type {
3195 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3197 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3198 struct obd_uuid uuid_buf;
3199 char *poolname = NULL;
3200 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3201 { LL_STATFS_LOV, "OST" },
3203 struct ll_stat_type *tp;
3204 __u64 ost_ffree = 0;
3212 poolname = strchr(pool, '.');
3213 if (poolname != NULL) {
3214 if (strncmp(fsname, pool, strlen(fsname))) {
3215 fprintf(stderr, "filesystem name incorrect\n");
3223 fd = open(mntdir, O_RDONLY);
3226 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3231 if (flags & MNTDF_INODES)
3232 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3233 "UUID", "Inodes", "IUsed", "IFree",
3234 "IUse%", "Mounted on");
3236 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3237 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3238 "Used", "Available", "Use%", "Mounted on");
3240 for (tp = types; tp->st_name != NULL; tp++) {
3241 for (index = 0; ; index++) {
3242 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3243 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3244 type = flags & MNTDF_LAZY ?
3245 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3246 rc2 = llapi_obd_fstatfs(fd, type, index,
3247 &stat_buf, &uuid_buf);
3252 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3253 if (!(flags & MNTDF_VERBOSE))
3255 } else if (rc2 < 0 && rc == 0) {
3259 if (poolname && tp->st_op == LL_STATFS_LOV &&
3260 llapi_search_ost(fsname, poolname,
3261 obd_uuid2str(&uuid_buf)) != 1)
3264 /* the llapi_obd_statfs() call may have returned with
3265 * an error, but if it filled in uuid_buf we will at
3266 * lease use that to print out a message for that OBD.
3267 * If we didn't get anything in the uuid_buf, then fill
3268 * it in so that we can print an error message. */
3269 if (uuid_buf.uuid[0] == '\0')
3270 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3271 "%s%04x", tp->st_name, index);
3272 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3273 flags, tp->st_name, index, rc2);
3276 if (tp->st_op == LL_STATFS_LMV) {
3277 sum.os_ffree += stat_buf.os_ffree;
3278 sum.os_files += stat_buf.os_files;
3279 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3280 sum.os_blocks += stat_buf.os_blocks *
3282 sum.os_bfree += stat_buf.os_bfree *
3284 sum.os_bavail += stat_buf.os_bavail *
3286 ost_ffree += stat_buf.os_ffree;
3294 /* If we don't have as many objects free on the OST as inodes
3295 * on the MDS, we reduce the total number of inodes to
3296 * compensate, so that the "inodes in use" number is correct.
3297 * Matches ll_statfs_internal() so the results are consistent. */
3298 if (ost_ffree < sum.os_ffree) {
3299 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3300 sum.os_ffree = ost_ffree;
3303 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3309 static int lfs_df(int argc, char **argv)
3311 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3312 enum mntdf_flags flags = 0;
3313 int c, rc = 0, index = 0;
3314 char fsname[PATH_MAX] = "", *pool_name = NULL;
3315 struct option long_opts[] = {
3316 {"human-readable", 0, 0, 'h'},
3317 {"inodes", 0, 0, 'i'},
3318 {"lazy", 0, 0, 'l'},
3319 {"pool", required_argument, 0, 'p'},
3320 {"verbose", 0, 0, 'v'},
3324 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3327 flags |= MNTDF_COOKED;
3330 flags |= MNTDF_INODES;
3333 flags |= MNTDF_LAZY;
3339 flags |= MNTDF_VERBOSE;
3345 if (optind < argc && !realpath(argv[optind], path)) {
3347 fprintf(stderr, "error: invalid path '%s': %s\n",
3348 argv[optind], strerror(-rc));
3352 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3353 /* Check if we have a mount point */
3354 if (mntdir[0] == '\0')
3357 rc = mntdf(mntdir, fsname, pool_name, flags);
3358 if (rc || path[0] != '\0')
3360 fsname[0] = '\0'; /* avoid matching in next loop */
3361 mntdir[0] = '\0'; /* avoid matching in next loop */
3367 static int lfs_getname(int argc, char **argv)
3369 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3370 int rc = 0, index = 0, c;
3371 char buf[sizeof(struct obd_uuid)];
3373 while ((c = getopt(argc, argv, "h")) != -1)
3376 if (optind == argc) { /* no paths specified, get all paths. */
3377 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3378 rc = llapi_getname(mntdir, buf, sizeof(buf));
3381 "cannot get name for `%s': %s\n",
3382 mntdir, strerror(-rc));
3386 printf("%s %s\n", buf, mntdir);
3388 path[0] = fsname[0] = mntdir[0] = 0;
3390 } else { /* paths specified, only attempt to search these. */
3391 for (; optind < argc; optind++) {
3392 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3395 "cannot get name for `%s': %s\n",
3396 argv[optind], strerror(-rc));
3400 printf("%s %s\n", buf, argv[optind]);
3406 static int lfs_check(int argc, char **argv)
3409 char mntdir[PATH_MAX] = {'\0'};
3418 obd_types[0] = obd_type1;
3419 obd_types[1] = obd_type2;
3421 if (strcmp(argv[1], "osts") == 0) {
3422 strcpy(obd_types[0], "osc");
3423 } else if (strcmp(argv[1], "mds") == 0) {
3424 strcpy(obd_types[0], "mdc");
3425 } else if (strcmp(argv[1], "servers") == 0) {
3427 strcpy(obd_types[0], "osc");
3428 strcpy(obd_types[1], "mdc");
3430 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3435 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3436 if (rc < 0 || mntdir[0] == '\0') {
3437 fprintf(stderr, "No suitable Lustre mount found\n");
3441 rc = llapi_target_check(num_types, obd_types, mntdir);
3443 fprintf(stderr, "error: %s: %s status failed\n",
3450 #ifdef HAVE_SYS_QUOTA_H
3451 #define ARG2INT(nr, str, msg) \
3454 nr = strtol(str, &endp, 0); \
3456 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3461 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3463 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3464 * returns the value or ULONG_MAX on integer overflow or incorrect format
3466 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3467 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3468 * 3. empty integer value is interpreted as 0
3470 static unsigned long str2sec(const char* timestr)
3472 const char spec[] = "smhdw";
3473 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3474 unsigned long val = 0;
3477 if (strpbrk(timestr, spec) == NULL) {
3478 /* no specifiers inside the time string,
3479 should treat it as an integer value */
3480 val = strtoul(timestr, &tail, 10);
3481 return *tail ? ULONG_MAX : val;
3484 /* format string is XXwXXdXXhXXmXXs */
3490 v = strtoul(timestr, &tail, 10);
3491 if (v == ULONG_MAX || *tail == '\0')
3492 /* value too large (ULONG_MAX or more)
3493 or missing specifier */
3496 ptr = strchr(spec, *tail);
3498 /* unknown specifier */
3503 /* check if product will overflow the type */
3504 if (!(v < ULONG_MAX / mult[ind]))
3507 ADD_OVERFLOW(val, mult[ind] * v);
3508 if (val == ULONG_MAX)
3520 #define ARG2ULL(nr, str, def_units) \
3522 unsigned long long limit, units = def_units; \
3525 rc = llapi_parse_size(str, &limit, &units, 1); \
3527 fprintf(stderr, "error: bad limit value %s\n", str); \
3533 static inline int has_times_option(int argc, char **argv)
3537 for (i = 1; i < argc; i++)
3538 if (!strcmp(argv[i], "-t"))
3544 int lfs_setquota_times(int argc, char **argv)
3547 struct if_quotactl qctl;
3548 char *mnt, *obd_type = (char *)qctl.obd_type;
3549 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3550 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3551 struct option long_opts[] = {
3552 {"block-grace", required_argument, 0, 'b'},
3553 {"group", no_argument, 0, 'g'},
3554 {"inode-grace", required_argument, 0, 'i'},
3555 {"projid", no_argument, 0, 'p'},
3556 {"times", no_argument, 0, 't'},
3557 {"user", no_argument, 0, 'u'},
3562 memset(&qctl, 0, sizeof(qctl));
3563 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3564 qctl.qc_type = ALLQUOTA;
3566 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3567 long_opts, NULL)) != -1) {
3578 if (qctl.qc_type != ALLQUOTA) {
3579 fprintf(stderr, "error: -u/g/p can't be used "
3580 "more than once\n");
3583 qctl.qc_type = qtype;
3586 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3587 fprintf(stderr, "error: bad block-grace: %s\n",
3591 dqb->dqb_valid |= QIF_BTIME;
3594 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3595 fprintf(stderr, "error: bad inode-grace: %s\n",
3599 dqb->dqb_valid |= QIF_ITIME;
3601 case 't': /* Yes, of course! */
3603 default: /* getopt prints error message for us when opterr != 0 */
3608 if (qctl.qc_type == ALLQUOTA) {
3609 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3613 if (optind != argc - 1) {
3614 fprintf(stderr, "error: unexpected parameters encountered\n");
3619 rc = llapi_quotactl(mnt, &qctl);
3622 fprintf(stderr, "%s %s ", obd_type,
3623 obd_uuid2str(&qctl.obd_uuid));
3624 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3631 #define BSLIMIT (1 << 0)
3632 #define BHLIMIT (1 << 1)
3633 #define ISLIMIT (1 << 2)
3634 #define IHLIMIT (1 << 3)
3636 int lfs_setquota(int argc, char **argv)
3639 struct if_quotactl qctl;
3640 char *mnt, *obd_type = (char *)qctl.obd_type;
3641 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3642 struct option long_opts[] = {
3643 {"block-softlimit", required_argument, 0, 'b'},
3644 {"block-hardlimit", required_argument, 0, 'B'},
3645 {"group", required_argument, 0, 'g'},
3646 {"inode-softlimit", required_argument, 0, 'i'},
3647 {"inode-hardlimit", required_argument, 0, 'I'},
3648 {"user", required_argument, 0, 'u'},
3649 {"projid", required_argument, 0, 'p'},
3652 unsigned limit_mask = 0;
3656 if (has_times_option(argc, argv))
3657 return lfs_setquota_times(argc, argv);
3659 memset(&qctl, 0, sizeof(qctl));
3660 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3661 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3662 * so it can be used as a marker that qc_type
3663 * isn't reinitialized from command line */
3665 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3666 long_opts, NULL)) != -1) {
3670 rc = name2uid(&qctl.qc_id, optarg);
3674 rc = name2gid(&qctl.qc_id, optarg);
3678 rc = name2projid(&qctl.qc_id, optarg);
3680 if (qctl.qc_type != ALLQUOTA) {
3681 fprintf(stderr, "error: -u and -g can't be used"
3682 " more than once\n");
3685 qctl.qc_type = qtype;
3687 qctl.qc_id = strtoul(optarg, &endptr, 10);
3688 if (*endptr != '\0') {
3689 fprintf(stderr, "error: can't find id "
3690 "for name %s\n", optarg);
3696 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3697 dqb->dqb_bsoftlimit >>= 10;
3698 limit_mask |= BSLIMIT;
3699 if (dqb->dqb_bsoftlimit &&
3700 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3701 fprintf(stderr, "warning: block softlimit is "
3702 "smaller than the miminal qunit size, "
3703 "please see the help of setquota or "
3704 "Lustre manual for details.\n");
3707 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3708 dqb->dqb_bhardlimit >>= 10;
3709 limit_mask |= BHLIMIT;
3710 if (dqb->dqb_bhardlimit &&
3711 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3712 fprintf(stderr, "warning: block hardlimit is "
3713 "smaller than the miminal qunit size, "
3714 "please see the help of setquota or "
3715 "Lustre manual for details.\n");
3718 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3719 limit_mask |= ISLIMIT;
3720 if (dqb->dqb_isoftlimit &&
3721 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3722 fprintf(stderr, "warning: inode softlimit is "
3723 "smaller than the miminal qunit size, "
3724 "please see the help of setquota or "
3725 "Lustre manual for details.\n");
3728 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3729 limit_mask |= IHLIMIT;
3730 if (dqb->dqb_ihardlimit &&
3731 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3732 fprintf(stderr, "warning: inode hardlimit is "
3733 "smaller than the miminal qunit size, "
3734 "please see the help of setquota or "
3735 "Lustre manual for details.\n");
3737 default: /* getopt prints error message for us when opterr != 0 */
3742 if (qctl.qc_type == ALLQUOTA) {
3743 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3747 if (limit_mask == 0) {
3748 fprintf(stderr, "error: at least one limit must be specified\n");
3752 if (optind != argc - 1) {
3753 fprintf(stderr, "error: unexpected parameters encountered\n");
3759 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3760 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3761 /* sigh, we can't just set blimits/ilimits */
3762 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3763 .qc_type = qctl.qc_type,
3764 .qc_id = qctl.qc_id};
3766 rc = llapi_quotactl(mnt, &tmp_qctl);
3768 fprintf(stderr, "error: setquota failed while retrieving"
3769 " current quota settings (%s)\n",
3774 if (!(limit_mask & BHLIMIT))
3775 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3776 if (!(limit_mask & BSLIMIT))
3777 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3778 if (!(limit_mask & IHLIMIT))
3779 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3780 if (!(limit_mask & ISLIMIT))
3781 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3783 /* Keep grace times if we have got no softlimit arguments */
3784 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3785 dqb->dqb_valid |= QIF_BTIME;
3786 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3789 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3790 dqb->dqb_valid |= QIF_ITIME;
3791 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3795 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3796 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3798 rc = llapi_quotactl(mnt, &qctl);
3801 fprintf(stderr, "%s %s ", obd_type,
3802 obd_uuid2str(&qctl.obd_uuid));
3803 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3810 /* Converts seconds value into format string
3811 * result is returned in buf
3813 * 1. result is in descenting order: 1w2d3h4m5s
3814 * 2. zero fields are not filled (except for p. 3): 5d1s
3815 * 3. zero seconds value is presented as "0s"
3817 static char * __sec2str(time_t seconds, char *buf)
3819 const char spec[] = "smhdw";
3820 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3825 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3826 c = seconds / mult[i];
3828 if (c > 0 || (i == 0 && buf == tail))
3829 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3837 static void sec2str(time_t seconds, char *buf, int rc)
3844 tail = __sec2str(seconds, tail);
3846 if (rc && tail - buf < 39) {
3852 static void diff2str(time_t seconds, char *buf, time_t now)
3858 if (seconds <= now) {
3859 strcpy(buf, "none");
3862 __sec2str(seconds - now, buf);
3865 static void print_quota_title(char *name, struct if_quotactl *qctl,
3866 bool human_readable)
3868 printf("Disk quotas for %s %s (%cid %u):\n",
3869 qtype_name(qctl->qc_type), name,
3870 *qtype_name(qctl->qc_type), qctl->qc_id);
3871 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3872 "Filesystem", human_readable ? "used" : "kbytes",
3873 "quota", "limit", "grace",
3874 "files", "quota", "limit", "grace");
3877 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3880 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3883 snprintf(buf, buflen, "%5.4gP",
3884 (double)num / ((__u64)1 << 40));
3886 snprintf(buf, buflen, "%5.4gT",
3887 (double)num / (1 << 30));
3889 snprintf(buf, buflen, "%5.4gG",
3890 (double)num / (1 << 20));
3892 snprintf(buf, buflen, "%5.4gM",
3893 (double)num / (1 << 10));
3895 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3899 #define STRBUF_LEN 32
3900 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3907 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3908 int bover = 0, iover = 0;
3909 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3910 char numbuf[3][STRBUF_LEN];
3912 char strbuf[STRBUF_LEN];
3914 if (dqb->dqb_bhardlimit &&
3915 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3917 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3918 if (dqb->dqb_btime > now) {
3925 if (dqb->dqb_ihardlimit &&
3926 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3928 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3929 if (dqb->dqb_itime > now) {
3937 if (strlen(mnt) > 15)
3938 printf("%s\n%15s", mnt, "");
3940 printf("%15s", mnt);
3943 diff2str(dqb->dqb_btime, timebuf, now);
3945 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3946 strbuf, sizeof(strbuf), h);
3947 if (rc == -EREMOTEIO)
3948 sprintf(numbuf[0], "%s*", strbuf);
3950 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3951 "%s" : "[%s]", strbuf);
3953 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3954 if (type == QC_GENERAL)
3955 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3956 "%s" : "[%s]", strbuf);
3958 sprintf(numbuf[1], "%s", "-");
3960 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3961 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3962 "%s" : "[%s]", strbuf);
3964 printf(" %7s%c %6s %7s %7s",
3965 numbuf[0], bover ? '*' : ' ', numbuf[1],
3966 numbuf[2], bover > 1 ? timebuf : "-");
3969 diff2str(dqb->dqb_itime, timebuf, now);
3971 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3972 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3974 if (type == QC_GENERAL)
3975 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3977 (uintmax_t)dqb->dqb_isoftlimit);
3979 sprintf(numbuf[1], "%s", "-");
3981 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3982 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3984 if (type != QC_OSTIDX)
3985 printf(" %7s%c %6s %7s %7s",
3986 numbuf[0], iover ? '*' : ' ', numbuf[1],
3987 numbuf[2], iover > 1 ? timebuf : "-");
3989 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3992 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3993 qctl->qc_cmd == Q_GETOINFO) {
3997 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3998 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3999 printf("Block grace time: %s; Inode grace time: %s\n",
4000 bgtimebuf, igtimebuf);
4004 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4005 bool h, __u64 *total)
4007 int rc = 0, rc1 = 0, count = 0;
4008 __u32 valid = qctl->qc_valid;
4010 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4012 fprintf(stderr, "can not get %s count: %s\n",
4013 is_mdt ? "mdt": "ost", strerror(-rc));
4017 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4018 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4019 rc = llapi_quotactl(mnt, qctl);
4021 /* It is remote client case. */
4022 if (rc == -EOPNOTSUPP) {
4029 fprintf(stderr, "quotactl %s%d failed.\n",
4030 is_mdt ? "mdt": "ost", qctl->qc_idx);
4034 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4035 qctl->qc_valid, 0, h);
4036 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4037 qctl->qc_dqblk.dqb_bhardlimit;
4040 qctl->qc_valid = valid;
4044 static int lfs_quota(int argc, char **argv)
4047 char *mnt, *name = NULL;
4048 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4049 .qc_type = ALLQUOTA };
4050 char *obd_type = (char *)qctl.obd_type;
4051 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4052 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4053 verbose = 0, pass = 0, quiet = 0, inacc;
4055 __u32 valid = QC_GENERAL, idx = 0;
4056 __u64 total_ialloc = 0, total_balloc = 0;
4057 bool human_readable = false;
4060 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4071 if (qctl.qc_type != ALLQUOTA) {
4072 fprintf(stderr, "error: use either -u or -g\n");
4075 qctl.qc_type = qtype;
4078 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4081 valid = qctl.qc_valid = QC_UUID;
4082 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4085 valid = qctl.qc_valid = QC_MDTIDX;
4086 idx = qctl.qc_idx = atoi(optarg);
4089 valid = qctl.qc_valid = QC_OSTIDX;
4090 idx = qctl.qc_idx = atoi(optarg);
4099 human_readable = true;
4102 fprintf(stderr, "error: %s: option '-%c' "
4103 "unrecognized\n", argv[0], c);
4108 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4109 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4110 optind == argc - 1) {
4112 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4113 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4114 qctl.qc_valid = valid;
4116 qctl.qc_type = pass;
4117 switch (qctl.qc_type) {
4119 qctl.qc_id = geteuid();
4120 rc = uid2name(&name, qctl.qc_id);
4123 qctl.qc_id = getegid();
4124 rc = gid2name(&name, qctl.qc_id);
4133 /* lfs quota -u username /path/to/lustre/mount */
4134 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4135 /* options should be followed by u/g-name and mntpoint */
4136 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4137 fprintf(stderr, "error: missing quota argument(s)\n");
4141 name = argv[optind++];
4142 switch (qctl.qc_type) {
4144 rc = name2uid(&qctl.qc_id, name);
4147 rc = name2gid(&qctl.qc_id, name);
4150 rc = name2projid(&qctl.qc_id, name);
4157 qctl.qc_id = strtoul(name, &endptr, 10);
4158 if (*endptr != '\0') {
4159 fprintf(stderr, "error: can't find id for name: %s\n",
4164 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4165 fprintf(stderr, "error: missing quota info argument(s)\n");
4170 rc1 = llapi_quotactl(mnt, &qctl);
4174 fprintf(stderr, "%s quotas are not enabled.\n",
4175 qtype_name(qctl.qc_type));
4178 fprintf(stderr, "Permission denied.\n");
4181 /* We already got error message. */
4184 fprintf(stderr, "Unexpected quotactl error: %s\n",
4189 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4190 print_quota_title(name, &qctl, human_readable);
4192 if (rc1 && *obd_type)
4193 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4195 if (qctl.qc_valid != QC_GENERAL)
4198 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4199 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4200 (QIF_LIMITS|QIF_USAGE));
4202 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4204 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4206 char strbuf[STRBUF_LEN];
4208 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4210 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4212 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4214 printf("Total allocated inode limit: %ju, total "
4215 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4219 if (rc1 || rc2 || rc3 || inacc)
4220 printf("Some errors happened when getting quota info. "
4221 "Some devices may be not working or deactivated. "
4222 "The data in \"[]\" is inaccurate.\n");
4225 if (pass > 0 && pass < LL_MAXQUOTAS)
4230 #endif /* HAVE_SYS_QUOTA_H! */
4232 static int flushctx_ioctl(char *mp)
4236 fd = open(mp, O_RDONLY);
4238 fprintf(stderr, "flushctx: error open %s: %s\n",
4239 mp, strerror(errno));
4243 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4245 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4246 mp, strerror(errno));
4252 static int lfs_flushctx(int argc, char **argv)
4254 int kdestroy = 0, c;
4255 char mntdir[PATH_MAX] = {'\0'};
4259 while ((c = getopt(argc, argv, "k")) != -1) {
4265 fprintf(stderr, "error: %s: option '-%c' "
4266 "unrecognized\n", argv[0], c);
4272 if ((rc = system("kdestroy > /dev/null")) != 0) {
4273 rc = WEXITSTATUS(rc);
4274 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4278 if (optind >= argc) {
4279 /* flush for all mounted lustre fs. */
4280 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4281 /* Check if we have a mount point */
4282 if (mntdir[0] == '\0')
4285 if (flushctx_ioctl(mntdir))
4288 mntdir[0] = '\0'; /* avoid matching in next loop */
4291 /* flush fs as specified */
4292 while (optind < argc) {
4293 if (flushctx_ioctl(argv[optind++]))
4300 static int lfs_cp(int argc, char **argv)
4302 fprintf(stderr, "remote client copy file(s).\n"
4303 "obsolete, does not support it anymore.\n");
4307 static int lfs_ls(int argc, char **argv)
4309 fprintf(stderr, "remote client lists directory contents.\n"
4310 "obsolete, does not support it anymore.\n");
4314 static int lfs_changelog(int argc, char **argv)
4316 void *changelog_priv;
4317 struct changelog_rec *rec;
4318 long long startrec = 0, endrec = 0;
4320 struct option long_opts[] = {
4321 {"follow", no_argument, 0, 'f'},
4324 char short_opts[] = "f";
4327 while ((rc = getopt_long(argc, argv, short_opts,
4328 long_opts, NULL)) != -1) {
4336 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4337 argv[0], argv[optind - 1]);
4344 mdd = argv[optind++];
4346 startrec = strtoll(argv[optind++], NULL, 10);
4348 endrec = strtoll(argv[optind++], NULL, 10);
4350 rc = llapi_changelog_start(&changelog_priv,
4351 CHANGELOG_FLAG_BLOCK |
4352 CHANGELOG_FLAG_JOBID |
4353 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4356 fprintf(stderr, "Can't start changelog: %s\n",
4357 strerror(errno = -rc));
4361 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4365 if (endrec && rec->cr_index > endrec) {
4366 llapi_changelog_free(&rec);
4369 if (rec->cr_index < startrec) {
4370 llapi_changelog_free(&rec);
4374 secs = rec->cr_time >> 30;
4375 gmtime_r(&secs, &ts);
4376 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4377 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4378 changelog_type2str(rec->cr_type),
4379 ts.tm_hour, ts.tm_min, ts.tm_sec,
4380 (int)(rec->cr_time & ((1 << 30) - 1)),
4381 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4382 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4384 if (rec->cr_flags & CLF_JOBID) {
4385 struct changelog_ext_jobid *jid =
4386 changelog_rec_jobid(rec);
4388 if (jid->cr_jobid[0] != '\0')
4389 printf(" j=%s", jid->cr_jobid);
4392 if (rec->cr_namelen)
4393 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4394 rec->cr_namelen, changelog_rec_name(rec));
4396 if (rec->cr_flags & CLF_RENAME) {
4397 struct changelog_ext_rename *rnm =
4398 changelog_rec_rename(rec);
4400 if (!fid_is_zero(&rnm->cr_sfid))
4401 printf(" s="DFID" sp="DFID" %.*s",
4402 PFID(&rnm->cr_sfid),
4403 PFID(&rnm->cr_spfid),
4404 (int)changelog_rec_snamelen(rec),
4405 changelog_rec_sname(rec));
4409 llapi_changelog_free(&rec);
4412 llapi_changelog_fini(&changelog_priv);
4415 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4417 return (rc == 1 ? 0 : rc);
4420 static int lfs_changelog_clear(int argc, char **argv)
4428 endrec = strtoll(argv[3], NULL, 10);
4430 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4433 fprintf(stderr, "%s: record out of range: %llu\n",
4435 else if (rc == -ENOENT)
4436 fprintf(stderr, "%s: no changelog user: %s\n",
4439 fprintf(stderr, "%s error: %s\n", argv[0],
4448 static int lfs_fid2path(int argc, char **argv)
4450 struct option long_opts[] = {
4451 {"cur", no_argument, 0, 'c'},
4452 {"link", required_argument, 0, 'l'},
4453 {"rec", required_argument, 0, 'r'},
4456 char short_opts[] = "cl:r:";
4457 char *device, *fid, *path;
4458 long long recno = -1;
4464 while ((rc = getopt_long(argc, argv, short_opts,
4465 long_opts, NULL)) != -1) {
4471 linkno = strtol(optarg, NULL, 10);
4474 recno = strtoll(optarg, NULL, 10);
4479 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4480 argv[0], argv[optind - 1]);
4488 device = argv[optind++];
4489 path = calloc(1, PATH_MAX);
4491 fprintf(stderr, "error: Not enough memory\n");
4496 while (optind < argc) {
4497 fid = argv[optind++];
4499 lnktmp = (linkno >= 0) ? linkno : 0;
4501 int oldtmp = lnktmp;
4502 long long rectmp = recno;
4504 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4507 fprintf(stderr, "%s: error on FID %s: %s\n",
4508 argv[0], fid, strerror(errno = -rc2));
4515 fprintf(stdout, "%lld ", rectmp);
4516 if (device[0] == '/') {
4517 fprintf(stdout, "%s", device);
4518 if (device[strlen(device) - 1] != '/')
4519 fprintf(stdout, "/");
4520 } else if (path[0] == '\0') {
4521 fprintf(stdout, "/");
4523 fprintf(stdout, "%s\n", path);
4526 /* specified linkno */
4528 if (oldtmp == lnktmp)
4538 static int lfs_path2fid(int argc, char **argv)
4540 struct option long_opts[] = {
4541 {"parents", no_argument, 0, 'p'},
4545 const char short_opts[] = "p";
4546 const char *sep = "";
4549 bool show_parents = false;
4551 while ((rc = getopt_long(argc, argv, short_opts,
4552 long_opts, NULL)) != -1) {
4555 show_parents = true;
4558 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4559 argv[0], argv[optind - 1]);
4564 if (optind > argc - 1)
4566 else if (optind < argc - 1)
4570 for (path = argv + optind; *path != NULL; path++) {
4572 if (!show_parents) {
4573 err = llapi_path2fid(*path, &fid);
4575 printf("%s%s"DFID"\n",
4576 *sep != '\0' ? *path : "", sep,
4579 char name[NAME_MAX + 1];
4580 unsigned int linkno = 0;
4582 while ((err = llapi_path2parent(*path, linkno, &fid,
4583 name, sizeof(name))) == 0) {
4584 if (*sep != '\0' && linkno == 0)
4585 printf("%s%s", *path, sep);
4587 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4592 /* err == -ENODATA is end-of-loop */
4593 if (linkno > 0 && err == -ENODATA) {
4600 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4601 argv[0], show_parents ? "parent " : "", *path,
4613 static int lfs_data_version(int argc, char **argv)
4620 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4625 while ((c = getopt(argc, argv, "nrw")) != -1) {
4628 data_version_flags = 0;
4631 data_version_flags |= LL_DV_RD_FLUSH;
4634 data_version_flags |= LL_DV_WR_FLUSH;
4643 path = argv[optind];
4644 fd = open(path, O_RDONLY);
4646 err(errno, "cannot open file %s", path);
4648 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4650 err(errno, "cannot get version for %s", path);
4652 printf("%ju" "\n", (uintmax_t)data_version);
4658 static int lfs_hsm_state(int argc, char **argv)
4663 struct hsm_user_state hus;
4671 rc = llapi_hsm_state_get(path, &hus);
4673 fprintf(stderr, "can't get hsm state for %s: %s\n",
4674 path, strerror(errno = -rc));
4678 /* Display path name and status flags */
4679 printf("%s: (0x%08x)", path, hus.hus_states);
4681 if (hus.hus_states & HS_RELEASED)
4682 printf(" released");
4683 if (hus.hus_states & HS_EXISTS)
4685 if (hus.hus_states & HS_DIRTY)
4687 if (hus.hus_states & HS_ARCHIVED)
4688 printf(" archived");
4689 /* Display user-settable flags */
4690 if (hus.hus_states & HS_NORELEASE)
4691 printf(" never_release");
4692 if (hus.hus_states & HS_NOARCHIVE)
4693 printf(" never_archive");
4694 if (hus.hus_states & HS_LOST)
4695 printf(" lost_from_hsm");
4697 if (hus.hus_archive_id != 0)
4698 printf(", archive_id:%d", hus.hus_archive_id);
4701 } while (++i < argc);
4706 #define LFS_HSM_SET 0
4707 #define LFS_HSM_CLEAR 1
4710 * Generic function to set or clear HSM flags.
4711 * Used by hsm_set and hsm_clear.
4713 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4715 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4717 struct option long_opts[] = {
4718 {"lost", 0, 0, 'l'},
4719 {"norelease", 0, 0, 'r'},
4720 {"noarchive", 0, 0, 'a'},
4721 {"archived", 0, 0, 'A'},
4722 {"dirty", 0, 0, 'd'},
4723 {"exists", 0, 0, 'e'},
4726 char short_opts[] = "lraAde";
4734 while ((c = getopt_long(argc, argv, short_opts,
4735 long_opts, NULL)) != -1) {
4741 mask |= HS_NOARCHIVE;
4744 mask |= HS_ARCHIVED;
4747 mask |= HS_NORELEASE;
4758 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4759 argv[0], argv[optind - 1]);
4764 /* User should have specified a flag */
4768 while (optind < argc) {
4770 path = argv[optind];
4772 /* If mode == 0, this means we apply the mask. */
4773 if (mode == LFS_HSM_SET)
4774 rc = llapi_hsm_state_set(path, mask, 0, 0);
4776 rc = llapi_hsm_state_set(path, 0, mask, 0);
4779 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4780 path, strerror(errno = -rc));
4789 static int lfs_hsm_action(int argc, char **argv)
4794 struct hsm_current_action hca;
4795 struct hsm_extent he;
4796 enum hsm_user_action hua;
4797 enum hsm_progress_states hps;
4805 rc = llapi_hsm_current_action(path, &hca);
4807 fprintf(stderr, "can't get hsm action for %s: %s\n",
4808 path, strerror(errno = -rc));
4811 he = hca.hca_location;
4812 hua = hca.hca_action;
4813 hps = hca.hca_state;
4815 printf("%s: %s", path, hsm_user_action2name(hua));
4817 /* Skip file without action */
4818 if (hca.hca_action == HUA_NONE) {
4823 printf(" %s ", hsm_progress_state2name(hps));
4825 if ((hps == HPS_RUNNING) &&
4826 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4827 printf("(%llu bytes moved)\n",
4828 (unsigned long long)he.length);
4829 else if ((he.offset + he.length) == LUSTRE_EOF)
4830 printf("(from %llu to EOF)\n",
4831 (unsigned long long)he.offset);
4833 printf("(from %llu to %llu)\n",
4834 (unsigned long long)he.offset,
4835 (unsigned long long)(he.offset + he.length));
4837 } while (++i < argc);
4842 static int lfs_hsm_set(int argc, char **argv)
4844 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4847 static int lfs_hsm_clear(int argc, char **argv)
4849 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4853 * Check file state and return its fid, to be used by lfs_hsm_request().
4855 * \param[in] file Path to file to check
4856 * \param[in,out] fid Pointer to allocated lu_fid struct.
4857 * \param[in,out] last_dev Pointer to last device id used.
4859 * \return 0 on success.
4861 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4867 rc = lstat(file, &st);
4869 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4872 /* Checking for regular file as archiving as posix copytool
4873 * rejects archiving files other than regular files
4875 if (!S_ISREG(st.st_mode)) {
4876 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4879 /* A request should be ... */
4880 if (*last_dev != st.st_dev && *last_dev != 0) {
4881 fprintf(stderr, "All files should be "
4882 "on the same filesystem: %s\n", file);
4885 *last_dev = st.st_dev;
4887 rc = llapi_path2fid(file, fid);
4889 fprintf(stderr, "Cannot read FID of %s: %s\n",
4890 file, strerror(-rc));
4896 /* Fill an HSM HUR item with a given file name.
4898 * If mntpath is set, then the filename is actually a FID, and no
4899 * lookup on the filesystem will be performed.
4901 * \param[in] hur the user request to fill
4902 * \param[in] idx index of the item inside the HUR to fill
4903 * \param[in] mntpath mountpoint of Lustre
4904 * \param[in] fname filename (if mtnpath is NULL)
4905 * or FID (if mntpath is set)
4906 * \param[in] last_dev pointer to last device id used
4908 * \retval 0 on success
4909 * \retval CMD_HELP or a negative errno on error
4911 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4912 const char *mntpath, const char *fname,
4915 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4918 hui->hui_extent.length = -1;
4920 if (mntpath != NULL) {
4923 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4927 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4932 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4936 hur->hur_request.hr_itemcount++;
4941 static int lfs_hsm_request(int argc, char **argv, int action)
4943 struct option long_opts[] = {
4944 {"filelist", 1, 0, 'l'},
4945 {"data", 1, 0, 'D'},
4946 {"archive", 1, 0, 'a'},
4947 {"mntpath", 1, 0, 'm'},
4951 char short_opts[] = "l:D:a:m:";
4952 struct hsm_user_request *hur, *oldhur;
4957 char *filelist = NULL;
4958 char fullpath[PATH_MAX];
4959 char *opaque = NULL;
4963 int nbfile_alloc = 0;
4964 char *some_file = NULL;
4965 char *mntpath = NULL;
4971 while ((c = getopt_long(argc, argv, short_opts,
4972 long_opts, NULL)) != -1) {
4981 if (action != HUA_ARCHIVE &&
4982 action != HUA_REMOVE) {
4984 "error: -a is supported only "
4985 "when archiving or removing\n");
4988 archive_id = atoi(optarg);
4991 if (some_file == NULL) {
4993 some_file = strdup(optarg);
4999 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5000 argv[0], argv[optind - 1]);
5005 /* All remaining args are files, so we have at least nbfile */
5006 nbfile = argc - optind;
5008 if ((nbfile == 0) && (filelist == NULL))
5012 opaque_len = strlen(opaque);
5014 /* Alloc the request structure with enough place to store all files
5015 * from command line. */
5016 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5018 fprintf(stderr, "Cannot create the request: %s\n",
5022 nbfile_alloc = nbfile;
5024 hur->hur_request.hr_action = action;
5025 hur->hur_request.hr_archive_id = archive_id;
5026 hur->hur_request.hr_flags = 0;
5028 /* All remaining args are files, add them */
5029 if (nbfile != 0 && some_file == NULL)
5030 some_file = strdup(argv[optind]);
5032 for (i = 0; i < nbfile; i++) {
5033 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5039 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5041 /* If a filelist was specified, read the filelist from it. */
5042 if (filelist != NULL) {
5043 fp = fopen(filelist, "r");
5045 fprintf(stderr, "Cannot read the file list %s: %s\n",
5046 filelist, strerror(errno));
5051 while ((rc = getline(&line, &len, fp)) != -1) {
5052 /* If allocated buffer was too small, get something
5054 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5057 nbfile_alloc = nbfile_alloc * 2 + 1;
5059 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5062 fprintf(stderr, "hsm: cannot allocate "
5063 "the request: %s\n",
5070 size = hur_len(oldhur);
5072 fprintf(stderr, "hsm: cannot allocate "
5073 "%u files + %u bytes data\n",
5074 oldhur->hur_request.hr_itemcount,
5075 oldhur->hur_request.hr_data_len);
5082 memcpy(hur, oldhur, size);
5087 if (line[strlen(line) - 1] == '\n')
5088 line[strlen(line) - 1] = '\0';
5090 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5091 mntpath, line, &last_dev);
5097 if (some_file == NULL) {
5107 /* If a --data was used, add it to the request */
5108 hur->hur_request.hr_data_len = opaque_len;
5110 memcpy(hur_data(hur), opaque, opaque_len);
5112 /* Send the HSM request */
5113 if (realpath(some_file, fullpath) == NULL) {
5114 fprintf(stderr, "Could not find path '%s': %s\n",
5115 some_file, strerror(errno));
5117 rc = llapi_hsm_request(fullpath, hur);
5119 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5120 some_file, strerror(-rc));
5130 static int lfs_hsm_archive(int argc, char **argv)
5132 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5135 static int lfs_hsm_restore(int argc, char **argv)
5137 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5140 static int lfs_hsm_release(int argc, char **argv)
5142 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5145 static int lfs_hsm_remove(int argc, char **argv)
5147 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5150 static int lfs_hsm_cancel(int argc, char **argv)
5152 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5155 static int lfs_swap_layouts(int argc, char **argv)
5160 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5161 SWAP_LAYOUTS_KEEP_MTIME |
5162 SWAP_LAYOUTS_KEEP_ATIME);
5165 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5167 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5169 enum lu_ladvise_type advice;
5172 advice < ARRAY_SIZE(ladvise_names); advice++) {
5173 if (ladvise_names[advice] == NULL)
5175 if (strcmp(string, ladvise_names[advice]) == 0)
5179 return LU_LADVISE_INVALID;
5182 static int lfs_ladvise(int argc, char **argv)
5184 struct option long_opts[] = {
5185 {"advice", required_argument, 0, 'a'},
5186 {"background", no_argument, 0, 'b'},
5187 {"end", required_argument, 0, 'e'},
5188 {"start", required_argument, 0, 's'},
5189 {"length", required_argument, 0, 'l'},
5192 char short_opts[] = "a:be:l:s:";
5197 struct llapi_lu_ladvise advice;
5198 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5199 unsigned long long start = 0;
5200 unsigned long long end = LUSTRE_EOF;
5201 unsigned long long length = 0;
5202 unsigned long long size_units;
5203 unsigned long long flags = 0;
5206 while ((c = getopt_long(argc, argv, short_opts,
5207 long_opts, NULL)) != -1) {
5210 advice_type = lfs_get_ladvice(optarg);
5211 if (advice_type == LU_LADVISE_INVALID) {
5212 fprintf(stderr, "%s: invalid advice type "
5213 "'%s'\n", argv[0], optarg);
5214 fprintf(stderr, "Valid types:");
5216 for (advice_type = 0;
5217 advice_type < ARRAY_SIZE(ladvise_names);
5219 if (ladvise_names[advice_type] == NULL)
5221 fprintf(stderr, " %s",
5222 ladvise_names[advice_type]);
5224 fprintf(stderr, "\n");
5234 rc = llapi_parse_size(optarg, &end,
5237 fprintf(stderr, "%s: bad end offset '%s'\n",
5244 rc = llapi_parse_size(optarg, &start,
5247 fprintf(stderr, "%s: bad start offset "
5248 "'%s'\n", argv[0], optarg);
5254 rc = llapi_parse_size(optarg, &length,
5257 fprintf(stderr, "%s: bad length '%s'\n",
5265 fprintf(stderr, "%s: option '%s' unrecognized\n",
5266 argv[0], argv[optind - 1]);
5271 if (advice_type == LU_LADVISE_INVALID) {
5272 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5273 fprintf(stderr, "Valid types:");
5274 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5276 if (ladvise_names[advice_type] == NULL)
5278 fprintf(stderr, " %s", ladvise_names[advice_type]);
5280 fprintf(stderr, "\n");
5284 if (argc <= optind) {
5285 fprintf(stderr, "%s: please give one or more file names\n",
5290 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5291 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5296 if (end == LUSTRE_EOF && length != 0)
5297 end = start + length;
5300 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5301 argv[0], start, end);
5305 while (optind < argc) {
5308 path = argv[optind++];
5310 fd = open(path, O_RDONLY);
5312 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5313 argv[0], path, strerror(errno));
5318 advice.lla_start = start;
5319 advice.lla_end = end;
5320 advice.lla_advice = advice_type;
5321 advice.lla_value1 = 0;
5322 advice.lla_value2 = 0;
5323 advice.lla_value3 = 0;
5324 advice.lla_value4 = 0;
5325 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5328 fprintf(stderr, "%s: cannot give advice '%s' to file "
5329 "'%s': %s\n", argv[0],
5330 ladvise_names[advice_type],
5331 path, strerror(errno));
5334 if (rc == 0 && rc2 < 0)
5340 static int lfs_list_commands(int argc, char **argv)
5342 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5344 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5349 int main(int argc, char **argv)
5353 /* Ensure that liblustreapi constructor has run */
5354 if (!liblustreapi_initialized)
5355 fprintf(stderr, "liblustreapi was not properly initialized\n");
5359 Parser_init("lfs > ", cmdlist);
5361 progname = argv[0]; /* Used in error messages */
5363 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5365 rc = Parser_commands();
5368 return rc < 0 ? -rc : rc;
5371 #ifdef _LUSTRE_IDL_H_
5372 /* Everything we need here should be included by lustreapi.h. */
5373 # error "lfs should not depend on lustre_idl.h"
5374 #endif /* _LUSTRE_IDL_H_ */