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 {"component-add", no_argument, 0, LFS_COMP_ADD_OPT},
1307 {"component-del", no_argument, 0, LFS_COMP_DEL_OPT},
1308 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1309 {"component-set", no_argument, 0, LFS_COMP_SET_OPT},
1310 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1311 /* This formerly implied "stripe-count", but was explicitly
1312 * made "stripe-count" for consistency with other options,
1313 * and to separate it from "mdt-count" when DNE arrives. */
1314 {"count", required_argument, 0, 'c'},
1316 {"stripe-count", required_argument, 0, 'c'},
1317 {"stripe_count", required_argument, 0, 'c'},
1318 {"delete", no_argument, 0, 'd'},
1319 {"component-end", required_argument, 0, 'E'},
1320 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1321 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1322 /* This formerly implied "stripe-index", but was explicitly
1323 * made "stripe-index" for consistency with other options,
1324 * and to separate it from "mdt-index" when DNE arrives. */
1325 {"index", required_argument, 0, 'i'},
1327 {"stripe-index", required_argument, 0, 'i'},
1328 {"stripe_index", required_argument, 0, 'i'},
1329 {"component-id", required_argument, 0, 'I'},
1330 {"mdt", required_argument, 0, 'm'},
1331 {"mdt-index", required_argument, 0, 'm'},
1332 {"mdt_index", required_argument, 0, 'm'},
1333 /* --non-block is only valid in migrate mode */
1334 {"non-block", no_argument, 0, 'n'},
1335 {"ost", required_argument, 0, 'o'},
1336 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1337 {"ost-list", required_argument, 0, 'o'},
1338 {"ost_list", required_argument, 0, 'o'},
1340 {"pool", required_argument, 0, 'p'},
1341 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1342 /* This formerly implied "--stripe-size", but was confusing
1343 * with "lfs find --size|-s", which means "file size", so use
1344 * the consistent "--stripe-size|-S" for all commands. */
1345 {"size", required_argument, 0, 's'},
1347 {"stripe-size", required_argument, 0, 'S'},
1348 {"stripe_size", required_argument, 0, 'S'},
1349 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1350 /* --verbose is only valid in migrate mode */
1351 {"verbose", no_argument, 0, 'v'},
1355 setstripe_args_init(&lsa);
1357 if (strcmp(argv[0], "migrate") == 0)
1358 migrate_mode = true;
1360 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1361 long_opts, NULL)) >= 0) {
1366 case LFS_COMP_ADD_OPT:
1369 case LFS_COMP_DEL_OPT:
1372 case LFS_COMP_FLAGS_OPT:
1373 result = comp_name2flags(&lsa.lsa_comp_flags, optarg);
1375 fprintf(stderr, "error: %s: bad comp flags "
1376 "'%s'\n", argv[0], optarg);
1380 case LFS_COMP_SET_OPT:
1384 if (!migrate_mode) {
1385 fprintf(stderr, "--block is valid only for"
1389 migration_block = true;
1392 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1393 if (strcmp(argv[optind - 1], "--count") == 0)
1394 fprintf(stderr, "warning: '--count' deprecated"
1395 ", use '--stripe-count' instead\n");
1397 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1399 fprintf(stderr, "error: %s: bad stripe count "
1400 "'%s'\n", argv[0], optarg);
1405 /* delete the default striping pattern */
1409 if (lsa.lsa_comp_end != 0) {
1410 result = comp_args_to_layout(&layout, &lsa);
1414 setstripe_args_init(&lsa);
1417 if (!strncmp(optarg, "-1", strlen("-1")) ||
1418 !strncmp(optarg, "EOF", strlen("EOF")) ||
1419 !strncmp(optarg, "eof", strlen("eof"))) {
1420 lsa.lsa_comp_end = LUSTRE_EOF;
1422 result = llapi_parse_size(optarg,
1426 fprintf(stderr, "error: %s: "
1427 "bad component end '%s'\n",
1434 if (strcmp(argv[optind - 1], "--index") == 0)
1435 fprintf(stderr, "warning: '--index' deprecated"
1436 ", use '--stripe-index' instead\n");
1437 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1439 fprintf(stderr, "error: %s: bad stripe offset "
1440 "'%s'\n", argv[0], optarg);
1445 comp_id = strtoul(optarg, &end, 0);
1446 if (*end != '\0' || comp_id == 0) {
1447 fprintf(stderr, "error: %s: bad comp ID "
1448 "'%s'\n", argv[0], optarg);
1453 if (!migrate_mode) {
1454 fprintf(stderr, "--mdt-index is valid only for"
1458 mdt_idx_arg = optarg;
1461 if (!migrate_mode) {
1462 fprintf(stderr, "--non-block is valid only for"
1466 migration_flags |= MIGRATION_NONBLOCK;
1469 lsa.lsa_nr_osts = parse_targets(osts,
1470 sizeof(osts) / sizeof(__u32),
1471 lsa.lsa_nr_osts, optarg);
1472 if (lsa.lsa_nr_osts < 0) {
1474 "error: %s: bad OST indices '%s'\n",
1479 lsa.lsa_osts = osts;
1480 if (lsa.lsa_stripe_off == -1)
1481 lsa.lsa_stripe_off = osts[0];
1484 result = verify_pool_name(argv[0], optarg);
1487 lsa.lsa_pool_name = optarg;
1489 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1491 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1492 fprintf(stderr, "warning: '--size|-s' deprecated, "
1493 "use '--stripe-size|-S' instead\n");
1495 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1497 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1500 fprintf(stderr, "error: %s: bad stripe size "
1501 "'%s'\n", argv[0], optarg);
1506 if (!migrate_mode) {
1507 fprintf(stderr, "--verbose is valid only for"
1511 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1518 fname = argv[optind];
1520 if (lsa.lsa_comp_end != 0) {
1521 result = comp_args_to_layout(&layout, &lsa);
1526 if (optind == argc) {
1527 fprintf(stderr, "error: %s: missing filename|dirname\n",
1532 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1533 * altered by user space tool, so we don't need to support the
1534 * --component-set for this moment. */
1535 if (comp_set != 0) {
1536 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1541 if ((delete + comp_set + comp_del + comp_add) > 1) {
1542 fprintf(stderr, "error: %s: can't specify --component-set, "
1543 "--component-del, --component-add or -d together\n",
1548 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1549 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1550 fprintf(stderr, "error: %s: can't specify -d with "
1551 "-s, -c, -o, -p, -I, -F or -E options\n",
1556 if ((comp_set || comp_del) &&
1557 (setstripe_args_specified(&lsa) || layout != NULL)) {
1558 fprintf(stderr, "error: %s: can't specify --component-del or "
1559 "--component-set with -s, -c, -o, -p or -E options.\n",
1564 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1565 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1566 "--component-del option.\n", argv[0]);
1571 if (layout == NULL) {
1572 fprintf(stderr, "error: %s: -E option must be present"
1573 "in --component-add mode.\n", argv[0]);
1576 result = adjust_first_extent(fname, layout);
1581 if (mdt_idx_arg != NULL && optind > 3) {
1582 fprintf(stderr, "error: %s: cannot specify -m with other "
1583 "options\n", argv[0]);
1587 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1589 "error: %s: cannot specify --non-block and --block\n",
1594 /* support --component-id option for migrate later. */
1595 if (migrate_mode && comp_id != 0) {
1596 fprintf(stderr, "error: %s: -I isn't supported yet.\n",
1601 if (mdt_idx_arg != NULL) {
1602 /* initialize migrate mdt parameters */
1603 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1605 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1606 argv[0], mdt_idx_arg);
1609 migrate_mdt_param.fp_migrate = 1;
1610 } else if (layout == NULL) {
1611 /* initialize stripe parameters */
1612 param = calloc(1, offsetof(typeof(*param),
1613 lsp_osts[lsa.lsa_nr_osts]));
1614 if (param == NULL) {
1615 fprintf(stderr, "error: %s: %s\n", argv[0],
1620 param->lsp_stripe_size = lsa.lsa_stripe_size;
1621 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1622 param->lsp_stripe_count = lsa.lsa_stripe_count;
1623 param->lsp_stripe_pattern = 0;
1624 param->lsp_pool = lsa.lsa_pool_name;
1625 param->lsp_is_specific = false;
1626 if (lsa.lsa_nr_osts > 0) {
1627 if (lsa.lsa_stripe_count > 0 &&
1628 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1629 fprintf(stderr, "error: %s: stripe count '%d' "
1630 "doesn't match the number of OSTs: %d\n"
1631 , argv[0], lsa.lsa_stripe_count,
1637 param->lsp_is_specific = true;
1638 param->lsp_stripe_count = lsa.lsa_nr_osts;
1639 memcpy(param->lsp_osts, osts,
1640 sizeof(*osts) * lsa.lsa_nr_osts);
1644 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1646 if (mdt_idx_arg != NULL) {
1647 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1648 op = "migrate mdt objects of";
1649 } else if (migrate_mode) {
1650 result = lfs_migrate(fname, migration_flags, param,
1652 op = "migrate ost objects of";
1653 } else if (comp_set != 0) {
1654 result = lfs_component_set(fname, comp_id,
1655 lsa.lsa_comp_flags);
1656 op = "modify component flags of";
1657 } else if (comp_del != 0) {
1658 result = lfs_component_del(fname, comp_id,
1659 lsa.lsa_comp_flags);
1660 op = "delete component of";
1661 } else if (comp_add != 0) {
1662 result = lfs_component_add(fname, layout);
1663 op = "add component to";
1664 } else if (layout != NULL) {
1665 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1671 op = "create composite";
1673 result = llapi_file_open_param(fname,
1680 op = "create striped";
1683 /* Save the first error encountered. */
1686 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1688 lsa.lsa_pool_name != NULL && result == EINVAL ?
1689 "OST not in pool?" : strerror(errno));
1695 llapi_layout_free(layout);
1698 llapi_layout_free(layout);
1702 static int lfs_poollist(int argc, char **argv)
1707 return llapi_poollist(argv[1]);
1710 static int set_time(time_t *time, time_t *set, char *str)
1717 else if (str[0] == '-')
1723 t = strtol(str, NULL, 0);
1724 if (*time < t * 24 * 60 * 60) {
1727 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1731 *set = *time - t * 24 * 60 * 60;
1734 static int name2uid(unsigned int *id, const char *name)
1736 struct passwd *passwd;
1738 passwd = getpwnam(name);
1741 *id = passwd->pw_uid;
1746 static int name2gid(unsigned int *id, const char *name)
1748 struct group *group;
1750 group = getgrnam(name);
1753 *id = group->gr_gid;
1758 static inline int name2projid(unsigned int *id, const char *name)
1763 static int uid2name(char **name, unsigned int id)
1765 struct passwd *passwd;
1767 passwd = getpwuid(id);
1770 *name = passwd->pw_name;
1775 static inline int gid2name(char **name, unsigned int id)
1777 struct group *group;
1779 group = getgrgid(id);
1782 *name = group->gr_name;
1787 static int name2layout(__u32 *layout, char *name)
1792 for (ptr = name; ; ptr = NULL) {
1793 lyt = strtok(ptr, ",");
1796 if (strcmp(lyt, "released") == 0)
1797 *layout |= LOV_PATTERN_F_RELEASED;
1798 else if (strcmp(lyt, "raid0") == 0)
1799 *layout |= LOV_PATTERN_RAID0;
1806 static int lfs_find(int argc, char **argv)
1811 struct find_param param = {
1815 struct option long_opts[] = {
1816 {"atime", required_argument, 0, 'A'},
1817 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1818 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1819 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1820 {"stripe-count", required_argument, 0, 'c'},
1821 {"stripe_count", required_argument, 0, 'c'},
1822 {"ctime", required_argument, 0, 'C'},
1823 {"maxdepth", required_argument, 0, 'D'},
1824 {"component-end", required_argument, 0, 'E'},
1825 {"gid", required_argument, 0, 'g'},
1826 {"group", required_argument, 0, 'G'},
1827 {"mdt-hash", required_argument, 0, 'H'},
1828 {"stripe-index", required_argument, 0, 'i'},
1829 {"stripe_index", required_argument, 0, 'i'},
1830 /*{"component-id", required_argument, 0, 'I'},*/
1831 {"layout", required_argument, 0, 'L'},
1832 {"mdt", required_argument, 0, 'm'},
1833 {"mdt-index", required_argument, 0, 'm'},
1834 {"mdt_index", required_argument, 0, 'm'},
1835 {"mtime", required_argument, 0, 'M'},
1836 {"name", required_argument, 0, 'n'},
1837 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1838 {"obd", required_argument, 0, 'O'},
1839 {"ost", required_argument, 0, 'O'},
1840 /* no short option for pool, p/P already used */
1841 {"pool", required_argument, 0, LFS_POOL_OPT},
1842 {"print0", no_argument, 0, 'p'},
1843 {"print", no_argument, 0, 'P'},
1844 {"size", required_argument, 0, 's'},
1845 {"stripe-size", required_argument, 0, 'S'},
1846 {"stripe_size", required_argument, 0, 'S'},
1847 {"type", required_argument, 0, 't'},
1848 {"mdt-count", required_argument, 0, 'T'},
1849 {"uid", required_argument, 0, 'u'},
1850 {"user", required_argument, 0, 'U'},
1863 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1864 while ((c = getopt_long_only(argc, argv,
1865 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1866 long_opts, NULL)) >= 0) {
1871 /* '!' is part of option */
1872 /* when getopt_long_only() finds a string which is not
1873 * an option nor a known option argument it returns 1
1874 * in that case if we already have found pathstart and pathend
1875 * (i.e. we have the list of pathnames),
1876 * the only supported value is "!"
1878 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1879 if (!isoption && pathend != -1) {
1880 fprintf(stderr, "err: %s: filename|dirname must either "
1881 "precede options or follow options\n",
1886 if (!isoption && pathstart == -1)
1887 pathstart = optind - 1;
1888 if (isoption && pathstart != -1 && pathend == -1)
1889 pathend = optind - 2;
1895 /* unknown; opt is "!" or path component,
1896 * checking done above.
1898 if (strcmp(optarg, "!") == 0)
1902 xtime = ¶m.fp_atime;
1903 xsign = ¶m.fp_asign;
1904 param.fp_exclude_atime = !!neg_opt;
1905 /* no break, this falls through to 'C' for ctime */
1908 xtime = ¶m.fp_ctime;
1909 xsign = ¶m.fp_csign;
1910 param.fp_exclude_ctime = !!neg_opt;
1912 /* no break, this falls through to 'M' for mtime */
1915 xtime = ¶m.fp_mtime;
1916 xsign = ¶m.fp_msign;
1917 param.fp_exclude_mtime = !!neg_opt;
1919 rc = set_time(&t, xtime, optarg);
1920 if (rc == INT_MAX) {
1927 case LFS_COMP_COUNT_OPT:
1928 if (optarg[0] == '+') {
1929 param.fp_comp_count_sign = -1;
1931 } else if (optarg[0] == '-') {
1932 param.fp_comp_count_sign = 1;
1936 param.fp_comp_count = strtoul(optarg, &endptr, 0);
1937 if (*endptr != '\0') {
1938 fprintf(stderr, "error: bad component count "
1942 param.fp_check_comp_count = 1;
1943 param.fp_exclude_comp_count = !!neg_opt;
1945 case LFS_COMP_FLAGS_OPT:
1946 rc = comp_name2flags(¶m.fp_comp_flags, optarg);
1948 fprintf(stderr, "error: bad component flags "
1952 param.fp_check_comp_flags = 1;
1953 param.fp_exclude_comp_flags = !!neg_opt;
1955 case LFS_COMP_START_OPT:
1956 if (optarg[0] == '+') {
1957 param.fp_comp_start_sign = -1;
1959 } else if (optarg[0] == '-') {
1960 param.fp_comp_start_sign = 1;
1964 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
1965 ¶m.fp_comp_start_units, 0);
1967 fprintf(stderr, "error: bad component start "
1971 param.fp_check_comp_start = 1;
1972 param.fp_exclude_comp_start = !!neg_opt;
1975 if (optarg[0] == '+') {
1976 param.fp_stripe_count_sign = -1;
1978 } else if (optarg[0] == '-') {
1979 param.fp_stripe_count_sign = 1;
1983 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1984 if (*endptr != '\0') {
1985 fprintf(stderr,"error: bad stripe_count '%s'\n",
1990 param.fp_check_stripe_count = 1;
1991 param.fp_exclude_stripe_count = !!neg_opt;
1994 param.fp_max_depth = strtol(optarg, 0, 0);
1997 if (optarg[0] == '+') {
1998 param.fp_comp_end_sign = -1;
2000 } else if (optarg[0] == '-') {
2001 param.fp_comp_end_sign = 1;
2005 rc = llapi_parse_size(optarg, ¶m.fp_comp_end,
2006 ¶m.fp_comp_end_units, 0);
2008 fprintf(stderr, "error: bad component end "
2012 param.fp_check_comp_end = 1;
2013 param.fp_exclude_comp_end = !!neg_opt;
2017 rc = name2gid(¶m.fp_gid, optarg);
2019 param.fp_gid = strtoul(optarg, &endptr, 10);
2020 if (*endptr != '\0') {
2021 fprintf(stderr, "Group/GID: %s cannot "
2022 "be found.\n", optarg);
2027 param.fp_exclude_gid = !!neg_opt;
2028 param.fp_check_gid = 1;
2031 param.fp_hash_type = check_hashtype(optarg);
2032 if (param.fp_hash_type == 0) {
2033 fprintf(stderr, "error: bad hash_type '%s'\n",
2038 param.fp_check_hash_type = 1;
2039 param.fp_exclude_hash_type = !!neg_opt;
2042 ret = name2layout(¶m.fp_layout, optarg);
2045 param.fp_exclude_layout = !!neg_opt;
2046 param.fp_check_layout = 1;
2050 rc = name2uid(¶m.fp_uid, optarg);
2052 param.fp_uid = strtoul(optarg, &endptr, 10);
2053 if (*endptr != '\0') {
2054 fprintf(stderr, "User/UID: %s cannot "
2055 "be found.\n", optarg);
2060 param.fp_exclude_uid = !!neg_opt;
2061 param.fp_check_uid = 1;
2064 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2066 "Pool name %s is too long"
2067 " (max is %d)\n", optarg,
2072 /* we do check for empty pool because empty pool
2073 * is used to find V1 lov attributes */
2074 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2075 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2076 param.fp_exclude_pool = !!neg_opt;
2077 param.fp_check_pool = 1;
2080 param.fp_pattern = (char *)optarg;
2081 param.fp_exclude_pattern = !!neg_opt;
2086 char *buf, *token, *next, *p;
2090 buf = strdup(optarg);
2096 param.fp_exclude_obd = !!neg_opt;
2099 while (token && *token) {
2100 token = strchr(token, ',');
2107 param.fp_exclude_mdt = !!neg_opt;
2108 param.fp_num_alloc_mdts += len;
2109 tmp = realloc(param.fp_mdt_uuid,
2110 param.fp_num_alloc_mdts *
2111 sizeof(*param.fp_mdt_uuid));
2117 param.fp_mdt_uuid = tmp;
2119 param.fp_exclude_obd = !!neg_opt;
2120 param.fp_num_alloc_obds += len;
2121 tmp = realloc(param.fp_obd_uuid,
2122 param.fp_num_alloc_obds *
2123 sizeof(*param.fp_obd_uuid));
2129 param.fp_obd_uuid = tmp;
2131 for (token = buf; token && *token; token = next) {
2132 struct obd_uuid *puuid;
2135 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2138 ¶m.fp_obd_uuid[param.fp_num_obds++];
2140 p = strchr(token, ',');
2147 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2152 strncpy(puuid->uuid, token,
2153 sizeof(puuid->uuid));
2161 param.fp_zero_end = 1;
2166 if (optarg[0] == '+') {
2167 param.fp_size_sign = -1;
2169 } else if (optarg[0] == '-') {
2170 param.fp_size_sign = 1;
2174 ret = llapi_parse_size(optarg, ¶m.fp_size,
2175 ¶m.fp_size_units, 0);
2177 fprintf(stderr, "error: bad file size '%s'\n",
2181 param.fp_check_size = 1;
2182 param.fp_exclude_size = !!neg_opt;
2185 if (optarg[0] == '+') {
2186 param.fp_stripe_size_sign = -1;
2188 } else if (optarg[0] == '-') {
2189 param.fp_stripe_size_sign = 1;
2193 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2194 ¶m.fp_stripe_size_units, 0);
2196 fprintf(stderr, "error: bad stripe_size '%s'\n",
2200 param.fp_check_stripe_size = 1;
2201 param.fp_exclude_stripe_size = !!neg_opt;
2204 param.fp_exclude_type = !!neg_opt;
2205 switch (optarg[0]) {
2207 param.fp_type = S_IFBLK;
2210 param.fp_type = S_IFCHR;
2213 param.fp_type = S_IFDIR;
2216 param.fp_type = S_IFREG;
2219 param.fp_type = S_IFLNK;
2222 param.fp_type = S_IFIFO;
2225 param.fp_type = S_IFSOCK;
2228 fprintf(stderr, "error: %s: bad type '%s'\n",
2235 if (optarg[0] == '+') {
2236 param.fp_mdt_count_sign = -1;
2238 } else if (optarg[0] == '-') {
2239 param.fp_mdt_count_sign = 1;
2243 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2244 if (*endptr != '\0') {
2245 fprintf(stderr, "error: bad mdt_count '%s'\n",
2250 param.fp_check_mdt_count = 1;
2251 param.fp_exclude_mdt_count = !!neg_opt;
2259 if (pathstart == -1) {
2260 fprintf(stderr, "error: %s: no filename|pathname\n",
2264 } else if (pathend == -1) {
2270 rc = llapi_find(argv[pathstart], ¶m);
2271 if (rc != 0 && ret == 0)
2273 } while (++pathstart < pathend);
2276 fprintf(stderr, "error: %s failed for %s.\n",
2277 argv[0], argv[optind - 1]);
2279 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2280 free(param.fp_obd_uuid);
2282 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2283 free(param.fp_mdt_uuid);
2288 static int lfs_getstripe_internal(int argc, char **argv,
2289 struct find_param *param)
2291 struct option long_opts[] = {
2292 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2293 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2294 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
2295 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2296 /* This formerly implied "stripe-count", but was explicitly
2297 * made "stripe-count" for consistency with other options,
2298 * and to separate it from "mdt-count" when DNE arrives. */
2299 {"count", no_argument, 0, 'c'},
2301 {"stripe-count", no_argument, 0, 'c'},
2302 {"stripe_count", no_argument, 0, 'c'},
2303 {"directory", no_argument, 0, 'd'},
2304 {"default", no_argument, 0, 'D'},
2305 {"component-end", required_argument, 0, 'E'},
2306 {"fid", no_argument, 0, 'F'},
2307 {"generation", no_argument, 0, 'g'},
2308 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
2309 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2310 /* This formerly implied "stripe-index", but was explicitly
2311 * made "stripe-index" for consistency with other options,
2312 * and to separate it from "mdt-index" when DNE arrives. */
2313 {"index", no_argument, 0, 'i'},
2315 {"stripe-index", no_argument, 0, 'i'},
2316 {"stripe_index", no_argument, 0, 'i'},
2317 {"component-id", required_argument, 0, 'I'},
2318 {"layout", no_argument, 0, 'L'},
2319 {"mdt", no_argument, 0, 'm'},
2320 {"mdt-index", no_argument, 0, 'm'},
2321 {"mdt_index", no_argument, 0, 'm'},
2322 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2323 {"mdt-index", no_argument, 0, 'M'},
2324 {"mdt_index", no_argument, 0, 'M'},
2326 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2327 /* This formerly implied "stripe-index", but was confusing
2328 * with "file offset" (which will eventually be needed for
2329 * with different layouts by offset), so deprecate it. */
2330 {"offset", no_argument, 0, 'o'},
2332 {"obd", required_argument, 0, 'O'},
2333 {"ost", required_argument, 0, 'O'},
2334 {"pool", no_argument, 0, 'p'},
2335 {"quiet", no_argument, 0, 'q'},
2336 {"recursive", no_argument, 0, 'r'},
2337 {"raw", no_argument, 0, 'R'},
2338 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2339 /* This formerly implied "--stripe-size", but was confusing
2340 * with "lfs find --size|-s", which means "file size", so use
2341 * the consistent "--stripe-size|-S" for all commands. */
2342 {"size", no_argument, 0, 's'},
2344 {"stripe-size", no_argument, 0, 'S'},
2345 {"stripe_size", no_argument, 0, 'S'},
2346 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
2347 {"verbose", no_argument, 0, 'v'},
2353 while ((c = getopt_long(argc, argv, "cdDE:FghiI:LmMoO:pqrRsSv",
2354 long_opts, NULL)) != -1) {
2357 if (strcmp(argv[optind - 1], "--count") == 0)
2358 fprintf(stderr, "warning: '--count' deprecated,"
2359 " use '--stripe-count' instead\n");
2360 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2361 param->fp_verbose |= VERBOSE_COUNT;
2362 param->fp_max_depth = 0;
2365 case LFS_COMP_COUNT_OPT:
2366 param->fp_verbose |= VERBOSE_COMP_COUNT;
2367 param->fp_max_depth = 0;
2369 case LFS_COMP_FLAGS_OPT:
2370 if (optarg != NULL) {
2371 rc = comp_name2flags(¶m->fp_comp_flags,
2374 param->fp_verbose |=
2376 param->fp_max_depth = 0;
2379 param->fp_check_comp_flags = 1;
2382 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2383 param->fp_max_depth = 0;
2386 case LFS_COMP_START_OPT:
2387 if (optarg != NULL) {
2389 if (tmp[0] == '+') {
2390 param->fp_comp_start_sign = 1;
2392 } else if (tmp[0] == '-') {
2393 param->fp_comp_start_sign = -1;
2396 rc = llapi_parse_size(tmp,
2397 ¶m->fp_comp_start,
2398 ¶m->fp_comp_start_units, 0);
2400 param->fp_verbose |= VERBOSE_COMP_START;
2401 param->fp_max_depth = 0;
2404 param->fp_check_comp_start = 1;
2407 param->fp_verbose |= VERBOSE_COMP_START;
2408 param->fp_max_depth = 0;
2412 param->fp_max_depth = 0;
2415 param->fp_get_default_lmv = 1;
2418 if (optarg != NULL) {
2420 if (tmp[0] == '+') {
2421 param->fp_comp_end_sign = 1;
2423 } else if (tmp[0] == '-') {
2424 param->fp_comp_end_sign = -1;
2427 rc = llapi_parse_size(tmp,
2428 ¶m->fp_comp_end,
2429 ¶m->fp_comp_end_units, 0);
2431 param->fp_verbose |= VERBOSE_COMP_END;
2432 param->fp_max_depth = 0;
2435 param->fp_check_comp_end = 1;
2438 param->fp_verbose |= VERBOSE_COMP_END;
2439 param->fp_max_depth = 0;
2443 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2444 param->fp_verbose |= VERBOSE_DFID;
2445 param->fp_max_depth = 0;
2449 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2450 param->fp_verbose |= VERBOSE_GENERATION;
2451 param->fp_max_depth = 0;
2454 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2456 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2457 "use '--stripe-index|-i' instead\n");
2460 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2461 if (strcmp(argv[optind - 1], "--index") == 0)
2462 fprintf(stderr, "warning: '--index' deprecated"
2463 ", use '--stripe-index' instead\n");
2465 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2466 param->fp_verbose |= VERBOSE_OFFSET;
2467 param->fp_max_depth = 0;
2471 if (optarg != NULL) {
2472 param->fp_comp_id = strtoul(optarg, &end, 0);
2474 param->fp_verbose |= VERBOSE_COMP_ID;
2475 param->fp_max_depth = 0;
2478 param->fp_check_comp_id = 1;
2481 param->fp_max_depth = 0;
2482 param->fp_verbose |= VERBOSE_COMP_ID;
2486 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2487 param->fp_verbose |= VERBOSE_LAYOUT;
2488 param->fp_max_depth = 0;
2491 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2493 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2494 fprintf(stderr, "warning: '-M' deprecated"
2495 ", use '-m' instead\n");
2499 if (!(param->fp_verbose & VERBOSE_DETAIL))
2500 param->fp_max_depth = 0;
2501 param->fp_verbose |= VERBOSE_MDTINDEX;
2504 if (param->fp_obd_uuid) {
2506 "error: %s: only one obduuid allowed",
2510 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2513 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2514 param->fp_verbose |= VERBOSE_POOL;
2515 param->fp_max_depth = 0;
2522 param->fp_recursive = 1;
2527 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2529 fprintf(stderr, "warning: '--size|-s' deprecated, "
2530 "use '--stripe-size|-S' instead\n");
2531 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2533 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2534 param->fp_verbose |= VERBOSE_SIZE;
2535 param->fp_max_depth = 0;
2539 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2549 if (param->fp_recursive)
2550 param->fp_max_depth = -1;
2551 else if (param->fp_verbose & VERBOSE_DETAIL)
2552 param->fp_max_depth = 1;
2554 if (!param->fp_verbose)
2555 param->fp_verbose = VERBOSE_DEFAULT;
2556 if (param->fp_quiet)
2557 param->fp_verbose = VERBOSE_OBJID;
2560 rc = llapi_getstripe(argv[optind], param);
2561 } while (++optind < argc && !rc);
2564 fprintf(stderr, "error: %s failed for %s.\n",
2565 argv[0], argv[optind - 1]);
2569 static int lfs_tgts(int argc, char **argv)
2571 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2572 struct find_param param;
2573 int index = 0, rc=0;
2578 if (argc == 2 && !realpath(argv[1], path)) {
2580 fprintf(stderr, "error: invalid path '%s': %s\n",
2581 argv[1], strerror(-rc));
2585 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2586 /* Check if we have a mount point */
2587 if (mntdir[0] == '\0')
2590 memset(¶m, 0, sizeof(param));
2591 if (!strcmp(argv[0], "mdts"))
2592 param.fp_get_lmv = 1;
2594 rc = llapi_ostlist(mntdir, ¶m);
2596 fprintf(stderr, "error: %s: failed on %s\n",
2599 if (path[0] != '\0')
2601 memset(mntdir, 0, PATH_MAX);
2607 static int lfs_getstripe(int argc, char **argv)
2609 struct find_param param = { 0 };
2611 param.fp_max_depth = 1;
2612 return lfs_getstripe_internal(argc, argv, ¶m);
2616 static int lfs_getdirstripe(int argc, char **argv)
2618 struct find_param param = { 0 };
2619 struct option long_opts[] = {
2620 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2621 {"mdt-count", no_argument, 0, 'c'},
2623 {"mdt-hash", no_argument, 0, 'H'},
2624 {"mdt-index", no_argument, 0, 'i'},
2625 {"recursive", no_argument, 0, 'r'},
2626 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2627 {"mdt-hash", no_argument, 0, 't'},
2629 {"default", no_argument, 0, 'D'},
2630 {"obd", required_argument, 0, 'O'},
2631 {"mdt-count", no_argument, 0, 'T'},
2636 param.fp_get_lmv = 1;
2638 while ((c = getopt_long(argc, argv,
2639 "cDHiO:rtT", long_opts, NULL)) != -1)
2643 if (param.fp_obd_uuid) {
2645 "error: %s: only one obduuid allowed",
2649 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2651 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2653 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2654 fprintf(stderr, "warning: '-c' deprecated"
2655 ", use '-T' instead\n");
2659 param.fp_verbose |= VERBOSE_COUNT;
2662 param.fp_verbose |= VERBOSE_OFFSET;
2664 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2668 param.fp_verbose |= VERBOSE_HASH_TYPE;
2671 param.fp_get_default_lmv = 1;
2674 param.fp_recursive = 1;
2684 if (param.fp_recursive)
2685 param.fp_max_depth = -1;
2687 if (!param.fp_verbose)
2688 param.fp_verbose = VERBOSE_DEFAULT;
2691 rc = llapi_getstripe(argv[optind], ¶m);
2692 } while (++optind < argc && !rc);
2695 fprintf(stderr, "error: %s failed for %s.\n",
2696 argv[0], argv[optind - 1]);
2701 static int lfs_setdirstripe(int argc, char **argv)
2705 unsigned int stripe_offset = -1;
2706 unsigned int stripe_count = 1;
2707 enum lmv_hash_type hash_type;
2710 char *stripe_offset_opt = NULL;
2711 char *stripe_count_opt = NULL;
2712 char *stripe_hash_opt = NULL;
2713 char *mode_opt = NULL;
2714 bool default_stripe = false;
2715 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2716 mode_t previous_mode = 0;
2717 bool delete = false;
2719 struct option long_opts[] = {
2720 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2721 {"count", required_argument, 0, 'c'},
2723 {"mdt-count", required_argument, 0, 'c'},
2724 {"delete", no_argument, 0, 'd'},
2725 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2726 {"index", required_argument, 0, 'i'},
2728 {"mdt-index", required_argument, 0, 'i'},
2729 {"mode", required_argument, 0, 'm'},
2730 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2731 {"hash-type", required_argument, 0, 't'},
2732 {"mdt-hash", required_argument, 0, 't'},
2734 {"mdt-hash", required_argument, 0, 'H'},
2735 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2736 {"default_stripe", no_argument, 0, 'D'},
2738 {"default", no_argument, 0, 'D'},
2742 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2749 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2750 if (strcmp(argv[optind - 1], "--count") == 0)
2751 fprintf(stderr, "warning: '--count' deprecated"
2752 ", use '--mdt-count' instead\n");
2754 stripe_count_opt = optarg;
2758 default_stripe = true;
2761 default_stripe = true;
2764 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2765 if (strcmp(argv[optind - 1], "--index") == 0)
2766 fprintf(stderr, "warning: '--index' deprecated"
2767 ", use '--mdt-index' instead\n");
2769 stripe_offset_opt = optarg;
2774 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2778 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2779 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2780 fprintf(stderr, "warning: '--hash-type' "
2781 "deprecated, use '--mdt-hash' "
2784 stripe_hash_opt = optarg;
2787 fprintf(stderr, "error: %s: option '%s' "
2789 argv[0], argv[optind - 1]);
2794 if (optind == argc) {
2795 fprintf(stderr, "error: %s: missing dirname\n",
2800 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2801 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2806 if (stripe_offset_opt != NULL) {
2807 /* get the stripe offset */
2808 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2810 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2811 argv[0], stripe_offset_opt);
2817 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2818 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2819 " or -i options.\n", argv[0]);
2827 if (mode_opt != NULL) {
2828 mode = strtoul(mode_opt, &end, 8);
2830 fprintf(stderr, "error: %s: bad mode '%s'\n",
2834 previous_mode = umask(0);
2837 if (stripe_hash_opt == NULL) {
2838 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2840 hash_type = check_hashtype(stripe_hash_opt);
2841 if (hash_type == 0) {
2843 "error: %s: bad stripe hash type '%s'\n",
2844 argv[0], stripe_hash_opt);
2849 /* get the stripe count */
2850 if (stripe_count_opt != NULL) {
2851 stripe_count = strtoul(stripe_count_opt, &end, 0);
2853 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2854 argv[0], stripe_count_opt);
2859 dname = argv[optind];
2861 if (default_stripe) {
2862 result = llapi_dir_set_default_lmv_stripe(dname,
2863 stripe_offset, stripe_count,
2866 result = llapi_dir_create_pool(dname, mode,
2868 stripe_count, hash_type,
2873 fprintf(stderr, "error: %s: create stripe dir '%s' "
2874 "failed\n", argv[0], dname);
2877 dname = argv[++optind];
2878 } while (dname != NULL);
2880 if (mode_opt != NULL)
2881 umask(previous_mode);
2887 static int lfs_rmentry(int argc, char **argv)
2894 fprintf(stderr, "error: %s: missing dirname\n",
2900 dname = argv[index];
2901 while (dname != NULL) {
2902 result = llapi_direntry_remove(dname);
2904 fprintf(stderr, "error: %s: remove dir entry '%s' "
2905 "failed\n", argv[0], dname);
2908 dname = argv[++index];
2913 static int lfs_mv(int argc, char **argv)
2915 struct find_param param = {
2922 struct option long_opts[] = {
2923 {"mdt-index", required_argument, 0, 'M'},
2924 {"verbose", no_argument, 0, 'v'},
2928 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2931 param.fp_mdt_index = strtoul(optarg, &end, 0);
2933 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2940 param.fp_verbose = VERBOSE_DETAIL;
2944 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2945 argv[0], argv[optind - 1]);
2950 if (param.fp_mdt_index == -1) {
2951 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2955 if (optind >= argc) {
2956 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2960 param.fp_migrate = 1;
2961 rc = llapi_migrate_mdt(argv[optind], ¶m);
2963 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2964 argv[0], argv[optind], param.fp_mdt_index,
2969 static int lfs_osts(int argc, char **argv)
2971 return lfs_tgts(argc, argv);
2974 static int lfs_mdts(int argc, char **argv)
2976 return lfs_tgts(argc, argv);
2979 #define COOK(value) \
2982 while (value > 1024) { \
2990 #define CDF "%11llu"
2991 #define HDF "%8.1f%c"
2996 MNTDF_INODES = 0x0001,
2997 MNTDF_COOKED = 0x0002,
2998 MNTDF_LAZY = 0x0004,
2999 MNTDF_VERBOSE = 0x0008,
3002 static int showdf(char *mntdir, struct obd_statfs *stat,
3003 char *uuid, enum mntdf_flags flags,
3004 char *type, int index, int rc)
3006 long long avail, used, total;
3008 char *suffix = "KMGTPEZY";
3009 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3010 char tbuf[3 * sizeof(__u64)];
3011 char ubuf[3 * sizeof(__u64)];
3012 char abuf[3 * sizeof(__u64)];
3013 char rbuf[3 * sizeof(__u64)];
3020 if (flags & MNTDF_INODES) {
3021 avail = stat->os_ffree;
3022 used = stat->os_files - stat->os_ffree;
3023 total = stat->os_files;
3025 int shift = flags & MNTDF_COOKED ? 0 : 10;
3027 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3028 used = ((stat->os_blocks - stat->os_bfree) *
3029 stat->os_bsize) >> shift;
3030 total = (stat->os_blocks * stat->os_bsize) >> shift;
3033 if ((used + avail) > 0)
3034 ratio = (double)used / (double)(used + avail);
3036 if (flags & MNTDF_COOKED) {
3040 cook_val = (double)total;
3043 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3046 snprintf(tbuf, sizeof(tbuf), CDF, total);
3048 cook_val = (double)used;
3051 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3054 snprintf(ubuf, sizeof(ubuf), CDF, used);
3056 cook_val = (double)avail;
3059 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3062 snprintf(abuf, sizeof(abuf), CDF, avail);
3064 snprintf(tbuf, sizeof(tbuf), CDF, total);
3065 snprintf(ubuf, sizeof(tbuf), CDF, used);
3066 snprintf(abuf, sizeof(tbuf), CDF, avail);
3069 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3070 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3071 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3073 printf("[%s:%d]", type, index);
3075 if (stat->os_state) {
3077 * Each character represents the matching
3080 const char state_names[] = "DRSI";
3085 for (i = 0, state = stat->os_state;
3086 state && i < sizeof(state_names); i++) {
3087 if (!(state & (1 << i)))
3089 printf("%c", state_names[i]);
3097 printf(UUF": inactive device\n", uuid);
3100 printf(UUF": %s\n", uuid, strerror(-rc));
3107 struct ll_stat_type {
3112 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3114 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3115 struct obd_uuid uuid_buf;
3116 char *poolname = NULL;
3117 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3118 { LL_STATFS_LOV, "OST" },
3120 struct ll_stat_type *tp;
3121 __u64 ost_ffree = 0;
3129 poolname = strchr(pool, '.');
3130 if (poolname != NULL) {
3131 if (strncmp(fsname, pool, strlen(fsname))) {
3132 fprintf(stderr, "filesystem name incorrect\n");
3140 fd = open(mntdir, O_RDONLY);
3143 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3148 if (flags & MNTDF_INODES)
3149 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3150 "UUID", "Inodes", "IUsed", "IFree",
3151 "IUse%", "Mounted on");
3153 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3154 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3155 "Used", "Available", "Use%", "Mounted on");
3157 for (tp = types; tp->st_name != NULL; tp++) {
3158 for (index = 0; ; index++) {
3159 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3160 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3161 type = flags & MNTDF_LAZY ?
3162 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3163 rc2 = llapi_obd_fstatfs(fd, type, index,
3164 &stat_buf, &uuid_buf);
3169 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3170 if (!(flags & MNTDF_VERBOSE))
3172 } else if (rc2 < 0 && rc == 0) {
3176 if (poolname && tp->st_op == LL_STATFS_LOV &&
3177 llapi_search_ost(fsname, poolname,
3178 obd_uuid2str(&uuid_buf)) != 1)
3181 /* the llapi_obd_statfs() call may have returned with
3182 * an error, but if it filled in uuid_buf we will at
3183 * lease use that to print out a message for that OBD.
3184 * If we didn't get anything in the uuid_buf, then fill
3185 * it in so that we can print an error message. */
3186 if (uuid_buf.uuid[0] == '\0')
3187 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3188 "%s%04x", tp->st_name, index);
3189 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3190 flags, tp->st_name, index, rc2);
3193 if (tp->st_op == LL_STATFS_LMV) {
3194 sum.os_ffree += stat_buf.os_ffree;
3195 sum.os_files += stat_buf.os_files;
3196 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3197 sum.os_blocks += stat_buf.os_blocks *
3199 sum.os_bfree += stat_buf.os_bfree *
3201 sum.os_bavail += stat_buf.os_bavail *
3203 ost_ffree += stat_buf.os_ffree;
3211 /* If we don't have as many objects free on the OST as inodes
3212 * on the MDS, we reduce the total number of inodes to
3213 * compensate, so that the "inodes in use" number is correct.
3214 * Matches ll_statfs_internal() so the results are consistent. */
3215 if (ost_ffree < sum.os_ffree) {
3216 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3217 sum.os_ffree = ost_ffree;
3220 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3226 static int lfs_df(int argc, char **argv)
3228 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3229 enum mntdf_flags flags = 0;
3230 int c, rc = 0, index = 0;
3231 char fsname[PATH_MAX] = "", *pool_name = NULL;
3232 struct option long_opts[] = {
3233 {"human-readable", 0, 0, 'h'},
3234 {"inodes", 0, 0, 'i'},
3235 {"lazy", 0, 0, 'l'},
3236 {"pool", required_argument, 0, 'p'},
3237 {"verbose", 0, 0, 'v'},
3241 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3244 flags |= MNTDF_COOKED;
3247 flags |= MNTDF_INODES;
3250 flags |= MNTDF_LAZY;
3256 flags |= MNTDF_VERBOSE;
3262 if (optind < argc && !realpath(argv[optind], path)) {
3264 fprintf(stderr, "error: invalid path '%s': %s\n",
3265 argv[optind], strerror(-rc));
3269 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3270 /* Check if we have a mount point */
3271 if (mntdir[0] == '\0')
3274 rc = mntdf(mntdir, fsname, pool_name, flags);
3275 if (rc || path[0] != '\0')
3277 fsname[0] = '\0'; /* avoid matching in next loop */
3278 mntdir[0] = '\0'; /* avoid matching in next loop */
3284 static int lfs_getname(int argc, char **argv)
3286 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3287 int rc = 0, index = 0, c;
3288 char buf[sizeof(struct obd_uuid)];
3290 while ((c = getopt(argc, argv, "h")) != -1)
3293 if (optind == argc) { /* no paths specified, get all paths. */
3294 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3295 rc = llapi_getname(mntdir, buf, sizeof(buf));
3298 "cannot get name for `%s': %s\n",
3299 mntdir, strerror(-rc));
3303 printf("%s %s\n", buf, mntdir);
3305 path[0] = fsname[0] = mntdir[0] = 0;
3307 } else { /* paths specified, only attempt to search these. */
3308 for (; optind < argc; optind++) {
3309 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3312 "cannot get name for `%s': %s\n",
3313 argv[optind], strerror(-rc));
3317 printf("%s %s\n", buf, argv[optind]);
3323 static int lfs_check(int argc, char **argv)
3326 char mntdir[PATH_MAX] = {'\0'};
3335 obd_types[0] = obd_type1;
3336 obd_types[1] = obd_type2;
3338 if (strcmp(argv[1], "osts") == 0) {
3339 strcpy(obd_types[0], "osc");
3340 } else if (strcmp(argv[1], "mds") == 0) {
3341 strcpy(obd_types[0], "mdc");
3342 } else if (strcmp(argv[1], "servers") == 0) {
3344 strcpy(obd_types[0], "osc");
3345 strcpy(obd_types[1], "mdc");
3347 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3352 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3353 if (rc < 0 || mntdir[0] == '\0') {
3354 fprintf(stderr, "No suitable Lustre mount found\n");
3358 rc = llapi_target_check(num_types, obd_types, mntdir);
3360 fprintf(stderr, "error: %s: %s status failed\n",
3367 #ifdef HAVE_SYS_QUOTA_H
3368 #define ARG2INT(nr, str, msg) \
3371 nr = strtol(str, &endp, 0); \
3373 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3378 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3380 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3381 * returns the value or ULONG_MAX on integer overflow or incorrect format
3383 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3384 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3385 * 3. empty integer value is interpreted as 0
3387 static unsigned long str2sec(const char* timestr)
3389 const char spec[] = "smhdw";
3390 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3391 unsigned long val = 0;
3394 if (strpbrk(timestr, spec) == NULL) {
3395 /* no specifiers inside the time string,
3396 should treat it as an integer value */
3397 val = strtoul(timestr, &tail, 10);
3398 return *tail ? ULONG_MAX : val;
3401 /* format string is XXwXXdXXhXXmXXs */
3407 v = strtoul(timestr, &tail, 10);
3408 if (v == ULONG_MAX || *tail == '\0')
3409 /* value too large (ULONG_MAX or more)
3410 or missing specifier */
3413 ptr = strchr(spec, *tail);
3415 /* unknown specifier */
3420 /* check if product will overflow the type */
3421 if (!(v < ULONG_MAX / mult[ind]))
3424 ADD_OVERFLOW(val, mult[ind] * v);
3425 if (val == ULONG_MAX)
3437 #define ARG2ULL(nr, str, def_units) \
3439 unsigned long long limit, units = def_units; \
3442 rc = llapi_parse_size(str, &limit, &units, 1); \
3444 fprintf(stderr, "error: bad limit value %s\n", str); \
3450 static inline int has_times_option(int argc, char **argv)
3454 for (i = 1; i < argc; i++)
3455 if (!strcmp(argv[i], "-t"))
3461 int lfs_setquota_times(int argc, char **argv)
3464 struct if_quotactl qctl;
3465 char *mnt, *obd_type = (char *)qctl.obd_type;
3466 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3467 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3468 struct option long_opts[] = {
3469 {"block-grace", required_argument, 0, 'b'},
3470 {"group", no_argument, 0, 'g'},
3471 {"inode-grace", required_argument, 0, 'i'},
3472 {"project", no_argument, 0, 'p'},
3473 {"times", no_argument, 0, 't'},
3474 {"user", no_argument, 0, 'u'},
3479 memset(&qctl, 0, sizeof(qctl));
3480 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3481 qctl.qc_type = ALLQUOTA;
3483 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3484 long_opts, NULL)) != -1) {
3495 if (qctl.qc_type != ALLQUOTA) {
3496 fprintf(stderr, "error: -u/g/p can't be used "
3497 "more than once\n");
3500 qctl.qc_type = qtype;
3503 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3504 fprintf(stderr, "error: bad block-grace: %s\n",
3508 dqb->dqb_valid |= QIF_BTIME;
3511 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3512 fprintf(stderr, "error: bad inode-grace: %s\n",
3516 dqb->dqb_valid |= QIF_ITIME;
3518 case 't': /* Yes, of course! */
3520 default: /* getopt prints error message for us when opterr != 0 */
3525 if (qctl.qc_type == ALLQUOTA) {
3526 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3530 if (optind != argc - 1) {
3531 fprintf(stderr, "error: unexpected parameters encountered\n");
3536 rc = llapi_quotactl(mnt, &qctl);
3539 fprintf(stderr, "%s %s ", obd_type,
3540 obd_uuid2str(&qctl.obd_uuid));
3541 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3548 #define BSLIMIT (1 << 0)
3549 #define BHLIMIT (1 << 1)
3550 #define ISLIMIT (1 << 2)
3551 #define IHLIMIT (1 << 3)
3553 int lfs_setquota(int argc, char **argv)
3556 struct if_quotactl qctl;
3557 char *mnt, *obd_type = (char *)qctl.obd_type;
3558 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3559 struct option long_opts[] = {
3560 {"block-softlimit", required_argument, 0, 'b'},
3561 {"block-hardlimit", required_argument, 0, 'B'},
3562 {"group", required_argument, 0, 'g'},
3563 {"inode-softlimit", required_argument, 0, 'i'},
3564 {"inode-hardlimit", required_argument, 0, 'I'},
3565 {"user", required_argument, 0, 'u'},
3566 {"project", required_argument, 0, 'p'},
3569 unsigned limit_mask = 0;
3573 if (has_times_option(argc, argv))
3574 return lfs_setquota_times(argc, argv);
3576 memset(&qctl, 0, sizeof(qctl));
3577 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3578 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3579 * so it can be used as a marker that qc_type
3580 * isn't reinitialized from command line */
3582 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3583 long_opts, NULL)) != -1) {
3587 rc = name2uid(&qctl.qc_id, optarg);
3591 rc = name2gid(&qctl.qc_id, optarg);
3595 rc = name2projid(&qctl.qc_id, optarg);
3597 if (qctl.qc_type != ALLQUOTA) {
3598 fprintf(stderr, "error: -u and -g can't be used"
3599 " more than once\n");
3602 qctl.qc_type = qtype;
3604 qctl.qc_id = strtoul(optarg, &endptr, 10);
3605 if (*endptr != '\0') {
3606 fprintf(stderr, "error: can't find id "
3607 "for name %s\n", optarg);
3613 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3614 dqb->dqb_bsoftlimit >>= 10;
3615 limit_mask |= BSLIMIT;
3616 if (dqb->dqb_bsoftlimit &&
3617 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3618 fprintf(stderr, "warning: block softlimit is "
3619 "smaller than the miminal qunit size, "
3620 "please see the help of setquota or "
3621 "Lustre manual for details.\n");
3624 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3625 dqb->dqb_bhardlimit >>= 10;
3626 limit_mask |= BHLIMIT;
3627 if (dqb->dqb_bhardlimit &&
3628 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3629 fprintf(stderr, "warning: block hardlimit is "
3630 "smaller than the miminal qunit size, "
3631 "please see the help of setquota or "
3632 "Lustre manual for details.\n");
3635 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3636 limit_mask |= ISLIMIT;
3637 if (dqb->dqb_isoftlimit &&
3638 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3639 fprintf(stderr, "warning: inode softlimit is "
3640 "smaller than the miminal qunit size, "
3641 "please see the help of setquota or "
3642 "Lustre manual for details.\n");
3645 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3646 limit_mask |= IHLIMIT;
3647 if (dqb->dqb_ihardlimit &&
3648 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3649 fprintf(stderr, "warning: inode hardlimit is "
3650 "smaller than the miminal qunit size, "
3651 "please see the help of setquota or "
3652 "Lustre manual for details.\n");
3654 default: /* getopt prints error message for us when opterr != 0 */
3659 if (qctl.qc_type == ALLQUOTA) {
3660 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3664 if (limit_mask == 0) {
3665 fprintf(stderr, "error: at least one limit must be specified\n");
3669 if (optind != argc - 1) {
3670 fprintf(stderr, "error: unexpected parameters encountered\n");
3676 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3677 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3678 /* sigh, we can't just set blimits/ilimits */
3679 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3680 .qc_type = qctl.qc_type,
3681 .qc_id = qctl.qc_id};
3683 rc = llapi_quotactl(mnt, &tmp_qctl);
3685 fprintf(stderr, "error: setquota failed while retrieving"
3686 " current quota settings (%s)\n",
3691 if (!(limit_mask & BHLIMIT))
3692 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3693 if (!(limit_mask & BSLIMIT))
3694 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3695 if (!(limit_mask & IHLIMIT))
3696 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3697 if (!(limit_mask & ISLIMIT))
3698 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3700 /* Keep grace times if we have got no softlimit arguments */
3701 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3702 dqb->dqb_valid |= QIF_BTIME;
3703 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3706 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3707 dqb->dqb_valid |= QIF_ITIME;
3708 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3712 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3713 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3715 rc = llapi_quotactl(mnt, &qctl);
3718 fprintf(stderr, "%s %s ", obd_type,
3719 obd_uuid2str(&qctl.obd_uuid));
3720 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3727 /* Converts seconds value into format string
3728 * result is returned in buf
3730 * 1. result is in descenting order: 1w2d3h4m5s
3731 * 2. zero fields are not filled (except for p. 3): 5d1s
3732 * 3. zero seconds value is presented as "0s"
3734 static char * __sec2str(time_t seconds, char *buf)
3736 const char spec[] = "smhdw";
3737 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3742 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3743 c = seconds / mult[i];
3745 if (c > 0 || (i == 0 && buf == tail))
3746 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3754 static void sec2str(time_t seconds, char *buf, int rc)
3761 tail = __sec2str(seconds, tail);
3763 if (rc && tail - buf < 39) {
3769 static void diff2str(time_t seconds, char *buf, time_t now)
3775 if (seconds <= now) {
3776 strcpy(buf, "none");
3779 __sec2str(seconds - now, buf);
3782 static void print_quota_title(char *name, struct if_quotactl *qctl,
3783 bool human_readable)
3785 printf("Disk quotas for %s %s (%cid %u):\n",
3786 qtype_name(qctl->qc_type), name,
3787 *qtype_name(qctl->qc_type), qctl->qc_id);
3788 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3789 "Filesystem", human_readable ? "used" : "kbytes",
3790 "quota", "limit", "grace",
3791 "files", "quota", "limit", "grace");
3794 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3797 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3800 snprintf(buf, buflen, "%5.4gP",
3801 (double)num / ((__u64)1 << 40));
3803 snprintf(buf, buflen, "%5.4gT",
3804 (double)num / (1 << 30));
3806 snprintf(buf, buflen, "%5.4gG",
3807 (double)num / (1 << 20));
3809 snprintf(buf, buflen, "%5.4gM",
3810 (double)num / (1 << 10));
3812 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3816 #define STRBUF_LEN 32
3817 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3824 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3825 int bover = 0, iover = 0;
3826 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3827 char numbuf[3][STRBUF_LEN];
3829 char strbuf[STRBUF_LEN];
3831 if (dqb->dqb_bhardlimit &&
3832 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3834 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3835 if (dqb->dqb_btime > now) {
3842 if (dqb->dqb_ihardlimit &&
3843 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3845 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3846 if (dqb->dqb_itime > now) {
3854 if (strlen(mnt) > 15)
3855 printf("%s\n%15s", mnt, "");
3857 printf("%15s", mnt);
3860 diff2str(dqb->dqb_btime, timebuf, now);
3862 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3863 strbuf, sizeof(strbuf), h);
3864 if (rc == -EREMOTEIO)
3865 sprintf(numbuf[0], "%s*", strbuf);
3867 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3868 "%s" : "[%s]", strbuf);
3870 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3871 if (type == QC_GENERAL)
3872 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3873 "%s" : "[%s]", strbuf);
3875 sprintf(numbuf[1], "%s", "-");
3877 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3878 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3879 "%s" : "[%s]", strbuf);
3881 printf(" %7s%c %6s %7s %7s",
3882 numbuf[0], bover ? '*' : ' ', numbuf[1],
3883 numbuf[2], bover > 1 ? timebuf : "-");
3886 diff2str(dqb->dqb_itime, timebuf, now);
3888 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3889 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3891 if (type == QC_GENERAL)
3892 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3894 (uintmax_t)dqb->dqb_isoftlimit);
3896 sprintf(numbuf[1], "%s", "-");
3898 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3899 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3901 if (type != QC_OSTIDX)
3902 printf(" %7s%c %6s %7s %7s",
3903 numbuf[0], iover ? '*' : ' ', numbuf[1],
3904 numbuf[2], iover > 1 ? timebuf : "-");
3906 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3909 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3910 qctl->qc_cmd == Q_GETOINFO) {
3914 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3915 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3916 printf("Block grace time: %s; Inode grace time: %s\n",
3917 bgtimebuf, igtimebuf);
3921 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3922 bool h, __u64 *total)
3924 int rc = 0, rc1 = 0, count = 0;
3925 __u32 valid = qctl->qc_valid;
3927 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3929 fprintf(stderr, "can not get %s count: %s\n",
3930 is_mdt ? "mdt": "ost", strerror(-rc));
3934 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3935 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3936 rc = llapi_quotactl(mnt, qctl);
3938 /* It is remote client case. */
3939 if (rc == -EOPNOTSUPP) {
3946 fprintf(stderr, "quotactl %s%d failed.\n",
3947 is_mdt ? "mdt": "ost", qctl->qc_idx);
3951 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3952 qctl->qc_valid, 0, h);
3953 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3954 qctl->qc_dqblk.dqb_bhardlimit;
3957 qctl->qc_valid = valid;
3961 static int lfs_quota(int argc, char **argv)
3964 char *mnt, *name = NULL;
3965 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3966 .qc_type = ALLQUOTA };
3967 char *obd_type = (char *)qctl.obd_type;
3968 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
3969 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
3970 verbose = 0, pass = 0, quiet = 0, inacc;
3972 __u32 valid = QC_GENERAL, idx = 0;
3973 __u64 total_ialloc = 0, total_balloc = 0;
3974 bool human_readable = false;
3977 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
3988 if (qctl.qc_type != ALLQUOTA) {
3989 fprintf(stderr, "error: use either -u or -g\n");
3992 qctl.qc_type = qtype;
3995 qctl.qc_cmd = LUSTRE_Q_GETINFO;
3998 valid = qctl.qc_valid = QC_UUID;
3999 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4002 valid = qctl.qc_valid = QC_MDTIDX;
4003 idx = qctl.qc_idx = atoi(optarg);
4006 valid = qctl.qc_valid = QC_OSTIDX;
4007 idx = qctl.qc_idx = atoi(optarg);
4016 human_readable = true;
4019 fprintf(stderr, "error: %s: option '-%c' "
4020 "unrecognized\n", argv[0], c);
4025 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4026 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4027 optind == argc - 1) {
4029 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4030 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4031 qctl.qc_valid = valid;
4033 qctl.qc_type = pass;
4034 switch (qctl.qc_type) {
4036 qctl.qc_id = geteuid();
4037 rc = uid2name(&name, qctl.qc_id);
4040 qctl.qc_id = getegid();
4041 rc = gid2name(&name, qctl.qc_id);
4050 /* lfs quota -u username /path/to/lustre/mount */
4051 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4052 /* options should be followed by u/g-name and mntpoint */
4053 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4054 fprintf(stderr, "error: missing quota argument(s)\n");
4058 name = argv[optind++];
4059 switch (qctl.qc_type) {
4061 rc = name2uid(&qctl.qc_id, name);
4064 rc = name2gid(&qctl.qc_id, name);
4067 rc = name2projid(&qctl.qc_id, name);
4074 qctl.qc_id = strtoul(name, &endptr, 10);
4075 if (*endptr != '\0') {
4076 fprintf(stderr, "error: can't find id for name "
4081 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4082 fprintf(stderr, "error: missing quota info argument(s)\n");
4088 rc1 = llapi_quotactl(mnt, &qctl);
4092 fprintf(stderr, "%s quotas are not enabled.\n",
4093 qtype_name(qctl.qc_type));
4096 fprintf(stderr, "Permission denied.\n");
4099 /* We already got error message. */
4102 fprintf(stderr, "Unexpected quotactl error: %s\n",
4107 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4108 print_quota_title(name, &qctl, human_readable);
4110 if (rc1 && *obd_type)
4111 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4113 if (qctl.qc_valid != QC_GENERAL)
4116 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4117 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4118 (QIF_LIMITS|QIF_USAGE));
4120 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4122 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4124 char strbuf[STRBUF_LEN];
4126 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4128 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4130 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4132 printf("Total allocated inode limit: %ju, total "
4133 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4137 if (rc1 || rc2 || rc3 || inacc)
4138 printf("Some errors happened when getting quota info. "
4139 "Some devices may be not working or deactivated. "
4140 "The data in \"[]\" is inaccurate.\n");
4143 if (pass > 0 && pass < LL_MAXQUOTAS)
4148 #endif /* HAVE_SYS_QUOTA_H! */
4150 static int flushctx_ioctl(char *mp)
4154 fd = open(mp, O_RDONLY);
4156 fprintf(stderr, "flushctx: error open %s: %s\n",
4157 mp, strerror(errno));
4161 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4163 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4164 mp, strerror(errno));
4170 static int lfs_flushctx(int argc, char **argv)
4172 int kdestroy = 0, c;
4173 char mntdir[PATH_MAX] = {'\0'};
4177 while ((c = getopt(argc, argv, "k")) != -1) {
4183 fprintf(stderr, "error: %s: option '-%c' "
4184 "unrecognized\n", argv[0], c);
4190 if ((rc = system("kdestroy > /dev/null")) != 0) {
4191 rc = WEXITSTATUS(rc);
4192 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4196 if (optind >= argc) {
4197 /* flush for all mounted lustre fs. */
4198 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4199 /* Check if we have a mount point */
4200 if (mntdir[0] == '\0')
4203 if (flushctx_ioctl(mntdir))
4206 mntdir[0] = '\0'; /* avoid matching in next loop */
4209 /* flush fs as specified */
4210 while (optind < argc) {
4211 if (flushctx_ioctl(argv[optind++]))
4218 static int lfs_cp(int argc, char **argv)
4220 fprintf(stderr, "remote client copy file(s).\n"
4221 "obsolete, does not support it anymore.\n");
4225 static int lfs_ls(int argc, char **argv)
4227 fprintf(stderr, "remote client lists directory contents.\n"
4228 "obsolete, does not support it anymore.\n");
4232 static int lfs_changelog(int argc, char **argv)
4234 void *changelog_priv;
4235 struct changelog_rec *rec;
4236 long long startrec = 0, endrec = 0;
4238 struct option long_opts[] = {
4239 {"follow", no_argument, 0, 'f'},
4242 char short_opts[] = "f";
4245 while ((rc = getopt_long(argc, argv, short_opts,
4246 long_opts, NULL)) != -1) {
4254 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4255 argv[0], argv[optind - 1]);
4262 mdd = argv[optind++];
4264 startrec = strtoll(argv[optind++], NULL, 10);
4266 endrec = strtoll(argv[optind++], NULL, 10);
4268 rc = llapi_changelog_start(&changelog_priv,
4269 CHANGELOG_FLAG_BLOCK |
4270 CHANGELOG_FLAG_JOBID |
4271 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4274 fprintf(stderr, "Can't start changelog: %s\n",
4275 strerror(errno = -rc));
4279 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4283 if (endrec && rec->cr_index > endrec) {
4284 llapi_changelog_free(&rec);
4287 if (rec->cr_index < startrec) {
4288 llapi_changelog_free(&rec);
4292 secs = rec->cr_time >> 30;
4293 gmtime_r(&secs, &ts);
4294 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
4295 "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
4296 changelog_type2str(rec->cr_type),
4297 ts.tm_hour, ts.tm_min, ts.tm_sec,
4298 (int)(rec->cr_time & ((1<<30) - 1)),
4299 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4300 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4302 if (rec->cr_flags & CLF_JOBID) {
4303 struct changelog_ext_jobid *jid =
4304 changelog_rec_jobid(rec);
4306 if (jid->cr_jobid[0] != '\0')
4307 printf(" j=%s", jid->cr_jobid);
4310 if (rec->cr_namelen)
4311 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4312 rec->cr_namelen, changelog_rec_name(rec));
4314 if (rec->cr_flags & CLF_RENAME) {
4315 struct changelog_ext_rename *rnm =
4316 changelog_rec_rename(rec);
4318 if (!fid_is_zero(&rnm->cr_sfid))
4319 printf(" s="DFID" sp="DFID" %.*s",
4320 PFID(&rnm->cr_sfid),
4321 PFID(&rnm->cr_spfid),
4322 (int)changelog_rec_snamelen(rec),
4323 changelog_rec_sname(rec));
4327 llapi_changelog_free(&rec);
4330 llapi_changelog_fini(&changelog_priv);
4333 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4335 return (rc == 1 ? 0 : rc);
4338 static int lfs_changelog_clear(int argc, char **argv)
4346 endrec = strtoll(argv[3], NULL, 10);
4348 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4351 fprintf(stderr, "%s: record out of range: %llu\n",
4353 else if (rc == -ENOENT)
4354 fprintf(stderr, "%s: no changelog user: %s\n",
4357 fprintf(stderr, "%s error: %s\n", argv[0],
4366 static int lfs_fid2path(int argc, char **argv)
4368 struct option long_opts[] = {
4369 {"cur", no_argument, 0, 'c'},
4370 {"link", required_argument, 0, 'l'},
4371 {"rec", required_argument, 0, 'r'},
4374 char short_opts[] = "cl:r:";
4375 char *device, *fid, *path;
4376 long long recno = -1;
4382 while ((rc = getopt_long(argc, argv, short_opts,
4383 long_opts, NULL)) != -1) {
4389 linkno = strtol(optarg, NULL, 10);
4392 recno = strtoll(optarg, NULL, 10);
4397 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4398 argv[0], argv[optind - 1]);
4406 device = argv[optind++];
4407 path = calloc(1, PATH_MAX);
4409 fprintf(stderr, "error: Not enough memory\n");
4414 while (optind < argc) {
4415 fid = argv[optind++];
4417 lnktmp = (linkno >= 0) ? linkno : 0;
4419 int oldtmp = lnktmp;
4420 long long rectmp = recno;
4422 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4425 fprintf(stderr, "%s: error on FID %s: %s\n",
4426 argv[0], fid, strerror(errno = -rc2));
4433 fprintf(stdout, "%lld ", rectmp);
4434 if (device[0] == '/') {
4435 fprintf(stdout, "%s", device);
4436 if (device[strlen(device) - 1] != '/')
4437 fprintf(stdout, "/");
4438 } else if (path[0] == '\0') {
4439 fprintf(stdout, "/");
4441 fprintf(stdout, "%s\n", path);
4444 /* specified linkno */
4446 if (oldtmp == lnktmp)
4456 static int lfs_path2fid(int argc, char **argv)
4458 struct option long_opts[] = {
4459 {"parents", no_argument, 0, 'p'},
4463 const char short_opts[] = "p";
4464 const char *sep = "";
4467 bool show_parents = false;
4469 while ((rc = getopt_long(argc, argv, short_opts,
4470 long_opts, NULL)) != -1) {
4473 show_parents = true;
4476 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4477 argv[0], argv[optind - 1]);
4482 if (optind > argc - 1)
4484 else if (optind < argc - 1)
4488 for (path = argv + optind; *path != NULL; path++) {
4490 if (!show_parents) {
4491 err = llapi_path2fid(*path, &fid);
4493 printf("%s%s"DFID"\n",
4494 *sep != '\0' ? *path : "", sep,
4497 char name[NAME_MAX + 1];
4498 unsigned int linkno = 0;
4500 while ((err = llapi_path2parent(*path, linkno, &fid,
4501 name, sizeof(name))) == 0) {
4502 if (*sep != '\0' && linkno == 0)
4503 printf("%s%s", *path, sep);
4505 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4510 /* err == -ENODATA is end-of-loop */
4511 if (linkno > 0 && err == -ENODATA) {
4518 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4519 argv[0], show_parents ? "parent " : "", *path,
4531 static int lfs_data_version(int argc, char **argv)
4538 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4543 while ((c = getopt(argc, argv, "nrw")) != -1) {
4546 data_version_flags = 0;
4549 data_version_flags |= LL_DV_RD_FLUSH;
4552 data_version_flags |= LL_DV_WR_FLUSH;
4561 path = argv[optind];
4562 fd = open(path, O_RDONLY);
4564 err(errno, "cannot open file %s", path);
4566 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4568 err(errno, "cannot get version for %s", path);
4570 printf("%ju" "\n", (uintmax_t)data_version);
4576 static int lfs_hsm_state(int argc, char **argv)
4581 struct hsm_user_state hus;
4589 rc = llapi_hsm_state_get(path, &hus);
4591 fprintf(stderr, "can't get hsm state for %s: %s\n",
4592 path, strerror(errno = -rc));
4596 /* Display path name and status flags */
4597 printf("%s: (0x%08x)", path, hus.hus_states);
4599 if (hus.hus_states & HS_RELEASED)
4600 printf(" released");
4601 if (hus.hus_states & HS_EXISTS)
4603 if (hus.hus_states & HS_DIRTY)
4605 if (hus.hus_states & HS_ARCHIVED)
4606 printf(" archived");
4607 /* Display user-settable flags */
4608 if (hus.hus_states & HS_NORELEASE)
4609 printf(" never_release");
4610 if (hus.hus_states & HS_NOARCHIVE)
4611 printf(" never_archive");
4612 if (hus.hus_states & HS_LOST)
4613 printf(" lost_from_hsm");
4615 if (hus.hus_archive_id != 0)
4616 printf(", archive_id:%d", hus.hus_archive_id);
4619 } while (++i < argc);
4624 #define LFS_HSM_SET 0
4625 #define LFS_HSM_CLEAR 1
4628 * Generic function to set or clear HSM flags.
4629 * Used by hsm_set and hsm_clear.
4631 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4633 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4635 struct option long_opts[] = {
4636 {"lost", 0, 0, 'l'},
4637 {"norelease", 0, 0, 'r'},
4638 {"noarchive", 0, 0, 'a'},
4639 {"archived", 0, 0, 'A'},
4640 {"dirty", 0, 0, 'd'},
4641 {"exists", 0, 0, 'e'},
4644 char short_opts[] = "lraAde";
4652 while ((c = getopt_long(argc, argv, short_opts,
4653 long_opts, NULL)) != -1) {
4659 mask |= HS_NOARCHIVE;
4662 mask |= HS_ARCHIVED;
4665 mask |= HS_NORELEASE;
4676 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4677 argv[0], argv[optind - 1]);
4682 /* User should have specified a flag */
4686 while (optind < argc) {
4688 path = argv[optind];
4690 /* If mode == 0, this means we apply the mask. */
4691 if (mode == LFS_HSM_SET)
4692 rc = llapi_hsm_state_set(path, mask, 0, 0);
4694 rc = llapi_hsm_state_set(path, 0, mask, 0);
4697 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4698 path, strerror(errno = -rc));
4707 static int lfs_hsm_action(int argc, char **argv)
4712 struct hsm_current_action hca;
4713 struct hsm_extent he;
4714 enum hsm_user_action hua;
4715 enum hsm_progress_states hps;
4723 rc = llapi_hsm_current_action(path, &hca);
4725 fprintf(stderr, "can't get hsm action for %s: %s\n",
4726 path, strerror(errno = -rc));
4729 he = hca.hca_location;
4730 hua = hca.hca_action;
4731 hps = hca.hca_state;
4733 printf("%s: %s", path, hsm_user_action2name(hua));
4735 /* Skip file without action */
4736 if (hca.hca_action == HUA_NONE) {
4741 printf(" %s ", hsm_progress_state2name(hps));
4743 if ((hps == HPS_RUNNING) &&
4744 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4745 printf("(%llu bytes moved)\n",
4746 (unsigned long long)he.length);
4747 else if ((he.offset + he.length) == LUSTRE_EOF)
4748 printf("(from %llu to EOF)\n",
4749 (unsigned long long)he.offset);
4751 printf("(from %llu to %llu)\n",
4752 (unsigned long long)he.offset,
4753 (unsigned long long)(he.offset + he.length));
4755 } while (++i < argc);
4760 static int lfs_hsm_set(int argc, char **argv)
4762 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4765 static int lfs_hsm_clear(int argc, char **argv)
4767 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4771 * Check file state and return its fid, to be used by lfs_hsm_request().
4773 * \param[in] file Path to file to check
4774 * \param[in,out] fid Pointer to allocated lu_fid struct.
4775 * \param[in,out] last_dev Pointer to last device id used.
4777 * \return 0 on success.
4779 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4785 rc = lstat(file, &st);
4787 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4790 /* Checking for regular file as archiving as posix copytool
4791 * rejects archiving files other than regular files
4793 if (!S_ISREG(st.st_mode)) {
4794 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4797 /* A request should be ... */
4798 if (*last_dev != st.st_dev && *last_dev != 0) {
4799 fprintf(stderr, "All files should be "
4800 "on the same filesystem: %s\n", file);
4803 *last_dev = st.st_dev;
4805 rc = llapi_path2fid(file, fid);
4807 fprintf(stderr, "Cannot read FID of %s: %s\n",
4808 file, strerror(-rc));
4814 /* Fill an HSM HUR item with a given file name.
4816 * If mntpath is set, then the filename is actually a FID, and no
4817 * lookup on the filesystem will be performed.
4819 * \param[in] hur the user request to fill
4820 * \param[in] idx index of the item inside the HUR to fill
4821 * \param[in] mntpath mountpoint of Lustre
4822 * \param[in] fname filename (if mtnpath is NULL)
4823 * or FID (if mntpath is set)
4824 * \param[in] last_dev pointer to last device id used
4826 * \retval 0 on success
4827 * \retval CMD_HELP or a negative errno on error
4829 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4830 const char *mntpath, const char *fname,
4833 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4836 hui->hui_extent.length = -1;
4838 if (mntpath != NULL) {
4841 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4845 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4850 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4854 hur->hur_request.hr_itemcount++;
4859 static int lfs_hsm_request(int argc, char **argv, int action)
4861 struct option long_opts[] = {
4862 {"filelist", 1, 0, 'l'},
4863 {"data", 1, 0, 'D'},
4864 {"archive", 1, 0, 'a'},
4865 {"mntpath", 1, 0, 'm'},
4869 char short_opts[] = "l:D:a:m:";
4870 struct hsm_user_request *hur, *oldhur;
4875 char *filelist = NULL;
4876 char fullpath[PATH_MAX];
4877 char *opaque = NULL;
4881 int nbfile_alloc = 0;
4882 char *some_file = NULL;
4883 char *mntpath = NULL;
4889 while ((c = getopt_long(argc, argv, short_opts,
4890 long_opts, NULL)) != -1) {
4899 if (action != HUA_ARCHIVE &&
4900 action != HUA_REMOVE) {
4902 "error: -a is supported only "
4903 "when archiving or removing\n");
4906 archive_id = atoi(optarg);
4909 if (some_file == NULL) {
4911 some_file = strdup(optarg);
4917 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4918 argv[0], argv[optind - 1]);
4923 /* All remaining args are files, so we have at least nbfile */
4924 nbfile = argc - optind;
4926 if ((nbfile == 0) && (filelist == NULL))
4930 opaque_len = strlen(opaque);
4932 /* Alloc the request structure with enough place to store all files
4933 * from command line. */
4934 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4936 fprintf(stderr, "Cannot create the request: %s\n",
4940 nbfile_alloc = nbfile;
4942 hur->hur_request.hr_action = action;
4943 hur->hur_request.hr_archive_id = archive_id;
4944 hur->hur_request.hr_flags = 0;
4946 /* All remaining args are files, add them */
4947 if (nbfile != 0 && some_file == NULL)
4948 some_file = strdup(argv[optind]);
4950 for (i = 0; i < nbfile; i++) {
4951 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4957 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4959 /* If a filelist was specified, read the filelist from it. */
4960 if (filelist != NULL) {
4961 fp = fopen(filelist, "r");
4963 fprintf(stderr, "Cannot read the file list %s: %s\n",
4964 filelist, strerror(errno));
4969 while ((rc = getline(&line, &len, fp)) != -1) {
4970 /* If allocated buffer was too small, get something
4972 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
4975 nbfile_alloc = nbfile_alloc * 2 + 1;
4977 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
4980 fprintf(stderr, "hsm: cannot allocate "
4981 "the request: %s\n",
4988 size = hur_len(oldhur);
4990 fprintf(stderr, "hsm: cannot allocate "
4991 "%u files + %u bytes data\n",
4992 oldhur->hur_request.hr_itemcount,
4993 oldhur->hur_request.hr_data_len);
5000 memcpy(hur, oldhur, size);
5005 if (line[strlen(line) - 1] == '\n')
5006 line[strlen(line) - 1] = '\0';
5008 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5009 mntpath, line, &last_dev);
5015 if (some_file == NULL) {
5025 /* If a --data was used, add it to the request */
5026 hur->hur_request.hr_data_len = opaque_len;
5028 memcpy(hur_data(hur), opaque, opaque_len);
5030 /* Send the HSM request */
5031 if (realpath(some_file, fullpath) == NULL) {
5032 fprintf(stderr, "Could not find path '%s': %s\n",
5033 some_file, strerror(errno));
5035 rc = llapi_hsm_request(fullpath, hur);
5037 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5038 some_file, strerror(-rc));
5048 static int lfs_hsm_archive(int argc, char **argv)
5050 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5053 static int lfs_hsm_restore(int argc, char **argv)
5055 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5058 static int lfs_hsm_release(int argc, char **argv)
5060 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5063 static int lfs_hsm_remove(int argc, char **argv)
5065 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5068 static int lfs_hsm_cancel(int argc, char **argv)
5070 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5073 static int lfs_swap_layouts(int argc, char **argv)
5078 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5079 SWAP_LAYOUTS_KEEP_MTIME |
5080 SWAP_LAYOUTS_KEEP_ATIME);
5083 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5085 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5087 enum lu_ladvise_type advice;
5090 advice < ARRAY_SIZE(ladvise_names); advice++) {
5091 if (ladvise_names[advice] == NULL)
5093 if (strcmp(string, ladvise_names[advice]) == 0)
5097 return LU_LADVISE_INVALID;
5100 static int lfs_ladvise(int argc, char **argv)
5102 struct option long_opts[] = {
5103 {"advice", required_argument, 0, 'a'},
5104 {"background", no_argument, 0, 'b'},
5105 {"end", required_argument, 0, 'e'},
5106 {"start", required_argument, 0, 's'},
5107 {"length", required_argument, 0, 'l'},
5110 char short_opts[] = "a:be:l:s:";
5115 struct llapi_lu_ladvise advice;
5116 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5117 unsigned long long start = 0;
5118 unsigned long long end = LUSTRE_EOF;
5119 unsigned long long length = 0;
5120 unsigned long long size_units;
5121 unsigned long long flags = 0;
5124 while ((c = getopt_long(argc, argv, short_opts,
5125 long_opts, NULL)) != -1) {
5128 advice_type = lfs_get_ladvice(optarg);
5129 if (advice_type == LU_LADVISE_INVALID) {
5130 fprintf(stderr, "%s: invalid advice type "
5131 "'%s'\n", argv[0], optarg);
5132 fprintf(stderr, "Valid types:");
5134 for (advice_type = 0;
5135 advice_type < ARRAY_SIZE(ladvise_names);
5137 if (ladvise_names[advice_type] == NULL)
5139 fprintf(stderr, " %s",
5140 ladvise_names[advice_type]);
5142 fprintf(stderr, "\n");
5152 rc = llapi_parse_size(optarg, &end,
5155 fprintf(stderr, "%s: bad end offset '%s'\n",
5162 rc = llapi_parse_size(optarg, &start,
5165 fprintf(stderr, "%s: bad start offset "
5166 "'%s'\n", argv[0], optarg);
5172 rc = llapi_parse_size(optarg, &length,
5175 fprintf(stderr, "%s: bad length '%s'\n",
5183 fprintf(stderr, "%s: option '%s' unrecognized\n",
5184 argv[0], argv[optind - 1]);
5189 if (advice_type == LU_LADVISE_INVALID) {
5190 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5191 fprintf(stderr, "Valid types:");
5192 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5194 if (ladvise_names[advice_type] == NULL)
5196 fprintf(stderr, " %s", ladvise_names[advice_type]);
5198 fprintf(stderr, "\n");
5202 if (argc <= optind) {
5203 fprintf(stderr, "%s: please give one or more file names\n",
5208 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5209 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5214 if (end == LUSTRE_EOF && length != 0)
5215 end = start + length;
5218 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5219 argv[0], start, end);
5223 while (optind < argc) {
5226 path = argv[optind++];
5228 fd = open(path, O_RDONLY);
5230 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5231 argv[0], path, strerror(errno));
5236 advice.lla_start = start;
5237 advice.lla_end = end;
5238 advice.lla_advice = advice_type;
5239 advice.lla_value1 = 0;
5240 advice.lla_value2 = 0;
5241 advice.lla_value3 = 0;
5242 advice.lla_value4 = 0;
5243 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5246 fprintf(stderr, "%s: cannot give advice '%s' to file "
5247 "'%s': %s\n", argv[0],
5248 ladvise_names[advice_type],
5249 path, strerror(errno));
5252 if (rc == 0 && rc2 < 0)
5258 static int lfs_list_commands(int argc, char **argv)
5260 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5262 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5267 int main(int argc, char **argv)
5271 /* Ensure that liblustreapi constructor has run */
5272 if (!liblustreapi_initialized)
5273 fprintf(stderr, "liblustreapi was not properly initialized\n");
5277 Parser_init("lfs > ", cmdlist);
5279 progname = argv[0]; /* Used in error messages */
5281 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5283 rc = Parser_commands();
5286 return rc < 0 ? -rc : rc;
5289 #ifdef _LUSTRE_IDL_H_
5290 /* Everything we need here should be included by lustreapi.h. */
5291 # error "lfs should not depend on lustre_idl.h"
5292 #endif /* _LUSTRE_IDL_H_ */