4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
57 #include <sys/types.h>
64 #include <libcfs/util/string.h>
65 #include <libcfs/util/ioctl.h>
66 #include <libcfs/util/parser.h>
67 #include <lustre/lustreapi.h>
68 #include <lustre_ver.h>
69 #include <lustre_param.h>
72 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
73 #endif /* !ARRAY_SIZE */
76 static int lfs_setstripe(int argc, char **argv);
77 static int lfs_find(int argc, char **argv);
78 static int lfs_getstripe(int argc, char **argv);
79 static int lfs_getdirstripe(int argc, char **argv);
80 static int lfs_setdirstripe(int argc, char **argv);
81 static int lfs_rmentry(int argc, char **argv);
82 static int lfs_osts(int argc, char **argv);
83 static int lfs_mdts(int argc, char **argv);
84 static int lfs_df(int argc, char **argv);
85 static int lfs_getname(int argc, char **argv);
86 static int lfs_check(int argc, char **argv);
87 #ifdef HAVE_SYS_QUOTA_H
88 static int lfs_setquota(int argc, char **argv);
89 static int lfs_quota(int argc, char **argv);
91 static int lfs_flushctx(int argc, char **argv);
92 static int lfs_cp(int argc, char **argv);
93 static int lfs_ls(int argc, char **argv);
94 static int lfs_poollist(int argc, char **argv);
95 static int lfs_changelog(int argc, char **argv);
96 static int lfs_changelog_clear(int argc, char **argv);
97 static int lfs_fid2path(int argc, char **argv);
98 static int lfs_path2fid(int argc, char **argv);
99 static int lfs_data_version(int argc, char **argv);
100 static int lfs_hsm_state(int argc, char **argv);
101 static int lfs_hsm_set(int argc, char **argv);
102 static int lfs_hsm_clear(int argc, char **argv);
103 static int lfs_hsm_action(int argc, char **argv);
104 static int lfs_hsm_archive(int argc, char **argv);
105 static int lfs_hsm_restore(int argc, char **argv);
106 static int lfs_hsm_release(int argc, char **argv);
107 static int lfs_hsm_remove(int argc, char **argv);
108 static int lfs_hsm_cancel(int argc, char **argv);
109 static int lfs_swap_layouts(int argc, char **argv);
110 static int lfs_mv(int argc, char **argv);
111 static int lfs_ladvise(int argc, char **argv);
112 static int lfs_list_commands(int argc, char **argv);
114 /* Setstripe and migrate share mostly the same parameters */
115 #define SSM_CMD_COMMON(cmd) \
116 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
117 " [--stripe-index|-i <start_ost_idx>]\n" \
118 " [--stripe-size|-S <stripe_size>]\n" \
119 " [--pool|-p <pool_name>]\n" \
120 " [--ost|-o <ost_indices>]\n" \
121 " [--component-end|-E <comp_end>]\n"
123 #define SSM_HELP_COMMON \
124 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
125 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
126 "\t respectively)\n" \
127 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
128 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
129 "\tpool_name: Name of OST pool to use (default none)\n" \
130 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
131 "\t Indices be specified in a format of:\n" \
132 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
134 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
135 "\t If --pool is set with --ost, then the OSTs\n" \
136 "\t must be the members of the pool." \
137 "\tcomp_end: Extent end of the component\n" \
138 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
139 "\t respectively, -1 for EOF), it must be aligned with\n"\
140 "\t the stripe_size\n"
142 #define SETSTRIPE_USAGE \
143 SSM_CMD_COMMON("setstripe") \
144 " <directory|filename>\n" \
147 #define MIGRATE_USAGE \
148 SSM_CMD_COMMON("migrate ") \
150 " [--non-block|-n]\n" \
154 "\tblock: Block file access during data migration (default)\n" \
155 "\tnon-block: Abort migrations if concurrent access is detected\n" \
157 #define SETDIRSTRIPE_USAGE \
158 " [--mdt-count|-c stripe_count>\n" \
159 " [--mdt-index|-i mdt_index]\n" \
160 " [--mdt-hash|-H mdt_hash]\n" \
161 " [--default|-D] [--mode|-m mode] <dir>\n" \
162 "\tstripe_count: stripe count of the striped directory\n" \
163 "\tmdt_index: MDT index of first stripe\n" \
164 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
165 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
166 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
167 "\tdefault_stripe: set default dirstripe of the directory\n" \
168 "\tmode: the mode of the directory\n"
170 static const char *progname;
171 static bool file_lease_supported = true;
173 /* all available commands */
174 command_t cmdlist[] = {
175 {"setstripe", lfs_setstripe, 0,
176 "Create a new file with a specific striping pattern or\n"
177 "set the default striping pattern on an existing directory or\n"
178 "delete the default striping pattern from an existing directory or\n"
179 "add layout component(s) to an existing composite file or\n"
180 "delete specified component(s) from an existing composite file\n\n"
181 "To delete default striping from an existing directory:\n"
182 "usage: setstripe -d <directory>\n"
184 "To delete component(s) from an existing composite file:\n"
185 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
186 " [--component-flags|-F <comp_flags>]\n"
188 "\tcomp_id: Unique component ID\n"
189 "\tcomp_flags: 'init' indicating all instantiated components\n"
190 "\t-I and -F can't be specified at the same time\n"
192 "To add component(s) to an existing composite file:\n"
193 SSM_CMD_COMMON("setstripe --component-add")
195 "To create a file with specified striping/composite layout:\n"
197 {"getstripe", lfs_getstripe, 0,
198 "To list the striping info for a given file or files in a\n"
199 "directory or recursively for all files in a directory tree.\n"
200 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
201 " [--stripe-count|-c] [--stripe-index|-i]\n"
202 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
203 " [--mdt|-m] [--recursive|-r] [--raw|-R]\n"
204 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
205 " [--component-id|-I [comp_id]]\n"
206 " [--component-flags [comp_flags]]\n"
207 " [--component-count [comp_count]]\n"
208 " [--component-start [comp_start]]\n"
209 " [--component-end|-E [comp_end]]\n"
210 " <directory|filename> ..."},
211 {"setdirstripe", lfs_setdirstripe, 0,
212 "To create a striped directory on a specified MDT. This can only\n"
213 "be done on MDT0 with the right of administrator.\n"
214 "usage: setdirstripe [OPTION] <directory>\n"
216 {"getdirstripe", lfs_getdirstripe, 0,
217 "To list the striping info for a given directory\n"
218 "or recursively for all directories in a directory tree.\n"
219 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
220 " [--mdt-index|-i] [--mdt-hash|-H]\n"
221 " [--recursive|-r] [--default|-D] <dir> ..."},
222 {"mkdir", lfs_setdirstripe, 0,
223 "To create a striped directory on a specified MDT. This can only\n"
224 "be done on MDT0 with the right of administrator.\n"
225 "usage: mkdir [OPTION] <directory>\n"
227 {"rm_entry", lfs_rmentry, 0,
228 "To remove the name entry of the remote directory. Note: This\n"
229 "command will only delete the name entry, i.e. the remote directory\n"
230 "will become inaccessable after this command. This can only be done\n"
231 "by the administrator\n"
232 "usage: rm_entry <dir>\n"},
233 {"pool_list", lfs_poollist, 0,
234 "List pools or pool OSTs\n"
235 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
236 {"find", lfs_find, 0,
237 "find files matching given attributes recursively in directory tree.\n"
238 "usage: find <directory|filename> ...\n"
239 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
240 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
241 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
242 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
243 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
244 " [[!] --stripe-count|-c [+-]<stripes>]\n"
245 " [[!] --stripe-index|-i <index,...>]\n"
246 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
247 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
248 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
249 " [[!] --layout|-L released,raid0]\n"
250 " [[!] --component-count [+-]<comp_cnt>]\n"
251 " [[!] --component-start [+-]N[kMGTPE]]\n"
252 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
253 " [[!] --component-flags <comp_flags>]\n"
254 " [[!] --mdt-count|-T [+-]<stripes>]\n"
255 " [[!] --mdt-hash|-H <hashtype>\n"
256 "\t !: used before an option indicates 'NOT' requested attribute\n"
257 "\t -: used before a value indicates 'AT MOST' requested value\n"
258 "\t +: used before a value indicates 'AT LEAST' requested value\n"
259 "\tmdt-hash: hash type of the striped directory.\n"
260 "\t fnv_1a_64 FNV-1a hash algorithm\n"
261 "\t all_char sum of characters % MDT_COUNT\n"},
262 {"check", lfs_check, 0,
263 "Display the status of MDS or OSTs (as specified in the command)\n"
264 "or all the servers (MDS and OSTs).\n"
265 "usage: check <osts|mds|servers>"},
266 {"osts", lfs_osts, 0, "list OSTs connected to client "
267 "[for specified path only]\n" "usage: osts [path]"},
268 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
269 "[for specified path only]\n" "usage: mdts [path]"},
271 "report filesystem disk space usage or inodes usage"
272 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
273 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
274 {"getname", lfs_getname, 0, "list instances and specified mount points "
275 "[for specified path only]\n"
276 "Usage: getname [-h]|[path ...] "},
277 #ifdef HAVE_SYS_QUOTA_H
278 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
279 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
280 " -b <block-softlimit> -B <block-hardlimit>\n"
281 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
282 " setquota <-u|--user|-g|--group|-p|--project> <uname>|<uid>|<gname>|<gid>|<projid>\n"
283 " [--block-softlimit <block-softlimit>]\n"
284 " [--block-hardlimit <block-hardlimit>]\n"
285 " [--inode-softlimit <inode-softlimit>]\n"
286 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
287 " setquota [-t] <-u|--user|-g|--group|-p|--project>\n"
288 " [--block-grace <block-grace>]\n"
289 " [--inode-grace <inode-grace>] <filesystem>\n"
290 " -b can be used instead of --block-softlimit/--block-grace\n"
291 " -B can be used instead of --block-hardlimit\n"
292 " -i can be used instead of --inode-softlimit/--inode-grace\n"
293 " -I can be used instead of --inode-hardlimit\n\n"
294 "Note: The total quota space will be split into many qunits and\n"
295 " balanced over all server targets, the minimal qunit size is\n"
296 " 1M bytes for block space and 1K inodes for inode space.\n\n"
297 " Quota space rebalancing process will stop when this mininum\n"
298 " value is reached. As a result, quota exceeded can be returned\n"
299 " while many targets still have 1MB or 1K inodes of spare\n"
301 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
302 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
304 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
305 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
307 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
308 "usage: flushctx [-k] [mountpoint...]"},
310 "Remote user copy files and directories.\n"
311 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
313 "Remote user list directory contents.\n"
314 "usage: ls [OPTION]... [FILE]..."},
315 {"changelog", lfs_changelog, 0,
316 "Show the metadata changes on an MDT."
317 "\nusage: changelog <mdtname> [startrec [endrec]]"},
318 {"changelog_clear", lfs_changelog_clear, 0,
319 "Indicate that old changelog records up to <endrec> are no longer of "
320 "interest to consumer <id>, allowing the system to free up space.\n"
321 "An <endrec> of 0 means all records.\n"
322 "usage: changelog_clear <mdtname> <id> <endrec>"},
323 {"fid2path", lfs_fid2path, 0,
324 "Resolve the full path(s) for given FID(s). For a specific hardlink "
325 "specify link number <linkno>.\n"
326 /* "For a historical link name, specify changelog record <recno>.\n" */
327 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
328 /* [ --rec <recno> ] */ },
329 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
330 "usage: path2fid [--parents] <path> ..."},
331 {"data_version", lfs_data_version, 0, "Display file data version for "
332 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
333 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
334 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
335 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
336 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
337 "[--archived] [--lost] <file> ..."},
338 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
340 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
341 "[--archived] [--lost] <file> ..."},
342 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
343 "given files.\n" "usage: hsm_action <file> ..."},
344 {"hsm_archive", lfs_hsm_archive, 0,
345 "Archive file to external storage.\n"
346 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
348 {"hsm_restore", lfs_hsm_restore, 0,
349 "Restore file from external storage.\n"
350 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
351 {"hsm_release", lfs_hsm_release, 0,
352 "Release files from Lustre.\n"
353 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
354 {"hsm_remove", lfs_hsm_remove, 0,
355 "Remove file copy from external storage.\n"
356 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
357 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
359 "Note: To remove files from the archive that have been deleted on\n"
360 "Lustre, set mntpath and optionally archive. In that case, all the\n"
361 "positional arguments and entries in the file list must be FIDs."
363 {"hsm_cancel", lfs_hsm_cancel, 0,
364 "Cancel requests related to specified files.\n"
365 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
366 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
367 "usage: swap_layouts <path1> <path2>"},
368 {"migrate", lfs_setstripe, 0,
369 "migrate a directory between MDTs.\n"
370 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
372 "\tmdt_idx: index of the destination MDT\n"
374 "migrate file objects from one OST "
375 "layout\nto another (may be not safe with concurent writes).\n"
377 "[--stripe-count|-c] <stripe_count>\n"
378 " [--stripe-index|-i] <start_ost_index>\n"
379 " [--stripe-size|-S] <stripe_size>\n"
380 " [--pool|-p] <pool_name>\n"
381 " [--ost-list|-o] <ost_indices>\n"
383 " [--non-block|-n]\n"
384 " <file|directory>\n"
385 "\tstripe_count: number of OSTs to stripe a file over\n"
386 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
387 "\tstripe_size: number of bytes to store before moving to the next OST\n"
388 "\tpool_name: name of the predefined pool of OSTs\n"
389 "\tost_indices: OSTs to stripe over, in order\n"
390 "\tblock: wait for the operation to return before continuing\n"
391 "\tnon-block: do not wait for the operation to return.\n"},
393 "To move directories between MDTs. This command is deprecated, "
394 "use \"migrate\" instead.\n"
395 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
397 {"ladvise", lfs_ladvise, 0,
398 "Provide servers with advice about access patterns for a file.\n"
399 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
400 " [--background|-b]\n"
401 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
403 {"help", Parser_help, 0, "help"},
404 {"exit", Parser_quit, 0, "quit"},
405 {"quit", Parser_quit, 0, "quit"},
406 {"--version", Parser_version, 0,
407 "output build version of the utility and exit"},
408 {"--list-commands", lfs_list_commands, 0,
409 "list commands supported by the utility and exit"},
414 #define MIGRATION_NONBLOCK 1
416 static int check_hashtype(const char *hashtype)
420 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
421 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
428 * Internal helper for migrate_copy_data(). Check lease and report error if
431 * \param[in] fd File descriptor on which to check the lease.
432 * \param[out] lease_broken Set to true if the lease was broken.
433 * \param[in] group_locked Whether a group lock was taken or not.
434 * \param[in] path Name of the file being processed, for error
437 * \retval 0 Migration can keep on going.
438 * \retval -errno Error occurred, abort migration.
440 static int check_lease(int fd, bool *lease_broken, bool group_locked,
445 if (!file_lease_supported)
448 rc = llapi_lease_check(fd);
450 return 0; /* llapi_check_lease returns > 0 on success. */
453 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
455 rc = rc ? rc : -EAGAIN;
457 fprintf(stderr, "%s: external attempt to access file '%s' "
458 "blocked until migration ends.\n", progname, path);
461 *lease_broken = true;
465 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
466 bool group_locked, const char *fname)
475 bool lease_broken = false;
477 /* Use a page-aligned buffer for direct I/O */
478 rc = posix_memalign(&buf, getpagesize(), buf_size);
483 /* read new data only if we have written all
484 * previously read data */
487 rc = check_lease(fd_src, &lease_broken,
488 group_locked, fname);
492 rsize = read(fd_src, buf, buf_size);
495 fprintf(stderr, "%s: %s: read failed: %s\n",
496 progname, fname, strerror(-rc));
506 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
510 "%s: %s: write failed on volatile: %s\n",
511 progname, fname, strerror(-rc));
521 fprintf(stderr, "%s: %s: fsync failed: %s\n",
522 progname, fname, strerror(-rc));
530 static int migrate_copy_timestamps(int fdv, const struct stat *st)
532 struct timeval tv[2] = {
533 {.tv_sec = st->st_atime},
534 {.tv_sec = st->st_mtime}
537 return futimes(fdv, tv);
540 static int migrate_block(int fd, int fdv, const struct stat *st,
541 size_t buf_size, const char *name)
548 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
550 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
551 progname, name, strerror(-rc));
559 /* The grouplock blocks all concurrent accesses to the file.
560 * It has to be taken after llapi_get_data_version as it would
562 rc = llapi_group_lock(fd, gid);
564 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
565 progname, name, strerror(-rc));
569 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
571 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
575 /* Make sure we keep original atime/mtime values */
576 rc = migrate_copy_timestamps(fdv, st);
578 fprintf(stderr, "%s: %s: timestamp copy failed\n",
584 * for a migration we need to check data version on file did
587 * Pass in gid=0 since we already own grouplock. */
588 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
589 SWAP_LAYOUTS_CHECK_DV1);
591 fprintf(stderr, "%s: %s: dataversion changed during copy, "
592 "migration aborted\n", progname, name);
595 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
596 name, strerror(-rc));
601 rc2 = llapi_group_unlock(fd, gid);
602 if (rc2 < 0 && rc == 0) {
603 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
604 progname, name, strerror(-rc2));
611 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
612 size_t buf_size, const char *name)
618 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
620 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
621 progname, name, strerror(-rc));
625 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
627 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
631 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
633 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
634 progname, name, strerror(-rc));
640 fprintf(stderr, "%s: %s: data version changed during "
646 /* Make sure we keep original atime/mtime values */
647 rc = migrate_copy_timestamps(fdv, st);
649 fprintf(stderr, "%s: %s: timestamp copy failed\n",
654 /* Atomically put lease, swap layouts and close.
655 * for a migration we need to check data version on file did
657 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
659 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
660 progname, name, strerror(-rc));
667 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
672 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
676 if (flags != 0 && comp_id != 0)
679 /* LCME_FL_INIT is the only supported flag in PFL */
681 if (flags & ~LCME_KNOWN_FLAGS) {
682 fprintf(stderr, "Invalid component flags %#x\n", flags);
685 comp_id = LCME_ID_NONE | flags;
686 } else if (comp_id > LCME_ID_MAX) {
687 fprintf(stderr, "Invalid component id %u\n", comp_id);
691 rc = llapi_layout_file_comp_del(fname, comp_id);
693 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
694 comp_id, fname, strerror(errno));
698 static int lfs_component_add(char *fname, struct llapi_layout *layout)
705 rc = llapi_layout_file_comp_add(fname, layout);
707 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
708 fname, strerror(errno));
712 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
713 struct llapi_layout *layout)
721 fd = lstat(fname, &st);
722 if (fd == 0 && S_ISDIR(st.st_mode))
723 open_flags = O_DIRECTORY | O_RDONLY;
725 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
727 fprintf(stderr, "%s %s failed. %s\n",
728 S_ISDIR(st.st_mode) ?
729 "Set default composite layout to " :
730 "Create composite file",
731 fname, strerror(errno));
735 static int lfs_migrate(char *name, __u64 migration_flags,
736 struct llapi_stripe_param *param,
737 struct llapi_layout *layout)
741 char parent[PATH_MAX];
744 char volatile_file[sizeof(parent) +
745 LUSTRE_VOLATILE_HDR_LEN +
746 2 * sizeof(mdt_index) +
747 2 * sizeof(random_value) + 4];
750 struct lov_user_md *lum = NULL;
752 int buf_size = 1024 * 1024 * 4;
753 bool have_lease_rdlck = false;
757 /* find the right size for the IO and allocate the buffer */
758 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
759 lum = malloc(lum_size);
765 rc = llapi_file_get_stripe(name, lum);
766 /* failure can happen for many reasons and some may be not real errors
768 * in case of a real error, a later call will fail with better
769 * error management */
771 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
772 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
773 lum->lmm_stripe_size != 0)
774 buf_size = lum->lmm_stripe_size;
777 /* open file, direct io */
778 /* even if the file is only read, WR mode is nedeed to allow
779 * layout swap on fd */
780 fd = open(name, O_RDWR | O_DIRECT);
783 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
788 if (file_lease_supported) {
789 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
790 if (rc == -EOPNOTSUPP) {
791 /* Older servers do not support file lease.
792 * Disable related checks. This opens race conditions
793 * as explained in LU-4840 */
794 file_lease_supported = false;
796 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
797 progname, name, strerror(-rc));
800 have_lease_rdlck = true;
804 /* search for file directory pathname */
805 if (strlen(name) > sizeof(parent)-1) {
809 strncpy(parent, name, sizeof(parent));
810 ptr = strrchr(parent, '/');
812 if (getcwd(parent, sizeof(parent)) == NULL) {
823 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
825 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
826 progname, name, strerror(-rc));
831 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
832 mode_t open_mode = S_IRUSR | S_IWUSR;
834 random_value = random();
835 rc = snprintf(volatile_file, sizeof(volatile_file),
836 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
837 mdt_index, random_value);
838 if (rc >= sizeof(volatile_file)) {
843 /* create, open a volatile file, use caching (ie no directio) */
845 fdv = llapi_file_open_param(volatile_file, open_flags,
847 else if (layout != NULL)
848 fdv = lfs_component_create(volatile_file, open_flags,
852 } while (fdv == -EEXIST);
856 fprintf(stderr, "%s: %s: cannot create volatile file in"
858 progname, parent, strerror(-rc));
862 /* In case the MDT does not support creation of volatile files
863 * we should try to unlink it. */
864 (void)unlink(volatile_file);
866 /* Not-owner (root?) special case.
867 * Need to set owner/group of volatile file like original.
868 * This will allow to pass related check during layout_swap.
873 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
877 rc = fstat(fdv, &stv);
880 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
881 volatile_file, strerror(errno));
884 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
885 rc = fchown(fdv, st.st_uid, st.st_gid);
888 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
889 name, strerror(errno));
894 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
895 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
897 have_lease_rdlck = false;
898 fdv = -1; /* The volatile file is closed as we put the
899 * lease in non-blocking mode. */
902 /* Blocking mode (forced if servers do not support file lease).
903 * It is also the default mode, since we cannot distinguish
904 * between a broken lease and a server that does not support
905 * atomic swap/close (LU-6785) */
906 rc = migrate_block(fd, fdv, &st, buf_size, name);
910 if (have_lease_rdlck)
927 * Parse a string containing an OST index list into an array of integers.
929 * The input string contains a comma delimited list of individual
930 * indices and ranges, for example "1,2-4,7". Add the indices into the
931 * \a osts array and remove duplicates.
933 * \param[out] osts array to store indices in
934 * \param[in] size size of \a osts array
935 * \param[in] offset starting index in \a osts
936 * \param[in] arg string containing OST index list
938 * \retval positive number of indices in \a osts
939 * \retval -EINVAL unable to parse \a arg
941 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
945 int slots = size - offset;
953 while (!end_of_loop) {
961 ptr = strchrnul(arg, ',');
963 end_of_loop = *ptr == '\0';
966 start_index = strtol(arg, &endptr, 0);
967 if (endptr == arg) /* no data at all */
969 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
974 end_index = start_index;
975 if (*endptr == '-') {
976 end_index = strtol(endptr + 1, &endptr, 0);
979 if (end_index < start_index)
983 for (i = start_index; i <= end_index && slots > 0; i++) {
986 /* remove duplicate */
987 for (j = 0; j < offset; j++) {
991 if (j == offset) { /* no duplicate */
996 if (slots == 0 && i < end_index)
1004 if (!end_of_loop && ptr != NULL)
1007 return rc < 0 ? rc : nr;
1010 static int verify_pool_name(char *prog_name, char *pool_name)
1015 if (pool_name == NULL)
1018 ptr = strchr(pool_name, '.');
1022 if (ptr == pool_name) {
1023 fprintf(stderr, "error: %s: fsname is empty "
1024 "in pool name '%s'\n",
1025 prog_name, pool_name);
1031 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1033 fprintf(stderr, "error: %s: poolname '%s' is empty\n",
1034 prog_name, pool_name);
1036 } else if (rc == -2) {
1037 fprintf(stderr, "error: %s: pool name '%s' is too long "
1038 "(max is %d characters)\n",
1039 prog_name, pool_name, LOV_MAXPOOLNAME);
1041 } else if (rc > 0) {
1042 fprintf(stderr, "error: %s: char '%c' not allowed in "
1044 prog_name, rc, pool_name);
1050 struct lfs_setstripe_args {
1052 unsigned long long lsa_stripe_size;
1053 int lsa_stripe_count;
1055 __u32 lsa_comp_flags;
1058 char *lsa_pool_name;
1061 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1063 memset(lsa, 0, sizeof(*lsa));
1064 lsa->lsa_stripe_off = -1;
1067 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1069 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1070 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1071 lsa->lsa_comp_end != 0);
1074 static int comp_args_to_layout(struct llapi_layout **composite,
1075 struct lfs_setstripe_args *lsa)
1077 struct llapi_layout *layout = *composite;
1078 uint64_t prev_end = 0;
1081 if (layout == NULL) {
1082 layout = llapi_layout_alloc();
1083 if (layout == NULL) {
1084 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1088 *composite = layout;
1092 /* Get current component extent, current component
1093 * must be the tail component. */
1094 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1096 fprintf(stderr, "Get comp extent failed. %s\n",
1101 rc = llapi_layout_comp_add(layout);
1103 fprintf(stderr, "Add component failed. %s\n",
1109 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1111 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1112 prev_end, lsa->lsa_comp_end, strerror(errno));
1116 if (lsa->lsa_stripe_size != 0) {
1117 rc = llapi_layout_stripe_size_set(layout,
1118 lsa->lsa_stripe_size);
1120 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1121 lsa->lsa_stripe_size, strerror(errno));
1126 if (lsa->lsa_stripe_count != 0) {
1127 rc = llapi_layout_stripe_count_set(layout,
1128 lsa->lsa_stripe_count == -1 ?
1130 lsa->lsa_stripe_count);
1132 fprintf(stderr, "Set stripe count %d failed. %s\n",
1133 lsa->lsa_stripe_count, strerror(errno));
1138 if (lsa->lsa_pool_name != NULL) {
1139 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1141 fprintf(stderr, "Set pool name: %s failed. %s\n",
1142 lsa->lsa_pool_name, strerror(errno));
1147 if (lsa->lsa_nr_osts > 0) {
1148 if (lsa->lsa_stripe_count > 0 &&
1149 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1150 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1151 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1154 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1155 rc = llapi_layout_ost_index_set(layout, i,
1160 } else if (lsa->lsa_stripe_off != -1) {
1161 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1164 fprintf(stderr, "Set ost index %d failed. %s\n",
1165 i, strerror(errno));
1172 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1173 * end of the last component in the existing file, and adjust the
1174 * first extent start of the components to be added accordingly. */
1175 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1177 struct llapi_layout *head;
1178 uint64_t start, end, stripe_size, prev_end = 0;
1184 head = llapi_layout_get_by_path(fname, 0);
1186 fprintf(stderr, "Read layout from %s failed. %s\n",
1187 fname, strerror(errno));
1191 /* Current component of 'head' should be tail of component list. */
1192 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1194 fprintf(stderr, "Get prev extent failed. %s\n",
1196 llapi_layout_free(head);
1200 llapi_layout_free(head);
1202 /* Make sure we use the first component of the layout to be added. */
1203 rc = llapi_layout_comp_move(layout, LLAPI_LAYOUT_COMP_POS_FIRST);
1205 fprintf(stderr, "Move component cursor failed. %s\n",
1210 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1212 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1216 if (start > prev_end || end <= prev_end) {
1217 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1218 "adjacent with the existing file extent end: %lu\n",
1219 start, end, prev_end);
1223 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1225 fprintf(stderr, "Get stripe size failed. %s\n",
1230 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1231 (prev_end & (stripe_size - 1))) {
1232 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1233 stripe_size, prev_end);
1237 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1239 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1240 prev_end, end, strerror(errno));
1247 static int comp_name2flags(__u32 *flags, char *name)
1255 for (ptr = name; ; ptr = NULL) {
1256 char *flg = strtok(ptr, ",");
1259 if (strcmp(flg, "init") == 0)
1260 *flags |= LCME_FL_INIT;
1264 return (*flags == 0) ? -EINVAL : 0;
1278 static int lfs_setstripe(int argc, char **argv)
1280 struct lfs_setstripe_args lsa;
1281 struct llapi_stripe_param *param = NULL;
1282 struct find_param migrate_mdt_param = {
1292 char *mdt_idx_arg = NULL;
1293 unsigned long long size_units = 1;
1294 bool migrate_mode = false;
1295 bool migration_block = false;
1296 __u64 migration_flags = 0;
1297 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1298 int comp_del = 0, comp_set = 0;
1301 struct llapi_layout *layout = NULL;
1303 struct option long_opts[] = {
1304 /* --block is only valid in migrate mode */
1305 {"block", no_argument, 0, 'b'},
1306 {"comp-add", no_argument, 0, LFS_COMP_ADD_OPT},
1307 {"component-add", no_argument, 0, LFS_COMP_ADD_OPT},
1308 {"comp-del", no_argument, 0, LFS_COMP_DEL_OPT},
1309 {"component-del", no_argument, 0, LFS_COMP_DEL_OPT},
1310 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1311 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1312 {"comp-set", no_argument, 0, LFS_COMP_SET_OPT},
1313 {"component-set", no_argument, 0, LFS_COMP_SET_OPT},
1314 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1315 /* This formerly implied "stripe-count", but was explicitly
1316 * made "stripe-count" for consistency with other options,
1317 * and to separate it from "mdt-count" when DNE arrives. */
1318 {"count", required_argument, 0, 'c'},
1320 {"stripe-count", required_argument, 0, 'c'},
1321 {"stripe_count", required_argument, 0, 'c'},
1322 {"delete", no_argument, 0, 'd'},
1323 {"comp-end", required_argument, 0, 'E'},
1324 {"component-end", required_argument, 0, 'E'},
1325 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1326 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1327 /* This formerly implied "stripe-index", but was explicitly
1328 * made "stripe-index" for consistency with other options,
1329 * and to separate it from "mdt-index" when DNE arrives. */
1330 {"index", required_argument, 0, 'i'},
1332 {"stripe-index", required_argument, 0, 'i'},
1333 {"stripe_index", required_argument, 0, 'i'},
1334 {"comp-id", required_argument, 0, 'I'},
1335 {"component-id", required_argument, 0, 'I'},
1336 {"mdt", required_argument, 0, 'm'},
1337 {"mdt-index", required_argument, 0, 'm'},
1338 {"mdt_index", required_argument, 0, 'm'},
1339 /* --non-block is only valid in migrate mode */
1340 {"non-block", no_argument, 0, 'n'},
1341 {"ost", required_argument, 0, 'o'},
1342 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1343 {"ost-list", required_argument, 0, 'o'},
1344 {"ost_list", required_argument, 0, 'o'},
1346 {"pool", required_argument, 0, 'p'},
1347 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1348 /* This formerly implied "--stripe-size", but was confusing
1349 * with "lfs find --size|-s", which means "file size", so use
1350 * the consistent "--stripe-size|-S" for all commands. */
1351 {"size", required_argument, 0, 's'},
1353 {"stripe-size", required_argument, 0, 'S'},
1354 {"stripe_size", required_argument, 0, 'S'},
1355 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1356 /* --verbose is only valid in migrate mode */
1357 {"verbose", no_argument, 0, 'v'},
1361 setstripe_args_init(&lsa);
1363 if (strcmp(argv[0], "migrate") == 0)
1364 migrate_mode = true;
1366 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1367 long_opts, NULL)) >= 0) {
1372 case LFS_COMP_ADD_OPT:
1375 case LFS_COMP_DEL_OPT:
1378 case LFS_COMP_FLAGS_OPT:
1379 result = comp_name2flags(&lsa.lsa_comp_flags, optarg);
1381 fprintf(stderr, "error: %s: bad comp flags "
1382 "'%s'\n", argv[0], optarg);
1386 case LFS_COMP_SET_OPT:
1390 if (!migrate_mode) {
1391 fprintf(stderr, "--block is valid only for"
1395 migration_block = true;
1398 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1399 if (strcmp(argv[optind - 1], "--count") == 0)
1400 fprintf(stderr, "warning: '--count' deprecated"
1401 ", use '--stripe-count' instead\n");
1403 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1405 fprintf(stderr, "error: %s: bad stripe count "
1406 "'%s'\n", argv[0], optarg);
1411 /* delete the default striping pattern */
1415 if (lsa.lsa_comp_end != 0) {
1416 result = comp_args_to_layout(&layout, &lsa);
1420 setstripe_args_init(&lsa);
1423 if (!strncmp(optarg, "-1", strlen("-1")) ||
1424 !strncmp(optarg, "EOF", strlen("EOF")) ||
1425 !strncmp(optarg, "eof", strlen("eof"))) {
1426 lsa.lsa_comp_end = LUSTRE_EOF;
1428 result = llapi_parse_size(optarg,
1432 fprintf(stderr, "error: %s: "
1433 "bad component end '%s'\n",
1440 if (strcmp(argv[optind - 1], "--index") == 0)
1441 fprintf(stderr, "warning: '--index' deprecated"
1442 ", use '--stripe-index' instead\n");
1443 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1445 fprintf(stderr, "error: %s: bad stripe offset "
1446 "'%s'\n", argv[0], optarg);
1451 comp_id = strtoul(optarg, &end, 0);
1452 if (*end != '\0' || comp_id == 0) {
1453 fprintf(stderr, "error: %s: bad comp ID "
1454 "'%s'\n", argv[0], optarg);
1459 if (!migrate_mode) {
1460 fprintf(stderr, "--mdt-index is valid only for"
1464 mdt_idx_arg = optarg;
1467 if (!migrate_mode) {
1468 fprintf(stderr, "--non-block is valid only for"
1472 migration_flags |= MIGRATION_NONBLOCK;
1475 lsa.lsa_nr_osts = parse_targets(osts,
1476 sizeof(osts) / sizeof(__u32),
1477 lsa.lsa_nr_osts, optarg);
1478 if (lsa.lsa_nr_osts < 0) {
1480 "error: %s: bad OST indices '%s'\n",
1485 lsa.lsa_osts = osts;
1486 if (lsa.lsa_stripe_off == -1)
1487 lsa.lsa_stripe_off = osts[0];
1490 result = verify_pool_name(argv[0], optarg);
1493 lsa.lsa_pool_name = optarg;
1495 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1497 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1498 fprintf(stderr, "warning: '--size|-s' deprecated, "
1499 "use '--stripe-size|-S' instead\n");
1501 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1503 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1506 fprintf(stderr, "error: %s: bad stripe size "
1507 "'%s'\n", argv[0], optarg);
1512 if (!migrate_mode) {
1513 fprintf(stderr, "--verbose is valid only for"
1517 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1524 fname = argv[optind];
1526 if (lsa.lsa_comp_end != 0) {
1527 result = comp_args_to_layout(&layout, &lsa);
1532 if (optind == argc) {
1533 fprintf(stderr, "error: %s: missing filename|dirname\n",
1538 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1539 * altered by user space tool, so we don't need to support the
1540 * --component-set for this moment. */
1541 if (comp_set != 0) {
1542 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1547 if ((delete + comp_set + comp_del + comp_add) > 1) {
1548 fprintf(stderr, "error: %s: can't specify --component-set, "
1549 "--component-del, --component-add or -d together\n",
1554 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1555 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1556 fprintf(stderr, "error: %s: can't specify -d with "
1557 "-s, -c, -o, -p, -I, -F or -E options\n",
1562 if ((comp_set || comp_del) &&
1563 (setstripe_args_specified(&lsa) || layout != NULL)) {
1564 fprintf(stderr, "error: %s: can't specify --component-del or "
1565 "--component-set with -s, -c, -o, -p or -E options.\n",
1570 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1571 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1572 "--component-del option.\n", argv[0]);
1577 if (layout == NULL) {
1578 fprintf(stderr, "error: %s: -E option must be present"
1579 "in --component-add mode.\n", argv[0]);
1582 result = adjust_first_extent(fname, layout);
1587 if (mdt_idx_arg != NULL && optind > 3) {
1588 fprintf(stderr, "error: %s: cannot specify -m with other "
1589 "options\n", argv[0]);
1593 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1595 "error: %s: cannot specify --non-block and --block\n",
1600 /* support --component-id option for migrate later. */
1601 if (migrate_mode && comp_id != 0) {
1602 fprintf(stderr, "error: %s: -I isn't supported yet.\n",
1607 if (mdt_idx_arg != NULL) {
1608 /* initialize migrate mdt parameters */
1609 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1611 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1612 argv[0], mdt_idx_arg);
1615 migrate_mdt_param.fp_migrate = 1;
1616 } else if (layout == NULL) {
1617 /* initialize stripe parameters */
1618 param = calloc(1, offsetof(typeof(*param),
1619 lsp_osts[lsa.lsa_nr_osts]));
1620 if (param == NULL) {
1621 fprintf(stderr, "error: %s: %s\n", argv[0],
1626 param->lsp_stripe_size = lsa.lsa_stripe_size;
1627 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1628 param->lsp_stripe_count = lsa.lsa_stripe_count;
1629 param->lsp_stripe_pattern = 0;
1630 param->lsp_pool = lsa.lsa_pool_name;
1631 param->lsp_is_specific = false;
1632 if (lsa.lsa_nr_osts > 0) {
1633 if (lsa.lsa_stripe_count > 0 &&
1634 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1635 fprintf(stderr, "error: %s: stripe count '%d' "
1636 "doesn't match the number of OSTs: %d\n"
1637 , argv[0], lsa.lsa_stripe_count,
1643 param->lsp_is_specific = true;
1644 param->lsp_stripe_count = lsa.lsa_nr_osts;
1645 memcpy(param->lsp_osts, osts,
1646 sizeof(*osts) * lsa.lsa_nr_osts);
1650 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1652 if (mdt_idx_arg != NULL) {
1653 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1654 op = "migrate mdt objects of";
1655 } else if (migrate_mode) {
1656 result = lfs_migrate(fname, migration_flags, param,
1658 op = "migrate ost objects of";
1659 } else if (comp_set != 0) {
1660 result = lfs_component_set(fname, comp_id,
1661 lsa.lsa_comp_flags);
1662 op = "modify component flags of";
1663 } else if (comp_del != 0) {
1664 result = lfs_component_del(fname, comp_id,
1665 lsa.lsa_comp_flags);
1666 op = "delete component of";
1667 } else if (comp_add != 0) {
1668 result = lfs_component_add(fname, layout);
1669 op = "add component to";
1670 } else if (layout != NULL) {
1671 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1677 op = "create composite";
1679 result = llapi_file_open_param(fname,
1686 op = "create striped";
1689 /* Save the first error encountered. */
1692 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1694 lsa.lsa_pool_name != NULL && result == EINVAL ?
1695 "OST not in pool?" : strerror(errno));
1701 llapi_layout_free(layout);
1704 llapi_layout_free(layout);
1708 static int lfs_poollist(int argc, char **argv)
1713 return llapi_poollist(argv[1]);
1716 static int set_time(time_t *time, time_t *set, char *str)
1723 else if (str[0] == '-')
1729 t = strtol(str, NULL, 0);
1730 if (*time < t * 24 * 60 * 60) {
1733 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1737 *set = *time - t * 24 * 60 * 60;
1740 static int name2uid(unsigned int *id, const char *name)
1742 struct passwd *passwd;
1744 passwd = getpwnam(name);
1747 *id = passwd->pw_uid;
1752 static int name2gid(unsigned int *id, const char *name)
1754 struct group *group;
1756 group = getgrnam(name);
1759 *id = group->gr_gid;
1764 static inline int name2projid(unsigned int *id, const char *name)
1769 static int uid2name(char **name, unsigned int id)
1771 struct passwd *passwd;
1773 passwd = getpwuid(id);
1776 *name = passwd->pw_name;
1781 static inline int gid2name(char **name, unsigned int id)
1783 struct group *group;
1785 group = getgrgid(id);
1788 *name = group->gr_name;
1793 static int name2layout(__u32 *layout, char *name)
1798 for (ptr = name; ; ptr = NULL) {
1799 lyt = strtok(ptr, ",");
1802 if (strcmp(lyt, "released") == 0)
1803 *layout |= LOV_PATTERN_F_RELEASED;
1804 else if (strcmp(lyt, "raid0") == 0)
1805 *layout |= LOV_PATTERN_RAID0;
1812 static int lfs_find(int argc, char **argv)
1817 struct find_param param = {
1821 struct option long_opts[] = {
1822 {"atime", required_argument, 0, 'A'},
1823 {"comp-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1824 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1825 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1826 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1827 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
1828 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1829 {"stripe-count", required_argument, 0, 'c'},
1830 {"stripe_count", required_argument, 0, 'c'},
1831 {"ctime", required_argument, 0, 'C'},
1832 {"maxdepth", required_argument, 0, 'D'},
1833 {"comp-end", required_argument, 0, 'E'},
1834 {"component-end", required_argument, 0, 'E'},
1835 {"gid", required_argument, 0, 'g'},
1836 {"group", required_argument, 0, 'G'},
1837 {"mdt-hash", required_argument, 0, 'H'},
1838 {"stripe-index", required_argument, 0, 'i'},
1839 {"stripe_index", required_argument, 0, 'i'},
1840 /*{"component-id", required_argument, 0, 'I'},*/
1841 {"layout", required_argument, 0, 'L'},
1842 {"mdt", required_argument, 0, 'm'},
1843 {"mdt-index", required_argument, 0, 'm'},
1844 {"mdt_index", required_argument, 0, 'm'},
1845 {"mtime", required_argument, 0, 'M'},
1846 {"name", required_argument, 0, 'n'},
1847 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1848 {"obd", required_argument, 0, 'O'},
1849 {"ost", required_argument, 0, 'O'},
1850 /* no short option for pool, p/P already used */
1851 {"pool", required_argument, 0, LFS_POOL_OPT},
1852 {"print0", no_argument, 0, 'p'},
1853 {"print", no_argument, 0, 'P'},
1854 {"size", required_argument, 0, 's'},
1855 {"stripe-size", required_argument, 0, 'S'},
1856 {"stripe_size", required_argument, 0, 'S'},
1857 {"type", required_argument, 0, 't'},
1858 {"mdt-count", required_argument, 0, 'T'},
1859 {"uid", required_argument, 0, 'u'},
1860 {"user", required_argument, 0, 'U'},
1873 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1874 while ((c = getopt_long_only(argc, argv,
1875 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1876 long_opts, NULL)) >= 0) {
1881 /* '!' is part of option */
1882 /* when getopt_long_only() finds a string which is not
1883 * an option nor a known option argument it returns 1
1884 * in that case if we already have found pathstart and pathend
1885 * (i.e. we have the list of pathnames),
1886 * the only supported value is "!"
1888 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1889 if (!isoption && pathend != -1) {
1890 fprintf(stderr, "err: %s: filename|dirname must either "
1891 "precede options or follow options\n",
1896 if (!isoption && pathstart == -1)
1897 pathstart = optind - 1;
1898 if (isoption && pathstart != -1 && pathend == -1)
1899 pathend = optind - 2;
1905 /* unknown; opt is "!" or path component,
1906 * checking done above.
1908 if (strcmp(optarg, "!") == 0)
1912 xtime = ¶m.fp_atime;
1913 xsign = ¶m.fp_asign;
1914 param.fp_exclude_atime = !!neg_opt;
1915 /* no break, this falls through to 'C' for ctime */
1918 xtime = ¶m.fp_ctime;
1919 xsign = ¶m.fp_csign;
1920 param.fp_exclude_ctime = !!neg_opt;
1922 /* no break, this falls through to 'M' for mtime */
1925 xtime = ¶m.fp_mtime;
1926 xsign = ¶m.fp_msign;
1927 param.fp_exclude_mtime = !!neg_opt;
1929 rc = set_time(&t, xtime, optarg);
1930 if (rc == INT_MAX) {
1937 case LFS_COMP_COUNT_OPT:
1938 if (optarg[0] == '+') {
1939 param.fp_comp_count_sign = -1;
1941 } else if (optarg[0] == '-') {
1942 param.fp_comp_count_sign = 1;
1946 param.fp_comp_count = strtoul(optarg, &endptr, 0);
1947 if (*endptr != '\0') {
1948 fprintf(stderr, "error: bad component count "
1952 param.fp_check_comp_count = 1;
1953 param.fp_exclude_comp_count = !!neg_opt;
1955 case LFS_COMP_FLAGS_OPT:
1956 rc = comp_name2flags(¶m.fp_comp_flags, optarg);
1958 fprintf(stderr, "error: bad component flags "
1962 param.fp_check_comp_flags = 1;
1963 param.fp_exclude_comp_flags = !!neg_opt;
1965 case LFS_COMP_START_OPT:
1966 if (optarg[0] == '+') {
1967 param.fp_comp_start_sign = -1;
1969 } else if (optarg[0] == '-') {
1970 param.fp_comp_start_sign = 1;
1974 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
1975 ¶m.fp_comp_start_units, 0);
1977 fprintf(stderr, "error: bad component start "
1981 param.fp_check_comp_start = 1;
1982 param.fp_exclude_comp_start = !!neg_opt;
1985 if (optarg[0] == '+') {
1986 param.fp_stripe_count_sign = -1;
1988 } else if (optarg[0] == '-') {
1989 param.fp_stripe_count_sign = 1;
1993 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1994 if (*endptr != '\0') {
1995 fprintf(stderr,"error: bad stripe_count '%s'\n",
2000 param.fp_check_stripe_count = 1;
2001 param.fp_exclude_stripe_count = !!neg_opt;
2004 param.fp_max_depth = strtol(optarg, 0, 0);
2007 if (optarg[0] == '+') {
2008 param.fp_comp_end_sign = -1;
2010 } else if (optarg[0] == '-') {
2011 param.fp_comp_end_sign = 1;
2015 rc = llapi_parse_size(optarg, ¶m.fp_comp_end,
2016 ¶m.fp_comp_end_units, 0);
2018 fprintf(stderr, "error: bad component end "
2022 param.fp_check_comp_end = 1;
2023 param.fp_exclude_comp_end = !!neg_opt;
2027 rc = name2gid(¶m.fp_gid, optarg);
2029 param.fp_gid = strtoul(optarg, &endptr, 10);
2030 if (*endptr != '\0') {
2031 fprintf(stderr, "Group/GID: %s cannot "
2032 "be found.\n", optarg);
2037 param.fp_exclude_gid = !!neg_opt;
2038 param.fp_check_gid = 1;
2041 param.fp_hash_type = check_hashtype(optarg);
2042 if (param.fp_hash_type == 0) {
2043 fprintf(stderr, "error: bad hash_type '%s'\n",
2048 param.fp_check_hash_type = 1;
2049 param.fp_exclude_hash_type = !!neg_opt;
2052 ret = name2layout(¶m.fp_layout, optarg);
2055 param.fp_exclude_layout = !!neg_opt;
2056 param.fp_check_layout = 1;
2060 rc = name2uid(¶m.fp_uid, optarg);
2062 param.fp_uid = strtoul(optarg, &endptr, 10);
2063 if (*endptr != '\0') {
2064 fprintf(stderr, "User/UID: %s cannot "
2065 "be found.\n", optarg);
2070 param.fp_exclude_uid = !!neg_opt;
2071 param.fp_check_uid = 1;
2074 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2076 "Pool name %s is too long"
2077 " (max is %d)\n", optarg,
2082 /* we do check for empty pool because empty pool
2083 * is used to find V1 lov attributes */
2084 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2085 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2086 param.fp_exclude_pool = !!neg_opt;
2087 param.fp_check_pool = 1;
2090 param.fp_pattern = (char *)optarg;
2091 param.fp_exclude_pattern = !!neg_opt;
2096 char *buf, *token, *next, *p;
2100 buf = strdup(optarg);
2106 param.fp_exclude_obd = !!neg_opt;
2109 while (token && *token) {
2110 token = strchr(token, ',');
2117 param.fp_exclude_mdt = !!neg_opt;
2118 param.fp_num_alloc_mdts += len;
2119 tmp = realloc(param.fp_mdt_uuid,
2120 param.fp_num_alloc_mdts *
2121 sizeof(*param.fp_mdt_uuid));
2127 param.fp_mdt_uuid = tmp;
2129 param.fp_exclude_obd = !!neg_opt;
2130 param.fp_num_alloc_obds += len;
2131 tmp = realloc(param.fp_obd_uuid,
2132 param.fp_num_alloc_obds *
2133 sizeof(*param.fp_obd_uuid));
2139 param.fp_obd_uuid = tmp;
2141 for (token = buf; token && *token; token = next) {
2142 struct obd_uuid *puuid;
2145 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2148 ¶m.fp_obd_uuid[param.fp_num_obds++];
2150 p = strchr(token, ',');
2157 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2162 strncpy(puuid->uuid, token,
2163 sizeof(puuid->uuid));
2171 param.fp_zero_end = 1;
2176 if (optarg[0] == '+') {
2177 param.fp_size_sign = -1;
2179 } else if (optarg[0] == '-') {
2180 param.fp_size_sign = 1;
2184 ret = llapi_parse_size(optarg, ¶m.fp_size,
2185 ¶m.fp_size_units, 0);
2187 fprintf(stderr, "error: bad file size '%s'\n",
2191 param.fp_check_size = 1;
2192 param.fp_exclude_size = !!neg_opt;
2195 if (optarg[0] == '+') {
2196 param.fp_stripe_size_sign = -1;
2198 } else if (optarg[0] == '-') {
2199 param.fp_stripe_size_sign = 1;
2203 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2204 ¶m.fp_stripe_size_units, 0);
2206 fprintf(stderr, "error: bad stripe_size '%s'\n",
2210 param.fp_check_stripe_size = 1;
2211 param.fp_exclude_stripe_size = !!neg_opt;
2214 param.fp_exclude_type = !!neg_opt;
2215 switch (optarg[0]) {
2217 param.fp_type = S_IFBLK;
2220 param.fp_type = S_IFCHR;
2223 param.fp_type = S_IFDIR;
2226 param.fp_type = S_IFREG;
2229 param.fp_type = S_IFLNK;
2232 param.fp_type = S_IFIFO;
2235 param.fp_type = S_IFSOCK;
2238 fprintf(stderr, "error: %s: bad type '%s'\n",
2245 if (optarg[0] == '+') {
2246 param.fp_mdt_count_sign = -1;
2248 } else if (optarg[0] == '-') {
2249 param.fp_mdt_count_sign = 1;
2253 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2254 if (*endptr != '\0') {
2255 fprintf(stderr, "error: bad mdt_count '%s'\n",
2260 param.fp_check_mdt_count = 1;
2261 param.fp_exclude_mdt_count = !!neg_opt;
2269 if (pathstart == -1) {
2270 fprintf(stderr, "error: %s: no filename|pathname\n",
2274 } else if (pathend == -1) {
2280 rc = llapi_find(argv[pathstart], ¶m);
2281 if (rc != 0 && ret == 0)
2283 } while (++pathstart < pathend);
2286 fprintf(stderr, "error: %s failed for %s.\n",
2287 argv[0], argv[optind - 1]);
2289 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2290 free(param.fp_obd_uuid);
2292 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2293 free(param.fp_mdt_uuid);
2298 static int lfs_getstripe_internal(int argc, char **argv,
2299 struct find_param *param)
2301 struct option long_opts[] = {
2302 {"comp-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2303 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2304 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2305 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2306 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
2307 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
2308 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2309 /* This formerly implied "stripe-count", but was explicitly
2310 * made "stripe-count" for consistency with other options,
2311 * and to separate it from "mdt-count" when DNE arrives. */
2312 {"count", no_argument, 0, 'c'},
2314 {"stripe-count", no_argument, 0, 'c'},
2315 {"stripe_count", no_argument, 0, 'c'},
2316 {"directory", no_argument, 0, 'd'},
2317 {"default", no_argument, 0, 'D'},
2318 {"comp-end", required_argument, 0, 'E'},
2319 {"component-end", required_argument, 0, 'E'},
2320 {"fid", no_argument, 0, 'F'},
2321 {"generation", no_argument, 0, 'g'},
2322 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
2323 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2324 /* This formerly implied "stripe-index", but was explicitly
2325 * made "stripe-index" for consistency with other options,
2326 * and to separate it from "mdt-index" when DNE arrives. */
2327 {"index", no_argument, 0, 'i'},
2329 {"stripe-index", no_argument, 0, 'i'},
2330 {"stripe_index", no_argument, 0, 'i'},
2331 {"comp-id", required_argument, 0, 'I'},
2332 {"component-id", required_argument, 0, 'I'},
2333 {"layout", no_argument, 0, 'L'},
2334 {"mdt", no_argument, 0, 'm'},
2335 {"mdt-index", no_argument, 0, 'm'},
2336 {"mdt_index", no_argument, 0, 'm'},
2337 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2338 {"mdt-index", no_argument, 0, 'M'},
2339 {"mdt_index", no_argument, 0, 'M'},
2341 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2342 /* This formerly implied "stripe-index", but was confusing
2343 * with "file offset" (which will eventually be needed for
2344 * with different layouts by offset), so deprecate it. */
2345 {"offset", no_argument, 0, 'o'},
2347 {"obd", required_argument, 0, 'O'},
2348 {"ost", required_argument, 0, 'O'},
2349 {"pool", no_argument, 0, 'p'},
2350 {"quiet", no_argument, 0, 'q'},
2351 {"recursive", no_argument, 0, 'r'},
2352 {"raw", no_argument, 0, 'R'},
2353 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2354 /* This formerly implied "--stripe-size", but was confusing
2355 * with "lfs find --size|-s", which means "file size", so use
2356 * the consistent "--stripe-size|-S" for all commands. */
2357 {"size", no_argument, 0, 's'},
2359 {"stripe-size", no_argument, 0, 'S'},
2360 {"stripe_size", no_argument, 0, 'S'},
2361 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
2362 {"verbose", no_argument, 0, 'v'},
2368 while ((c = getopt_long(argc, argv, "cdDE:FghiI:LmMoO:pqrRsSv",
2369 long_opts, NULL)) != -1) {
2372 if (strcmp(argv[optind - 1], "--count") == 0)
2373 fprintf(stderr, "warning: '--count' deprecated,"
2374 " use '--stripe-count' instead\n");
2375 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2376 param->fp_verbose |= VERBOSE_COUNT;
2377 param->fp_max_depth = 0;
2380 case LFS_COMP_COUNT_OPT:
2381 param->fp_verbose |= VERBOSE_COMP_COUNT;
2382 param->fp_max_depth = 0;
2384 case LFS_COMP_FLAGS_OPT:
2385 if (optarg != NULL) {
2386 rc = comp_name2flags(¶m->fp_comp_flags,
2389 param->fp_verbose |=
2391 param->fp_max_depth = 0;
2394 param->fp_check_comp_flags = 1;
2397 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2398 param->fp_max_depth = 0;
2401 case LFS_COMP_START_OPT:
2402 if (optarg != NULL) {
2404 if (tmp[0] == '+') {
2405 param->fp_comp_start_sign = 1;
2407 } else if (tmp[0] == '-') {
2408 param->fp_comp_start_sign = -1;
2411 rc = llapi_parse_size(tmp,
2412 ¶m->fp_comp_start,
2413 ¶m->fp_comp_start_units, 0);
2415 param->fp_verbose |= VERBOSE_COMP_START;
2416 param->fp_max_depth = 0;
2419 param->fp_check_comp_start = 1;
2422 param->fp_verbose |= VERBOSE_COMP_START;
2423 param->fp_max_depth = 0;
2427 param->fp_max_depth = 0;
2430 param->fp_get_default_lmv = 1;
2433 if (optarg != NULL) {
2435 if (tmp[0] == '+') {
2436 param->fp_comp_end_sign = 1;
2438 } else if (tmp[0] == '-') {
2439 param->fp_comp_end_sign = -1;
2442 rc = llapi_parse_size(tmp,
2443 ¶m->fp_comp_end,
2444 ¶m->fp_comp_end_units, 0);
2446 param->fp_verbose |= VERBOSE_COMP_END;
2447 param->fp_max_depth = 0;
2450 param->fp_check_comp_end = 1;
2453 param->fp_verbose |= VERBOSE_COMP_END;
2454 param->fp_max_depth = 0;
2458 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2459 param->fp_verbose |= VERBOSE_DFID;
2460 param->fp_max_depth = 0;
2464 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2465 param->fp_verbose |= VERBOSE_GENERATION;
2466 param->fp_max_depth = 0;
2469 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2471 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2472 "use '--stripe-index|-i' instead\n");
2475 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2476 if (strcmp(argv[optind - 1], "--index") == 0)
2477 fprintf(stderr, "warning: '--index' deprecated"
2478 ", use '--stripe-index' instead\n");
2480 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2481 param->fp_verbose |= VERBOSE_OFFSET;
2482 param->fp_max_depth = 0;
2486 if (optarg != NULL) {
2487 param->fp_comp_id = strtoul(optarg, &end, 0);
2489 param->fp_verbose |= VERBOSE_COMP_ID;
2490 param->fp_max_depth = 0;
2493 param->fp_check_comp_id = 1;
2496 param->fp_max_depth = 0;
2497 param->fp_verbose |= VERBOSE_COMP_ID;
2501 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2502 param->fp_verbose |= VERBOSE_LAYOUT;
2503 param->fp_max_depth = 0;
2506 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2508 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2509 fprintf(stderr, "warning: '-M' deprecated"
2510 ", use '-m' instead\n");
2514 if (!(param->fp_verbose & VERBOSE_DETAIL))
2515 param->fp_max_depth = 0;
2516 param->fp_verbose |= VERBOSE_MDTINDEX;
2519 if (param->fp_obd_uuid) {
2521 "error: %s: only one obduuid allowed",
2525 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2528 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2529 param->fp_verbose |= VERBOSE_POOL;
2530 param->fp_max_depth = 0;
2537 param->fp_recursive = 1;
2542 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2544 fprintf(stderr, "warning: '--size|-s' deprecated, "
2545 "use '--stripe-size|-S' instead\n");
2546 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2548 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2549 param->fp_verbose |= VERBOSE_SIZE;
2550 param->fp_max_depth = 0;
2554 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2564 if (param->fp_recursive)
2565 param->fp_max_depth = -1;
2566 else if (param->fp_verbose & VERBOSE_DETAIL)
2567 param->fp_max_depth = 1;
2569 if (!param->fp_verbose)
2570 param->fp_verbose = VERBOSE_DEFAULT;
2571 if (param->fp_quiet)
2572 param->fp_verbose = VERBOSE_OBJID;
2575 rc = llapi_getstripe(argv[optind], param);
2576 } while (++optind < argc && !rc);
2579 fprintf(stderr, "error: %s failed for %s.\n",
2580 argv[0], argv[optind - 1]);
2584 static int lfs_tgts(int argc, char **argv)
2586 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2587 struct find_param param;
2588 int index = 0, rc=0;
2593 if (argc == 2 && !realpath(argv[1], path)) {
2595 fprintf(stderr, "error: invalid path '%s': %s\n",
2596 argv[1], strerror(-rc));
2600 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2601 /* Check if we have a mount point */
2602 if (mntdir[0] == '\0')
2605 memset(¶m, 0, sizeof(param));
2606 if (!strcmp(argv[0], "mdts"))
2607 param.fp_get_lmv = 1;
2609 rc = llapi_ostlist(mntdir, ¶m);
2611 fprintf(stderr, "error: %s: failed on %s\n",
2614 if (path[0] != '\0')
2616 memset(mntdir, 0, PATH_MAX);
2622 static int lfs_getstripe(int argc, char **argv)
2624 struct find_param param = { 0 };
2626 param.fp_max_depth = 1;
2627 return lfs_getstripe_internal(argc, argv, ¶m);
2631 static int lfs_getdirstripe(int argc, char **argv)
2633 struct find_param param = { 0 };
2634 struct option long_opts[] = {
2635 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2636 {"mdt-count", no_argument, 0, 'c'},
2638 {"mdt-hash", no_argument, 0, 'H'},
2639 {"mdt-index", no_argument, 0, 'i'},
2640 {"recursive", no_argument, 0, 'r'},
2641 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2642 {"mdt-hash", no_argument, 0, 't'},
2644 {"default", no_argument, 0, 'D'},
2645 {"obd", required_argument, 0, 'O'},
2646 {"mdt-count", no_argument, 0, 'T'},
2651 param.fp_get_lmv = 1;
2653 while ((c = getopt_long(argc, argv,
2654 "cDHiO:rtT", long_opts, NULL)) != -1)
2658 if (param.fp_obd_uuid) {
2660 "error: %s: only one obduuid allowed",
2664 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2666 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2668 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2669 fprintf(stderr, "warning: '-c' deprecated"
2670 ", use '-T' instead\n");
2674 param.fp_verbose |= VERBOSE_COUNT;
2677 param.fp_verbose |= VERBOSE_OFFSET;
2679 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2683 param.fp_verbose |= VERBOSE_HASH_TYPE;
2686 param.fp_get_default_lmv = 1;
2689 param.fp_recursive = 1;
2699 if (param.fp_recursive)
2700 param.fp_max_depth = -1;
2702 if (!param.fp_verbose)
2703 param.fp_verbose = VERBOSE_DEFAULT;
2706 rc = llapi_getstripe(argv[optind], ¶m);
2707 } while (++optind < argc && !rc);
2710 fprintf(stderr, "error: %s failed for %s.\n",
2711 argv[0], argv[optind - 1]);
2716 static int lfs_setdirstripe(int argc, char **argv)
2720 unsigned int stripe_offset = -1;
2721 unsigned int stripe_count = 1;
2722 enum lmv_hash_type hash_type;
2725 char *stripe_offset_opt = NULL;
2726 char *stripe_count_opt = NULL;
2727 char *stripe_hash_opt = NULL;
2728 char *mode_opt = NULL;
2729 bool default_stripe = false;
2730 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2731 mode_t previous_mode = 0;
2732 bool delete = false;
2734 struct option long_opts[] = {
2735 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2736 {"count", required_argument, 0, 'c'},
2738 {"mdt-count", required_argument, 0, 'c'},
2739 {"delete", no_argument, 0, 'd'},
2740 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2741 {"index", required_argument, 0, 'i'},
2743 {"mdt-index", required_argument, 0, 'i'},
2744 {"mode", required_argument, 0, 'm'},
2745 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2746 {"hash-type", required_argument, 0, 't'},
2747 {"mdt-hash", required_argument, 0, 't'},
2749 {"mdt-hash", required_argument, 0, 'H'},
2750 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2751 {"default_stripe", no_argument, 0, 'D'},
2753 {"default", no_argument, 0, 'D'},
2757 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2764 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2765 if (strcmp(argv[optind - 1], "--count") == 0)
2766 fprintf(stderr, "warning: '--count' deprecated"
2767 ", use '--mdt-count' instead\n");
2769 stripe_count_opt = optarg;
2773 default_stripe = true;
2776 default_stripe = true;
2779 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2780 if (strcmp(argv[optind - 1], "--index") == 0)
2781 fprintf(stderr, "warning: '--index' deprecated"
2782 ", use '--mdt-index' instead\n");
2784 stripe_offset_opt = optarg;
2789 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2793 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2794 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2795 fprintf(stderr, "warning: '--hash-type' "
2796 "deprecated, use '--mdt-hash' "
2799 stripe_hash_opt = optarg;
2802 fprintf(stderr, "error: %s: option '%s' "
2804 argv[0], argv[optind - 1]);
2809 if (optind == argc) {
2810 fprintf(stderr, "error: %s: missing dirname\n",
2815 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2816 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2821 if (stripe_offset_opt != NULL) {
2822 /* get the stripe offset */
2823 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2825 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2826 argv[0], stripe_offset_opt);
2832 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2833 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2834 " or -i options.\n", argv[0]);
2842 if (mode_opt != NULL) {
2843 mode = strtoul(mode_opt, &end, 8);
2845 fprintf(stderr, "error: %s: bad mode '%s'\n",
2849 previous_mode = umask(0);
2852 if (stripe_hash_opt == NULL) {
2853 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2855 hash_type = check_hashtype(stripe_hash_opt);
2856 if (hash_type == 0) {
2858 "error: %s: bad stripe hash type '%s'\n",
2859 argv[0], stripe_hash_opt);
2864 /* get the stripe count */
2865 if (stripe_count_opt != NULL) {
2866 stripe_count = strtoul(stripe_count_opt, &end, 0);
2868 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2869 argv[0], stripe_count_opt);
2874 dname = argv[optind];
2876 if (default_stripe) {
2877 result = llapi_dir_set_default_lmv_stripe(dname,
2878 stripe_offset, stripe_count,
2881 result = llapi_dir_create_pool(dname, mode,
2883 stripe_count, hash_type,
2888 fprintf(stderr, "error: %s: create stripe dir '%s' "
2889 "failed\n", argv[0], dname);
2892 dname = argv[++optind];
2893 } while (dname != NULL);
2895 if (mode_opt != NULL)
2896 umask(previous_mode);
2902 static int lfs_rmentry(int argc, char **argv)
2909 fprintf(stderr, "error: %s: missing dirname\n",
2915 dname = argv[index];
2916 while (dname != NULL) {
2917 result = llapi_direntry_remove(dname);
2919 fprintf(stderr, "error: %s: remove dir entry '%s' "
2920 "failed\n", argv[0], dname);
2923 dname = argv[++index];
2928 static int lfs_mv(int argc, char **argv)
2930 struct find_param param = {
2937 struct option long_opts[] = {
2938 {"mdt-index", required_argument, 0, 'M'},
2939 {"verbose", no_argument, 0, 'v'},
2943 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2946 param.fp_mdt_index = strtoul(optarg, &end, 0);
2948 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2955 param.fp_verbose = VERBOSE_DETAIL;
2959 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2960 argv[0], argv[optind - 1]);
2965 if (param.fp_mdt_index == -1) {
2966 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2970 if (optind >= argc) {
2971 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2975 param.fp_migrate = 1;
2976 rc = llapi_migrate_mdt(argv[optind], ¶m);
2978 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2979 argv[0], argv[optind], param.fp_mdt_index,
2984 static int lfs_osts(int argc, char **argv)
2986 return lfs_tgts(argc, argv);
2989 static int lfs_mdts(int argc, char **argv)
2991 return lfs_tgts(argc, argv);
2994 #define COOK(value) \
2997 while (value > 1024) { \
3005 #define CDF "%11llu"
3006 #define HDF "%8.1f%c"
3011 MNTDF_INODES = 0x0001,
3012 MNTDF_COOKED = 0x0002,
3013 MNTDF_LAZY = 0x0004,
3014 MNTDF_VERBOSE = 0x0008,
3017 static int showdf(char *mntdir, struct obd_statfs *stat,
3018 char *uuid, enum mntdf_flags flags,
3019 char *type, int index, int rc)
3021 long long avail, used, total;
3023 char *suffix = "KMGTPEZY";
3024 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3025 char tbuf[3 * sizeof(__u64)];
3026 char ubuf[3 * sizeof(__u64)];
3027 char abuf[3 * sizeof(__u64)];
3028 char rbuf[3 * sizeof(__u64)];
3035 if (flags & MNTDF_INODES) {
3036 avail = stat->os_ffree;
3037 used = stat->os_files - stat->os_ffree;
3038 total = stat->os_files;
3040 int shift = flags & MNTDF_COOKED ? 0 : 10;
3042 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3043 used = ((stat->os_blocks - stat->os_bfree) *
3044 stat->os_bsize) >> shift;
3045 total = (stat->os_blocks * stat->os_bsize) >> shift;
3048 if ((used + avail) > 0)
3049 ratio = (double)used / (double)(used + avail);
3051 if (flags & MNTDF_COOKED) {
3055 cook_val = (double)total;
3058 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3061 snprintf(tbuf, sizeof(tbuf), CDF, total);
3063 cook_val = (double)used;
3066 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3069 snprintf(ubuf, sizeof(ubuf), CDF, used);
3071 cook_val = (double)avail;
3074 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3077 snprintf(abuf, sizeof(abuf), CDF, avail);
3079 snprintf(tbuf, sizeof(tbuf), CDF, total);
3080 snprintf(ubuf, sizeof(tbuf), CDF, used);
3081 snprintf(abuf, sizeof(tbuf), CDF, avail);
3084 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3085 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3086 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3088 printf("[%s:%d]", type, index);
3090 if (stat->os_state) {
3092 * Each character represents the matching
3095 const char state_names[] = "DRSI";
3100 for (i = 0, state = stat->os_state;
3101 state && i < sizeof(state_names); i++) {
3102 if (!(state & (1 << i)))
3104 printf("%c", state_names[i]);
3112 printf(UUF": inactive device\n", uuid);
3115 printf(UUF": %s\n", uuid, strerror(-rc));
3122 struct ll_stat_type {
3127 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3129 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3130 struct obd_uuid uuid_buf;
3131 char *poolname = NULL;
3132 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3133 { LL_STATFS_LOV, "OST" },
3135 struct ll_stat_type *tp;
3136 __u64 ost_ffree = 0;
3144 poolname = strchr(pool, '.');
3145 if (poolname != NULL) {
3146 if (strncmp(fsname, pool, strlen(fsname))) {
3147 fprintf(stderr, "filesystem name incorrect\n");
3155 fd = open(mntdir, O_RDONLY);
3158 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3163 if (flags & MNTDF_INODES)
3164 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3165 "UUID", "Inodes", "IUsed", "IFree",
3166 "IUse%", "Mounted on");
3168 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3169 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3170 "Used", "Available", "Use%", "Mounted on");
3172 for (tp = types; tp->st_name != NULL; tp++) {
3173 for (index = 0; ; index++) {
3174 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3175 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3176 type = flags & MNTDF_LAZY ?
3177 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3178 rc2 = llapi_obd_fstatfs(fd, type, index,
3179 &stat_buf, &uuid_buf);
3184 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3185 if (!(flags & MNTDF_VERBOSE))
3187 } else if (rc2 < 0 && rc == 0) {
3191 if (poolname && tp->st_op == LL_STATFS_LOV &&
3192 llapi_search_ost(fsname, poolname,
3193 obd_uuid2str(&uuid_buf)) != 1)
3196 /* the llapi_obd_statfs() call may have returned with
3197 * an error, but if it filled in uuid_buf we will at
3198 * lease use that to print out a message for that OBD.
3199 * If we didn't get anything in the uuid_buf, then fill
3200 * it in so that we can print an error message. */
3201 if (uuid_buf.uuid[0] == '\0')
3202 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3203 "%s%04x", tp->st_name, index);
3204 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3205 flags, tp->st_name, index, rc2);
3208 if (tp->st_op == LL_STATFS_LMV) {
3209 sum.os_ffree += stat_buf.os_ffree;
3210 sum.os_files += stat_buf.os_files;
3211 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3212 sum.os_blocks += stat_buf.os_blocks *
3214 sum.os_bfree += stat_buf.os_bfree *
3216 sum.os_bavail += stat_buf.os_bavail *
3218 ost_ffree += stat_buf.os_ffree;
3226 /* If we don't have as many objects free on the OST as inodes
3227 * on the MDS, we reduce the total number of inodes to
3228 * compensate, so that the "inodes in use" number is correct.
3229 * Matches ll_statfs_internal() so the results are consistent. */
3230 if (ost_ffree < sum.os_ffree) {
3231 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3232 sum.os_ffree = ost_ffree;
3235 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3241 static int lfs_df(int argc, char **argv)
3243 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3244 enum mntdf_flags flags = 0;
3245 int c, rc = 0, index = 0;
3246 char fsname[PATH_MAX] = "", *pool_name = NULL;
3247 struct option long_opts[] = {
3248 {"human-readable", 0, 0, 'h'},
3249 {"inodes", 0, 0, 'i'},
3250 {"lazy", 0, 0, 'l'},
3251 {"pool", required_argument, 0, 'p'},
3252 {"verbose", 0, 0, 'v'},
3256 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3259 flags |= MNTDF_COOKED;
3262 flags |= MNTDF_INODES;
3265 flags |= MNTDF_LAZY;
3271 flags |= MNTDF_VERBOSE;
3277 if (optind < argc && !realpath(argv[optind], path)) {
3279 fprintf(stderr, "error: invalid path '%s': %s\n",
3280 argv[optind], strerror(-rc));
3284 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3285 /* Check if we have a mount point */
3286 if (mntdir[0] == '\0')
3289 rc = mntdf(mntdir, fsname, pool_name, flags);
3290 if (rc || path[0] != '\0')
3292 fsname[0] = '\0'; /* avoid matching in next loop */
3293 mntdir[0] = '\0'; /* avoid matching in next loop */
3299 static int lfs_getname(int argc, char **argv)
3301 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3302 int rc = 0, index = 0, c;
3303 char buf[sizeof(struct obd_uuid)];
3305 while ((c = getopt(argc, argv, "h")) != -1)
3308 if (optind == argc) { /* no paths specified, get all paths. */
3309 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3310 rc = llapi_getname(mntdir, buf, sizeof(buf));
3313 "cannot get name for `%s': %s\n",
3314 mntdir, strerror(-rc));
3318 printf("%s %s\n", buf, mntdir);
3320 path[0] = fsname[0] = mntdir[0] = 0;
3322 } else { /* paths specified, only attempt to search these. */
3323 for (; optind < argc; optind++) {
3324 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3327 "cannot get name for `%s': %s\n",
3328 argv[optind], strerror(-rc));
3332 printf("%s %s\n", buf, argv[optind]);
3338 static int lfs_check(int argc, char **argv)
3341 char mntdir[PATH_MAX] = {'\0'};
3350 obd_types[0] = obd_type1;
3351 obd_types[1] = obd_type2;
3353 if (strcmp(argv[1], "osts") == 0) {
3354 strcpy(obd_types[0], "osc");
3355 } else if (strcmp(argv[1], "mds") == 0) {
3356 strcpy(obd_types[0], "mdc");
3357 } else if (strcmp(argv[1], "servers") == 0) {
3359 strcpy(obd_types[0], "osc");
3360 strcpy(obd_types[1], "mdc");
3362 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3367 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3368 if (rc < 0 || mntdir[0] == '\0') {
3369 fprintf(stderr, "No suitable Lustre mount found\n");
3373 rc = llapi_target_check(num_types, obd_types, mntdir);
3375 fprintf(stderr, "error: %s: %s status failed\n",
3382 #ifdef HAVE_SYS_QUOTA_H
3383 #define ARG2INT(nr, str, msg) \
3386 nr = strtol(str, &endp, 0); \
3388 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3393 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3395 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3396 * returns the value or ULONG_MAX on integer overflow or incorrect format
3398 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3399 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3400 * 3. empty integer value is interpreted as 0
3402 static unsigned long str2sec(const char* timestr)
3404 const char spec[] = "smhdw";
3405 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3406 unsigned long val = 0;
3409 if (strpbrk(timestr, spec) == NULL) {
3410 /* no specifiers inside the time string,
3411 should treat it as an integer value */
3412 val = strtoul(timestr, &tail, 10);
3413 return *tail ? ULONG_MAX : val;
3416 /* format string is XXwXXdXXhXXmXXs */
3422 v = strtoul(timestr, &tail, 10);
3423 if (v == ULONG_MAX || *tail == '\0')
3424 /* value too large (ULONG_MAX or more)
3425 or missing specifier */
3428 ptr = strchr(spec, *tail);
3430 /* unknown specifier */
3435 /* check if product will overflow the type */
3436 if (!(v < ULONG_MAX / mult[ind]))
3439 ADD_OVERFLOW(val, mult[ind] * v);
3440 if (val == ULONG_MAX)
3452 #define ARG2ULL(nr, str, def_units) \
3454 unsigned long long limit, units = def_units; \
3457 rc = llapi_parse_size(str, &limit, &units, 1); \
3459 fprintf(stderr, "error: bad limit value %s\n", str); \
3465 static inline int has_times_option(int argc, char **argv)
3469 for (i = 1; i < argc; i++)
3470 if (!strcmp(argv[i], "-t"))
3476 int lfs_setquota_times(int argc, char **argv)
3479 struct if_quotactl qctl;
3480 char *mnt, *obd_type = (char *)qctl.obd_type;
3481 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3482 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3483 struct option long_opts[] = {
3484 {"block-grace", required_argument, 0, 'b'},
3485 {"group", no_argument, 0, 'g'},
3486 {"inode-grace", required_argument, 0, 'i'},
3487 {"project", no_argument, 0, 'p'},
3488 {"times", no_argument, 0, 't'},
3489 {"user", no_argument, 0, 'u'},
3494 memset(&qctl, 0, sizeof(qctl));
3495 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3496 qctl.qc_type = ALLQUOTA;
3498 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3499 long_opts, NULL)) != -1) {
3510 if (qctl.qc_type != ALLQUOTA) {
3511 fprintf(stderr, "error: -u/g/p can't be used "
3512 "more than once\n");
3515 qctl.qc_type = qtype;
3518 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3519 fprintf(stderr, "error: bad block-grace: %s\n",
3523 dqb->dqb_valid |= QIF_BTIME;
3526 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3527 fprintf(stderr, "error: bad inode-grace: %s\n",
3531 dqb->dqb_valid |= QIF_ITIME;
3533 case 't': /* Yes, of course! */
3535 default: /* getopt prints error message for us when opterr != 0 */
3540 if (qctl.qc_type == ALLQUOTA) {
3541 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3545 if (optind != argc - 1) {
3546 fprintf(stderr, "error: unexpected parameters encountered\n");
3551 rc = llapi_quotactl(mnt, &qctl);
3554 fprintf(stderr, "%s %s ", obd_type,
3555 obd_uuid2str(&qctl.obd_uuid));
3556 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3563 #define BSLIMIT (1 << 0)
3564 #define BHLIMIT (1 << 1)
3565 #define ISLIMIT (1 << 2)
3566 #define IHLIMIT (1 << 3)
3568 int lfs_setquota(int argc, char **argv)
3571 struct if_quotactl qctl;
3572 char *mnt, *obd_type = (char *)qctl.obd_type;
3573 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3574 struct option long_opts[] = {
3575 {"block-softlimit", required_argument, 0, 'b'},
3576 {"block-hardlimit", required_argument, 0, 'B'},
3577 {"group", required_argument, 0, 'g'},
3578 {"inode-softlimit", required_argument, 0, 'i'},
3579 {"inode-hardlimit", required_argument, 0, 'I'},
3580 {"user", required_argument, 0, 'u'},
3581 {"project", required_argument, 0, 'p'},
3584 unsigned limit_mask = 0;
3588 if (has_times_option(argc, argv))
3589 return lfs_setquota_times(argc, argv);
3591 memset(&qctl, 0, sizeof(qctl));
3592 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3593 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3594 * so it can be used as a marker that qc_type
3595 * isn't reinitialized from command line */
3597 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3598 long_opts, NULL)) != -1) {
3602 rc = name2uid(&qctl.qc_id, optarg);
3606 rc = name2gid(&qctl.qc_id, optarg);
3610 rc = name2projid(&qctl.qc_id, optarg);
3612 if (qctl.qc_type != ALLQUOTA) {
3613 fprintf(stderr, "error: -u and -g can't be used"
3614 " more than once\n");
3617 qctl.qc_type = qtype;
3619 qctl.qc_id = strtoul(optarg, &endptr, 10);
3620 if (*endptr != '\0') {
3621 fprintf(stderr, "error: can't find id "
3622 "for name %s\n", optarg);
3628 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3629 dqb->dqb_bsoftlimit >>= 10;
3630 limit_mask |= BSLIMIT;
3631 if (dqb->dqb_bsoftlimit &&
3632 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3633 fprintf(stderr, "warning: block softlimit is "
3634 "smaller than the miminal qunit size, "
3635 "please see the help of setquota or "
3636 "Lustre manual for details.\n");
3639 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3640 dqb->dqb_bhardlimit >>= 10;
3641 limit_mask |= BHLIMIT;
3642 if (dqb->dqb_bhardlimit &&
3643 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3644 fprintf(stderr, "warning: block hardlimit is "
3645 "smaller than the miminal qunit size, "
3646 "please see the help of setquota or "
3647 "Lustre manual for details.\n");
3650 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3651 limit_mask |= ISLIMIT;
3652 if (dqb->dqb_isoftlimit &&
3653 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3654 fprintf(stderr, "warning: inode softlimit is "
3655 "smaller than the miminal qunit size, "
3656 "please see the help of setquota or "
3657 "Lustre manual for details.\n");
3660 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3661 limit_mask |= IHLIMIT;
3662 if (dqb->dqb_ihardlimit &&
3663 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3664 fprintf(stderr, "warning: inode hardlimit is "
3665 "smaller than the miminal qunit size, "
3666 "please see the help of setquota or "
3667 "Lustre manual for details.\n");
3669 default: /* getopt prints error message for us when opterr != 0 */
3674 if (qctl.qc_type == ALLQUOTA) {
3675 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3679 if (limit_mask == 0) {
3680 fprintf(stderr, "error: at least one limit must be specified\n");
3684 if (optind != argc - 1) {
3685 fprintf(stderr, "error: unexpected parameters encountered\n");
3691 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3692 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3693 /* sigh, we can't just set blimits/ilimits */
3694 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3695 .qc_type = qctl.qc_type,
3696 .qc_id = qctl.qc_id};
3698 rc = llapi_quotactl(mnt, &tmp_qctl);
3700 fprintf(stderr, "error: setquota failed while retrieving"
3701 " current quota settings (%s)\n",
3706 if (!(limit_mask & BHLIMIT))
3707 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3708 if (!(limit_mask & BSLIMIT))
3709 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3710 if (!(limit_mask & IHLIMIT))
3711 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3712 if (!(limit_mask & ISLIMIT))
3713 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3715 /* Keep grace times if we have got no softlimit arguments */
3716 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3717 dqb->dqb_valid |= QIF_BTIME;
3718 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3721 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3722 dqb->dqb_valid |= QIF_ITIME;
3723 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3727 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3728 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3730 rc = llapi_quotactl(mnt, &qctl);
3733 fprintf(stderr, "%s %s ", obd_type,
3734 obd_uuid2str(&qctl.obd_uuid));
3735 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3742 /* Converts seconds value into format string
3743 * result is returned in buf
3745 * 1. result is in descenting order: 1w2d3h4m5s
3746 * 2. zero fields are not filled (except for p. 3): 5d1s
3747 * 3. zero seconds value is presented as "0s"
3749 static char * __sec2str(time_t seconds, char *buf)
3751 const char spec[] = "smhdw";
3752 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3757 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3758 c = seconds / mult[i];
3760 if (c > 0 || (i == 0 && buf == tail))
3761 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3769 static void sec2str(time_t seconds, char *buf, int rc)
3776 tail = __sec2str(seconds, tail);
3778 if (rc && tail - buf < 39) {
3784 static void diff2str(time_t seconds, char *buf, time_t now)
3790 if (seconds <= now) {
3791 strcpy(buf, "none");
3794 __sec2str(seconds - now, buf);
3797 static void print_quota_title(char *name, struct if_quotactl *qctl,
3798 bool human_readable)
3800 printf("Disk quotas for %s %s (%cid %u):\n",
3801 qtype_name(qctl->qc_type), name,
3802 *qtype_name(qctl->qc_type), qctl->qc_id);
3803 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3804 "Filesystem", human_readable ? "used" : "kbytes",
3805 "quota", "limit", "grace",
3806 "files", "quota", "limit", "grace");
3809 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3812 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3815 snprintf(buf, buflen, "%5.4gP",
3816 (double)num / ((__u64)1 << 40));
3818 snprintf(buf, buflen, "%5.4gT",
3819 (double)num / (1 << 30));
3821 snprintf(buf, buflen, "%5.4gG",
3822 (double)num / (1 << 20));
3824 snprintf(buf, buflen, "%5.4gM",
3825 (double)num / (1 << 10));
3827 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3831 #define STRBUF_LEN 32
3832 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3839 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3840 int bover = 0, iover = 0;
3841 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3842 char numbuf[3][STRBUF_LEN];
3844 char strbuf[STRBUF_LEN];
3846 if (dqb->dqb_bhardlimit &&
3847 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3849 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3850 if (dqb->dqb_btime > now) {
3857 if (dqb->dqb_ihardlimit &&
3858 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3860 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3861 if (dqb->dqb_itime > now) {
3869 if (strlen(mnt) > 15)
3870 printf("%s\n%15s", mnt, "");
3872 printf("%15s", mnt);
3875 diff2str(dqb->dqb_btime, timebuf, now);
3877 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3878 strbuf, sizeof(strbuf), h);
3879 if (rc == -EREMOTEIO)
3880 sprintf(numbuf[0], "%s*", strbuf);
3882 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3883 "%s" : "[%s]", strbuf);
3885 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3886 if (type == QC_GENERAL)
3887 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3888 "%s" : "[%s]", strbuf);
3890 sprintf(numbuf[1], "%s", "-");
3892 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3893 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3894 "%s" : "[%s]", strbuf);
3896 printf(" %7s%c %6s %7s %7s",
3897 numbuf[0], bover ? '*' : ' ', numbuf[1],
3898 numbuf[2], bover > 1 ? timebuf : "-");
3901 diff2str(dqb->dqb_itime, timebuf, now);
3903 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3904 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3906 if (type == QC_GENERAL)
3907 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3909 (uintmax_t)dqb->dqb_isoftlimit);
3911 sprintf(numbuf[1], "%s", "-");
3913 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3914 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3916 if (type != QC_OSTIDX)
3917 printf(" %7s%c %6s %7s %7s",
3918 numbuf[0], iover ? '*' : ' ', numbuf[1],
3919 numbuf[2], iover > 1 ? timebuf : "-");
3921 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3924 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3925 qctl->qc_cmd == Q_GETOINFO) {
3929 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3930 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3931 printf("Block grace time: %s; Inode grace time: %s\n",
3932 bgtimebuf, igtimebuf);
3936 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3937 bool h, __u64 *total)
3939 int rc = 0, rc1 = 0, count = 0;
3940 __u32 valid = qctl->qc_valid;
3942 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3944 fprintf(stderr, "can not get %s count: %s\n",
3945 is_mdt ? "mdt": "ost", strerror(-rc));
3949 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3950 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3951 rc = llapi_quotactl(mnt, qctl);
3953 /* It is remote client case. */
3954 if (rc == -EOPNOTSUPP) {
3961 fprintf(stderr, "quotactl %s%d failed.\n",
3962 is_mdt ? "mdt": "ost", qctl->qc_idx);
3966 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3967 qctl->qc_valid, 0, h);
3968 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3969 qctl->qc_dqblk.dqb_bhardlimit;
3972 qctl->qc_valid = valid;
3976 static int lfs_quota(int argc, char **argv)
3979 char *mnt, *name = NULL;
3980 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3981 .qc_type = ALLQUOTA };
3982 char *obd_type = (char *)qctl.obd_type;
3983 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3984 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
3985 verbose = 0, pass = 0, quiet = 0, inacc;
3987 __u32 valid = QC_GENERAL, idx = 0;
3988 __u64 total_ialloc = 0, total_balloc = 0;
3989 bool human_readable = false;
3992 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4003 if (qctl.qc_type != ALLQUOTA) {
4004 fprintf(stderr, "error: use either -u or -g\n");
4007 qctl.qc_type = qtype;
4010 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4013 valid = qctl.qc_valid = QC_UUID;
4014 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4017 valid = qctl.qc_valid = QC_MDTIDX;
4018 idx = qctl.qc_idx = atoi(optarg);
4021 valid = qctl.qc_valid = QC_OSTIDX;
4022 idx = qctl.qc_idx = atoi(optarg);
4031 human_readable = true;
4034 fprintf(stderr, "error: %s: option '-%c' "
4035 "unrecognized\n", argv[0], c);
4040 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4041 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4042 optind == argc - 1) {
4044 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4045 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4046 qctl.qc_valid = valid;
4048 qctl.qc_type = pass;
4049 switch (qctl.qc_type) {
4051 qctl.qc_id = geteuid();
4052 rc = uid2name(&name, qctl.qc_id);
4055 qctl.qc_id = getegid();
4056 rc = gid2name(&name, qctl.qc_id);
4065 /* lfs quota -u username /path/to/lustre/mount */
4066 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4067 /* options should be followed by u/g-name and mntpoint */
4068 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4069 fprintf(stderr, "error: missing quota argument(s)\n");
4073 name = argv[optind++];
4074 switch (qctl.qc_type) {
4076 rc = name2uid(&qctl.qc_id, name);
4079 rc = name2gid(&qctl.qc_id, name);
4082 rc = name2projid(&qctl.qc_id, name);
4089 qctl.qc_id = strtoul(name, &endptr, 10);
4090 if (*endptr != '\0') {
4091 fprintf(stderr, "error: can't find id for name "
4096 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4097 fprintf(stderr, "error: missing quota info argument(s)\n");
4103 rc1 = llapi_quotactl(mnt, &qctl);
4107 fprintf(stderr, "%s quotas are not enabled.\n",
4108 qtype_name(qctl.qc_type));
4111 fprintf(stderr, "Permission denied.\n");
4114 /* We already got error message. */
4117 fprintf(stderr, "Unexpected quotactl error: %s\n",
4122 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4123 print_quota_title(name, &qctl, human_readable);
4125 if (rc1 && *obd_type)
4126 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4128 if (qctl.qc_valid != QC_GENERAL)
4131 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4132 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4133 (QIF_LIMITS|QIF_USAGE));
4135 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4137 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4139 char strbuf[STRBUF_LEN];
4141 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4143 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4145 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4147 printf("Total allocated inode limit: %ju, total "
4148 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4152 if (rc1 || rc2 || rc3 || inacc)
4153 printf("Some errors happened when getting quota info. "
4154 "Some devices may be not working or deactivated. "
4155 "The data in \"[]\" is inaccurate.\n");
4158 if (pass > 0 && pass < LL_MAXQUOTAS)
4163 #endif /* HAVE_SYS_QUOTA_H! */
4165 static int flushctx_ioctl(char *mp)
4169 fd = open(mp, O_RDONLY);
4171 fprintf(stderr, "flushctx: error open %s: %s\n",
4172 mp, strerror(errno));
4176 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4178 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4179 mp, strerror(errno));
4185 static int lfs_flushctx(int argc, char **argv)
4187 int kdestroy = 0, c;
4188 char mntdir[PATH_MAX] = {'\0'};
4192 while ((c = getopt(argc, argv, "k")) != -1) {
4198 fprintf(stderr, "error: %s: option '-%c' "
4199 "unrecognized\n", argv[0], c);
4205 if ((rc = system("kdestroy > /dev/null")) != 0) {
4206 rc = WEXITSTATUS(rc);
4207 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4211 if (optind >= argc) {
4212 /* flush for all mounted lustre fs. */
4213 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4214 /* Check if we have a mount point */
4215 if (mntdir[0] == '\0')
4218 if (flushctx_ioctl(mntdir))
4221 mntdir[0] = '\0'; /* avoid matching in next loop */
4224 /* flush fs as specified */
4225 while (optind < argc) {
4226 if (flushctx_ioctl(argv[optind++]))
4233 static int lfs_cp(int argc, char **argv)
4235 fprintf(stderr, "remote client copy file(s).\n"
4236 "obsolete, does not support it anymore.\n");
4240 static int lfs_ls(int argc, char **argv)
4242 fprintf(stderr, "remote client lists directory contents.\n"
4243 "obsolete, does not support it anymore.\n");
4247 static int lfs_changelog(int argc, char **argv)
4249 void *changelog_priv;
4250 struct changelog_rec *rec;
4251 long long startrec = 0, endrec = 0;
4253 struct option long_opts[] = {
4254 {"follow", no_argument, 0, 'f'},
4257 char short_opts[] = "f";
4260 while ((rc = getopt_long(argc, argv, short_opts,
4261 long_opts, NULL)) != -1) {
4269 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4270 argv[0], argv[optind - 1]);
4277 mdd = argv[optind++];
4279 startrec = strtoll(argv[optind++], NULL, 10);
4281 endrec = strtoll(argv[optind++], NULL, 10);
4283 rc = llapi_changelog_start(&changelog_priv,
4284 CHANGELOG_FLAG_BLOCK |
4285 CHANGELOG_FLAG_JOBID |
4286 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4289 fprintf(stderr, "Can't start changelog: %s\n",
4290 strerror(errno = -rc));
4294 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4298 if (endrec && rec->cr_index > endrec) {
4299 llapi_changelog_free(&rec);
4302 if (rec->cr_index < startrec) {
4303 llapi_changelog_free(&rec);
4307 secs = rec->cr_time >> 30;
4308 gmtime_r(&secs, &ts);
4309 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
4310 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
4311 changelog_type2str(rec->cr_type),
4312 ts.tm_hour, ts.tm_min, ts.tm_sec,
4313 (int)(rec->cr_time & ((1<<30) - 1)),
4314 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4315 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4317 if (rec->cr_flags & CLF_JOBID) {
4318 struct changelog_ext_jobid *jid =
4319 changelog_rec_jobid(rec);
4321 if (jid->cr_jobid[0] != '\0')
4322 printf(" j=%s", jid->cr_jobid);
4325 if (rec->cr_namelen)
4326 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4327 rec->cr_namelen, changelog_rec_name(rec));
4329 if (rec->cr_flags & CLF_RENAME) {
4330 struct changelog_ext_rename *rnm =
4331 changelog_rec_rename(rec);
4333 if (!fid_is_zero(&rnm->cr_sfid))
4334 printf(" s="DFID" sp="DFID" %.*s",
4335 PFID(&rnm->cr_sfid),
4336 PFID(&rnm->cr_spfid),
4337 (int)changelog_rec_snamelen(rec),
4338 changelog_rec_sname(rec));
4342 llapi_changelog_free(&rec);
4345 llapi_changelog_fini(&changelog_priv);
4348 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4350 return (rc == 1 ? 0 : rc);
4353 static int lfs_changelog_clear(int argc, char **argv)
4361 endrec = strtoll(argv[3], NULL, 10);
4363 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4366 fprintf(stderr, "%s: record out of range: %llu\n",
4368 else if (rc == -ENOENT)
4369 fprintf(stderr, "%s: no changelog user: %s\n",
4372 fprintf(stderr, "%s error: %s\n", argv[0],
4381 static int lfs_fid2path(int argc, char **argv)
4383 struct option long_opts[] = {
4384 {"cur", no_argument, 0, 'c'},
4385 {"link", required_argument, 0, 'l'},
4386 {"rec", required_argument, 0, 'r'},
4389 char short_opts[] = "cl:r:";
4390 char *device, *fid, *path;
4391 long long recno = -1;
4397 while ((rc = getopt_long(argc, argv, short_opts,
4398 long_opts, NULL)) != -1) {
4404 linkno = strtol(optarg, NULL, 10);
4407 recno = strtoll(optarg, NULL, 10);
4412 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4413 argv[0], argv[optind - 1]);
4421 device = argv[optind++];
4422 path = calloc(1, PATH_MAX);
4424 fprintf(stderr, "error: Not enough memory\n");
4429 while (optind < argc) {
4430 fid = argv[optind++];
4432 lnktmp = (linkno >= 0) ? linkno : 0;
4434 int oldtmp = lnktmp;
4435 long long rectmp = recno;
4437 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4440 fprintf(stderr, "%s: error on FID %s: %s\n",
4441 argv[0], fid, strerror(errno = -rc2));
4448 fprintf(stdout, "%lld ", rectmp);
4449 if (device[0] == '/') {
4450 fprintf(stdout, "%s", device);
4451 if (device[strlen(device) - 1] != '/')
4452 fprintf(stdout, "/");
4453 } else if (path[0] == '\0') {
4454 fprintf(stdout, "/");
4456 fprintf(stdout, "%s\n", path);
4459 /* specified linkno */
4461 if (oldtmp == lnktmp)
4471 static int lfs_path2fid(int argc, char **argv)
4473 struct option long_opts[] = {
4474 {"parents", no_argument, 0, 'p'},
4478 const char short_opts[] = "p";
4479 const char *sep = "";
4482 bool show_parents = false;
4484 while ((rc = getopt_long(argc, argv, short_opts,
4485 long_opts, NULL)) != -1) {
4488 show_parents = true;
4491 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4492 argv[0], argv[optind - 1]);
4497 if (optind > argc - 1)
4499 else if (optind < argc - 1)
4503 for (path = argv + optind; *path != NULL; path++) {
4505 if (!show_parents) {
4506 err = llapi_path2fid(*path, &fid);
4508 printf("%s%s"DFID"\n",
4509 *sep != '\0' ? *path : "", sep,
4512 char name[NAME_MAX + 1];
4513 unsigned int linkno = 0;
4515 while ((err = llapi_path2parent(*path, linkno, &fid,
4516 name, sizeof(name))) == 0) {
4517 if (*sep != '\0' && linkno == 0)
4518 printf("%s%s", *path, sep);
4520 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4525 /* err == -ENODATA is end-of-loop */
4526 if (linkno > 0 && err == -ENODATA) {
4533 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4534 argv[0], show_parents ? "parent " : "", *path,
4546 static int lfs_data_version(int argc, char **argv)
4553 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4558 while ((c = getopt(argc, argv, "nrw")) != -1) {
4561 data_version_flags = 0;
4564 data_version_flags |= LL_DV_RD_FLUSH;
4567 data_version_flags |= LL_DV_WR_FLUSH;
4576 path = argv[optind];
4577 fd = open(path, O_RDONLY);
4579 err(errno, "cannot open file %s", path);
4581 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4583 err(errno, "cannot get version for %s", path);
4585 printf("%ju" "\n", (uintmax_t)data_version);
4591 static int lfs_hsm_state(int argc, char **argv)
4596 struct hsm_user_state hus;
4604 rc = llapi_hsm_state_get(path, &hus);
4606 fprintf(stderr, "can't get hsm state for %s: %s\n",
4607 path, strerror(errno = -rc));
4611 /* Display path name and status flags */
4612 printf("%s: (0x%08x)", path, hus.hus_states);
4614 if (hus.hus_states & HS_RELEASED)
4615 printf(" released");
4616 if (hus.hus_states & HS_EXISTS)
4618 if (hus.hus_states & HS_DIRTY)
4620 if (hus.hus_states & HS_ARCHIVED)
4621 printf(" archived");
4622 /* Display user-settable flags */
4623 if (hus.hus_states & HS_NORELEASE)
4624 printf(" never_release");
4625 if (hus.hus_states & HS_NOARCHIVE)
4626 printf(" never_archive");
4627 if (hus.hus_states & HS_LOST)
4628 printf(" lost_from_hsm");
4630 if (hus.hus_archive_id != 0)
4631 printf(", archive_id:%d", hus.hus_archive_id);
4634 } while (++i < argc);
4639 #define LFS_HSM_SET 0
4640 #define LFS_HSM_CLEAR 1
4643 * Generic function to set or clear HSM flags.
4644 * Used by hsm_set and hsm_clear.
4646 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4648 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4650 struct option long_opts[] = {
4651 {"lost", 0, 0, 'l'},
4652 {"norelease", 0, 0, 'r'},
4653 {"noarchive", 0, 0, 'a'},
4654 {"archived", 0, 0, 'A'},
4655 {"dirty", 0, 0, 'd'},
4656 {"exists", 0, 0, 'e'},
4659 char short_opts[] = "lraAde";
4667 while ((c = getopt_long(argc, argv, short_opts,
4668 long_opts, NULL)) != -1) {
4674 mask |= HS_NOARCHIVE;
4677 mask |= HS_ARCHIVED;
4680 mask |= HS_NORELEASE;
4691 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4692 argv[0], argv[optind - 1]);
4697 /* User should have specified a flag */
4701 while (optind < argc) {
4703 path = argv[optind];
4705 /* If mode == 0, this means we apply the mask. */
4706 if (mode == LFS_HSM_SET)
4707 rc = llapi_hsm_state_set(path, mask, 0, 0);
4709 rc = llapi_hsm_state_set(path, 0, mask, 0);
4712 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4713 path, strerror(errno = -rc));
4722 static int lfs_hsm_action(int argc, char **argv)
4727 struct hsm_current_action hca;
4728 struct hsm_extent he;
4729 enum hsm_user_action hua;
4730 enum hsm_progress_states hps;
4738 rc = llapi_hsm_current_action(path, &hca);
4740 fprintf(stderr, "can't get hsm action for %s: %s\n",
4741 path, strerror(errno = -rc));
4744 he = hca.hca_location;
4745 hua = hca.hca_action;
4746 hps = hca.hca_state;
4748 printf("%s: %s", path, hsm_user_action2name(hua));
4750 /* Skip file without action */
4751 if (hca.hca_action == HUA_NONE) {
4756 printf(" %s ", hsm_progress_state2name(hps));
4758 if ((hps == HPS_RUNNING) &&
4759 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4760 printf("(%llu bytes moved)\n",
4761 (unsigned long long)he.length);
4762 else if ((he.offset + he.length) == LUSTRE_EOF)
4763 printf("(from %llu to EOF)\n",
4764 (unsigned long long)he.offset);
4766 printf("(from %llu to %llu)\n",
4767 (unsigned long long)he.offset,
4768 (unsigned long long)(he.offset + he.length));
4770 } while (++i < argc);
4775 static int lfs_hsm_set(int argc, char **argv)
4777 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4780 static int lfs_hsm_clear(int argc, char **argv)
4782 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4786 * Check file state and return its fid, to be used by lfs_hsm_request().
4788 * \param[in] file Path to file to check
4789 * \param[in,out] fid Pointer to allocated lu_fid struct.
4790 * \param[in,out] last_dev Pointer to last device id used.
4792 * \return 0 on success.
4794 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4800 rc = lstat(file, &st);
4802 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4805 /* Checking for regular file as archiving as posix copytool
4806 * rejects archiving files other than regular files
4808 if (!S_ISREG(st.st_mode)) {
4809 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4812 /* A request should be ... */
4813 if (*last_dev != st.st_dev && *last_dev != 0) {
4814 fprintf(stderr, "All files should be "
4815 "on the same filesystem: %s\n", file);
4818 *last_dev = st.st_dev;
4820 rc = llapi_path2fid(file, fid);
4822 fprintf(stderr, "Cannot read FID of %s: %s\n",
4823 file, strerror(-rc));
4829 /* Fill an HSM HUR item with a given file name.
4831 * If mntpath is set, then the filename is actually a FID, and no
4832 * lookup on the filesystem will be performed.
4834 * \param[in] hur the user request to fill
4835 * \param[in] idx index of the item inside the HUR to fill
4836 * \param[in] mntpath mountpoint of Lustre
4837 * \param[in] fname filename (if mtnpath is NULL)
4838 * or FID (if mntpath is set)
4839 * \param[in] last_dev pointer to last device id used
4841 * \retval 0 on success
4842 * \retval CMD_HELP or a negative errno on error
4844 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4845 const char *mntpath, const char *fname,
4848 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4851 hui->hui_extent.length = -1;
4853 if (mntpath != NULL) {
4856 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4860 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4865 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4869 hur->hur_request.hr_itemcount++;
4874 static int lfs_hsm_request(int argc, char **argv, int action)
4876 struct option long_opts[] = {
4877 {"filelist", 1, 0, 'l'},
4878 {"data", 1, 0, 'D'},
4879 {"archive", 1, 0, 'a'},
4880 {"mntpath", 1, 0, 'm'},
4884 char short_opts[] = "l:D:a:m:";
4885 struct hsm_user_request *hur, *oldhur;
4890 char *filelist = NULL;
4891 char fullpath[PATH_MAX];
4892 char *opaque = NULL;
4896 int nbfile_alloc = 0;
4897 char *some_file = NULL;
4898 char *mntpath = NULL;
4904 while ((c = getopt_long(argc, argv, short_opts,
4905 long_opts, NULL)) != -1) {
4914 if (action != HUA_ARCHIVE &&
4915 action != HUA_REMOVE) {
4917 "error: -a is supported only "
4918 "when archiving or removing\n");
4921 archive_id = atoi(optarg);
4924 if (some_file == NULL) {
4926 some_file = strdup(optarg);
4932 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4933 argv[0], argv[optind - 1]);
4938 /* All remaining args are files, so we have at least nbfile */
4939 nbfile = argc - optind;
4941 if ((nbfile == 0) && (filelist == NULL))
4945 opaque_len = strlen(opaque);
4947 /* Alloc the request structure with enough place to store all files
4948 * from command line. */
4949 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4951 fprintf(stderr, "Cannot create the request: %s\n",
4955 nbfile_alloc = nbfile;
4957 hur->hur_request.hr_action = action;
4958 hur->hur_request.hr_archive_id = archive_id;
4959 hur->hur_request.hr_flags = 0;
4961 /* All remaining args are files, add them */
4962 if (nbfile != 0 && some_file == NULL)
4963 some_file = strdup(argv[optind]);
4965 for (i = 0; i < nbfile; i++) {
4966 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4972 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4974 /* If a filelist was specified, read the filelist from it. */
4975 if (filelist != NULL) {
4976 fp = fopen(filelist, "r");
4978 fprintf(stderr, "Cannot read the file list %s: %s\n",
4979 filelist, strerror(errno));
4984 while ((rc = getline(&line, &len, fp)) != -1) {
4985 /* If allocated buffer was too small, get something
4987 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4990 nbfile_alloc = nbfile_alloc * 2 + 1;
4992 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4995 fprintf(stderr, "hsm: cannot allocate "
4996 "the request: %s\n",
5003 size = hur_len(oldhur);
5005 fprintf(stderr, "hsm: cannot allocate "
5006 "%u files + %u bytes data\n",
5007 oldhur->hur_request.hr_itemcount,
5008 oldhur->hur_request.hr_data_len);
5015 memcpy(hur, oldhur, size);
5020 if (line[strlen(line) - 1] == '\n')
5021 line[strlen(line) - 1] = '\0';
5023 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5024 mntpath, line, &last_dev);
5030 if (some_file == NULL) {
5040 /* If a --data was used, add it to the request */
5041 hur->hur_request.hr_data_len = opaque_len;
5043 memcpy(hur_data(hur), opaque, opaque_len);
5045 /* Send the HSM request */
5046 if (realpath(some_file, fullpath) == NULL) {
5047 fprintf(stderr, "Could not find path '%s': %s\n",
5048 some_file, strerror(errno));
5050 rc = llapi_hsm_request(fullpath, hur);
5052 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5053 some_file, strerror(-rc));
5063 static int lfs_hsm_archive(int argc, char **argv)
5065 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5068 static int lfs_hsm_restore(int argc, char **argv)
5070 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5073 static int lfs_hsm_release(int argc, char **argv)
5075 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5078 static int lfs_hsm_remove(int argc, char **argv)
5080 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5083 static int lfs_hsm_cancel(int argc, char **argv)
5085 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5088 static int lfs_swap_layouts(int argc, char **argv)
5093 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5094 SWAP_LAYOUTS_KEEP_MTIME |
5095 SWAP_LAYOUTS_KEEP_ATIME);
5098 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5100 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5102 enum lu_ladvise_type advice;
5105 advice < ARRAY_SIZE(ladvise_names); advice++) {
5106 if (ladvise_names[advice] == NULL)
5108 if (strcmp(string, ladvise_names[advice]) == 0)
5112 return LU_LADVISE_INVALID;
5115 static int lfs_ladvise(int argc, char **argv)
5117 struct option long_opts[] = {
5118 {"advice", required_argument, 0, 'a'},
5119 {"background", no_argument, 0, 'b'},
5120 {"end", required_argument, 0, 'e'},
5121 {"start", required_argument, 0, 's'},
5122 {"length", required_argument, 0, 'l'},
5125 char short_opts[] = "a:be:l:s:";
5130 struct llapi_lu_ladvise advice;
5131 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5132 unsigned long long start = 0;
5133 unsigned long long end = LUSTRE_EOF;
5134 unsigned long long length = 0;
5135 unsigned long long size_units;
5136 unsigned long long flags = 0;
5139 while ((c = getopt_long(argc, argv, short_opts,
5140 long_opts, NULL)) != -1) {
5143 advice_type = lfs_get_ladvice(optarg);
5144 if (advice_type == LU_LADVISE_INVALID) {
5145 fprintf(stderr, "%s: invalid advice type "
5146 "'%s'\n", argv[0], optarg);
5147 fprintf(stderr, "Valid types:");
5149 for (advice_type = 0;
5150 advice_type < ARRAY_SIZE(ladvise_names);
5152 if (ladvise_names[advice_type] == NULL)
5154 fprintf(stderr, " %s",
5155 ladvise_names[advice_type]);
5157 fprintf(stderr, "\n");
5167 rc = llapi_parse_size(optarg, &end,
5170 fprintf(stderr, "%s: bad end offset '%s'\n",
5177 rc = llapi_parse_size(optarg, &start,
5180 fprintf(stderr, "%s: bad start offset "
5181 "'%s'\n", argv[0], optarg);
5187 rc = llapi_parse_size(optarg, &length,
5190 fprintf(stderr, "%s: bad length '%s'\n",
5198 fprintf(stderr, "%s: option '%s' unrecognized\n",
5199 argv[0], argv[optind - 1]);
5204 if (advice_type == LU_LADVISE_INVALID) {
5205 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5206 fprintf(stderr, "Valid types:");
5207 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5209 if (ladvise_names[advice_type] == NULL)
5211 fprintf(stderr, " %s", ladvise_names[advice_type]);
5213 fprintf(stderr, "\n");
5217 if (argc <= optind) {
5218 fprintf(stderr, "%s: please give one or more file names\n",
5223 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5224 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5229 if (end == LUSTRE_EOF && length != 0)
5230 end = start + length;
5233 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5234 argv[0], start, end);
5238 while (optind < argc) {
5241 path = argv[optind++];
5243 fd = open(path, O_RDONLY);
5245 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5246 argv[0], path, strerror(errno));
5251 advice.lla_start = start;
5252 advice.lla_end = end;
5253 advice.lla_advice = advice_type;
5254 advice.lla_value1 = 0;
5255 advice.lla_value2 = 0;
5256 advice.lla_value3 = 0;
5257 advice.lla_value4 = 0;
5258 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5261 fprintf(stderr, "%s: cannot give advice '%s' to file "
5262 "'%s': %s\n", argv[0],
5263 ladvise_names[advice_type],
5264 path, strerror(errno));
5267 if (rc == 0 && rc2 < 0)
5273 static int lfs_list_commands(int argc, char **argv)
5275 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5277 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5282 int main(int argc, char **argv)
5286 /* Ensure that liblustreapi constructor has run */
5287 if (!liblustreapi_initialized)
5288 fprintf(stderr, "liblustreapi was not properly initialized\n");
5292 Parser_init("lfs > ", cmdlist);
5294 progname = argv[0]; /* Used in error messages */
5296 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5298 rc = Parser_commands();
5301 return rc < 0 ? -rc : rc;
5304 #ifdef _LUSTRE_IDL_H_
5305 /* Everything we need here should be included by lustreapi.h. */
5306 # error "lfs should not depend on lustre_idl.h"
5307 #endif /* _LUSTRE_IDL_H_ */