4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
57 #include <sys/types.h>
64 #include <libcfs/util/string.h>
65 #include <libcfs/util/ioctl.h>
66 #include <libcfs/util/parser.h>
67 #include <lustre/lustreapi.h>
68 #include <lustre_ver.h>
69 #include <linux/lustre_param.h>
72 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
73 #endif /* !ARRAY_SIZE */
76 static int lfs_setstripe(int argc, char **argv);
77 static int lfs_find(int argc, char **argv);
78 static int lfs_getstripe(int argc, char **argv);
79 static int lfs_getdirstripe(int argc, char **argv);
80 static int lfs_setdirstripe(int argc, char **argv);
81 static int lfs_rmentry(int argc, char **argv);
82 static int lfs_osts(int argc, char **argv);
83 static int lfs_mdts(int argc, char **argv);
84 static int lfs_df(int argc, char **argv);
85 static int lfs_getname(int argc, char **argv);
86 static int lfs_check(int argc, char **argv);
87 #ifdef HAVE_SYS_QUOTA_H
88 static int lfs_setquota(int argc, char **argv);
89 static int lfs_quota(int argc, char **argv);
91 static int lfs_flushctx(int argc, char **argv);
92 static int lfs_cp(int argc, char **argv);
93 static int lfs_ls(int argc, char **argv);
94 static int lfs_poollist(int argc, char **argv);
95 static int lfs_changelog(int argc, char **argv);
96 static int lfs_changelog_clear(int argc, char **argv);
97 static int lfs_fid2path(int argc, char **argv);
98 static int lfs_path2fid(int argc, char **argv);
99 static int lfs_data_version(int argc, char **argv);
100 static int lfs_hsm_state(int argc, char **argv);
101 static int lfs_hsm_set(int argc, char **argv);
102 static int lfs_hsm_clear(int argc, char **argv);
103 static int lfs_hsm_action(int argc, char **argv);
104 static int lfs_hsm_archive(int argc, char **argv);
105 static int lfs_hsm_restore(int argc, char **argv);
106 static int lfs_hsm_release(int argc, char **argv);
107 static int lfs_hsm_remove(int argc, char **argv);
108 static int lfs_hsm_cancel(int argc, char **argv);
109 static int lfs_swap_layouts(int argc, char **argv);
110 static int lfs_mv(int argc, char **argv);
111 static int lfs_ladvise(int argc, char **argv);
112 static int lfs_list_commands(int argc, char **argv);
114 /* Setstripe and migrate share mostly the same parameters */
115 #define SSM_CMD_COMMON(cmd) \
116 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
117 " [--stripe-index|-i <start_ost_idx>]\n" \
118 " [--stripe-size|-S <stripe_size>]\n" \
119 " [--pool|-p <pool_name>]\n" \
120 " [--ost|-o <ost_indices>]\n" \
121 " [--component-end|-E <comp_end>]\n"
123 #define SSM_HELP_COMMON \
124 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
125 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
126 "\t respectively)\n" \
127 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
128 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
129 "\tpool_name: Name of OST pool to use (default none)\n" \
130 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
131 "\t Indices be specified in a format of:\n" \
132 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
134 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
135 "\t If --pool is set with --ost, then the OSTs\n" \
136 "\t must be the members of the pool." \
137 "\tcomp_end: Extent end of the component\n" \
138 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
139 "\t respectively, -1 for EOF), it must be aligned with\n"\
140 "\t the stripe_size\n"
142 #define SETSTRIPE_USAGE \
143 SSM_CMD_COMMON("setstripe") \
144 " <directory|filename>\n" \
147 #define MIGRATE_USAGE \
148 SSM_CMD_COMMON("migrate ") \
150 " [--non-block|-n]\n" \
154 "\tblock: Block file access during data migration (default)\n" \
155 "\tnon-block: Abort migrations if concurrent access is detected\n" \
157 #define SETDIRSTRIPE_USAGE \
158 " [--mdt-count|-c stripe_count>\n" \
159 " [--mdt-index|-i mdt_index]\n" \
160 " [--mdt-hash|-H mdt_hash]\n" \
161 " [--default|-D] [--mode|-m mode] <dir>\n" \
162 "\tstripe_count: stripe count of the striped directory\n" \
163 "\tmdt_index: MDT index of first stripe\n" \
164 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
165 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
166 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
167 "\tdefault_stripe: set default dirstripe of the directory\n" \
168 "\tmode: the mode of the directory\n"
170 static const char *progname;
171 static bool file_lease_supported = true;
173 /* all available commands */
174 command_t cmdlist[] = {
175 {"setstripe", lfs_setstripe, 0,
176 "Create a new file with a specific striping pattern or\n"
177 "set the default striping pattern on an existing directory or\n"
178 "delete the default striping pattern from an existing directory or\n"
179 "add layout component(s) to an existing composite file or\n"
180 "delete specified component(s) from an existing composite file\n\n"
181 "To delete default striping from an existing directory:\n"
182 "usage: setstripe -d <directory>\n"
184 "To delete component(s) from an existing composite file:\n"
185 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
186 " [--component-flags|-F <comp_flags>]\n"
188 "\tcomp_id: Unique component ID\n"
189 "\tcomp_flags: 'init' indicating all instantiated components\n"
190 "\t '^init' indicating all uninstantiated components\n"
191 "\t-I and -F can't be specified at the same time\n"
193 "To add component(s) to an existing composite file:\n"
194 SSM_CMD_COMMON("setstripe --component-add")
196 "To create a file with specified striping/composite layout:\n"
198 {"getstripe", lfs_getstripe, 0,
199 "To list the striping info for a given file or files in a\n"
200 "directory or recursively for all files in a directory tree.\n"
201 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
202 " [--stripe-count|-c] [--stripe-index|-i]\n"
203 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
204 " [--mdt|-m] [--recursive|-r] [--raw|-R] [--yaml|-y]\n"
205 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
206 " [--component-id|-I [comp_id]]\n"
207 " [--component-flags [comp_flags]]\n"
208 " [--component-count [comp_count]]\n"
209 " [--component-start [comp_start]]\n"
210 " [--component-end|-E [comp_end]]\n"
211 " <directory|filename> ..."},
212 {"setdirstripe", lfs_setdirstripe, 0,
213 "To create a striped directory on a specified MDT. This can only\n"
214 "be done on MDT0 with the right of administrator.\n"
215 "usage: setdirstripe [OPTION] <directory>\n"
217 {"getdirstripe", lfs_getdirstripe, 0,
218 "To list the striping info for a given directory\n"
219 "or recursively for all directories in a directory tree.\n"
220 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
221 " [--mdt-index|-i] [--mdt-hash|-t]\n"
222 " [--recursive|-r] [--yaml|-y]\n"
223 " [--default|-D] <dir> ..."},
224 {"mkdir", lfs_setdirstripe, 0,
225 "To create a striped directory on a specified MDT. This can only\n"
226 "be done on MDT0 with the right of administrator.\n"
227 "usage: mkdir [OPTION] <directory>\n"
229 {"rm_entry", lfs_rmentry, 0,
230 "To remove the name entry of the remote directory. Note: This\n"
231 "command will only delete the name entry, i.e. the remote directory\n"
232 "will become inaccessable after this command. This can only be done\n"
233 "by the administrator\n"
234 "usage: rm_entry <dir>\n"},
235 {"pool_list", lfs_poollist, 0,
236 "List pools or pool OSTs\n"
237 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
238 {"find", lfs_find, 0,
239 "find files matching given attributes recursively in directory tree.\n"
240 "usage: find <directory|filename> ...\n"
241 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
242 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
243 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
244 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
245 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
246 " [[!] --stripe-count|-c [+-]<stripes>]\n"
247 " [[!] --stripe-index|-i <index,...>]\n"
248 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
249 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
250 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
251 " [[!] --projid <projid>]\n"
252 " [[!] --layout|-L released,raid0]\n"
253 " [[!] --component-count [+-]<comp_cnt>]\n"
254 " [[!] --component-start [+-]N[kMGTPE]]\n"
255 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
256 " [[!] --component-flags <comp_flags>]\n"
257 " [[!] --mdt-count|-T [+-]<stripes>]\n"
258 " [[!] --mdt-hash|-H <hashtype>\n"
259 "\t !: used before an option indicates 'NOT' requested attribute\n"
260 "\t -: used before a value indicates 'AT MOST' requested value\n"
261 "\t +: used before a value indicates 'AT LEAST' requested value\n"
262 "\tmdt-hash: hash type of the striped directory.\n"
263 "\t fnv_1a_64 FNV-1a hash algorithm\n"
264 "\t all_char sum of characters % MDT_COUNT\n"},
265 {"check", lfs_check, 0,
266 "Display the status of MDS or OSTs (as specified in the command)\n"
267 "or all the servers (MDS and OSTs).\n"
268 "usage: check <osts|mds|servers>"},
269 {"osts", lfs_osts, 0, "list OSTs connected to client "
270 "[for specified path only]\n" "usage: osts [path]"},
271 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
272 "[for specified path only]\n" "usage: mdts [path]"},
274 "report filesystem disk space usage or inodes usage"
275 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
276 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
277 {"getname", lfs_getname, 0, "list instances and specified mount points "
278 "[for specified path only]\n"
279 "Usage: getname [-h]|[path ...] "},
280 #ifdef HAVE_SYS_QUOTA_H
281 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
282 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
283 " -b <block-softlimit> -B <block-hardlimit>\n"
284 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
285 " setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
286 " [--block-softlimit <block-softlimit>]\n"
287 " [--block-hardlimit <block-hardlimit>]\n"
288 " [--inode-softlimit <inode-softlimit>]\n"
289 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
290 " setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
291 " [--block-grace <block-grace>]\n"
292 " [--inode-grace <inode-grace>] <filesystem>\n"
293 " -b can be used instead of --block-softlimit/--block-grace\n"
294 " -B can be used instead of --block-hardlimit\n"
295 " -i can be used instead of --inode-softlimit/--inode-grace\n"
296 " -I can be used instead of --inode-hardlimit\n\n"
297 "Note: The total quota space will be split into many qunits and\n"
298 " balanced over all server targets, the minimal qunit size is\n"
299 " 1M bytes for block space and 1K inodes for inode space.\n\n"
300 " Quota space rebalancing process will stop when this mininum\n"
301 " value is reached. As a result, quota exceeded can be returned\n"
302 " while many targets still have 1MB or 1K inodes of spare\n"
304 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
305 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
307 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
308 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
310 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
311 "usage: flushctx [-k] [mountpoint...]"},
313 "Remote user copy files and directories.\n"
314 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
316 "Remote user list directory contents.\n"
317 "usage: ls [OPTION]... [FILE]..."},
318 {"changelog", lfs_changelog, 0,
319 "Show the metadata changes on an MDT."
320 "\nusage: changelog <mdtname> [startrec [endrec]]"},
321 {"changelog_clear", lfs_changelog_clear, 0,
322 "Indicate that old changelog records up to <endrec> are no longer of "
323 "interest to consumer <id>, allowing the system to free up space.\n"
324 "An <endrec> of 0 means all records.\n"
325 "usage: changelog_clear <mdtname> <id> <endrec>"},
326 {"fid2path", lfs_fid2path, 0,
327 "Resolve the full path(s) for given FID(s). For a specific hardlink "
328 "specify link number <linkno>.\n"
329 /* "For a historical link name, specify changelog record <recno>.\n" */
330 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
331 /* [ --rec <recno> ] */ },
332 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
333 "usage: path2fid [--parents] <path> ..."},
334 {"data_version", lfs_data_version, 0, "Display file data version for "
335 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
336 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
337 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
338 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
339 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
340 "[--archived] [--lost] <file> ..."},
341 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
343 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
344 "[--archived] [--lost] <file> ..."},
345 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
346 "given files.\n" "usage: hsm_action <file> ..."},
347 {"hsm_archive", lfs_hsm_archive, 0,
348 "Archive file to external storage.\n"
349 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
351 {"hsm_restore", lfs_hsm_restore, 0,
352 "Restore file from external storage.\n"
353 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
354 {"hsm_release", lfs_hsm_release, 0,
355 "Release files from Lustre.\n"
356 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
357 {"hsm_remove", lfs_hsm_remove, 0,
358 "Remove file copy from external storage.\n"
359 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
360 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
362 "Note: To remove files from the archive that have been deleted on\n"
363 "Lustre, set mntpath and optionally archive. In that case, all the\n"
364 "positional arguments and entries in the file list must be FIDs."
366 {"hsm_cancel", lfs_hsm_cancel, 0,
367 "Cancel requests related to specified files.\n"
368 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
369 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
370 "usage: swap_layouts <path1> <path2>"},
371 {"migrate", lfs_setstripe, 0,
372 "migrate a directory between MDTs.\n"
373 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
375 "\tmdt_idx: index of the destination MDT\n"
377 "migrate file objects from one OST "
378 "layout\nto another (may be not safe with concurent writes).\n"
380 "[--stripe-count|-c] <stripe_count>\n"
381 " [--stripe-index|-i] <start_ost_index>\n"
382 " [--stripe-size|-S] <stripe_size>\n"
383 " [--pool|-p] <pool_name>\n"
384 " [--ost-list|-o] <ost_indices>\n"
386 " [--non-block|-n]\n"
387 " <file|directory>\n"
388 "\tstripe_count: number of OSTs to stripe a file over\n"
389 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
390 "\tstripe_size: number of bytes to store before moving to the next OST\n"
391 "\tpool_name: name of the predefined pool of OSTs\n"
392 "\tost_indices: OSTs to stripe over, in order\n"
393 "\tblock: wait for the operation to return before continuing\n"
394 "\tnon-block: do not wait for the operation to return.\n"},
396 "To move directories between MDTs. This command is deprecated, "
397 "use \"migrate\" instead.\n"
398 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
400 {"ladvise", lfs_ladvise, 0,
401 "Provide servers with advice about access patterns for a file.\n"
402 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
403 " [--background|-b]\n"
404 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
406 {"help", Parser_help, 0, "help"},
407 {"exit", Parser_quit, 0, "quit"},
408 {"quit", Parser_quit, 0, "quit"},
409 {"--version", Parser_version, 0,
410 "output build version of the utility and exit"},
411 {"--list-commands", lfs_list_commands, 0,
412 "list commands supported by the utility and exit"},
417 #define MIGRATION_NONBLOCK 1
419 static int check_hashtype(const char *hashtype)
423 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
424 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
431 * Internal helper for migrate_copy_data(). Check lease and report error if
434 * \param[in] fd File descriptor on which to check the lease.
435 * \param[out] lease_broken Set to true if the lease was broken.
436 * \param[in] group_locked Whether a group lock was taken or not.
437 * \param[in] path Name of the file being processed, for error
440 * \retval 0 Migration can keep on going.
441 * \retval -errno Error occurred, abort migration.
443 static int check_lease(int fd, bool *lease_broken, bool group_locked,
448 if (!file_lease_supported)
451 rc = llapi_lease_check(fd);
453 return 0; /* llapi_check_lease returns > 0 on success. */
456 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
458 rc = rc ? rc : -EAGAIN;
460 fprintf(stderr, "%s: external attempt to access file '%s' "
461 "blocked until migration ends.\n", progname, path);
464 *lease_broken = true;
468 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
469 bool group_locked, const char *fname)
478 bool lease_broken = false;
480 /* Use a page-aligned buffer for direct I/O */
481 rc = posix_memalign(&buf, getpagesize(), buf_size);
486 /* read new data only if we have written all
487 * previously read data */
490 rc = check_lease(fd_src, &lease_broken,
491 group_locked, fname);
495 rsize = read(fd_src, buf, buf_size);
498 fprintf(stderr, "%s: %s: read failed: %s\n",
499 progname, fname, strerror(-rc));
509 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
513 "%s: %s: write failed on volatile: %s\n",
514 progname, fname, strerror(-rc));
524 fprintf(stderr, "%s: %s: fsync failed: %s\n",
525 progname, fname, strerror(-rc));
533 static int migrate_copy_timestamps(int fdv, const struct stat *st)
535 struct timeval tv[2] = {
536 {.tv_sec = st->st_atime},
537 {.tv_sec = st->st_mtime}
540 return futimes(fdv, tv);
543 static int migrate_block(int fd, int fdv, const struct stat *st,
544 size_t buf_size, const char *name)
551 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
553 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
554 progname, name, strerror(-rc));
562 /* The grouplock blocks all concurrent accesses to the file.
563 * It has to be taken after llapi_get_data_version as it would
565 rc = llapi_group_lock(fd, gid);
567 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
568 progname, name, strerror(-rc));
572 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
574 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
578 /* Make sure we keep original atime/mtime values */
579 rc = migrate_copy_timestamps(fdv, st);
581 fprintf(stderr, "%s: %s: timestamp copy failed\n",
587 * for a migration we need to check data version on file did
590 * Pass in gid=0 since we already own grouplock. */
591 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
592 SWAP_LAYOUTS_CHECK_DV1);
594 fprintf(stderr, "%s: %s: dataversion changed during copy, "
595 "migration aborted\n", progname, name);
598 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
599 name, strerror(-rc));
604 rc2 = llapi_group_unlock(fd, gid);
605 if (rc2 < 0 && rc == 0) {
606 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
607 progname, name, strerror(-rc2));
614 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
615 size_t buf_size, const char *name)
621 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
623 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
624 progname, name, strerror(-rc));
628 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
630 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
634 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
636 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
637 progname, name, strerror(-rc));
643 fprintf(stderr, "%s: %s: data version changed during "
649 /* Make sure we keep original atime/mtime values */
650 rc = migrate_copy_timestamps(fdv, st);
652 fprintf(stderr, "%s: %s: timestamp copy failed\n",
657 /* Atomically put lease, swap layouts and close.
658 * for a migration we need to check data version on file did
660 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
662 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
663 progname, name, strerror(-rc));
670 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
675 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
679 if (flags != 0 && comp_id != 0)
682 /* LCME_FL_INIT is the only supported flag in PFL */
684 if (flags & ~LCME_KNOWN_FLAGS) {
685 fprintf(stderr, "Invalid component flags %#x\n", flags);
688 } else if (comp_id > LCME_ID_MAX) {
689 fprintf(stderr, "Invalid component id %u\n", comp_id);
693 rc = llapi_layout_file_comp_del(fname, comp_id, flags);
695 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
696 comp_id, fname, strerror(errno));
700 static int lfs_component_add(char *fname, struct llapi_layout *layout)
707 rc = llapi_layout_file_comp_add(fname, layout);
709 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
710 fname, strerror(errno));
714 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
715 struct llapi_layout *layout)
723 fd = lstat(fname, &st);
724 if (fd == 0 && S_ISDIR(st.st_mode))
725 open_flags = O_DIRECTORY | O_RDONLY;
727 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
729 fprintf(stderr, "%s %s failed. %s\n",
730 S_ISDIR(st.st_mode) ?
731 "Set default composite layout to " :
732 "Create composite file",
733 fname, strerror(errno));
737 static int lfs_migrate(char *name, __u64 migration_flags,
738 struct llapi_stripe_param *param,
739 struct llapi_layout *layout)
743 char parent[PATH_MAX];
746 char volatile_file[sizeof(parent) +
747 LUSTRE_VOLATILE_HDR_LEN +
748 2 * sizeof(mdt_index) +
749 2 * sizeof(random_value) + 4];
752 struct lov_user_md *lum = NULL;
754 int buf_size = 1024 * 1024 * 4;
755 bool have_lease_rdlck = false;
759 /* find the right size for the IO and allocate the buffer */
760 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
761 lum = malloc(lum_size);
767 rc = llapi_file_get_stripe(name, lum);
768 /* failure can happen for many reasons and some may be not real errors
770 * in case of a real error, a later call will fail with better
771 * error management */
773 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
774 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
775 lum->lmm_stripe_size != 0)
776 buf_size = lum->lmm_stripe_size;
779 /* open file, direct io */
780 /* even if the file is only read, WR mode is nedeed to allow
781 * layout swap on fd */
782 fd = open(name, O_RDWR | O_DIRECT);
785 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
790 if (file_lease_supported) {
791 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
792 if (rc == -EOPNOTSUPP) {
793 /* Older servers do not support file lease.
794 * Disable related checks. This opens race conditions
795 * as explained in LU-4840 */
796 file_lease_supported = false;
798 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
799 progname, name, strerror(-rc));
802 have_lease_rdlck = true;
806 /* search for file directory pathname */
807 if (strlen(name) > sizeof(parent)-1) {
811 strncpy(parent, name, sizeof(parent));
812 ptr = strrchr(parent, '/');
814 if (getcwd(parent, sizeof(parent)) == NULL) {
825 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
827 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
828 progname, name, strerror(-rc));
833 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
834 mode_t open_mode = S_IRUSR | S_IWUSR;
836 random_value = random();
837 rc = snprintf(volatile_file, sizeof(volatile_file),
838 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
839 mdt_index, random_value);
840 if (rc >= sizeof(volatile_file)) {
845 /* create, open a volatile file, use caching (ie no directio) */
847 fdv = llapi_file_open_param(volatile_file, open_flags,
849 else if (layout != NULL)
850 fdv = lfs_component_create(volatile_file, open_flags,
854 } while (fdv == -EEXIST);
858 fprintf(stderr, "%s: %s: cannot create volatile file in"
860 progname, parent, strerror(-rc));
864 /* In case the MDT does not support creation of volatile files
865 * we should try to unlink it. */
866 (void)unlink(volatile_file);
868 /* Not-owner (root?) special case.
869 * Need to set owner/group of volatile file like original.
870 * This will allow to pass related check during layout_swap.
875 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
879 rc = fstat(fdv, &stv);
882 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
883 volatile_file, strerror(errno));
886 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
887 rc = fchown(fdv, st.st_uid, st.st_gid);
890 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
891 name, strerror(errno));
896 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
897 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
899 have_lease_rdlck = false;
900 fdv = -1; /* The volatile file is closed as we put the
901 * lease in non-blocking mode. */
904 /* Blocking mode (forced if servers do not support file lease).
905 * It is also the default mode, since we cannot distinguish
906 * between a broken lease and a server that does not support
907 * atomic swap/close (LU-6785) */
908 rc = migrate_block(fd, fdv, &st, buf_size, name);
912 if (have_lease_rdlck)
929 * Parse a string containing an OST index list into an array of integers.
931 * The input string contains a comma delimited list of individual
932 * indices and ranges, for example "1,2-4,7". Add the indices into the
933 * \a osts array and remove duplicates.
935 * \param[out] osts array to store indices in
936 * \param[in] size size of \a osts array
937 * \param[in] offset starting index in \a osts
938 * \param[in] arg string containing OST index list
940 * \retval positive number of indices in \a osts
941 * \retval -EINVAL unable to parse \a arg
943 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
947 int slots = size - offset;
955 while (!end_of_loop) {
963 ptr = strchrnul(arg, ',');
965 end_of_loop = *ptr == '\0';
968 start_index = strtol(arg, &endptr, 0);
969 if (endptr == arg) /* no data at all */
971 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
976 end_index = start_index;
977 if (*endptr == '-') {
978 end_index = strtol(endptr + 1, &endptr, 0);
981 if (end_index < start_index)
985 for (i = start_index; i <= end_index && slots > 0; i++) {
988 /* remove duplicate */
989 for (j = 0; j < offset; j++) {
993 if (j == offset) { /* no duplicate */
998 if (slots == 0 && i < end_index)
1006 if (!end_of_loop && ptr != NULL)
1009 return rc < 0 ? rc : nr;
1012 static int verify_pool_name(char *prog_name, char *pool_name)
1016 if (pool_name == NULL)
1019 ptr = strchr(pool_name, '.');
1020 if (ptr != NULL && ptr == pool_name) {
1021 fprintf(stderr, "error: %s: fsname is empty in pool name '%s'\n",
1022 prog_name, pool_name);
1029 struct lfs_setstripe_args {
1030 unsigned long long lsa_comp_end;
1031 unsigned long long lsa_stripe_size;
1032 int lsa_stripe_count;
1034 __u32 lsa_comp_flags;
1037 char *lsa_pool_name;
1040 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1042 memset(lsa, 0, sizeof(*lsa));
1043 lsa->lsa_stripe_off = -1;
1046 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1048 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1049 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1050 lsa->lsa_comp_end != 0);
1053 static int comp_args_to_layout(struct llapi_layout **composite,
1054 struct lfs_setstripe_args *lsa)
1056 struct llapi_layout *layout = *composite;
1057 uint64_t prev_end = 0;
1060 if (layout == NULL) {
1061 layout = llapi_layout_alloc();
1062 if (layout == NULL) {
1063 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1067 *composite = layout;
1071 /* Get current component extent, current component
1072 * must be the tail component. */
1073 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1075 fprintf(stderr, "Get comp extent failed. %s\n",
1080 rc = llapi_layout_comp_add(layout);
1082 fprintf(stderr, "Add component failed. %s\n",
1088 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1090 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1091 prev_end, lsa->lsa_comp_end, strerror(errno));
1095 if (lsa->lsa_stripe_size != 0) {
1096 rc = llapi_layout_stripe_size_set(layout,
1097 lsa->lsa_stripe_size);
1099 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1100 lsa->lsa_stripe_size, strerror(errno));
1105 if (lsa->lsa_stripe_count != 0) {
1106 rc = llapi_layout_stripe_count_set(layout,
1107 lsa->lsa_stripe_count == -1 ?
1109 lsa->lsa_stripe_count);
1111 fprintf(stderr, "Set stripe count %d failed. %s\n",
1112 lsa->lsa_stripe_count, strerror(errno));
1117 if (lsa->lsa_pool_name != NULL) {
1118 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1120 fprintf(stderr, "Set pool name: %s failed. %s\n",
1121 lsa->lsa_pool_name, strerror(errno));
1126 if (lsa->lsa_nr_osts > 0) {
1127 if (lsa->lsa_stripe_count > 0 &&
1128 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1129 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1130 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1133 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1134 rc = llapi_layout_ost_index_set(layout, i,
1139 } else if (lsa->lsa_stripe_off != -1) {
1140 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1143 fprintf(stderr, "Set ost index %d failed. %s\n",
1144 i, strerror(errno));
1151 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1152 * end of the last component in the existing file, and adjust the
1153 * first extent start of the components to be added accordingly. */
1154 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1156 struct llapi_layout *head;
1157 uint64_t start, end, stripe_size, prev_end = 0;
1163 head = llapi_layout_get_by_path(fname, 0);
1165 fprintf(stderr, "Read layout from %s failed. %s\n",
1166 fname, strerror(errno));
1170 /* Current component of 'head' should be tail of component list. */
1171 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1173 fprintf(stderr, "Get prev extent failed. %s\n",
1175 llapi_layout_free(head);
1179 llapi_layout_free(head);
1181 /* Make sure we use the first component of the layout to be added. */
1182 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1184 fprintf(stderr, "Move component cursor failed. %s\n",
1189 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1191 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1195 if (start > prev_end || end <= prev_end) {
1196 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1197 "adjacent with the existing file extent end: %lu\n",
1198 start, end, prev_end);
1202 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1204 fprintf(stderr, "Get stripe size failed. %s\n",
1209 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1210 (prev_end & (stripe_size - 1))) {
1211 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1212 stripe_size, prev_end);
1216 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1218 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1219 prev_end, end, strerror(errno));
1226 static inline bool comp_flags_is_neg(__u32 flags)
1228 return flags & LCME_FL_NEG;
1231 static inline void comp_flags_set_neg(__u32 *flags)
1233 *flags |= LCME_FL_NEG;
1236 static inline void comp_flags_clear_neg(__u32 *flags)
1238 *flags &= ~LCME_FL_NEG;
1241 static int comp_name2flags(__u32 *flags, char *name)
1244 __u32 neg_flags = 0;
1250 for (ptr = name; ; ptr = NULL) {
1251 char *flg = strtok(ptr, ",");
1254 if (strcmp(flg, "init") == 0)
1255 *flags |= LCME_FL_INIT;
1256 else if (strcmp(flg, "^init") == 0)
1257 neg_flags |= LCME_FL_INIT;
1262 if (*flags == 0 && neg_flags == 0)
1264 /* don't support mixed flags for now */
1265 if (*flags && neg_flags)
1270 comp_flags_set_neg(flags);
1288 static int lfs_setstripe(int argc, char **argv)
1290 struct lfs_setstripe_args lsa;
1291 struct llapi_stripe_param *param = NULL;
1292 struct find_param migrate_mdt_param = {
1302 char *mdt_idx_arg = NULL;
1303 unsigned long long size_units = 1;
1304 bool migrate_mode = false;
1305 bool migration_block = false;
1306 __u64 migration_flags = 0;
1307 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1308 int comp_del = 0, comp_set = 0;
1311 struct llapi_layout *layout = NULL;
1313 struct option long_opts[] = {
1314 /* --block is only valid in migrate mode */
1315 {"block", no_argument, 0, 'b'},
1316 {"comp-add", no_argument, 0, LFS_COMP_ADD_OPT},
1317 {"component-add", no_argument, 0, LFS_COMP_ADD_OPT},
1318 {"comp-del", no_argument, 0, LFS_COMP_DEL_OPT},
1319 {"component-del", no_argument, 0, LFS_COMP_DEL_OPT},
1320 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1321 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1322 {"comp-set", no_argument, 0, LFS_COMP_SET_OPT},
1323 {"component-set", no_argument, 0, LFS_COMP_SET_OPT},
1324 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1325 /* This formerly implied "stripe-count", but was explicitly
1326 * made "stripe-count" for consistency with other options,
1327 * and to separate it from "mdt-count" when DNE arrives. */
1328 {"count", required_argument, 0, 'c'},
1330 {"stripe-count", required_argument, 0, 'c'},
1331 {"stripe_count", required_argument, 0, 'c'},
1332 {"delete", no_argument, 0, 'd'},
1333 {"comp-end", required_argument, 0, 'E'},
1334 {"component-end", required_argument, 0, 'E'},
1335 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1336 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1337 /* This formerly implied "stripe-index", but was explicitly
1338 * made "stripe-index" for consistency with other options,
1339 * and to separate it from "mdt-index" when DNE arrives. */
1340 {"index", required_argument, 0, 'i'},
1342 {"stripe-index", required_argument, 0, 'i'},
1343 {"stripe_index", required_argument, 0, 'i'},
1344 {"comp-id", required_argument, 0, 'I'},
1345 {"component-id", required_argument, 0, 'I'},
1346 {"mdt", required_argument, 0, 'm'},
1347 {"mdt-index", required_argument, 0, 'm'},
1348 {"mdt_index", required_argument, 0, 'm'},
1349 /* --non-block is only valid in migrate mode */
1350 {"non-block", no_argument, 0, 'n'},
1351 {"ost", required_argument, 0, 'o'},
1352 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1353 {"ost-list", required_argument, 0, 'o'},
1354 {"ost_list", required_argument, 0, 'o'},
1356 {"pool", required_argument, 0, 'p'},
1357 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1358 /* This formerly implied "--stripe-size", but was confusing
1359 * with "lfs find --size|-s", which means "file size", so use
1360 * the consistent "--stripe-size|-S" for all commands. */
1361 {"size", required_argument, 0, 's'},
1363 {"stripe-size", required_argument, 0, 'S'},
1364 {"stripe_size", required_argument, 0, 'S'},
1365 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1366 /* --verbose is only valid in migrate mode */
1367 {"verbose", no_argument, 0, 'v'},
1371 setstripe_args_init(&lsa);
1373 if (strcmp(argv[0], "migrate") == 0)
1374 migrate_mode = true;
1376 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1377 long_opts, NULL)) >= 0) {
1382 case LFS_COMP_ADD_OPT:
1385 case LFS_COMP_DEL_OPT:
1388 case LFS_COMP_FLAGS_OPT:
1389 result = comp_name2flags(&lsa.lsa_comp_flags, optarg);
1391 fprintf(stderr, "error: %s: bad comp flags "
1392 "'%s'\n", argv[0], optarg);
1396 case LFS_COMP_SET_OPT:
1400 if (!migrate_mode) {
1401 fprintf(stderr, "--block is valid only for"
1405 migration_block = true;
1408 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1409 if (strcmp(argv[optind - 1], "--count") == 0)
1410 fprintf(stderr, "warning: '--count' deprecated"
1411 ", use '--stripe-count' instead\n");
1413 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1415 fprintf(stderr, "error: %s: bad stripe count "
1416 "'%s'\n", argv[0], optarg);
1421 /* delete the default striping pattern */
1425 if (lsa.lsa_comp_end != 0) {
1426 result = comp_args_to_layout(&layout, &lsa);
1430 setstripe_args_init(&lsa);
1433 if (!strncmp(optarg, "-1", strlen("-1")) ||
1434 !strncmp(optarg, "EOF", strlen("EOF")) ||
1435 !strncmp(optarg, "eof", strlen("eof"))) {
1436 lsa.lsa_comp_end = LUSTRE_EOF;
1438 result = llapi_parse_size(optarg,
1442 fprintf(stderr, "error: %s: "
1443 "bad component end '%s'\n",
1450 if (strcmp(argv[optind - 1], "--index") == 0)
1451 fprintf(stderr, "warning: '--index' deprecated"
1452 ", use '--stripe-index' instead\n");
1453 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1455 fprintf(stderr, "error: %s: bad stripe offset "
1456 "'%s'\n", argv[0], optarg);
1461 comp_id = strtoul(optarg, &end, 0);
1462 if (*end != '\0' || comp_id == 0) {
1463 fprintf(stderr, "error: %s: bad comp ID "
1464 "'%s'\n", argv[0], optarg);
1469 if (!migrate_mode) {
1470 fprintf(stderr, "--mdt-index is valid only for"
1474 mdt_idx_arg = optarg;
1477 if (!migrate_mode) {
1478 fprintf(stderr, "--non-block is valid only for"
1482 migration_flags |= MIGRATION_NONBLOCK;
1485 lsa.lsa_nr_osts = parse_targets(osts,
1486 sizeof(osts) / sizeof(__u32),
1487 lsa.lsa_nr_osts, optarg);
1488 if (lsa.lsa_nr_osts < 0) {
1490 "error: %s: bad OST indices '%s'\n",
1495 lsa.lsa_osts = osts;
1496 if (lsa.lsa_stripe_off == -1)
1497 lsa.lsa_stripe_off = osts[0];
1500 result = verify_pool_name(argv[0], optarg);
1503 lsa.lsa_pool_name = optarg;
1505 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1507 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1508 fprintf(stderr, "warning: '--size|-s' deprecated, "
1509 "use '--stripe-size|-S' instead\n");
1511 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1513 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1516 fprintf(stderr, "error: %s: bad stripe size "
1517 "'%s'\n", argv[0], optarg);
1522 if (!migrate_mode) {
1523 fprintf(stderr, "--verbose is valid only for"
1527 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1534 fname = argv[optind];
1536 if (lsa.lsa_comp_end != 0) {
1537 result = comp_args_to_layout(&layout, &lsa);
1542 if (optind == argc) {
1543 fprintf(stderr, "error: %s: missing filename|dirname\n",
1548 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1549 * altered by user space tool, so we don't need to support the
1550 * --component-set for this moment. */
1551 if (comp_set != 0) {
1552 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1557 if ((delete + comp_set + comp_del + comp_add) > 1) {
1558 fprintf(stderr, "error: %s: can't specify --component-set, "
1559 "--component-del, --component-add or -d together\n",
1564 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1565 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1566 fprintf(stderr, "error: %s: can't specify -d with "
1567 "-s, -c, -o, -p, -I, -F or -E options\n",
1572 if ((comp_set || comp_del) &&
1573 (setstripe_args_specified(&lsa) || layout != NULL)) {
1574 fprintf(stderr, "error: %s: can't specify --component-del or "
1575 "--component-set with -s, -c, -o, -p or -E options.\n",
1580 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1581 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1582 "--component-del option.\n", argv[0]);
1587 if (layout == NULL) {
1588 fprintf(stderr, "error: %s: -E option must be present"
1589 "in --component-add mode.\n", argv[0]);
1592 result = adjust_first_extent(fname, layout);
1597 if (mdt_idx_arg != NULL && optind > 3) {
1598 fprintf(stderr, "error: %s: cannot specify -m with other "
1599 "options\n", argv[0]);
1603 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1605 "error: %s: cannot specify --non-block and --block\n",
1610 /* support --component-id option for migrate later. */
1611 if (migrate_mode && comp_id != 0) {
1612 fprintf(stderr, "error: %s: -I isn't supported yet.\n",
1617 if (mdt_idx_arg != NULL) {
1618 /* initialize migrate mdt parameters */
1619 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1621 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1622 argv[0], mdt_idx_arg);
1625 migrate_mdt_param.fp_migrate = 1;
1626 } else if (layout == NULL) {
1627 /* initialize stripe parameters */
1628 param = calloc(1, offsetof(typeof(*param),
1629 lsp_osts[lsa.lsa_nr_osts]));
1630 if (param == NULL) {
1631 fprintf(stderr, "error: %s: %s\n", argv[0],
1636 param->lsp_stripe_size = lsa.lsa_stripe_size;
1637 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1638 param->lsp_stripe_count = lsa.lsa_stripe_count;
1639 param->lsp_stripe_pattern = 0;
1640 param->lsp_pool = lsa.lsa_pool_name;
1641 param->lsp_is_specific = false;
1642 if (lsa.lsa_nr_osts > 0) {
1643 if (lsa.lsa_stripe_count > 0 &&
1644 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1645 fprintf(stderr, "error: %s: stripe count '%d' "
1646 "doesn't match the number of OSTs: %d\n"
1647 , argv[0], lsa.lsa_stripe_count,
1653 param->lsp_is_specific = true;
1654 param->lsp_stripe_count = lsa.lsa_nr_osts;
1655 memcpy(param->lsp_osts, osts,
1656 sizeof(*osts) * lsa.lsa_nr_osts);
1660 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1662 if (mdt_idx_arg != NULL) {
1663 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1664 op = "migrate mdt objects of";
1665 } else if (migrate_mode) {
1666 result = lfs_migrate(fname, migration_flags, param,
1668 op = "migrate ost objects of";
1669 } else if (comp_set != 0) {
1670 result = lfs_component_set(fname, comp_id,
1671 lsa.lsa_comp_flags);
1672 op = "modify component flags of";
1673 } else if (comp_del != 0) {
1674 result = lfs_component_del(fname, comp_id,
1675 lsa.lsa_comp_flags);
1676 op = "delete component of";
1677 } else if (comp_add != 0) {
1678 result = lfs_component_add(fname, layout);
1679 op = "add component to";
1680 } else if (layout != NULL) {
1681 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1687 op = "create composite";
1689 result = llapi_file_open_param(fname,
1696 op = "create striped";
1699 /* Save the first error encountered. */
1702 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1704 lsa.lsa_pool_name != NULL && result == EINVAL ?
1705 "OST not in pool?" : strerror(errno));
1711 llapi_layout_free(layout);
1714 llapi_layout_free(layout);
1718 static int lfs_poollist(int argc, char **argv)
1723 return llapi_poollist(argv[1]);
1726 static int set_time(time_t *time, time_t *set, char *str)
1733 else if (str[0] == '-')
1739 t = strtol(str, NULL, 0);
1740 if (*time < t * 24 * 60 * 60) {
1743 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1747 *set = *time - t * 24 * 60 * 60;
1750 static int name2uid(unsigned int *id, const char *name)
1752 struct passwd *passwd;
1754 passwd = getpwnam(name);
1757 *id = passwd->pw_uid;
1762 static int name2gid(unsigned int *id, const char *name)
1764 struct group *group;
1766 group = getgrnam(name);
1769 *id = group->gr_gid;
1774 static inline int name2projid(unsigned int *id, const char *name)
1779 static int uid2name(char **name, unsigned int id)
1781 struct passwd *passwd;
1783 passwd = getpwuid(id);
1786 *name = passwd->pw_name;
1791 static inline int gid2name(char **name, unsigned int id)
1793 struct group *group;
1795 group = getgrgid(id);
1798 *name = group->gr_name;
1803 static int name2layout(__u32 *layout, char *name)
1808 for (ptr = name; ; ptr = NULL) {
1809 lyt = strtok(ptr, ",");
1812 if (strcmp(lyt, "released") == 0)
1813 *layout |= LOV_PATTERN_F_RELEASED;
1814 else if (strcmp(lyt, "raid0") == 0)
1815 *layout |= LOV_PATTERN_RAID0;
1822 static int lfs_find(int argc, char **argv)
1827 struct find_param param = {
1831 struct option long_opts[] = {
1832 {"atime", required_argument, 0, 'A'},
1833 {"comp-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1834 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1835 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1836 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1837 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
1838 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1839 {"stripe-count", required_argument, 0, 'c'},
1840 {"stripe_count", required_argument, 0, 'c'},
1841 {"ctime", required_argument, 0, 'C'},
1842 {"maxdepth", required_argument, 0, 'D'},
1843 {"comp-end", required_argument, 0, 'E'},
1844 {"component-end", required_argument, 0, 'E'},
1845 {"gid", required_argument, 0, 'g'},
1846 {"group", required_argument, 0, 'G'},
1847 {"mdt-hash", required_argument, 0, 'H'},
1848 {"stripe-index", required_argument, 0, 'i'},
1849 {"stripe_index", required_argument, 0, 'i'},
1850 /*{"component-id", required_argument, 0, 'I'},*/
1851 {"layout", required_argument, 0, 'L'},
1852 {"mdt", required_argument, 0, 'm'},
1853 {"mdt-index", required_argument, 0, 'm'},
1854 {"mdt_index", required_argument, 0, 'm'},
1855 {"mtime", required_argument, 0, 'M'},
1856 {"name", required_argument, 0, 'n'},
1857 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1858 {"obd", required_argument, 0, 'O'},
1859 {"ost", required_argument, 0, 'O'},
1860 /* no short option for pool, p/P already used */
1861 {"pool", required_argument, 0, LFS_POOL_OPT},
1862 {"print0", no_argument, 0, 'p'},
1863 {"print", no_argument, 0, 'P'},
1864 {"projid", required_argument, 0, LFS_PROJID_OPT},
1865 {"size", required_argument, 0, 's'},
1866 {"stripe-size", required_argument, 0, 'S'},
1867 {"stripe_size", required_argument, 0, 'S'},
1868 {"type", required_argument, 0, 't'},
1869 {"mdt-count", required_argument, 0, 'T'},
1870 {"uid", required_argument, 0, 'u'},
1871 {"user", required_argument, 0, 'U'},
1884 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1885 while ((c = getopt_long_only(argc, argv,
1886 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1887 long_opts, NULL)) >= 0) {
1892 /* '!' is part of option */
1893 /* when getopt_long_only() finds a string which is not
1894 * an option nor a known option argument it returns 1
1895 * in that case if we already have found pathstart and pathend
1896 * (i.e. we have the list of pathnames),
1897 * the only supported value is "!"
1899 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1900 if (!isoption && pathend != -1) {
1901 fprintf(stderr, "err: %s: filename|dirname must either "
1902 "precede options or follow options\n",
1907 if (!isoption && pathstart == -1)
1908 pathstart = optind - 1;
1909 if (isoption && pathstart != -1 && pathend == -1)
1910 pathend = optind - 2;
1916 /* unknown; opt is "!" or path component,
1917 * checking done above.
1919 if (strcmp(optarg, "!") == 0)
1923 xtime = ¶m.fp_atime;
1924 xsign = ¶m.fp_asign;
1925 param.fp_exclude_atime = !!neg_opt;
1926 /* no break, this falls through to 'C' for ctime */
1929 xtime = ¶m.fp_ctime;
1930 xsign = ¶m.fp_csign;
1931 param.fp_exclude_ctime = !!neg_opt;
1933 /* no break, this falls through to 'M' for mtime */
1936 xtime = ¶m.fp_mtime;
1937 xsign = ¶m.fp_msign;
1938 param.fp_exclude_mtime = !!neg_opt;
1940 rc = set_time(&t, xtime, optarg);
1941 if (rc == INT_MAX) {
1948 case LFS_COMP_COUNT_OPT:
1949 if (optarg[0] == '+') {
1950 param.fp_comp_count_sign = -1;
1952 } else if (optarg[0] == '-') {
1953 param.fp_comp_count_sign = 1;
1957 param.fp_comp_count = strtoul(optarg, &endptr, 0);
1958 if (*endptr != '\0') {
1959 fprintf(stderr, "error: bad component count "
1963 param.fp_check_comp_count = 1;
1964 param.fp_exclude_comp_count = !!neg_opt;
1966 case LFS_COMP_FLAGS_OPT:
1967 rc = comp_name2flags(¶m.fp_comp_flags, optarg);
1969 fprintf(stderr, "error: bad component flags "
1973 param.fp_check_comp_flags = 1;
1974 param.fp_exclude_comp_flags = !!neg_opt;
1976 case LFS_COMP_START_OPT:
1977 if (optarg[0] == '+') {
1978 param.fp_comp_start_sign = -1;
1980 } else if (optarg[0] == '-') {
1981 param.fp_comp_start_sign = 1;
1985 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
1986 ¶m.fp_comp_start_units, 0);
1988 fprintf(stderr, "error: bad component start "
1992 param.fp_check_comp_start = 1;
1993 param.fp_exclude_comp_start = !!neg_opt;
1996 if (optarg[0] == '+') {
1997 param.fp_stripe_count_sign = -1;
1999 } else if (optarg[0] == '-') {
2000 param.fp_stripe_count_sign = 1;
2004 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2005 if (*endptr != '\0') {
2006 fprintf(stderr,"error: bad stripe_count '%s'\n",
2011 param.fp_check_stripe_count = 1;
2012 param.fp_exclude_stripe_count = !!neg_opt;
2015 param.fp_max_depth = strtol(optarg, 0, 0);
2018 if (optarg[0] == '+') {
2019 param.fp_comp_end_sign = -1;
2021 } else if (optarg[0] == '-') {
2022 param.fp_comp_end_sign = 1;
2026 rc = llapi_parse_size(optarg, ¶m.fp_comp_end,
2027 ¶m.fp_comp_end_units, 0);
2029 fprintf(stderr, "error: bad component end "
2033 param.fp_check_comp_end = 1;
2034 param.fp_exclude_comp_end = !!neg_opt;
2038 rc = name2gid(¶m.fp_gid, optarg);
2040 param.fp_gid = strtoul(optarg, &endptr, 10);
2041 if (*endptr != '\0') {
2042 fprintf(stderr, "Group/GID: %s cannot "
2043 "be found.\n", optarg);
2048 param.fp_exclude_gid = !!neg_opt;
2049 param.fp_check_gid = 1;
2052 param.fp_hash_type = check_hashtype(optarg);
2053 if (param.fp_hash_type == 0) {
2054 fprintf(stderr, "error: bad hash_type '%s'\n",
2059 param.fp_check_hash_type = 1;
2060 param.fp_exclude_hash_type = !!neg_opt;
2063 ret = name2layout(¶m.fp_layout, optarg);
2066 param.fp_exclude_layout = !!neg_opt;
2067 param.fp_check_layout = 1;
2071 rc = name2uid(¶m.fp_uid, optarg);
2073 param.fp_uid = strtoul(optarg, &endptr, 10);
2074 if (*endptr != '\0') {
2075 fprintf(stderr, "User/UID: %s cannot "
2076 "be found.\n", optarg);
2081 param.fp_exclude_uid = !!neg_opt;
2082 param.fp_check_uid = 1;
2085 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2087 "Pool name %s is too long"
2088 " (max is %d)\n", optarg,
2093 /* we do check for empty pool because empty pool
2094 * is used to find V1 lov attributes */
2095 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2096 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2097 param.fp_exclude_pool = !!neg_opt;
2098 param.fp_check_pool = 1;
2101 param.fp_pattern = (char *)optarg;
2102 param.fp_exclude_pattern = !!neg_opt;
2107 char *buf, *token, *next, *p;
2111 buf = strdup(optarg);
2117 param.fp_exclude_obd = !!neg_opt;
2120 while (token && *token) {
2121 token = strchr(token, ',');
2128 param.fp_exclude_mdt = !!neg_opt;
2129 param.fp_num_alloc_mdts += len;
2130 tmp = realloc(param.fp_mdt_uuid,
2131 param.fp_num_alloc_mdts *
2132 sizeof(*param.fp_mdt_uuid));
2138 param.fp_mdt_uuid = tmp;
2140 param.fp_exclude_obd = !!neg_opt;
2141 param.fp_num_alloc_obds += len;
2142 tmp = realloc(param.fp_obd_uuid,
2143 param.fp_num_alloc_obds *
2144 sizeof(*param.fp_obd_uuid));
2150 param.fp_obd_uuid = tmp;
2152 for (token = buf; token && *token; token = next) {
2153 struct obd_uuid *puuid;
2156 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2159 ¶m.fp_obd_uuid[param.fp_num_obds++];
2161 p = strchr(token, ',');
2168 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2173 strncpy(puuid->uuid, token,
2174 sizeof(puuid->uuid));
2182 param.fp_zero_end = 1;
2186 case LFS_PROJID_OPT:
2187 rc = name2projid(¶m.fp_projid, optarg);
2189 param.fp_projid = strtoul(optarg, &endptr, 10);
2190 if (*endptr != '\0') {
2192 "Invalid project ID: %s",
2198 param.fp_exclude_projid = !!neg_opt;
2199 param.fp_check_projid = 1;
2202 if (optarg[0] == '+') {
2203 param.fp_size_sign = -1;
2205 } else if (optarg[0] == '-') {
2206 param.fp_size_sign = 1;
2210 ret = llapi_parse_size(optarg, ¶m.fp_size,
2211 ¶m.fp_size_units, 0);
2213 fprintf(stderr, "error: bad file size '%s'\n",
2217 param.fp_check_size = 1;
2218 param.fp_exclude_size = !!neg_opt;
2221 if (optarg[0] == '+') {
2222 param.fp_stripe_size_sign = -1;
2224 } else if (optarg[0] == '-') {
2225 param.fp_stripe_size_sign = 1;
2229 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2230 ¶m.fp_stripe_size_units, 0);
2232 fprintf(stderr, "error: bad stripe_size '%s'\n",
2236 param.fp_check_stripe_size = 1;
2237 param.fp_exclude_stripe_size = !!neg_opt;
2240 param.fp_exclude_type = !!neg_opt;
2241 switch (optarg[0]) {
2243 param.fp_type = S_IFBLK;
2246 param.fp_type = S_IFCHR;
2249 param.fp_type = S_IFDIR;
2252 param.fp_type = S_IFREG;
2255 param.fp_type = S_IFLNK;
2258 param.fp_type = S_IFIFO;
2261 param.fp_type = S_IFSOCK;
2264 fprintf(stderr, "error: %s: bad type '%s'\n",
2271 if (optarg[0] == '+') {
2272 param.fp_mdt_count_sign = -1;
2274 } else if (optarg[0] == '-') {
2275 param.fp_mdt_count_sign = 1;
2279 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2280 if (*endptr != '\0') {
2281 fprintf(stderr, "error: bad mdt_count '%s'\n",
2286 param.fp_check_mdt_count = 1;
2287 param.fp_exclude_mdt_count = !!neg_opt;
2295 if (pathstart == -1) {
2296 fprintf(stderr, "error: %s: no filename|pathname\n",
2300 } else if (pathend == -1) {
2306 rc = llapi_find(argv[pathstart], ¶m);
2307 if (rc != 0 && ret == 0)
2309 } while (++pathstart < pathend);
2312 fprintf(stderr, "error: %s failed for %s.\n",
2313 argv[0], argv[optind - 1]);
2315 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2316 free(param.fp_obd_uuid);
2318 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2319 free(param.fp_mdt_uuid);
2324 static int lfs_getstripe_internal(int argc, char **argv,
2325 struct find_param *param)
2327 struct option long_opts[] = {
2328 {"comp-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2329 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2330 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2331 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2332 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
2333 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
2334 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2335 /* This formerly implied "stripe-count", but was explicitly
2336 * made "stripe-count" for consistency with other options,
2337 * and to separate it from "mdt-count" when DNE arrives. */
2338 {"count", no_argument, 0, 'c'},
2340 {"stripe-count", no_argument, 0, 'c'},
2341 {"stripe_count", no_argument, 0, 'c'},
2342 {"directory", no_argument, 0, 'd'},
2343 {"default", no_argument, 0, 'D'},
2344 {"comp-end", required_argument, 0, 'E'},
2345 {"component-end", required_argument, 0, 'E'},
2346 {"fid", no_argument, 0, 'F'},
2347 {"generation", no_argument, 0, 'g'},
2348 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
2349 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2350 /* This formerly implied "stripe-index", but was explicitly
2351 * made "stripe-index" for consistency with other options,
2352 * and to separate it from "mdt-index" when DNE arrives. */
2353 {"index", no_argument, 0, 'i'},
2355 {"stripe-index", no_argument, 0, 'i'},
2356 {"stripe_index", no_argument, 0, 'i'},
2357 {"comp-id", required_argument, 0, 'I'},
2358 {"component-id", required_argument, 0, 'I'},
2359 {"layout", no_argument, 0, 'L'},
2360 {"mdt", no_argument, 0, 'm'},
2361 {"mdt-index", no_argument, 0, 'm'},
2362 {"mdt_index", no_argument, 0, 'm'},
2363 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2364 {"mdt-index", no_argument, 0, 'M'},
2365 {"mdt_index", no_argument, 0, 'M'},
2367 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2368 /* This formerly implied "stripe-index", but was confusing
2369 * with "file offset" (which will eventually be needed for
2370 * with different layouts by offset), so deprecate it. */
2371 {"offset", no_argument, 0, 'o'},
2373 {"obd", required_argument, 0, 'O'},
2374 {"ost", required_argument, 0, 'O'},
2375 {"pool", no_argument, 0, 'p'},
2376 {"quiet", no_argument, 0, 'q'},
2377 {"recursive", no_argument, 0, 'r'},
2378 {"raw", no_argument, 0, 'R'},
2379 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2380 /* This formerly implied "--stripe-size", but was confusing
2381 * with "lfs find --size|-s", which means "file size", so use
2382 * the consistent "--stripe-size|-S" for all commands. */
2383 {"size", no_argument, 0, 's'},
2385 {"stripe-size", no_argument, 0, 'S'},
2386 {"stripe_size", no_argument, 0, 'S'},
2387 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
2388 {"verbose", no_argument, 0, 'v'},
2389 {"yaml", no_argument, 0, 'y'},
2395 while ((c = getopt_long(argc, argv, "cdDE:FghiI:LmMoO:pqrRsSvy",
2396 long_opts, NULL)) != -1) {
2399 if (strcmp(argv[optind - 1], "--count") == 0)
2400 fprintf(stderr, "warning: '--count' deprecated,"
2401 " use '--stripe-count' instead\n");
2402 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2403 param->fp_verbose |= VERBOSE_COUNT;
2404 param->fp_max_depth = 0;
2407 case LFS_COMP_COUNT_OPT:
2408 param->fp_verbose |= VERBOSE_COMP_COUNT;
2409 param->fp_max_depth = 0;
2411 case LFS_COMP_FLAGS_OPT:
2412 if (optarg != NULL) {
2413 rc = comp_name2flags(¶m->fp_comp_flags,
2416 param->fp_verbose |=
2418 param->fp_max_depth = 0;
2421 param->fp_check_comp_flags = 1;
2424 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2425 param->fp_max_depth = 0;
2428 case LFS_COMP_START_OPT:
2429 if (optarg != NULL) {
2431 if (tmp[0] == '+') {
2432 param->fp_comp_start_sign = 1;
2434 } else if (tmp[0] == '-') {
2435 param->fp_comp_start_sign = -1;
2438 rc = llapi_parse_size(tmp,
2439 ¶m->fp_comp_start,
2440 ¶m->fp_comp_start_units, 0);
2442 param->fp_verbose |= VERBOSE_COMP_START;
2443 param->fp_max_depth = 0;
2446 param->fp_check_comp_start = 1;
2449 param->fp_verbose |= VERBOSE_COMP_START;
2450 param->fp_max_depth = 0;
2454 param->fp_max_depth = 0;
2457 param->fp_get_default_lmv = 1;
2460 if (optarg != NULL) {
2462 if (tmp[0] == '+') {
2463 param->fp_comp_end_sign = 1;
2465 } else if (tmp[0] == '-') {
2466 param->fp_comp_end_sign = -1;
2469 rc = llapi_parse_size(tmp,
2470 ¶m->fp_comp_end,
2471 ¶m->fp_comp_end_units, 0);
2473 param->fp_verbose |= VERBOSE_COMP_END;
2474 param->fp_max_depth = 0;
2477 param->fp_check_comp_end = 1;
2480 param->fp_verbose |= VERBOSE_COMP_END;
2481 param->fp_max_depth = 0;
2485 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2486 param->fp_verbose |= VERBOSE_DFID;
2487 param->fp_max_depth = 0;
2491 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2492 param->fp_verbose |= VERBOSE_GENERATION;
2493 param->fp_max_depth = 0;
2496 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2498 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2499 "use '--stripe-index|-i' instead\n");
2502 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2503 if (strcmp(argv[optind - 1], "--index") == 0)
2504 fprintf(stderr, "warning: '--index' deprecated"
2505 ", use '--stripe-index' instead\n");
2507 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2508 param->fp_verbose |= VERBOSE_OFFSET;
2509 param->fp_max_depth = 0;
2513 if (optarg != NULL) {
2514 param->fp_comp_id = strtoul(optarg, &end, 0);
2516 param->fp_verbose |= VERBOSE_COMP_ID;
2517 param->fp_max_depth = 0;
2520 param->fp_check_comp_id = 1;
2523 param->fp_max_depth = 0;
2524 param->fp_verbose |= VERBOSE_COMP_ID;
2528 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2529 param->fp_verbose |= VERBOSE_LAYOUT;
2530 param->fp_max_depth = 0;
2533 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2535 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2536 fprintf(stderr, "warning: '-M' deprecated"
2537 ", use '-m' instead\n");
2541 if (!(param->fp_verbose & VERBOSE_DETAIL))
2542 param->fp_max_depth = 0;
2543 param->fp_verbose |= VERBOSE_MDTINDEX;
2546 if (param->fp_obd_uuid) {
2548 "error: %s: only one obduuid allowed",
2552 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2555 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2556 param->fp_verbose |= VERBOSE_POOL;
2557 param->fp_max_depth = 0;
2564 param->fp_recursive = 1;
2569 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2571 fprintf(stderr, "warning: '--size|-s' deprecated, "
2572 "use '--stripe-size|-S' instead\n");
2573 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2575 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2576 param->fp_verbose |= VERBOSE_SIZE;
2577 param->fp_max_depth = 0;
2581 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2594 if (param->fp_recursive)
2595 param->fp_max_depth = -1;
2596 else if (param->fp_verbose & VERBOSE_DETAIL)
2597 param->fp_max_depth = 1;
2599 if (!param->fp_verbose)
2600 param->fp_verbose = VERBOSE_DEFAULT;
2601 if (param->fp_quiet)
2602 param->fp_verbose = VERBOSE_OBJID;
2605 rc = llapi_getstripe(argv[optind], param);
2606 } while (++optind < argc && !rc);
2609 fprintf(stderr, "error: %s failed for %s.\n",
2610 argv[0], argv[optind - 1]);
2614 static int lfs_tgts(int argc, char **argv)
2616 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2617 struct find_param param;
2618 int index = 0, rc=0;
2623 if (argc == 2 && !realpath(argv[1], path)) {
2625 fprintf(stderr, "error: invalid path '%s': %s\n",
2626 argv[1], strerror(-rc));
2630 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2631 /* Check if we have a mount point */
2632 if (mntdir[0] == '\0')
2635 memset(¶m, 0, sizeof(param));
2636 if (!strcmp(argv[0], "mdts"))
2637 param.fp_get_lmv = 1;
2639 rc = llapi_ostlist(mntdir, ¶m);
2641 fprintf(stderr, "error: %s: failed on %s\n",
2644 if (path[0] != '\0')
2646 memset(mntdir, 0, PATH_MAX);
2652 static int lfs_getstripe(int argc, char **argv)
2654 struct find_param param = { 0 };
2656 param.fp_max_depth = 1;
2657 return lfs_getstripe_internal(argc, argv, ¶m);
2661 static int lfs_getdirstripe(int argc, char **argv)
2663 struct find_param param = { 0 };
2664 struct option long_opts[] = {
2665 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2666 {"mdt-count", no_argument, 0, 'c'},
2668 {"mdt-hash", no_argument, 0, 'H'},
2669 {"mdt-index", no_argument, 0, 'i'},
2670 {"recursive", no_argument, 0, 'r'},
2671 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2672 {"mdt-hash", no_argument, 0, 't'},
2674 {"default", no_argument, 0, 'D'},
2675 {"obd", required_argument, 0, 'O'},
2676 {"mdt-count", no_argument, 0, 'T'},
2677 {"yaml", no_argument, 0, 'y'},
2682 param.fp_get_lmv = 1;
2684 while ((c = getopt_long(argc, argv,
2685 "cDHiO:rtTy", long_opts, NULL)) != -1)
2689 if (param.fp_obd_uuid) {
2691 "error: %s: only one obduuid allowed",
2695 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2697 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2699 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2700 fprintf(stderr, "warning: '-c' deprecated"
2701 ", use '-T' instead\n");
2705 param.fp_verbose |= VERBOSE_COUNT;
2708 param.fp_verbose |= VERBOSE_OFFSET;
2710 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2714 param.fp_verbose |= VERBOSE_HASH_TYPE;
2717 param.fp_get_default_lmv = 1;
2720 param.fp_recursive = 1;
2733 if (param.fp_recursive)
2734 param.fp_max_depth = -1;
2736 if (!param.fp_verbose)
2737 param.fp_verbose = VERBOSE_DEFAULT;
2740 rc = llapi_getstripe(argv[optind], ¶m);
2741 } while (++optind < argc && !rc);
2744 fprintf(stderr, "error: %s failed for %s.\n",
2745 argv[0], argv[optind - 1]);
2750 static int lfs_setdirstripe(int argc, char **argv)
2754 unsigned int stripe_offset = -1;
2755 unsigned int stripe_count = 1;
2756 enum lmv_hash_type hash_type;
2759 char *stripe_offset_opt = NULL;
2760 char *stripe_count_opt = NULL;
2761 char *stripe_hash_opt = NULL;
2762 char *mode_opt = NULL;
2763 bool default_stripe = false;
2764 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2765 mode_t previous_mode = 0;
2766 bool delete = false;
2768 struct option long_opts[] = {
2769 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2770 {"count", required_argument, 0, 'c'},
2772 {"mdt-count", required_argument, 0, 'c'},
2773 {"delete", no_argument, 0, 'd'},
2774 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2775 {"index", required_argument, 0, 'i'},
2777 {"mdt-index", required_argument, 0, 'i'},
2778 {"mode", required_argument, 0, 'm'},
2779 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2780 {"hash-type", required_argument, 0, 't'},
2781 {"mdt-hash", required_argument, 0, 't'},
2783 {"mdt-hash", required_argument, 0, 'H'},
2784 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2785 {"default_stripe", no_argument, 0, 'D'},
2787 {"default", no_argument, 0, 'D'},
2791 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2798 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2799 if (strcmp(argv[optind - 1], "--count") == 0)
2800 fprintf(stderr, "warning: '--count' deprecated"
2801 ", use '--mdt-count' instead\n");
2803 stripe_count_opt = optarg;
2807 default_stripe = true;
2810 default_stripe = true;
2813 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2814 if (strcmp(argv[optind - 1], "--index") == 0)
2815 fprintf(stderr, "warning: '--index' deprecated"
2816 ", use '--mdt-index' instead\n");
2818 stripe_offset_opt = optarg;
2823 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2827 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2828 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2829 fprintf(stderr, "warning: '--hash-type' "
2830 "deprecated, use '--mdt-hash' "
2833 stripe_hash_opt = optarg;
2836 fprintf(stderr, "error: %s: option '%s' "
2838 argv[0], argv[optind - 1]);
2843 if (optind == argc) {
2844 fprintf(stderr, "error: %s: missing dirname\n",
2849 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2850 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2855 if (stripe_offset_opt != NULL) {
2856 /* get the stripe offset */
2857 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2859 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2860 argv[0], stripe_offset_opt);
2866 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2867 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2868 " or -i options.\n", argv[0]);
2876 if (mode_opt != NULL) {
2877 mode = strtoul(mode_opt, &end, 8);
2879 fprintf(stderr, "error: %s: bad mode '%s'\n",
2883 previous_mode = umask(0);
2886 if (stripe_hash_opt == NULL) {
2887 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2889 hash_type = check_hashtype(stripe_hash_opt);
2890 if (hash_type == 0) {
2892 "error: %s: bad stripe hash type '%s'\n",
2893 argv[0], stripe_hash_opt);
2898 /* get the stripe count */
2899 if (stripe_count_opt != NULL) {
2900 stripe_count = strtoul(stripe_count_opt, &end, 0);
2902 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2903 argv[0], stripe_count_opt);
2908 dname = argv[optind];
2910 if (default_stripe) {
2911 result = llapi_dir_set_default_lmv_stripe(dname,
2912 stripe_offset, stripe_count,
2915 result = llapi_dir_create_pool(dname, mode,
2917 stripe_count, hash_type,
2922 fprintf(stderr, "error: %s: create stripe dir '%s' "
2923 "failed\n", argv[0], dname);
2926 dname = argv[++optind];
2927 } while (dname != NULL);
2929 if (mode_opt != NULL)
2930 umask(previous_mode);
2936 static int lfs_rmentry(int argc, char **argv)
2943 fprintf(stderr, "error: %s: missing dirname\n",
2949 dname = argv[index];
2950 while (dname != NULL) {
2951 result = llapi_direntry_remove(dname);
2953 fprintf(stderr, "error: %s: remove dir entry '%s' "
2954 "failed\n", argv[0], dname);
2957 dname = argv[++index];
2962 static int lfs_mv(int argc, char **argv)
2964 struct find_param param = {
2971 struct option long_opts[] = {
2972 {"mdt-index", required_argument, 0, 'M'},
2973 {"verbose", no_argument, 0, 'v'},
2977 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2980 param.fp_mdt_index = strtoul(optarg, &end, 0);
2982 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2989 param.fp_verbose = VERBOSE_DETAIL;
2993 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2994 argv[0], argv[optind - 1]);
2999 if (param.fp_mdt_index == -1) {
3000 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3004 if (optind >= argc) {
3005 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3009 param.fp_migrate = 1;
3010 rc = llapi_migrate_mdt(argv[optind], ¶m);
3012 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3013 argv[0], argv[optind], param.fp_mdt_index,
3018 static int lfs_osts(int argc, char **argv)
3020 return lfs_tgts(argc, argv);
3023 static int lfs_mdts(int argc, char **argv)
3025 return lfs_tgts(argc, argv);
3028 #define COOK(value) \
3031 while (value > 1024) { \
3039 #define CDF "%11llu"
3040 #define HDF "%8.1f%c"
3045 MNTDF_INODES = 0x0001,
3046 MNTDF_COOKED = 0x0002,
3047 MNTDF_LAZY = 0x0004,
3048 MNTDF_VERBOSE = 0x0008,
3051 static int showdf(char *mntdir, struct obd_statfs *stat,
3052 char *uuid, enum mntdf_flags flags,
3053 char *type, int index, int rc)
3055 long long avail, used, total;
3057 char *suffix = "KMGTPEZY";
3058 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3059 char tbuf[3 * sizeof(__u64)];
3060 char ubuf[3 * sizeof(__u64)];
3061 char abuf[3 * sizeof(__u64)];
3062 char rbuf[3 * sizeof(__u64)];
3069 if (flags & MNTDF_INODES) {
3070 avail = stat->os_ffree;
3071 used = stat->os_files - stat->os_ffree;
3072 total = stat->os_files;
3074 int shift = flags & MNTDF_COOKED ? 0 : 10;
3076 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3077 used = ((stat->os_blocks - stat->os_bfree) *
3078 stat->os_bsize) >> shift;
3079 total = (stat->os_blocks * stat->os_bsize) >> shift;
3082 if ((used + avail) > 0)
3083 ratio = (double)used / (double)(used + avail);
3085 if (flags & MNTDF_COOKED) {
3089 cook_val = (double)total;
3092 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3095 snprintf(tbuf, sizeof(tbuf), CDF, total);
3097 cook_val = (double)used;
3100 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3103 snprintf(ubuf, sizeof(ubuf), CDF, used);
3105 cook_val = (double)avail;
3108 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3111 snprintf(abuf, sizeof(abuf), CDF, avail);
3113 snprintf(tbuf, sizeof(tbuf), CDF, total);
3114 snprintf(ubuf, sizeof(tbuf), CDF, used);
3115 snprintf(abuf, sizeof(tbuf), CDF, avail);
3118 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3119 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3120 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3122 printf("[%s:%d]", type, index);
3124 if (stat->os_state) {
3126 * Each character represents the matching
3129 const char state_names[] = "DRSI";
3134 for (i = 0, state = stat->os_state;
3135 state && i < sizeof(state_names); i++) {
3136 if (!(state & (1 << i)))
3138 printf("%c", state_names[i]);
3146 printf(UUF": inactive device\n", uuid);
3149 printf(UUF": %s\n", uuid, strerror(-rc));
3156 struct ll_stat_type {
3161 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3163 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3164 struct obd_uuid uuid_buf;
3165 char *poolname = NULL;
3166 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3167 { LL_STATFS_LOV, "OST" },
3169 struct ll_stat_type *tp;
3170 __u64 ost_ffree = 0;
3178 poolname = strchr(pool, '.');
3179 if (poolname != NULL) {
3180 if (strncmp(fsname, pool, strlen(fsname))) {
3181 fprintf(stderr, "filesystem name incorrect\n");
3189 fd = open(mntdir, O_RDONLY);
3192 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3197 if (flags & MNTDF_INODES)
3198 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3199 "UUID", "Inodes", "IUsed", "IFree",
3200 "IUse%", "Mounted on");
3202 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3203 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3204 "Used", "Available", "Use%", "Mounted on");
3206 for (tp = types; tp->st_name != NULL; tp++) {
3207 for (index = 0; ; index++) {
3208 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3209 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3210 type = flags & MNTDF_LAZY ?
3211 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3212 rc2 = llapi_obd_fstatfs(fd, type, index,
3213 &stat_buf, &uuid_buf);
3218 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3219 if (!(flags & MNTDF_VERBOSE))
3221 } else if (rc2 < 0 && rc == 0) {
3225 if (poolname && tp->st_op == LL_STATFS_LOV &&
3226 llapi_search_ost(fsname, poolname,
3227 obd_uuid2str(&uuid_buf)) != 1)
3230 /* the llapi_obd_statfs() call may have returned with
3231 * an error, but if it filled in uuid_buf we will at
3232 * lease use that to print out a message for that OBD.
3233 * If we didn't get anything in the uuid_buf, then fill
3234 * it in so that we can print an error message. */
3235 if (uuid_buf.uuid[0] == '\0')
3236 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3237 "%s%04x", tp->st_name, index);
3238 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3239 flags, tp->st_name, index, rc2);
3242 if (tp->st_op == LL_STATFS_LMV) {
3243 sum.os_ffree += stat_buf.os_ffree;
3244 sum.os_files += stat_buf.os_files;
3245 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3246 sum.os_blocks += stat_buf.os_blocks *
3248 sum.os_bfree += stat_buf.os_bfree *
3250 sum.os_bavail += stat_buf.os_bavail *
3252 ost_ffree += stat_buf.os_ffree;
3260 /* If we don't have as many objects free on the OST as inodes
3261 * on the MDS, we reduce the total number of inodes to
3262 * compensate, so that the "inodes in use" number is correct.
3263 * Matches ll_statfs_internal() so the results are consistent. */
3264 if (ost_ffree < sum.os_ffree) {
3265 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3266 sum.os_ffree = ost_ffree;
3269 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3275 static int lfs_df(int argc, char **argv)
3277 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3278 enum mntdf_flags flags = 0;
3279 int c, rc = 0, index = 0;
3280 char fsname[PATH_MAX] = "", *pool_name = NULL;
3281 struct option long_opts[] = {
3282 {"human-readable", 0, 0, 'h'},
3283 {"inodes", 0, 0, 'i'},
3284 {"lazy", 0, 0, 'l'},
3285 {"pool", required_argument, 0, 'p'},
3286 {"verbose", 0, 0, 'v'},
3290 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3293 flags |= MNTDF_COOKED;
3296 flags |= MNTDF_INODES;
3299 flags |= MNTDF_LAZY;
3305 flags |= MNTDF_VERBOSE;
3311 if (optind < argc && !realpath(argv[optind], path)) {
3313 fprintf(stderr, "error: invalid path '%s': %s\n",
3314 argv[optind], strerror(-rc));
3318 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3319 /* Check if we have a mount point */
3320 if (mntdir[0] == '\0')
3323 rc = mntdf(mntdir, fsname, pool_name, flags);
3324 if (rc || path[0] != '\0')
3326 fsname[0] = '\0'; /* avoid matching in next loop */
3327 mntdir[0] = '\0'; /* avoid matching in next loop */
3333 static int lfs_getname(int argc, char **argv)
3335 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3336 int rc = 0, index = 0, c;
3337 char buf[sizeof(struct obd_uuid)];
3339 while ((c = getopt(argc, argv, "h")) != -1)
3342 if (optind == argc) { /* no paths specified, get all paths. */
3343 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3344 rc = llapi_getname(mntdir, buf, sizeof(buf));
3347 "cannot get name for `%s': %s\n",
3348 mntdir, strerror(-rc));
3352 printf("%s %s\n", buf, mntdir);
3354 path[0] = fsname[0] = mntdir[0] = 0;
3356 } else { /* paths specified, only attempt to search these. */
3357 for (; optind < argc; optind++) {
3358 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3361 "cannot get name for `%s': %s\n",
3362 argv[optind], strerror(-rc));
3366 printf("%s %s\n", buf, argv[optind]);
3372 static int lfs_check(int argc, char **argv)
3375 char mntdir[PATH_MAX] = {'\0'};
3384 obd_types[0] = obd_type1;
3385 obd_types[1] = obd_type2;
3387 if (strcmp(argv[1], "osts") == 0) {
3388 strcpy(obd_types[0], "osc");
3389 } else if (strcmp(argv[1], "mds") == 0) {
3390 strcpy(obd_types[0], "mdc");
3391 } else if (strcmp(argv[1], "servers") == 0) {
3393 strcpy(obd_types[0], "osc");
3394 strcpy(obd_types[1], "mdc");
3396 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3401 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3402 if (rc < 0 || mntdir[0] == '\0') {
3403 fprintf(stderr, "No suitable Lustre mount found\n");
3407 rc = llapi_target_check(num_types, obd_types, mntdir);
3409 fprintf(stderr, "error: %s: %s status failed\n",
3416 #ifdef HAVE_SYS_QUOTA_H
3417 #define ARG2INT(nr, str, msg) \
3420 nr = strtol(str, &endp, 0); \
3422 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3427 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3429 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3430 * returns the value or ULONG_MAX on integer overflow or incorrect format
3432 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3433 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3434 * 3. empty integer value is interpreted as 0
3436 static unsigned long str2sec(const char* timestr)
3438 const char spec[] = "smhdw";
3439 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3440 unsigned long val = 0;
3443 if (strpbrk(timestr, spec) == NULL) {
3444 /* no specifiers inside the time string,
3445 should treat it as an integer value */
3446 val = strtoul(timestr, &tail, 10);
3447 return *tail ? ULONG_MAX : val;
3450 /* format string is XXwXXdXXhXXmXXs */
3456 v = strtoul(timestr, &tail, 10);
3457 if (v == ULONG_MAX || *tail == '\0')
3458 /* value too large (ULONG_MAX or more)
3459 or missing specifier */
3462 ptr = strchr(spec, *tail);
3464 /* unknown specifier */
3469 /* check if product will overflow the type */
3470 if (!(v < ULONG_MAX / mult[ind]))
3473 ADD_OVERFLOW(val, mult[ind] * v);
3474 if (val == ULONG_MAX)
3486 #define ARG2ULL(nr, str, def_units) \
3488 unsigned long long limit, units = def_units; \
3491 rc = llapi_parse_size(str, &limit, &units, 1); \
3493 fprintf(stderr, "error: bad limit value %s\n", str); \
3499 static inline int has_times_option(int argc, char **argv)
3503 for (i = 1; i < argc; i++)
3504 if (!strcmp(argv[i], "-t"))
3510 int lfs_setquota_times(int argc, char **argv)
3513 struct if_quotactl qctl;
3514 char *mnt, *obd_type = (char *)qctl.obd_type;
3515 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3516 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3517 struct option long_opts[] = {
3518 {"block-grace", required_argument, 0, 'b'},
3519 {"group", no_argument, 0, 'g'},
3520 {"inode-grace", required_argument, 0, 'i'},
3521 {"projid", no_argument, 0, 'p'},
3522 {"times", no_argument, 0, 't'},
3523 {"user", no_argument, 0, 'u'},
3528 memset(&qctl, 0, sizeof(qctl));
3529 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3530 qctl.qc_type = ALLQUOTA;
3532 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3533 long_opts, NULL)) != -1) {
3544 if (qctl.qc_type != ALLQUOTA) {
3545 fprintf(stderr, "error: -u/g/p can't be used "
3546 "more than once\n");
3549 qctl.qc_type = qtype;
3552 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3553 fprintf(stderr, "error: bad block-grace: %s\n",
3557 dqb->dqb_valid |= QIF_BTIME;
3560 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3561 fprintf(stderr, "error: bad inode-grace: %s\n",
3565 dqb->dqb_valid |= QIF_ITIME;
3567 case 't': /* Yes, of course! */
3569 default: /* getopt prints error message for us when opterr != 0 */
3574 if (qctl.qc_type == ALLQUOTA) {
3575 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3579 if (optind != argc - 1) {
3580 fprintf(stderr, "error: unexpected parameters encountered\n");
3585 rc = llapi_quotactl(mnt, &qctl);
3588 fprintf(stderr, "%s %s ", obd_type,
3589 obd_uuid2str(&qctl.obd_uuid));
3590 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3597 #define BSLIMIT (1 << 0)
3598 #define BHLIMIT (1 << 1)
3599 #define ISLIMIT (1 << 2)
3600 #define IHLIMIT (1 << 3)
3602 int lfs_setquota(int argc, char **argv)
3605 struct if_quotactl qctl;
3606 char *mnt, *obd_type = (char *)qctl.obd_type;
3607 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3608 struct option long_opts[] = {
3609 {"block-softlimit", required_argument, 0, 'b'},
3610 {"block-hardlimit", required_argument, 0, 'B'},
3611 {"group", required_argument, 0, 'g'},
3612 {"inode-softlimit", required_argument, 0, 'i'},
3613 {"inode-hardlimit", required_argument, 0, 'I'},
3614 {"user", required_argument, 0, 'u'},
3615 {"projid", required_argument, 0, 'p'},
3618 unsigned limit_mask = 0;
3622 if (has_times_option(argc, argv))
3623 return lfs_setquota_times(argc, argv);
3625 memset(&qctl, 0, sizeof(qctl));
3626 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3627 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3628 * so it can be used as a marker that qc_type
3629 * isn't reinitialized from command line */
3631 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3632 long_opts, NULL)) != -1) {
3636 rc = name2uid(&qctl.qc_id, optarg);
3640 rc = name2gid(&qctl.qc_id, optarg);
3644 rc = name2projid(&qctl.qc_id, optarg);
3646 if (qctl.qc_type != ALLQUOTA) {
3647 fprintf(stderr, "error: -u and -g can't be used"
3648 " more than once\n");
3651 qctl.qc_type = qtype;
3653 qctl.qc_id = strtoul(optarg, &endptr, 10);
3654 if (*endptr != '\0') {
3655 fprintf(stderr, "error: can't find id "
3656 "for name %s\n", optarg);
3662 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3663 dqb->dqb_bsoftlimit >>= 10;
3664 limit_mask |= BSLIMIT;
3665 if (dqb->dqb_bsoftlimit &&
3666 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3667 fprintf(stderr, "warning: block softlimit is "
3668 "smaller than the miminal qunit size, "
3669 "please see the help of setquota or "
3670 "Lustre manual for details.\n");
3673 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3674 dqb->dqb_bhardlimit >>= 10;
3675 limit_mask |= BHLIMIT;
3676 if (dqb->dqb_bhardlimit &&
3677 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3678 fprintf(stderr, "warning: block hardlimit is "
3679 "smaller than the miminal qunit size, "
3680 "please see the help of setquota or "
3681 "Lustre manual for details.\n");
3684 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3685 limit_mask |= ISLIMIT;
3686 if (dqb->dqb_isoftlimit &&
3687 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3688 fprintf(stderr, "warning: inode softlimit is "
3689 "smaller than the miminal qunit size, "
3690 "please see the help of setquota or "
3691 "Lustre manual for details.\n");
3694 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3695 limit_mask |= IHLIMIT;
3696 if (dqb->dqb_ihardlimit &&
3697 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3698 fprintf(stderr, "warning: inode hardlimit is "
3699 "smaller than the miminal qunit size, "
3700 "please see the help of setquota or "
3701 "Lustre manual for details.\n");
3703 default: /* getopt prints error message for us when opterr != 0 */
3708 if (qctl.qc_type == ALLQUOTA) {
3709 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3713 if (limit_mask == 0) {
3714 fprintf(stderr, "error: at least one limit must be specified\n");
3718 if (optind != argc - 1) {
3719 fprintf(stderr, "error: unexpected parameters encountered\n");
3725 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3726 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3727 /* sigh, we can't just set blimits/ilimits */
3728 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3729 .qc_type = qctl.qc_type,
3730 .qc_id = qctl.qc_id};
3732 rc = llapi_quotactl(mnt, &tmp_qctl);
3734 fprintf(stderr, "error: setquota failed while retrieving"
3735 " current quota settings (%s)\n",
3740 if (!(limit_mask & BHLIMIT))
3741 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3742 if (!(limit_mask & BSLIMIT))
3743 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3744 if (!(limit_mask & IHLIMIT))
3745 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3746 if (!(limit_mask & ISLIMIT))
3747 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3749 /* Keep grace times if we have got no softlimit arguments */
3750 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3751 dqb->dqb_valid |= QIF_BTIME;
3752 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3755 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3756 dqb->dqb_valid |= QIF_ITIME;
3757 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3761 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3762 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3764 rc = llapi_quotactl(mnt, &qctl);
3767 fprintf(stderr, "%s %s ", obd_type,
3768 obd_uuid2str(&qctl.obd_uuid));
3769 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3776 /* Converts seconds value into format string
3777 * result is returned in buf
3779 * 1. result is in descenting order: 1w2d3h4m5s
3780 * 2. zero fields are not filled (except for p. 3): 5d1s
3781 * 3. zero seconds value is presented as "0s"
3783 static char * __sec2str(time_t seconds, char *buf)
3785 const char spec[] = "smhdw";
3786 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3791 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3792 c = seconds / mult[i];
3794 if (c > 0 || (i == 0 && buf == tail))
3795 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3803 static void sec2str(time_t seconds, char *buf, int rc)
3810 tail = __sec2str(seconds, tail);
3812 if (rc && tail - buf < 39) {
3818 static void diff2str(time_t seconds, char *buf, time_t now)
3824 if (seconds <= now) {
3825 strcpy(buf, "none");
3828 __sec2str(seconds - now, buf);
3831 static void print_quota_title(char *name, struct if_quotactl *qctl,
3832 bool human_readable)
3834 printf("Disk quotas for %s %s (%cid %u):\n",
3835 qtype_name(qctl->qc_type), name,
3836 *qtype_name(qctl->qc_type), qctl->qc_id);
3837 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3838 "Filesystem", human_readable ? "used" : "kbytes",
3839 "quota", "limit", "grace",
3840 "files", "quota", "limit", "grace");
3843 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3846 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3849 snprintf(buf, buflen, "%5.4gP",
3850 (double)num / ((__u64)1 << 40));
3852 snprintf(buf, buflen, "%5.4gT",
3853 (double)num / (1 << 30));
3855 snprintf(buf, buflen, "%5.4gG",
3856 (double)num / (1 << 20));
3858 snprintf(buf, buflen, "%5.4gM",
3859 (double)num / (1 << 10));
3861 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3865 #define STRBUF_LEN 32
3866 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3873 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3874 int bover = 0, iover = 0;
3875 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3876 char numbuf[3][STRBUF_LEN];
3878 char strbuf[STRBUF_LEN];
3880 if (dqb->dqb_bhardlimit &&
3881 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3883 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3884 if (dqb->dqb_btime > now) {
3891 if (dqb->dqb_ihardlimit &&
3892 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3894 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3895 if (dqb->dqb_itime > now) {
3903 if (strlen(mnt) > 15)
3904 printf("%s\n%15s", mnt, "");
3906 printf("%15s", mnt);
3909 diff2str(dqb->dqb_btime, timebuf, now);
3911 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3912 strbuf, sizeof(strbuf), h);
3913 if (rc == -EREMOTEIO)
3914 sprintf(numbuf[0], "%s*", strbuf);
3916 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3917 "%s" : "[%s]", strbuf);
3919 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3920 if (type == QC_GENERAL)
3921 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3922 "%s" : "[%s]", strbuf);
3924 sprintf(numbuf[1], "%s", "-");
3926 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3927 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3928 "%s" : "[%s]", strbuf);
3930 printf(" %7s%c %6s %7s %7s",
3931 numbuf[0], bover ? '*' : ' ', numbuf[1],
3932 numbuf[2], bover > 1 ? timebuf : "-");
3935 diff2str(dqb->dqb_itime, timebuf, now);
3937 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3938 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3940 if (type == QC_GENERAL)
3941 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3943 (uintmax_t)dqb->dqb_isoftlimit);
3945 sprintf(numbuf[1], "%s", "-");
3947 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3948 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3950 if (type != QC_OSTIDX)
3951 printf(" %7s%c %6s %7s %7s",
3952 numbuf[0], iover ? '*' : ' ', numbuf[1],
3953 numbuf[2], iover > 1 ? timebuf : "-");
3955 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3958 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3959 qctl->qc_cmd == Q_GETOINFO) {
3963 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3964 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3965 printf("Block grace time: %s; Inode grace time: %s\n",
3966 bgtimebuf, igtimebuf);
3970 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3971 bool h, __u64 *total)
3973 int rc = 0, rc1 = 0, count = 0;
3974 __u32 valid = qctl->qc_valid;
3976 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3978 fprintf(stderr, "can not get %s count: %s\n",
3979 is_mdt ? "mdt": "ost", strerror(-rc));
3983 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3984 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3985 rc = llapi_quotactl(mnt, qctl);
3987 /* It is remote client case. */
3988 if (rc == -EOPNOTSUPP) {
3995 fprintf(stderr, "quotactl %s%d failed.\n",
3996 is_mdt ? "mdt": "ost", qctl->qc_idx);
4000 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4001 qctl->qc_valid, 0, h);
4002 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4003 qctl->qc_dqblk.dqb_bhardlimit;
4006 qctl->qc_valid = valid;
4010 static int lfs_quota(int argc, char **argv)
4013 char *mnt, *name = NULL;
4014 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4015 .qc_type = ALLQUOTA };
4016 char *obd_type = (char *)qctl.obd_type;
4017 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4018 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4019 verbose = 0, pass = 0, quiet = 0, inacc;
4021 __u32 valid = QC_GENERAL, idx = 0;
4022 __u64 total_ialloc = 0, total_balloc = 0;
4023 bool human_readable = false;
4026 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4037 if (qctl.qc_type != ALLQUOTA) {
4038 fprintf(stderr, "error: use either -u or -g\n");
4041 qctl.qc_type = qtype;
4044 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4047 valid = qctl.qc_valid = QC_UUID;
4048 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4051 valid = qctl.qc_valid = QC_MDTIDX;
4052 idx = qctl.qc_idx = atoi(optarg);
4055 valid = qctl.qc_valid = QC_OSTIDX;
4056 idx = qctl.qc_idx = atoi(optarg);
4065 human_readable = true;
4068 fprintf(stderr, "error: %s: option '-%c' "
4069 "unrecognized\n", argv[0], c);
4074 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4075 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4076 optind == argc - 1) {
4078 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4079 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4080 qctl.qc_valid = valid;
4082 qctl.qc_type = pass;
4083 switch (qctl.qc_type) {
4085 qctl.qc_id = geteuid();
4086 rc = uid2name(&name, qctl.qc_id);
4089 qctl.qc_id = getegid();
4090 rc = gid2name(&name, qctl.qc_id);
4099 /* lfs quota -u username /path/to/lustre/mount */
4100 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4101 /* options should be followed by u/g-name and mntpoint */
4102 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4103 fprintf(stderr, "error: missing quota argument(s)\n");
4107 name = argv[optind++];
4108 switch (qctl.qc_type) {
4110 rc = name2uid(&qctl.qc_id, name);
4113 rc = name2gid(&qctl.qc_id, name);
4116 rc = name2projid(&qctl.qc_id, name);
4123 qctl.qc_id = strtoul(name, &endptr, 10);
4124 if (*endptr != '\0') {
4125 fprintf(stderr, "error: can't find id for name: %s\n",
4130 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4131 fprintf(stderr, "error: missing quota info argument(s)\n");
4136 rc1 = llapi_quotactl(mnt, &qctl);
4140 fprintf(stderr, "%s quotas are not enabled.\n",
4141 qtype_name(qctl.qc_type));
4144 fprintf(stderr, "Permission denied.\n");
4147 /* We already got error message. */
4150 fprintf(stderr, "Unexpected quotactl error: %s\n",
4155 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4156 print_quota_title(name, &qctl, human_readable);
4158 if (rc1 && *obd_type)
4159 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4161 if (qctl.qc_valid != QC_GENERAL)
4164 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4165 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4166 (QIF_LIMITS|QIF_USAGE));
4168 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4170 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4172 char strbuf[STRBUF_LEN];
4174 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4176 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4178 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4180 printf("Total allocated inode limit: %ju, total "
4181 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4185 if (rc1 || rc2 || rc3 || inacc)
4186 printf("Some errors happened when getting quota info. "
4187 "Some devices may be not working or deactivated. "
4188 "The data in \"[]\" is inaccurate.\n");
4191 if (pass > 0 && pass < LL_MAXQUOTAS)
4196 #endif /* HAVE_SYS_QUOTA_H! */
4198 static int flushctx_ioctl(char *mp)
4202 fd = open(mp, O_RDONLY);
4204 fprintf(stderr, "flushctx: error open %s: %s\n",
4205 mp, strerror(errno));
4209 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4211 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4212 mp, strerror(errno));
4218 static int lfs_flushctx(int argc, char **argv)
4220 int kdestroy = 0, c;
4221 char mntdir[PATH_MAX] = {'\0'};
4225 while ((c = getopt(argc, argv, "k")) != -1) {
4231 fprintf(stderr, "error: %s: option '-%c' "
4232 "unrecognized\n", argv[0], c);
4238 if ((rc = system("kdestroy > /dev/null")) != 0) {
4239 rc = WEXITSTATUS(rc);
4240 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4244 if (optind >= argc) {
4245 /* flush for all mounted lustre fs. */
4246 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4247 /* Check if we have a mount point */
4248 if (mntdir[0] == '\0')
4251 if (flushctx_ioctl(mntdir))
4254 mntdir[0] = '\0'; /* avoid matching in next loop */
4257 /* flush fs as specified */
4258 while (optind < argc) {
4259 if (flushctx_ioctl(argv[optind++]))
4266 static int lfs_cp(int argc, char **argv)
4268 fprintf(stderr, "remote client copy file(s).\n"
4269 "obsolete, does not support it anymore.\n");
4273 static int lfs_ls(int argc, char **argv)
4275 fprintf(stderr, "remote client lists directory contents.\n"
4276 "obsolete, does not support it anymore.\n");
4280 static int lfs_changelog(int argc, char **argv)
4282 void *changelog_priv;
4283 struct changelog_rec *rec;
4284 long long startrec = 0, endrec = 0;
4286 struct option long_opts[] = {
4287 {"follow", no_argument, 0, 'f'},
4290 char short_opts[] = "f";
4293 while ((rc = getopt_long(argc, argv, short_opts,
4294 long_opts, NULL)) != -1) {
4302 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4303 argv[0], argv[optind - 1]);
4310 mdd = argv[optind++];
4312 startrec = strtoll(argv[optind++], NULL, 10);
4314 endrec = strtoll(argv[optind++], NULL, 10);
4316 rc = llapi_changelog_start(&changelog_priv,
4317 CHANGELOG_FLAG_BLOCK |
4318 CHANGELOG_FLAG_JOBID |
4319 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4322 fprintf(stderr, "Can't start changelog: %s\n",
4323 strerror(errno = -rc));
4327 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4331 if (endrec && rec->cr_index > endrec) {
4332 llapi_changelog_free(&rec);
4335 if (rec->cr_index < startrec) {
4336 llapi_changelog_free(&rec);
4340 secs = rec->cr_time >> 30;
4341 gmtime_r(&secs, &ts);
4342 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4343 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4344 changelog_type2str(rec->cr_type),
4345 ts.tm_hour, ts.tm_min, ts.tm_sec,
4346 (int)(rec->cr_time & ((1 << 30) - 1)),
4347 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4348 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4350 if (rec->cr_flags & CLF_JOBID) {
4351 struct changelog_ext_jobid *jid =
4352 changelog_rec_jobid(rec);
4354 if (jid->cr_jobid[0] != '\0')
4355 printf(" j=%s", jid->cr_jobid);
4358 if (rec->cr_namelen)
4359 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4360 rec->cr_namelen, changelog_rec_name(rec));
4362 if (rec->cr_flags & CLF_RENAME) {
4363 struct changelog_ext_rename *rnm =
4364 changelog_rec_rename(rec);
4366 if (!fid_is_zero(&rnm->cr_sfid))
4367 printf(" s="DFID" sp="DFID" %.*s",
4368 PFID(&rnm->cr_sfid),
4369 PFID(&rnm->cr_spfid),
4370 (int)changelog_rec_snamelen(rec),
4371 changelog_rec_sname(rec));
4375 llapi_changelog_free(&rec);
4378 llapi_changelog_fini(&changelog_priv);
4381 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4383 return (rc == 1 ? 0 : rc);
4386 static int lfs_changelog_clear(int argc, char **argv)
4394 endrec = strtoll(argv[3], NULL, 10);
4396 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4399 fprintf(stderr, "%s: record out of range: %llu\n",
4401 else if (rc == -ENOENT)
4402 fprintf(stderr, "%s: no changelog user: %s\n",
4405 fprintf(stderr, "%s error: %s\n", argv[0],
4414 static int lfs_fid2path(int argc, char **argv)
4416 struct option long_opts[] = {
4417 {"cur", no_argument, 0, 'c'},
4418 {"link", required_argument, 0, 'l'},
4419 {"rec", required_argument, 0, 'r'},
4422 char short_opts[] = "cl:r:";
4423 char *device, *fid, *path;
4424 long long recno = -1;
4430 while ((rc = getopt_long(argc, argv, short_opts,
4431 long_opts, NULL)) != -1) {
4437 linkno = strtol(optarg, NULL, 10);
4440 recno = strtoll(optarg, NULL, 10);
4445 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4446 argv[0], argv[optind - 1]);
4454 device = argv[optind++];
4455 path = calloc(1, PATH_MAX);
4457 fprintf(stderr, "error: Not enough memory\n");
4462 while (optind < argc) {
4463 fid = argv[optind++];
4465 lnktmp = (linkno >= 0) ? linkno : 0;
4467 int oldtmp = lnktmp;
4468 long long rectmp = recno;
4470 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4473 fprintf(stderr, "%s: error on FID %s: %s\n",
4474 argv[0], fid, strerror(errno = -rc2));
4481 fprintf(stdout, "%lld ", rectmp);
4482 if (device[0] == '/') {
4483 fprintf(stdout, "%s", device);
4484 if (device[strlen(device) - 1] != '/')
4485 fprintf(stdout, "/");
4486 } else if (path[0] == '\0') {
4487 fprintf(stdout, "/");
4489 fprintf(stdout, "%s\n", path);
4492 /* specified linkno */
4494 if (oldtmp == lnktmp)
4504 static int lfs_path2fid(int argc, char **argv)
4506 struct option long_opts[] = {
4507 {"parents", no_argument, 0, 'p'},
4511 const char short_opts[] = "p";
4512 const char *sep = "";
4515 bool show_parents = false;
4517 while ((rc = getopt_long(argc, argv, short_opts,
4518 long_opts, NULL)) != -1) {
4521 show_parents = true;
4524 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4525 argv[0], argv[optind - 1]);
4530 if (optind > argc - 1)
4532 else if (optind < argc - 1)
4536 for (path = argv + optind; *path != NULL; path++) {
4538 if (!show_parents) {
4539 err = llapi_path2fid(*path, &fid);
4541 printf("%s%s"DFID"\n",
4542 *sep != '\0' ? *path : "", sep,
4545 char name[NAME_MAX + 1];
4546 unsigned int linkno = 0;
4548 while ((err = llapi_path2parent(*path, linkno, &fid,
4549 name, sizeof(name))) == 0) {
4550 if (*sep != '\0' && linkno == 0)
4551 printf("%s%s", *path, sep);
4553 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4558 /* err == -ENODATA is end-of-loop */
4559 if (linkno > 0 && err == -ENODATA) {
4566 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4567 argv[0], show_parents ? "parent " : "", *path,
4579 static int lfs_data_version(int argc, char **argv)
4586 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4591 while ((c = getopt(argc, argv, "nrw")) != -1) {
4594 data_version_flags = 0;
4597 data_version_flags |= LL_DV_RD_FLUSH;
4600 data_version_flags |= LL_DV_WR_FLUSH;
4609 path = argv[optind];
4610 fd = open(path, O_RDONLY);
4612 err(errno, "cannot open file %s", path);
4614 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4616 err(errno, "cannot get version for %s", path);
4618 printf("%ju" "\n", (uintmax_t)data_version);
4624 static int lfs_hsm_state(int argc, char **argv)
4629 struct hsm_user_state hus;
4637 rc = llapi_hsm_state_get(path, &hus);
4639 fprintf(stderr, "can't get hsm state for %s: %s\n",
4640 path, strerror(errno = -rc));
4644 /* Display path name and status flags */
4645 printf("%s: (0x%08x)", path, hus.hus_states);
4647 if (hus.hus_states & HS_RELEASED)
4648 printf(" released");
4649 if (hus.hus_states & HS_EXISTS)
4651 if (hus.hus_states & HS_DIRTY)
4653 if (hus.hus_states & HS_ARCHIVED)
4654 printf(" archived");
4655 /* Display user-settable flags */
4656 if (hus.hus_states & HS_NORELEASE)
4657 printf(" never_release");
4658 if (hus.hus_states & HS_NOARCHIVE)
4659 printf(" never_archive");
4660 if (hus.hus_states & HS_LOST)
4661 printf(" lost_from_hsm");
4663 if (hus.hus_archive_id != 0)
4664 printf(", archive_id:%d", hus.hus_archive_id);
4667 } while (++i < argc);
4672 #define LFS_HSM_SET 0
4673 #define LFS_HSM_CLEAR 1
4676 * Generic function to set or clear HSM flags.
4677 * Used by hsm_set and hsm_clear.
4679 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4681 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4683 struct option long_opts[] = {
4684 {"lost", 0, 0, 'l'},
4685 {"norelease", 0, 0, 'r'},
4686 {"noarchive", 0, 0, 'a'},
4687 {"archived", 0, 0, 'A'},
4688 {"dirty", 0, 0, 'd'},
4689 {"exists", 0, 0, 'e'},
4692 char short_opts[] = "lraAde";
4700 while ((c = getopt_long(argc, argv, short_opts,
4701 long_opts, NULL)) != -1) {
4707 mask |= HS_NOARCHIVE;
4710 mask |= HS_ARCHIVED;
4713 mask |= HS_NORELEASE;
4724 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4725 argv[0], argv[optind - 1]);
4730 /* User should have specified a flag */
4734 while (optind < argc) {
4736 path = argv[optind];
4738 /* If mode == 0, this means we apply the mask. */
4739 if (mode == LFS_HSM_SET)
4740 rc = llapi_hsm_state_set(path, mask, 0, 0);
4742 rc = llapi_hsm_state_set(path, 0, mask, 0);
4745 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4746 path, strerror(errno = -rc));
4755 static int lfs_hsm_action(int argc, char **argv)
4760 struct hsm_current_action hca;
4761 struct hsm_extent he;
4762 enum hsm_user_action hua;
4763 enum hsm_progress_states hps;
4771 rc = llapi_hsm_current_action(path, &hca);
4773 fprintf(stderr, "can't get hsm action for %s: %s\n",
4774 path, strerror(errno = -rc));
4777 he = hca.hca_location;
4778 hua = hca.hca_action;
4779 hps = hca.hca_state;
4781 printf("%s: %s", path, hsm_user_action2name(hua));
4783 /* Skip file without action */
4784 if (hca.hca_action == HUA_NONE) {
4789 printf(" %s ", hsm_progress_state2name(hps));
4791 if ((hps == HPS_RUNNING) &&
4792 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4793 printf("(%llu bytes moved)\n",
4794 (unsigned long long)he.length);
4795 else if ((he.offset + he.length) == LUSTRE_EOF)
4796 printf("(from %llu to EOF)\n",
4797 (unsigned long long)he.offset);
4799 printf("(from %llu to %llu)\n",
4800 (unsigned long long)he.offset,
4801 (unsigned long long)(he.offset + he.length));
4803 } while (++i < argc);
4808 static int lfs_hsm_set(int argc, char **argv)
4810 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4813 static int lfs_hsm_clear(int argc, char **argv)
4815 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4819 * Check file state and return its fid, to be used by lfs_hsm_request().
4821 * \param[in] file Path to file to check
4822 * \param[in,out] fid Pointer to allocated lu_fid struct.
4823 * \param[in,out] last_dev Pointer to last device id used.
4825 * \return 0 on success.
4827 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4833 rc = lstat(file, &st);
4835 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4838 /* Checking for regular file as archiving as posix copytool
4839 * rejects archiving files other than regular files
4841 if (!S_ISREG(st.st_mode)) {
4842 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4845 /* A request should be ... */
4846 if (*last_dev != st.st_dev && *last_dev != 0) {
4847 fprintf(stderr, "All files should be "
4848 "on the same filesystem: %s\n", file);
4851 *last_dev = st.st_dev;
4853 rc = llapi_path2fid(file, fid);
4855 fprintf(stderr, "Cannot read FID of %s: %s\n",
4856 file, strerror(-rc));
4862 /* Fill an HSM HUR item with a given file name.
4864 * If mntpath is set, then the filename is actually a FID, and no
4865 * lookup on the filesystem will be performed.
4867 * \param[in] hur the user request to fill
4868 * \param[in] idx index of the item inside the HUR to fill
4869 * \param[in] mntpath mountpoint of Lustre
4870 * \param[in] fname filename (if mtnpath is NULL)
4871 * or FID (if mntpath is set)
4872 * \param[in] last_dev pointer to last device id used
4874 * \retval 0 on success
4875 * \retval CMD_HELP or a negative errno on error
4877 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4878 const char *mntpath, const char *fname,
4881 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4884 hui->hui_extent.length = -1;
4886 if (mntpath != NULL) {
4889 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4893 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4898 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4902 hur->hur_request.hr_itemcount++;
4907 static int lfs_hsm_request(int argc, char **argv, int action)
4909 struct option long_opts[] = {
4910 {"filelist", 1, 0, 'l'},
4911 {"data", 1, 0, 'D'},
4912 {"archive", 1, 0, 'a'},
4913 {"mntpath", 1, 0, 'm'},
4917 char short_opts[] = "l:D:a:m:";
4918 struct hsm_user_request *hur, *oldhur;
4923 char *filelist = NULL;
4924 char fullpath[PATH_MAX];
4925 char *opaque = NULL;
4929 int nbfile_alloc = 0;
4930 char *some_file = NULL;
4931 char *mntpath = NULL;
4937 while ((c = getopt_long(argc, argv, short_opts,
4938 long_opts, NULL)) != -1) {
4947 if (action != HUA_ARCHIVE &&
4948 action != HUA_REMOVE) {
4950 "error: -a is supported only "
4951 "when archiving or removing\n");
4954 archive_id = atoi(optarg);
4957 if (some_file == NULL) {
4959 some_file = strdup(optarg);
4965 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4966 argv[0], argv[optind - 1]);
4971 /* All remaining args are files, so we have at least nbfile */
4972 nbfile = argc - optind;
4974 if ((nbfile == 0) && (filelist == NULL))
4978 opaque_len = strlen(opaque);
4980 /* Alloc the request structure with enough place to store all files
4981 * from command line. */
4982 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4984 fprintf(stderr, "Cannot create the request: %s\n",
4988 nbfile_alloc = nbfile;
4990 hur->hur_request.hr_action = action;
4991 hur->hur_request.hr_archive_id = archive_id;
4992 hur->hur_request.hr_flags = 0;
4994 /* All remaining args are files, add them */
4995 if (nbfile != 0 && some_file == NULL)
4996 some_file = strdup(argv[optind]);
4998 for (i = 0; i < nbfile; i++) {
4999 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5005 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5007 /* If a filelist was specified, read the filelist from it. */
5008 if (filelist != NULL) {
5009 fp = fopen(filelist, "r");
5011 fprintf(stderr, "Cannot read the file list %s: %s\n",
5012 filelist, strerror(errno));
5017 while ((rc = getline(&line, &len, fp)) != -1) {
5018 /* If allocated buffer was too small, get something
5020 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5023 nbfile_alloc = nbfile_alloc * 2 + 1;
5025 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5028 fprintf(stderr, "hsm: cannot allocate "
5029 "the request: %s\n",
5036 size = hur_len(oldhur);
5038 fprintf(stderr, "hsm: cannot allocate "
5039 "%u files + %u bytes data\n",
5040 oldhur->hur_request.hr_itemcount,
5041 oldhur->hur_request.hr_data_len);
5048 memcpy(hur, oldhur, size);
5053 if (line[strlen(line) - 1] == '\n')
5054 line[strlen(line) - 1] = '\0';
5056 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5057 mntpath, line, &last_dev);
5063 if (some_file == NULL) {
5073 /* If a --data was used, add it to the request */
5074 hur->hur_request.hr_data_len = opaque_len;
5076 memcpy(hur_data(hur), opaque, opaque_len);
5078 /* Send the HSM request */
5079 if (realpath(some_file, fullpath) == NULL) {
5080 fprintf(stderr, "Could not find path '%s': %s\n",
5081 some_file, strerror(errno));
5083 rc = llapi_hsm_request(fullpath, hur);
5085 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5086 some_file, strerror(-rc));
5096 static int lfs_hsm_archive(int argc, char **argv)
5098 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5101 static int lfs_hsm_restore(int argc, char **argv)
5103 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5106 static int lfs_hsm_release(int argc, char **argv)
5108 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5111 static int lfs_hsm_remove(int argc, char **argv)
5113 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5116 static int lfs_hsm_cancel(int argc, char **argv)
5118 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5121 static int lfs_swap_layouts(int argc, char **argv)
5126 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5127 SWAP_LAYOUTS_KEEP_MTIME |
5128 SWAP_LAYOUTS_KEEP_ATIME);
5131 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5133 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5135 enum lu_ladvise_type advice;
5138 advice < ARRAY_SIZE(ladvise_names); advice++) {
5139 if (ladvise_names[advice] == NULL)
5141 if (strcmp(string, ladvise_names[advice]) == 0)
5145 return LU_LADVISE_INVALID;
5148 static int lfs_ladvise(int argc, char **argv)
5150 struct option long_opts[] = {
5151 {"advice", required_argument, 0, 'a'},
5152 {"background", no_argument, 0, 'b'},
5153 {"end", required_argument, 0, 'e'},
5154 {"start", required_argument, 0, 's'},
5155 {"length", required_argument, 0, 'l'},
5158 char short_opts[] = "a:be:l:s:";
5163 struct llapi_lu_ladvise advice;
5164 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5165 unsigned long long start = 0;
5166 unsigned long long end = LUSTRE_EOF;
5167 unsigned long long length = 0;
5168 unsigned long long size_units;
5169 unsigned long long flags = 0;
5172 while ((c = getopt_long(argc, argv, short_opts,
5173 long_opts, NULL)) != -1) {
5176 advice_type = lfs_get_ladvice(optarg);
5177 if (advice_type == LU_LADVISE_INVALID) {
5178 fprintf(stderr, "%s: invalid advice type "
5179 "'%s'\n", argv[0], optarg);
5180 fprintf(stderr, "Valid types:");
5182 for (advice_type = 0;
5183 advice_type < ARRAY_SIZE(ladvise_names);
5185 if (ladvise_names[advice_type] == NULL)
5187 fprintf(stderr, " %s",
5188 ladvise_names[advice_type]);
5190 fprintf(stderr, "\n");
5200 rc = llapi_parse_size(optarg, &end,
5203 fprintf(stderr, "%s: bad end offset '%s'\n",
5210 rc = llapi_parse_size(optarg, &start,
5213 fprintf(stderr, "%s: bad start offset "
5214 "'%s'\n", argv[0], optarg);
5220 rc = llapi_parse_size(optarg, &length,
5223 fprintf(stderr, "%s: bad length '%s'\n",
5231 fprintf(stderr, "%s: option '%s' unrecognized\n",
5232 argv[0], argv[optind - 1]);
5237 if (advice_type == LU_LADVISE_INVALID) {
5238 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5239 fprintf(stderr, "Valid types:");
5240 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5242 if (ladvise_names[advice_type] == NULL)
5244 fprintf(stderr, " %s", ladvise_names[advice_type]);
5246 fprintf(stderr, "\n");
5250 if (argc <= optind) {
5251 fprintf(stderr, "%s: please give one or more file names\n",
5256 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5257 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5262 if (end == LUSTRE_EOF && length != 0)
5263 end = start + length;
5266 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5267 argv[0], start, end);
5271 while (optind < argc) {
5274 path = argv[optind++];
5276 fd = open(path, O_RDONLY);
5278 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5279 argv[0], path, strerror(errno));
5284 advice.lla_start = start;
5285 advice.lla_end = end;
5286 advice.lla_advice = advice_type;
5287 advice.lla_value1 = 0;
5288 advice.lla_value2 = 0;
5289 advice.lla_value3 = 0;
5290 advice.lla_value4 = 0;
5291 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5294 fprintf(stderr, "%s: cannot give advice '%s' to file "
5295 "'%s': %s\n", argv[0],
5296 ladvise_names[advice_type],
5297 path, strerror(errno));
5300 if (rc == 0 && rc2 < 0)
5306 static int lfs_list_commands(int argc, char **argv)
5308 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5310 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5315 int main(int argc, char **argv)
5319 /* Ensure that liblustreapi constructor has run */
5320 if (!liblustreapi_initialized)
5321 fprintf(stderr, "liblustreapi was not properly initialized\n");
5325 Parser_init("lfs > ", cmdlist);
5327 progname = argv[0]; /* Used in error messages */
5329 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5331 rc = Parser_commands();
5334 return rc < 0 ? -rc : rc;
5337 #ifdef _LUSTRE_IDL_H_
5338 /* Everything we need here should be included by lustreapi.h. */
5339 # error "lfs should not depend on lustre_idl.h"
5340 #endif /* _LUSTRE_IDL_H_ */