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] [--yaml|-y]\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|-t]\n"
221 " [--recursive|-r] [--yaml|-y]\n"
222 " [--default|-D] <dir> ..."},
223 {"mkdir", lfs_setdirstripe, 0,
224 "To create a striped directory on a specified MDT. This can only\n"
225 "be done on MDT0 with the right of administrator.\n"
226 "usage: mkdir [OPTION] <directory>\n"
228 {"rm_entry", lfs_rmentry, 0,
229 "To remove the name entry of the remote directory. Note: This\n"
230 "command will only delete the name entry, i.e. the remote directory\n"
231 "will become inaccessable after this command. This can only be done\n"
232 "by the administrator\n"
233 "usage: rm_entry <dir>\n"},
234 {"pool_list", lfs_poollist, 0,
235 "List pools or pool OSTs\n"
236 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
237 {"find", lfs_find, 0,
238 "find files matching given attributes recursively in directory tree.\n"
239 "usage: find <directory|filename> ...\n"
240 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
241 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
242 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
243 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
244 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
245 " [[!] --stripe-count|-c [+-]<stripes>]\n"
246 " [[!] --stripe-index|-i <index,...>]\n"
247 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
248 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
249 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
250 " [[!] --projid <projid>]\n"
251 " [[!] --layout|-L released,raid0]\n"
252 " [[!] --component-count [+-]<comp_cnt>]\n"
253 " [[!] --component-start [+-]N[kMGTPE]]\n"
254 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
255 " [[!] --component-flags <comp_flags>]\n"
256 " [[!] --mdt-count|-T [+-]<stripes>]\n"
257 " [[!] --mdt-hash|-H <hashtype>\n"
258 "\t !: used before an option indicates 'NOT' requested attribute\n"
259 "\t -: used before a value indicates 'AT MOST' requested value\n"
260 "\t +: used before a value indicates 'AT LEAST' requested value\n"
261 "\tmdt-hash: hash type of the striped directory.\n"
262 "\t fnv_1a_64 FNV-1a hash algorithm\n"
263 "\t all_char sum of characters % MDT_COUNT\n"},
264 {"check", lfs_check, 0,
265 "Display the status of MDS or OSTs (as specified in the command)\n"
266 "or all the servers (MDS and OSTs).\n"
267 "usage: check <osts|mds|servers>"},
268 {"osts", lfs_osts, 0, "list OSTs connected to client "
269 "[for specified path only]\n" "usage: osts [path]"},
270 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
271 "[for specified path only]\n" "usage: mdts [path]"},
273 "report filesystem disk space usage or inodes usage"
274 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
275 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
276 {"getname", lfs_getname, 0, "list instances and specified mount points "
277 "[for specified path only]\n"
278 "Usage: getname [-h]|[path ...] "},
279 #ifdef HAVE_SYS_QUOTA_H
280 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
281 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
282 " -b <block-softlimit> -B <block-hardlimit>\n"
283 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
284 " setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
285 " [--block-softlimit <block-softlimit>]\n"
286 " [--block-hardlimit <block-hardlimit>]\n"
287 " [--inode-softlimit <inode-softlimit>]\n"
288 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
289 " setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
290 " [--block-grace <block-grace>]\n"
291 " [--inode-grace <inode-grace>] <filesystem>\n"
292 " -b can be used instead of --block-softlimit/--block-grace\n"
293 " -B can be used instead of --block-hardlimit\n"
294 " -i can be used instead of --inode-softlimit/--inode-grace\n"
295 " -I can be used instead of --inode-hardlimit\n\n"
296 "Note: The total quota space will be split into many qunits and\n"
297 " balanced over all server targets, the minimal qunit size is\n"
298 " 1M bytes for block space and 1K inodes for inode space.\n\n"
299 " Quota space rebalancing process will stop when this mininum\n"
300 " value is reached. As a result, quota exceeded can be returned\n"
301 " while many targets still have 1MB or 1K inodes of spare\n"
303 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
304 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
306 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
307 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
309 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
310 "usage: flushctx [-k] [mountpoint...]"},
312 "Remote user copy files and directories.\n"
313 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
315 "Remote user list directory contents.\n"
316 "usage: ls [OPTION]... [FILE]..."},
317 {"changelog", lfs_changelog, 0,
318 "Show the metadata changes on an MDT."
319 "\nusage: changelog <mdtname> [startrec [endrec]]"},
320 {"changelog_clear", lfs_changelog_clear, 0,
321 "Indicate that old changelog records up to <endrec> are no longer of "
322 "interest to consumer <id>, allowing the system to free up space.\n"
323 "An <endrec> of 0 means all records.\n"
324 "usage: changelog_clear <mdtname> <id> <endrec>"},
325 {"fid2path", lfs_fid2path, 0,
326 "Resolve the full path(s) for given FID(s). For a specific hardlink "
327 "specify link number <linkno>.\n"
328 /* "For a historical link name, specify changelog record <recno>.\n" */
329 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
330 /* [ --rec <recno> ] */ },
331 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
332 "usage: path2fid [--parents] <path> ..."},
333 {"data_version", lfs_data_version, 0, "Display file data version for "
334 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
335 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
336 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
337 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
338 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
339 "[--archived] [--lost] <file> ..."},
340 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
342 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
343 "[--archived] [--lost] <file> ..."},
344 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
345 "given files.\n" "usage: hsm_action <file> ..."},
346 {"hsm_archive", lfs_hsm_archive, 0,
347 "Archive file to external storage.\n"
348 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
350 {"hsm_restore", lfs_hsm_restore, 0,
351 "Restore file from external storage.\n"
352 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
353 {"hsm_release", lfs_hsm_release, 0,
354 "Release files from Lustre.\n"
355 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
356 {"hsm_remove", lfs_hsm_remove, 0,
357 "Remove file copy from external storage.\n"
358 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
359 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
361 "Note: To remove files from the archive that have been deleted on\n"
362 "Lustre, set mntpath and optionally archive. In that case, all the\n"
363 "positional arguments and entries in the file list must be FIDs."
365 {"hsm_cancel", lfs_hsm_cancel, 0,
366 "Cancel requests related to specified files.\n"
367 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
368 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
369 "usage: swap_layouts <path1> <path2>"},
370 {"migrate", lfs_setstripe, 0,
371 "migrate a directory between MDTs.\n"
372 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
374 "\tmdt_idx: index of the destination MDT\n"
376 "migrate file objects from one OST "
377 "layout\nto another (may be not safe with concurent writes).\n"
379 "[--stripe-count|-c] <stripe_count>\n"
380 " [--stripe-index|-i] <start_ost_index>\n"
381 " [--stripe-size|-S] <stripe_size>\n"
382 " [--pool|-p] <pool_name>\n"
383 " [--ost-list|-o] <ost_indices>\n"
385 " [--non-block|-n]\n"
386 " <file|directory>\n"
387 "\tstripe_count: number of OSTs to stripe a file over\n"
388 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
389 "\tstripe_size: number of bytes to store before moving to the next OST\n"
390 "\tpool_name: name of the predefined pool of OSTs\n"
391 "\tost_indices: OSTs to stripe over, in order\n"
392 "\tblock: wait for the operation to return before continuing\n"
393 "\tnon-block: do not wait for the operation to return.\n"},
395 "To move directories between MDTs. This command is deprecated, "
396 "use \"migrate\" instead.\n"
397 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
399 {"ladvise", lfs_ladvise, 0,
400 "Provide servers with advice about access patterns for a file.\n"
401 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
402 " [--background|-b]\n"
403 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
405 {"help", Parser_help, 0, "help"},
406 {"exit", Parser_quit, 0, "quit"},
407 {"quit", Parser_quit, 0, "quit"},
408 {"--version", Parser_version, 0,
409 "output build version of the utility and exit"},
410 {"--list-commands", lfs_list_commands, 0,
411 "list commands supported by the utility and exit"},
416 #define MIGRATION_NONBLOCK 1
418 static int check_hashtype(const char *hashtype)
422 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
423 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
430 * Internal helper for migrate_copy_data(). Check lease and report error if
433 * \param[in] fd File descriptor on which to check the lease.
434 * \param[out] lease_broken Set to true if the lease was broken.
435 * \param[in] group_locked Whether a group lock was taken or not.
436 * \param[in] path Name of the file being processed, for error
439 * \retval 0 Migration can keep on going.
440 * \retval -errno Error occurred, abort migration.
442 static int check_lease(int fd, bool *lease_broken, bool group_locked,
447 if (!file_lease_supported)
450 rc = llapi_lease_check(fd);
452 return 0; /* llapi_check_lease returns > 0 on success. */
455 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
457 rc = rc ? rc : -EAGAIN;
459 fprintf(stderr, "%s: external attempt to access file '%s' "
460 "blocked until migration ends.\n", progname, path);
463 *lease_broken = true;
467 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
468 bool group_locked, const char *fname)
477 bool lease_broken = false;
479 /* Use a page-aligned buffer for direct I/O */
480 rc = posix_memalign(&buf, getpagesize(), buf_size);
485 /* read new data only if we have written all
486 * previously read data */
489 rc = check_lease(fd_src, &lease_broken,
490 group_locked, fname);
494 rsize = read(fd_src, buf, buf_size);
497 fprintf(stderr, "%s: %s: read failed: %s\n",
498 progname, fname, strerror(-rc));
508 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
512 "%s: %s: write failed on volatile: %s\n",
513 progname, fname, strerror(-rc));
523 fprintf(stderr, "%s: %s: fsync failed: %s\n",
524 progname, fname, strerror(-rc));
532 static int migrate_copy_timestamps(int fdv, const struct stat *st)
534 struct timeval tv[2] = {
535 {.tv_sec = st->st_atime},
536 {.tv_sec = st->st_mtime}
539 return futimes(fdv, tv);
542 static int migrate_block(int fd, int fdv, const struct stat *st,
543 size_t buf_size, const char *name)
550 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
552 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
553 progname, name, strerror(-rc));
561 /* The grouplock blocks all concurrent accesses to the file.
562 * It has to be taken after llapi_get_data_version as it would
564 rc = llapi_group_lock(fd, gid);
566 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
567 progname, name, strerror(-rc));
571 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
573 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
577 /* Make sure we keep original atime/mtime values */
578 rc = migrate_copy_timestamps(fdv, st);
580 fprintf(stderr, "%s: %s: timestamp copy failed\n",
586 * for a migration we need to check data version on file did
589 * Pass in gid=0 since we already own grouplock. */
590 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
591 SWAP_LAYOUTS_CHECK_DV1);
593 fprintf(stderr, "%s: %s: dataversion changed during copy, "
594 "migration aborted\n", progname, name);
597 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
598 name, strerror(-rc));
603 rc2 = llapi_group_unlock(fd, gid);
604 if (rc2 < 0 && rc == 0) {
605 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
606 progname, name, strerror(-rc2));
613 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
614 size_t buf_size, const char *name)
620 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
622 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
623 progname, name, strerror(-rc));
627 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
629 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
633 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
635 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
636 progname, name, strerror(-rc));
642 fprintf(stderr, "%s: %s: data version changed during "
648 /* Make sure we keep original atime/mtime values */
649 rc = migrate_copy_timestamps(fdv, st);
651 fprintf(stderr, "%s: %s: timestamp copy failed\n",
656 /* Atomically put lease, swap layouts and close.
657 * for a migration we need to check data version on file did
659 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
661 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
662 progname, name, strerror(-rc));
669 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
674 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
678 if (flags != 0 && comp_id != 0)
681 /* LCME_FL_INIT is the only supported flag in PFL */
683 if (flags & ~LCME_KNOWN_FLAGS) {
684 fprintf(stderr, "Invalid component flags %#x\n", flags);
687 comp_id = LCME_ID_NONE | flags;
688 } else if (comp_id > LCME_ID_MAX) {
689 fprintf(stderr, "Invalid component id %u\n", comp_id);
693 rc = llapi_layout_file_comp_del(fname, comp_id);
695 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
696 comp_id, fname, strerror(errno));
700 static int lfs_component_add(char *fname, struct llapi_layout *layout)
707 rc = llapi_layout_file_comp_add(fname, layout);
709 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
710 fname, strerror(errno));
714 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
715 struct llapi_layout *layout)
723 fd = lstat(fname, &st);
724 if (fd == 0 && S_ISDIR(st.st_mode))
725 open_flags = O_DIRECTORY | O_RDONLY;
727 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
729 fprintf(stderr, "%s %s failed. %s\n",
730 S_ISDIR(st.st_mode) ?
731 "Set default composite layout to " :
732 "Create composite file",
733 fname, strerror(errno));
737 static int lfs_migrate(char *name, __u64 migration_flags,
738 struct llapi_stripe_param *param,
739 struct llapi_layout *layout)
743 char parent[PATH_MAX];
746 char volatile_file[sizeof(parent) +
747 LUSTRE_VOLATILE_HDR_LEN +
748 2 * sizeof(mdt_index) +
749 2 * sizeof(random_value) + 4];
752 struct lov_user_md *lum = NULL;
754 int buf_size = 1024 * 1024 * 4;
755 bool have_lease_rdlck = false;
759 /* find the right size for the IO and allocate the buffer */
760 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
761 lum = malloc(lum_size);
767 rc = llapi_file_get_stripe(name, lum);
768 /* failure can happen for many reasons and some may be not real errors
770 * in case of a real error, a later call will fail with better
771 * error management */
773 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
774 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
775 lum->lmm_stripe_size != 0)
776 buf_size = lum->lmm_stripe_size;
779 /* open file, direct io */
780 /* even if the file is only read, WR mode is nedeed to allow
781 * layout swap on fd */
782 fd = open(name, O_RDWR | O_DIRECT);
785 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
790 if (file_lease_supported) {
791 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
792 if (rc == -EOPNOTSUPP) {
793 /* Older servers do not support file lease.
794 * Disable related checks. This opens race conditions
795 * as explained in LU-4840 */
796 file_lease_supported = false;
798 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
799 progname, name, strerror(-rc));
802 have_lease_rdlck = true;
806 /* search for file directory pathname */
807 if (strlen(name) > sizeof(parent)-1) {
811 strncpy(parent, name, sizeof(parent));
812 ptr = strrchr(parent, '/');
814 if (getcwd(parent, sizeof(parent)) == NULL) {
825 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
827 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
828 progname, name, strerror(-rc));
833 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
834 mode_t open_mode = S_IRUSR | S_IWUSR;
836 random_value = random();
837 rc = snprintf(volatile_file, sizeof(volatile_file),
838 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
839 mdt_index, random_value);
840 if (rc >= sizeof(volatile_file)) {
845 /* create, open a volatile file, use caching (ie no directio) */
847 fdv = llapi_file_open_param(volatile_file, open_flags,
849 else if (layout != NULL)
850 fdv = lfs_component_create(volatile_file, open_flags,
854 } while (fdv == -EEXIST);
858 fprintf(stderr, "%s: %s: cannot create volatile file in"
860 progname, parent, strerror(-rc));
864 /* In case the MDT does not support creation of volatile files
865 * we should try to unlink it. */
866 (void)unlink(volatile_file);
868 /* Not-owner (root?) special case.
869 * Need to set owner/group of volatile file like original.
870 * This will allow to pass related check during layout_swap.
875 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
879 rc = fstat(fdv, &stv);
882 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
883 volatile_file, strerror(errno));
886 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
887 rc = fchown(fdv, st.st_uid, st.st_gid);
890 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
891 name, strerror(errno));
896 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
897 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
899 have_lease_rdlck = false;
900 fdv = -1; /* The volatile file is closed as we put the
901 * lease in non-blocking mode. */
904 /* Blocking mode (forced if servers do not support file lease).
905 * It is also the default mode, since we cannot distinguish
906 * between a broken lease and a server that does not support
907 * atomic swap/close (LU-6785) */
908 rc = migrate_block(fd, fdv, &st, buf_size, name);
912 if (have_lease_rdlck)
929 * Parse a string containing an OST index list into an array of integers.
931 * The input string contains a comma delimited list of individual
932 * indices and ranges, for example "1,2-4,7". Add the indices into the
933 * \a osts array and remove duplicates.
935 * \param[out] osts array to store indices in
936 * \param[in] size size of \a osts array
937 * \param[in] offset starting index in \a osts
938 * \param[in] arg string containing OST index list
940 * \retval positive number of indices in \a osts
941 * \retval -EINVAL unable to parse \a arg
943 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
947 int slots = size - offset;
955 while (!end_of_loop) {
963 ptr = strchrnul(arg, ',');
965 end_of_loop = *ptr == '\0';
968 start_index = strtol(arg, &endptr, 0);
969 if (endptr == arg) /* no data at all */
971 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
976 end_index = start_index;
977 if (*endptr == '-') {
978 end_index = strtol(endptr + 1, &endptr, 0);
981 if (end_index < start_index)
985 for (i = start_index; i <= end_index && slots > 0; i++) {
988 /* remove duplicate */
989 for (j = 0; j < offset; j++) {
993 if (j == offset) { /* no duplicate */
998 if (slots == 0 && i < end_index)
1006 if (!end_of_loop && ptr != NULL)
1009 return rc < 0 ? rc : nr;
1012 static int verify_pool_name(char *prog_name, char *pool_name)
1017 if (pool_name == NULL)
1020 ptr = strchr(pool_name, '.');
1024 if (ptr == pool_name) {
1025 fprintf(stderr, "error: %s: fsname is empty "
1026 "in pool name '%s'\n",
1027 prog_name, pool_name);
1033 rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1035 fprintf(stderr, "error: %s: poolname '%s' is empty\n",
1036 prog_name, pool_name);
1038 } else if (rc == -2) {
1039 fprintf(stderr, "error: %s: pool name '%s' is too long "
1040 "(max is %d characters)\n",
1041 prog_name, pool_name, LOV_MAXPOOLNAME);
1043 } else if (rc > 0) {
1044 fprintf(stderr, "error: %s: char '%c' not allowed in "
1046 prog_name, rc, pool_name);
1052 struct lfs_setstripe_args {
1053 unsigned long long lsa_comp_end;
1054 unsigned long long lsa_stripe_size;
1055 int lsa_stripe_count;
1057 __u32 lsa_comp_flags;
1060 char *lsa_pool_name;
1063 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1065 memset(lsa, 0, sizeof(*lsa));
1066 lsa->lsa_stripe_off = -1;
1069 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1071 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1072 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1073 lsa->lsa_comp_end != 0);
1076 static int comp_args_to_layout(struct llapi_layout **composite,
1077 struct lfs_setstripe_args *lsa)
1079 struct llapi_layout *layout = *composite;
1080 uint64_t prev_end = 0;
1083 if (layout == NULL) {
1084 layout = llapi_layout_alloc();
1085 if (layout == NULL) {
1086 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1090 *composite = layout;
1094 /* Get current component extent, current component
1095 * must be the tail component. */
1096 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1098 fprintf(stderr, "Get comp extent failed. %s\n",
1103 rc = llapi_layout_comp_add(layout);
1105 fprintf(stderr, "Add component failed. %s\n",
1111 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1113 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1114 prev_end, lsa->lsa_comp_end, strerror(errno));
1118 if (lsa->lsa_stripe_size != 0) {
1119 rc = llapi_layout_stripe_size_set(layout,
1120 lsa->lsa_stripe_size);
1122 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1123 lsa->lsa_stripe_size, strerror(errno));
1128 if (lsa->lsa_stripe_count != 0) {
1129 rc = llapi_layout_stripe_count_set(layout,
1130 lsa->lsa_stripe_count == -1 ?
1132 lsa->lsa_stripe_count);
1134 fprintf(stderr, "Set stripe count %d failed. %s\n",
1135 lsa->lsa_stripe_count, strerror(errno));
1140 if (lsa->lsa_pool_name != NULL) {
1141 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1143 fprintf(stderr, "Set pool name: %s failed. %s\n",
1144 lsa->lsa_pool_name, strerror(errno));
1149 if (lsa->lsa_nr_osts > 0) {
1150 if (lsa->lsa_stripe_count > 0 &&
1151 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1152 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1153 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1156 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1157 rc = llapi_layout_ost_index_set(layout, i,
1162 } else if (lsa->lsa_stripe_off != -1) {
1163 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1166 fprintf(stderr, "Set ost index %d failed. %s\n",
1167 i, strerror(errno));
1174 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1175 * end of the last component in the existing file, and adjust the
1176 * first extent start of the components to be added accordingly. */
1177 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1179 struct llapi_layout *head;
1180 uint64_t start, end, stripe_size, prev_end = 0;
1186 head = llapi_layout_get_by_path(fname, 0);
1188 fprintf(stderr, "Read layout from %s failed. %s\n",
1189 fname, strerror(errno));
1193 /* Current component of 'head' should be tail of component list. */
1194 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1196 fprintf(stderr, "Get prev extent failed. %s\n",
1198 llapi_layout_free(head);
1202 llapi_layout_free(head);
1204 /* Make sure we use the first component of the layout to be added. */
1205 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1207 fprintf(stderr, "Move component cursor failed. %s\n",
1212 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1214 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1218 if (start > prev_end || end <= prev_end) {
1219 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1220 "adjacent with the existing file extent end: %lu\n",
1221 start, end, prev_end);
1225 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1227 fprintf(stderr, "Get stripe size failed. %s\n",
1232 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1233 (prev_end & (stripe_size - 1))) {
1234 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1235 stripe_size, prev_end);
1239 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1241 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1242 prev_end, end, strerror(errno));
1249 static int comp_name2flags(__u32 *flags, char *name)
1257 for (ptr = name; ; ptr = NULL) {
1258 char *flg = strtok(ptr, ",");
1261 if (strcmp(flg, "init") == 0)
1262 *flags |= LCME_FL_INIT;
1266 return (*flags == 0) ? -EINVAL : 0;
1281 static int lfs_setstripe(int argc, char **argv)
1283 struct lfs_setstripe_args lsa;
1284 struct llapi_stripe_param *param = NULL;
1285 struct find_param migrate_mdt_param = {
1295 char *mdt_idx_arg = NULL;
1296 unsigned long long size_units = 1;
1297 bool migrate_mode = false;
1298 bool migration_block = false;
1299 __u64 migration_flags = 0;
1300 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1301 int comp_del = 0, comp_set = 0;
1304 struct llapi_layout *layout = NULL;
1306 struct option long_opts[] = {
1307 /* --block is only valid in migrate mode */
1308 {"block", no_argument, 0, 'b'},
1309 {"comp-add", no_argument, 0, LFS_COMP_ADD_OPT},
1310 {"component-add", no_argument, 0, LFS_COMP_ADD_OPT},
1311 {"comp-del", no_argument, 0, LFS_COMP_DEL_OPT},
1312 {"component-del", no_argument, 0, LFS_COMP_DEL_OPT},
1313 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1314 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1315 {"comp-set", no_argument, 0, LFS_COMP_SET_OPT},
1316 {"component-set", no_argument, 0, LFS_COMP_SET_OPT},
1317 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1318 /* This formerly implied "stripe-count", but was explicitly
1319 * made "stripe-count" for consistency with other options,
1320 * and to separate it from "mdt-count" when DNE arrives. */
1321 {"count", required_argument, 0, 'c'},
1323 {"stripe-count", required_argument, 0, 'c'},
1324 {"stripe_count", required_argument, 0, 'c'},
1325 {"delete", no_argument, 0, 'd'},
1326 {"comp-end", required_argument, 0, 'E'},
1327 {"component-end", required_argument, 0, 'E'},
1328 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1329 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1330 /* This formerly implied "stripe-index", but was explicitly
1331 * made "stripe-index" for consistency with other options,
1332 * and to separate it from "mdt-index" when DNE arrives. */
1333 {"index", required_argument, 0, 'i'},
1335 {"stripe-index", required_argument, 0, 'i'},
1336 {"stripe_index", required_argument, 0, 'i'},
1337 {"comp-id", required_argument, 0, 'I'},
1338 {"component-id", required_argument, 0, 'I'},
1339 {"mdt", required_argument, 0, 'm'},
1340 {"mdt-index", required_argument, 0, 'm'},
1341 {"mdt_index", required_argument, 0, 'm'},
1342 /* --non-block is only valid in migrate mode */
1343 {"non-block", no_argument, 0, 'n'},
1344 {"ost", required_argument, 0, 'o'},
1345 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1346 {"ost-list", required_argument, 0, 'o'},
1347 {"ost_list", required_argument, 0, 'o'},
1349 {"pool", required_argument, 0, 'p'},
1350 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1351 /* This formerly implied "--stripe-size", but was confusing
1352 * with "lfs find --size|-s", which means "file size", so use
1353 * the consistent "--stripe-size|-S" for all commands. */
1354 {"size", required_argument, 0, 's'},
1356 {"stripe-size", required_argument, 0, 'S'},
1357 {"stripe_size", required_argument, 0, 'S'},
1358 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1359 /* --verbose is only valid in migrate mode */
1360 {"verbose", no_argument, 0, 'v'},
1364 setstripe_args_init(&lsa);
1366 if (strcmp(argv[0], "migrate") == 0)
1367 migrate_mode = true;
1369 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1370 long_opts, NULL)) >= 0) {
1375 case LFS_COMP_ADD_OPT:
1378 case LFS_COMP_DEL_OPT:
1381 case LFS_COMP_FLAGS_OPT:
1382 result = comp_name2flags(&lsa.lsa_comp_flags, optarg);
1384 fprintf(stderr, "error: %s: bad comp flags "
1385 "'%s'\n", argv[0], optarg);
1389 case LFS_COMP_SET_OPT:
1393 if (!migrate_mode) {
1394 fprintf(stderr, "--block is valid only for"
1398 migration_block = true;
1401 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1402 if (strcmp(argv[optind - 1], "--count") == 0)
1403 fprintf(stderr, "warning: '--count' deprecated"
1404 ", use '--stripe-count' instead\n");
1406 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1408 fprintf(stderr, "error: %s: bad stripe count "
1409 "'%s'\n", argv[0], optarg);
1414 /* delete the default striping pattern */
1418 if (lsa.lsa_comp_end != 0) {
1419 result = comp_args_to_layout(&layout, &lsa);
1423 setstripe_args_init(&lsa);
1426 if (!strncmp(optarg, "-1", strlen("-1")) ||
1427 !strncmp(optarg, "EOF", strlen("EOF")) ||
1428 !strncmp(optarg, "eof", strlen("eof"))) {
1429 lsa.lsa_comp_end = LUSTRE_EOF;
1431 result = llapi_parse_size(optarg,
1435 fprintf(stderr, "error: %s: "
1436 "bad component end '%s'\n",
1443 if (strcmp(argv[optind - 1], "--index") == 0)
1444 fprintf(stderr, "warning: '--index' deprecated"
1445 ", use '--stripe-index' instead\n");
1446 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1448 fprintf(stderr, "error: %s: bad stripe offset "
1449 "'%s'\n", argv[0], optarg);
1454 comp_id = strtoul(optarg, &end, 0);
1455 if (*end != '\0' || comp_id == 0) {
1456 fprintf(stderr, "error: %s: bad comp ID "
1457 "'%s'\n", argv[0], optarg);
1462 if (!migrate_mode) {
1463 fprintf(stderr, "--mdt-index is valid only for"
1467 mdt_idx_arg = optarg;
1470 if (!migrate_mode) {
1471 fprintf(stderr, "--non-block is valid only for"
1475 migration_flags |= MIGRATION_NONBLOCK;
1478 lsa.lsa_nr_osts = parse_targets(osts,
1479 sizeof(osts) / sizeof(__u32),
1480 lsa.lsa_nr_osts, optarg);
1481 if (lsa.lsa_nr_osts < 0) {
1483 "error: %s: bad OST indices '%s'\n",
1488 lsa.lsa_osts = osts;
1489 if (lsa.lsa_stripe_off == -1)
1490 lsa.lsa_stripe_off = osts[0];
1493 result = verify_pool_name(argv[0], optarg);
1496 lsa.lsa_pool_name = optarg;
1498 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1500 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1501 fprintf(stderr, "warning: '--size|-s' deprecated, "
1502 "use '--stripe-size|-S' instead\n");
1504 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1506 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1509 fprintf(stderr, "error: %s: bad stripe size "
1510 "'%s'\n", argv[0], optarg);
1515 if (!migrate_mode) {
1516 fprintf(stderr, "--verbose is valid only for"
1520 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1527 fname = argv[optind];
1529 if (lsa.lsa_comp_end != 0) {
1530 result = comp_args_to_layout(&layout, &lsa);
1535 if (optind == argc) {
1536 fprintf(stderr, "error: %s: missing filename|dirname\n",
1541 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1542 * altered by user space tool, so we don't need to support the
1543 * --component-set for this moment. */
1544 if (comp_set != 0) {
1545 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1550 if ((delete + comp_set + comp_del + comp_add) > 1) {
1551 fprintf(stderr, "error: %s: can't specify --component-set, "
1552 "--component-del, --component-add or -d together\n",
1557 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1558 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1559 fprintf(stderr, "error: %s: can't specify -d with "
1560 "-s, -c, -o, -p, -I, -F or -E options\n",
1565 if ((comp_set || comp_del) &&
1566 (setstripe_args_specified(&lsa) || layout != NULL)) {
1567 fprintf(stderr, "error: %s: can't specify --component-del or "
1568 "--component-set with -s, -c, -o, -p or -E options.\n",
1573 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1574 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1575 "--component-del option.\n", argv[0]);
1580 if (layout == NULL) {
1581 fprintf(stderr, "error: %s: -E option must be present"
1582 "in --component-add mode.\n", argv[0]);
1585 result = adjust_first_extent(fname, layout);
1590 if (mdt_idx_arg != NULL && optind > 3) {
1591 fprintf(stderr, "error: %s: cannot specify -m with other "
1592 "options\n", argv[0]);
1596 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1598 "error: %s: cannot specify --non-block and --block\n",
1603 /* support --component-id option for migrate later. */
1604 if (migrate_mode && comp_id != 0) {
1605 fprintf(stderr, "error: %s: -I isn't supported yet.\n",
1610 if (mdt_idx_arg != NULL) {
1611 /* initialize migrate mdt parameters */
1612 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1614 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1615 argv[0], mdt_idx_arg);
1618 migrate_mdt_param.fp_migrate = 1;
1619 } else if (layout == NULL) {
1620 /* initialize stripe parameters */
1621 param = calloc(1, offsetof(typeof(*param),
1622 lsp_osts[lsa.lsa_nr_osts]));
1623 if (param == NULL) {
1624 fprintf(stderr, "error: %s: %s\n", argv[0],
1629 param->lsp_stripe_size = lsa.lsa_stripe_size;
1630 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1631 param->lsp_stripe_count = lsa.lsa_stripe_count;
1632 param->lsp_stripe_pattern = 0;
1633 param->lsp_pool = lsa.lsa_pool_name;
1634 param->lsp_is_specific = false;
1635 if (lsa.lsa_nr_osts > 0) {
1636 if (lsa.lsa_stripe_count > 0 &&
1637 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1638 fprintf(stderr, "error: %s: stripe count '%d' "
1639 "doesn't match the number of OSTs: %d\n"
1640 , argv[0], lsa.lsa_stripe_count,
1646 param->lsp_is_specific = true;
1647 param->lsp_stripe_count = lsa.lsa_nr_osts;
1648 memcpy(param->lsp_osts, osts,
1649 sizeof(*osts) * lsa.lsa_nr_osts);
1653 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1655 if (mdt_idx_arg != NULL) {
1656 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1657 op = "migrate mdt objects of";
1658 } else if (migrate_mode) {
1659 result = lfs_migrate(fname, migration_flags, param,
1661 op = "migrate ost objects of";
1662 } else if (comp_set != 0) {
1663 result = lfs_component_set(fname, comp_id,
1664 lsa.lsa_comp_flags);
1665 op = "modify component flags of";
1666 } else if (comp_del != 0) {
1667 result = lfs_component_del(fname, comp_id,
1668 lsa.lsa_comp_flags);
1669 op = "delete component of";
1670 } else if (comp_add != 0) {
1671 result = lfs_component_add(fname, layout);
1672 op = "add component to";
1673 } else if (layout != NULL) {
1674 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1680 op = "create composite";
1682 result = llapi_file_open_param(fname,
1689 op = "create striped";
1692 /* Save the first error encountered. */
1695 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1697 lsa.lsa_pool_name != NULL && result == EINVAL ?
1698 "OST not in pool?" : strerror(errno));
1704 llapi_layout_free(layout);
1707 llapi_layout_free(layout);
1711 static int lfs_poollist(int argc, char **argv)
1716 return llapi_poollist(argv[1]);
1719 static int set_time(time_t *time, time_t *set, char *str)
1726 else if (str[0] == '-')
1732 t = strtol(str, NULL, 0);
1733 if (*time < t * 24 * 60 * 60) {
1736 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1740 *set = *time - t * 24 * 60 * 60;
1743 static int name2uid(unsigned int *id, const char *name)
1745 struct passwd *passwd;
1747 passwd = getpwnam(name);
1750 *id = passwd->pw_uid;
1755 static int name2gid(unsigned int *id, const char *name)
1757 struct group *group;
1759 group = getgrnam(name);
1762 *id = group->gr_gid;
1767 static inline int name2projid(unsigned int *id, const char *name)
1772 static int uid2name(char **name, unsigned int id)
1774 struct passwd *passwd;
1776 passwd = getpwuid(id);
1779 *name = passwd->pw_name;
1784 static inline int gid2name(char **name, unsigned int id)
1786 struct group *group;
1788 group = getgrgid(id);
1791 *name = group->gr_name;
1796 static int name2layout(__u32 *layout, char *name)
1801 for (ptr = name; ; ptr = NULL) {
1802 lyt = strtok(ptr, ",");
1805 if (strcmp(lyt, "released") == 0)
1806 *layout |= LOV_PATTERN_F_RELEASED;
1807 else if (strcmp(lyt, "raid0") == 0)
1808 *layout |= LOV_PATTERN_RAID0;
1815 static int lfs_find(int argc, char **argv)
1820 struct find_param param = {
1824 struct option long_opts[] = {
1825 {"atime", required_argument, 0, 'A'},
1826 {"comp-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1827 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1828 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1829 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1830 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
1831 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1832 {"stripe-count", required_argument, 0, 'c'},
1833 {"stripe_count", required_argument, 0, 'c'},
1834 {"ctime", required_argument, 0, 'C'},
1835 {"maxdepth", required_argument, 0, 'D'},
1836 {"comp-end", required_argument, 0, 'E'},
1837 {"component-end", required_argument, 0, 'E'},
1838 {"gid", required_argument, 0, 'g'},
1839 {"group", required_argument, 0, 'G'},
1840 {"mdt-hash", required_argument, 0, 'H'},
1841 {"stripe-index", required_argument, 0, 'i'},
1842 {"stripe_index", required_argument, 0, 'i'},
1843 /*{"component-id", required_argument, 0, 'I'},*/
1844 {"layout", required_argument, 0, 'L'},
1845 {"mdt", required_argument, 0, 'm'},
1846 {"mdt-index", required_argument, 0, 'm'},
1847 {"mdt_index", required_argument, 0, 'm'},
1848 {"mtime", required_argument, 0, 'M'},
1849 {"name", required_argument, 0, 'n'},
1850 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1851 {"obd", required_argument, 0, 'O'},
1852 {"ost", required_argument, 0, 'O'},
1853 /* no short option for pool, p/P already used */
1854 {"pool", required_argument, 0, LFS_POOL_OPT},
1855 {"print0", no_argument, 0, 'p'},
1856 {"print", no_argument, 0, 'P'},
1857 {"projid", required_argument, 0, LFS_PROJID_OPT},
1858 {"size", required_argument, 0, 's'},
1859 {"stripe-size", required_argument, 0, 'S'},
1860 {"stripe_size", required_argument, 0, 'S'},
1861 {"type", required_argument, 0, 't'},
1862 {"mdt-count", required_argument, 0, 'T'},
1863 {"uid", required_argument, 0, 'u'},
1864 {"user", required_argument, 0, 'U'},
1877 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1878 while ((c = getopt_long_only(argc, argv,
1879 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1880 long_opts, NULL)) >= 0) {
1885 /* '!' is part of option */
1886 /* when getopt_long_only() finds a string which is not
1887 * an option nor a known option argument it returns 1
1888 * in that case if we already have found pathstart and pathend
1889 * (i.e. we have the list of pathnames),
1890 * the only supported value is "!"
1892 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1893 if (!isoption && pathend != -1) {
1894 fprintf(stderr, "err: %s: filename|dirname must either "
1895 "precede options or follow options\n",
1900 if (!isoption && pathstart == -1)
1901 pathstart = optind - 1;
1902 if (isoption && pathstart != -1 && pathend == -1)
1903 pathend = optind - 2;
1909 /* unknown; opt is "!" or path component,
1910 * checking done above.
1912 if (strcmp(optarg, "!") == 0)
1916 xtime = ¶m.fp_atime;
1917 xsign = ¶m.fp_asign;
1918 param.fp_exclude_atime = !!neg_opt;
1919 /* no break, this falls through to 'C' for ctime */
1922 xtime = ¶m.fp_ctime;
1923 xsign = ¶m.fp_csign;
1924 param.fp_exclude_ctime = !!neg_opt;
1926 /* no break, this falls through to 'M' for mtime */
1929 xtime = ¶m.fp_mtime;
1930 xsign = ¶m.fp_msign;
1931 param.fp_exclude_mtime = !!neg_opt;
1933 rc = set_time(&t, xtime, optarg);
1934 if (rc == INT_MAX) {
1941 case LFS_COMP_COUNT_OPT:
1942 if (optarg[0] == '+') {
1943 param.fp_comp_count_sign = -1;
1945 } else if (optarg[0] == '-') {
1946 param.fp_comp_count_sign = 1;
1950 param.fp_comp_count = strtoul(optarg, &endptr, 0);
1951 if (*endptr != '\0') {
1952 fprintf(stderr, "error: bad component count "
1956 param.fp_check_comp_count = 1;
1957 param.fp_exclude_comp_count = !!neg_opt;
1959 case LFS_COMP_FLAGS_OPT:
1960 rc = comp_name2flags(¶m.fp_comp_flags, optarg);
1962 fprintf(stderr, "error: bad component flags "
1966 param.fp_check_comp_flags = 1;
1967 param.fp_exclude_comp_flags = !!neg_opt;
1969 case LFS_COMP_START_OPT:
1970 if (optarg[0] == '+') {
1971 param.fp_comp_start_sign = -1;
1973 } else if (optarg[0] == '-') {
1974 param.fp_comp_start_sign = 1;
1978 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
1979 ¶m.fp_comp_start_units, 0);
1981 fprintf(stderr, "error: bad component start "
1985 param.fp_check_comp_start = 1;
1986 param.fp_exclude_comp_start = !!neg_opt;
1989 if (optarg[0] == '+') {
1990 param.fp_stripe_count_sign = -1;
1992 } else if (optarg[0] == '-') {
1993 param.fp_stripe_count_sign = 1;
1997 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1998 if (*endptr != '\0') {
1999 fprintf(stderr,"error: bad stripe_count '%s'\n",
2004 param.fp_check_stripe_count = 1;
2005 param.fp_exclude_stripe_count = !!neg_opt;
2008 param.fp_max_depth = strtol(optarg, 0, 0);
2011 if (optarg[0] == '+') {
2012 param.fp_comp_end_sign = -1;
2014 } else if (optarg[0] == '-') {
2015 param.fp_comp_end_sign = 1;
2019 rc = llapi_parse_size(optarg, ¶m.fp_comp_end,
2020 ¶m.fp_comp_end_units, 0);
2022 fprintf(stderr, "error: bad component end "
2026 param.fp_check_comp_end = 1;
2027 param.fp_exclude_comp_end = !!neg_opt;
2031 rc = name2gid(¶m.fp_gid, optarg);
2033 param.fp_gid = strtoul(optarg, &endptr, 10);
2034 if (*endptr != '\0') {
2035 fprintf(stderr, "Group/GID: %s cannot "
2036 "be found.\n", optarg);
2041 param.fp_exclude_gid = !!neg_opt;
2042 param.fp_check_gid = 1;
2045 param.fp_hash_type = check_hashtype(optarg);
2046 if (param.fp_hash_type == 0) {
2047 fprintf(stderr, "error: bad hash_type '%s'\n",
2052 param.fp_check_hash_type = 1;
2053 param.fp_exclude_hash_type = !!neg_opt;
2056 ret = name2layout(¶m.fp_layout, optarg);
2059 param.fp_exclude_layout = !!neg_opt;
2060 param.fp_check_layout = 1;
2064 rc = name2uid(¶m.fp_uid, optarg);
2066 param.fp_uid = strtoul(optarg, &endptr, 10);
2067 if (*endptr != '\0') {
2068 fprintf(stderr, "User/UID: %s cannot "
2069 "be found.\n", optarg);
2074 param.fp_exclude_uid = !!neg_opt;
2075 param.fp_check_uid = 1;
2078 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2080 "Pool name %s is too long"
2081 " (max is %d)\n", optarg,
2086 /* we do check for empty pool because empty pool
2087 * is used to find V1 lov attributes */
2088 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2089 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2090 param.fp_exclude_pool = !!neg_opt;
2091 param.fp_check_pool = 1;
2094 param.fp_pattern = (char *)optarg;
2095 param.fp_exclude_pattern = !!neg_opt;
2100 char *buf, *token, *next, *p;
2104 buf = strdup(optarg);
2110 param.fp_exclude_obd = !!neg_opt;
2113 while (token && *token) {
2114 token = strchr(token, ',');
2121 param.fp_exclude_mdt = !!neg_opt;
2122 param.fp_num_alloc_mdts += len;
2123 tmp = realloc(param.fp_mdt_uuid,
2124 param.fp_num_alloc_mdts *
2125 sizeof(*param.fp_mdt_uuid));
2131 param.fp_mdt_uuid = tmp;
2133 param.fp_exclude_obd = !!neg_opt;
2134 param.fp_num_alloc_obds += len;
2135 tmp = realloc(param.fp_obd_uuid,
2136 param.fp_num_alloc_obds *
2137 sizeof(*param.fp_obd_uuid));
2143 param.fp_obd_uuid = tmp;
2145 for (token = buf; token && *token; token = next) {
2146 struct obd_uuid *puuid;
2149 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2152 ¶m.fp_obd_uuid[param.fp_num_obds++];
2154 p = strchr(token, ',');
2161 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2166 strncpy(puuid->uuid, token,
2167 sizeof(puuid->uuid));
2175 param.fp_zero_end = 1;
2179 case LFS_PROJID_OPT:
2180 rc = name2projid(¶m.fp_projid, optarg);
2182 param.fp_projid = strtoul(optarg, &endptr, 10);
2183 if (*endptr != '\0') {
2185 "Invalid project ID: %s",
2191 param.fp_exclude_projid = !!neg_opt;
2192 param.fp_check_projid = 1;
2195 if (optarg[0] == '+') {
2196 param.fp_size_sign = -1;
2198 } else if (optarg[0] == '-') {
2199 param.fp_size_sign = 1;
2203 ret = llapi_parse_size(optarg, ¶m.fp_size,
2204 ¶m.fp_size_units, 0);
2206 fprintf(stderr, "error: bad file size '%s'\n",
2210 param.fp_check_size = 1;
2211 param.fp_exclude_size = !!neg_opt;
2214 if (optarg[0] == '+') {
2215 param.fp_stripe_size_sign = -1;
2217 } else if (optarg[0] == '-') {
2218 param.fp_stripe_size_sign = 1;
2222 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2223 ¶m.fp_stripe_size_units, 0);
2225 fprintf(stderr, "error: bad stripe_size '%s'\n",
2229 param.fp_check_stripe_size = 1;
2230 param.fp_exclude_stripe_size = !!neg_opt;
2233 param.fp_exclude_type = !!neg_opt;
2234 switch (optarg[0]) {
2236 param.fp_type = S_IFBLK;
2239 param.fp_type = S_IFCHR;
2242 param.fp_type = S_IFDIR;
2245 param.fp_type = S_IFREG;
2248 param.fp_type = S_IFLNK;
2251 param.fp_type = S_IFIFO;
2254 param.fp_type = S_IFSOCK;
2257 fprintf(stderr, "error: %s: bad type '%s'\n",
2264 if (optarg[0] == '+') {
2265 param.fp_mdt_count_sign = -1;
2267 } else if (optarg[0] == '-') {
2268 param.fp_mdt_count_sign = 1;
2272 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2273 if (*endptr != '\0') {
2274 fprintf(stderr, "error: bad mdt_count '%s'\n",
2279 param.fp_check_mdt_count = 1;
2280 param.fp_exclude_mdt_count = !!neg_opt;
2288 if (pathstart == -1) {
2289 fprintf(stderr, "error: %s: no filename|pathname\n",
2293 } else if (pathend == -1) {
2299 rc = llapi_find(argv[pathstart], ¶m);
2300 if (rc != 0 && ret == 0)
2302 } while (++pathstart < pathend);
2305 fprintf(stderr, "error: %s failed for %s.\n",
2306 argv[0], argv[optind - 1]);
2308 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2309 free(param.fp_obd_uuid);
2311 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2312 free(param.fp_mdt_uuid);
2317 static int lfs_getstripe_internal(int argc, char **argv,
2318 struct find_param *param)
2320 struct option long_opts[] = {
2321 {"comp-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2322 {"component-count", no_argument, 0, LFS_COMP_COUNT_OPT},
2323 {"comp-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2324 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2325 {"comp-start", required_argument, 0, LFS_COMP_START_OPT},
2326 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
2327 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2328 /* This formerly implied "stripe-count", but was explicitly
2329 * made "stripe-count" for consistency with other options,
2330 * and to separate it from "mdt-count" when DNE arrives. */
2331 {"count", no_argument, 0, 'c'},
2333 {"stripe-count", no_argument, 0, 'c'},
2334 {"stripe_count", no_argument, 0, 'c'},
2335 {"directory", no_argument, 0, 'd'},
2336 {"default", no_argument, 0, 'D'},
2337 {"comp-end", required_argument, 0, 'E'},
2338 {"component-end", required_argument, 0, 'E'},
2339 {"fid", no_argument, 0, 'F'},
2340 {"generation", no_argument, 0, 'g'},
2341 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
2342 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2343 /* This formerly implied "stripe-index", but was explicitly
2344 * made "stripe-index" for consistency with other options,
2345 * and to separate it from "mdt-index" when DNE arrives. */
2346 {"index", no_argument, 0, 'i'},
2348 {"stripe-index", no_argument, 0, 'i'},
2349 {"stripe_index", no_argument, 0, 'i'},
2350 {"comp-id", required_argument, 0, 'I'},
2351 {"component-id", required_argument, 0, 'I'},
2352 {"layout", no_argument, 0, 'L'},
2353 {"mdt", no_argument, 0, 'm'},
2354 {"mdt-index", no_argument, 0, 'm'},
2355 {"mdt_index", no_argument, 0, 'm'},
2356 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2357 {"mdt-index", no_argument, 0, 'M'},
2358 {"mdt_index", no_argument, 0, 'M'},
2360 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2361 /* This formerly implied "stripe-index", but was confusing
2362 * with "file offset" (which will eventually be needed for
2363 * with different layouts by offset), so deprecate it. */
2364 {"offset", no_argument, 0, 'o'},
2366 {"obd", required_argument, 0, 'O'},
2367 {"ost", required_argument, 0, 'O'},
2368 {"pool", no_argument, 0, 'p'},
2369 {"quiet", no_argument, 0, 'q'},
2370 {"recursive", no_argument, 0, 'r'},
2371 {"raw", no_argument, 0, 'R'},
2372 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2373 /* This formerly implied "--stripe-size", but was confusing
2374 * with "lfs find --size|-s", which means "file size", so use
2375 * the consistent "--stripe-size|-S" for all commands. */
2376 {"size", no_argument, 0, 's'},
2378 {"stripe-size", no_argument, 0, 'S'},
2379 {"stripe_size", no_argument, 0, 'S'},
2380 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
2381 {"verbose", no_argument, 0, 'v'},
2382 {"yaml", no_argument, 0, 'y'},
2388 while ((c = getopt_long(argc, argv, "cdDE:FghiI:LmMoO:pqrRsSvy",
2389 long_opts, NULL)) != -1) {
2392 if (strcmp(argv[optind - 1], "--count") == 0)
2393 fprintf(stderr, "warning: '--count' deprecated,"
2394 " use '--stripe-count' instead\n");
2395 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2396 param->fp_verbose |= VERBOSE_COUNT;
2397 param->fp_max_depth = 0;
2400 case LFS_COMP_COUNT_OPT:
2401 param->fp_verbose |= VERBOSE_COMP_COUNT;
2402 param->fp_max_depth = 0;
2404 case LFS_COMP_FLAGS_OPT:
2405 if (optarg != NULL) {
2406 rc = comp_name2flags(¶m->fp_comp_flags,
2409 param->fp_verbose |=
2411 param->fp_max_depth = 0;
2414 param->fp_check_comp_flags = 1;
2417 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2418 param->fp_max_depth = 0;
2421 case LFS_COMP_START_OPT:
2422 if (optarg != NULL) {
2424 if (tmp[0] == '+') {
2425 param->fp_comp_start_sign = 1;
2427 } else if (tmp[0] == '-') {
2428 param->fp_comp_start_sign = -1;
2431 rc = llapi_parse_size(tmp,
2432 ¶m->fp_comp_start,
2433 ¶m->fp_comp_start_units, 0);
2435 param->fp_verbose |= VERBOSE_COMP_START;
2436 param->fp_max_depth = 0;
2439 param->fp_check_comp_start = 1;
2442 param->fp_verbose |= VERBOSE_COMP_START;
2443 param->fp_max_depth = 0;
2447 param->fp_max_depth = 0;
2450 param->fp_get_default_lmv = 1;
2453 if (optarg != NULL) {
2455 if (tmp[0] == '+') {
2456 param->fp_comp_end_sign = 1;
2458 } else if (tmp[0] == '-') {
2459 param->fp_comp_end_sign = -1;
2462 rc = llapi_parse_size(tmp,
2463 ¶m->fp_comp_end,
2464 ¶m->fp_comp_end_units, 0);
2466 param->fp_verbose |= VERBOSE_COMP_END;
2467 param->fp_max_depth = 0;
2470 param->fp_check_comp_end = 1;
2473 param->fp_verbose |= VERBOSE_COMP_END;
2474 param->fp_max_depth = 0;
2478 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2479 param->fp_verbose |= VERBOSE_DFID;
2480 param->fp_max_depth = 0;
2484 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2485 param->fp_verbose |= VERBOSE_GENERATION;
2486 param->fp_max_depth = 0;
2489 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2491 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2492 "use '--stripe-index|-i' instead\n");
2495 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2496 if (strcmp(argv[optind - 1], "--index") == 0)
2497 fprintf(stderr, "warning: '--index' deprecated"
2498 ", use '--stripe-index' instead\n");
2500 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2501 param->fp_verbose |= VERBOSE_OFFSET;
2502 param->fp_max_depth = 0;
2506 if (optarg != NULL) {
2507 param->fp_comp_id = strtoul(optarg, &end, 0);
2509 param->fp_verbose |= VERBOSE_COMP_ID;
2510 param->fp_max_depth = 0;
2513 param->fp_check_comp_id = 1;
2516 param->fp_max_depth = 0;
2517 param->fp_verbose |= VERBOSE_COMP_ID;
2521 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2522 param->fp_verbose |= VERBOSE_LAYOUT;
2523 param->fp_max_depth = 0;
2526 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2528 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2529 fprintf(stderr, "warning: '-M' deprecated"
2530 ", use '-m' instead\n");
2534 if (!(param->fp_verbose & VERBOSE_DETAIL))
2535 param->fp_max_depth = 0;
2536 param->fp_verbose |= VERBOSE_MDTINDEX;
2539 if (param->fp_obd_uuid) {
2541 "error: %s: only one obduuid allowed",
2545 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2548 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2549 param->fp_verbose |= VERBOSE_POOL;
2550 param->fp_max_depth = 0;
2557 param->fp_recursive = 1;
2562 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2564 fprintf(stderr, "warning: '--size|-s' deprecated, "
2565 "use '--stripe-size|-S' instead\n");
2566 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2568 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2569 param->fp_verbose |= VERBOSE_SIZE;
2570 param->fp_max_depth = 0;
2574 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2587 if (param->fp_recursive)
2588 param->fp_max_depth = -1;
2589 else if (param->fp_verbose & VERBOSE_DETAIL)
2590 param->fp_max_depth = 1;
2592 if (!param->fp_verbose)
2593 param->fp_verbose = VERBOSE_DEFAULT;
2594 if (param->fp_quiet)
2595 param->fp_verbose = VERBOSE_OBJID;
2598 rc = llapi_getstripe(argv[optind], param);
2599 } while (++optind < argc && !rc);
2602 fprintf(stderr, "error: %s failed for %s.\n",
2603 argv[0], argv[optind - 1]);
2607 static int lfs_tgts(int argc, char **argv)
2609 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2610 struct find_param param;
2611 int index = 0, rc=0;
2616 if (argc == 2 && !realpath(argv[1], path)) {
2618 fprintf(stderr, "error: invalid path '%s': %s\n",
2619 argv[1], strerror(-rc));
2623 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2624 /* Check if we have a mount point */
2625 if (mntdir[0] == '\0')
2628 memset(¶m, 0, sizeof(param));
2629 if (!strcmp(argv[0], "mdts"))
2630 param.fp_get_lmv = 1;
2632 rc = llapi_ostlist(mntdir, ¶m);
2634 fprintf(stderr, "error: %s: failed on %s\n",
2637 if (path[0] != '\0')
2639 memset(mntdir, 0, PATH_MAX);
2645 static int lfs_getstripe(int argc, char **argv)
2647 struct find_param param = { 0 };
2649 param.fp_max_depth = 1;
2650 return lfs_getstripe_internal(argc, argv, ¶m);
2654 static int lfs_getdirstripe(int argc, char **argv)
2656 struct find_param param = { 0 };
2657 struct option long_opts[] = {
2658 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2659 {"mdt-count", no_argument, 0, 'c'},
2661 {"mdt-hash", no_argument, 0, 'H'},
2662 {"mdt-index", no_argument, 0, 'i'},
2663 {"recursive", no_argument, 0, 'r'},
2664 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2665 {"mdt-hash", no_argument, 0, 't'},
2667 {"default", no_argument, 0, 'D'},
2668 {"obd", required_argument, 0, 'O'},
2669 {"mdt-count", no_argument, 0, 'T'},
2670 {"yaml", no_argument, 0, 'y'},
2675 param.fp_get_lmv = 1;
2677 while ((c = getopt_long(argc, argv,
2678 "cDHiO:rtTy", long_opts, NULL)) != -1)
2682 if (param.fp_obd_uuid) {
2684 "error: %s: only one obduuid allowed",
2688 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2690 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2692 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2693 fprintf(stderr, "warning: '-c' deprecated"
2694 ", use '-T' instead\n");
2698 param.fp_verbose |= VERBOSE_COUNT;
2701 param.fp_verbose |= VERBOSE_OFFSET;
2703 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2707 param.fp_verbose |= VERBOSE_HASH_TYPE;
2710 param.fp_get_default_lmv = 1;
2713 param.fp_recursive = 1;
2726 if (param.fp_recursive)
2727 param.fp_max_depth = -1;
2729 if (!param.fp_verbose)
2730 param.fp_verbose = VERBOSE_DEFAULT;
2733 rc = llapi_getstripe(argv[optind], ¶m);
2734 } while (++optind < argc && !rc);
2737 fprintf(stderr, "error: %s failed for %s.\n",
2738 argv[0], argv[optind - 1]);
2743 static int lfs_setdirstripe(int argc, char **argv)
2747 unsigned int stripe_offset = -1;
2748 unsigned int stripe_count = 1;
2749 enum lmv_hash_type hash_type;
2752 char *stripe_offset_opt = NULL;
2753 char *stripe_count_opt = NULL;
2754 char *stripe_hash_opt = NULL;
2755 char *mode_opt = NULL;
2756 bool default_stripe = false;
2757 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2758 mode_t previous_mode = 0;
2759 bool delete = false;
2761 struct option long_opts[] = {
2762 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2763 {"count", required_argument, 0, 'c'},
2765 {"mdt-count", required_argument, 0, 'c'},
2766 {"delete", no_argument, 0, 'd'},
2767 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2768 {"index", required_argument, 0, 'i'},
2770 {"mdt-index", required_argument, 0, 'i'},
2771 {"mode", required_argument, 0, 'm'},
2772 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2773 {"hash-type", required_argument, 0, 't'},
2774 {"mdt-hash", required_argument, 0, 't'},
2776 {"mdt-hash", required_argument, 0, 'H'},
2777 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2778 {"default_stripe", no_argument, 0, 'D'},
2780 {"default", no_argument, 0, 'D'},
2784 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2791 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2792 if (strcmp(argv[optind - 1], "--count") == 0)
2793 fprintf(stderr, "warning: '--count' deprecated"
2794 ", use '--mdt-count' instead\n");
2796 stripe_count_opt = optarg;
2800 default_stripe = true;
2803 default_stripe = true;
2806 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2807 if (strcmp(argv[optind - 1], "--index") == 0)
2808 fprintf(stderr, "warning: '--index' deprecated"
2809 ", use '--mdt-index' instead\n");
2811 stripe_offset_opt = optarg;
2816 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2820 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2821 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2822 fprintf(stderr, "warning: '--hash-type' "
2823 "deprecated, use '--mdt-hash' "
2826 stripe_hash_opt = optarg;
2829 fprintf(stderr, "error: %s: option '%s' "
2831 argv[0], argv[optind - 1]);
2836 if (optind == argc) {
2837 fprintf(stderr, "error: %s: missing dirname\n",
2842 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2843 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2848 if (stripe_offset_opt != NULL) {
2849 /* get the stripe offset */
2850 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2852 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2853 argv[0], stripe_offset_opt);
2859 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2860 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2861 " or -i options.\n", argv[0]);
2869 if (mode_opt != NULL) {
2870 mode = strtoul(mode_opt, &end, 8);
2872 fprintf(stderr, "error: %s: bad mode '%s'\n",
2876 previous_mode = umask(0);
2879 if (stripe_hash_opt == NULL) {
2880 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2882 hash_type = check_hashtype(stripe_hash_opt);
2883 if (hash_type == 0) {
2885 "error: %s: bad stripe hash type '%s'\n",
2886 argv[0], stripe_hash_opt);
2891 /* get the stripe count */
2892 if (stripe_count_opt != NULL) {
2893 stripe_count = strtoul(stripe_count_opt, &end, 0);
2895 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2896 argv[0], stripe_count_opt);
2901 dname = argv[optind];
2903 if (default_stripe) {
2904 result = llapi_dir_set_default_lmv_stripe(dname,
2905 stripe_offset, stripe_count,
2908 result = llapi_dir_create_pool(dname, mode,
2910 stripe_count, hash_type,
2915 fprintf(stderr, "error: %s: create stripe dir '%s' "
2916 "failed\n", argv[0], dname);
2919 dname = argv[++optind];
2920 } while (dname != NULL);
2922 if (mode_opt != NULL)
2923 umask(previous_mode);
2929 static int lfs_rmentry(int argc, char **argv)
2936 fprintf(stderr, "error: %s: missing dirname\n",
2942 dname = argv[index];
2943 while (dname != NULL) {
2944 result = llapi_direntry_remove(dname);
2946 fprintf(stderr, "error: %s: remove dir entry '%s' "
2947 "failed\n", argv[0], dname);
2950 dname = argv[++index];
2955 static int lfs_mv(int argc, char **argv)
2957 struct find_param param = {
2964 struct option long_opts[] = {
2965 {"mdt-index", required_argument, 0, 'M'},
2966 {"verbose", no_argument, 0, 'v'},
2970 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2973 param.fp_mdt_index = strtoul(optarg, &end, 0);
2975 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2982 param.fp_verbose = VERBOSE_DETAIL;
2986 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2987 argv[0], argv[optind - 1]);
2992 if (param.fp_mdt_index == -1) {
2993 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2997 if (optind >= argc) {
2998 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3002 param.fp_migrate = 1;
3003 rc = llapi_migrate_mdt(argv[optind], ¶m);
3005 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3006 argv[0], argv[optind], param.fp_mdt_index,
3011 static int lfs_osts(int argc, char **argv)
3013 return lfs_tgts(argc, argv);
3016 static int lfs_mdts(int argc, char **argv)
3018 return lfs_tgts(argc, argv);
3021 #define COOK(value) \
3024 while (value > 1024) { \
3032 #define CDF "%11llu"
3033 #define HDF "%8.1f%c"
3038 MNTDF_INODES = 0x0001,
3039 MNTDF_COOKED = 0x0002,
3040 MNTDF_LAZY = 0x0004,
3041 MNTDF_VERBOSE = 0x0008,
3044 static int showdf(char *mntdir, struct obd_statfs *stat,
3045 char *uuid, enum mntdf_flags flags,
3046 char *type, int index, int rc)
3048 long long avail, used, total;
3050 char *suffix = "KMGTPEZY";
3051 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3052 char tbuf[3 * sizeof(__u64)];
3053 char ubuf[3 * sizeof(__u64)];
3054 char abuf[3 * sizeof(__u64)];
3055 char rbuf[3 * sizeof(__u64)];
3062 if (flags & MNTDF_INODES) {
3063 avail = stat->os_ffree;
3064 used = stat->os_files - stat->os_ffree;
3065 total = stat->os_files;
3067 int shift = flags & MNTDF_COOKED ? 0 : 10;
3069 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3070 used = ((stat->os_blocks - stat->os_bfree) *
3071 stat->os_bsize) >> shift;
3072 total = (stat->os_blocks * stat->os_bsize) >> shift;
3075 if ((used + avail) > 0)
3076 ratio = (double)used / (double)(used + avail);
3078 if (flags & MNTDF_COOKED) {
3082 cook_val = (double)total;
3085 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3088 snprintf(tbuf, sizeof(tbuf), CDF, total);
3090 cook_val = (double)used;
3093 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3096 snprintf(ubuf, sizeof(ubuf), CDF, used);
3098 cook_val = (double)avail;
3101 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3104 snprintf(abuf, sizeof(abuf), CDF, avail);
3106 snprintf(tbuf, sizeof(tbuf), CDF, total);
3107 snprintf(ubuf, sizeof(tbuf), CDF, used);
3108 snprintf(abuf, sizeof(tbuf), CDF, avail);
3111 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3112 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3113 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3115 printf("[%s:%d]", type, index);
3117 if (stat->os_state) {
3119 * Each character represents the matching
3122 const char state_names[] = "DRSI";
3127 for (i = 0, state = stat->os_state;
3128 state && i < sizeof(state_names); i++) {
3129 if (!(state & (1 << i)))
3131 printf("%c", state_names[i]);
3139 printf(UUF": inactive device\n", uuid);
3142 printf(UUF": %s\n", uuid, strerror(-rc));
3149 struct ll_stat_type {
3154 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3156 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3157 struct obd_uuid uuid_buf;
3158 char *poolname = NULL;
3159 struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3160 { LL_STATFS_LOV, "OST" },
3162 struct ll_stat_type *tp;
3163 __u64 ost_ffree = 0;
3171 poolname = strchr(pool, '.');
3172 if (poolname != NULL) {
3173 if (strncmp(fsname, pool, strlen(fsname))) {
3174 fprintf(stderr, "filesystem name incorrect\n");
3182 fd = open(mntdir, O_RDONLY);
3185 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3190 if (flags & MNTDF_INODES)
3191 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3192 "UUID", "Inodes", "IUsed", "IFree",
3193 "IUse%", "Mounted on");
3195 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3196 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3197 "Used", "Available", "Use%", "Mounted on");
3199 for (tp = types; tp->st_name != NULL; tp++) {
3200 for (index = 0; ; index++) {
3201 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3202 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3203 type = flags & MNTDF_LAZY ?
3204 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3205 rc2 = llapi_obd_fstatfs(fd, type, index,
3206 &stat_buf, &uuid_buf);
3211 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3212 if (!(flags & MNTDF_VERBOSE))
3214 } else if (rc2 < 0 && rc == 0) {
3218 if (poolname && tp->st_op == LL_STATFS_LOV &&
3219 llapi_search_ost(fsname, poolname,
3220 obd_uuid2str(&uuid_buf)) != 1)
3223 /* the llapi_obd_statfs() call may have returned with
3224 * an error, but if it filled in uuid_buf we will at
3225 * lease use that to print out a message for that OBD.
3226 * If we didn't get anything in the uuid_buf, then fill
3227 * it in so that we can print an error message. */
3228 if (uuid_buf.uuid[0] == '\0')
3229 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3230 "%s%04x", tp->st_name, index);
3231 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3232 flags, tp->st_name, index, rc2);
3235 if (tp->st_op == LL_STATFS_LMV) {
3236 sum.os_ffree += stat_buf.os_ffree;
3237 sum.os_files += stat_buf.os_files;
3238 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3239 sum.os_blocks += stat_buf.os_blocks *
3241 sum.os_bfree += stat_buf.os_bfree *
3243 sum.os_bavail += stat_buf.os_bavail *
3245 ost_ffree += stat_buf.os_ffree;
3253 /* If we don't have as many objects free on the OST as inodes
3254 * on the MDS, we reduce the total number of inodes to
3255 * compensate, so that the "inodes in use" number is correct.
3256 * Matches ll_statfs_internal() so the results are consistent. */
3257 if (ost_ffree < sum.os_ffree) {
3258 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3259 sum.os_ffree = ost_ffree;
3262 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3268 static int lfs_df(int argc, char **argv)
3270 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3271 enum mntdf_flags flags = 0;
3272 int c, rc = 0, index = 0;
3273 char fsname[PATH_MAX] = "", *pool_name = NULL;
3274 struct option long_opts[] = {
3275 {"human-readable", 0, 0, 'h'},
3276 {"inodes", 0, 0, 'i'},
3277 {"lazy", 0, 0, 'l'},
3278 {"pool", required_argument, 0, 'p'},
3279 {"verbose", 0, 0, 'v'},
3283 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3286 flags |= MNTDF_COOKED;
3289 flags |= MNTDF_INODES;
3292 flags |= MNTDF_LAZY;
3298 flags |= MNTDF_VERBOSE;
3304 if (optind < argc && !realpath(argv[optind], path)) {
3306 fprintf(stderr, "error: invalid path '%s': %s\n",
3307 argv[optind], strerror(-rc));
3311 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3312 /* Check if we have a mount point */
3313 if (mntdir[0] == '\0')
3316 rc = mntdf(mntdir, fsname, pool_name, flags);
3317 if (rc || path[0] != '\0')
3319 fsname[0] = '\0'; /* avoid matching in next loop */
3320 mntdir[0] = '\0'; /* avoid matching in next loop */
3326 static int lfs_getname(int argc, char **argv)
3328 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3329 int rc = 0, index = 0, c;
3330 char buf[sizeof(struct obd_uuid)];
3332 while ((c = getopt(argc, argv, "h")) != -1)
3335 if (optind == argc) { /* no paths specified, get all paths. */
3336 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3337 rc = llapi_getname(mntdir, buf, sizeof(buf));
3340 "cannot get name for `%s': %s\n",
3341 mntdir, strerror(-rc));
3345 printf("%s %s\n", buf, mntdir);
3347 path[0] = fsname[0] = mntdir[0] = 0;
3349 } else { /* paths specified, only attempt to search these. */
3350 for (; optind < argc; optind++) {
3351 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3354 "cannot get name for `%s': %s\n",
3355 argv[optind], strerror(-rc));
3359 printf("%s %s\n", buf, argv[optind]);
3365 static int lfs_check(int argc, char **argv)
3368 char mntdir[PATH_MAX] = {'\0'};
3377 obd_types[0] = obd_type1;
3378 obd_types[1] = obd_type2;
3380 if (strcmp(argv[1], "osts") == 0) {
3381 strcpy(obd_types[0], "osc");
3382 } else if (strcmp(argv[1], "mds") == 0) {
3383 strcpy(obd_types[0], "mdc");
3384 } else if (strcmp(argv[1], "servers") == 0) {
3386 strcpy(obd_types[0], "osc");
3387 strcpy(obd_types[1], "mdc");
3389 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3394 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3395 if (rc < 0 || mntdir[0] == '\0') {
3396 fprintf(stderr, "No suitable Lustre mount found\n");
3400 rc = llapi_target_check(num_types, obd_types, mntdir);
3402 fprintf(stderr, "error: %s: %s status failed\n",
3409 #ifdef HAVE_SYS_QUOTA_H
3410 #define ARG2INT(nr, str, msg) \
3413 nr = strtol(str, &endp, 0); \
3415 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3420 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3422 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3423 * returns the value or ULONG_MAX on integer overflow or incorrect format
3425 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3426 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3427 * 3. empty integer value is interpreted as 0
3429 static unsigned long str2sec(const char* timestr)
3431 const char spec[] = "smhdw";
3432 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3433 unsigned long val = 0;
3436 if (strpbrk(timestr, spec) == NULL) {
3437 /* no specifiers inside the time string,
3438 should treat it as an integer value */
3439 val = strtoul(timestr, &tail, 10);
3440 return *tail ? ULONG_MAX : val;
3443 /* format string is XXwXXdXXhXXmXXs */
3449 v = strtoul(timestr, &tail, 10);
3450 if (v == ULONG_MAX || *tail == '\0')
3451 /* value too large (ULONG_MAX or more)
3452 or missing specifier */
3455 ptr = strchr(spec, *tail);
3457 /* unknown specifier */
3462 /* check if product will overflow the type */
3463 if (!(v < ULONG_MAX / mult[ind]))
3466 ADD_OVERFLOW(val, mult[ind] * v);
3467 if (val == ULONG_MAX)
3479 #define ARG2ULL(nr, str, def_units) \
3481 unsigned long long limit, units = def_units; \
3484 rc = llapi_parse_size(str, &limit, &units, 1); \
3486 fprintf(stderr, "error: bad limit value %s\n", str); \
3492 static inline int has_times_option(int argc, char **argv)
3496 for (i = 1; i < argc; i++)
3497 if (!strcmp(argv[i], "-t"))
3503 int lfs_setquota_times(int argc, char **argv)
3506 struct if_quotactl qctl;
3507 char *mnt, *obd_type = (char *)qctl.obd_type;
3508 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3509 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3510 struct option long_opts[] = {
3511 {"block-grace", required_argument, 0, 'b'},
3512 {"group", no_argument, 0, 'g'},
3513 {"inode-grace", required_argument, 0, 'i'},
3514 {"projid", no_argument, 0, 'p'},
3515 {"times", no_argument, 0, 't'},
3516 {"user", no_argument, 0, 'u'},
3521 memset(&qctl, 0, sizeof(qctl));
3522 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3523 qctl.qc_type = ALLQUOTA;
3525 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3526 long_opts, NULL)) != -1) {
3537 if (qctl.qc_type != ALLQUOTA) {
3538 fprintf(stderr, "error: -u/g/p can't be used "
3539 "more than once\n");
3542 qctl.qc_type = qtype;
3545 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3546 fprintf(stderr, "error: bad block-grace: %s\n",
3550 dqb->dqb_valid |= QIF_BTIME;
3553 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3554 fprintf(stderr, "error: bad inode-grace: %s\n",
3558 dqb->dqb_valid |= QIF_ITIME;
3560 case 't': /* Yes, of course! */
3562 default: /* getopt prints error message for us when opterr != 0 */
3567 if (qctl.qc_type == ALLQUOTA) {
3568 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3572 if (optind != argc - 1) {
3573 fprintf(stderr, "error: unexpected parameters encountered\n");
3578 rc = llapi_quotactl(mnt, &qctl);
3581 fprintf(stderr, "%s %s ", obd_type,
3582 obd_uuid2str(&qctl.obd_uuid));
3583 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3590 #define BSLIMIT (1 << 0)
3591 #define BHLIMIT (1 << 1)
3592 #define ISLIMIT (1 << 2)
3593 #define IHLIMIT (1 << 3)
3595 int lfs_setquota(int argc, char **argv)
3598 struct if_quotactl qctl;
3599 char *mnt, *obd_type = (char *)qctl.obd_type;
3600 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3601 struct option long_opts[] = {
3602 {"block-softlimit", required_argument, 0, 'b'},
3603 {"block-hardlimit", required_argument, 0, 'B'},
3604 {"group", required_argument, 0, 'g'},
3605 {"inode-softlimit", required_argument, 0, 'i'},
3606 {"inode-hardlimit", required_argument, 0, 'I'},
3607 {"user", required_argument, 0, 'u'},
3608 {"projid", required_argument, 0, 'p'},
3611 unsigned limit_mask = 0;
3615 if (has_times_option(argc, argv))
3616 return lfs_setquota_times(argc, argv);
3618 memset(&qctl, 0, sizeof(qctl));
3619 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3620 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3621 * so it can be used as a marker that qc_type
3622 * isn't reinitialized from command line */
3624 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3625 long_opts, NULL)) != -1) {
3629 rc = name2uid(&qctl.qc_id, optarg);
3633 rc = name2gid(&qctl.qc_id, optarg);
3637 rc = name2projid(&qctl.qc_id, optarg);
3639 if (qctl.qc_type != ALLQUOTA) {
3640 fprintf(stderr, "error: -u and -g can't be used"
3641 " more than once\n");
3644 qctl.qc_type = qtype;
3646 qctl.qc_id = strtoul(optarg, &endptr, 10);
3647 if (*endptr != '\0') {
3648 fprintf(stderr, "error: can't find id "
3649 "for name %s\n", optarg);
3655 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3656 dqb->dqb_bsoftlimit >>= 10;
3657 limit_mask |= BSLIMIT;
3658 if (dqb->dqb_bsoftlimit &&
3659 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3660 fprintf(stderr, "warning: block softlimit is "
3661 "smaller than the miminal qunit size, "
3662 "please see the help of setquota or "
3663 "Lustre manual for details.\n");
3666 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3667 dqb->dqb_bhardlimit >>= 10;
3668 limit_mask |= BHLIMIT;
3669 if (dqb->dqb_bhardlimit &&
3670 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3671 fprintf(stderr, "warning: block hardlimit is "
3672 "smaller than the miminal qunit size, "
3673 "please see the help of setquota or "
3674 "Lustre manual for details.\n");
3677 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3678 limit_mask |= ISLIMIT;
3679 if (dqb->dqb_isoftlimit &&
3680 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3681 fprintf(stderr, "warning: inode softlimit is "
3682 "smaller than the miminal qunit size, "
3683 "please see the help of setquota or "
3684 "Lustre manual for details.\n");
3687 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3688 limit_mask |= IHLIMIT;
3689 if (dqb->dqb_ihardlimit &&
3690 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3691 fprintf(stderr, "warning: inode hardlimit is "
3692 "smaller than the miminal qunit size, "
3693 "please see the help of setquota or "
3694 "Lustre manual for details.\n");
3696 default: /* getopt prints error message for us when opterr != 0 */
3701 if (qctl.qc_type == ALLQUOTA) {
3702 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3706 if (limit_mask == 0) {
3707 fprintf(stderr, "error: at least one limit must be specified\n");
3711 if (optind != argc - 1) {
3712 fprintf(stderr, "error: unexpected parameters encountered\n");
3718 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3719 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3720 /* sigh, we can't just set blimits/ilimits */
3721 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3722 .qc_type = qctl.qc_type,
3723 .qc_id = qctl.qc_id};
3725 rc = llapi_quotactl(mnt, &tmp_qctl);
3727 fprintf(stderr, "error: setquota failed while retrieving"
3728 " current quota settings (%s)\n",
3733 if (!(limit_mask & BHLIMIT))
3734 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3735 if (!(limit_mask & BSLIMIT))
3736 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3737 if (!(limit_mask & IHLIMIT))
3738 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3739 if (!(limit_mask & ISLIMIT))
3740 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3742 /* Keep grace times if we have got no softlimit arguments */
3743 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3744 dqb->dqb_valid |= QIF_BTIME;
3745 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3748 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3749 dqb->dqb_valid |= QIF_ITIME;
3750 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3754 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3755 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3757 rc = llapi_quotactl(mnt, &qctl);
3760 fprintf(stderr, "%s %s ", obd_type,
3761 obd_uuid2str(&qctl.obd_uuid));
3762 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3769 /* Converts seconds value into format string
3770 * result is returned in buf
3772 * 1. result is in descenting order: 1w2d3h4m5s
3773 * 2. zero fields are not filled (except for p. 3): 5d1s
3774 * 3. zero seconds value is presented as "0s"
3776 static char * __sec2str(time_t seconds, char *buf)
3778 const char spec[] = "smhdw";
3779 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3784 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3785 c = seconds / mult[i];
3787 if (c > 0 || (i == 0 && buf == tail))
3788 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3796 static void sec2str(time_t seconds, char *buf, int rc)
3803 tail = __sec2str(seconds, tail);
3805 if (rc && tail - buf < 39) {
3811 static void diff2str(time_t seconds, char *buf, time_t now)
3817 if (seconds <= now) {
3818 strcpy(buf, "none");
3821 __sec2str(seconds - now, buf);
3824 static void print_quota_title(char *name, struct if_quotactl *qctl,
3825 bool human_readable)
3827 printf("Disk quotas for %s %s (%cid %u):\n",
3828 qtype_name(qctl->qc_type), name,
3829 *qtype_name(qctl->qc_type), qctl->qc_id);
3830 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3831 "Filesystem", human_readable ? "used" : "kbytes",
3832 "quota", "limit", "grace",
3833 "files", "quota", "limit", "grace");
3836 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3839 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3842 snprintf(buf, buflen, "%5.4gP",
3843 (double)num / ((__u64)1 << 40));
3845 snprintf(buf, buflen, "%5.4gT",
3846 (double)num / (1 << 30));
3848 snprintf(buf, buflen, "%5.4gG",
3849 (double)num / (1 << 20));
3851 snprintf(buf, buflen, "%5.4gM",
3852 (double)num / (1 << 10));
3854 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3858 #define STRBUF_LEN 32
3859 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3866 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3867 int bover = 0, iover = 0;
3868 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3869 char numbuf[3][STRBUF_LEN];
3871 char strbuf[STRBUF_LEN];
3873 if (dqb->dqb_bhardlimit &&
3874 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3876 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3877 if (dqb->dqb_btime > now) {
3884 if (dqb->dqb_ihardlimit &&
3885 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3887 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3888 if (dqb->dqb_itime > now) {
3896 if (strlen(mnt) > 15)
3897 printf("%s\n%15s", mnt, "");
3899 printf("%15s", mnt);
3902 diff2str(dqb->dqb_btime, timebuf, now);
3904 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3905 strbuf, sizeof(strbuf), h);
3906 if (rc == -EREMOTEIO)
3907 sprintf(numbuf[0], "%s*", strbuf);
3909 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3910 "%s" : "[%s]", strbuf);
3912 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3913 if (type == QC_GENERAL)
3914 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3915 "%s" : "[%s]", strbuf);
3917 sprintf(numbuf[1], "%s", "-");
3919 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3920 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3921 "%s" : "[%s]", strbuf);
3923 printf(" %7s%c %6s %7s %7s",
3924 numbuf[0], bover ? '*' : ' ', numbuf[1],
3925 numbuf[2], bover > 1 ? timebuf : "-");
3928 diff2str(dqb->dqb_itime, timebuf, now);
3930 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3931 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3933 if (type == QC_GENERAL)
3934 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3936 (uintmax_t)dqb->dqb_isoftlimit);
3938 sprintf(numbuf[1], "%s", "-");
3940 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3941 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3943 if (type != QC_OSTIDX)
3944 printf(" %7s%c %6s %7s %7s",
3945 numbuf[0], iover ? '*' : ' ', numbuf[1],
3946 numbuf[2], iover > 1 ? timebuf : "-");
3948 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3951 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3952 qctl->qc_cmd == Q_GETOINFO) {
3956 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3957 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3958 printf("Block grace time: %s; Inode grace time: %s\n",
3959 bgtimebuf, igtimebuf);
3963 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3964 bool h, __u64 *total)
3966 int rc = 0, rc1 = 0, count = 0;
3967 __u32 valid = qctl->qc_valid;
3969 rc = llapi_get_obd_count(mnt, &count, is_mdt);
3971 fprintf(stderr, "can not get %s count: %s\n",
3972 is_mdt ? "mdt": "ost", strerror(-rc));
3976 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3977 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3978 rc = llapi_quotactl(mnt, qctl);
3980 /* It is remote client case. */
3981 if (rc == -EOPNOTSUPP) {
3988 fprintf(stderr, "quotactl %s%d failed.\n",
3989 is_mdt ? "mdt": "ost", qctl->qc_idx);
3993 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3994 qctl->qc_valid, 0, h);
3995 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3996 qctl->qc_dqblk.dqb_bhardlimit;
3999 qctl->qc_valid = valid;
4003 static int lfs_quota(int argc, char **argv)
4006 char *mnt, *name = NULL;
4007 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4008 .qc_type = ALLQUOTA };
4009 char *obd_type = (char *)qctl.obd_type;
4010 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4011 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4012 verbose = 0, pass = 0, quiet = 0, inacc;
4014 __u32 valid = QC_GENERAL, idx = 0;
4015 __u64 total_ialloc = 0, total_balloc = 0;
4016 bool human_readable = false;
4019 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4030 if (qctl.qc_type != ALLQUOTA) {
4031 fprintf(stderr, "error: use either -u or -g\n");
4034 qctl.qc_type = qtype;
4037 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4040 valid = qctl.qc_valid = QC_UUID;
4041 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4044 valid = qctl.qc_valid = QC_MDTIDX;
4045 idx = qctl.qc_idx = atoi(optarg);
4048 valid = qctl.qc_valid = QC_OSTIDX;
4049 idx = qctl.qc_idx = atoi(optarg);
4058 human_readable = true;
4061 fprintf(stderr, "error: %s: option '-%c' "
4062 "unrecognized\n", argv[0], c);
4067 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4068 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4069 optind == argc - 1) {
4071 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4072 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4073 qctl.qc_valid = valid;
4075 qctl.qc_type = pass;
4076 switch (qctl.qc_type) {
4078 qctl.qc_id = geteuid();
4079 rc = uid2name(&name, qctl.qc_id);
4082 qctl.qc_id = getegid();
4083 rc = gid2name(&name, qctl.qc_id);
4092 /* lfs quota -u username /path/to/lustre/mount */
4093 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4094 /* options should be followed by u/g-name and mntpoint */
4095 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4096 fprintf(stderr, "error: missing quota argument(s)\n");
4100 name = argv[optind++];
4101 switch (qctl.qc_type) {
4103 rc = name2uid(&qctl.qc_id, name);
4106 rc = name2gid(&qctl.qc_id, name);
4109 rc = name2projid(&qctl.qc_id, name);
4116 qctl.qc_id = strtoul(name, &endptr, 10);
4117 if (*endptr != '\0') {
4118 fprintf(stderr, "error: can't find id for name: %s\n",
4123 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4124 fprintf(stderr, "error: missing quota info argument(s)\n");
4129 rc1 = llapi_quotactl(mnt, &qctl);
4133 fprintf(stderr, "%s quotas are not enabled.\n",
4134 qtype_name(qctl.qc_type));
4137 fprintf(stderr, "Permission denied.\n");
4140 /* We already got error message. */
4143 fprintf(stderr, "Unexpected quotactl error: %s\n",
4148 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4149 print_quota_title(name, &qctl, human_readable);
4151 if (rc1 && *obd_type)
4152 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4154 if (qctl.qc_valid != QC_GENERAL)
4157 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4158 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4159 (QIF_LIMITS|QIF_USAGE));
4161 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4163 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4165 char strbuf[STRBUF_LEN];
4167 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4169 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4171 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4173 printf("Total allocated inode limit: %ju, total "
4174 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4178 if (rc1 || rc2 || rc3 || inacc)
4179 printf("Some errors happened when getting quota info. "
4180 "Some devices may be not working or deactivated. "
4181 "The data in \"[]\" is inaccurate.\n");
4184 if (pass > 0 && pass < LL_MAXQUOTAS)
4189 #endif /* HAVE_SYS_QUOTA_H! */
4191 static int flushctx_ioctl(char *mp)
4195 fd = open(mp, O_RDONLY);
4197 fprintf(stderr, "flushctx: error open %s: %s\n",
4198 mp, strerror(errno));
4202 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4204 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4205 mp, strerror(errno));
4211 static int lfs_flushctx(int argc, char **argv)
4213 int kdestroy = 0, c;
4214 char mntdir[PATH_MAX] = {'\0'};
4218 while ((c = getopt(argc, argv, "k")) != -1) {
4224 fprintf(stderr, "error: %s: option '-%c' "
4225 "unrecognized\n", argv[0], c);
4231 if ((rc = system("kdestroy > /dev/null")) != 0) {
4232 rc = WEXITSTATUS(rc);
4233 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4237 if (optind >= argc) {
4238 /* flush for all mounted lustre fs. */
4239 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4240 /* Check if we have a mount point */
4241 if (mntdir[0] == '\0')
4244 if (flushctx_ioctl(mntdir))
4247 mntdir[0] = '\0'; /* avoid matching in next loop */
4250 /* flush fs as specified */
4251 while (optind < argc) {
4252 if (flushctx_ioctl(argv[optind++]))
4259 static int lfs_cp(int argc, char **argv)
4261 fprintf(stderr, "remote client copy file(s).\n"
4262 "obsolete, does not support it anymore.\n");
4266 static int lfs_ls(int argc, char **argv)
4268 fprintf(stderr, "remote client lists directory contents.\n"
4269 "obsolete, does not support it anymore.\n");
4273 static int lfs_changelog(int argc, char **argv)
4275 void *changelog_priv;
4276 struct changelog_rec *rec;
4277 long long startrec = 0, endrec = 0;
4279 struct option long_opts[] = {
4280 {"follow", no_argument, 0, 'f'},
4283 char short_opts[] = "f";
4286 while ((rc = getopt_long(argc, argv, short_opts,
4287 long_opts, NULL)) != -1) {
4295 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4296 argv[0], argv[optind - 1]);
4303 mdd = argv[optind++];
4305 startrec = strtoll(argv[optind++], NULL, 10);
4307 endrec = strtoll(argv[optind++], NULL, 10);
4309 rc = llapi_changelog_start(&changelog_priv,
4310 CHANGELOG_FLAG_BLOCK |
4311 CHANGELOG_FLAG_JOBID |
4312 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4315 fprintf(stderr, "Can't start changelog: %s\n",
4316 strerror(errno = -rc));
4320 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4324 if (endrec && rec->cr_index > endrec) {
4325 llapi_changelog_free(&rec);
4328 if (rec->cr_index < startrec) {
4329 llapi_changelog_free(&rec);
4333 secs = rec->cr_time >> 30;
4334 gmtime_r(&secs, &ts);
4335 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4336 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4337 changelog_type2str(rec->cr_type),
4338 ts.tm_hour, ts.tm_min, ts.tm_sec,
4339 (int)(rec->cr_time & ((1 << 30) - 1)),
4340 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4341 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4343 if (rec->cr_flags & CLF_JOBID) {
4344 struct changelog_ext_jobid *jid =
4345 changelog_rec_jobid(rec);
4347 if (jid->cr_jobid[0] != '\0')
4348 printf(" j=%s", jid->cr_jobid);
4351 if (rec->cr_namelen)
4352 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4353 rec->cr_namelen, changelog_rec_name(rec));
4355 if (rec->cr_flags & CLF_RENAME) {
4356 struct changelog_ext_rename *rnm =
4357 changelog_rec_rename(rec);
4359 if (!fid_is_zero(&rnm->cr_sfid))
4360 printf(" s="DFID" sp="DFID" %.*s",
4361 PFID(&rnm->cr_sfid),
4362 PFID(&rnm->cr_spfid),
4363 (int)changelog_rec_snamelen(rec),
4364 changelog_rec_sname(rec));
4368 llapi_changelog_free(&rec);
4371 llapi_changelog_fini(&changelog_priv);
4374 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4376 return (rc == 1 ? 0 : rc);
4379 static int lfs_changelog_clear(int argc, char **argv)
4387 endrec = strtoll(argv[3], NULL, 10);
4389 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4392 fprintf(stderr, "%s: record out of range: %llu\n",
4394 else if (rc == -ENOENT)
4395 fprintf(stderr, "%s: no changelog user: %s\n",
4398 fprintf(stderr, "%s error: %s\n", argv[0],
4407 static int lfs_fid2path(int argc, char **argv)
4409 struct option long_opts[] = {
4410 {"cur", no_argument, 0, 'c'},
4411 {"link", required_argument, 0, 'l'},
4412 {"rec", required_argument, 0, 'r'},
4415 char short_opts[] = "cl:r:";
4416 char *device, *fid, *path;
4417 long long recno = -1;
4423 while ((rc = getopt_long(argc, argv, short_opts,
4424 long_opts, NULL)) != -1) {
4430 linkno = strtol(optarg, NULL, 10);
4433 recno = strtoll(optarg, NULL, 10);
4438 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4439 argv[0], argv[optind - 1]);
4447 device = argv[optind++];
4448 path = calloc(1, PATH_MAX);
4450 fprintf(stderr, "error: Not enough memory\n");
4455 while (optind < argc) {
4456 fid = argv[optind++];
4458 lnktmp = (linkno >= 0) ? linkno : 0;
4460 int oldtmp = lnktmp;
4461 long long rectmp = recno;
4463 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4466 fprintf(stderr, "%s: error on FID %s: %s\n",
4467 argv[0], fid, strerror(errno = -rc2));
4474 fprintf(stdout, "%lld ", rectmp);
4475 if (device[0] == '/') {
4476 fprintf(stdout, "%s", device);
4477 if (device[strlen(device) - 1] != '/')
4478 fprintf(stdout, "/");
4479 } else if (path[0] == '\0') {
4480 fprintf(stdout, "/");
4482 fprintf(stdout, "%s\n", path);
4485 /* specified linkno */
4487 if (oldtmp == lnktmp)
4497 static int lfs_path2fid(int argc, char **argv)
4499 struct option long_opts[] = {
4500 {"parents", no_argument, 0, 'p'},
4504 const char short_opts[] = "p";
4505 const char *sep = "";
4508 bool show_parents = false;
4510 while ((rc = getopt_long(argc, argv, short_opts,
4511 long_opts, NULL)) != -1) {
4514 show_parents = true;
4517 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4518 argv[0], argv[optind - 1]);
4523 if (optind > argc - 1)
4525 else if (optind < argc - 1)
4529 for (path = argv + optind; *path != NULL; path++) {
4531 if (!show_parents) {
4532 err = llapi_path2fid(*path, &fid);
4534 printf("%s%s"DFID"\n",
4535 *sep != '\0' ? *path : "", sep,
4538 char name[NAME_MAX + 1];
4539 unsigned int linkno = 0;
4541 while ((err = llapi_path2parent(*path, linkno, &fid,
4542 name, sizeof(name))) == 0) {
4543 if (*sep != '\0' && linkno == 0)
4544 printf("%s%s", *path, sep);
4546 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4551 /* err == -ENODATA is end-of-loop */
4552 if (linkno > 0 && err == -ENODATA) {
4559 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4560 argv[0], show_parents ? "parent " : "", *path,
4572 static int lfs_data_version(int argc, char **argv)
4579 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4584 while ((c = getopt(argc, argv, "nrw")) != -1) {
4587 data_version_flags = 0;
4590 data_version_flags |= LL_DV_RD_FLUSH;
4593 data_version_flags |= LL_DV_WR_FLUSH;
4602 path = argv[optind];
4603 fd = open(path, O_RDONLY);
4605 err(errno, "cannot open file %s", path);
4607 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4609 err(errno, "cannot get version for %s", path);
4611 printf("%ju" "\n", (uintmax_t)data_version);
4617 static int lfs_hsm_state(int argc, char **argv)
4622 struct hsm_user_state hus;
4630 rc = llapi_hsm_state_get(path, &hus);
4632 fprintf(stderr, "can't get hsm state for %s: %s\n",
4633 path, strerror(errno = -rc));
4637 /* Display path name and status flags */
4638 printf("%s: (0x%08x)", path, hus.hus_states);
4640 if (hus.hus_states & HS_RELEASED)
4641 printf(" released");
4642 if (hus.hus_states & HS_EXISTS)
4644 if (hus.hus_states & HS_DIRTY)
4646 if (hus.hus_states & HS_ARCHIVED)
4647 printf(" archived");
4648 /* Display user-settable flags */
4649 if (hus.hus_states & HS_NORELEASE)
4650 printf(" never_release");
4651 if (hus.hus_states & HS_NOARCHIVE)
4652 printf(" never_archive");
4653 if (hus.hus_states & HS_LOST)
4654 printf(" lost_from_hsm");
4656 if (hus.hus_archive_id != 0)
4657 printf(", archive_id:%d", hus.hus_archive_id);
4660 } while (++i < argc);
4665 #define LFS_HSM_SET 0
4666 #define LFS_HSM_CLEAR 1
4669 * Generic function to set or clear HSM flags.
4670 * Used by hsm_set and hsm_clear.
4672 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4674 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4676 struct option long_opts[] = {
4677 {"lost", 0, 0, 'l'},
4678 {"norelease", 0, 0, 'r'},
4679 {"noarchive", 0, 0, 'a'},
4680 {"archived", 0, 0, 'A'},
4681 {"dirty", 0, 0, 'd'},
4682 {"exists", 0, 0, 'e'},
4685 char short_opts[] = "lraAde";
4693 while ((c = getopt_long(argc, argv, short_opts,
4694 long_opts, NULL)) != -1) {
4700 mask |= HS_NOARCHIVE;
4703 mask |= HS_ARCHIVED;
4706 mask |= HS_NORELEASE;
4717 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4718 argv[0], argv[optind - 1]);
4723 /* User should have specified a flag */
4727 while (optind < argc) {
4729 path = argv[optind];
4731 /* If mode == 0, this means we apply the mask. */
4732 if (mode == LFS_HSM_SET)
4733 rc = llapi_hsm_state_set(path, mask, 0, 0);
4735 rc = llapi_hsm_state_set(path, 0, mask, 0);
4738 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4739 path, strerror(errno = -rc));
4748 static int lfs_hsm_action(int argc, char **argv)
4753 struct hsm_current_action hca;
4754 struct hsm_extent he;
4755 enum hsm_user_action hua;
4756 enum hsm_progress_states hps;
4764 rc = llapi_hsm_current_action(path, &hca);
4766 fprintf(stderr, "can't get hsm action for %s: %s\n",
4767 path, strerror(errno = -rc));
4770 he = hca.hca_location;
4771 hua = hca.hca_action;
4772 hps = hca.hca_state;
4774 printf("%s: %s", path, hsm_user_action2name(hua));
4776 /* Skip file without action */
4777 if (hca.hca_action == HUA_NONE) {
4782 printf(" %s ", hsm_progress_state2name(hps));
4784 if ((hps == HPS_RUNNING) &&
4785 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4786 printf("(%llu bytes moved)\n",
4787 (unsigned long long)he.length);
4788 else if ((he.offset + he.length) == LUSTRE_EOF)
4789 printf("(from %llu to EOF)\n",
4790 (unsigned long long)he.offset);
4792 printf("(from %llu to %llu)\n",
4793 (unsigned long long)he.offset,
4794 (unsigned long long)(he.offset + he.length));
4796 } while (++i < argc);
4801 static int lfs_hsm_set(int argc, char **argv)
4803 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4806 static int lfs_hsm_clear(int argc, char **argv)
4808 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4812 * Check file state and return its fid, to be used by lfs_hsm_request().
4814 * \param[in] file Path to file to check
4815 * \param[in,out] fid Pointer to allocated lu_fid struct.
4816 * \param[in,out] last_dev Pointer to last device id used.
4818 * \return 0 on success.
4820 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4826 rc = lstat(file, &st);
4828 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4831 /* Checking for regular file as archiving as posix copytool
4832 * rejects archiving files other than regular files
4834 if (!S_ISREG(st.st_mode)) {
4835 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4838 /* A request should be ... */
4839 if (*last_dev != st.st_dev && *last_dev != 0) {
4840 fprintf(stderr, "All files should be "
4841 "on the same filesystem: %s\n", file);
4844 *last_dev = st.st_dev;
4846 rc = llapi_path2fid(file, fid);
4848 fprintf(stderr, "Cannot read FID of %s: %s\n",
4849 file, strerror(-rc));
4855 /* Fill an HSM HUR item with a given file name.
4857 * If mntpath is set, then the filename is actually a FID, and no
4858 * lookup on the filesystem will be performed.
4860 * \param[in] hur the user request to fill
4861 * \param[in] idx index of the item inside the HUR to fill
4862 * \param[in] mntpath mountpoint of Lustre
4863 * \param[in] fname filename (if mtnpath is NULL)
4864 * or FID (if mntpath is set)
4865 * \param[in] last_dev pointer to last device id used
4867 * \retval 0 on success
4868 * \retval CMD_HELP or a negative errno on error
4870 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4871 const char *mntpath, const char *fname,
4874 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4877 hui->hui_extent.length = -1;
4879 if (mntpath != NULL) {
4882 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4886 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4891 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4895 hur->hur_request.hr_itemcount++;
4900 static int lfs_hsm_request(int argc, char **argv, int action)
4902 struct option long_opts[] = {
4903 {"filelist", 1, 0, 'l'},
4904 {"data", 1, 0, 'D'},
4905 {"archive", 1, 0, 'a'},
4906 {"mntpath", 1, 0, 'm'},
4910 char short_opts[] = "l:D:a:m:";
4911 struct hsm_user_request *hur, *oldhur;
4916 char *filelist = NULL;
4917 char fullpath[PATH_MAX];
4918 char *opaque = NULL;
4922 int nbfile_alloc = 0;
4923 char *some_file = NULL;
4924 char *mntpath = NULL;
4930 while ((c = getopt_long(argc, argv, short_opts,
4931 long_opts, NULL)) != -1) {
4940 if (action != HUA_ARCHIVE &&
4941 action != HUA_REMOVE) {
4943 "error: -a is supported only "
4944 "when archiving or removing\n");
4947 archive_id = atoi(optarg);
4950 if (some_file == NULL) {
4952 some_file = strdup(optarg);
4958 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4959 argv[0], argv[optind - 1]);
4964 /* All remaining args are files, so we have at least nbfile */
4965 nbfile = argc - optind;
4967 if ((nbfile == 0) && (filelist == NULL))
4971 opaque_len = strlen(opaque);
4973 /* Alloc the request structure with enough place to store all files
4974 * from command line. */
4975 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4977 fprintf(stderr, "Cannot create the request: %s\n",
4981 nbfile_alloc = nbfile;
4983 hur->hur_request.hr_action = action;
4984 hur->hur_request.hr_archive_id = archive_id;
4985 hur->hur_request.hr_flags = 0;
4987 /* All remaining args are files, add them */
4988 if (nbfile != 0 && some_file == NULL)
4989 some_file = strdup(argv[optind]);
4991 for (i = 0; i < nbfile; i++) {
4992 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4998 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5000 /* If a filelist was specified, read the filelist from it. */
5001 if (filelist != NULL) {
5002 fp = fopen(filelist, "r");
5004 fprintf(stderr, "Cannot read the file list %s: %s\n",
5005 filelist, strerror(errno));
5010 while ((rc = getline(&line, &len, fp)) != -1) {
5011 /* If allocated buffer was too small, get something
5013 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5016 nbfile_alloc = nbfile_alloc * 2 + 1;
5018 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5021 fprintf(stderr, "hsm: cannot allocate "
5022 "the request: %s\n",
5029 size = hur_len(oldhur);
5031 fprintf(stderr, "hsm: cannot allocate "
5032 "%u files + %u bytes data\n",
5033 oldhur->hur_request.hr_itemcount,
5034 oldhur->hur_request.hr_data_len);
5041 memcpy(hur, oldhur, size);
5046 if (line[strlen(line) - 1] == '\n')
5047 line[strlen(line) - 1] = '\0';
5049 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5050 mntpath, line, &last_dev);
5056 if (some_file == NULL) {
5066 /* If a --data was used, add it to the request */
5067 hur->hur_request.hr_data_len = opaque_len;
5069 memcpy(hur_data(hur), opaque, opaque_len);
5071 /* Send the HSM request */
5072 if (realpath(some_file, fullpath) == NULL) {
5073 fprintf(stderr, "Could not find path '%s': %s\n",
5074 some_file, strerror(errno));
5076 rc = llapi_hsm_request(fullpath, hur);
5078 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5079 some_file, strerror(-rc));
5089 static int lfs_hsm_archive(int argc, char **argv)
5091 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5094 static int lfs_hsm_restore(int argc, char **argv)
5096 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5099 static int lfs_hsm_release(int argc, char **argv)
5101 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5104 static int lfs_hsm_remove(int argc, char **argv)
5106 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5109 static int lfs_hsm_cancel(int argc, char **argv)
5111 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5114 static int lfs_swap_layouts(int argc, char **argv)
5119 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5120 SWAP_LAYOUTS_KEEP_MTIME |
5121 SWAP_LAYOUTS_KEEP_ATIME);
5124 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5126 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5128 enum lu_ladvise_type advice;
5131 advice < ARRAY_SIZE(ladvise_names); advice++) {
5132 if (ladvise_names[advice] == NULL)
5134 if (strcmp(string, ladvise_names[advice]) == 0)
5138 return LU_LADVISE_INVALID;
5141 static int lfs_ladvise(int argc, char **argv)
5143 struct option long_opts[] = {
5144 {"advice", required_argument, 0, 'a'},
5145 {"background", no_argument, 0, 'b'},
5146 {"end", required_argument, 0, 'e'},
5147 {"start", required_argument, 0, 's'},
5148 {"length", required_argument, 0, 'l'},
5151 char short_opts[] = "a:be:l:s:";
5156 struct llapi_lu_ladvise advice;
5157 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5158 unsigned long long start = 0;
5159 unsigned long long end = LUSTRE_EOF;
5160 unsigned long long length = 0;
5161 unsigned long long size_units;
5162 unsigned long long flags = 0;
5165 while ((c = getopt_long(argc, argv, short_opts,
5166 long_opts, NULL)) != -1) {
5169 advice_type = lfs_get_ladvice(optarg);
5170 if (advice_type == LU_LADVISE_INVALID) {
5171 fprintf(stderr, "%s: invalid advice type "
5172 "'%s'\n", argv[0], optarg);
5173 fprintf(stderr, "Valid types:");
5175 for (advice_type = 0;
5176 advice_type < ARRAY_SIZE(ladvise_names);
5178 if (ladvise_names[advice_type] == NULL)
5180 fprintf(stderr, " %s",
5181 ladvise_names[advice_type]);
5183 fprintf(stderr, "\n");
5193 rc = llapi_parse_size(optarg, &end,
5196 fprintf(stderr, "%s: bad end offset '%s'\n",
5203 rc = llapi_parse_size(optarg, &start,
5206 fprintf(stderr, "%s: bad start offset "
5207 "'%s'\n", argv[0], optarg);
5213 rc = llapi_parse_size(optarg, &length,
5216 fprintf(stderr, "%s: bad length '%s'\n",
5224 fprintf(stderr, "%s: option '%s' unrecognized\n",
5225 argv[0], argv[optind - 1]);
5230 if (advice_type == LU_LADVISE_INVALID) {
5231 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5232 fprintf(stderr, "Valid types:");
5233 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5235 if (ladvise_names[advice_type] == NULL)
5237 fprintf(stderr, " %s", ladvise_names[advice_type]);
5239 fprintf(stderr, "\n");
5243 if (argc <= optind) {
5244 fprintf(stderr, "%s: please give one or more file names\n",
5249 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5250 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5255 if (end == LUSTRE_EOF && length != 0)
5256 end = start + length;
5259 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5260 argv[0], start, end);
5264 while (optind < argc) {
5267 path = argv[optind++];
5269 fd = open(path, O_RDONLY);
5271 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5272 argv[0], path, strerror(errno));
5277 advice.lla_start = start;
5278 advice.lla_end = end;
5279 advice.lla_advice = advice_type;
5280 advice.lla_value1 = 0;
5281 advice.lla_value2 = 0;
5282 advice.lla_value3 = 0;
5283 advice.lla_value4 = 0;
5284 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5287 fprintf(stderr, "%s: cannot give advice '%s' to file "
5288 "'%s': %s\n", argv[0],
5289 ladvise_names[advice_type],
5290 path, strerror(errno));
5293 if (rc == 0 && rc2 < 0)
5299 static int lfs_list_commands(int argc, char **argv)
5301 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5303 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5308 int main(int argc, char **argv)
5312 /* Ensure that liblustreapi constructor has run */
5313 if (!liblustreapi_initialized)
5314 fprintf(stderr, "liblustreapi was not properly initialized\n");
5318 Parser_init("lfs > ", cmdlist);
5320 progname = argv[0]; /* Used in error messages */
5322 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5324 rc = Parser_commands();
5327 return rc < 0 ? -rc : rc;
5330 #ifdef _LUSTRE_IDL_H_
5331 /* Everything we need here should be included by lustreapi.h. */
5332 # error "lfs should not depend on lustre_idl.h"
5333 #endif /* _LUSTRE_IDL_H_ */