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 <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-I and -F can't be specified at the same time\n"
192 "To add component(s) to an existing composite file:\n"
193 SSM_CMD_COMMON("setstripe --component-add")
195 "To create a file with specified striping/composite layout:\n"
197 {"getstripe", lfs_getstripe, 0,
198 "To list the striping info for a given file or files in a\n"
199 "directory or recursively for all files in a directory tree.\n"
200 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
201 " [--stripe-count|-c] [--stripe-index|-i]\n"
202 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
203 " [--mdt|-m] [--recursive|-r] [--raw|-R]\n"
204 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
205 " [--component-id|-I [comp_id]]\n"
206 " [--component-flags [comp_flags]]\n"
207 " [--component-count [comp_count]]\n"
208 " [--component-start [comp_start]]\n"
209 " [--component-end|-E [comp_end]]\n"
210 " <directory|filename> ..."},
211 {"setdirstripe", lfs_setdirstripe, 0,
212 "To create a striped directory on a specified MDT. This can only\n"
213 "be done on MDT0 with the right of administrator.\n"
214 "usage: setdirstripe [OPTION] <directory>\n"
216 {"getdirstripe", lfs_getdirstripe, 0,
217 "To list the striping info for a given directory\n"
218 "or recursively for all directories in a directory tree.\n"
219 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
220 " [--mdt-index|-i] [--mdt-hash|-H]\n"
221 " [--recursive|-r] [--default|-D] <dir> ..."},
222 {"mkdir", lfs_setdirstripe, 0,
223 "To create a striped directory on a specified MDT. This can only\n"
224 "be done on MDT0 with the right of administrator.\n"
225 "usage: mkdir [OPTION] <directory>\n"
227 {"rm_entry", lfs_rmentry, 0,
228 "To remove the name entry of the remote directory. Note: This\n"
229 "command will only delete the name entry, i.e. the remote directory\n"
230 "will become inaccessable after this command. This can only be done\n"
231 "by the administrator\n"
232 "usage: rm_entry <dir>\n"},
233 {"pool_list", lfs_poollist, 0,
234 "List pools or pool OSTs\n"
235 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
236 {"find", lfs_find, 0,
237 "find files matching given attributes recursively in directory tree.\n"
238 "usage: find <directory|filename> ...\n"
239 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
240 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
241 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
242 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
243 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
244 " [[!] --stripe-count|-c [+-]<stripes>]\n"
245 " [[!] --stripe-index|-i <index,...>]\n"
246 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
247 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
248 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
249 " [[!] --projid <projid>]\n"
250 " [[!] --layout|-L released,raid0]\n"
251 " [[!] --component-count [+-]<comp_cnt>]\n"
252 " [[!] --component-start [+-]N[kMGTPE]]\n"
253 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
254 " [[!] --component-flags <comp_flags>]\n"
255 " [[!] --mdt-count|-T [+-]<stripes>]\n"
256 " [[!] --mdt-hash|-H <hashtype>\n"
257 "\t !: used before an option indicates 'NOT' requested attribute\n"
258 "\t -: used before a value indicates 'AT MOST' requested value\n"
259 "\t +: used before a value indicates 'AT LEAST' requested value\n"
260 "\tmdt-hash: hash type of the striped directory.\n"
261 "\t fnv_1a_64 FNV-1a hash algorithm\n"
262 "\t all_char sum of characters % MDT_COUNT\n"},
263 {"check", lfs_check, 0,
264 "Display the status of MDS or OSTs (as specified in the command)\n"
265 "or all the servers (MDS and OSTs).\n"
266 "usage: check <osts|mds|servers>"},
267 {"osts", lfs_osts, 0, "list OSTs connected to client "
268 "[for specified path only]\n" "usage: osts [path]"},
269 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
270 "[for specified path only]\n" "usage: mdts [path]"},
272 "report filesystem disk space usage or inodes usage"
273 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
274 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
275 {"getname", lfs_getname, 0, "list instances and specified mount points "
276 "[for specified path only]\n"
277 "Usage: getname [-h]|[path ...] "},
278 #ifdef HAVE_SYS_QUOTA_H
279 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
280 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
281 " -b <block-softlimit> -B <block-hardlimit>\n"
282 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
283 " setquota <-u|--user|-g|--group|-p|--project> <uname>|<uid>|<gname>|<gid>|<projid>\n"
284 " [--block-softlimit <block-softlimit>]\n"
285 " [--block-hardlimit <block-hardlimit>]\n"
286 " [--inode-softlimit <inode-softlimit>]\n"
287 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
288 " setquota [-t] <-u|--user|-g|--group|-p|--project>\n"
289 " [--block-grace <block-grace>]\n"
290 " [--inode-grace <inode-grace>] <filesystem>\n"
291 " -b can be used instead of --block-softlimit/--block-grace\n"
292 " -B can be used instead of --block-hardlimit\n"
293 " -i can be used instead of --inode-softlimit/--inode-grace\n"
294 " -I can be used instead of --inode-hardlimit\n\n"
295 "Note: The total quota space will be split into many qunits and\n"
296 " balanced over all server targets, the minimal qunit size is\n"
297 " 1M bytes for block space and 1K inodes for inode space.\n\n"
298 " Quota space rebalancing process will stop when this mininum\n"
299 " value is reached. As a result, quota exceeded can be returned\n"
300 " while many targets still have 1MB or 1K inodes of spare\n"
302 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
303 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
305 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
306 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
308 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
309 "usage: flushctx [-k] [mountpoint...]"},
311 "Remote user copy files and directories.\n"
312 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
314 "Remote user list directory contents.\n"
315 "usage: ls [OPTION]... [FILE]..."},
316 {"changelog", lfs_changelog, 0,
317 "Show the metadata changes on an MDT."
318 "\nusage: changelog <mdtname> [startrec [endrec]]"},
319 {"changelog_clear", lfs_changelog_clear, 0,
320 "Indicate that old changelog records up to <endrec> are no longer of "
321 "interest to consumer <id>, allowing the system to free up space.\n"
322 "An <endrec> of 0 means all records.\n"
323 "usage: changelog_clear <mdtname> <id> <endrec>"},
324 {"fid2path", lfs_fid2path, 0,
325 "Resolve the full path(s) for given FID(s). For a specific hardlink "
326 "specify link number <linkno>.\n"
327 /* "For a historical link name, specify changelog record <recno>.\n" */
328 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
329 /* [ --rec <recno> ] */ },
330 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
331 "usage: path2fid [--parents] <path> ..."},
332 {"data_version", lfs_data_version, 0, "Display file data version for "
333 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
334 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
335 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
336 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
337 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
338 "[--archived] [--lost] <file> ..."},
339 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
341 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
342 "[--archived] [--lost] <file> ..."},
343 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
344 "given files.\n" "usage: hsm_action <file> ..."},
345 {"hsm_archive", lfs_hsm_archive, 0,
346 "Archive file to external storage.\n"
347 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
349 {"hsm_restore", lfs_hsm_restore, 0,
350 "Restore file from external storage.\n"
351 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
352 {"hsm_release", lfs_hsm_release, 0,
353 "Release files from Lustre.\n"
354 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
355 {"hsm_remove", lfs_hsm_remove, 0,
356 "Remove file copy from external storage.\n"
357 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
358 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
360 "Note: To remove files from the archive that have been deleted on\n"
361 "Lustre, set mntpath and optionally archive. In that case, all the\n"
362 "positional arguments and entries in the file list must be FIDs."
364 {"hsm_cancel", lfs_hsm_cancel, 0,
365 "Cancel requests related to specified files.\n"
366 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
367 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
368 "usage: swap_layouts <path1> <path2>"},
369 {"migrate", lfs_setstripe, 0,
370 "migrate a directory between MDTs.\n"
371 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
373 "\tmdt_idx: index of the destination MDT\n"
375 "migrate file objects from one OST "
376 "layout\nto another (may be not safe with concurent writes).\n"
378 "[--stripe-count|-c] <stripe_count>\n"
379 " [--stripe-index|-i] <start_ost_index>\n"
380 " [--stripe-size|-S] <stripe_size>\n"
381 " [--pool|-p] <pool_name>\n"
382 " [--ost-list|-o] <ost_indices>\n"
384 " [--non-block|-n]\n"
385 " <file|directory>\n"
386 "\tstripe_count: number of OSTs to stripe a file over\n"
387 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
388 "\tstripe_size: number of bytes to store before moving to the next OST\n"
389 "\tpool_name: name of the predefined pool of OSTs\n"
390 "\tost_indices: OSTs to stripe over, in order\n"
391 "\tblock: wait for the operation to return before continuing\n"
392 "\tnon-block: do not wait for the operation to return.\n"},
394 "To move directories between MDTs. This command is deprecated, "
395 "use \"migrate\" instead.\n"
396 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
398 {"ladvise", lfs_ladvise, 0,
399 "Provide servers with advice about access patterns for a file.\n"
400 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
401 " [--background|-b]\n"
402 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
404 {"help", Parser_help, 0, "help"},
405 {"exit", Parser_quit, 0, "quit"},
406 {"quit", Parser_quit, 0, "quit"},
407 {"--version", Parser_version, 0,
408 "output build version of the utility and exit"},
409 {"--list-commands", lfs_list_commands, 0,
410 "list commands supported by the utility and exit"},
415 #define MIGRATION_NONBLOCK 1
417 static int check_hashtype(const char *hashtype)
421 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
422 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
429 * Internal helper for migrate_copy_data(). Check lease and report error if
432 * \param[in] fd File descriptor on which to check the lease.
433 * \param[out] lease_broken Set to true if the lease was broken.
434 * \param[in] group_locked Whether a group lock was taken or not.
435 * \param[in] path Name of the file being processed, for error
438 * \retval 0 Migration can keep on going.
439 * \retval -errno Error occurred, abort migration.
441 static int check_lease(int fd, bool *lease_broken, bool group_locked,
446 if (!file_lease_supported)
449 rc = llapi_lease_check(fd);
451 return 0; /* llapi_check_lease returns > 0 on success. */
454 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
456 rc = rc ? rc : -EAGAIN;
458 fprintf(stderr, "%s: external attempt to access file '%s' "
459 "blocked until migration ends.\n", progname, path);
462 *lease_broken = true;
466 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
467 bool group_locked, const char *fname)
476 bool lease_broken = false;
478 /* Use a page-aligned buffer for direct I/O */
479 rc = posix_memalign(&buf, getpagesize(), buf_size);
484 /* read new data only if we have written all
485 * previously read data */
488 rc = check_lease(fd_src, &lease_broken,
489 group_locked, fname);
493 rsize = read(fd_src, buf, buf_size);
496 fprintf(stderr, "%s: %s: read failed: %s\n",
497 progname, fname, strerror(-rc));
507 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
511 "%s: %s: write failed on volatile: %s\n",
512 progname, fname, strerror(-rc));
522 fprintf(stderr, "%s: %s: fsync failed: %s\n",
523 progname, fname, strerror(-rc));
531 static int migrate_copy_timestamps(int fdv, const struct stat *st)
533 struct timeval tv[2] = {
534 {.tv_sec = st->st_atime},
535 {.tv_sec = st->st_mtime}
538 return futimes(fdv, tv);
541 static int migrate_block(int fd, int fdv, const struct stat *st,
542 size_t buf_size, const char *name)
549 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
551 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
552 progname, name, strerror(-rc));
560 /* The grouplock blocks all concurrent accesses to the file.
561 * It has to be taken after llapi_get_data_version as it would
563 rc = llapi_group_lock(fd, gid);
565 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
566 progname, name, strerror(-rc));
570 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
572 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
576 /* Make sure we keep original atime/mtime values */
577 rc = migrate_copy_timestamps(fdv, st);
579 fprintf(stderr, "%s: %s: timestamp copy failed\n",
585 * for a migration we need to check data version on file did
588 * Pass in gid=0 since we already own grouplock. */
589 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
590 SWAP_LAYOUTS_CHECK_DV1);
592 fprintf(stderr, "%s: %s: dataversion changed during copy, "
593 "migration aborted\n", progname, name);
596 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
597 name, strerror(-rc));
602 rc2 = llapi_group_unlock(fd, gid);
603 if (rc2 < 0 && rc == 0) {
604 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
605 progname, name, strerror(-rc2));
612 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
613 size_t buf_size, const char *name)
619 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
621 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
622 progname, name, strerror(-rc));
626 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
628 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
632 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
634 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
635 progname, name, strerror(-rc));
641 fprintf(stderr, "%s: %s: data version changed during "
647 /* Make sure we keep original atime/mtime values */
648 rc = migrate_copy_timestamps(fdv, st);
650 fprintf(stderr, "%s: %s: timestamp copy failed\n",
655 /* Atomically put lease, swap layouts and close.
656 * for a migration we need to check data version on file did
658 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
660 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
661 progname, name, strerror(-rc));
668 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
673 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
677 if (flags != 0 && comp_id != 0)
680 /* LCME_FL_INIT is the only supported flag in PFL */
682 if (flags & ~LCME_KNOWN_FLAGS) {
683 fprintf(stderr, "Invalid component flags %#x\n", flags);
686 comp_id = LCME_ID_NONE | flags;
687 } else if (comp_id > LCME_ID_MAX) {
688 fprintf(stderr, "Invalid component id %u\n", comp_id);
692 rc = llapi_layout_file_comp_del(fname, comp_id);
694 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
695 comp_id, fname, strerror(errno));
699 static int lfs_component_add(char *fname, struct llapi_layout *layout)
706 rc = llapi_layout_file_comp_add(fname, layout);
708 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
709 fname, strerror(errno));
713 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
714 struct llapi_layout *layout)
722 fd = lstat(fname, &st);
723 if (fd == 0 && S_ISDIR(st.st_mode))
724 open_flags = O_DIRECTORY | O_RDONLY;
726 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
728 fprintf(stderr, "%s %s failed. %s\n",
729 S_ISDIR(st.st_mode) ?
730 "Set default composite layout to " :
731 "Create composite file",
732 fname, strerror(errno));
736 static int lfs_migrate(char *name, __u64 migration_flags,
737 struct llapi_stripe_param *param,
738 struct llapi_layout *layout)
742 char parent[PATH_MAX];
745 char volatile_file[sizeof(parent) +
746 LUSTRE_VOLATILE_HDR_LEN +
747 2 * sizeof(mdt_index) +
748 2 * sizeof(random_value) + 4];
751 struct lov_user_md *lum = NULL;
753 int buf_size = 1024 * 1024 * 4;
754 bool have_lease_rdlck = false;
758 /* find the right size for the IO and allocate the buffer */
759 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
760 lum = malloc(lum_size);
766 rc = llapi_file_get_stripe(name, lum);
767 /* failure can happen for many reasons and some may be not real errors
769 * in case of a real error, a later call will fail with better
770 * error management */
772 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
773 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
774 lum->lmm_stripe_size != 0)
775 buf_size = lum->lmm_stripe_size;
778 /* open file, direct io */
779 /* even if the file is only read, WR mode is nedeed to allow
780 * layout swap on fd */
781 fd = open(name, O_RDWR | O_DIRECT);
784 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
789 if (file_lease_supported) {
790 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
791 if (rc == -EOPNOTSUPP) {
792 /* Older servers do not support file lease.
793 * Disable related checks. This opens race conditions
794 * as explained in LU-4840 */
795 file_lease_supported = false;
797 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
798 progname, name, strerror(-rc));
801 have_lease_rdlck = true;
805 /* search for file directory pathname */
806 if (strlen(name) > sizeof(parent)-1) {
810 strncpy(parent, name, sizeof(parent));
811 ptr = strrchr(parent, '/');
813 if (getcwd(parent, sizeof(parent)) == NULL) {
824 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
826 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
827 progname, name, strerror(-rc));
832 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
833 mode_t open_mode = S_IRUSR | S_IWUSR;
835 random_value = random();
836 rc = snprintf(volatile_file, sizeof(volatile_file),
837 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
838 mdt_index, random_value);
839 if (rc >= sizeof(volatile_file)) {
844 /* create, open a volatile file, use caching (ie no directio) */
846 fdv = llapi_file_open_param(volatile_file, open_flags,
848 else if (layout != NULL)
849 fdv = lfs_component_create(volatile_file, open_flags,
853 } while (fdv == -EEXIST);
857 fprintf(stderr, "%s: %s: cannot create volatile file in"
859 progname, parent, strerror(-rc));
863 /* In case the MDT does not support creation of volatile files
864 * we should try to unlink it. */
865 (void)unlink(volatile_file);
867 /* Not-owner (root?) special case.
868 * Need to set owner/group of volatile file like original.
869 * This will allow to pass related check during layout_swap.
874 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
878 rc = fstat(fdv, &stv);
881 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
882 volatile_file, strerror(errno));
885 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
886 rc = fchown(fdv, st.st_uid, st.st_gid);
889 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
890 name, strerror(errno));
895 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
896 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
898 have_lease_rdlck = false;
899 fdv = -1; /* The volatile file is closed as we put the
900 * lease in non-blocking mode. */
903 /* Blocking mode (forced if servers do not support file lease).
904 * It is also the default mode, since we cannot distinguish
905 * between a broken lease and a server that does not support
906 * atomic swap/close (LU-6785) */
907 rc = migrate_block(fd, fdv, &st, buf_size, name);
911 if (have_lease_rdlck)
928 * Parse a string containing an OST index list into an array of integers.
930 * The input string contains a comma delimited list of individual
931 * indices and ranges, for example "1,2-4,7". Add the indices into the
932 * \a osts array and remove duplicates.
934 * \param[out] osts array to store indices in
935 * \param[in] size size of \a osts array
936 * \param[in] offset starting index in \a osts
937 * \param[in] arg string containing OST index list
939 * \retval positive number of indices in \a osts
940 * \retval -EINVAL unable to parse \a arg
942 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
946 int slots = size - offset;
954 while (!end_of_loop) {
962 ptr = strchrnul(arg, ',');
964 end_of_loop = *ptr == '\0';
967 start_index = strtol(arg, &endptr, 0);
968 if (endptr == arg) /* no data at all */
970 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
975 end_index = start_index;
976 if (*endptr == '-') {
977 end_index = strtol(endptr + 1, &endptr, 0);
980 if (end_index < start_index)
984 for (i = start_index; i <= end_index && slots > 0; i++) {
987 /* remove duplicate */
988 for (j = 0; j < offset; j++) {
992 if (j == offset) { /* no duplicate */
997 if (slots == 0 && i < end_index)
1005 if (!end_of_loop && ptr != NULL)
1008 return rc < 0 ? rc : nr;
1011 static int verify_pool_name(char *prog_name, char *pool_name)
1016 if (pool_name == NULL)
1019 ptr = strchr(pool_name, '.');
1023 if (ptr == pool_name) {
1024 fprintf(stderr, "error: %s: fsname is empty "
1025 "in pool name '%s'\n",
1026 prog_name, pool_name);
1032 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1034 fprintf(stderr, "error: %s: poolname '%s' is empty\n",
1035 prog_name, pool_name);
1037 } else if (rc == -2) {
1038 fprintf(stderr, "error: %s: pool name '%s' is too long "
1039 "(max is %d characters)\n",
1040 prog_name, pool_name, LOV_MAXPOOLNAME);
1042 } else if (rc > 0) {
1043 fprintf(stderr, "error: %s: char '%c' not allowed in "
1045 prog_name, rc, pool_name);
1051 struct lfs_setstripe_args {
1052 unsigned long long lsa_comp_end;
1053 unsigned long long lsa_stripe_size;
1054 int lsa_stripe_count;
1056 __u32 lsa_comp_flags;
1059 char *lsa_pool_name;
1062 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1064 memset(lsa, 0, sizeof(*lsa));
1065 lsa->lsa_stripe_off = -1;
1068 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1070 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1071 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1072 lsa->lsa_comp_end != 0);
1075 static int comp_args_to_layout(struct llapi_layout **composite,
1076 struct lfs_setstripe_args *lsa)
1078 struct llapi_layout *layout = *composite;
1079 uint64_t prev_end = 0;
1082 if (layout == NULL) {
1083 layout = llapi_layout_alloc();
1084 if (layout == NULL) {
1085 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1089 *composite = layout;
1093 /* Get current component extent, current component
1094 * must be the tail component. */
1095 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1097 fprintf(stderr, "Get comp extent failed. %s\n",
1102 rc = llapi_layout_comp_add(layout);
1104 fprintf(stderr, "Add component failed. %s\n",
1110 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1112 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1113 prev_end, lsa->lsa_comp_end, strerror(errno));
1117 if (lsa->lsa_stripe_size != 0) {
1118 rc = llapi_layout_stripe_size_set(layout,
1119 lsa->lsa_stripe_size);
1121 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1122 lsa->lsa_stripe_size, strerror(errno));
1127 if (lsa->lsa_stripe_count != 0) {
1128 rc = llapi_layout_stripe_count_set(layout,
1129 lsa->lsa_stripe_count == -1 ?
1131 lsa->lsa_stripe_count);
1133 fprintf(stderr, "Set stripe count %d failed. %s\n",
1134 lsa->lsa_stripe_count, strerror(errno));
1139 if (lsa->lsa_pool_name != NULL) {
1140 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1142 fprintf(stderr, "Set pool name: %s failed. %s\n",
1143 lsa->lsa_pool_name, strerror(errno));
1148 if (lsa->lsa_nr_osts > 0) {
1149 if (lsa->lsa_stripe_count > 0 &&
1150 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1151 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1152 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1155 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1156 rc = llapi_layout_ost_index_set(layout, i,
1161 } else if (lsa->lsa_stripe_off != -1) {
1162 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1165 fprintf(stderr, "Set ost index %d failed. %s\n",
1166 i, strerror(errno));
1173 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1174 * end of the last component in the existing file, and adjust the
1175 * first extent start of the components to be added accordingly. */
1176 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1178 struct llapi_layout *head;
1179 uint64_t start, end, stripe_size, prev_end = 0;
1185 head = llapi_layout_get_by_path(fname, 0);
1187 fprintf(stderr, "Read layout from %s failed. %s\n",
1188 fname, strerror(errno));
1192 /* Current component of 'head' should be tail of component list. */
1193 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1195 fprintf(stderr, "Get prev extent failed. %s\n",
1197 llapi_layout_free(head);
1201 llapi_layout_free(head);
1203 /* Make sure we use the first component of the layout to be added. */
1204 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1206 fprintf(stderr, "Move component cursor failed. %s\n",
1211 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1213 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1217 if (start > prev_end || end <= prev_end) {
1218 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1219 "adjacent with the existing file extent end: %lu\n",
1220 start, end, prev_end);
1224 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1226 fprintf(stderr, "Get stripe size failed. %s\n",
1231 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1232 (prev_end & (stripe_size - 1))) {
1233 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1234 stripe_size, prev_end);
1238 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1240 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1241 prev_end, end, strerror(errno));
1248 static int comp_name2flags(__u32 *flags, char *name)
1256 for (ptr = name; ; ptr = NULL) {
1257 char *flg = strtok(ptr, ",");
1260 if (strcmp(flg, "init") == 0)
1261 *flags |= LCME_FL_INIT;
1265 return (*flags == 0) ? -EINVAL : 0;
1280 static int lfs_setstripe(int argc, char **argv)
1282 struct lfs_setstripe_args lsa;
1283 struct llapi_stripe_param *param = NULL;
1284 struct find_param migrate_mdt_param = {
1294 char *mdt_idx_arg = NULL;
1295 unsigned long long size_units = 1;
1296 bool migrate_mode = false;
1297 bool migration_block = false;
1298 __u64 migration_flags = 0;
1299 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1300 int comp_del = 0, comp_set = 0;
1303 struct llapi_layout *layout = NULL;
1305 struct option long_opts[] = {
1306 /* --block is only valid in migrate mode */
1307 {"block", no_argument, 0, 'b'},
1308 {"comp-add", no_argument, 0, LFS_COMP_ADD_OPT},
1309 {"component-add", no_argument, 0, LFS_COMP_ADD_OPT},
1310 {"comp-del", no_argument, 0, LFS_COMP_DEL_OPT},
1311 {"component-del", no_argument, 0, LFS_COMP_DEL_OPT},
1312 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1313 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1314 {"comp-set", no_argument, 0, LFS_COMP_SET_OPT},
1315 {"component-set", no_argument, 0, LFS_COMP_SET_OPT},
1316 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1317 /* This formerly implied "stripe-count", but was explicitly
1318 * made "stripe-count" for consistency with other options,
1319 * and to separate it from "mdt-count" when DNE arrives. */
1320 {"count", required_argument, 0, 'c'},
1322 {"stripe-count", required_argument, 0, 'c'},
1323 {"stripe_count", required_argument, 0, 'c'},
1324 {"delete", no_argument, 0, 'd'},
1325 {"comp-end", required_argument, 0, 'E'},
1326 {"component-end", required_argument, 0, 'E'},
1327 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1328 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1329 /* This formerly implied "stripe-index", but was explicitly
1330 * made "stripe-index" for consistency with other options,
1331 * and to separate it from "mdt-index" when DNE arrives. */
1332 {"index", required_argument, 0, 'i'},
1334 {"stripe-index", required_argument, 0, 'i'},
1335 {"stripe_index", required_argument, 0, 'i'},
1336 {"comp-id", required_argument, 0, 'I'},
1337 {"component-id", required_argument, 0, 'I'},
1338 {"mdt", required_argument, 0, 'm'},
1339 {"mdt-index", required_argument, 0, 'm'},
1340 {"mdt_index", required_argument, 0, 'm'},
1341 /* --non-block is only valid in migrate mode */
1342 {"non-block", no_argument, 0, 'n'},
1343 {"ost", required_argument, 0, 'o'},
1344 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1345 {"ost-list", required_argument, 0, 'o'},
1346 {"ost_list", required_argument, 0, 'o'},
1348 {"pool", required_argument, 0, 'p'},
1349 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1350 /* This formerly implied "--stripe-size", but was confusing
1351 * with "lfs find --size|-s", which means "file size", so use
1352 * the consistent "--stripe-size|-S" for all commands. */
1353 {"size", required_argument, 0, 's'},
1355 {"stripe-size", required_argument, 0, 'S'},
1356 {"stripe_size", required_argument, 0, 'S'},
1357 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1358 /* --verbose is only valid in migrate mode */
1359 {"verbose", no_argument, 0, 'v'},
1363 setstripe_args_init(&lsa);
1365 if (strcmp(argv[0], "migrate") == 0)
1366 migrate_mode = true;
1368 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1369 long_opts, NULL)) >= 0) {
1374 case LFS_COMP_ADD_OPT:
1377 case LFS_COMP_DEL_OPT:
1380 case LFS_COMP_FLAGS_OPT:
1381 result = comp_name2flags(&lsa.lsa_comp_flags, optarg);
1383 fprintf(stderr, "error: %s: bad comp flags "
1384 "'%s'\n", argv[0], optarg);
1388 case LFS_COMP_SET_OPT:
1392 if (!migrate_mode) {
1393 fprintf(stderr, "--block is valid only for"
1397 migration_block = true;
1400 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1401 if (strcmp(argv[optind - 1], "--count") == 0)
1402 fprintf(stderr, "warning: '--count' deprecated"
1403 ", use '--stripe-count' instead\n");
1405 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1407 fprintf(stderr, "error: %s: bad stripe count "
1408 "'%s'\n", argv[0], optarg);
1413 /* delete the default striping pattern */
1417 if (lsa.lsa_comp_end != 0) {
1418 result = comp_args_to_layout(&layout, &lsa);
1422 setstripe_args_init(&lsa);
1425 if (!strncmp(optarg, "-1", strlen("-1")) ||
1426 !strncmp(optarg, "EOF", strlen("EOF")) ||
1427 !strncmp(optarg, "eof", strlen("eof"))) {
1428 lsa.lsa_comp_end = LUSTRE_EOF;
1430 result = llapi_parse_size(optarg,
1434 fprintf(stderr, "error: %s: "
1435 "bad component end '%s'\n",
1442 if (strcmp(argv[optind - 1], "--index") == 0)
1443 fprintf(stderr, "warning: '--index' deprecated"
1444 ", use '--stripe-index' instead\n");
1445 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1447 fprintf(stderr, "error: %s: bad stripe offset "
1448 "'%s'\n", argv[0], optarg);
1453 comp_id = strtoul(optarg, &end, 0);
1454 if (*end != '\0' || comp_id == 0) {
1455 fprintf(stderr, "error: %s: bad comp ID "
1456 "'%s'\n", argv[0], optarg);
1461 if (!migrate_mode) {
1462 fprintf(stderr, "--mdt-index is valid only for"
1466 mdt_idx_arg = optarg;
1469 if (!migrate_mode) {
1470 fprintf(stderr, "--non-block is valid only for"
1474 migration_flags |= MIGRATION_NONBLOCK;
1477 lsa.lsa_nr_osts = parse_targets(osts,
1478 sizeof(osts) / sizeof(__u32),
1479 lsa.lsa_nr_osts, optarg);
1480 if (lsa.lsa_nr_osts < 0) {
1482 "error: %s: bad OST indices '%s'\n",
1487 lsa.lsa_osts = osts;
1488 if (lsa.lsa_stripe_off == -1)
1489 lsa.lsa_stripe_off = osts[0];
1492 result = verify_pool_name(argv[0], optarg);
1495 lsa.lsa_pool_name = optarg;
1497 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1499 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1500 fprintf(stderr, "warning: '--size|-s' deprecated, "
1501 "use '--stripe-size|-S' instead\n");
1503 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1505 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1508 fprintf(stderr, "error: %s: bad stripe size "
1509 "'%s'\n", argv[0], optarg);
1514 if (!migrate_mode) {
1515 fprintf(stderr, "--verbose is valid only for"
1519 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1526 fname = argv[optind];
1528 if (lsa.lsa_comp_end != 0) {
1529 result = comp_args_to_layout(&layout, &lsa);
1534 if (optind == argc) {
1535 fprintf(stderr, "error: %s: missing filename|dirname\n",
1540 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1541 * altered by user space tool, so we don't need to support the
1542 * --component-set for this moment. */
1543 if (comp_set != 0) {
1544 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1549 if ((delete + comp_set + comp_del + comp_add) > 1) {
1550 fprintf(stderr, "error: %s: can't specify --component-set, "
1551 "--component-del, --component-add or -d together\n",
1556 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1557 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1558 fprintf(stderr, "error: %s: can't specify -d with "
1559 "-s, -c, -o, -p, -I, -F or -E options\n",
1564 if ((comp_set || comp_del) &&
1565 (setstripe_args_specified(&lsa) || layout != NULL)) {
1566 fprintf(stderr, "error: %s: can't specify --component-del or "
1567 "--component-set with -s, -c, -o, -p or -E options.\n",
1572 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1573 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1574 "--component-del option.\n", argv[0]);
1579 if (layout == NULL) {
1580 fprintf(stderr, "error: %s: -E option must be present"
1581 "in --component-add mode.\n", argv[0]);
1584 result = adjust_first_extent(fname, layout);
1589 if (mdt_idx_arg != NULL && optind > 3) {
1590 fprintf(stderr, "error: %s: cannot specify -m with other "
1591 "options\n", argv[0]);
1595 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1597 "error: %s: cannot specify --non-block and --block\n",
1602 /* support --component-id option for migrate later. */
1603 if (migrate_mode && comp_id != 0) {
1604 fprintf(stderr, "error: %s: -I isn't supported yet.\n",
1609 if (mdt_idx_arg != NULL) {
1610 /* initialize migrate mdt parameters */
1611 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1613 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1614 argv[0], mdt_idx_arg);
1617 migrate_mdt_param.fp_migrate = 1;
1618 } else if (layout == NULL) {
1619 /* initialize stripe parameters */
1620 param = calloc(1, offsetof(typeof(*param),
1621 lsp_osts[lsa.lsa_nr_osts]));
1622 if (param == NULL) {
1623 fprintf(stderr, "error: %s: %s\n", argv[0],
1628 param->lsp_stripe_size = lsa.lsa_stripe_size;
1629 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1630 param->lsp_stripe_count = lsa.lsa_stripe_count;
1631 param->lsp_stripe_pattern = 0;
1632 param->lsp_pool = lsa.lsa_pool_name;
1633 param->lsp_is_specific = false;
1634 if (lsa.lsa_nr_osts > 0) {
1635 if (lsa.lsa_stripe_count > 0 &&
1636 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1637 fprintf(stderr, "error: %s: stripe count '%d' "
1638 "doesn't match the number of OSTs: %d\n"
1639 , argv[0], lsa.lsa_stripe_count,
1645 param->lsp_is_specific = true;
1646 param->lsp_stripe_count = lsa.lsa_nr_osts;
1647 memcpy(param->lsp_osts, osts,
1648 sizeof(*osts) * lsa.lsa_nr_osts);
1652 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1654 if (mdt_idx_arg != NULL) {
1655 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1656 op = "migrate mdt objects of";
1657 } else if (migrate_mode) {
1658 result = lfs_migrate(fname, migration_flags, param,
1660 op = "migrate ost objects of";
1661 } else if (comp_set != 0) {
1662 result = lfs_component_set(fname, comp_id,
1663 lsa.lsa_comp_flags);
1664 op = "modify component flags of";
1665 } else if (comp_del != 0) {
1666 result = lfs_component_del(fname, comp_id,
1667 lsa.lsa_comp_flags);
1668 op = "delete component of";
1669 } else if (comp_add != 0) {
1670 result = lfs_component_add(fname, layout);
1671 op = "add component to";
1672 } else if (layout != NULL) {
1673 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1679 op = "create composite";
1681 result = llapi_file_open_param(fname,
1688 op = "create striped";
1691 /* Save the first error encountered. */
1694 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1696 lsa.lsa_pool_name != NULL && result == EINVAL ?
1697 "OST not in pool?" : strerror(errno));
1703 llapi_layout_free(layout);
1706 llapi_layout_free(layout);
1710 static int lfs_poollist(int argc, char **argv)
1715 return llapi_poollist(argv[1]);
1718 static int set_time(time_t *time, time_t *set, char *str)
1725 else if (str[0] == '-')
1731 t = strtol(str, NULL, 0);
1732 if (*time < t * 24 * 60 * 60) {
1735 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1739 *set = *time - t * 24 * 60 * 60;
1742 static int name2uid(unsigned int *id, const char *name)
1744 struct passwd *passwd;
1746 passwd = getpwnam(name);
1749 *id = passwd->pw_uid;
1754 static int name2gid(unsigned int *id, const char *name)
1756 struct group *group;
1758 group = getgrnam(name);
1761 *id = group->gr_gid;
1766 static inline int name2projid(unsigned int *id, const char *name)
1771 static int uid2name(char **name, unsigned int id)
1773 struct passwd *passwd;
1775 passwd = getpwuid(id);
1778 *name = passwd->pw_name;
1783 static inline int gid2name(char **name, unsigned int id)
1785 struct group *group;
1787 group = getgrgid(id);
1790 *name = group->gr_name;
1795 static int name2layout(__u32 *layout, char *name)
1800 for (ptr = name; ; ptr = NULL) {
1801 lyt = strtok(ptr, ",");
1804 if (strcmp(lyt, "released") == 0)
1805 *layout |= LOV_PATTERN_F_RELEASED;
1806 else if (strcmp(lyt, "raid0") == 0)
1807 *layout |= LOV_PATTERN_RAID0;
1814 static int lfs_find(int argc, char **argv)
1819 struct find_param param = {
1823 struct option long_opts[] = {
1824 {"atime", required_argument, 0, 'A'},
1825 {"comp-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1826 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1827 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1828 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1829 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
1830 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1831 {"stripe-count", required_argument, 0, 'c'},
1832 {"stripe_count", required_argument, 0, 'c'},
1833 {"ctime", required_argument, 0, 'C'},
1834 {"maxdepth", required_argument, 0, 'D'},
1835 {"comp-end", required_argument, 0, 'E'},
1836 {"component-end", required_argument, 0, 'E'},
1837 {"gid", required_argument, 0, 'g'},
1838 {"group", required_argument, 0, 'G'},
1839 {"mdt-hash", required_argument, 0, 'H'},
1840 {"stripe-index", required_argument, 0, 'i'},
1841 {"stripe_index", required_argument, 0, 'i'},
1842 /*{"component-id", required_argument, 0, 'I'},*/
1843 {"layout", required_argument, 0, 'L'},
1844 {"mdt", required_argument, 0, 'm'},
1845 {"mdt-index", required_argument, 0, 'm'},
1846 {"mdt_index", required_argument, 0, 'm'},
1847 {"mtime", required_argument, 0, 'M'},
1848 {"name", required_argument, 0, 'n'},
1849 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1850 {"obd", required_argument, 0, 'O'},
1851 {"ost", required_argument, 0, 'O'},
1852 /* no short option for pool, p/P already used */
1853 {"pool", required_argument, 0, LFS_POOL_OPT},
1854 {"print0", no_argument, 0, 'p'},
1855 {"print", no_argument, 0, 'P'},
1856 {"projid", required_argument, 0, LFS_PROJID_OPT},
1857 {"size", required_argument, 0, 's'},
1858 {"stripe-size", required_argument, 0, 'S'},
1859 {"stripe_size", required_argument, 0, 'S'},
1860 {"type", required_argument, 0, 't'},
1861 {"mdt-count", required_argument, 0, 'T'},
1862 {"uid", required_argument, 0, 'u'},
1863 {"user", required_argument, 0, 'U'},
1876 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1877 while ((c = getopt_long_only(argc, argv,
1878 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1879 long_opts, NULL)) >= 0) {
1884 /* '!' is part of option */
1885 /* when getopt_long_only() finds a string which is not
1886 * an option nor a known option argument it returns 1
1887 * in that case if we already have found pathstart and pathend
1888 * (i.e. we have the list of pathnames),
1889 * the only supported value is "!"
1891 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1892 if (!isoption && pathend != -1) {
1893 fprintf(stderr, "err: %s: filename|dirname must either "
1894 "precede options or follow options\n",
1899 if (!isoption && pathstart == -1)
1900 pathstart = optind - 1;
1901 if (isoption && pathstart != -1 && pathend == -1)
1902 pathend = optind - 2;
1908 /* unknown; opt is "!" or path component,
1909 * checking done above.
1911 if (strcmp(optarg, "!") == 0)
1915 xtime = ¶m.fp_atime;
1916 xsign = ¶m.fp_asign;
1917 param.fp_exclude_atime = !!neg_opt;
1918 /* no break, this falls through to 'C' for ctime */
1921 xtime = ¶m.fp_ctime;
1922 xsign = ¶m.fp_csign;
1923 param.fp_exclude_ctime = !!neg_opt;
1925 /* no break, this falls through to 'M' for mtime */
1928 xtime = ¶m.fp_mtime;
1929 xsign = ¶m.fp_msign;
1930 param.fp_exclude_mtime = !!neg_opt;
1932 rc = set_time(&t, xtime, optarg);
1933 if (rc == INT_MAX) {
1940 case LFS_COMP_COUNT_OPT:
1941 if (optarg[0] == '+') {
1942 param.fp_comp_count_sign = -1;
1944 } else if (optarg[0] == '-') {
1945 param.fp_comp_count_sign = 1;
1949 param.fp_comp_count = strtoul(optarg, &endptr, 0);
1950 if (*endptr != '\0') {
1951 fprintf(stderr, "error: bad component count "
1955 param.fp_check_comp_count = 1;
1956 param.fp_exclude_comp_count = !!neg_opt;
1958 case LFS_COMP_FLAGS_OPT:
1959 rc = comp_name2flags(¶m.fp_comp_flags, optarg);
1961 fprintf(stderr, "error: bad component flags "
1965 param.fp_check_comp_flags = 1;
1966 param.fp_exclude_comp_flags = !!neg_opt;
1968 case LFS_COMP_START_OPT:
1969 if (optarg[0] == '+') {
1970 param.fp_comp_start_sign = -1;
1972 } else if (optarg[0] == '-') {
1973 param.fp_comp_start_sign = 1;
1977 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
1978 ¶m.fp_comp_start_units, 0);
1980 fprintf(stderr, "error: bad component start "
1984 param.fp_check_comp_start = 1;
1985 param.fp_exclude_comp_start = !!neg_opt;
1988 if (optarg[0] == '+') {
1989 param.fp_stripe_count_sign = -1;
1991 } else if (optarg[0] == '-') {
1992 param.fp_stripe_count_sign = 1;
1996 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1997 if (*endptr != '\0') {
1998 fprintf(stderr,"error: bad stripe_count '%s'\n",
2003 param.fp_check_stripe_count = 1;
2004 param.fp_exclude_stripe_count = !!neg_opt;
2007 param.fp_max_depth = strtol(optarg, 0, 0);
2010 if (optarg[0] == '+') {
2011 param.fp_comp_end_sign = -1;
2013 } else if (optarg[0] == '-') {
2014 param.fp_comp_end_sign = 1;
2018 rc = llapi_parse_size(optarg, ¶m.fp_comp_end,
2019 ¶m.fp_comp_end_units, 0);
2021 fprintf(stderr, "error: bad component end "
2025 param.fp_check_comp_end = 1;
2026 param.fp_exclude_comp_end = !!neg_opt;
2030 rc = name2gid(¶m.fp_gid, optarg);
2032 param.fp_gid = strtoul(optarg, &endptr, 10);
2033 if (*endptr != '\0') {
2034 fprintf(stderr, "Group/GID: %s cannot "
2035 "be found.\n", optarg);
2040 param.fp_exclude_gid = !!neg_opt;
2041 param.fp_check_gid = 1;
2044 param.fp_hash_type = check_hashtype(optarg);
2045 if (param.fp_hash_type == 0) {
2046 fprintf(stderr, "error: bad hash_type '%s'\n",
2051 param.fp_check_hash_type = 1;
2052 param.fp_exclude_hash_type = !!neg_opt;
2055 ret = name2layout(¶m.fp_layout, optarg);
2058 param.fp_exclude_layout = !!neg_opt;
2059 param.fp_check_layout = 1;
2063 rc = name2uid(¶m.fp_uid, optarg);
2065 param.fp_uid = strtoul(optarg, &endptr, 10);
2066 if (*endptr != '\0') {
2067 fprintf(stderr, "User/UID: %s cannot "
2068 "be found.\n", optarg);
2073 param.fp_exclude_uid = !!neg_opt;
2074 param.fp_check_uid = 1;
2077 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2079 "Pool name %s is too long"
2080 " (max is %d)\n", optarg,
2085 /* we do check for empty pool because empty pool
2086 * is used to find V1 lov attributes */
2087 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2088 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2089 param.fp_exclude_pool = !!neg_opt;
2090 param.fp_check_pool = 1;
2093 param.fp_pattern = (char *)optarg;
2094 param.fp_exclude_pattern = !!neg_opt;
2099 char *buf, *token, *next, *p;
2103 buf = strdup(optarg);
2109 param.fp_exclude_obd = !!neg_opt;
2112 while (token && *token) {
2113 token = strchr(token, ',');
2120 param.fp_exclude_mdt = !!neg_opt;
2121 param.fp_num_alloc_mdts += len;
2122 tmp = realloc(param.fp_mdt_uuid,
2123 param.fp_num_alloc_mdts *
2124 sizeof(*param.fp_mdt_uuid));
2130 param.fp_mdt_uuid = tmp;
2132 param.fp_exclude_obd = !!neg_opt;
2133 param.fp_num_alloc_obds += len;
2134 tmp = realloc(param.fp_obd_uuid,
2135 param.fp_num_alloc_obds *
2136 sizeof(*param.fp_obd_uuid));
2142 param.fp_obd_uuid = tmp;
2144 for (token = buf; token && *token; token = next) {
2145 struct obd_uuid *puuid;
2148 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2151 ¶m.fp_obd_uuid[param.fp_num_obds++];
2153 p = strchr(token, ',');
2160 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2165 strncpy(puuid->uuid, token,
2166 sizeof(puuid->uuid));
2174 param.fp_zero_end = 1;
2178 case LFS_PROJID_OPT:
2179 rc = name2projid(¶m.fp_projid, optarg);
2181 param.fp_projid = strtoul(optarg, &endptr, 10);
2182 if (*endptr != '\0') {
2184 "Invalid project ID: %s",
2190 param.fp_exclude_projid = !!neg_opt;
2191 param.fp_check_projid = 1;
2194 if (optarg[0] == '+') {
2195 param.fp_size_sign = -1;
2197 } else if (optarg[0] == '-') {
2198 param.fp_size_sign = 1;
2202 ret = llapi_parse_size(optarg, ¶m.fp_size,
2203 ¶m.fp_size_units, 0);
2205 fprintf(stderr, "error: bad file size '%s'\n",
2209 param.fp_check_size = 1;
2210 param.fp_exclude_size = !!neg_opt;
2213 if (optarg[0] == '+') {
2214 param.fp_stripe_size_sign = -1;
2216 } else if (optarg[0] == '-') {
2217 param.fp_stripe_size_sign = 1;
2221 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2222 ¶m.fp_stripe_size_units, 0);
2224 fprintf(stderr, "error: bad stripe_size '%s'\n",
2228 param.fp_check_stripe_size = 1;
2229 param.fp_exclude_stripe_size = !!neg_opt;
2232 param.fp_exclude_type = !!neg_opt;
2233 switch (optarg[0]) {
2235 param.fp_type = S_IFBLK;
2238 param.fp_type = S_IFCHR;
2241 param.fp_type = S_IFDIR;
2244 param.fp_type = S_IFREG;
2247 param.fp_type = S_IFLNK;
2250 param.fp_type = S_IFIFO;
2253 param.fp_type = S_IFSOCK;
2256 fprintf(stderr, "error: %s: bad type '%s'\n",
2263 if (optarg[0] == '+') {
2264 param.fp_mdt_count_sign = -1;
2266 } else if (optarg[0] == '-') {
2267 param.fp_mdt_count_sign = 1;
2271 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2272 if (*endptr != '\0') {
2273 fprintf(stderr, "error: bad mdt_count '%s'\n",
2278 param.fp_check_mdt_count = 1;
2279 param.fp_exclude_mdt_count = !!neg_opt;
2287 if (pathstart == -1) {
2288 fprintf(stderr, "error: %s: no filename|pathname\n",
2292 } else if (pathend == -1) {
2298 rc = llapi_find(argv[pathstart], ¶m);
2299 if (rc != 0 && ret == 0)
2301 } while (++pathstart < pathend);
2304 fprintf(stderr, "error: %s failed for %s.\n",
2305 argv[0], argv[optind - 1]);
2307 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2308 free(param.fp_obd_uuid);
2310 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2311 free(param.fp_mdt_uuid);
2316 static int lfs_getstripe_internal(int argc, char **argv,
2317 struct find_param *param)
2319 struct option long_opts[] = {
2320 {"comp-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2321 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2322 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2323 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2324 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
2325 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
2326 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2327 /* This formerly implied "stripe-count", but was explicitly
2328 * made "stripe-count" for consistency with other options,
2329 * and to separate it from "mdt-count" when DNE arrives. */
2330 {"count", no_argument, 0, 'c'},
2332 {"stripe-count", no_argument, 0, 'c'},
2333 {"stripe_count", no_argument, 0, 'c'},
2334 {"directory", no_argument, 0, 'd'},
2335 {"default", no_argument, 0, 'D'},
2336 {"comp-end", required_argument, 0, 'E'},
2337 {"component-end", required_argument, 0, 'E'},
2338 {"fid", no_argument, 0, 'F'},
2339 {"generation", no_argument, 0, 'g'},
2340 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
2341 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2342 /* This formerly implied "stripe-index", but was explicitly
2343 * made "stripe-index" for consistency with other options,
2344 * and to separate it from "mdt-index" when DNE arrives. */
2345 {"index", no_argument, 0, 'i'},
2347 {"stripe-index", no_argument, 0, 'i'},
2348 {"stripe_index", no_argument, 0, 'i'},
2349 {"comp-id", required_argument, 0, 'I'},
2350 {"component-id", required_argument, 0, 'I'},
2351 {"layout", no_argument, 0, 'L'},
2352 {"mdt", no_argument, 0, 'm'},
2353 {"mdt-index", no_argument, 0, 'm'},
2354 {"mdt_index", no_argument, 0, 'm'},
2355 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2356 {"mdt-index", no_argument, 0, 'M'},
2357 {"mdt_index", no_argument, 0, 'M'},
2359 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2360 /* This formerly implied "stripe-index", but was confusing
2361 * with "file offset" (which will eventually be needed for
2362 * with different layouts by offset), so deprecate it. */
2363 {"offset", no_argument, 0, 'o'},
2365 {"obd", required_argument, 0, 'O'},
2366 {"ost", required_argument, 0, 'O'},
2367 {"pool", no_argument, 0, 'p'},
2368 {"quiet", no_argument, 0, 'q'},
2369 {"recursive", no_argument, 0, 'r'},
2370 {"raw", no_argument, 0, 'R'},
2371 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2372 /* This formerly implied "--stripe-size", but was confusing
2373 * with "lfs find --size|-s", which means "file size", so use
2374 * the consistent "--stripe-size|-S" for all commands. */
2375 {"size", no_argument, 0, 's'},
2377 {"stripe-size", no_argument, 0, 'S'},
2378 {"stripe_size", no_argument, 0, 'S'},
2379 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
2380 {"verbose", no_argument, 0, 'v'},
2386 while ((c = getopt_long(argc, argv, "cdDE:FghiI:LmMoO:pqrRsSv",
2387 long_opts, NULL)) != -1) {
2390 if (strcmp(argv[optind - 1], "--count") == 0)
2391 fprintf(stderr, "warning: '--count' deprecated,"
2392 " use '--stripe-count' instead\n");
2393 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2394 param->fp_verbose |= VERBOSE_COUNT;
2395 param->fp_max_depth = 0;
2398 case LFS_COMP_COUNT_OPT:
2399 param->fp_verbose |= VERBOSE_COMP_COUNT;
2400 param->fp_max_depth = 0;
2402 case LFS_COMP_FLAGS_OPT:
2403 if (optarg != NULL) {
2404 rc = comp_name2flags(¶m->fp_comp_flags,
2407 param->fp_verbose |=
2409 param->fp_max_depth = 0;
2412 param->fp_check_comp_flags = 1;
2415 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2416 param->fp_max_depth = 0;
2419 case LFS_COMP_START_OPT:
2420 if (optarg != NULL) {
2422 if (tmp[0] == '+') {
2423 param->fp_comp_start_sign = 1;
2425 } else if (tmp[0] == '-') {
2426 param->fp_comp_start_sign = -1;
2429 rc = llapi_parse_size(tmp,
2430 ¶m->fp_comp_start,
2431 ¶m->fp_comp_start_units, 0);
2433 param->fp_verbose |= VERBOSE_COMP_START;
2434 param->fp_max_depth = 0;
2437 param->fp_check_comp_start = 1;
2440 param->fp_verbose |= VERBOSE_COMP_START;
2441 param->fp_max_depth = 0;
2445 param->fp_max_depth = 0;
2448 param->fp_get_default_lmv = 1;
2451 if (optarg != NULL) {
2453 if (tmp[0] == '+') {
2454 param->fp_comp_end_sign = 1;
2456 } else if (tmp[0] == '-') {
2457 param->fp_comp_end_sign = -1;
2460 rc = llapi_parse_size(tmp,
2461 ¶m->fp_comp_end,
2462 ¶m->fp_comp_end_units, 0);
2464 param->fp_verbose |= VERBOSE_COMP_END;
2465 param->fp_max_depth = 0;
2468 param->fp_check_comp_end = 1;
2471 param->fp_verbose |= VERBOSE_COMP_END;
2472 param->fp_max_depth = 0;
2476 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2477 param->fp_verbose |= VERBOSE_DFID;
2478 param->fp_max_depth = 0;
2482 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2483 param->fp_verbose |= VERBOSE_GENERATION;
2484 param->fp_max_depth = 0;
2487 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2489 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2490 "use '--stripe-index|-i' instead\n");
2493 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2494 if (strcmp(argv[optind - 1], "--index") == 0)
2495 fprintf(stderr, "warning: '--index' deprecated"
2496 ", use '--stripe-index' instead\n");
2498 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2499 param->fp_verbose |= VERBOSE_OFFSET;
2500 param->fp_max_depth = 0;
2504 if (optarg != NULL) {
2505 param->fp_comp_id = strtoul(optarg, &end, 0);
2507 param->fp_verbose |= VERBOSE_COMP_ID;
2508 param->fp_max_depth = 0;
2511 param->fp_check_comp_id = 1;
2514 param->fp_max_depth = 0;
2515 param->fp_verbose |= VERBOSE_COMP_ID;
2519 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2520 param->fp_verbose |= VERBOSE_LAYOUT;
2521 param->fp_max_depth = 0;
2524 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2526 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2527 fprintf(stderr, "warning: '-M' deprecated"
2528 ", use '-m' instead\n");
2532 if (!(param->fp_verbose & VERBOSE_DETAIL))
2533 param->fp_max_depth = 0;
2534 param->fp_verbose |= VERBOSE_MDTINDEX;
2537 if (param->fp_obd_uuid) {
2539 "error: %s: only one obduuid allowed",
2543 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2546 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2547 param->fp_verbose |= VERBOSE_POOL;
2548 param->fp_max_depth = 0;
2555 param->fp_recursive = 1;
2560 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2562 fprintf(stderr, "warning: '--size|-s' deprecated, "
2563 "use '--stripe-size|-S' instead\n");
2564 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2566 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2567 param->fp_verbose |= VERBOSE_SIZE;
2568 param->fp_max_depth = 0;
2572 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2582 if (param->fp_recursive)
2583 param->fp_max_depth = -1;
2584 else if (param->fp_verbose & VERBOSE_DETAIL)
2585 param->fp_max_depth = 1;
2587 if (!param->fp_verbose)
2588 param->fp_verbose = VERBOSE_DEFAULT;
2589 if (param->fp_quiet)
2590 param->fp_verbose = VERBOSE_OBJID;
2593 rc = llapi_getstripe(argv[optind], param);
2594 } while (++optind < argc && !rc);
2597 fprintf(stderr, "error: %s failed for %s.\n",
2598 argv[0], argv[optind - 1]);
2602 static int lfs_tgts(int argc, char **argv)
2604 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2605 struct find_param param;
2606 int index = 0, rc=0;
2611 if (argc == 2 && !realpath(argv[1], path)) {
2613 fprintf(stderr, "error: invalid path '%s': %s\n",
2614 argv[1], strerror(-rc));
2618 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2619 /* Check if we have a mount point */
2620 if (mntdir[0] == '\0')
2623 memset(¶m, 0, sizeof(param));
2624 if (!strcmp(argv[0], "mdts"))
2625 param.fp_get_lmv = 1;
2627 rc = llapi_ostlist(mntdir, ¶m);
2629 fprintf(stderr, "error: %s: failed on %s\n",
2632 if (path[0] != '\0')
2634 memset(mntdir, 0, PATH_MAX);
2640 static int lfs_getstripe(int argc, char **argv)
2642 struct find_param param = { 0 };
2644 param.fp_max_depth = 1;
2645 return lfs_getstripe_internal(argc, argv, ¶m);
2649 static int lfs_getdirstripe(int argc, char **argv)
2651 struct find_param param = { 0 };
2652 struct option long_opts[] = {
2653 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2654 {"mdt-count", no_argument, 0, 'c'},
2656 {"mdt-hash", no_argument, 0, 'H'},
2657 {"mdt-index", no_argument, 0, 'i'},
2658 {"recursive", no_argument, 0, 'r'},
2659 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2660 {"mdt-hash", no_argument, 0, 't'},
2662 {"default", no_argument, 0, 'D'},
2663 {"obd", required_argument, 0, 'O'},
2664 {"mdt-count", no_argument, 0, 'T'},
2669 param.fp_get_lmv = 1;
2671 while ((c = getopt_long(argc, argv,
2672 "cDHiO:rtT", long_opts, NULL)) != -1)
2676 if (param.fp_obd_uuid) {
2678 "error: %s: only one obduuid allowed",
2682 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2684 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2686 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2687 fprintf(stderr, "warning: '-c' deprecated"
2688 ", use '-T' instead\n");
2692 param.fp_verbose |= VERBOSE_COUNT;
2695 param.fp_verbose |= VERBOSE_OFFSET;
2697 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2701 param.fp_verbose |= VERBOSE_HASH_TYPE;
2704 param.fp_get_default_lmv = 1;
2707 param.fp_recursive = 1;
2717 if (param.fp_recursive)
2718 param.fp_max_depth = -1;
2720 if (!param.fp_verbose)
2721 param.fp_verbose = VERBOSE_DEFAULT;
2724 rc = llapi_getstripe(argv[optind], ¶m);
2725 } while (++optind < argc && !rc);
2728 fprintf(stderr, "error: %s failed for %s.\n",
2729 argv[0], argv[optind - 1]);
2734 static int lfs_setdirstripe(int argc, char **argv)
2738 unsigned int stripe_offset = -1;
2739 unsigned int stripe_count = 1;
2740 enum lmv_hash_type hash_type;
2743 char *stripe_offset_opt = NULL;
2744 char *stripe_count_opt = NULL;
2745 char *stripe_hash_opt = NULL;
2746 char *mode_opt = NULL;
2747 bool default_stripe = false;
2748 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2749 mode_t previous_mode = 0;
2750 bool delete = false;
2752 struct option long_opts[] = {
2753 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2754 {"count", required_argument, 0, 'c'},
2756 {"mdt-count", required_argument, 0, 'c'},
2757 {"delete", no_argument, 0, 'd'},
2758 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2759 {"index", required_argument, 0, 'i'},
2761 {"mdt-index", required_argument, 0, 'i'},
2762 {"mode", required_argument, 0, 'm'},
2763 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2764 {"hash-type", required_argument, 0, 't'},
2765 {"mdt-hash", required_argument, 0, 't'},
2767 {"mdt-hash", required_argument, 0, 'H'},
2768 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2769 {"default_stripe", no_argument, 0, 'D'},
2771 {"default", no_argument, 0, 'D'},
2775 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2782 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2783 if (strcmp(argv[optind - 1], "--count") == 0)
2784 fprintf(stderr, "warning: '--count' deprecated"
2785 ", use '--mdt-count' instead\n");
2787 stripe_count_opt = optarg;
2791 default_stripe = true;
2794 default_stripe = true;
2797 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2798 if (strcmp(argv[optind - 1], "--index") == 0)
2799 fprintf(stderr, "warning: '--index' deprecated"
2800 ", use '--mdt-index' instead\n");
2802 stripe_offset_opt = optarg;
2807 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2811 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2812 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2813 fprintf(stderr, "warning: '--hash-type' "
2814 "deprecated, use '--mdt-hash' "
2817 stripe_hash_opt = optarg;
2820 fprintf(stderr, "error: %s: option '%s' "
2822 argv[0], argv[optind - 1]);
2827 if (optind == argc) {
2828 fprintf(stderr, "error: %s: missing dirname\n",
2833 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2834 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2839 if (stripe_offset_opt != NULL) {
2840 /* get the stripe offset */
2841 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2843 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2844 argv[0], stripe_offset_opt);
2850 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2851 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2852 " or -i options.\n", argv[0]);
2860 if (mode_opt != NULL) {
2861 mode = strtoul(mode_opt, &end, 8);
2863 fprintf(stderr, "error: %s: bad mode '%s'\n",
2867 previous_mode = umask(0);
2870 if (stripe_hash_opt == NULL) {
2871 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2873 hash_type = check_hashtype(stripe_hash_opt);
2874 if (hash_type == 0) {
2876 "error: %s: bad stripe hash type '%s'\n",
2877 argv[0], stripe_hash_opt);
2882 /* get the stripe count */
2883 if (stripe_count_opt != NULL) {
2884 stripe_count = strtoul(stripe_count_opt, &end, 0);
2886 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2887 argv[0], stripe_count_opt);
2892 dname = argv[optind];
2894 if (default_stripe) {
2895 result = llapi_dir_set_default_lmv_stripe(dname,
2896 stripe_offset, stripe_count,
2899 result = llapi_dir_create_pool(dname, mode,
2901 stripe_count, hash_type,
2906 fprintf(stderr, "error: %s: create stripe dir '%s' "
2907 "failed\n", argv[0], dname);
2910 dname = argv[++optind];
2911 } while (dname != NULL);
2913 if (mode_opt != NULL)
2914 umask(previous_mode);
2920 static int lfs_rmentry(int argc, char **argv)
2927 fprintf(stderr, "error: %s: missing dirname\n",
2933 dname = argv[index];
2934 while (dname != NULL) {
2935 result = llapi_direntry_remove(dname);
2937 fprintf(stderr, "error: %s: remove dir entry '%s' "
2938 "failed\n", argv[0], dname);
2941 dname = argv[++index];
2946 static int lfs_mv(int argc, char **argv)
2948 struct find_param param = {
2955 struct option long_opts[] = {
2956 {"mdt-index", required_argument, 0, 'M'},
2957 {"verbose", no_argument, 0, 'v'},
2961 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2964 param.fp_mdt_index = strtoul(optarg, &end, 0);
2966 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2973 param.fp_verbose = VERBOSE_DETAIL;
2977 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2978 argv[0], argv[optind - 1]);
2983 if (param.fp_mdt_index == -1) {
2984 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2988 if (optind >= argc) {
2989 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2993 param.fp_migrate = 1;
2994 rc = llapi_migrate_mdt(argv[optind], ¶m);
2996 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2997 argv[0], argv[optind], param.fp_mdt_index,
3002 static int lfs_osts(int argc, char **argv)
3004 return lfs_tgts(argc, argv);
3007 static int lfs_mdts(int argc, char **argv)
3009 return lfs_tgts(argc, argv);
3012 #define COOK(value) \
3015 while (value > 1024) { \
3023 #define CDF "%11llu"
3024 #define HDF "%8.1f%c"
3029 MNTDF_INODES = 0x0001,
3030 MNTDF_COOKED = 0x0002,
3031 MNTDF_LAZY = 0x0004,
3032 MNTDF_VERBOSE = 0x0008,
3035 static int showdf(char *mntdir, struct obd_statfs *stat,
3036 char *uuid, enum mntdf_flags flags,
3037 char *type, int index, int rc)
3039 long long avail, used, total;
3041 char *suffix = "KMGTPEZY";
3042 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3043 char tbuf[3 * sizeof(__u64)];
3044 char ubuf[3 * sizeof(__u64)];
3045 char abuf[3 * sizeof(__u64)];
3046 char rbuf[3 * sizeof(__u64)];
3053 if (flags & MNTDF_INODES) {
3054 avail = stat->os_ffree;
3055 used = stat->os_files - stat->os_ffree;
3056 total = stat->os_files;
3058 int shift = flags & MNTDF_COOKED ? 0 : 10;
3060 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3061 used = ((stat->os_blocks - stat->os_bfree) *
3062 stat->os_bsize) >> shift;
3063 total = (stat->os_blocks * stat->os_bsize) >> shift;
3066 if ((used + avail) > 0)
3067 ratio = (double)used / (double)(used + avail);
3069 if (flags & MNTDF_COOKED) {
3073 cook_val = (double)total;
3076 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3079 snprintf(tbuf, sizeof(tbuf), CDF, total);
3081 cook_val = (double)used;
3084 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3087 snprintf(ubuf, sizeof(ubuf), CDF, used);
3089 cook_val = (double)avail;
3092 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3095 snprintf(abuf, sizeof(abuf), CDF, avail);
3097 snprintf(tbuf, sizeof(tbuf), CDF, total);
3098 snprintf(ubuf, sizeof(tbuf), CDF, used);
3099 snprintf(abuf, sizeof(tbuf), CDF, avail);
3102 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3103 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3104 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3106 printf("[%s:%d]", type, index);
3108 if (stat->os_state) {
3110 * Each character represents the matching
3113 const char state_names[] = "DRSI";
3118 for (i = 0, state = stat->os_state;
3119 state && i < sizeof(state_names); i++) {
3120 if (!(state & (1 << i)))
3122 printf("%c", state_names[i]);
3130 printf(UUF": inactive device\n", uuid);
3133 printf(UUF": %s\n", uuid, strerror(-rc));
3140 struct ll_stat_type {
3145 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3147 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3148 struct obd_uuid uuid_buf;
3149 char *poolname = NULL;
3150 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3151 { LL_STATFS_LOV, "OST" },
3153 struct ll_stat_type *tp;
3154 __u64 ost_ffree = 0;
3162 poolname = strchr(pool, '.');
3163 if (poolname != NULL) {
3164 if (strncmp(fsname, pool, strlen(fsname))) {
3165 fprintf(stderr, "filesystem name incorrect\n");
3173 fd = open(mntdir, O_RDONLY);
3176 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3181 if (flags & MNTDF_INODES)
3182 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3183 "UUID", "Inodes", "IUsed", "IFree",
3184 "IUse%", "Mounted on");
3186 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3187 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3188 "Used", "Available", "Use%", "Mounted on");
3190 for (tp = types; tp->st_name != NULL; tp++) {
3191 for (index = 0; ; index++) {
3192 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3193 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3194 type = flags & MNTDF_LAZY ?
3195 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3196 rc2 = llapi_obd_fstatfs(fd, type, index,
3197 &stat_buf, &uuid_buf);
3202 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3203 if (!(flags & MNTDF_VERBOSE))
3205 } else if (rc2 < 0 && rc == 0) {
3209 if (poolname && tp->st_op == LL_STATFS_LOV &&
3210 llapi_search_ost(fsname, poolname,
3211 obd_uuid2str(&uuid_buf)) != 1)
3214 /* the llapi_obd_statfs() call may have returned with
3215 * an error, but if it filled in uuid_buf we will at
3216 * lease use that to print out a message for that OBD.
3217 * If we didn't get anything in the uuid_buf, then fill
3218 * it in so that we can print an error message. */
3219 if (uuid_buf.uuid[0] == '\0')
3220 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3221 "%s%04x", tp->st_name, index);
3222 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3223 flags, tp->st_name, index, rc2);
3226 if (tp->st_op == LL_STATFS_LMV) {
3227 sum.os_ffree += stat_buf.os_ffree;
3228 sum.os_files += stat_buf.os_files;
3229 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3230 sum.os_blocks += stat_buf.os_blocks *
3232 sum.os_bfree += stat_buf.os_bfree *
3234 sum.os_bavail += stat_buf.os_bavail *
3236 ost_ffree += stat_buf.os_ffree;
3244 /* If we don't have as many objects free on the OST as inodes
3245 * on the MDS, we reduce the total number of inodes to
3246 * compensate, so that the "inodes in use" number is correct.
3247 * Matches ll_statfs_internal() so the results are consistent. */
3248 if (ost_ffree < sum.os_ffree) {
3249 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3250 sum.os_ffree = ost_ffree;
3253 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3259 static int lfs_df(int argc, char **argv)
3261 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3262 enum mntdf_flags flags = 0;
3263 int c, rc = 0, index = 0;
3264 char fsname[PATH_MAX] = "", *pool_name = NULL;
3265 struct option long_opts[] = {
3266 {"human-readable", 0, 0, 'h'},
3267 {"inodes", 0, 0, 'i'},
3268 {"lazy", 0, 0, 'l'},
3269 {"pool", required_argument, 0, 'p'},
3270 {"verbose", 0, 0, 'v'},
3274 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3277 flags |= MNTDF_COOKED;
3280 flags |= MNTDF_INODES;
3283 flags |= MNTDF_LAZY;
3289 flags |= MNTDF_VERBOSE;
3295 if (optind < argc && !realpath(argv[optind], path)) {
3297 fprintf(stderr, "error: invalid path '%s': %s\n",
3298 argv[optind], strerror(-rc));
3302 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3303 /* Check if we have a mount point */
3304 if (mntdir[0] == '\0')
3307 rc = mntdf(mntdir, fsname, pool_name, flags);
3308 if (rc || path[0] != '\0')
3310 fsname[0] = '\0'; /* avoid matching in next loop */
3311 mntdir[0] = '\0'; /* avoid matching in next loop */
3317 static int lfs_getname(int argc, char **argv)
3319 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3320 int rc = 0, index = 0, c;
3321 char buf[sizeof(struct obd_uuid)];
3323 while ((c = getopt(argc, argv, "h")) != -1)
3326 if (optind == argc) { /* no paths specified, get all paths. */
3327 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3328 rc = llapi_getname(mntdir, buf, sizeof(buf));
3331 "cannot get name for `%s': %s\n",
3332 mntdir, strerror(-rc));
3336 printf("%s %s\n", buf, mntdir);
3338 path[0] = fsname[0] = mntdir[0] = 0;
3340 } else { /* paths specified, only attempt to search these. */
3341 for (; optind < argc; optind++) {
3342 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3345 "cannot get name for `%s': %s\n",
3346 argv[optind], strerror(-rc));
3350 printf("%s %s\n", buf, argv[optind]);
3356 static int lfs_check(int argc, char **argv)
3359 char mntdir[PATH_MAX] = {'\0'};
3368 obd_types[0] = obd_type1;
3369 obd_types[1] = obd_type2;
3371 if (strcmp(argv[1], "osts") == 0) {
3372 strcpy(obd_types[0], "osc");
3373 } else if (strcmp(argv[1], "mds") == 0) {
3374 strcpy(obd_types[0], "mdc");
3375 } else if (strcmp(argv[1], "servers") == 0) {
3377 strcpy(obd_types[0], "osc");
3378 strcpy(obd_types[1], "mdc");
3380 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3385 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3386 if (rc < 0 || mntdir[0] == '\0') {
3387 fprintf(stderr, "No suitable Lustre mount found\n");
3391 rc = llapi_target_check(num_types, obd_types, mntdir);
3393 fprintf(stderr, "error: %s: %s status failed\n",
3400 #ifdef HAVE_SYS_QUOTA_H
3401 #define ARG2INT(nr, str, msg) \
3404 nr = strtol(str, &endp, 0); \
3406 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3411 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3413 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3414 * returns the value or ULONG_MAX on integer overflow or incorrect format
3416 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3417 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3418 * 3. empty integer value is interpreted as 0
3420 static unsigned long str2sec(const char* timestr)
3422 const char spec[] = "smhdw";
3423 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3424 unsigned long val = 0;
3427 if (strpbrk(timestr, spec) == NULL) {
3428 /* no specifiers inside the time string,
3429 should treat it as an integer value */
3430 val = strtoul(timestr, &tail, 10);
3431 return *tail ? ULONG_MAX : val;
3434 /* format string is XXwXXdXXhXXmXXs */
3440 v = strtoul(timestr, &tail, 10);
3441 if (v == ULONG_MAX || *tail == '\0')
3442 /* value too large (ULONG_MAX or more)
3443 or missing specifier */
3446 ptr = strchr(spec, *tail);
3448 /* unknown specifier */
3453 /* check if product will overflow the type */
3454 if (!(v < ULONG_MAX / mult[ind]))
3457 ADD_OVERFLOW(val, mult[ind] * v);
3458 if (val == ULONG_MAX)
3470 #define ARG2ULL(nr, str, def_units) \
3472 unsigned long long limit, units = def_units; \
3475 rc = llapi_parse_size(str, &limit, &units, 1); \
3477 fprintf(stderr, "error: bad limit value %s\n", str); \
3483 static inline int has_times_option(int argc, char **argv)
3487 for (i = 1; i < argc; i++)
3488 if (!strcmp(argv[i], "-t"))
3494 int lfs_setquota_times(int argc, char **argv)
3497 struct if_quotactl qctl;
3498 char *mnt, *obd_type = (char *)qctl.obd_type;
3499 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3500 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3501 struct option long_opts[] = {
3502 {"block-grace", required_argument, 0, 'b'},
3503 {"group", no_argument, 0, 'g'},
3504 {"inode-grace", required_argument, 0, 'i'},
3505 {"project", no_argument, 0, 'p'},
3506 {"times", no_argument, 0, 't'},
3507 {"user", no_argument, 0, 'u'},
3512 memset(&qctl, 0, sizeof(qctl));
3513 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3514 qctl.qc_type = ALLQUOTA;
3516 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3517 long_opts, NULL)) != -1) {
3528 if (qctl.qc_type != ALLQUOTA) {
3529 fprintf(stderr, "error: -u/g/p can't be used "
3530 "more than once\n");
3533 qctl.qc_type = qtype;
3536 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3537 fprintf(stderr, "error: bad block-grace: %s\n",
3541 dqb->dqb_valid |= QIF_BTIME;
3544 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3545 fprintf(stderr, "error: bad inode-grace: %s\n",
3549 dqb->dqb_valid |= QIF_ITIME;
3551 case 't': /* Yes, of course! */
3553 default: /* getopt prints error message for us when opterr != 0 */
3558 if (qctl.qc_type == ALLQUOTA) {
3559 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3563 if (optind != argc - 1) {
3564 fprintf(stderr, "error: unexpected parameters encountered\n");
3569 rc = llapi_quotactl(mnt, &qctl);
3572 fprintf(stderr, "%s %s ", obd_type,
3573 obd_uuid2str(&qctl.obd_uuid));
3574 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3581 #define BSLIMIT (1 << 0)
3582 #define BHLIMIT (1 << 1)
3583 #define ISLIMIT (1 << 2)
3584 #define IHLIMIT (1 << 3)
3586 int lfs_setquota(int argc, char **argv)
3589 struct if_quotactl qctl;
3590 char *mnt, *obd_type = (char *)qctl.obd_type;
3591 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3592 struct option long_opts[] = {
3593 {"block-softlimit", required_argument, 0, 'b'},
3594 {"block-hardlimit", required_argument, 0, 'B'},
3595 {"group", required_argument, 0, 'g'},
3596 {"inode-softlimit", required_argument, 0, 'i'},
3597 {"inode-hardlimit", required_argument, 0, 'I'},
3598 {"user", required_argument, 0, 'u'},
3599 {"project", required_argument, 0, 'p'},
3602 unsigned limit_mask = 0;
3606 if (has_times_option(argc, argv))
3607 return lfs_setquota_times(argc, argv);
3609 memset(&qctl, 0, sizeof(qctl));
3610 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3611 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3612 * so it can be used as a marker that qc_type
3613 * isn't reinitialized from command line */
3615 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3616 long_opts, NULL)) != -1) {
3620 rc = name2uid(&qctl.qc_id, optarg);
3624 rc = name2gid(&qctl.qc_id, optarg);
3628 rc = name2projid(&qctl.qc_id, optarg);
3630 if (qctl.qc_type != ALLQUOTA) {
3631 fprintf(stderr, "error: -u and -g can't be used"
3632 " more than once\n");
3635 qctl.qc_type = qtype;
3637 qctl.qc_id = strtoul(optarg, &endptr, 10);
3638 if (*endptr != '\0') {
3639 fprintf(stderr, "error: can't find id "
3640 "for name %s\n", optarg);
3646 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3647 dqb->dqb_bsoftlimit >>= 10;
3648 limit_mask |= BSLIMIT;
3649 if (dqb->dqb_bsoftlimit &&
3650 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3651 fprintf(stderr, "warning: block softlimit is "
3652 "smaller than the miminal qunit size, "
3653 "please see the help of setquota or "
3654 "Lustre manual for details.\n");
3657 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3658 dqb->dqb_bhardlimit >>= 10;
3659 limit_mask |= BHLIMIT;
3660 if (dqb->dqb_bhardlimit &&
3661 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3662 fprintf(stderr, "warning: block hardlimit is "
3663 "smaller than the miminal qunit size, "
3664 "please see the help of setquota or "
3665 "Lustre manual for details.\n");
3668 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3669 limit_mask |= ISLIMIT;
3670 if (dqb->dqb_isoftlimit &&
3671 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3672 fprintf(stderr, "warning: inode softlimit is "
3673 "smaller than the miminal qunit size, "
3674 "please see the help of setquota or "
3675 "Lustre manual for details.\n");
3678 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3679 limit_mask |= IHLIMIT;
3680 if (dqb->dqb_ihardlimit &&
3681 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3682 fprintf(stderr, "warning: inode hardlimit is "
3683 "smaller than the miminal qunit size, "
3684 "please see the help of setquota or "
3685 "Lustre manual for details.\n");
3687 default: /* getopt prints error message for us when opterr != 0 */
3692 if (qctl.qc_type == ALLQUOTA) {
3693 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3697 if (limit_mask == 0) {
3698 fprintf(stderr, "error: at least one limit must be specified\n");
3702 if (optind != argc - 1) {
3703 fprintf(stderr, "error: unexpected parameters encountered\n");
3709 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3710 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3711 /* sigh, we can't just set blimits/ilimits */
3712 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3713 .qc_type = qctl.qc_type,
3714 .qc_id = qctl.qc_id};
3716 rc = llapi_quotactl(mnt, &tmp_qctl);
3718 fprintf(stderr, "error: setquota failed while retrieving"
3719 " current quota settings (%s)\n",
3724 if (!(limit_mask & BHLIMIT))
3725 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3726 if (!(limit_mask & BSLIMIT))
3727 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3728 if (!(limit_mask & IHLIMIT))
3729 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3730 if (!(limit_mask & ISLIMIT))
3731 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3733 /* Keep grace times if we have got no softlimit arguments */
3734 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3735 dqb->dqb_valid |= QIF_BTIME;
3736 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3739 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3740 dqb->dqb_valid |= QIF_ITIME;
3741 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3745 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3746 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3748 rc = llapi_quotactl(mnt, &qctl);
3751 fprintf(stderr, "%s %s ", obd_type,
3752 obd_uuid2str(&qctl.obd_uuid));
3753 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3760 /* Converts seconds value into format string
3761 * result is returned in buf
3763 * 1. result is in descenting order: 1w2d3h4m5s
3764 * 2. zero fields are not filled (except for p. 3): 5d1s
3765 * 3. zero seconds value is presented as "0s"
3767 static char * __sec2str(time_t seconds, char *buf)
3769 const char spec[] = "smhdw";
3770 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3775 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3776 c = seconds / mult[i];
3778 if (c > 0 || (i == 0 && buf == tail))
3779 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3787 static void sec2str(time_t seconds, char *buf, int rc)
3794 tail = __sec2str(seconds, tail);
3796 if (rc && tail - buf < 39) {
3802 static void diff2str(time_t seconds, char *buf, time_t now)
3808 if (seconds <= now) {
3809 strcpy(buf, "none");
3812 __sec2str(seconds - now, buf);
3815 static void print_quota_title(char *name, struct if_quotactl *qctl,
3816 bool human_readable)
3818 printf("Disk quotas for %s %s (%cid %u):\n",
3819 qtype_name(qctl->qc_type), name,
3820 *qtype_name(qctl->qc_type), qctl->qc_id);
3821 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3822 "Filesystem", human_readable ? "used" : "kbytes",
3823 "quota", "limit", "grace",
3824 "files", "quota", "limit", "grace");
3827 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3830 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3833 snprintf(buf, buflen, "%5.4gP",
3834 (double)num / ((__u64)1 << 40));
3836 snprintf(buf, buflen, "%5.4gT",
3837 (double)num / (1 << 30));
3839 snprintf(buf, buflen, "%5.4gG",
3840 (double)num / (1 << 20));
3842 snprintf(buf, buflen, "%5.4gM",
3843 (double)num / (1 << 10));
3845 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3849 #define STRBUF_LEN 32
3850 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3857 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3858 int bover = 0, iover = 0;
3859 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3860 char numbuf[3][STRBUF_LEN];
3862 char strbuf[STRBUF_LEN];
3864 if (dqb->dqb_bhardlimit &&
3865 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3867 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3868 if (dqb->dqb_btime > now) {
3875 if (dqb->dqb_ihardlimit &&
3876 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3878 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3879 if (dqb->dqb_itime > now) {
3887 if (strlen(mnt) > 15)
3888 printf("%s\n%15s", mnt, "");
3890 printf("%15s", mnt);
3893 diff2str(dqb->dqb_btime, timebuf, now);
3895 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3896 strbuf, sizeof(strbuf), h);
3897 if (rc == -EREMOTEIO)
3898 sprintf(numbuf[0], "%s*", strbuf);
3900 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3901 "%s" : "[%s]", strbuf);
3903 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3904 if (type == QC_GENERAL)
3905 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3906 "%s" : "[%s]", strbuf);
3908 sprintf(numbuf[1], "%s", "-");
3910 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3911 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3912 "%s" : "[%s]", strbuf);
3914 printf(" %7s%c %6s %7s %7s",
3915 numbuf[0], bover ? '*' : ' ', numbuf[1],
3916 numbuf[2], bover > 1 ? timebuf : "-");
3919 diff2str(dqb->dqb_itime, timebuf, now);
3921 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3922 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3924 if (type == QC_GENERAL)
3925 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3927 (uintmax_t)dqb->dqb_isoftlimit);
3929 sprintf(numbuf[1], "%s", "-");
3931 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3932 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3934 if (type != QC_OSTIDX)
3935 printf(" %7s%c %6s %7s %7s",
3936 numbuf[0], iover ? '*' : ' ', numbuf[1],
3937 numbuf[2], iover > 1 ? timebuf : "-");
3939 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3942 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3943 qctl->qc_cmd == Q_GETOINFO) {
3947 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3948 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3949 printf("Block grace time: %s; Inode grace time: %s\n",
3950 bgtimebuf, igtimebuf);
3954 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3955 bool h, __u64 *total)
3957 int rc = 0, rc1 = 0, count = 0;
3958 __u32 valid = qctl->qc_valid;
3960 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3962 fprintf(stderr, "can not get %s count: %s\n",
3963 is_mdt ? "mdt": "ost", strerror(-rc));
3967 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3968 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3969 rc = llapi_quotactl(mnt, qctl);
3971 /* It is remote client case. */
3972 if (rc == -EOPNOTSUPP) {
3979 fprintf(stderr, "quotactl %s%d failed.\n",
3980 is_mdt ? "mdt": "ost", qctl->qc_idx);
3984 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3985 qctl->qc_valid, 0, h);
3986 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3987 qctl->qc_dqblk.dqb_bhardlimit;
3990 qctl->qc_valid = valid;
3994 static int lfs_quota(int argc, char **argv)
3997 char *mnt, *name = NULL;
3998 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3999 .qc_type = ALLQUOTA };
4000 char *obd_type = (char *)qctl.obd_type;
4001 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4002 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4003 verbose = 0, pass = 0, quiet = 0, inacc;
4005 __u32 valid = QC_GENERAL, idx = 0;
4006 __u64 total_ialloc = 0, total_balloc = 0;
4007 bool human_readable = false;
4010 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4021 if (qctl.qc_type != ALLQUOTA) {
4022 fprintf(stderr, "error: use either -u or -g\n");
4025 qctl.qc_type = qtype;
4028 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4031 valid = qctl.qc_valid = QC_UUID;
4032 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4035 valid = qctl.qc_valid = QC_MDTIDX;
4036 idx = qctl.qc_idx = atoi(optarg);
4039 valid = qctl.qc_valid = QC_OSTIDX;
4040 idx = qctl.qc_idx = atoi(optarg);
4049 human_readable = true;
4052 fprintf(stderr, "error: %s: option '-%c' "
4053 "unrecognized\n", argv[0], c);
4058 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4059 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4060 optind == argc - 1) {
4062 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4063 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4064 qctl.qc_valid = valid;
4066 qctl.qc_type = pass;
4067 switch (qctl.qc_type) {
4069 qctl.qc_id = geteuid();
4070 rc = uid2name(&name, qctl.qc_id);
4073 qctl.qc_id = getegid();
4074 rc = gid2name(&name, qctl.qc_id);
4083 /* lfs quota -u username /path/to/lustre/mount */
4084 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4085 /* options should be followed by u/g-name and mntpoint */
4086 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4087 fprintf(stderr, "error: missing quota argument(s)\n");
4091 name = argv[optind++];
4092 switch (qctl.qc_type) {
4094 rc = name2uid(&qctl.qc_id, name);
4097 rc = name2gid(&qctl.qc_id, name);
4100 rc = name2projid(&qctl.qc_id, name);
4107 qctl.qc_id = strtoul(name, &endptr, 10);
4108 if (*endptr != '\0') {
4109 fprintf(stderr, "error: can't find id for name "
4114 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4115 fprintf(stderr, "error: missing quota info argument(s)\n");
4121 rc1 = llapi_quotactl(mnt, &qctl);
4125 fprintf(stderr, "%s quotas are not enabled.\n",
4126 qtype_name(qctl.qc_type));
4129 fprintf(stderr, "Permission denied.\n");
4132 /* We already got error message. */
4135 fprintf(stderr, "Unexpected quotactl error: %s\n",
4140 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4141 print_quota_title(name, &qctl, human_readable);
4143 if (rc1 && *obd_type)
4144 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4146 if (qctl.qc_valid != QC_GENERAL)
4149 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4150 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4151 (QIF_LIMITS|QIF_USAGE));
4153 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4155 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4157 char strbuf[STRBUF_LEN];
4159 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4161 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4163 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4165 printf("Total allocated inode limit: %ju, total "
4166 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4170 if (rc1 || rc2 || rc3 || inacc)
4171 printf("Some errors happened when getting quota info. "
4172 "Some devices may be not working or deactivated. "
4173 "The data in \"[]\" is inaccurate.\n");
4176 if (pass > 0 && pass < LL_MAXQUOTAS)
4181 #endif /* HAVE_SYS_QUOTA_H! */
4183 static int flushctx_ioctl(char *mp)
4187 fd = open(mp, O_RDONLY);
4189 fprintf(stderr, "flushctx: error open %s: %s\n",
4190 mp, strerror(errno));
4194 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4196 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4197 mp, strerror(errno));
4203 static int lfs_flushctx(int argc, char **argv)
4205 int kdestroy = 0, c;
4206 char mntdir[PATH_MAX] = {'\0'};
4210 while ((c = getopt(argc, argv, "k")) != -1) {
4216 fprintf(stderr, "error: %s: option '-%c' "
4217 "unrecognized\n", argv[0], c);
4223 if ((rc = system("kdestroy > /dev/null")) != 0) {
4224 rc = WEXITSTATUS(rc);
4225 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4229 if (optind >= argc) {
4230 /* flush for all mounted lustre fs. */
4231 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4232 /* Check if we have a mount point */
4233 if (mntdir[0] == '\0')
4236 if (flushctx_ioctl(mntdir))
4239 mntdir[0] = '\0'; /* avoid matching in next loop */
4242 /* flush fs as specified */
4243 while (optind < argc) {
4244 if (flushctx_ioctl(argv[optind++]))
4251 static int lfs_cp(int argc, char **argv)
4253 fprintf(stderr, "remote client copy file(s).\n"
4254 "obsolete, does not support it anymore.\n");
4258 static int lfs_ls(int argc, char **argv)
4260 fprintf(stderr, "remote client lists directory contents.\n"
4261 "obsolete, does not support it anymore.\n");
4265 static int lfs_changelog(int argc, char **argv)
4267 void *changelog_priv;
4268 struct changelog_rec *rec;
4269 long long startrec = 0, endrec = 0;
4271 struct option long_opts[] = {
4272 {"follow", no_argument, 0, 'f'},
4275 char short_opts[] = "f";
4278 while ((rc = getopt_long(argc, argv, short_opts,
4279 long_opts, NULL)) != -1) {
4287 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4288 argv[0], argv[optind - 1]);
4295 mdd = argv[optind++];
4297 startrec = strtoll(argv[optind++], NULL, 10);
4299 endrec = strtoll(argv[optind++], NULL, 10);
4301 rc = llapi_changelog_start(&changelog_priv,
4302 CHANGELOG_FLAG_BLOCK |
4303 CHANGELOG_FLAG_JOBID |
4304 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4307 fprintf(stderr, "Can't start changelog: %s\n",
4308 strerror(errno = -rc));
4312 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4316 if (endrec && rec->cr_index > endrec) {
4317 llapi_changelog_free(&rec);
4320 if (rec->cr_index < startrec) {
4321 llapi_changelog_free(&rec);
4325 secs = rec->cr_time >> 30;
4326 gmtime_r(&secs, &ts);
4327 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
4328 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
4329 changelog_type2str(rec->cr_type),
4330 ts.tm_hour, ts.tm_min, ts.tm_sec,
4331 (int)(rec->cr_time & ((1<<30) - 1)),
4332 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4333 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4335 if (rec->cr_flags & CLF_JOBID) {
4336 struct changelog_ext_jobid *jid =
4337 changelog_rec_jobid(rec);
4339 if (jid->cr_jobid[0] != '\0')
4340 printf(" j=%s", jid->cr_jobid);
4343 if (rec->cr_namelen)
4344 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4345 rec->cr_namelen, changelog_rec_name(rec));
4347 if (rec->cr_flags & CLF_RENAME) {
4348 struct changelog_ext_rename *rnm =
4349 changelog_rec_rename(rec);
4351 if (!fid_is_zero(&rnm->cr_sfid))
4352 printf(" s="DFID" sp="DFID" %.*s",
4353 PFID(&rnm->cr_sfid),
4354 PFID(&rnm->cr_spfid),
4355 (int)changelog_rec_snamelen(rec),
4356 changelog_rec_sname(rec));
4360 llapi_changelog_free(&rec);
4363 llapi_changelog_fini(&changelog_priv);
4366 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4368 return (rc == 1 ? 0 : rc);
4371 static int lfs_changelog_clear(int argc, char **argv)
4379 endrec = strtoll(argv[3], NULL, 10);
4381 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4384 fprintf(stderr, "%s: record out of range: %llu\n",
4386 else if (rc == -ENOENT)
4387 fprintf(stderr, "%s: no changelog user: %s\n",
4390 fprintf(stderr, "%s error: %s\n", argv[0],
4399 static int lfs_fid2path(int argc, char **argv)
4401 struct option long_opts[] = {
4402 {"cur", no_argument, 0, 'c'},
4403 {"link", required_argument, 0, 'l'},
4404 {"rec", required_argument, 0, 'r'},
4407 char short_opts[] = "cl:r:";
4408 char *device, *fid, *path;
4409 long long recno = -1;
4415 while ((rc = getopt_long(argc, argv, short_opts,
4416 long_opts, NULL)) != -1) {
4422 linkno = strtol(optarg, NULL, 10);
4425 recno = strtoll(optarg, NULL, 10);
4430 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4431 argv[0], argv[optind - 1]);
4439 device = argv[optind++];
4440 path = calloc(1, PATH_MAX);
4442 fprintf(stderr, "error: Not enough memory\n");
4447 while (optind < argc) {
4448 fid = argv[optind++];
4450 lnktmp = (linkno >= 0) ? linkno : 0;
4452 int oldtmp = lnktmp;
4453 long long rectmp = recno;
4455 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4458 fprintf(stderr, "%s: error on FID %s: %s\n",
4459 argv[0], fid, strerror(errno = -rc2));
4466 fprintf(stdout, "%lld ", rectmp);
4467 if (device[0] == '/') {
4468 fprintf(stdout, "%s", device);
4469 if (device[strlen(device) - 1] != '/')
4470 fprintf(stdout, "/");
4471 } else if (path[0] == '\0') {
4472 fprintf(stdout, "/");
4474 fprintf(stdout, "%s\n", path);
4477 /* specified linkno */
4479 if (oldtmp == lnktmp)
4489 static int lfs_path2fid(int argc, char **argv)
4491 struct option long_opts[] = {
4492 {"parents", no_argument, 0, 'p'},
4496 const char short_opts[] = "p";
4497 const char *sep = "";
4500 bool show_parents = false;
4502 while ((rc = getopt_long(argc, argv, short_opts,
4503 long_opts, NULL)) != -1) {
4506 show_parents = true;
4509 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4510 argv[0], argv[optind - 1]);
4515 if (optind > argc - 1)
4517 else if (optind < argc - 1)
4521 for (path = argv + optind; *path != NULL; path++) {
4523 if (!show_parents) {
4524 err = llapi_path2fid(*path, &fid);
4526 printf("%s%s"DFID"\n",
4527 *sep != '\0' ? *path : "", sep,
4530 char name[NAME_MAX + 1];
4531 unsigned int linkno = 0;
4533 while ((err = llapi_path2parent(*path, linkno, &fid,
4534 name, sizeof(name))) == 0) {
4535 if (*sep != '\0' && linkno == 0)
4536 printf("%s%s", *path, sep);
4538 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4543 /* err == -ENODATA is end-of-loop */
4544 if (linkno > 0 && err == -ENODATA) {
4551 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4552 argv[0], show_parents ? "parent " : "", *path,
4564 static int lfs_data_version(int argc, char **argv)
4571 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4576 while ((c = getopt(argc, argv, "nrw")) != -1) {
4579 data_version_flags = 0;
4582 data_version_flags |= LL_DV_RD_FLUSH;
4585 data_version_flags |= LL_DV_WR_FLUSH;
4594 path = argv[optind];
4595 fd = open(path, O_RDONLY);
4597 err(errno, "cannot open file %s", path);
4599 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4601 err(errno, "cannot get version for %s", path);
4603 printf("%ju" "\n", (uintmax_t)data_version);
4609 static int lfs_hsm_state(int argc, char **argv)
4614 struct hsm_user_state hus;
4622 rc = llapi_hsm_state_get(path, &hus);
4624 fprintf(stderr, "can't get hsm state for %s: %s\n",
4625 path, strerror(errno = -rc));
4629 /* Display path name and status flags */
4630 printf("%s: (0x%08x)", path, hus.hus_states);
4632 if (hus.hus_states & HS_RELEASED)
4633 printf(" released");
4634 if (hus.hus_states & HS_EXISTS)
4636 if (hus.hus_states & HS_DIRTY)
4638 if (hus.hus_states & HS_ARCHIVED)
4639 printf(" archived");
4640 /* Display user-settable flags */
4641 if (hus.hus_states & HS_NORELEASE)
4642 printf(" never_release");
4643 if (hus.hus_states & HS_NOARCHIVE)
4644 printf(" never_archive");
4645 if (hus.hus_states & HS_LOST)
4646 printf(" lost_from_hsm");
4648 if (hus.hus_archive_id != 0)
4649 printf(", archive_id:%d", hus.hus_archive_id);
4652 } while (++i < argc);
4657 #define LFS_HSM_SET 0
4658 #define LFS_HSM_CLEAR 1
4661 * Generic function to set or clear HSM flags.
4662 * Used by hsm_set and hsm_clear.
4664 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4666 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4668 struct option long_opts[] = {
4669 {"lost", 0, 0, 'l'},
4670 {"norelease", 0, 0, 'r'},
4671 {"noarchive", 0, 0, 'a'},
4672 {"archived", 0, 0, 'A'},
4673 {"dirty", 0, 0, 'd'},
4674 {"exists", 0, 0, 'e'},
4677 char short_opts[] = "lraAde";
4685 while ((c = getopt_long(argc, argv, short_opts,
4686 long_opts, NULL)) != -1) {
4692 mask |= HS_NOARCHIVE;
4695 mask |= HS_ARCHIVED;
4698 mask |= HS_NORELEASE;
4709 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4710 argv[0], argv[optind - 1]);
4715 /* User should have specified a flag */
4719 while (optind < argc) {
4721 path = argv[optind];
4723 /* If mode == 0, this means we apply the mask. */
4724 if (mode == LFS_HSM_SET)
4725 rc = llapi_hsm_state_set(path, mask, 0, 0);
4727 rc = llapi_hsm_state_set(path, 0, mask, 0);
4730 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4731 path, strerror(errno = -rc));
4740 static int lfs_hsm_action(int argc, char **argv)
4745 struct hsm_current_action hca;
4746 struct hsm_extent he;
4747 enum hsm_user_action hua;
4748 enum hsm_progress_states hps;
4756 rc = llapi_hsm_current_action(path, &hca);
4758 fprintf(stderr, "can't get hsm action for %s: %s\n",
4759 path, strerror(errno = -rc));
4762 he = hca.hca_location;
4763 hua = hca.hca_action;
4764 hps = hca.hca_state;
4766 printf("%s: %s", path, hsm_user_action2name(hua));
4768 /* Skip file without action */
4769 if (hca.hca_action == HUA_NONE) {
4774 printf(" %s ", hsm_progress_state2name(hps));
4776 if ((hps == HPS_RUNNING) &&
4777 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4778 printf("(%llu bytes moved)\n",
4779 (unsigned long long)he.length);
4780 else if ((he.offset + he.length) == LUSTRE_EOF)
4781 printf("(from %llu to EOF)\n",
4782 (unsigned long long)he.offset);
4784 printf("(from %llu to %llu)\n",
4785 (unsigned long long)he.offset,
4786 (unsigned long long)(he.offset + he.length));
4788 } while (++i < argc);
4793 static int lfs_hsm_set(int argc, char **argv)
4795 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4798 static int lfs_hsm_clear(int argc, char **argv)
4800 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4804 * Check file state and return its fid, to be used by lfs_hsm_request().
4806 * \param[in] file Path to file to check
4807 * \param[in,out] fid Pointer to allocated lu_fid struct.
4808 * \param[in,out] last_dev Pointer to last device id used.
4810 * \return 0 on success.
4812 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4818 rc = lstat(file, &st);
4820 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4823 /* Checking for regular file as archiving as posix copytool
4824 * rejects archiving files other than regular files
4826 if (!S_ISREG(st.st_mode)) {
4827 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4830 /* A request should be ... */
4831 if (*last_dev != st.st_dev && *last_dev != 0) {
4832 fprintf(stderr, "All files should be "
4833 "on the same filesystem: %s\n", file);
4836 *last_dev = st.st_dev;
4838 rc = llapi_path2fid(file, fid);
4840 fprintf(stderr, "Cannot read FID of %s: %s\n",
4841 file, strerror(-rc));
4847 /* Fill an HSM HUR item with a given file name.
4849 * If mntpath is set, then the filename is actually a FID, and no
4850 * lookup on the filesystem will be performed.
4852 * \param[in] hur the user request to fill
4853 * \param[in] idx index of the item inside the HUR to fill
4854 * \param[in] mntpath mountpoint of Lustre
4855 * \param[in] fname filename (if mtnpath is NULL)
4856 * or FID (if mntpath is set)
4857 * \param[in] last_dev pointer to last device id used
4859 * \retval 0 on success
4860 * \retval CMD_HELP or a negative errno on error
4862 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4863 const char *mntpath, const char *fname,
4866 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4869 hui->hui_extent.length = -1;
4871 if (mntpath != NULL) {
4874 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4878 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4883 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4887 hur->hur_request.hr_itemcount++;
4892 static int lfs_hsm_request(int argc, char **argv, int action)
4894 struct option long_opts[] = {
4895 {"filelist", 1, 0, 'l'},
4896 {"data", 1, 0, 'D'},
4897 {"archive", 1, 0, 'a'},
4898 {"mntpath", 1, 0, 'm'},
4902 char short_opts[] = "l:D:a:m:";
4903 struct hsm_user_request *hur, *oldhur;
4908 char *filelist = NULL;
4909 char fullpath[PATH_MAX];
4910 char *opaque = NULL;
4914 int nbfile_alloc = 0;
4915 char *some_file = NULL;
4916 char *mntpath = NULL;
4922 while ((c = getopt_long(argc, argv, short_opts,
4923 long_opts, NULL)) != -1) {
4932 if (action != HUA_ARCHIVE &&
4933 action != HUA_REMOVE) {
4935 "error: -a is supported only "
4936 "when archiving or removing\n");
4939 archive_id = atoi(optarg);
4942 if (some_file == NULL) {
4944 some_file = strdup(optarg);
4950 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4951 argv[0], argv[optind - 1]);
4956 /* All remaining args are files, so we have at least nbfile */
4957 nbfile = argc - optind;
4959 if ((nbfile == 0) && (filelist == NULL))
4963 opaque_len = strlen(opaque);
4965 /* Alloc the request structure with enough place to store all files
4966 * from command line. */
4967 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4969 fprintf(stderr, "Cannot create the request: %s\n",
4973 nbfile_alloc = nbfile;
4975 hur->hur_request.hr_action = action;
4976 hur->hur_request.hr_archive_id = archive_id;
4977 hur->hur_request.hr_flags = 0;
4979 /* All remaining args are files, add them */
4980 if (nbfile != 0 && some_file == NULL)
4981 some_file = strdup(argv[optind]);
4983 for (i = 0; i < nbfile; i++) {
4984 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4990 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4992 /* If a filelist was specified, read the filelist from it. */
4993 if (filelist != NULL) {
4994 fp = fopen(filelist, "r");
4996 fprintf(stderr, "Cannot read the file list %s: %s\n",
4997 filelist, strerror(errno));
5002 while ((rc = getline(&line, &len, fp)) != -1) {
5003 /* If allocated buffer was too small, get something
5005 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5008 nbfile_alloc = nbfile_alloc * 2 + 1;
5010 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5013 fprintf(stderr, "hsm: cannot allocate "
5014 "the request: %s\n",
5021 size = hur_len(oldhur);
5023 fprintf(stderr, "hsm: cannot allocate "
5024 "%u files + %u bytes data\n",
5025 oldhur->hur_request.hr_itemcount,
5026 oldhur->hur_request.hr_data_len);
5033 memcpy(hur, oldhur, size);
5038 if (line[strlen(line) - 1] == '\n')
5039 line[strlen(line) - 1] = '\0';
5041 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5042 mntpath, line, &last_dev);
5048 if (some_file == NULL) {
5058 /* If a --data was used, add it to the request */
5059 hur->hur_request.hr_data_len = opaque_len;
5061 memcpy(hur_data(hur), opaque, opaque_len);
5063 /* Send the HSM request */
5064 if (realpath(some_file, fullpath) == NULL) {
5065 fprintf(stderr, "Could not find path '%s': %s\n",
5066 some_file, strerror(errno));
5068 rc = llapi_hsm_request(fullpath, hur);
5070 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5071 some_file, strerror(-rc));
5081 static int lfs_hsm_archive(int argc, char **argv)
5083 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5086 static int lfs_hsm_restore(int argc, char **argv)
5088 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5091 static int lfs_hsm_release(int argc, char **argv)
5093 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5096 static int lfs_hsm_remove(int argc, char **argv)
5098 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5101 static int lfs_hsm_cancel(int argc, char **argv)
5103 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5106 static int lfs_swap_layouts(int argc, char **argv)
5111 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5112 SWAP_LAYOUTS_KEEP_MTIME |
5113 SWAP_LAYOUTS_KEEP_ATIME);
5116 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5118 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5120 enum lu_ladvise_type advice;
5123 advice < ARRAY_SIZE(ladvise_names); advice++) {
5124 if (ladvise_names[advice] == NULL)
5126 if (strcmp(string, ladvise_names[advice]) == 0)
5130 return LU_LADVISE_INVALID;
5133 static int lfs_ladvise(int argc, char **argv)
5135 struct option long_opts[] = {
5136 {"advice", required_argument, 0, 'a'},
5137 {"background", no_argument, 0, 'b'},
5138 {"end", required_argument, 0, 'e'},
5139 {"start", required_argument, 0, 's'},
5140 {"length", required_argument, 0, 'l'},
5143 char short_opts[] = "a:be:l:s:";
5148 struct llapi_lu_ladvise advice;
5149 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5150 unsigned long long start = 0;
5151 unsigned long long end = LUSTRE_EOF;
5152 unsigned long long length = 0;
5153 unsigned long long size_units;
5154 unsigned long long flags = 0;
5157 while ((c = getopt_long(argc, argv, short_opts,
5158 long_opts, NULL)) != -1) {
5161 advice_type = lfs_get_ladvice(optarg);
5162 if (advice_type == LU_LADVISE_INVALID) {
5163 fprintf(stderr, "%s: invalid advice type "
5164 "'%s'\n", argv[0], optarg);
5165 fprintf(stderr, "Valid types:");
5167 for (advice_type = 0;
5168 advice_type < ARRAY_SIZE(ladvise_names);
5170 if (ladvise_names[advice_type] == NULL)
5172 fprintf(stderr, " %s",
5173 ladvise_names[advice_type]);
5175 fprintf(stderr, "\n");
5185 rc = llapi_parse_size(optarg, &end,
5188 fprintf(stderr, "%s: bad end offset '%s'\n",
5195 rc = llapi_parse_size(optarg, &start,
5198 fprintf(stderr, "%s: bad start offset "
5199 "'%s'\n", argv[0], optarg);
5205 rc = llapi_parse_size(optarg, &length,
5208 fprintf(stderr, "%s: bad length '%s'\n",
5216 fprintf(stderr, "%s: option '%s' unrecognized\n",
5217 argv[0], argv[optind - 1]);
5222 if (advice_type == LU_LADVISE_INVALID) {
5223 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5224 fprintf(stderr, "Valid types:");
5225 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5227 if (ladvise_names[advice_type] == NULL)
5229 fprintf(stderr, " %s", ladvise_names[advice_type]);
5231 fprintf(stderr, "\n");
5235 if (argc <= optind) {
5236 fprintf(stderr, "%s: please give one or more file names\n",
5241 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5242 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5247 if (end == LUSTRE_EOF && length != 0)
5248 end = start + length;
5251 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5252 argv[0], start, end);
5256 while (optind < argc) {
5259 path = argv[optind++];
5261 fd = open(path, O_RDONLY);
5263 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5264 argv[0], path, strerror(errno));
5269 advice.lla_start = start;
5270 advice.lla_end = end;
5271 advice.lla_advice = advice_type;
5272 advice.lla_value1 = 0;
5273 advice.lla_value2 = 0;
5274 advice.lla_value3 = 0;
5275 advice.lla_value4 = 0;
5276 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5279 fprintf(stderr, "%s: cannot give advice '%s' to file "
5280 "'%s': %s\n", argv[0],
5281 ladvise_names[advice_type],
5282 path, strerror(errno));
5285 if (rc == 0 && rc2 < 0)
5291 static int lfs_list_commands(int argc, char **argv)
5293 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5295 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5300 int main(int argc, char **argv)
5304 /* Ensure that liblustreapi constructor has run */
5305 if (!liblustreapi_initialized)
5306 fprintf(stderr, "liblustreapi was not properly initialized\n");
5310 Parser_init("lfs > ", cmdlist);
5312 progname = argv[0]; /* Used in error messages */
5314 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5316 rc = Parser_commands();
5319 return rc < 0 ? -rc : rc;
5322 #ifdef _LUSTRE_IDL_H_
5323 /* Everything we need here should be included by lustreapi.h. */
5324 # error "lfs should not depend on lustre_idl.h"
5325 #endif /* _LUSTRE_IDL_H_ */