4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
57 #include <sys/types.h>
64 #include <libcfs/util/string.h>
65 #include <libcfs/util/ioctl.h>
66 #include <libcfs/util/parser.h>
67 #include <lustre/lustreapi.h>
68 #include <lustre_ver.h>
69 #include <linux/lustre_param.h>
72 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
73 #endif /* !ARRAY_SIZE */
76 static int lfs_setstripe(int argc, char **argv);
77 static int lfs_find(int argc, char **argv);
78 static int lfs_getstripe(int argc, char **argv);
79 static int lfs_getdirstripe(int argc, char **argv);
80 static int lfs_setdirstripe(int argc, char **argv);
81 static int lfs_rmentry(int argc, char **argv);
82 static int lfs_osts(int argc, char **argv);
83 static int lfs_mdts(int argc, char **argv);
84 static int lfs_df(int argc, char **argv);
85 static int lfs_getname(int argc, char **argv);
86 static int lfs_check(int argc, char **argv);
87 #ifdef HAVE_SYS_QUOTA_H
88 static int lfs_setquota(int argc, char **argv);
89 static int lfs_quota(int argc, char **argv);
91 static int lfs_flushctx(int argc, char **argv);
92 static int lfs_cp(int argc, char **argv);
93 static int lfs_ls(int argc, char **argv);
94 static int lfs_poollist(int argc, char **argv);
95 static int lfs_changelog(int argc, char **argv);
96 static int lfs_changelog_clear(int argc, char **argv);
97 static int lfs_fid2path(int argc, char **argv);
98 static int lfs_path2fid(int argc, char **argv);
99 static int lfs_data_version(int argc, char **argv);
100 static int lfs_hsm_state(int argc, char **argv);
101 static int lfs_hsm_set(int argc, char **argv);
102 static int lfs_hsm_clear(int argc, char **argv);
103 static int lfs_hsm_action(int argc, char **argv);
104 static int lfs_hsm_archive(int argc, char **argv);
105 static int lfs_hsm_restore(int argc, char **argv);
106 static int lfs_hsm_release(int argc, char **argv);
107 static int lfs_hsm_remove(int argc, char **argv);
108 static int lfs_hsm_cancel(int argc, char **argv);
109 static int lfs_swap_layouts(int argc, char **argv);
110 static int lfs_mv(int argc, char **argv);
111 static int lfs_ladvise(int argc, char **argv);
112 static int lfs_list_commands(int argc, char **argv);
114 /* Setstripe and migrate share mostly the same parameters */
115 #define SSM_CMD_COMMON(cmd) \
116 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
117 " [--stripe-index|-i <start_ost_idx>]\n" \
118 " [--stripe-size|-S <stripe_size>]\n" \
119 " [--pool|-p <pool_name>]\n" \
120 " [--ost|-o <ost_indices>]\n" \
121 " [--component-end|-E <comp_end>]\n"
123 #define SSM_HELP_COMMON \
124 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
125 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
126 "\t respectively)\n" \
127 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
128 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
129 "\tpool_name: Name of OST pool to use (default none)\n" \
130 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
131 "\t Indices be specified in a format of:\n" \
132 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
134 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
135 "\t If --pool is set with --ost, then the OSTs\n" \
136 "\t must be the members of the pool." \
137 "\tcomp_end: Extent end of the component\n" \
138 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
139 "\t respectively, -1 for EOF), it must be aligned with\n"\
140 "\t the stripe_size\n"
142 #define SETSTRIPE_USAGE \
143 SSM_CMD_COMMON("setstripe") \
144 " <directory|filename>\n" \
147 #define MIGRATE_USAGE \
148 SSM_CMD_COMMON("migrate ") \
150 " [--non-block|-n]\n" \
154 "\tblock: Block file access during data migration (default)\n" \
155 "\tnon-block: Abort migrations if concurrent access is detected\n" \
157 #define SETDIRSTRIPE_USAGE \
158 " [--mdt-count|-c stripe_count>\n" \
159 " [--mdt-index|-i mdt_index]\n" \
160 " [--mdt-hash|-H mdt_hash]\n" \
161 " [--default|-D] [--mode|-m mode] <dir>\n" \
162 "\tstripe_count: stripe count of the striped directory\n" \
163 "\tmdt_index: MDT index of first stripe\n" \
164 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
165 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
166 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
167 "\tdefault_stripe: set default dirstripe of the directory\n" \
168 "\tmode: the mode of the directory\n"
170 static const char *progname;
171 static bool file_lease_supported = true;
173 /* all available commands */
174 command_t cmdlist[] = {
175 {"setstripe", lfs_setstripe, 0,
176 "Create a new file with a specific striping pattern or\n"
177 "set the default striping pattern on an existing directory or\n"
178 "delete the default striping pattern from an existing directory or\n"
179 "add layout component(s) to an existing composite file or\n"
180 "delete specified component(s) from an existing composite file\n\n"
181 "To delete default striping from an existing directory:\n"
182 "usage: setstripe -d <directory>\n"
184 "To delete component(s) from an existing composite file:\n"
185 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
186 " [--component-flags|-F <comp_flags>]\n"
188 "\tcomp_id: Unique component ID\n"
189 "\tcomp_flags: 'init' indicating all instantiated components\n"
190 "\t '^init' indicating all uninstantiated components\n"
191 "\t-I and -F can't be specified at the same time\n"
193 "To add component(s) to an existing composite file:\n"
194 SSM_CMD_COMMON("setstripe --component-add")
196 "To create a file with specified striping/composite layout:\n"
198 {"getstripe", lfs_getstripe, 0,
199 "To list the striping info for a given file or files in a\n"
200 "directory or recursively for all files in a directory tree.\n"
201 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
202 " [--stripe-count|-c] [--stripe-index|-i]\n"
203 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
204 " [--mdt|-m] [--recursive|-r] [--raw|-R] [--yaml|-y]\n"
205 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
206 " [--component-id[=comp_id]|-I[comp_id]]\n"
207 " [--component-flags[=comp_flags]]\n"
208 " [--component-count]\n"
209 " [--component-start[=[+-]comp_start]]\n"
210 " [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
211 " <directory|filename> ..."},
212 {"setdirstripe", lfs_setdirstripe, 0,
213 "To create a striped directory on a specified MDT. This can only\n"
214 "be done on MDT0 with the right of administrator.\n"
215 "usage: setdirstripe [OPTION] <directory>\n"
217 {"getdirstripe", lfs_getdirstripe, 0,
218 "To list the striping info for a given directory\n"
219 "or recursively for all directories in a directory tree.\n"
220 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
221 " [--mdt-index|-i] [--mdt-hash|-t]\n"
222 " [--recursive|-r] [--yaml|-y]\n"
223 " [--default|-D] <dir> ..."},
224 {"mkdir", lfs_setdirstripe, 0,
225 "To create a striped directory on a specified MDT. This can only\n"
226 "be done on MDT0 with the right of administrator.\n"
227 "usage: mkdir [OPTION] <directory>\n"
229 {"rm_entry", lfs_rmentry, 0,
230 "To remove the name entry of the remote directory. Note: This\n"
231 "command will only delete the name entry, i.e. the remote directory\n"
232 "will become inaccessable after this command. This can only be done\n"
233 "by the administrator\n"
234 "usage: rm_entry <dir>\n"},
235 {"pool_list", lfs_poollist, 0,
236 "List pools or pool OSTs\n"
237 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
238 {"find", lfs_find, 0,
239 "find files matching given attributes recursively in directory tree.\n"
240 "usage: find <directory|filename> ...\n"
241 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
242 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
243 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
244 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
245 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
246 " [[!] --stripe-count|-c [+-]<stripes>]\n"
247 " [[!] --stripe-index|-i <index,...>]\n"
248 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
249 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
250 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
251 " [[!] --projid <projid>]\n"
252 " [[!] --layout|-L released,raid0]\n"
253 " [[!] --component-count [+-]<comp_cnt>]\n"
254 " [[!] --component-start [+-]N[kMGTPE]]\n"
255 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
256 " [[!] --component-flags <comp_flags>]\n"
257 " [[!] --mdt-count|-T [+-]<stripes>]\n"
258 " [[!] --mdt-hash|-H <hashtype>\n"
259 "\t !: used before an option indicates 'NOT' requested attribute\n"
260 "\t -: used before a value indicates less than requested value\n"
261 "\t +: used before a value indicates more than requested value\n"
262 "\tmdt-hash: hash type of the striped directory.\n"
263 "\t fnv_1a_64 FNV-1a hash algorithm\n"
264 "\t all_char sum of characters % MDT_COUNT\n"},
265 {"check", lfs_check, 0,
266 "Display the status of MDS or OSTs (as specified in the command)\n"
267 "or all the servers (MDS and OSTs).\n"
268 "usage: check <osts|mds|servers>"},
269 {"osts", lfs_osts, 0, "list OSTs connected to client "
270 "[for specified path only]\n" "usage: osts [path]"},
271 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
272 "[for specified path only]\n" "usage: mdts [path]"},
274 "report filesystem disk space usage or inodes usage"
275 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
276 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
277 {"getname", lfs_getname, 0, "list instances and specified mount points "
278 "[for specified path only]\n"
279 "Usage: getname [-h]|[path ...] "},
280 #ifdef HAVE_SYS_QUOTA_H
281 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
282 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
283 " -b <block-softlimit> -B <block-hardlimit>\n"
284 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
285 " setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
286 " [--block-softlimit <block-softlimit>]\n"
287 " [--block-hardlimit <block-hardlimit>]\n"
288 " [--inode-softlimit <inode-softlimit>]\n"
289 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
290 " setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
291 " [--block-grace <block-grace>]\n"
292 " [--inode-grace <inode-grace>] <filesystem>\n"
293 " -b can be used instead of --block-softlimit/--block-grace\n"
294 " -B can be used instead of --block-hardlimit\n"
295 " -i can be used instead of --inode-softlimit/--inode-grace\n"
296 " -I can be used instead of --inode-hardlimit\n\n"
297 "Note: The total quota space will be split into many qunits and\n"
298 " balanced over all server targets, the minimal qunit size is\n"
299 " 1M bytes for block space and 1K inodes for inode space.\n\n"
300 " Quota space rebalancing process will stop when this mininum\n"
301 " value is reached. As a result, quota exceeded can be returned\n"
302 " while many targets still have 1MB or 1K inodes of spare\n"
304 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
305 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
307 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
308 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
310 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
311 "usage: flushctx [-k] [mountpoint...]"},
313 "Remote user copy files and directories.\n"
314 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
316 "Remote user list directory contents.\n"
317 "usage: ls [OPTION]... [FILE]..."},
318 {"changelog", lfs_changelog, 0,
319 "Show the metadata changes on an MDT."
320 "\nusage: changelog <mdtname> [startrec [endrec]]"},
321 {"changelog_clear", lfs_changelog_clear, 0,
322 "Indicate that old changelog records up to <endrec> are no longer of "
323 "interest to consumer <id>, allowing the system to free up space.\n"
324 "An <endrec> of 0 means all records.\n"
325 "usage: changelog_clear <mdtname> <id> <endrec>"},
326 {"fid2path", lfs_fid2path, 0,
327 "Resolve the full path(s) for given FID(s). For a specific hardlink "
328 "specify link number <linkno>.\n"
329 /* "For a historical link name, specify changelog record <recno>.\n" */
330 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
331 /* [ --rec <recno> ] */ },
332 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
333 "usage: path2fid [--parents] <path> ..."},
334 {"data_version", lfs_data_version, 0, "Display file data version for "
335 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
336 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
337 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
338 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
339 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
340 "[--archived] [--lost] <file> ..."},
341 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
343 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
344 "[--archived] [--lost] <file> ..."},
345 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
346 "given files.\n" "usage: hsm_action <file> ..."},
347 {"hsm_archive", lfs_hsm_archive, 0,
348 "Archive file to external storage.\n"
349 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
351 {"hsm_restore", lfs_hsm_restore, 0,
352 "Restore file from external storage.\n"
353 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
354 {"hsm_release", lfs_hsm_release, 0,
355 "Release files from Lustre.\n"
356 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
357 {"hsm_remove", lfs_hsm_remove, 0,
358 "Remove file copy from external storage.\n"
359 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
360 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
362 "Note: To remove files from the archive that have been deleted on\n"
363 "Lustre, set mntpath and optionally archive. In that case, all the\n"
364 "positional arguments and entries in the file list must be FIDs."
366 {"hsm_cancel", lfs_hsm_cancel, 0,
367 "Cancel requests related to specified files.\n"
368 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
369 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
370 "usage: swap_layouts <path1> <path2>"},
371 {"migrate", lfs_setstripe, 0,
372 "migrate a directory between MDTs.\n"
373 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
375 "\tmdt_idx: index of the destination MDT\n"
377 "migrate file objects from one OST "
378 "layout\nto another (may be not safe with concurent writes).\n"
380 "[--stripe-count|-c] <stripe_count>\n"
381 " [--stripe-index|-i] <start_ost_index>\n"
382 " [--stripe-size|-S] <stripe_size>\n"
383 " [--pool|-p] <pool_name>\n"
384 " [--ost-list|-o] <ost_indices>\n"
386 " [--non-block|-n]\n"
387 " <file|directory>\n"
388 "\tstripe_count: number of OSTs to stripe a file over\n"
389 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
390 "\tstripe_size: number of bytes to store before moving to the next OST\n"
391 "\tpool_name: name of the predefined pool of OSTs\n"
392 "\tost_indices: OSTs to stripe over, in order\n"
393 "\tblock: wait for the operation to return before continuing\n"
394 "\tnon-block: do not wait for the operation to return.\n"},
396 "To move directories between MDTs. This command is deprecated, "
397 "use \"migrate\" instead.\n"
398 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
400 {"ladvise", lfs_ladvise, 0,
401 "Provide servers with advice about access patterns for a file.\n"
402 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
403 " [--background|-b]\n"
404 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
406 {"help", Parser_help, 0, "help"},
407 {"exit", Parser_quit, 0, "quit"},
408 {"quit", Parser_quit, 0, "quit"},
409 {"--version", Parser_version, 0,
410 "output build version of the utility and exit"},
411 {"--list-commands", lfs_list_commands, 0,
412 "list commands supported by the utility and exit"},
417 #define MIGRATION_NONBLOCK 1
419 static int check_hashtype(const char *hashtype)
423 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
424 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
431 * Internal helper for migrate_copy_data(). Check lease and report error if
434 * \param[in] fd File descriptor on which to check the lease.
435 * \param[out] lease_broken Set to true if the lease was broken.
436 * \param[in] group_locked Whether a group lock was taken or not.
437 * \param[in] path Name of the file being processed, for error
440 * \retval 0 Migration can keep on going.
441 * \retval -errno Error occurred, abort migration.
443 static int check_lease(int fd, bool *lease_broken, bool group_locked,
448 if (!file_lease_supported)
451 rc = llapi_lease_check(fd);
453 return 0; /* llapi_check_lease returns > 0 on success. */
456 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
458 rc = rc ? rc : -EAGAIN;
460 fprintf(stderr, "%s: external attempt to access file '%s' "
461 "blocked until migration ends.\n", progname, path);
464 *lease_broken = true;
468 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
469 bool group_locked, const char *fname)
478 bool lease_broken = false;
480 /* Use a page-aligned buffer for direct I/O */
481 rc = posix_memalign(&buf, getpagesize(), buf_size);
486 /* read new data only if we have written all
487 * previously read data */
490 rc = check_lease(fd_src, &lease_broken,
491 group_locked, fname);
495 rsize = read(fd_src, buf, buf_size);
498 fprintf(stderr, "%s: %s: read failed: %s\n",
499 progname, fname, strerror(-rc));
509 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
513 "%s: %s: write failed on volatile: %s\n",
514 progname, fname, strerror(-rc));
524 fprintf(stderr, "%s: %s: fsync failed: %s\n",
525 progname, fname, strerror(-rc));
533 static int migrate_copy_timestamps(int fdv, const struct stat *st)
535 struct timeval tv[2] = {
536 {.tv_sec = st->st_atime},
537 {.tv_sec = st->st_mtime}
540 return futimes(fdv, tv);
543 static int migrate_block(int fd, int fdv, const struct stat *st,
544 size_t buf_size, const char *name)
551 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
553 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
554 progname, name, strerror(-rc));
562 /* The grouplock blocks all concurrent accesses to the file.
563 * It has to be taken after llapi_get_data_version as it would
565 rc = llapi_group_lock(fd, gid);
567 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
568 progname, name, strerror(-rc));
572 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
574 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
578 /* Make sure we keep original atime/mtime values */
579 rc = migrate_copy_timestamps(fdv, st);
581 fprintf(stderr, "%s: %s: timestamp copy failed\n",
587 * for a migration we need to check data version on file did
590 * Pass in gid=0 since we already own grouplock. */
591 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
592 SWAP_LAYOUTS_CHECK_DV1);
594 fprintf(stderr, "%s: %s: dataversion changed during copy, "
595 "migration aborted\n", progname, name);
598 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
599 name, strerror(-rc));
604 rc2 = llapi_group_unlock(fd, gid);
605 if (rc2 < 0 && rc == 0) {
606 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
607 progname, name, strerror(-rc2));
614 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
615 size_t buf_size, const char *name)
621 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
623 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
624 progname, name, strerror(-rc));
628 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
630 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
634 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
636 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
637 progname, name, strerror(-rc));
643 fprintf(stderr, "%s: %s: data version changed during "
649 /* Make sure we keep original atime/mtime values */
650 rc = migrate_copy_timestamps(fdv, st);
652 fprintf(stderr, "%s: %s: timestamp copy failed\n",
657 /* Atomically put lease, swap layouts and close.
658 * for a migration we need to check data version on file did
660 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
662 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
663 progname, name, strerror(-rc));
670 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
675 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
679 if (flags != 0 && comp_id != 0)
682 /* LCME_FL_INIT is the only supported flag in PFL */
684 if (flags & ~LCME_KNOWN_FLAGS) {
685 fprintf(stderr, "Invalid component flags %#x\n", flags);
688 } else if (comp_id > LCME_ID_MAX) {
689 fprintf(stderr, "Invalid component id %u\n", comp_id);
693 rc = llapi_layout_file_comp_del(fname, comp_id, flags);
695 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
696 comp_id, fname, strerror(errno));
700 static int lfs_component_add(char *fname, struct llapi_layout *layout)
707 rc = llapi_layout_file_comp_add(fname, layout);
709 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
710 fname, strerror(errno));
714 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
715 struct llapi_layout *layout)
723 fd = lstat(fname, &st);
724 if (fd == 0 && S_ISDIR(st.st_mode))
725 open_flags = O_DIRECTORY | O_RDONLY;
727 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
729 fprintf(stderr, "%s %s failed. %s\n",
730 S_ISDIR(st.st_mode) ?
731 "Set default composite layout to " :
732 "Create composite file",
733 fname, strerror(errno));
737 static int lfs_migrate(char *name, __u64 migration_flags,
738 struct llapi_stripe_param *param,
739 struct llapi_layout *layout)
743 char parent[PATH_MAX];
746 char volatile_file[sizeof(parent) +
747 LUSTRE_VOLATILE_HDR_LEN +
748 2 * sizeof(mdt_index) +
749 2 * sizeof(random_value) + 4];
752 struct lov_user_md *lum = NULL;
754 int buf_size = 1024 * 1024 * 4;
755 bool have_lease_rdlck = false;
759 /* find the right size for the IO and allocate the buffer */
760 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
761 lum = malloc(lum_size);
767 rc = llapi_file_get_stripe(name, lum);
768 /* failure can happen for many reasons and some may be not real errors
770 * in case of a real error, a later call will fail with better
771 * error management */
773 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
774 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
775 lum->lmm_stripe_size != 0)
776 buf_size = lum->lmm_stripe_size;
779 /* open file, direct io */
780 /* even if the file is only read, WR mode is nedeed to allow
781 * layout swap on fd */
782 fd = open(name, O_RDWR | O_DIRECT);
785 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
790 if (file_lease_supported) {
791 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
792 if (rc == -EOPNOTSUPP) {
793 /* Older servers do not support file lease.
794 * Disable related checks. This opens race conditions
795 * as explained in LU-4840 */
796 file_lease_supported = false;
798 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
799 progname, name, strerror(-rc));
802 have_lease_rdlck = true;
806 /* search for file directory pathname */
807 if (strlen(name) > sizeof(parent)-1) {
811 strncpy(parent, name, sizeof(parent));
812 ptr = strrchr(parent, '/');
814 if (getcwd(parent, sizeof(parent)) == NULL) {
825 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
827 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
828 progname, name, strerror(-rc));
833 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
834 mode_t open_mode = S_IRUSR | S_IWUSR;
836 random_value = random();
837 rc = snprintf(volatile_file, sizeof(volatile_file),
838 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
839 mdt_index, random_value);
840 if (rc >= sizeof(volatile_file)) {
845 /* create, open a volatile file, use caching (ie no directio) */
847 fdv = llapi_file_open_param(volatile_file, open_flags,
849 else if (layout != NULL)
850 fdv = lfs_component_create(volatile_file, open_flags,
854 } while (fdv == -EEXIST);
858 fprintf(stderr, "%s: %s: cannot create volatile file in"
860 progname, parent, strerror(-rc));
864 /* In case the MDT does not support creation of volatile files
865 * we should try to unlink it. */
866 (void)unlink(volatile_file);
868 /* Not-owner (root?) special case.
869 * Need to set owner/group of volatile file like original.
870 * This will allow to pass related check during layout_swap.
875 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
879 rc = fstat(fdv, &stv);
882 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
883 volatile_file, strerror(errno));
886 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
887 rc = fchown(fdv, st.st_uid, st.st_gid);
890 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
891 name, strerror(errno));
896 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
897 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
899 have_lease_rdlck = false;
900 fdv = -1; /* The volatile file is closed as we put the
901 * lease in non-blocking mode. */
904 /* Blocking mode (forced if servers do not support file lease).
905 * It is also the default mode, since we cannot distinguish
906 * between a broken lease and a server that does not support
907 * atomic swap/close (LU-6785) */
908 rc = migrate_block(fd, fdv, &st, buf_size, name);
912 if (have_lease_rdlck)
929 * Parse a string containing an OST index list into an array of integers.
931 * The input string contains a comma delimited list of individual
932 * indices and ranges, for example "1,2-4,7". Add the indices into the
933 * \a osts array and remove duplicates.
935 * \param[out] osts array to store indices in
936 * \param[in] size size of \a osts array
937 * \param[in] offset starting index in \a osts
938 * \param[in] arg string containing OST index list
940 * \retval positive number of indices in \a osts
941 * \retval -EINVAL unable to parse \a arg
943 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
947 int slots = size - offset;
955 while (!end_of_loop) {
963 ptr = strchrnul(arg, ',');
965 end_of_loop = *ptr == '\0';
968 start_index = strtol(arg, &endptr, 0);
969 if (endptr == arg) /* no data at all */
971 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
976 end_index = start_index;
977 if (*endptr == '-') {
978 end_index = strtol(endptr + 1, &endptr, 0);
981 if (end_index < start_index)
985 for (i = start_index; i <= end_index && slots > 0; i++) {
988 /* remove duplicate */
989 for (j = 0; j < offset; j++) {
993 if (j == offset) { /* no duplicate */
998 if (slots == 0 && i < end_index)
1006 if (!end_of_loop && ptr != NULL)
1009 return rc < 0 ? rc : nr;
1012 static int verify_pool_name(char *prog_name, char *pool_name)
1016 if (pool_name == NULL)
1019 ptr = strchr(pool_name, '.');
1020 if (ptr != NULL && ptr == pool_name) {
1021 fprintf(stderr, "error: %s: fsname is empty in pool name '%s'\n",
1022 prog_name, pool_name);
1029 struct lfs_setstripe_args {
1030 unsigned long long lsa_comp_end;
1031 unsigned long long lsa_stripe_size;
1032 int lsa_stripe_count;
1034 __u32 lsa_comp_flags;
1037 char *lsa_pool_name;
1040 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1042 memset(lsa, 0, sizeof(*lsa));
1043 lsa->lsa_stripe_off = -1;
1046 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1048 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1049 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1050 lsa->lsa_comp_end != 0);
1053 static int comp_args_to_layout(struct llapi_layout **composite,
1054 struct lfs_setstripe_args *lsa)
1056 struct llapi_layout *layout = *composite;
1057 uint64_t prev_end = 0;
1060 if (layout == NULL) {
1061 layout = llapi_layout_alloc();
1062 if (layout == NULL) {
1063 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1067 *composite = layout;
1071 /* Get current component extent, current component
1072 * must be the tail component. */
1073 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1075 fprintf(stderr, "Get comp extent failed. %s\n",
1080 rc = llapi_layout_comp_add(layout);
1082 fprintf(stderr, "Add component failed. %s\n",
1088 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1090 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1091 prev_end, lsa->lsa_comp_end, strerror(errno));
1095 if (lsa->lsa_stripe_size != 0) {
1096 rc = llapi_layout_stripe_size_set(layout,
1097 lsa->lsa_stripe_size);
1099 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1100 lsa->lsa_stripe_size, strerror(errno));
1105 if (lsa->lsa_stripe_count != 0) {
1106 rc = llapi_layout_stripe_count_set(layout,
1107 lsa->lsa_stripe_count == -1 ?
1109 lsa->lsa_stripe_count);
1111 fprintf(stderr, "Set stripe count %d failed. %s\n",
1112 lsa->lsa_stripe_count, strerror(errno));
1117 if (lsa->lsa_pool_name != NULL) {
1118 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1120 fprintf(stderr, "Set pool name: %s failed. %s\n",
1121 lsa->lsa_pool_name, strerror(errno));
1126 if (lsa->lsa_nr_osts > 0) {
1127 if (lsa->lsa_stripe_count > 0 &&
1128 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1129 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1130 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1133 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1134 rc = llapi_layout_ost_index_set(layout, i,
1139 } else if (lsa->lsa_stripe_off != -1) {
1140 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1143 fprintf(stderr, "Set ost index %d failed. %s\n",
1144 i, strerror(errno));
1151 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1152 * end of the last component in the existing file, and adjust the
1153 * first extent start of the components to be added accordingly. */
1154 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1156 struct llapi_layout *head;
1157 uint64_t start, end, stripe_size, prev_end = 0;
1164 head = llapi_layout_get_by_path(fname, 0);
1166 fprintf(stderr, "Read layout from %s failed. %s\n",
1167 fname, strerror(errno));
1169 } else if (errno == ENODATA) {
1170 /* file without LOVEA, this component-add will be turned
1171 * into a component-create. */
1172 llapi_layout_free(head);
1174 } else if (!llapi_layout_is_composite(head)) {
1175 fprintf(stderr, "'%s' isn't a composite file.\n",
1177 llapi_layout_free(head);
1181 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1183 fprintf(stderr, "Get prev extent failed. %s\n",
1185 llapi_layout_free(head);
1189 llapi_layout_free(head);
1191 /* Make sure we use the first component of the layout to be added. */
1192 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1194 fprintf(stderr, "Move component cursor failed. %s\n",
1199 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1201 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1205 if (start > prev_end || end <= prev_end) {
1206 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1207 "adjacent with the existing file extent end: %lu\n",
1208 start, end, prev_end);
1212 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1214 fprintf(stderr, "Get stripe size failed. %s\n",
1219 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1220 (prev_end & (stripe_size - 1))) {
1221 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1222 stripe_size, prev_end);
1226 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1228 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1229 prev_end, end, strerror(errno));
1236 static inline bool comp_flags_is_neg(__u32 flags)
1238 return flags & LCME_FL_NEG;
1241 static inline void comp_flags_set_neg(__u32 *flags)
1243 *flags |= LCME_FL_NEG;
1246 static inline void comp_flags_clear_neg(__u32 *flags)
1248 *flags &= ~LCME_FL_NEG;
1251 static int comp_str2flags(__u32 *flags, char *string)
1254 __u32 neg_flags = 0;
1260 for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1264 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1265 __u32 comp_flag = comp_flags_table[i].cfn_flag;
1266 const char *comp_name = comp_flags_table[i].cfn_name;
1268 if (strcmp(name, comp_name) == 0) {
1269 *flags |= comp_flag;
1271 } else if (strncmp(name, "^", 1) == 0 &&
1272 strcmp(name + 1, comp_name) == 0) {
1273 neg_flags |= comp_flag;
1278 llapi_printf(LLAPI_MSG_ERROR, "Component flag "
1279 "'%s' is not supported.\n", name);
1284 if (*flags == 0 && neg_flags == 0)
1286 /* don't support mixed flags for now */
1287 if (*flags && neg_flags)
1292 comp_flags_set_neg(flags);
1298 static inline bool arg_is_eof(char *arg)
1300 return !strncmp(arg, "-1", strlen("-1")) ||
1301 !strncmp(arg, "EOF", strlen("EOF")) ||
1302 !strncmp(arg, "eof", strlen("eof"));
1317 static int lfs_setstripe(int argc, char **argv)
1319 struct lfs_setstripe_args lsa;
1320 struct llapi_stripe_param *param = NULL;
1321 struct find_param migrate_mdt_param = {
1331 char *mdt_idx_arg = NULL;
1332 unsigned long long size_units = 1;
1333 bool migrate_mode = false;
1334 bool migration_block = false;
1335 __u64 migration_flags = 0;
1336 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1337 int comp_del = 0, comp_set = 0;
1340 struct llapi_layout *layout = NULL;
1342 struct option long_opts[] = {
1343 /* --block is only valid in migrate mode */
1344 { .val = 'b', .name = "block", .has_arg = no_argument},
1345 { .val = LFS_COMP_ADD_OPT,
1346 .name = "comp-add", .has_arg = no_argument},
1347 { .val = LFS_COMP_ADD_OPT,
1348 .name = "component-add",
1349 .has_arg = no_argument},
1350 { .val = LFS_COMP_DEL_OPT,
1351 .name = "comp-del", .has_arg = no_argument},
1352 { .val = LFS_COMP_DEL_OPT,
1353 .name = "component-del",
1354 .has_arg = no_argument},
1355 { .val = LFS_COMP_FLAGS_OPT,
1356 .name = "comp-flags", .has_arg = required_argument},
1357 { .val = LFS_COMP_FLAGS_OPT,
1358 .name = "component-flags",
1359 .has_arg = required_argument},
1360 { .val = LFS_COMP_SET_OPT,
1361 .name = "comp-set", .has_arg = no_argument},
1362 { .val = LFS_COMP_SET_OPT,
1363 .name = "component-set",
1364 .has_arg = no_argument},
1365 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1366 /* This formerly implied "stripe-count", but was explicitly
1367 * made "stripe-count" for consistency with other options,
1368 * and to separate it from "mdt-count" when DNE arrives. */
1369 { .val = 'c', .name = "count", .has_arg = required_argument },
1371 { .val = 'c', .name = "stripe-count", .has_arg = required_argument},
1372 { .val = 'c', .name = "stripe_count", .has_arg = required_argument},
1373 { .val = 'd', .name = "delete", .has_arg = no_argument},
1374 { .val = 'E', .name = "comp-end", .has_arg = required_argument},
1375 { .val = 'E', .name = "component-end",
1376 .has_arg = required_argument},
1377 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1378 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1379 /* This formerly implied "stripe-index", but was explicitly
1380 * made "stripe-index" for consistency with other options,
1381 * and to separate it from "mdt-index" when DNE arrives. */
1382 { .val = 'i', .name = "index", .has_arg = required_argument },
1384 { .val = 'i', .name = "stripe-index", .has_arg = required_argument},
1385 { .val = 'i', .name = "stripe_index", .has_arg = required_argument},
1386 { .val = 'I', .name = "comp-id", .has_arg = required_argument},
1387 { .val = 'I', .name = "component-id", .has_arg = required_argument},
1388 { .val = 'm', .name = "mdt", .has_arg = required_argument},
1389 { .val = 'm', .name = "mdt-index", .has_arg = required_argument},
1390 { .val = 'm', .name = "mdt_index", .has_arg = required_argument},
1391 /* --non-block is only valid in migrate mode */
1392 { .val = 'n', .name = "non-block", .has_arg = no_argument},
1393 { .val = 'o', .name = "ost", .has_arg = required_argument},
1394 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1395 { .val = 'o', .name = "ost-list", .has_arg = required_argument },
1396 { .val = 'o', .name = "ost_list", .has_arg = required_argument },
1398 { .val = 'p', .name = "pool", .has_arg = required_argument },
1399 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1400 /* This formerly implied "--stripe-size", but was confusing
1401 * with "lfs find --size|-s", which means "file size", so use
1402 * the consistent "--stripe-size|-S" for all commands. */
1403 { .val = 's', .name = "size", .has_arg = required_argument },
1405 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1406 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1407 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1408 /* --verbose is only valid in migrate mode */
1409 { .val = 'v', .name = "verbose", .has_arg = no_argument },
1410 { .val = LFS_COMP_ADD_OPT,
1411 .name = "component-add",
1412 .has_arg = no_argument },
1413 { .val = LFS_COMP_DEL_OPT,
1414 .name = "component-del",
1415 .has_arg = no_argument },
1416 { .val = LFS_COMP_FLAGS_OPT,
1417 .name = "component-flags",
1418 .has_arg = required_argument },
1419 { .val = LFS_COMP_SET_OPT,
1420 .name = "component-set",
1421 .has_arg = no_argument },
1424 setstripe_args_init(&lsa);
1426 if (strcmp(argv[0], "migrate") == 0)
1427 migrate_mode = true;
1429 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1430 long_opts, NULL)) >= 0) {
1435 case LFS_COMP_ADD_OPT:
1438 case LFS_COMP_DEL_OPT:
1441 case LFS_COMP_FLAGS_OPT:
1442 result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
1444 fprintf(stderr, "error: %s: bad comp flags "
1445 "'%s'\n", argv[0], optarg);
1449 case LFS_COMP_SET_OPT:
1453 if (!migrate_mode) {
1454 fprintf(stderr, "--block is valid only for"
1458 migration_block = true;
1461 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1462 if (strcmp(argv[optind - 1], "--count") == 0)
1463 fprintf(stderr, "warning: '--count' deprecated"
1464 ", use '--stripe-count' instead\n");
1466 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1468 fprintf(stderr, "error: %s: bad stripe count "
1469 "'%s'\n", argv[0], optarg);
1474 /* delete the default striping pattern */
1478 if (lsa.lsa_comp_end != 0) {
1479 result = comp_args_to_layout(&layout, &lsa);
1483 setstripe_args_init(&lsa);
1486 if (arg_is_eof(optarg)) {
1487 lsa.lsa_comp_end = LUSTRE_EOF;
1489 result = llapi_parse_size(optarg,
1493 fprintf(stderr, "error: %s: "
1494 "bad component end '%s'\n",
1501 if (strcmp(argv[optind - 1], "--index") == 0)
1502 fprintf(stderr, "warning: '--index' deprecated"
1503 ", use '--stripe-index' instead\n");
1504 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1506 fprintf(stderr, "error: %s: bad stripe offset "
1507 "'%s'\n", argv[0], optarg);
1512 comp_id = strtoul(optarg, &end, 0);
1513 if (*end != '\0' || comp_id == 0 ||
1514 comp_id > LCME_ID_MAX) {
1515 fprintf(stderr, "error: %s: bad comp ID "
1516 "'%s'\n", argv[0], optarg);
1521 if (!migrate_mode) {
1522 fprintf(stderr, "--mdt-index is valid only for"
1526 mdt_idx_arg = optarg;
1529 if (!migrate_mode) {
1530 fprintf(stderr, "--non-block is valid only for"
1534 migration_flags |= MIGRATION_NONBLOCK;
1537 lsa.lsa_nr_osts = parse_targets(osts,
1538 sizeof(osts) / sizeof(__u32),
1539 lsa.lsa_nr_osts, optarg);
1540 if (lsa.lsa_nr_osts < 0) {
1542 "error: %s: bad OST indices '%s'\n",
1547 lsa.lsa_osts = osts;
1548 if (lsa.lsa_stripe_off == -1)
1549 lsa.lsa_stripe_off = osts[0];
1552 result = verify_pool_name(argv[0], optarg);
1555 lsa.lsa_pool_name = optarg;
1557 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1559 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1560 fprintf(stderr, "warning: '--size|-s' deprecated, "
1561 "use '--stripe-size|-S' instead\n");
1563 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1565 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1568 fprintf(stderr, "error: %s: bad stripe size "
1569 "'%s'\n", argv[0], optarg);
1574 if (!migrate_mode) {
1575 fprintf(stderr, "--verbose is valid only for"
1579 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1586 fname = argv[optind];
1588 if (lsa.lsa_comp_end != 0) {
1589 result = comp_args_to_layout(&layout, &lsa);
1594 if (optind == argc) {
1595 fprintf(stderr, "error: %s: missing filename|dirname\n",
1600 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1601 * altered by user space tool, so we don't need to support the
1602 * --component-set for this moment. */
1603 if (comp_set != 0) {
1604 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1609 if ((delete + comp_set + comp_del + comp_add) > 1) {
1610 fprintf(stderr, "error: %s: can't specify --component-set, "
1611 "--component-del, --component-add or -d together\n",
1616 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1617 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1618 fprintf(stderr, "error: %s: can't specify -d with "
1619 "-s, -c, -o, -p, -I, -F or -E options\n",
1624 if ((comp_set || comp_del) &&
1625 (setstripe_args_specified(&lsa) || layout != NULL)) {
1626 fprintf(stderr, "error: %s: can't specify --component-del or "
1627 "--component-set with -s, -c, -o, -p or -E options.\n",
1632 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1633 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1634 "--component-del option.\n", argv[0]);
1638 if (comp_add || comp_del) {
1641 result = lstat(fname, &st);
1642 if (result == 0 && S_ISDIR(st.st_mode)) {
1643 fprintf(stderr, "error: %s: can't use --component-add "
1644 "or --component-del for directory.\n",
1651 if (layout == NULL) {
1652 fprintf(stderr, "error: %s: -E option must be present"
1653 "in --component-add mode.\n", argv[0]);
1656 result = adjust_first_extent(fname, layout);
1657 if (result == -ENODATA)
1659 else if (result != 0)
1663 if (mdt_idx_arg != NULL && optind > 3) {
1664 fprintf(stderr, "error: %s: cannot specify -m with other "
1665 "options\n", argv[0]);
1669 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1671 "error: %s: cannot specify --non-block and --block\n",
1676 if (!comp_del && !comp_set && comp_id != 0) {
1677 fprintf(stderr, "error: %s: -I can only be used with "
1678 "--component-del.\n", argv[0]);
1682 if (mdt_idx_arg != NULL) {
1683 /* initialize migrate mdt parameters */
1684 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1686 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1687 argv[0], mdt_idx_arg);
1690 migrate_mdt_param.fp_migrate = 1;
1691 } else if (layout == NULL) {
1692 /* initialize stripe parameters */
1693 param = calloc(1, offsetof(typeof(*param),
1694 lsp_osts[lsa.lsa_nr_osts]));
1695 if (param == NULL) {
1696 fprintf(stderr, "error: %s: %s\n", argv[0],
1701 param->lsp_stripe_size = lsa.lsa_stripe_size;
1702 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1703 param->lsp_stripe_count = lsa.lsa_stripe_count;
1704 param->lsp_stripe_pattern = 0;
1705 param->lsp_pool = lsa.lsa_pool_name;
1706 param->lsp_is_specific = false;
1707 if (lsa.lsa_nr_osts > 0) {
1708 if (lsa.lsa_stripe_count > 0 &&
1709 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1710 fprintf(stderr, "error: %s: stripe count '%d' "
1711 "doesn't match the number of OSTs: %d\n"
1712 , argv[0], lsa.lsa_stripe_count,
1718 param->lsp_is_specific = true;
1719 param->lsp_stripe_count = lsa.lsa_nr_osts;
1720 memcpy(param->lsp_osts, osts,
1721 sizeof(*osts) * lsa.lsa_nr_osts);
1725 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1727 if (mdt_idx_arg != NULL) {
1728 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1729 op = "migrate mdt objects of";
1730 } else if (migrate_mode) {
1731 result = lfs_migrate(fname, migration_flags, param,
1733 op = "migrate ost objects of";
1734 } else if (comp_set != 0) {
1735 result = lfs_component_set(fname, comp_id,
1736 lsa.lsa_comp_flags);
1737 op = "modify component flags of";
1738 } else if (comp_del != 0) {
1739 result = lfs_component_del(fname, comp_id,
1740 lsa.lsa_comp_flags);
1741 op = "delete component of";
1742 } else if (comp_add != 0) {
1743 result = lfs_component_add(fname, layout);
1744 op = "add component to";
1745 } else if (layout != NULL) {
1746 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1752 op = "create composite";
1754 result = llapi_file_open_param(fname,
1761 op = "create striped";
1764 /* Save the first error encountered. */
1767 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1769 lsa.lsa_pool_name != NULL && result == EINVAL ?
1770 "OST not in pool?" : strerror(errno));
1776 llapi_layout_free(layout);
1779 llapi_layout_free(layout);
1783 static int lfs_poollist(int argc, char **argv)
1788 return llapi_poollist(argv[1]);
1791 static int set_time(time_t *time, time_t *set, char *str)
1798 else if (str[0] == '-')
1804 t = strtol(str, NULL, 0);
1805 if (*time < t * 24 * 60 * 60) {
1808 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1812 *set = *time - t * 24 * 60 * 60;
1815 static int name2uid(unsigned int *id, const char *name)
1817 struct passwd *passwd;
1819 passwd = getpwnam(name);
1822 *id = passwd->pw_uid;
1827 static int name2gid(unsigned int *id, const char *name)
1829 struct group *group;
1831 group = getgrnam(name);
1834 *id = group->gr_gid;
1839 static inline int name2projid(unsigned int *id, const char *name)
1844 static int uid2name(char **name, unsigned int id)
1846 struct passwd *passwd;
1848 passwd = getpwuid(id);
1851 *name = passwd->pw_name;
1856 static inline int gid2name(char **name, unsigned int id)
1858 struct group *group;
1860 group = getgrgid(id);
1863 *name = group->gr_name;
1868 static int name2layout(__u32 *layout, char *name)
1873 for (ptr = name; ; ptr = NULL) {
1874 lyt = strtok(ptr, ",");
1877 if (strcmp(lyt, "released") == 0)
1878 *layout |= LOV_PATTERN_F_RELEASED;
1879 else if (strcmp(lyt, "raid0") == 0)
1880 *layout |= LOV_PATTERN_RAID0;
1887 static int lfs_find(int argc, char **argv)
1892 struct find_param param = {
1896 struct option long_opts[] = {
1897 { .val = 'A', .name = "atime", .has_arg = required_argument },
1898 { .val = LFS_COMP_COUNT_OPT,
1899 .name = "comp-count", .has_arg = required_argument },
1900 { .val = LFS_COMP_COUNT_OPT,
1901 .name = "component-count",
1902 .has_arg = required_argument },
1903 { .val = LFS_COMP_FLAGS_OPT,
1904 .name = "comp-flags", .has_arg = required_argument },
1905 { .val = LFS_COMP_FLAGS_OPT,
1906 .name = "component-flags",
1907 .has_arg = required_argument },
1908 { .val = LFS_COMP_START_OPT,
1909 .name = "comp-start", .has_arg = required_argument },
1910 { .val = LFS_COMP_START_OPT,
1911 .name = "component-start",
1912 .has_arg = required_argument },
1913 { .val = 'c', .name = "stripe-count", .has_arg = required_argument },
1914 { .val = 'c', .name = "stripe_count", .has_arg = required_argument },
1915 { .val = 'C', .name = "ctime", .has_arg = required_argument },
1916 { .val = 'D', .name = "maxdepth", .has_arg = required_argument },
1917 { .val = 'E', .name = "comp-end", .has_arg = required_argument },
1918 { .val = 'E', .name = "component-end",
1919 .has_arg = required_argument },
1920 { .val = 'g', .name = "gid", .has_arg = required_argument },
1921 { .val = 'G', .name = "group", .has_arg = required_argument },
1922 { .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
1923 { .val = 'i', .name = "stripe-index", .has_arg = required_argument },
1924 { .val = 'i', .name = "stripe_index", .has_arg = required_argument },
1925 /*{"component-id", required_argument, 0, 'I'},*/
1926 { .val = 'L', .name = "layout", .has_arg = required_argument },
1927 { .val = 'm', .name = "mdt", .has_arg = required_argument },
1928 { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
1929 { .val = 'm', .name = "mdt_index", .has_arg = required_argument },
1930 { .val = 'M', .name = "mtime", .has_arg = required_argument },
1931 { .val = 'n', .name = "name", .has_arg = required_argument },
1932 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1933 { .val = 'O', .name = "obd", .has_arg = required_argument },
1934 { .val = 'O', .name = "ost", .has_arg = required_argument },
1935 /* no short option for pool, p/P already used */
1936 { .val = LFS_POOL_OPT,
1937 .name = "pool", .has_arg = required_argument },
1938 { .val = 'p', .name = "print0", .has_arg = no_argument },
1939 { .val = 'P', .name = "print", .has_arg = no_argument },
1940 { .val = LFS_PROJID_OPT,
1941 .name = "projid", .has_arg = required_argument },
1942 { .val = 's', .name = "size", .has_arg = required_argument },
1943 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1944 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1945 { .val = 't', .name = "type", .has_arg = required_argument },
1946 { .val = 'T', .name = "mdt-count", .has_arg = required_argument },
1947 { .val = 'u', .name = "uid", .has_arg = required_argument },
1948 { .val = 'U', .name = "user", .has_arg = required_argument },
1960 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1961 while ((c = getopt_long_only(argc, argv,
1962 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1963 long_opts, NULL)) >= 0) {
1968 /* '!' is part of option */
1969 /* when getopt_long_only() finds a string which is not
1970 * an option nor a known option argument it returns 1
1971 * in that case if we already have found pathstart and pathend
1972 * (i.e. we have the list of pathnames),
1973 * the only supported value is "!"
1975 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1976 if (!isoption && pathend != -1) {
1977 fprintf(stderr, "err: %s: filename|dirname must either "
1978 "precede options or follow options\n",
1983 if (!isoption && pathstart == -1)
1984 pathstart = optind - 1;
1985 if (isoption && pathstart != -1 && pathend == -1)
1986 pathend = optind - 2;
1992 /* unknown; opt is "!" or path component,
1993 * checking done above.
1995 if (strcmp(optarg, "!") == 0)
1999 xtime = ¶m.fp_atime;
2000 xsign = ¶m.fp_asign;
2001 param.fp_exclude_atime = !!neg_opt;
2002 /* no break, this falls through to 'C' for ctime */
2005 xtime = ¶m.fp_ctime;
2006 xsign = ¶m.fp_csign;
2007 param.fp_exclude_ctime = !!neg_opt;
2009 /* no break, this falls through to 'M' for mtime */
2012 xtime = ¶m.fp_mtime;
2013 xsign = ¶m.fp_msign;
2014 param.fp_exclude_mtime = !!neg_opt;
2016 rc = set_time(&t, xtime, optarg);
2017 if (rc == INT_MAX) {
2024 case LFS_COMP_COUNT_OPT:
2025 if (optarg[0] == '+') {
2026 param.fp_comp_count_sign = -1;
2028 } else if (optarg[0] == '-') {
2029 param.fp_comp_count_sign = 1;
2033 param.fp_comp_count = strtoul(optarg, &endptr, 0);
2034 if (*endptr != '\0') {
2035 fprintf(stderr, "error: bad component count "
2039 param.fp_check_comp_count = 1;
2040 param.fp_exclude_comp_count = !!neg_opt;
2042 case LFS_COMP_FLAGS_OPT:
2043 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
2044 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2045 fprintf(stderr, "error: bad component flags "
2049 param.fp_check_comp_flags = 1;
2050 param.fp_exclude_comp_flags = !!neg_opt;
2052 case LFS_COMP_START_OPT:
2053 if (optarg[0] == '+') {
2054 param.fp_comp_start_sign = -1;
2056 } else if (optarg[0] == '-') {
2057 param.fp_comp_start_sign = 1;
2061 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2062 ¶m.fp_comp_start_units, 0);
2064 fprintf(stderr, "error: bad component start "
2068 param.fp_check_comp_start = 1;
2069 param.fp_exclude_comp_start = !!neg_opt;
2072 if (optarg[0] == '+') {
2073 param.fp_stripe_count_sign = -1;
2075 } else if (optarg[0] == '-') {
2076 param.fp_stripe_count_sign = 1;
2080 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2081 if (*endptr != '\0') {
2082 fprintf(stderr,"error: bad stripe_count '%s'\n",
2087 param.fp_check_stripe_count = 1;
2088 param.fp_exclude_stripe_count = !!neg_opt;
2091 param.fp_max_depth = strtol(optarg, 0, 0);
2094 if (optarg[0] == '+') {
2095 param.fp_comp_end_sign = -1;
2097 } else if (optarg[0] == '-') {
2098 param.fp_comp_end_sign = 1;
2102 if (arg_is_eof(optarg)) {
2103 param.fp_comp_end = LUSTRE_EOF;
2104 param.fp_comp_end_units = 1;
2107 rc = llapi_parse_size(optarg,
2109 ¶m.fp_comp_end_units, 0);
2112 fprintf(stderr, "error: bad component end "
2116 param.fp_check_comp_end = 1;
2117 param.fp_exclude_comp_end = !!neg_opt;
2121 rc = name2gid(¶m.fp_gid, optarg);
2123 param.fp_gid = strtoul(optarg, &endptr, 10);
2124 if (*endptr != '\0') {
2125 fprintf(stderr, "Group/GID: %s cannot "
2126 "be found.\n", optarg);
2131 param.fp_exclude_gid = !!neg_opt;
2132 param.fp_check_gid = 1;
2135 param.fp_hash_type = check_hashtype(optarg);
2136 if (param.fp_hash_type == 0) {
2137 fprintf(stderr, "error: bad hash_type '%s'\n",
2142 param.fp_check_hash_type = 1;
2143 param.fp_exclude_hash_type = !!neg_opt;
2146 ret = name2layout(¶m.fp_layout, optarg);
2149 param.fp_exclude_layout = !!neg_opt;
2150 param.fp_check_layout = 1;
2154 rc = name2uid(¶m.fp_uid, optarg);
2156 param.fp_uid = strtoul(optarg, &endptr, 10);
2157 if (*endptr != '\0') {
2158 fprintf(stderr, "User/UID: %s cannot "
2159 "be found.\n", optarg);
2164 param.fp_exclude_uid = !!neg_opt;
2165 param.fp_check_uid = 1;
2168 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2170 "Pool name %s is too long"
2171 " (max is %d)\n", optarg,
2176 /* we do check for empty pool because empty pool
2177 * is used to find V1 lov attributes */
2178 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2179 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2180 param.fp_exclude_pool = !!neg_opt;
2181 param.fp_check_pool = 1;
2184 param.fp_pattern = (char *)optarg;
2185 param.fp_exclude_pattern = !!neg_opt;
2190 char *buf, *token, *next, *p;
2194 buf = strdup(optarg);
2200 param.fp_exclude_obd = !!neg_opt;
2203 while (token && *token) {
2204 token = strchr(token, ',');
2211 param.fp_exclude_mdt = !!neg_opt;
2212 param.fp_num_alloc_mdts += len;
2213 tmp = realloc(param.fp_mdt_uuid,
2214 param.fp_num_alloc_mdts *
2215 sizeof(*param.fp_mdt_uuid));
2221 param.fp_mdt_uuid = tmp;
2223 param.fp_exclude_obd = !!neg_opt;
2224 param.fp_num_alloc_obds += len;
2225 tmp = realloc(param.fp_obd_uuid,
2226 param.fp_num_alloc_obds *
2227 sizeof(*param.fp_obd_uuid));
2233 param.fp_obd_uuid = tmp;
2235 for (token = buf; token && *token; token = next) {
2236 struct obd_uuid *puuid;
2239 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2242 ¶m.fp_obd_uuid[param.fp_num_obds++];
2244 p = strchr(token, ',');
2251 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2256 strncpy(puuid->uuid, token,
2257 sizeof(puuid->uuid));
2265 param.fp_zero_end = 1;
2269 case LFS_PROJID_OPT:
2270 rc = name2projid(¶m.fp_projid, optarg);
2272 param.fp_projid = strtoul(optarg, &endptr, 10);
2273 if (*endptr != '\0') {
2275 "Invalid project ID: %s",
2281 param.fp_exclude_projid = !!neg_opt;
2282 param.fp_check_projid = 1;
2285 if (optarg[0] == '+') {
2286 param.fp_size_sign = -1;
2288 } else if (optarg[0] == '-') {
2289 param.fp_size_sign = 1;
2293 ret = llapi_parse_size(optarg, ¶m.fp_size,
2294 ¶m.fp_size_units, 0);
2296 fprintf(stderr, "error: bad file size '%s'\n",
2300 param.fp_check_size = 1;
2301 param.fp_exclude_size = !!neg_opt;
2304 if (optarg[0] == '+') {
2305 param.fp_stripe_size_sign = -1;
2307 } else if (optarg[0] == '-') {
2308 param.fp_stripe_size_sign = 1;
2312 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2313 ¶m.fp_stripe_size_units, 0);
2315 fprintf(stderr, "error: bad stripe_size '%s'\n",
2319 param.fp_check_stripe_size = 1;
2320 param.fp_exclude_stripe_size = !!neg_opt;
2323 param.fp_exclude_type = !!neg_opt;
2324 switch (optarg[0]) {
2326 param.fp_type = S_IFBLK;
2329 param.fp_type = S_IFCHR;
2332 param.fp_type = S_IFDIR;
2335 param.fp_type = S_IFREG;
2338 param.fp_type = S_IFLNK;
2341 param.fp_type = S_IFIFO;
2344 param.fp_type = S_IFSOCK;
2347 fprintf(stderr, "error: %s: bad type '%s'\n",
2354 if (optarg[0] == '+') {
2355 param.fp_mdt_count_sign = -1;
2357 } else if (optarg[0] == '-') {
2358 param.fp_mdt_count_sign = 1;
2362 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2363 if (*endptr != '\0') {
2364 fprintf(stderr, "error: bad mdt_count '%s'\n",
2369 param.fp_check_mdt_count = 1;
2370 param.fp_exclude_mdt_count = !!neg_opt;
2378 if (pathstart == -1) {
2379 fprintf(stderr, "error: %s: no filename|pathname\n",
2383 } else if (pathend == -1) {
2389 rc = llapi_find(argv[pathstart], ¶m);
2390 if (rc != 0 && ret == 0)
2392 } while (++pathstart < pathend);
2395 fprintf(stderr, "error: %s failed for %s.\n",
2396 argv[0], argv[optind - 1]);
2398 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2399 free(param.fp_obd_uuid);
2401 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2402 free(param.fp_mdt_uuid);
2407 static int lfs_getstripe_internal(int argc, char **argv,
2408 struct find_param *param)
2410 struct option long_opts[] = {
2411 { .val = LFS_COMP_COUNT_OPT,
2412 .name = "comp-count", .has_arg = no_argument },
2413 { .val = LFS_COMP_COUNT_OPT,
2414 .name = "component-count", .has_arg = no_argument },
2415 { .val = LFS_COMP_FLAGS_OPT,
2416 .name = "comp-flags", .has_arg = optional_argument },
2417 { .val = LFS_COMP_FLAGS_OPT,
2418 .name = "component-flags", .has_arg = optional_argument },
2419 { .val = LFS_COMP_START_OPT,
2420 .name = "comp-start", .has_arg = optional_argument },
2421 { .val = LFS_COMP_START_OPT,
2422 .name = "component-start", .has_arg = optional_argument },
2423 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2424 /* This formerly implied "stripe-count", but was explicitly
2425 * made "stripe-count" for consistency with other options,
2426 * and to separate it from "mdt-count" when DNE arrives. */
2427 { .val = 'c', .name = "count", .has_arg = no_argument },
2429 { .val = 'c', .name = "stripe-count", .has_arg = no_argument },
2430 { .val = 'c', .name = "stripe_count", .has_arg = no_argument },
2431 { .val = 'd', .name = "directory", .has_arg = no_argument },
2432 { .val = 'D', .name = "default", .has_arg = no_argument },
2433 { .val = 'E', .name = "comp-end", .has_arg = optional_argument },
2434 { .val = 'E', .name = "component-end",
2435 .has_arg = optional_argument },
2436 { .val = 'F', .name = "fid", .has_arg = no_argument },
2437 { .val = 'g', .name = "generation", .has_arg = no_argument },
2438 /* dirstripe { .val = 'H', .name = "mdt-hash",
2439 * .has_arg = required_argument }, */
2440 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2441 /* This formerly implied "stripe-index", but was explicitly
2442 * made "stripe-index" for consistency with other options,
2443 * and to separate it from "mdt-index" when DNE arrives. */
2444 { .val = 'i', .name = "index", .has_arg = no_argument },
2446 { .val = 'i', .name = "stripe-index", .has_arg = no_argument },
2447 { .val = 'i', .name = "stripe_index", .has_arg = no_argument },
2448 { .val = 'I', .name = "comp-id", .has_arg = optional_argument },
2449 { .val = 'I', .name = "component-id", .has_arg = optional_argument },
2450 { .val = 'L', .name = "layout", .has_arg = no_argument },
2451 { .val = 'm', .name = "mdt", .has_arg = no_argument },
2452 { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
2453 { .val = 'm', .name = "mdt_index", .has_arg = no_argument },
2454 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2455 { .val = 'M', .name = "mdt-index", .has_arg = no_argument },
2456 { .val = 'M', .name = "mdt_index", .has_arg = no_argument },
2458 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2459 /* This formerly implied "stripe-index", but was confusing
2460 * with "file offset" (which will eventually be needed for
2461 * with different layouts by offset), so deprecate it. */
2462 { .val = 'o', .name = "offset", .has_arg = no_argument },
2464 { .val = 'O', .name = "obd", .has_arg = required_argument },
2465 { .val = 'O', .name = "ost", .has_arg = required_argument },
2466 { .val = 'p', .name = "pool", .has_arg = no_argument },
2467 { .val = 'q', .name = "quiet", .has_arg = no_argument },
2468 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2469 { .val = 'R', .name = "raw", .has_arg = no_argument },
2470 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2471 /* This formerly implied "--stripe-size", but was confusing
2472 * with "lfs find --size|-s", which means "file size", so use
2473 * the consistent "--stripe-size|-S" for all commands. */
2474 { .val = 's', .name = "size", .has_arg = no_argument },
2476 { .val = 'S', .name = "stripe-size", .has_arg = no_argument },
2477 { .val = 'S', .name = "stripe_size", .has_arg = no_argument },
2478 /* dirstripe { .val = 'T', .name = "mdt-count",
2479 * .has_arg = required_argument }, */
2480 { .val = 'v', .name = "verbose", .has_arg = no_argument },
2481 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2486 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2487 long_opts, NULL)) != -1) {
2490 if (strcmp(argv[optind - 1], "--count") == 0)
2491 fprintf(stderr, "warning: '--count' deprecated,"
2492 " use '--stripe-count' instead\n");
2493 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2494 param->fp_verbose |= VERBOSE_COUNT;
2495 param->fp_max_depth = 0;
2498 case LFS_COMP_COUNT_OPT:
2499 param->fp_verbose |= VERBOSE_COMP_COUNT;
2500 param->fp_max_depth = 0;
2502 case LFS_COMP_FLAGS_OPT:
2503 if (optarg != NULL) {
2504 __u32 *flags = ¶m->fp_comp_flags;
2505 rc = comp_str2flags(flags, optarg);
2507 fprintf(stderr, "error: %s bad "
2508 "component flags '%s'.\n",
2512 param->fp_check_comp_flags = 1;
2513 param->fp_exclude_comp_flags =
2514 comp_flags_is_neg(*flags);
2515 comp_flags_clear_neg(flags);
2518 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2519 param->fp_max_depth = 0;
2522 case LFS_COMP_START_OPT:
2523 if (optarg != NULL) {
2525 if (tmp[0] == '+') {
2526 param->fp_comp_start_sign = -1;
2528 } else if (tmp[0] == '-') {
2529 param->fp_comp_start_sign = 1;
2532 rc = llapi_parse_size(tmp,
2533 ¶m->fp_comp_start,
2534 ¶m->fp_comp_start_units, 0);
2536 fprintf(stderr, "error: %s bad "
2537 "component start '%s'.\n",
2541 param->fp_check_comp_start = 1;
2544 param->fp_verbose |= VERBOSE_COMP_START;
2545 param->fp_max_depth = 0;
2549 param->fp_max_depth = 0;
2552 param->fp_get_default_lmv = 1;
2555 if (optarg != NULL) {
2557 if (tmp[0] == '+') {
2558 param->fp_comp_end_sign = -1;
2560 } else if (tmp[0] == '-') {
2561 param->fp_comp_end_sign = 1;
2565 if (arg_is_eof(tmp)) {
2566 param->fp_comp_end = LUSTRE_EOF;
2567 param->fp_comp_end_units = 1;
2570 rc = llapi_parse_size(tmp,
2571 ¶m->fp_comp_end,
2572 ¶m->fp_comp_end_units, 0);
2575 fprintf(stderr, "error: %s bad "
2576 "component end '%s'.\n",
2580 param->fp_check_comp_end = 1;
2582 param->fp_verbose |= VERBOSE_COMP_END;
2583 param->fp_max_depth = 0;
2587 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2588 param->fp_verbose |= VERBOSE_DFID;
2589 param->fp_max_depth = 0;
2593 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2594 param->fp_verbose |= VERBOSE_GENERATION;
2595 param->fp_max_depth = 0;
2598 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2600 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2601 "use '--stripe-index|-i' instead\n");
2604 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2605 if (strcmp(argv[optind - 1], "--index") == 0)
2606 fprintf(stderr, "warning: '--index' deprecated"
2607 ", use '--stripe-index' instead\n");
2609 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2610 param->fp_verbose |= VERBOSE_OFFSET;
2611 param->fp_max_depth = 0;
2615 if (optarg != NULL) {
2616 param->fp_comp_id = strtoul(optarg, &end, 0);
2617 if (*end != '\0' || param->fp_comp_id == 0 ||
2618 param->fp_comp_id > LCME_ID_MAX) {
2619 fprintf(stderr, "error: %s bad "
2620 "component id '%s'\n",
2624 param->fp_check_comp_id = 1;
2627 param->fp_max_depth = 0;
2628 param->fp_verbose |= VERBOSE_COMP_ID;
2632 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2633 param->fp_verbose |= VERBOSE_LAYOUT;
2634 param->fp_max_depth = 0;
2637 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2639 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2640 fprintf(stderr, "warning: '-M' deprecated"
2641 ", use '-m' instead\n");
2645 if (!(param->fp_verbose & VERBOSE_DETAIL))
2646 param->fp_max_depth = 0;
2647 param->fp_verbose |= VERBOSE_MDTINDEX;
2650 if (param->fp_obd_uuid) {
2652 "error: %s: only one obduuid allowed",
2656 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2659 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2660 param->fp_verbose |= VERBOSE_POOL;
2661 param->fp_max_depth = 0;
2668 param->fp_recursive = 1;
2673 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2675 fprintf(stderr, "warning: '--size|-s' deprecated, "
2676 "use '--stripe-size|-S' instead\n");
2677 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2679 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2680 param->fp_verbose |= VERBOSE_SIZE;
2681 param->fp_max_depth = 0;
2685 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2698 if (param->fp_recursive)
2699 param->fp_max_depth = -1;
2700 else if (param->fp_verbose & VERBOSE_DETAIL)
2701 param->fp_max_depth = 1;
2703 if (!param->fp_verbose)
2704 param->fp_verbose = VERBOSE_DEFAULT;
2705 if (param->fp_quiet)
2706 param->fp_verbose = VERBOSE_OBJID;
2709 rc = llapi_getstripe(argv[optind], param);
2710 } while (++optind < argc && !rc);
2713 fprintf(stderr, "error: %s failed for %s.\n",
2714 argv[0], argv[optind - 1]);
2718 static int lfs_tgts(int argc, char **argv)
2720 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2721 struct find_param param;
2722 int index = 0, rc=0;
2727 if (argc == 2 && !realpath(argv[1], path)) {
2729 fprintf(stderr, "error: invalid path '%s': %s\n",
2730 argv[1], strerror(-rc));
2734 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2735 /* Check if we have a mount point */
2736 if (mntdir[0] == '\0')
2739 memset(¶m, 0, sizeof(param));
2740 if (!strcmp(argv[0], "mdts"))
2741 param.fp_get_lmv = 1;
2743 rc = llapi_ostlist(mntdir, ¶m);
2745 fprintf(stderr, "error: %s: failed on %s\n",
2748 if (path[0] != '\0')
2750 memset(mntdir, 0, PATH_MAX);
2756 static int lfs_getstripe(int argc, char **argv)
2758 struct find_param param = { 0 };
2760 param.fp_max_depth = 1;
2761 return lfs_getstripe_internal(argc, argv, ¶m);
2765 static int lfs_getdirstripe(int argc, char **argv)
2767 struct find_param param = { 0 };
2768 struct option long_opts[] = {
2769 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2770 {"mdt-count", no_argument, 0, 'c'},
2772 {"mdt-hash", no_argument, 0, 'H'},
2773 {"mdt-index", no_argument, 0, 'i'},
2774 {"recursive", no_argument, 0, 'r'},
2775 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2776 {"mdt-hash", no_argument, 0, 't'},
2778 {"default", no_argument, 0, 'D'},
2779 {"obd", required_argument, 0, 'O'},
2780 {"mdt-count", no_argument, 0, 'T'},
2781 {"yaml", no_argument, 0, 'y'},
2786 param.fp_get_lmv = 1;
2788 while ((c = getopt_long(argc, argv,
2789 "cDHiO:rtTy", long_opts, NULL)) != -1)
2793 if (param.fp_obd_uuid) {
2795 "error: %s: only one obduuid allowed",
2799 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2801 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2803 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2804 fprintf(stderr, "warning: '-c' deprecated"
2805 ", use '-T' instead\n");
2809 param.fp_verbose |= VERBOSE_COUNT;
2812 param.fp_verbose |= VERBOSE_OFFSET;
2814 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2818 param.fp_verbose |= VERBOSE_HASH_TYPE;
2821 param.fp_get_default_lmv = 1;
2824 param.fp_recursive = 1;
2837 if (param.fp_recursive)
2838 param.fp_max_depth = -1;
2840 if (!param.fp_verbose)
2841 param.fp_verbose = VERBOSE_DEFAULT;
2844 rc = llapi_getstripe(argv[optind], ¶m);
2845 } while (++optind < argc && !rc);
2848 fprintf(stderr, "error: %s failed for %s.\n",
2849 argv[0], argv[optind - 1]);
2854 static int lfs_setdirstripe(int argc, char **argv)
2858 unsigned int stripe_offset = -1;
2859 unsigned int stripe_count = 1;
2860 enum lmv_hash_type hash_type;
2863 char *stripe_offset_opt = NULL;
2864 char *stripe_count_opt = NULL;
2865 char *stripe_hash_opt = NULL;
2866 char *mode_opt = NULL;
2867 bool default_stripe = false;
2868 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2869 mode_t previous_mode = 0;
2870 bool delete = false;
2872 struct option long_opts[] = {
2873 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2874 { .val = 'c', .name = "count", .has_arg = required_argument },
2876 { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
2877 { .val = 'd', .name = "delete", .has_arg = no_argument },
2878 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2879 { .val = 'i', .name = "index", .has_arg = required_argument },
2881 { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
2882 { .val = 'm', .name = "mode", .has_arg = required_argument },
2883 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2884 { .val = 't', .name = "hash-type", .has_arg = required_argument },
2885 { .val = 't', .name = "mdt-hash", .has_arg = required_argument },
2887 {"mdt-hash", required_argument, 0, 'H'},
2888 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2889 { .val = 'D', .name = "default_stripe",
2890 .has_arg = no_argument },
2892 { .val = 'D', .name = "default", .has_arg = no_argument },
2895 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2902 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2903 if (strcmp(argv[optind - 1], "--count") == 0)
2904 fprintf(stderr, "warning: '--count' deprecated"
2905 ", use '--mdt-count' instead\n");
2907 stripe_count_opt = optarg;
2911 default_stripe = true;
2914 default_stripe = true;
2917 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2918 if (strcmp(argv[optind - 1], "--index") == 0)
2919 fprintf(stderr, "warning: '--index' deprecated"
2920 ", use '--mdt-index' instead\n");
2922 stripe_offset_opt = optarg;
2927 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2931 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2932 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2933 fprintf(stderr, "warning: '--hash-type' "
2934 "deprecated, use '--mdt-hash' "
2937 stripe_hash_opt = optarg;
2940 fprintf(stderr, "error: %s: option '%s' "
2942 argv[0], argv[optind - 1]);
2947 if (optind == argc) {
2948 fprintf(stderr, "error: %s: missing dirname\n",
2953 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2954 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2959 if (stripe_offset_opt != NULL) {
2960 /* get the stripe offset */
2961 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2963 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2964 argv[0], stripe_offset_opt);
2970 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2971 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2972 " or -i options.\n", argv[0]);
2980 if (mode_opt != NULL) {
2981 mode = strtoul(mode_opt, &end, 8);
2983 fprintf(stderr, "error: %s: bad mode '%s'\n",
2987 previous_mode = umask(0);
2990 if (stripe_hash_opt == NULL) {
2991 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2993 hash_type = check_hashtype(stripe_hash_opt);
2994 if (hash_type == 0) {
2996 "error: %s: bad stripe hash type '%s'\n",
2997 argv[0], stripe_hash_opt);
3002 /* get the stripe count */
3003 if (stripe_count_opt != NULL) {
3004 stripe_count = strtoul(stripe_count_opt, &end, 0);
3006 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
3007 argv[0], stripe_count_opt);
3012 dname = argv[optind];
3014 if (default_stripe) {
3015 result = llapi_dir_set_default_lmv_stripe(dname,
3016 stripe_offset, stripe_count,
3019 result = llapi_dir_create_pool(dname, mode,
3021 stripe_count, hash_type,
3026 fprintf(stderr, "error: %s: create stripe dir '%s' "
3027 "failed\n", argv[0], dname);
3030 dname = argv[++optind];
3031 } while (dname != NULL);
3033 if (mode_opt != NULL)
3034 umask(previous_mode);
3040 static int lfs_rmentry(int argc, char **argv)
3047 fprintf(stderr, "error: %s: missing dirname\n",
3053 dname = argv[index];
3054 while (dname != NULL) {
3055 result = llapi_direntry_remove(dname);
3057 fprintf(stderr, "error: %s: remove dir entry '%s' "
3058 "failed\n", argv[0], dname);
3061 dname = argv[++index];
3066 static int lfs_mv(int argc, char **argv)
3068 struct find_param param = {
3075 struct option long_opts[] = {
3076 { .val = 'M', .name = "mdt-index", .has_arg = required_argument },
3077 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3080 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3083 param.fp_mdt_index = strtoul(optarg, &end, 0);
3085 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3092 param.fp_verbose = VERBOSE_DETAIL;
3096 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3097 argv[0], argv[optind - 1]);
3102 if (param.fp_mdt_index == -1) {
3103 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3107 if (optind >= argc) {
3108 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3112 param.fp_migrate = 1;
3113 rc = llapi_migrate_mdt(argv[optind], ¶m);
3115 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3116 argv[0], argv[optind], param.fp_mdt_index,
3121 static int lfs_osts(int argc, char **argv)
3123 return lfs_tgts(argc, argv);
3126 static int lfs_mdts(int argc, char **argv)
3128 return lfs_tgts(argc, argv);
3131 #define COOK(value) \
3134 while (value > 1024) { \
3142 #define CDF "%11llu"
3143 #define HDF "%8.1f%c"
3148 MNTDF_INODES = 0x0001,
3149 MNTDF_COOKED = 0x0002,
3150 MNTDF_LAZY = 0x0004,
3151 MNTDF_VERBOSE = 0x0008,
3154 static int showdf(char *mntdir, struct obd_statfs *stat,
3155 char *uuid, enum mntdf_flags flags,
3156 char *type, int index, int rc)
3158 long long avail, used, total;
3160 char *suffix = "KMGTPEZY";
3161 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3162 char tbuf[3 * sizeof(__u64)];
3163 char ubuf[3 * sizeof(__u64)];
3164 char abuf[3 * sizeof(__u64)];
3165 char rbuf[3 * sizeof(__u64)];
3172 if (flags & MNTDF_INODES) {
3173 avail = stat->os_ffree;
3174 used = stat->os_files - stat->os_ffree;
3175 total = stat->os_files;
3177 int shift = flags & MNTDF_COOKED ? 0 : 10;
3179 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3180 used = ((stat->os_blocks - stat->os_bfree) *
3181 stat->os_bsize) >> shift;
3182 total = (stat->os_blocks * stat->os_bsize) >> shift;
3185 if ((used + avail) > 0)
3186 ratio = (double)used / (double)(used + avail);
3188 if (flags & MNTDF_COOKED) {
3192 cook_val = (double)total;
3195 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3198 snprintf(tbuf, sizeof(tbuf), CDF, total);
3200 cook_val = (double)used;
3203 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3206 snprintf(ubuf, sizeof(ubuf), CDF, used);
3208 cook_val = (double)avail;
3211 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3214 snprintf(abuf, sizeof(abuf), CDF, avail);
3216 snprintf(tbuf, sizeof(tbuf), CDF, total);
3217 snprintf(ubuf, sizeof(tbuf), CDF, used);
3218 snprintf(abuf, sizeof(tbuf), CDF, avail);
3221 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3222 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3223 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3225 printf("[%s:%d]", type, index);
3227 if (stat->os_state) {
3229 * Each character represents the matching
3232 const char state_names[] = "DRSI";
3237 for (i = 0, state = stat->os_state;
3238 state && i < sizeof(state_names); i++) {
3239 if (!(state & (1 << i)))
3241 printf("%c", state_names[i]);
3249 printf(UUF": inactive device\n", uuid);
3252 printf(UUF": %s\n", uuid, strerror(-rc));
3259 struct ll_stat_type {
3264 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3266 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3267 struct obd_uuid uuid_buf;
3268 char *poolname = NULL;
3269 struct ll_stat_type types[] = {
3270 { .st_op = LL_STATFS_LMV, .st_name = "MDT" },
3271 { .st_op = LL_STATFS_LOV, .st_name = "OST" },
3272 { .st_name = NULL } };
3273 struct ll_stat_type *tp;
3274 __u64 ost_ffree = 0;
3282 poolname = strchr(pool, '.');
3283 if (poolname != NULL) {
3284 if (strncmp(fsname, pool, strlen(fsname))) {
3285 fprintf(stderr, "filesystem name incorrect\n");
3293 fd = open(mntdir, O_RDONLY);
3296 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3301 if (flags & MNTDF_INODES)
3302 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3303 "UUID", "Inodes", "IUsed", "IFree",
3304 "IUse%", "Mounted on");
3306 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3307 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3308 "Used", "Available", "Use%", "Mounted on");
3310 for (tp = types; tp->st_name != NULL; tp++) {
3311 for (index = 0; ; index++) {
3312 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3313 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3314 type = flags & MNTDF_LAZY ?
3315 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3316 rc2 = llapi_obd_fstatfs(fd, type, index,
3317 &stat_buf, &uuid_buf);
3322 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3323 if (!(flags & MNTDF_VERBOSE))
3325 } else if (rc2 < 0 && rc == 0) {
3329 if (poolname && tp->st_op == LL_STATFS_LOV &&
3330 llapi_search_ost(fsname, poolname,
3331 obd_uuid2str(&uuid_buf)) != 1)
3334 /* the llapi_obd_statfs() call may have returned with
3335 * an error, but if it filled in uuid_buf we will at
3336 * lease use that to print out a message for that OBD.
3337 * If we didn't get anything in the uuid_buf, then fill
3338 * it in so that we can print an error message. */
3339 if (uuid_buf.uuid[0] == '\0')
3340 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3341 "%s%04x", tp->st_name, index);
3342 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3343 flags, tp->st_name, index, rc2);
3346 if (tp->st_op == LL_STATFS_LMV) {
3347 sum.os_ffree += stat_buf.os_ffree;
3348 sum.os_files += stat_buf.os_files;
3349 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3350 sum.os_blocks += stat_buf.os_blocks *
3352 sum.os_bfree += stat_buf.os_bfree *
3354 sum.os_bavail += stat_buf.os_bavail *
3356 ost_ffree += stat_buf.os_ffree;
3364 /* If we don't have as many objects free on the OST as inodes
3365 * on the MDS, we reduce the total number of inodes to
3366 * compensate, so that the "inodes in use" number is correct.
3367 * Matches ll_statfs_internal() so the results are consistent. */
3368 if (ost_ffree < sum.os_ffree) {
3369 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3370 sum.os_ffree = ost_ffree;
3373 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3379 static int lfs_df(int argc, char **argv)
3381 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3382 enum mntdf_flags flags = 0;
3383 int c, rc = 0, index = 0;
3384 char fsname[PATH_MAX] = "", *pool_name = NULL;
3385 struct option long_opts[] = {
3386 { .val = 'h', .name = "human-readable",
3387 .has_arg = no_argument },
3388 { .val = 'i', .name = "inodes", .has_arg = no_argument },
3389 { .val = 'l', .name = "lazy", .has_arg = no_argument },
3390 { .val = 'p', .name = "pool", .has_arg = required_argument },
3391 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3394 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3397 flags |= MNTDF_COOKED;
3400 flags |= MNTDF_INODES;
3403 flags |= MNTDF_LAZY;
3409 flags |= MNTDF_VERBOSE;
3415 if (optind < argc && !realpath(argv[optind], path)) {
3417 fprintf(stderr, "error: invalid path '%s': %s\n",
3418 argv[optind], strerror(-rc));
3422 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3423 /* Check if we have a mount point */
3424 if (mntdir[0] == '\0')
3427 rc = mntdf(mntdir, fsname, pool_name, flags);
3428 if (rc || path[0] != '\0')
3430 fsname[0] = '\0'; /* avoid matching in next loop */
3431 mntdir[0] = '\0'; /* avoid matching in next loop */
3437 static int lfs_getname(int argc, char **argv)
3439 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3440 int rc = 0, index = 0, c;
3441 char buf[sizeof(struct obd_uuid)];
3443 while ((c = getopt(argc, argv, "h")) != -1)
3446 if (optind == argc) { /* no paths specified, get all paths. */
3447 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3448 rc = llapi_getname(mntdir, buf, sizeof(buf));
3451 "cannot get name for `%s': %s\n",
3452 mntdir, strerror(-rc));
3456 printf("%s %s\n", buf, mntdir);
3458 path[0] = fsname[0] = mntdir[0] = 0;
3460 } else { /* paths specified, only attempt to search these. */
3461 for (; optind < argc; optind++) {
3462 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3465 "cannot get name for `%s': %s\n",
3466 argv[optind], strerror(-rc));
3470 printf("%s %s\n", buf, argv[optind]);
3476 static int lfs_check(int argc, char **argv)
3479 char mntdir[PATH_MAX] = {'\0'};
3488 obd_types[0] = obd_type1;
3489 obd_types[1] = obd_type2;
3491 if (strcmp(argv[1], "osts") == 0) {
3492 strcpy(obd_types[0], "osc");
3493 } else if (strcmp(argv[1], "mds") == 0) {
3494 strcpy(obd_types[0], "mdc");
3495 } else if (strcmp(argv[1], "servers") == 0) {
3497 strcpy(obd_types[0], "osc");
3498 strcpy(obd_types[1], "mdc");
3500 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3505 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3506 if (rc < 0 || mntdir[0] == '\0') {
3507 fprintf(stderr, "No suitable Lustre mount found\n");
3511 rc = llapi_target_check(num_types, obd_types, mntdir);
3513 fprintf(stderr, "error: %s: %s status failed\n",
3520 #ifdef HAVE_SYS_QUOTA_H
3521 #define ARG2INT(nr, str, msg) \
3524 nr = strtol(str, &endp, 0); \
3526 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3531 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3533 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3534 * returns the value or ULONG_MAX on integer overflow or incorrect format
3536 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3537 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3538 * 3. empty integer value is interpreted as 0
3540 static unsigned long str2sec(const char* timestr)
3542 const char spec[] = "smhdw";
3543 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3544 unsigned long val = 0;
3547 if (strpbrk(timestr, spec) == NULL) {
3548 /* no specifiers inside the time string,
3549 should treat it as an integer value */
3550 val = strtoul(timestr, &tail, 10);
3551 return *tail ? ULONG_MAX : val;
3554 /* format string is XXwXXdXXhXXmXXs */
3560 v = strtoul(timestr, &tail, 10);
3561 if (v == ULONG_MAX || *tail == '\0')
3562 /* value too large (ULONG_MAX or more)
3563 or missing specifier */
3566 ptr = strchr(spec, *tail);
3568 /* unknown specifier */
3573 /* check if product will overflow the type */
3574 if (!(v < ULONG_MAX / mult[ind]))
3577 ADD_OVERFLOW(val, mult[ind] * v);
3578 if (val == ULONG_MAX)
3590 #define ARG2ULL(nr, str, def_units) \
3592 unsigned long long limit, units = def_units; \
3595 rc = llapi_parse_size(str, &limit, &units, 1); \
3597 fprintf(stderr, "error: bad limit value %s\n", str); \
3603 static inline int has_times_option(int argc, char **argv)
3607 for (i = 1; i < argc; i++)
3608 if (!strcmp(argv[i], "-t"))
3614 int lfs_setquota_times(int argc, char **argv)
3617 struct if_quotactl qctl;
3618 char *mnt, *obd_type = (char *)qctl.obd_type;
3619 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3620 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3621 struct option long_opts[] = {
3622 { .val = 'b', .name = "block-grace", .has_arg = required_argument },
3623 { .val = 'g', .name = "group", .has_arg = no_argument },
3624 { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
3625 { .val = 'p', .name = "projid", .has_arg = no_argument },
3626 { .val = 't', .name = "times", .has_arg = no_argument },
3627 { .val = 'u', .name = "user", .has_arg = no_argument },
3631 memset(&qctl, 0, sizeof(qctl));
3632 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3633 qctl.qc_type = ALLQUOTA;
3635 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3636 long_opts, NULL)) != -1) {
3647 if (qctl.qc_type != ALLQUOTA) {
3648 fprintf(stderr, "error: -u/g/p can't be used "
3649 "more than once\n");
3652 qctl.qc_type = qtype;
3655 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3656 fprintf(stderr, "error: bad block-grace: %s\n",
3660 dqb->dqb_valid |= QIF_BTIME;
3663 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3664 fprintf(stderr, "error: bad inode-grace: %s\n",
3668 dqb->dqb_valid |= QIF_ITIME;
3670 case 't': /* Yes, of course! */
3672 default: /* getopt prints error message for us when opterr != 0 */
3677 if (qctl.qc_type == ALLQUOTA) {
3678 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3682 if (optind != argc - 1) {
3683 fprintf(stderr, "error: unexpected parameters encountered\n");
3688 rc = llapi_quotactl(mnt, &qctl);
3691 fprintf(stderr, "%s %s ", obd_type,
3692 obd_uuid2str(&qctl.obd_uuid));
3693 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3700 #define BSLIMIT (1 << 0)
3701 #define BHLIMIT (1 << 1)
3702 #define ISLIMIT (1 << 2)
3703 #define IHLIMIT (1 << 3)
3705 int lfs_setquota(int argc, char **argv)
3708 struct if_quotactl qctl;
3709 char *mnt, *obd_type = (char *)qctl.obd_type;
3710 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3711 struct option long_opts[] = {
3712 { .val = 'b', .name = "block-softlimit",
3713 .has_arg = required_argument },
3714 { .val = 'B', .name = "block-hardlimit",
3715 .has_arg = required_argument },
3716 { .val = 'g', .name = "group", .has_arg = required_argument },
3717 { .val = 'i', .name = "inode-softlimit",
3718 .has_arg = required_argument },
3719 { .val = 'I', .name = "inode-hardlimit",
3720 .has_arg = required_argument },
3721 { .val = 'p', .name = "projid", .has_arg = required_argument },
3722 { .val = 'u', .name = "user", .has_arg = required_argument },
3724 unsigned limit_mask = 0;
3728 if (has_times_option(argc, argv))
3729 return lfs_setquota_times(argc, argv);
3731 memset(&qctl, 0, sizeof(qctl));
3732 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3733 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3734 * so it can be used as a marker that qc_type
3735 * isn't reinitialized from command line */
3737 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3738 long_opts, NULL)) != -1) {
3742 rc = name2uid(&qctl.qc_id, optarg);
3746 rc = name2gid(&qctl.qc_id, optarg);
3750 rc = name2projid(&qctl.qc_id, optarg);
3752 if (qctl.qc_type != ALLQUOTA) {
3753 fprintf(stderr, "error: -u and -g can't be used"
3754 " more than once\n");
3757 qctl.qc_type = qtype;
3759 qctl.qc_id = strtoul(optarg, &endptr, 10);
3760 if (*endptr != '\0') {
3761 fprintf(stderr, "error: can't find id "
3762 "for name %s\n", optarg);
3768 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3769 dqb->dqb_bsoftlimit >>= 10;
3770 limit_mask |= BSLIMIT;
3771 if (dqb->dqb_bsoftlimit &&
3772 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3773 fprintf(stderr, "warning: block softlimit is "
3774 "smaller than the miminal qunit size, "
3775 "please see the help of setquota or "
3776 "Lustre manual for details.\n");
3779 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3780 dqb->dqb_bhardlimit >>= 10;
3781 limit_mask |= BHLIMIT;
3782 if (dqb->dqb_bhardlimit &&
3783 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3784 fprintf(stderr, "warning: block hardlimit is "
3785 "smaller than the miminal qunit size, "
3786 "please see the help of setquota or "
3787 "Lustre manual for details.\n");
3790 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3791 limit_mask |= ISLIMIT;
3792 if (dqb->dqb_isoftlimit &&
3793 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3794 fprintf(stderr, "warning: inode softlimit is "
3795 "smaller than the miminal qunit size, "
3796 "please see the help of setquota or "
3797 "Lustre manual for details.\n");
3800 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3801 limit_mask |= IHLIMIT;
3802 if (dqb->dqb_ihardlimit &&
3803 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3804 fprintf(stderr, "warning: inode hardlimit is "
3805 "smaller than the miminal qunit size, "
3806 "please see the help of setquota or "
3807 "Lustre manual for details.\n");
3809 default: /* getopt prints error message for us when opterr != 0 */
3814 if (qctl.qc_type == ALLQUOTA) {
3815 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3819 if (limit_mask == 0) {
3820 fprintf(stderr, "error: at least one limit must be specified\n");
3824 if (optind != argc - 1) {
3825 fprintf(stderr, "error: unexpected parameters encountered\n");
3831 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3832 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3833 /* sigh, we can't just set blimits/ilimits */
3834 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3835 .qc_type = qctl.qc_type,
3836 .qc_id = qctl.qc_id};
3838 rc = llapi_quotactl(mnt, &tmp_qctl);
3840 fprintf(stderr, "error: setquota failed while retrieving"
3841 " current quota settings (%s)\n",
3846 if (!(limit_mask & BHLIMIT))
3847 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3848 if (!(limit_mask & BSLIMIT))
3849 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3850 if (!(limit_mask & IHLIMIT))
3851 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3852 if (!(limit_mask & ISLIMIT))
3853 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3855 /* Keep grace times if we have got no softlimit arguments */
3856 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3857 dqb->dqb_valid |= QIF_BTIME;
3858 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3861 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3862 dqb->dqb_valid |= QIF_ITIME;
3863 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3867 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3868 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3870 rc = llapi_quotactl(mnt, &qctl);
3873 fprintf(stderr, "%s %s ", obd_type,
3874 obd_uuid2str(&qctl.obd_uuid));
3875 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3882 /* Converts seconds value into format string
3883 * result is returned in buf
3885 * 1. result is in descenting order: 1w2d3h4m5s
3886 * 2. zero fields are not filled (except for p. 3): 5d1s
3887 * 3. zero seconds value is presented as "0s"
3889 static char * __sec2str(time_t seconds, char *buf)
3891 const char spec[] = "smhdw";
3892 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3897 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3898 c = seconds / mult[i];
3900 if (c > 0 || (i == 0 && buf == tail))
3901 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3909 static void sec2str(time_t seconds, char *buf, int rc)
3916 tail = __sec2str(seconds, tail);
3918 if (rc && tail - buf < 39) {
3924 static void diff2str(time_t seconds, char *buf, time_t now)
3930 if (seconds <= now) {
3931 strcpy(buf, "none");
3934 __sec2str(seconds - now, buf);
3937 static void print_quota_title(char *name, struct if_quotactl *qctl,
3938 bool human_readable)
3940 printf("Disk quotas for %s %s (%cid %u):\n",
3941 qtype_name(qctl->qc_type), name,
3942 *qtype_name(qctl->qc_type), qctl->qc_id);
3943 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3944 "Filesystem", human_readable ? "used" : "kbytes",
3945 "quota", "limit", "grace",
3946 "files", "quota", "limit", "grace");
3949 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3952 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3955 snprintf(buf, buflen, "%5.4gP",
3956 (double)num / ((__u64)1 << 40));
3958 snprintf(buf, buflen, "%5.4gT",
3959 (double)num / (1 << 30));
3961 snprintf(buf, buflen, "%5.4gG",
3962 (double)num / (1 << 20));
3964 snprintf(buf, buflen, "%5.4gM",
3965 (double)num / (1 << 10));
3967 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3971 #define STRBUF_LEN 32
3972 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3979 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3980 int bover = 0, iover = 0;
3981 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3982 char numbuf[3][STRBUF_LEN];
3984 char strbuf[STRBUF_LEN];
3986 if (dqb->dqb_bhardlimit &&
3987 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3989 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3990 if (dqb->dqb_btime > now) {
3997 if (dqb->dqb_ihardlimit &&
3998 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
4000 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
4001 if (dqb->dqb_itime > now) {
4009 if (strlen(mnt) > 15)
4010 printf("%s\n%15s", mnt, "");
4012 printf("%15s", mnt);
4015 diff2str(dqb->dqb_btime, timebuf, now);
4017 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
4018 strbuf, sizeof(strbuf), h);
4019 if (rc == -EREMOTEIO)
4020 sprintf(numbuf[0], "%s*", strbuf);
4022 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
4023 "%s" : "[%s]", strbuf);
4025 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
4026 if (type == QC_GENERAL)
4027 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4028 "%s" : "[%s]", strbuf);
4030 sprintf(numbuf[1], "%s", "-");
4032 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4033 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4034 "%s" : "[%s]", strbuf);
4036 printf(" %7s%c %6s %7s %7s",
4037 numbuf[0], bover ? '*' : ' ', numbuf[1],
4038 numbuf[2], bover > 1 ? timebuf : "-");
4041 diff2str(dqb->dqb_itime, timebuf, now);
4043 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4044 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4046 if (type == QC_GENERAL)
4047 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4049 (uintmax_t)dqb->dqb_isoftlimit);
4051 sprintf(numbuf[1], "%s", "-");
4053 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4054 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4056 if (type != QC_OSTIDX)
4057 printf(" %7s%c %6s %7s %7s",
4058 numbuf[0], iover ? '*' : ' ', numbuf[1],
4059 numbuf[2], iover > 1 ? timebuf : "-");
4061 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4064 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4065 qctl->qc_cmd == Q_GETOINFO) {
4069 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4070 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4071 printf("Block grace time: %s; Inode grace time: %s\n",
4072 bgtimebuf, igtimebuf);
4076 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4077 bool h, __u64 *total)
4079 int rc = 0, rc1 = 0, count = 0;
4080 __u32 valid = qctl->qc_valid;
4082 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4084 fprintf(stderr, "can not get %s count: %s\n",
4085 is_mdt ? "mdt": "ost", strerror(-rc));
4089 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4090 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4091 rc = llapi_quotactl(mnt, qctl);
4093 /* It is remote client case. */
4094 if (rc == -EOPNOTSUPP) {
4101 fprintf(stderr, "quotactl %s%d failed.\n",
4102 is_mdt ? "mdt": "ost", qctl->qc_idx);
4106 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4107 qctl->qc_valid, 0, h);
4108 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4109 qctl->qc_dqblk.dqb_bhardlimit;
4112 qctl->qc_valid = valid;
4116 static int lfs_quota(int argc, char **argv)
4119 char *mnt, *name = NULL;
4120 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4121 .qc_type = ALLQUOTA };
4122 char *obd_type = (char *)qctl.obd_type;
4123 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4124 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4125 verbose = 0, pass = 0, quiet = 0, inacc;
4127 __u32 valid = QC_GENERAL, idx = 0;
4128 __u64 total_ialloc = 0, total_balloc = 0;
4129 bool human_readable = false;
4132 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4143 if (qctl.qc_type != ALLQUOTA) {
4144 fprintf(stderr, "error: use either -u or -g\n");
4147 qctl.qc_type = qtype;
4150 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4153 valid = qctl.qc_valid = QC_UUID;
4154 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4157 valid = qctl.qc_valid = QC_MDTIDX;
4158 idx = qctl.qc_idx = atoi(optarg);
4161 valid = qctl.qc_valid = QC_OSTIDX;
4162 idx = qctl.qc_idx = atoi(optarg);
4171 human_readable = true;
4174 fprintf(stderr, "error: %s: option '-%c' "
4175 "unrecognized\n", argv[0], c);
4180 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4181 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4182 optind == argc - 1) {
4184 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4185 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4186 qctl.qc_valid = valid;
4188 qctl.qc_type = pass;
4189 switch (qctl.qc_type) {
4191 qctl.qc_id = geteuid();
4192 rc = uid2name(&name, qctl.qc_id);
4195 qctl.qc_id = getegid();
4196 rc = gid2name(&name, qctl.qc_id);
4205 /* lfs quota -u username /path/to/lustre/mount */
4206 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4207 /* options should be followed by u/g-name and mntpoint */
4208 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4209 fprintf(stderr, "error: missing quota argument(s)\n");
4213 name = argv[optind++];
4214 switch (qctl.qc_type) {
4216 rc = name2uid(&qctl.qc_id, name);
4219 rc = name2gid(&qctl.qc_id, name);
4222 rc = name2projid(&qctl.qc_id, name);
4229 qctl.qc_id = strtoul(name, &endptr, 10);
4230 if (*endptr != '\0') {
4231 fprintf(stderr, "error: can't find id for name: %s\n",
4236 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4237 fprintf(stderr, "error: missing quota info argument(s)\n");
4242 rc1 = llapi_quotactl(mnt, &qctl);
4246 fprintf(stderr, "%s quotas are not enabled.\n",
4247 qtype_name(qctl.qc_type));
4250 fprintf(stderr, "Permission denied.\n");
4253 /* We already got error message. */
4256 fprintf(stderr, "Unexpected quotactl error: %s\n",
4261 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4262 print_quota_title(name, &qctl, human_readable);
4264 if (rc1 && *obd_type)
4265 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4267 if (qctl.qc_valid != QC_GENERAL)
4270 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4271 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4272 (QIF_LIMITS|QIF_USAGE));
4274 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4276 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4278 char strbuf[STRBUF_LEN];
4280 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4282 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4284 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4286 printf("Total allocated inode limit: %ju, total "
4287 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4291 if (rc1 || rc2 || rc3 || inacc)
4292 printf("Some errors happened when getting quota info. "
4293 "Some devices may be not working or deactivated. "
4294 "The data in \"[]\" is inaccurate.\n");
4297 if (pass > 0 && pass < LL_MAXQUOTAS)
4302 #endif /* HAVE_SYS_QUOTA_H! */
4304 static int flushctx_ioctl(char *mp)
4308 fd = open(mp, O_RDONLY);
4310 fprintf(stderr, "flushctx: error open %s: %s\n",
4311 mp, strerror(errno));
4315 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4317 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4318 mp, strerror(errno));
4324 static int lfs_flushctx(int argc, char **argv)
4326 int kdestroy = 0, c;
4327 char mntdir[PATH_MAX] = {'\0'};
4331 while ((c = getopt(argc, argv, "k")) != -1) {
4337 fprintf(stderr, "error: %s: option '-%c' "
4338 "unrecognized\n", argv[0], c);
4344 if ((rc = system("kdestroy > /dev/null")) != 0) {
4345 rc = WEXITSTATUS(rc);
4346 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4350 if (optind >= argc) {
4351 /* flush for all mounted lustre fs. */
4352 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4353 /* Check if we have a mount point */
4354 if (mntdir[0] == '\0')
4357 if (flushctx_ioctl(mntdir))
4360 mntdir[0] = '\0'; /* avoid matching in next loop */
4363 /* flush fs as specified */
4364 while (optind < argc) {
4365 if (flushctx_ioctl(argv[optind++]))
4372 static int lfs_cp(int argc, char **argv)
4374 fprintf(stderr, "remote client copy file(s).\n"
4375 "obsolete, does not support it anymore.\n");
4379 static int lfs_ls(int argc, char **argv)
4381 fprintf(stderr, "remote client lists directory contents.\n"
4382 "obsolete, does not support it anymore.\n");
4386 static int lfs_changelog(int argc, char **argv)
4388 void *changelog_priv;
4389 struct changelog_rec *rec;
4390 long long startrec = 0, endrec = 0;
4392 struct option long_opts[] = {
4393 {"follow", no_argument, 0, 'f'},
4396 char short_opts[] = "f";
4399 while ((rc = getopt_long(argc, argv, short_opts,
4400 long_opts, NULL)) != -1) {
4408 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4409 argv[0], argv[optind - 1]);
4416 mdd = argv[optind++];
4418 startrec = strtoll(argv[optind++], NULL, 10);
4420 endrec = strtoll(argv[optind++], NULL, 10);
4422 rc = llapi_changelog_start(&changelog_priv,
4423 CHANGELOG_FLAG_BLOCK |
4424 CHANGELOG_FLAG_JOBID |
4425 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4428 fprintf(stderr, "Can't start changelog: %s\n",
4429 strerror(errno = -rc));
4433 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4437 if (endrec && rec->cr_index > endrec) {
4438 llapi_changelog_free(&rec);
4441 if (rec->cr_index < startrec) {
4442 llapi_changelog_free(&rec);
4446 secs = rec->cr_time >> 30;
4447 gmtime_r(&secs, &ts);
4448 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4449 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4450 changelog_type2str(rec->cr_type),
4451 ts.tm_hour, ts.tm_min, ts.tm_sec,
4452 (int)(rec->cr_time & ((1 << 30) - 1)),
4453 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4454 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4456 if (rec->cr_flags & CLF_JOBID) {
4457 struct changelog_ext_jobid *jid =
4458 changelog_rec_jobid(rec);
4460 if (jid->cr_jobid[0] != '\0')
4461 printf(" j=%s", jid->cr_jobid);
4464 if (rec->cr_namelen)
4465 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4466 rec->cr_namelen, changelog_rec_name(rec));
4468 if (rec->cr_flags & CLF_RENAME) {
4469 struct changelog_ext_rename *rnm =
4470 changelog_rec_rename(rec);
4472 if (!fid_is_zero(&rnm->cr_sfid))
4473 printf(" s="DFID" sp="DFID" %.*s",
4474 PFID(&rnm->cr_sfid),
4475 PFID(&rnm->cr_spfid),
4476 (int)changelog_rec_snamelen(rec),
4477 changelog_rec_sname(rec));
4481 llapi_changelog_free(&rec);
4484 llapi_changelog_fini(&changelog_priv);
4487 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4489 return (rc == 1 ? 0 : rc);
4492 static int lfs_changelog_clear(int argc, char **argv)
4500 endrec = strtoll(argv[3], NULL, 10);
4502 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4505 fprintf(stderr, "%s: record out of range: %llu\n",
4507 else if (rc == -ENOENT)
4508 fprintf(stderr, "%s: no changelog user: %s\n",
4511 fprintf(stderr, "%s error: %s\n", argv[0],
4520 static int lfs_fid2path(int argc, char **argv)
4522 struct option long_opts[] = {
4523 { .val = 'c', .name = "cur", .has_arg = no_argument },
4524 { .val = 'l', .name = "link", .has_arg = required_argument },
4525 { .val = 'r', .name = "rec", .has_arg = required_argument },
4527 char short_opts[] = "cl:r:";
4528 char *device, *fid, *path;
4529 long long recno = -1;
4535 while ((rc = getopt_long(argc, argv, short_opts,
4536 long_opts, NULL)) != -1) {
4542 linkno = strtol(optarg, NULL, 10);
4545 recno = strtoll(optarg, NULL, 10);
4550 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4551 argv[0], argv[optind - 1]);
4559 device = argv[optind++];
4560 path = calloc(1, PATH_MAX);
4562 fprintf(stderr, "error: Not enough memory\n");
4567 while (optind < argc) {
4568 fid = argv[optind++];
4570 lnktmp = (linkno >= 0) ? linkno : 0;
4572 int oldtmp = lnktmp;
4573 long long rectmp = recno;
4575 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4578 fprintf(stderr, "%s: error on FID %s: %s\n",
4579 argv[0], fid, strerror(errno = -rc2));
4586 fprintf(stdout, "%lld ", rectmp);
4587 if (device[0] == '/') {
4588 fprintf(stdout, "%s", device);
4589 if (device[strlen(device) - 1] != '/')
4590 fprintf(stdout, "/");
4591 } else if (path[0] == '\0') {
4592 fprintf(stdout, "/");
4594 fprintf(stdout, "%s\n", path);
4597 /* specified linkno */
4599 if (oldtmp == lnktmp)
4609 static int lfs_path2fid(int argc, char **argv)
4611 struct option long_opts[] = {
4612 { .val = 'p', .name = "parents", .has_arg = no_argument },
4615 const char short_opts[] = "p";
4616 const char *sep = "";
4619 bool show_parents = false;
4621 while ((rc = getopt_long(argc, argv, short_opts,
4622 long_opts, NULL)) != -1) {
4625 show_parents = true;
4628 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4629 argv[0], argv[optind - 1]);
4634 if (optind > argc - 1)
4636 else if (optind < argc - 1)
4640 for (path = argv + optind; *path != NULL; path++) {
4642 if (!show_parents) {
4643 err = llapi_path2fid(*path, &fid);
4645 printf("%s%s"DFID"\n",
4646 *sep != '\0' ? *path : "", sep,
4649 char name[NAME_MAX + 1];
4650 unsigned int linkno = 0;
4652 while ((err = llapi_path2parent(*path, linkno, &fid,
4653 name, sizeof(name))) == 0) {
4654 if (*sep != '\0' && linkno == 0)
4655 printf("%s%s", *path, sep);
4657 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4662 /* err == -ENODATA is end-of-loop */
4663 if (linkno > 0 && err == -ENODATA) {
4670 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4671 argv[0], show_parents ? "parent " : "", *path,
4683 static int lfs_data_version(int argc, char **argv)
4690 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4695 while ((c = getopt(argc, argv, "nrw")) != -1) {
4698 data_version_flags = 0;
4701 data_version_flags |= LL_DV_RD_FLUSH;
4704 data_version_flags |= LL_DV_WR_FLUSH;
4713 path = argv[optind];
4714 fd = open(path, O_RDONLY);
4716 err(errno, "cannot open file %s", path);
4718 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4720 err(errno, "cannot get version for %s", path);
4722 printf("%ju" "\n", (uintmax_t)data_version);
4728 static int lfs_hsm_state(int argc, char **argv)
4733 struct hsm_user_state hus;
4741 rc = llapi_hsm_state_get(path, &hus);
4743 fprintf(stderr, "can't get hsm state for %s: %s\n",
4744 path, strerror(errno = -rc));
4748 /* Display path name and status flags */
4749 printf("%s: (0x%08x)", path, hus.hus_states);
4751 if (hus.hus_states & HS_RELEASED)
4752 printf(" released");
4753 if (hus.hus_states & HS_EXISTS)
4755 if (hus.hus_states & HS_DIRTY)
4757 if (hus.hus_states & HS_ARCHIVED)
4758 printf(" archived");
4759 /* Display user-settable flags */
4760 if (hus.hus_states & HS_NORELEASE)
4761 printf(" never_release");
4762 if (hus.hus_states & HS_NOARCHIVE)
4763 printf(" never_archive");
4764 if (hus.hus_states & HS_LOST)
4765 printf(" lost_from_hsm");
4767 if (hus.hus_archive_id != 0)
4768 printf(", archive_id:%d", hus.hus_archive_id);
4771 } while (++i < argc);
4776 #define LFS_HSM_SET 0
4777 #define LFS_HSM_CLEAR 1
4780 * Generic function to set or clear HSM flags.
4781 * Used by hsm_set and hsm_clear.
4783 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4785 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4787 struct option long_opts[] = {
4788 { .val = 'A', .name = "archived", .has_arg = no_argument },
4789 { .val = 'a', .name = "noarchive", .has_arg = no_argument },
4790 { .val = 'd', .name = "dirty", .has_arg = no_argument },
4791 { .val = 'e', .name = "exists", .has_arg = no_argument },
4792 { .val = 'l', .name = "lost", .has_arg = no_argument },
4793 { .val = 'r', .name = "norelease", .has_arg = no_argument },
4795 char short_opts[] = "lraAde";
4803 while ((c = getopt_long(argc, argv, short_opts,
4804 long_opts, NULL)) != -1) {
4810 mask |= HS_NOARCHIVE;
4813 mask |= HS_ARCHIVED;
4816 mask |= HS_NORELEASE;
4827 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4828 argv[0], argv[optind - 1]);
4833 /* User should have specified a flag */
4837 while (optind < argc) {
4839 path = argv[optind];
4841 /* If mode == 0, this means we apply the mask. */
4842 if (mode == LFS_HSM_SET)
4843 rc = llapi_hsm_state_set(path, mask, 0, 0);
4845 rc = llapi_hsm_state_set(path, 0, mask, 0);
4848 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4849 path, strerror(errno = -rc));
4858 static int lfs_hsm_action(int argc, char **argv)
4863 struct hsm_current_action hca;
4864 struct hsm_extent he;
4865 enum hsm_user_action hua;
4866 enum hsm_progress_states hps;
4874 rc = llapi_hsm_current_action(path, &hca);
4876 fprintf(stderr, "can't get hsm action for %s: %s\n",
4877 path, strerror(errno = -rc));
4880 he = hca.hca_location;
4881 hua = hca.hca_action;
4882 hps = hca.hca_state;
4884 printf("%s: %s", path, hsm_user_action2name(hua));
4886 /* Skip file without action */
4887 if (hca.hca_action == HUA_NONE) {
4892 printf(" %s ", hsm_progress_state2name(hps));
4894 if ((hps == HPS_RUNNING) &&
4895 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4896 printf("(%llu bytes moved)\n",
4897 (unsigned long long)he.length);
4898 else if ((he.offset + he.length) == LUSTRE_EOF)
4899 printf("(from %llu to EOF)\n",
4900 (unsigned long long)he.offset);
4902 printf("(from %llu to %llu)\n",
4903 (unsigned long long)he.offset,
4904 (unsigned long long)(he.offset + he.length));
4906 } while (++i < argc);
4911 static int lfs_hsm_set(int argc, char **argv)
4913 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4916 static int lfs_hsm_clear(int argc, char **argv)
4918 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4922 * Check file state and return its fid, to be used by lfs_hsm_request().
4924 * \param[in] file Path to file to check
4925 * \param[in,out] fid Pointer to allocated lu_fid struct.
4926 * \param[in,out] last_dev Pointer to last device id used.
4928 * \return 0 on success.
4930 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4936 rc = lstat(file, &st);
4938 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4941 /* Checking for regular file as archiving as posix copytool
4942 * rejects archiving files other than regular files
4944 if (!S_ISREG(st.st_mode)) {
4945 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4948 /* A request should be ... */
4949 if (*last_dev != st.st_dev && *last_dev != 0) {
4950 fprintf(stderr, "All files should be "
4951 "on the same filesystem: %s\n", file);
4954 *last_dev = st.st_dev;
4956 rc = llapi_path2fid(file, fid);
4958 fprintf(stderr, "Cannot read FID of %s: %s\n",
4959 file, strerror(-rc));
4965 /* Fill an HSM HUR item with a given file name.
4967 * If mntpath is set, then the filename is actually a FID, and no
4968 * lookup on the filesystem will be performed.
4970 * \param[in] hur the user request to fill
4971 * \param[in] idx index of the item inside the HUR to fill
4972 * \param[in] mntpath mountpoint of Lustre
4973 * \param[in] fname filename (if mtnpath is NULL)
4974 * or FID (if mntpath is set)
4975 * \param[in] last_dev pointer to last device id used
4977 * \retval 0 on success
4978 * \retval CMD_HELP or a negative errno on error
4980 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4981 const char *mntpath, const char *fname,
4984 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4987 hui->hui_extent.length = -1;
4989 if (mntpath != NULL) {
4992 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4996 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
5001 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
5005 hur->hur_request.hr_itemcount++;
5010 static int lfs_hsm_request(int argc, char **argv, int action)
5012 struct option long_opts[] = {
5013 { .val = 'a', .name = "archive", .has_arg = required_argument },
5014 { .val = 'D', .name = "data", .has_arg = required_argument },
5015 { .val = 'l', .name = "filelist", .has_arg = required_argument },
5016 { .val = 'm', .name = "mntpath", .has_arg = required_argument },
5019 char short_opts[] = "l:D:a:m:";
5020 struct hsm_user_request *hur, *oldhur;
5025 char *filelist = NULL;
5026 char fullpath[PATH_MAX];
5027 char *opaque = NULL;
5031 int nbfile_alloc = 0;
5032 char *some_file = NULL;
5033 char *mntpath = NULL;
5039 while ((c = getopt_long(argc, argv, short_opts,
5040 long_opts, NULL)) != -1) {
5049 if (action != HUA_ARCHIVE &&
5050 action != HUA_REMOVE) {
5052 "error: -a is supported only "
5053 "when archiving or removing\n");
5056 archive_id = atoi(optarg);
5059 if (some_file == NULL) {
5061 some_file = strdup(optarg);
5067 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5068 argv[0], argv[optind - 1]);
5073 /* All remaining args are files, so we have at least nbfile */
5074 nbfile = argc - optind;
5076 if ((nbfile == 0) && (filelist == NULL))
5080 opaque_len = strlen(opaque);
5082 /* Alloc the request structure with enough place to store all files
5083 * from command line. */
5084 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5086 fprintf(stderr, "Cannot create the request: %s\n",
5090 nbfile_alloc = nbfile;
5092 hur->hur_request.hr_action = action;
5093 hur->hur_request.hr_archive_id = archive_id;
5094 hur->hur_request.hr_flags = 0;
5096 /* All remaining args are files, add them */
5097 if (nbfile != 0 && some_file == NULL)
5098 some_file = strdup(argv[optind]);
5100 for (i = 0; i < nbfile; i++) {
5101 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5107 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5109 /* If a filelist was specified, read the filelist from it. */
5110 if (filelist != NULL) {
5111 fp = fopen(filelist, "r");
5113 fprintf(stderr, "Cannot read the file list %s: %s\n",
5114 filelist, strerror(errno));
5119 while ((rc = getline(&line, &len, fp)) != -1) {
5120 /* If allocated buffer was too small, get something
5122 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5125 nbfile_alloc = nbfile_alloc * 2 + 1;
5127 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5130 fprintf(stderr, "hsm: cannot allocate "
5131 "the request: %s\n",
5138 size = hur_len(oldhur);
5140 fprintf(stderr, "hsm: cannot allocate "
5141 "%u files + %u bytes data\n",
5142 oldhur->hur_request.hr_itemcount,
5143 oldhur->hur_request.hr_data_len);
5150 memcpy(hur, oldhur, size);
5155 if (line[strlen(line) - 1] == '\n')
5156 line[strlen(line) - 1] = '\0';
5158 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5159 mntpath, line, &last_dev);
5165 if (some_file == NULL) {
5175 /* If a --data was used, add it to the request */
5176 hur->hur_request.hr_data_len = opaque_len;
5178 memcpy(hur_data(hur), opaque, opaque_len);
5180 /* Send the HSM request */
5181 if (realpath(some_file, fullpath) == NULL) {
5182 fprintf(stderr, "Could not find path '%s': %s\n",
5183 some_file, strerror(errno));
5185 rc = llapi_hsm_request(fullpath, hur);
5187 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5188 some_file, strerror(-rc));
5198 static int lfs_hsm_archive(int argc, char **argv)
5200 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5203 static int lfs_hsm_restore(int argc, char **argv)
5205 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5208 static int lfs_hsm_release(int argc, char **argv)
5210 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5213 static int lfs_hsm_remove(int argc, char **argv)
5215 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5218 static int lfs_hsm_cancel(int argc, char **argv)
5220 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5223 static int lfs_swap_layouts(int argc, char **argv)
5228 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5229 SWAP_LAYOUTS_KEEP_MTIME |
5230 SWAP_LAYOUTS_KEEP_ATIME);
5233 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5235 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5237 enum lu_ladvise_type advice;
5240 advice < ARRAY_SIZE(ladvise_names); advice++) {
5241 if (ladvise_names[advice] == NULL)
5243 if (strcmp(string, ladvise_names[advice]) == 0)
5247 return LU_LADVISE_INVALID;
5250 static int lfs_ladvise(int argc, char **argv)
5252 struct option long_opts[] = {
5253 { .val = 'a', .name = "advice", .has_arg = required_argument },
5254 { .val = 'b', .name = "background", .has_arg = no_argument },
5255 { .val = 'e', .name = "end", .has_arg = required_argument },
5256 { .val = 'l', .name = "length", .has_arg = required_argument },
5257 { .val = 's', .name = "start", .has_arg = required_argument },
5259 char short_opts[] = "a:be:l:s:";
5264 struct llapi_lu_ladvise advice;
5265 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5266 unsigned long long start = 0;
5267 unsigned long long end = LUSTRE_EOF;
5268 unsigned long long length = 0;
5269 unsigned long long size_units;
5270 unsigned long long flags = 0;
5273 while ((c = getopt_long(argc, argv, short_opts,
5274 long_opts, NULL)) != -1) {
5277 advice_type = lfs_get_ladvice(optarg);
5278 if (advice_type == LU_LADVISE_INVALID) {
5279 fprintf(stderr, "%s: invalid advice type "
5280 "'%s'\n", argv[0], optarg);
5281 fprintf(stderr, "Valid types:");
5283 for (advice_type = 0;
5284 advice_type < ARRAY_SIZE(ladvise_names);
5286 if (ladvise_names[advice_type] == NULL)
5288 fprintf(stderr, " %s",
5289 ladvise_names[advice_type]);
5291 fprintf(stderr, "\n");
5301 rc = llapi_parse_size(optarg, &end,
5304 fprintf(stderr, "%s: bad end offset '%s'\n",
5311 rc = llapi_parse_size(optarg, &start,
5314 fprintf(stderr, "%s: bad start offset "
5315 "'%s'\n", argv[0], optarg);
5321 rc = llapi_parse_size(optarg, &length,
5324 fprintf(stderr, "%s: bad length '%s'\n",
5332 fprintf(stderr, "%s: option '%s' unrecognized\n",
5333 argv[0], argv[optind - 1]);
5338 if (advice_type == LU_LADVISE_INVALID) {
5339 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5340 fprintf(stderr, "Valid types:");
5341 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5343 if (ladvise_names[advice_type] == NULL)
5345 fprintf(stderr, " %s", ladvise_names[advice_type]);
5347 fprintf(stderr, "\n");
5351 if (argc <= optind) {
5352 fprintf(stderr, "%s: please give one or more file names\n",
5357 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5358 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5363 if (end == LUSTRE_EOF && length != 0)
5364 end = start + length;
5367 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5368 argv[0], start, end);
5372 while (optind < argc) {
5375 path = argv[optind++];
5377 fd = open(path, O_RDONLY);
5379 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5380 argv[0], path, strerror(errno));
5385 advice.lla_start = start;
5386 advice.lla_end = end;
5387 advice.lla_advice = advice_type;
5388 advice.lla_value1 = 0;
5389 advice.lla_value2 = 0;
5390 advice.lla_value3 = 0;
5391 advice.lla_value4 = 0;
5392 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5395 fprintf(stderr, "%s: cannot give advice '%s' to file "
5396 "'%s': %s\n", argv[0],
5397 ladvise_names[advice_type],
5398 path, strerror(errno));
5401 if (rc == 0 && rc2 < 0)
5407 static int lfs_list_commands(int argc, char **argv)
5409 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5411 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5416 int main(int argc, char **argv)
5420 /* Ensure that liblustreapi constructor has run */
5421 if (!liblustreapi_initialized)
5422 fprintf(stderr, "liblustreapi was not properly initialized\n");
5426 Parser_init("lfs > ", cmdlist);
5428 progname = argv[0]; /* Used in error messages */
5430 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5432 rc = Parser_commands();
5435 return rc < 0 ? -rc : rc;
5438 #ifdef _LUSTRE_IDL_H_
5439 /* Everything we need here should be included by lustreapi.h. */
5440 # error "lfs should not depend on lustre_idl.h"
5441 #endif /* _LUSTRE_IDL_H_ */