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 <linux/lustre/lustre_ver.h>
69 #include <linux/lustre/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] [--unset|-u]\n\n"
404 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
405 " {[--mode|-m [READ,WRITE]}\n"
407 {"help", Parser_help, 0, "help"},
408 {"exit", Parser_quit, 0, "quit"},
409 {"quit", Parser_quit, 0, "quit"},
410 {"--version", Parser_version, 0,
411 "output build version of the utility and exit"},
412 {"--list-commands", lfs_list_commands, 0,
413 "list commands supported by the utility and exit"},
418 #define MIGRATION_NONBLOCK 1
420 static int check_hashtype(const char *hashtype)
424 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
425 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
432 * Internal helper for migrate_copy_data(). Check lease and report error if
435 * \param[in] fd File descriptor on which to check the lease.
436 * \param[out] lease_broken Set to true if the lease was broken.
437 * \param[in] group_locked Whether a group lock was taken or not.
438 * \param[in] path Name of the file being processed, for error
441 * \retval 0 Migration can keep on going.
442 * \retval -errno Error occurred, abort migration.
444 static int check_lease(int fd, bool *lease_broken, bool group_locked,
449 if (!file_lease_supported)
452 rc = llapi_lease_check(fd);
454 return 0; /* llapi_check_lease returns > 0 on success. */
457 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
459 rc = rc ? rc : -EAGAIN;
461 fprintf(stderr, "%s: external attempt to access file '%s' "
462 "blocked until migration ends.\n", progname, path);
465 *lease_broken = true;
469 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
470 bool group_locked, const char *fname)
479 bool lease_broken = false;
481 /* Use a page-aligned buffer for direct I/O */
482 rc = posix_memalign(&buf, getpagesize(), buf_size);
487 /* read new data only if we have written all
488 * previously read data */
491 rc = check_lease(fd_src, &lease_broken,
492 group_locked, fname);
496 rsize = read(fd_src, buf, buf_size);
499 fprintf(stderr, "%s: %s: read failed: %s\n",
500 progname, fname, strerror(-rc));
510 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
514 "%s: %s: write failed on volatile: %s\n",
515 progname, fname, strerror(-rc));
525 fprintf(stderr, "%s: %s: fsync failed: %s\n",
526 progname, fname, strerror(-rc));
534 static int migrate_copy_timestamps(int fdv, const struct stat *st)
536 struct timeval tv[2] = {
537 {.tv_sec = st->st_atime},
538 {.tv_sec = st->st_mtime}
541 return futimes(fdv, tv);
544 static int migrate_block(int fd, int fdv, const struct stat *st,
545 size_t buf_size, const char *name)
552 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
554 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
555 progname, name, strerror(-rc));
563 /* The grouplock blocks all concurrent accesses to the file.
564 * It has to be taken after llapi_get_data_version as it would
566 rc = llapi_group_lock(fd, gid);
568 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
569 progname, name, strerror(-rc));
573 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
575 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
579 /* Make sure we keep original atime/mtime values */
580 rc = migrate_copy_timestamps(fdv, st);
582 fprintf(stderr, "%s: %s: timestamp copy failed\n",
588 * for a migration we need to check data version on file did
591 * Pass in gid=0 since we already own grouplock. */
592 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
593 SWAP_LAYOUTS_CHECK_DV1);
595 fprintf(stderr, "%s: %s: dataversion changed during copy, "
596 "migration aborted\n", progname, name);
599 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
600 name, strerror(-rc));
605 rc2 = llapi_group_unlock(fd, gid);
606 if (rc2 < 0 && rc == 0) {
607 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
608 progname, name, strerror(-rc2));
615 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
616 size_t buf_size, const char *name)
622 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
624 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
625 progname, name, strerror(-rc));
629 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
631 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
635 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
637 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
638 progname, name, strerror(-rc));
644 fprintf(stderr, "%s: %s: data version changed during "
650 /* Make sure we keep original atime/mtime values */
651 rc = migrate_copy_timestamps(fdv, st);
653 fprintf(stderr, "%s: %s: timestamp copy failed\n",
658 /* Atomically put lease, swap layouts and close.
659 * for a migration we need to check data version on file did
661 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
663 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
664 progname, name, strerror(-rc));
671 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
676 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
680 if (flags != 0 && comp_id != 0)
683 /* LCME_FL_INIT is the only supported flag in PFL */
685 if (flags & ~LCME_KNOWN_FLAGS) {
686 fprintf(stderr, "Invalid component flags %#x\n", flags);
689 } else if (comp_id > LCME_ID_MAX) {
690 fprintf(stderr, "Invalid component id %u\n", comp_id);
694 rc = llapi_layout_file_comp_del(fname, comp_id, flags);
696 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
697 comp_id, fname, strerror(errno));
701 static int lfs_component_add(char *fname, struct llapi_layout *layout)
708 rc = llapi_layout_file_comp_add(fname, layout);
710 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
711 fname, strerror(errno));
715 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
716 struct llapi_layout *layout)
724 fd = lstat(fname, &st);
725 if (fd == 0 && S_ISDIR(st.st_mode))
726 open_flags = O_DIRECTORY | O_RDONLY;
728 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
730 fprintf(stderr, "%s %s failed. %s\n",
731 S_ISDIR(st.st_mode) ?
732 "Set default composite layout to " :
733 "Create composite file",
734 fname, strerror(errno));
738 static int lfs_migrate(char *name, __u64 migration_flags,
739 struct llapi_stripe_param *param,
740 struct llapi_layout *layout)
744 char parent[PATH_MAX];
747 char volatile_file[sizeof(parent) +
748 LUSTRE_VOLATILE_HDR_LEN +
749 2 * sizeof(mdt_index) +
750 2 * sizeof(random_value) + 4];
753 struct lov_user_md *lum = NULL;
755 int buf_size = 1024 * 1024 * 4;
756 bool have_lease_rdlck = false;
760 /* find the right size for the IO and allocate the buffer */
761 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
762 lum = malloc(lum_size);
768 rc = llapi_file_get_stripe(name, lum);
769 /* failure can happen for many reasons and some may be not real errors
771 * in case of a real error, a later call will fail with better
772 * error management */
774 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
775 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
776 lum->lmm_stripe_size != 0)
777 buf_size = lum->lmm_stripe_size;
780 /* open file, direct io */
781 /* even if the file is only read, WR mode is nedeed to allow
782 * layout swap on fd */
783 fd = open(name, O_RDWR | O_DIRECT);
786 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
791 if (file_lease_supported) {
792 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
793 if (rc == -EOPNOTSUPP) {
794 /* Older servers do not support file lease.
795 * Disable related checks. This opens race conditions
796 * as explained in LU-4840 */
797 file_lease_supported = false;
799 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
800 progname, name, strerror(-rc));
803 have_lease_rdlck = true;
807 /* search for file directory pathname */
808 if (strlen(name) > sizeof(parent)-1) {
812 strncpy(parent, name, sizeof(parent));
813 ptr = strrchr(parent, '/');
815 if (getcwd(parent, sizeof(parent)) == NULL) {
826 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
828 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
829 progname, name, strerror(-rc));
834 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
835 mode_t open_mode = S_IRUSR | S_IWUSR;
837 random_value = random();
838 rc = snprintf(volatile_file, sizeof(volatile_file),
839 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
840 mdt_index, random_value);
841 if (rc >= sizeof(volatile_file)) {
846 /* create, open a volatile file, use caching (ie no directio) */
848 fdv = llapi_file_open_param(volatile_file, open_flags,
850 else if (layout != NULL)
851 fdv = lfs_component_create(volatile_file, open_flags,
855 } while (fdv == -EEXIST);
859 fprintf(stderr, "%s: %s: cannot create volatile file in"
861 progname, parent, strerror(-rc));
865 /* In case the MDT does not support creation of volatile files
866 * we should try to unlink it. */
867 (void)unlink(volatile_file);
869 /* Not-owner (root?) special case.
870 * Need to set owner/group of volatile file like original.
871 * This will allow to pass related check during layout_swap.
876 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
880 rc = fstat(fdv, &stv);
883 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
884 volatile_file, strerror(errno));
887 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
888 rc = fchown(fdv, st.st_uid, st.st_gid);
891 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
892 name, strerror(errno));
897 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
898 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
900 have_lease_rdlck = false;
901 fdv = -1; /* The volatile file is closed as we put the
902 * lease in non-blocking mode. */
905 /* Blocking mode (forced if servers do not support file lease).
906 * It is also the default mode, since we cannot distinguish
907 * between a broken lease and a server that does not support
908 * atomic swap/close (LU-6785) */
909 rc = migrate_block(fd, fdv, &st, buf_size, name);
913 if (have_lease_rdlck)
930 * Parse a string containing an OST index list into an array of integers.
932 * The input string contains a comma delimited list of individual
933 * indices and ranges, for example "1,2-4,7". Add the indices into the
934 * \a osts array and remove duplicates.
936 * \param[out] osts array to store indices in
937 * \param[in] size size of \a osts array
938 * \param[in] offset starting index in \a osts
939 * \param[in] arg string containing OST index list
941 * \retval positive number of indices in \a osts
942 * \retval -EINVAL unable to parse \a arg
944 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
948 int slots = size - offset;
956 while (!end_of_loop) {
964 ptr = strchrnul(arg, ',');
966 end_of_loop = *ptr == '\0';
969 start_index = strtol(arg, &endptr, 0);
970 if (endptr == arg) /* no data at all */
972 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
977 end_index = start_index;
978 if (*endptr == '-') {
979 end_index = strtol(endptr + 1, &endptr, 0);
982 if (end_index < start_index)
986 for (i = start_index; i <= end_index && slots > 0; i++) {
989 /* remove duplicate */
990 for (j = 0; j < offset; j++) {
994 if (j == offset) { /* no duplicate */
999 if (slots == 0 && i < end_index)
1007 if (!end_of_loop && ptr != NULL)
1010 return rc < 0 ? rc : nr;
1013 struct lfs_setstripe_args {
1014 unsigned long long lsa_comp_end;
1015 unsigned long long lsa_stripe_size;
1016 int lsa_stripe_count;
1018 __u32 lsa_comp_flags;
1021 char *lsa_pool_name;
1024 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1026 memset(lsa, 0, sizeof(*lsa));
1027 lsa->lsa_stripe_off = -1;
1030 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1032 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1033 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1034 lsa->lsa_comp_end != 0);
1037 static int comp_args_to_layout(struct llapi_layout **composite,
1038 struct lfs_setstripe_args *lsa)
1040 struct llapi_layout *layout = *composite;
1041 uint64_t prev_end = 0;
1044 if (layout == NULL) {
1045 layout = llapi_layout_alloc();
1046 if (layout == NULL) {
1047 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1051 *composite = layout;
1055 /* Get current component extent, current component
1056 * must be the tail component. */
1057 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1059 fprintf(stderr, "Get comp extent failed. %s\n",
1064 rc = llapi_layout_comp_add(layout);
1066 fprintf(stderr, "Add component failed. %s\n",
1072 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1074 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1075 prev_end, lsa->lsa_comp_end, strerror(errno));
1079 if (lsa->lsa_stripe_size != 0) {
1080 rc = llapi_layout_stripe_size_set(layout,
1081 lsa->lsa_stripe_size);
1083 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1084 lsa->lsa_stripe_size, strerror(errno));
1089 if (lsa->lsa_stripe_count != 0) {
1090 rc = llapi_layout_stripe_count_set(layout,
1091 lsa->lsa_stripe_count == -1 ?
1093 lsa->lsa_stripe_count);
1095 fprintf(stderr, "Set stripe count %d failed. %s\n",
1096 lsa->lsa_stripe_count, strerror(errno));
1101 if (lsa->lsa_pool_name != NULL) {
1102 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1104 fprintf(stderr, "Set pool name: %s failed. %s\n",
1105 lsa->lsa_pool_name, strerror(errno));
1110 if (lsa->lsa_nr_osts > 0) {
1111 if (lsa->lsa_stripe_count > 0 &&
1112 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1113 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1114 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1117 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1118 rc = llapi_layout_ost_index_set(layout, i,
1123 } else if (lsa->lsa_stripe_off != -1) {
1124 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1127 fprintf(stderr, "Set ost index %d failed. %s\n",
1128 i, strerror(errno));
1135 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1136 * end of the last component in the existing file, and adjust the
1137 * first extent start of the components to be added accordingly. */
1138 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1140 struct llapi_layout *head;
1141 uint64_t start, end, stripe_size, prev_end = 0;
1148 head = llapi_layout_get_by_path(fname, 0);
1150 fprintf(stderr, "Read layout from %s failed. %s\n",
1151 fname, strerror(errno));
1153 } else if (errno == ENODATA) {
1154 /* file without LOVEA, this component-add will be turned
1155 * into a component-create. */
1156 llapi_layout_free(head);
1158 } else if (!llapi_layout_is_composite(head)) {
1159 fprintf(stderr, "'%s' isn't a composite file.\n",
1161 llapi_layout_free(head);
1165 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1167 fprintf(stderr, "Get prev extent failed. %s\n",
1169 llapi_layout_free(head);
1173 llapi_layout_free(head);
1175 /* Make sure we use the first component of the layout to be added. */
1176 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1178 fprintf(stderr, "Move component cursor failed. %s\n",
1183 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1185 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1189 if (start > prev_end || end <= prev_end) {
1190 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1191 "adjacent with the existing file extent end: %lu\n",
1192 start, end, prev_end);
1196 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1198 fprintf(stderr, "Get stripe size failed. %s\n",
1203 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1204 (prev_end & (stripe_size - 1))) {
1205 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1206 stripe_size, prev_end);
1210 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1212 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1213 prev_end, end, strerror(errno));
1220 static inline bool comp_flags_is_neg(__u32 flags)
1222 return flags & LCME_FL_NEG;
1225 static inline void comp_flags_set_neg(__u32 *flags)
1227 *flags |= LCME_FL_NEG;
1230 static inline void comp_flags_clear_neg(__u32 *flags)
1232 *flags &= ~LCME_FL_NEG;
1235 static int comp_str2flags(__u32 *flags, char *string)
1238 __u32 neg_flags = 0;
1244 for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1248 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1249 __u32 comp_flag = comp_flags_table[i].cfn_flag;
1250 const char *comp_name = comp_flags_table[i].cfn_name;
1252 if (strcmp(name, comp_name) == 0) {
1253 *flags |= comp_flag;
1255 } else if (strncmp(name, "^", 1) == 0 &&
1256 strcmp(name + 1, comp_name) == 0) {
1257 neg_flags |= comp_flag;
1262 llapi_printf(LLAPI_MSG_ERROR, "Component flag "
1263 "'%s' is not supported.\n", name);
1268 if (*flags == 0 && neg_flags == 0)
1270 /* don't support mixed flags for now */
1271 if (*flags && neg_flags)
1276 comp_flags_set_neg(flags);
1282 static inline bool arg_is_eof(char *arg)
1284 return !strncmp(arg, "-1", strlen("-1")) ||
1285 !strncmp(arg, "EOF", strlen("EOF")) ||
1286 !strncmp(arg, "eof", strlen("eof"));
1301 static int lfs_setstripe(int argc, char **argv)
1303 struct lfs_setstripe_args lsa;
1304 struct llapi_stripe_param *param = NULL;
1305 struct find_param migrate_mdt_param = {
1315 char *mdt_idx_arg = NULL;
1316 unsigned long long size_units = 1;
1317 bool migrate_mode = false;
1318 bool migration_block = false;
1319 __u64 migration_flags = 0;
1320 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1321 int comp_del = 0, comp_set = 0;
1324 struct llapi_layout *layout = NULL;
1326 struct option long_opts[] = {
1327 /* --block is only valid in migrate mode */
1328 { .val = 'b', .name = "block", .has_arg = no_argument},
1329 { .val = LFS_COMP_ADD_OPT,
1330 .name = "comp-add", .has_arg = no_argument},
1331 { .val = LFS_COMP_ADD_OPT,
1332 .name = "component-add",
1333 .has_arg = no_argument},
1334 { .val = LFS_COMP_DEL_OPT,
1335 .name = "comp-del", .has_arg = no_argument},
1336 { .val = LFS_COMP_DEL_OPT,
1337 .name = "component-del",
1338 .has_arg = no_argument},
1339 { .val = LFS_COMP_FLAGS_OPT,
1340 .name = "comp-flags", .has_arg = required_argument},
1341 { .val = LFS_COMP_FLAGS_OPT,
1342 .name = "component-flags",
1343 .has_arg = required_argument},
1344 { .val = LFS_COMP_SET_OPT,
1345 .name = "comp-set", .has_arg = no_argument},
1346 { .val = LFS_COMP_SET_OPT,
1347 .name = "component-set",
1348 .has_arg = no_argument},
1349 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1350 /* This formerly implied "stripe-count", but was explicitly
1351 * made "stripe-count" for consistency with other options,
1352 * and to separate it from "mdt-count" when DNE arrives. */
1353 { .val = 'c', .name = "count", .has_arg = required_argument },
1355 { .val = 'c', .name = "stripe-count", .has_arg = required_argument},
1356 { .val = 'c', .name = "stripe_count", .has_arg = required_argument},
1357 { .val = 'd', .name = "delete", .has_arg = no_argument},
1358 { .val = 'E', .name = "comp-end", .has_arg = required_argument},
1359 { .val = 'E', .name = "component-end",
1360 .has_arg = required_argument},
1361 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1362 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1363 /* This formerly implied "stripe-index", but was explicitly
1364 * made "stripe-index" for consistency with other options,
1365 * and to separate it from "mdt-index" when DNE arrives. */
1366 { .val = 'i', .name = "index", .has_arg = required_argument },
1368 { .val = 'i', .name = "stripe-index", .has_arg = required_argument},
1369 { .val = 'i', .name = "stripe_index", .has_arg = required_argument},
1370 { .val = 'I', .name = "comp-id", .has_arg = required_argument},
1371 { .val = 'I', .name = "component-id", .has_arg = required_argument},
1372 { .val = 'm', .name = "mdt", .has_arg = required_argument},
1373 { .val = 'm', .name = "mdt-index", .has_arg = required_argument},
1374 { .val = 'm', .name = "mdt_index", .has_arg = required_argument},
1375 /* --non-block is only valid in migrate mode */
1376 { .val = 'n', .name = "non-block", .has_arg = no_argument},
1377 { .val = 'o', .name = "ost", .has_arg = required_argument},
1378 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1379 { .val = 'o', .name = "ost-list", .has_arg = required_argument },
1380 { .val = 'o', .name = "ost_list", .has_arg = required_argument },
1382 { .val = 'p', .name = "pool", .has_arg = required_argument },
1383 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1384 /* This formerly implied "--stripe-size", but was confusing
1385 * with "lfs find --size|-s", which means "file size", so use
1386 * the consistent "--stripe-size|-S" for all commands. */
1387 { .val = 's', .name = "size", .has_arg = required_argument },
1389 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1390 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1391 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1392 /* --verbose is only valid in migrate mode */
1393 { .val = 'v', .name = "verbose", .has_arg = no_argument },
1394 { .val = LFS_COMP_ADD_OPT,
1395 .name = "component-add",
1396 .has_arg = no_argument },
1397 { .val = LFS_COMP_DEL_OPT,
1398 .name = "component-del",
1399 .has_arg = no_argument },
1400 { .val = LFS_COMP_FLAGS_OPT,
1401 .name = "component-flags",
1402 .has_arg = required_argument },
1403 { .val = LFS_COMP_SET_OPT,
1404 .name = "component-set",
1405 .has_arg = no_argument },
1408 setstripe_args_init(&lsa);
1410 if (strcmp(argv[0], "migrate") == 0)
1411 migrate_mode = true;
1413 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1414 long_opts, NULL)) >= 0) {
1419 case LFS_COMP_ADD_OPT:
1422 case LFS_COMP_DEL_OPT:
1425 case LFS_COMP_FLAGS_OPT:
1426 result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
1428 fprintf(stderr, "error: %s: bad comp flags "
1429 "'%s'\n", argv[0], optarg);
1433 case LFS_COMP_SET_OPT:
1437 if (!migrate_mode) {
1438 fprintf(stderr, "--block is valid only for"
1442 migration_block = true;
1445 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1446 if (strcmp(argv[optind - 1], "--count") == 0)
1447 fprintf(stderr, "warning: '--count' deprecated"
1448 ", use '--stripe-count' instead\n");
1450 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1452 fprintf(stderr, "error: %s: bad stripe count "
1453 "'%s'\n", argv[0], optarg);
1458 /* delete the default striping pattern */
1462 if (lsa.lsa_comp_end != 0) {
1463 result = comp_args_to_layout(&layout, &lsa);
1467 setstripe_args_init(&lsa);
1470 if (arg_is_eof(optarg)) {
1471 lsa.lsa_comp_end = LUSTRE_EOF;
1473 result = llapi_parse_size(optarg,
1477 fprintf(stderr, "error: %s: "
1478 "bad component end '%s'\n",
1485 if (strcmp(argv[optind - 1], "--index") == 0)
1486 fprintf(stderr, "warning: '--index' deprecated"
1487 ", use '--stripe-index' instead\n");
1488 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1490 fprintf(stderr, "error: %s: bad stripe offset "
1491 "'%s'\n", argv[0], optarg);
1496 comp_id = strtoul(optarg, &end, 0);
1497 if (*end != '\0' || comp_id == 0 ||
1498 comp_id > LCME_ID_MAX) {
1499 fprintf(stderr, "error: %s: bad comp ID "
1500 "'%s'\n", argv[0], optarg);
1505 if (!migrate_mode) {
1506 fprintf(stderr, "--mdt-index is valid only for"
1510 mdt_idx_arg = optarg;
1513 if (!migrate_mode) {
1514 fprintf(stderr, "--non-block is valid only for"
1518 migration_flags |= MIGRATION_NONBLOCK;
1521 lsa.lsa_nr_osts = parse_targets(osts,
1522 sizeof(osts) / sizeof(__u32),
1523 lsa.lsa_nr_osts, optarg);
1524 if (lsa.lsa_nr_osts < 0) {
1526 "error: %s: bad OST indices '%s'\n",
1531 lsa.lsa_osts = osts;
1532 if (lsa.lsa_stripe_off == -1)
1533 lsa.lsa_stripe_off = osts[0];
1538 lsa.lsa_pool_name = optarg;
1540 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1542 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1543 fprintf(stderr, "warning: '--size|-s' deprecated, "
1544 "use '--stripe-size|-S' instead\n");
1546 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1548 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1551 fprintf(stderr, "error: %s: bad stripe size "
1552 "'%s'\n", argv[0], optarg);
1557 if (!migrate_mode) {
1558 fprintf(stderr, "--verbose is valid only for"
1562 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1569 fname = argv[optind];
1571 if (lsa.lsa_comp_end != 0) {
1572 result = comp_args_to_layout(&layout, &lsa);
1577 if (optind == argc) {
1578 fprintf(stderr, "error: %s: missing filename|dirname\n",
1583 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1584 * altered by user space tool, so we don't need to support the
1585 * --component-set for this moment. */
1586 if (comp_set != 0) {
1587 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1592 if ((delete + comp_set + comp_del + comp_add) > 1) {
1593 fprintf(stderr, "error: %s: can't specify --component-set, "
1594 "--component-del, --component-add or -d together\n",
1599 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1600 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1601 fprintf(stderr, "error: %s: can't specify -d with "
1602 "-s, -c, -o, -p, -I, -F or -E options\n",
1607 if ((comp_set || comp_del) &&
1608 (setstripe_args_specified(&lsa) || layout != NULL)) {
1609 fprintf(stderr, "error: %s: can't specify --component-del or "
1610 "--component-set with -s, -c, -o, -p or -E options.\n",
1615 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1616 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1617 "--component-del option.\n", argv[0]);
1621 if (comp_add || comp_del) {
1624 result = lstat(fname, &st);
1625 if (result == 0 && S_ISDIR(st.st_mode)) {
1626 fprintf(stderr, "error: %s: can't use --component-add "
1627 "or --component-del for directory.\n",
1634 if (layout == NULL) {
1635 fprintf(stderr, "error: %s: -E option must be present"
1636 "in --component-add mode.\n", argv[0]);
1639 result = adjust_first_extent(fname, layout);
1640 if (result == -ENODATA)
1642 else if (result != 0)
1646 if (mdt_idx_arg != NULL && optind > 3) {
1647 fprintf(stderr, "error: %s: cannot specify -m with other "
1648 "options\n", argv[0]);
1652 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1654 "error: %s: cannot specify --non-block and --block\n",
1659 if (!comp_del && !comp_set && comp_id != 0) {
1660 fprintf(stderr, "error: %s: -I can only be used with "
1661 "--component-del.\n", argv[0]);
1665 if (mdt_idx_arg != NULL) {
1666 /* initialize migrate mdt parameters */
1667 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1669 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1670 argv[0], mdt_idx_arg);
1673 migrate_mdt_param.fp_migrate = 1;
1674 } else if (layout == NULL) {
1675 /* initialize stripe parameters */
1676 param = calloc(1, offsetof(typeof(*param),
1677 lsp_osts[lsa.lsa_nr_osts]));
1678 if (param == NULL) {
1679 fprintf(stderr, "error: %s: %s\n", argv[0],
1684 param->lsp_stripe_size = lsa.lsa_stripe_size;
1685 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1686 param->lsp_stripe_count = lsa.lsa_stripe_count;
1687 param->lsp_stripe_pattern = 0;
1688 param->lsp_pool = lsa.lsa_pool_name;
1689 param->lsp_is_specific = false;
1690 if (lsa.lsa_nr_osts > 0) {
1691 if (lsa.lsa_stripe_count > 0 &&
1692 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1693 fprintf(stderr, "error: %s: stripe count '%d' "
1694 "doesn't match the number of OSTs: %d\n"
1695 , argv[0], lsa.lsa_stripe_count,
1701 param->lsp_is_specific = true;
1702 param->lsp_stripe_count = lsa.lsa_nr_osts;
1703 memcpy(param->lsp_osts, osts,
1704 sizeof(*osts) * lsa.lsa_nr_osts);
1708 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1710 if (mdt_idx_arg != NULL) {
1711 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1712 op = "migrate mdt objects of";
1713 } else if (migrate_mode) {
1714 result = lfs_migrate(fname, migration_flags, param,
1716 op = "migrate ost objects of";
1717 } else if (comp_set != 0) {
1718 result = lfs_component_set(fname, comp_id,
1719 lsa.lsa_comp_flags);
1720 op = "modify component flags of";
1721 } else if (comp_del != 0) {
1722 result = lfs_component_del(fname, comp_id,
1723 lsa.lsa_comp_flags);
1724 op = "delete component of";
1725 } else if (comp_add != 0) {
1726 result = lfs_component_add(fname, layout);
1727 op = "add component to";
1728 } else if (layout != NULL) {
1729 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1735 op = "create composite";
1737 result = llapi_file_open_param(fname,
1744 op = "create striped";
1747 /* Save the first error encountered. */
1750 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1752 lsa.lsa_pool_name != NULL && result == EINVAL ?
1753 "OST not in pool?" : strerror(errno));
1759 llapi_layout_free(layout);
1762 llapi_layout_free(layout);
1766 static int lfs_poollist(int argc, char **argv)
1771 return llapi_poollist(argv[1]);
1774 static int set_time(time_t *time, time_t *set, char *str)
1781 else if (str[0] == '-')
1787 t = strtol(str, NULL, 0);
1788 if (*time < t * 24 * 60 * 60) {
1791 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1795 *set = *time - t * 24 * 60 * 60;
1798 static int name2uid(unsigned int *id, const char *name)
1800 struct passwd *passwd;
1802 passwd = getpwnam(name);
1805 *id = passwd->pw_uid;
1810 static int name2gid(unsigned int *id, const char *name)
1812 struct group *group;
1814 group = getgrnam(name);
1817 *id = group->gr_gid;
1822 static inline int name2projid(unsigned int *id, const char *name)
1827 static int uid2name(char **name, unsigned int id)
1829 struct passwd *passwd;
1831 passwd = getpwuid(id);
1834 *name = passwd->pw_name;
1839 static inline int gid2name(char **name, unsigned int id)
1841 struct group *group;
1843 group = getgrgid(id);
1846 *name = group->gr_name;
1851 static int name2layout(__u32 *layout, char *name)
1856 for (ptr = name; ; ptr = NULL) {
1857 lyt = strtok(ptr, ",");
1860 if (strcmp(lyt, "released") == 0)
1861 *layout |= LOV_PATTERN_F_RELEASED;
1862 else if (strcmp(lyt, "raid0") == 0)
1863 *layout |= LOV_PATTERN_RAID0;
1870 static int lfs_find(int argc, char **argv)
1875 struct find_param param = {
1879 struct option long_opts[] = {
1880 { .val = 'A', .name = "atime", .has_arg = required_argument },
1881 { .val = LFS_COMP_COUNT_OPT,
1882 .name = "comp-count", .has_arg = required_argument },
1883 { .val = LFS_COMP_COUNT_OPT,
1884 .name = "component-count",
1885 .has_arg = required_argument },
1886 { .val = LFS_COMP_FLAGS_OPT,
1887 .name = "comp-flags", .has_arg = required_argument },
1888 { .val = LFS_COMP_FLAGS_OPT,
1889 .name = "component-flags",
1890 .has_arg = required_argument },
1891 { .val = LFS_COMP_START_OPT,
1892 .name = "comp-start", .has_arg = required_argument },
1893 { .val = LFS_COMP_START_OPT,
1894 .name = "component-start",
1895 .has_arg = required_argument },
1896 { .val = 'c', .name = "stripe-count", .has_arg = required_argument },
1897 { .val = 'c', .name = "stripe_count", .has_arg = required_argument },
1898 { .val = 'C', .name = "ctime", .has_arg = required_argument },
1899 { .val = 'D', .name = "maxdepth", .has_arg = required_argument },
1900 { .val = 'E', .name = "comp-end", .has_arg = required_argument },
1901 { .val = 'E', .name = "component-end",
1902 .has_arg = required_argument },
1903 { .val = 'g', .name = "gid", .has_arg = required_argument },
1904 { .val = 'G', .name = "group", .has_arg = required_argument },
1905 { .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
1906 { .val = 'i', .name = "stripe-index", .has_arg = required_argument },
1907 { .val = 'i', .name = "stripe_index", .has_arg = required_argument },
1908 /*{"component-id", required_argument, 0, 'I'},*/
1909 { .val = 'L', .name = "layout", .has_arg = required_argument },
1910 { .val = 'm', .name = "mdt", .has_arg = required_argument },
1911 { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
1912 { .val = 'm', .name = "mdt_index", .has_arg = required_argument },
1913 { .val = 'M', .name = "mtime", .has_arg = required_argument },
1914 { .val = 'n', .name = "name", .has_arg = required_argument },
1915 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1916 { .val = 'O', .name = "obd", .has_arg = required_argument },
1917 { .val = 'O', .name = "ost", .has_arg = required_argument },
1918 /* no short option for pool, p/P already used */
1919 { .val = LFS_POOL_OPT,
1920 .name = "pool", .has_arg = required_argument },
1921 { .val = 'p', .name = "print0", .has_arg = no_argument },
1922 { .val = 'P', .name = "print", .has_arg = no_argument },
1923 { .val = LFS_PROJID_OPT,
1924 .name = "projid", .has_arg = required_argument },
1925 { .val = 's', .name = "size", .has_arg = required_argument },
1926 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1927 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1928 { .val = 't', .name = "type", .has_arg = required_argument },
1929 { .val = 'T', .name = "mdt-count", .has_arg = required_argument },
1930 { .val = 'u', .name = "uid", .has_arg = required_argument },
1931 { .val = 'U', .name = "user", .has_arg = required_argument },
1943 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1944 while ((c = getopt_long_only(argc, argv,
1945 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1946 long_opts, NULL)) >= 0) {
1951 /* '!' is part of option */
1952 /* when getopt_long_only() finds a string which is not
1953 * an option nor a known option argument it returns 1
1954 * in that case if we already have found pathstart and pathend
1955 * (i.e. we have the list of pathnames),
1956 * the only supported value is "!"
1958 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1959 if (!isoption && pathend != -1) {
1960 fprintf(stderr, "err: %s: filename|dirname must either "
1961 "precede options or follow options\n",
1966 if (!isoption && pathstart == -1)
1967 pathstart = optind - 1;
1968 if (isoption && pathstart != -1 && pathend == -1)
1969 pathend = optind - 2;
1975 /* unknown; opt is "!" or path component,
1976 * checking done above.
1978 if (strcmp(optarg, "!") == 0)
1982 xtime = ¶m.fp_atime;
1983 xsign = ¶m.fp_asign;
1984 param.fp_exclude_atime = !!neg_opt;
1985 /* no break, this falls through to 'C' for ctime */
1988 xtime = ¶m.fp_ctime;
1989 xsign = ¶m.fp_csign;
1990 param.fp_exclude_ctime = !!neg_opt;
1992 /* no break, this falls through to 'M' for mtime */
1995 xtime = ¶m.fp_mtime;
1996 xsign = ¶m.fp_msign;
1997 param.fp_exclude_mtime = !!neg_opt;
1999 rc = set_time(&t, xtime, optarg);
2000 if (rc == INT_MAX) {
2007 case LFS_COMP_COUNT_OPT:
2008 if (optarg[0] == '+') {
2009 param.fp_comp_count_sign = -1;
2011 } else if (optarg[0] == '-') {
2012 param.fp_comp_count_sign = 1;
2016 param.fp_comp_count = strtoul(optarg, &endptr, 0);
2017 if (*endptr != '\0') {
2018 fprintf(stderr, "error: bad component count "
2022 param.fp_check_comp_count = 1;
2023 param.fp_exclude_comp_count = !!neg_opt;
2025 case LFS_COMP_FLAGS_OPT:
2026 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
2027 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2028 fprintf(stderr, "error: bad component flags "
2032 param.fp_check_comp_flags = 1;
2033 param.fp_exclude_comp_flags = !!neg_opt;
2035 case LFS_COMP_START_OPT:
2036 if (optarg[0] == '+') {
2037 param.fp_comp_start_sign = -1;
2039 } else if (optarg[0] == '-') {
2040 param.fp_comp_start_sign = 1;
2044 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2045 ¶m.fp_comp_start_units, 0);
2047 fprintf(stderr, "error: bad component start "
2051 param.fp_check_comp_start = 1;
2052 param.fp_exclude_comp_start = !!neg_opt;
2055 if (optarg[0] == '+') {
2056 param.fp_stripe_count_sign = -1;
2058 } else if (optarg[0] == '-') {
2059 param.fp_stripe_count_sign = 1;
2063 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2064 if (*endptr != '\0') {
2065 fprintf(stderr,"error: bad stripe_count '%s'\n",
2070 param.fp_check_stripe_count = 1;
2071 param.fp_exclude_stripe_count = !!neg_opt;
2074 param.fp_max_depth = strtol(optarg, 0, 0);
2077 if (optarg[0] == '+') {
2078 param.fp_comp_end_sign = -1;
2080 } else if (optarg[0] == '-') {
2081 param.fp_comp_end_sign = 1;
2085 if (arg_is_eof(optarg)) {
2086 param.fp_comp_end = LUSTRE_EOF;
2087 param.fp_comp_end_units = 1;
2090 rc = llapi_parse_size(optarg,
2092 ¶m.fp_comp_end_units, 0);
2095 fprintf(stderr, "error: bad component end "
2099 param.fp_check_comp_end = 1;
2100 param.fp_exclude_comp_end = !!neg_opt;
2104 rc = name2gid(¶m.fp_gid, optarg);
2106 param.fp_gid = strtoul(optarg, &endptr, 10);
2107 if (*endptr != '\0') {
2108 fprintf(stderr, "Group/GID: %s cannot "
2109 "be found.\n", optarg);
2114 param.fp_exclude_gid = !!neg_opt;
2115 param.fp_check_gid = 1;
2118 param.fp_hash_type = check_hashtype(optarg);
2119 if (param.fp_hash_type == 0) {
2120 fprintf(stderr, "error: bad hash_type '%s'\n",
2125 param.fp_check_hash_type = 1;
2126 param.fp_exclude_hash_type = !!neg_opt;
2129 ret = name2layout(¶m.fp_layout, optarg);
2132 param.fp_exclude_layout = !!neg_opt;
2133 param.fp_check_layout = 1;
2137 rc = name2uid(¶m.fp_uid, optarg);
2139 param.fp_uid = strtoul(optarg, &endptr, 10);
2140 if (*endptr != '\0') {
2141 fprintf(stderr, "User/UID: %s cannot "
2142 "be found.\n", optarg);
2147 param.fp_exclude_uid = !!neg_opt;
2148 param.fp_check_uid = 1;
2151 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2153 "Pool name %s is too long"
2154 " (max is %d)\n", optarg,
2159 /* we do check for empty pool because empty pool
2160 * is used to find V1 lov attributes */
2161 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2162 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2163 param.fp_exclude_pool = !!neg_opt;
2164 param.fp_check_pool = 1;
2167 param.fp_pattern = (char *)optarg;
2168 param.fp_exclude_pattern = !!neg_opt;
2173 char *buf, *token, *next, *p;
2177 buf = strdup(optarg);
2183 param.fp_exclude_obd = !!neg_opt;
2186 while (token && *token) {
2187 token = strchr(token, ',');
2194 param.fp_exclude_mdt = !!neg_opt;
2195 param.fp_num_alloc_mdts += len;
2196 tmp = realloc(param.fp_mdt_uuid,
2197 param.fp_num_alloc_mdts *
2198 sizeof(*param.fp_mdt_uuid));
2204 param.fp_mdt_uuid = tmp;
2206 param.fp_exclude_obd = !!neg_opt;
2207 param.fp_num_alloc_obds += len;
2208 tmp = realloc(param.fp_obd_uuid,
2209 param.fp_num_alloc_obds *
2210 sizeof(*param.fp_obd_uuid));
2216 param.fp_obd_uuid = tmp;
2218 for (token = buf; token && *token; token = next) {
2219 struct obd_uuid *puuid;
2222 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2225 ¶m.fp_obd_uuid[param.fp_num_obds++];
2227 p = strchr(token, ',');
2234 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2239 strncpy(puuid->uuid, token,
2240 sizeof(puuid->uuid));
2248 param.fp_zero_end = 1;
2252 case LFS_PROJID_OPT:
2253 rc = name2projid(¶m.fp_projid, optarg);
2255 param.fp_projid = strtoul(optarg, &endptr, 10);
2256 if (*endptr != '\0') {
2258 "Invalid project ID: %s",
2264 param.fp_exclude_projid = !!neg_opt;
2265 param.fp_check_projid = 1;
2268 if (optarg[0] == '+') {
2269 param.fp_size_sign = -1;
2271 } else if (optarg[0] == '-') {
2272 param.fp_size_sign = 1;
2276 ret = llapi_parse_size(optarg, ¶m.fp_size,
2277 ¶m.fp_size_units, 0);
2279 fprintf(stderr, "error: bad file size '%s'\n",
2283 param.fp_check_size = 1;
2284 param.fp_exclude_size = !!neg_opt;
2287 if (optarg[0] == '+') {
2288 param.fp_stripe_size_sign = -1;
2290 } else if (optarg[0] == '-') {
2291 param.fp_stripe_size_sign = 1;
2295 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2296 ¶m.fp_stripe_size_units, 0);
2298 fprintf(stderr, "error: bad stripe_size '%s'\n",
2302 param.fp_check_stripe_size = 1;
2303 param.fp_exclude_stripe_size = !!neg_opt;
2306 param.fp_exclude_type = !!neg_opt;
2307 switch (optarg[0]) {
2309 param.fp_type = S_IFBLK;
2312 param.fp_type = S_IFCHR;
2315 param.fp_type = S_IFDIR;
2318 param.fp_type = S_IFREG;
2321 param.fp_type = S_IFLNK;
2324 param.fp_type = S_IFIFO;
2327 param.fp_type = S_IFSOCK;
2330 fprintf(stderr, "error: %s: bad type '%s'\n",
2337 if (optarg[0] == '+') {
2338 param.fp_mdt_count_sign = -1;
2340 } else if (optarg[0] == '-') {
2341 param.fp_mdt_count_sign = 1;
2345 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2346 if (*endptr != '\0') {
2347 fprintf(stderr, "error: bad mdt_count '%s'\n",
2352 param.fp_check_mdt_count = 1;
2353 param.fp_exclude_mdt_count = !!neg_opt;
2361 if (pathstart == -1) {
2362 fprintf(stderr, "error: %s: no filename|pathname\n",
2366 } else if (pathend == -1) {
2372 rc = llapi_find(argv[pathstart], ¶m);
2373 if (rc != 0 && ret == 0)
2375 } while (++pathstart < pathend);
2378 fprintf(stderr, "error: %s failed for %s.\n",
2379 argv[0], argv[optind - 1]);
2381 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2382 free(param.fp_obd_uuid);
2384 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2385 free(param.fp_mdt_uuid);
2390 static int lfs_getstripe_internal(int argc, char **argv,
2391 struct find_param *param)
2393 struct option long_opts[] = {
2394 { .val = LFS_COMP_COUNT_OPT,
2395 .name = "comp-count", .has_arg = no_argument },
2396 { .val = LFS_COMP_COUNT_OPT,
2397 .name = "component-count", .has_arg = no_argument },
2398 { .val = LFS_COMP_FLAGS_OPT,
2399 .name = "comp-flags", .has_arg = optional_argument },
2400 { .val = LFS_COMP_FLAGS_OPT,
2401 .name = "component-flags", .has_arg = optional_argument },
2402 { .val = LFS_COMP_START_OPT,
2403 .name = "comp-start", .has_arg = optional_argument },
2404 { .val = LFS_COMP_START_OPT,
2405 .name = "component-start", .has_arg = optional_argument },
2406 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2407 /* This formerly implied "stripe-count", but was explicitly
2408 * made "stripe-count" for consistency with other options,
2409 * and to separate it from "mdt-count" when DNE arrives. */
2410 { .val = 'c', .name = "count", .has_arg = no_argument },
2412 { .val = 'c', .name = "stripe-count", .has_arg = no_argument },
2413 { .val = 'c', .name = "stripe_count", .has_arg = no_argument },
2414 { .val = 'd', .name = "directory", .has_arg = no_argument },
2415 { .val = 'D', .name = "default", .has_arg = no_argument },
2416 { .val = 'E', .name = "comp-end", .has_arg = optional_argument },
2417 { .val = 'E', .name = "component-end",
2418 .has_arg = optional_argument },
2419 { .val = 'F', .name = "fid", .has_arg = no_argument },
2420 { .val = 'g', .name = "generation", .has_arg = no_argument },
2421 /* dirstripe { .val = 'H', .name = "mdt-hash",
2422 * .has_arg = required_argument }, */
2423 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2424 /* This formerly implied "stripe-index", but was explicitly
2425 * made "stripe-index" for consistency with other options,
2426 * and to separate it from "mdt-index" when DNE arrives. */
2427 { .val = 'i', .name = "index", .has_arg = no_argument },
2429 { .val = 'i', .name = "stripe-index", .has_arg = no_argument },
2430 { .val = 'i', .name = "stripe_index", .has_arg = no_argument },
2431 { .val = 'I', .name = "comp-id", .has_arg = optional_argument },
2432 { .val = 'I', .name = "component-id", .has_arg = optional_argument },
2433 { .val = 'L', .name = "layout", .has_arg = no_argument },
2434 { .val = 'm', .name = "mdt", .has_arg = no_argument },
2435 { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
2436 { .val = 'm', .name = "mdt_index", .has_arg = no_argument },
2437 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2438 { .val = 'M', .name = "mdt-index", .has_arg = no_argument },
2439 { .val = 'M', .name = "mdt_index", .has_arg = no_argument },
2441 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2442 /* This formerly implied "stripe-index", but was confusing
2443 * with "file offset" (which will eventually be needed for
2444 * with different layouts by offset), so deprecate it. */
2445 { .val = 'o', .name = "offset", .has_arg = no_argument },
2447 { .val = 'O', .name = "obd", .has_arg = required_argument },
2448 { .val = 'O', .name = "ost", .has_arg = required_argument },
2449 { .val = 'p', .name = "pool", .has_arg = no_argument },
2450 { .val = 'q', .name = "quiet", .has_arg = no_argument },
2451 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2452 { .val = 'R', .name = "raw", .has_arg = no_argument },
2453 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2454 /* This formerly implied "--stripe-size", but was confusing
2455 * with "lfs find --size|-s", which means "file size", so use
2456 * the consistent "--stripe-size|-S" for all commands. */
2457 { .val = 's', .name = "size", .has_arg = no_argument },
2459 { .val = 'S', .name = "stripe-size", .has_arg = no_argument },
2460 { .val = 'S', .name = "stripe_size", .has_arg = no_argument },
2461 /* dirstripe { .val = 'T', .name = "mdt-count",
2462 * .has_arg = required_argument }, */
2463 { .val = 'v', .name = "verbose", .has_arg = no_argument },
2464 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2469 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2470 long_opts, NULL)) != -1) {
2473 if (strcmp(argv[optind - 1], "--count") == 0)
2474 fprintf(stderr, "warning: '--count' deprecated,"
2475 " use '--stripe-count' instead\n");
2476 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2477 param->fp_verbose |= VERBOSE_COUNT;
2478 param->fp_max_depth = 0;
2481 case LFS_COMP_COUNT_OPT:
2482 param->fp_verbose |= VERBOSE_COMP_COUNT;
2483 param->fp_max_depth = 0;
2485 case LFS_COMP_FLAGS_OPT:
2486 if (optarg != NULL) {
2487 __u32 *flags = ¶m->fp_comp_flags;
2488 rc = comp_str2flags(flags, optarg);
2490 fprintf(stderr, "error: %s bad "
2491 "component flags '%s'.\n",
2495 param->fp_check_comp_flags = 1;
2496 param->fp_exclude_comp_flags =
2497 comp_flags_is_neg(*flags);
2498 comp_flags_clear_neg(flags);
2501 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2502 param->fp_max_depth = 0;
2505 case LFS_COMP_START_OPT:
2506 if (optarg != NULL) {
2508 if (tmp[0] == '+') {
2509 param->fp_comp_start_sign = -1;
2511 } else if (tmp[0] == '-') {
2512 param->fp_comp_start_sign = 1;
2515 rc = llapi_parse_size(tmp,
2516 ¶m->fp_comp_start,
2517 ¶m->fp_comp_start_units, 0);
2519 fprintf(stderr, "error: %s bad "
2520 "component start '%s'.\n",
2524 param->fp_check_comp_start = 1;
2527 param->fp_verbose |= VERBOSE_COMP_START;
2528 param->fp_max_depth = 0;
2532 param->fp_max_depth = 0;
2535 param->fp_get_default_lmv = 1;
2538 if (optarg != NULL) {
2540 if (tmp[0] == '+') {
2541 param->fp_comp_end_sign = -1;
2543 } else if (tmp[0] == '-') {
2544 param->fp_comp_end_sign = 1;
2548 if (arg_is_eof(tmp)) {
2549 param->fp_comp_end = LUSTRE_EOF;
2550 param->fp_comp_end_units = 1;
2553 rc = llapi_parse_size(tmp,
2554 ¶m->fp_comp_end,
2555 ¶m->fp_comp_end_units, 0);
2558 fprintf(stderr, "error: %s bad "
2559 "component end '%s'.\n",
2563 param->fp_check_comp_end = 1;
2565 param->fp_verbose |= VERBOSE_COMP_END;
2566 param->fp_max_depth = 0;
2570 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2571 param->fp_verbose |= VERBOSE_DFID;
2572 param->fp_max_depth = 0;
2576 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2577 param->fp_verbose |= VERBOSE_GENERATION;
2578 param->fp_max_depth = 0;
2581 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2583 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2584 "use '--stripe-index|-i' instead\n");
2587 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2588 if (strcmp(argv[optind - 1], "--index") == 0)
2589 fprintf(stderr, "warning: '--index' deprecated"
2590 ", use '--stripe-index' instead\n");
2592 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2593 param->fp_verbose |= VERBOSE_OFFSET;
2594 param->fp_max_depth = 0;
2598 if (optarg != NULL) {
2599 param->fp_comp_id = strtoul(optarg, &end, 0);
2600 if (*end != '\0' || param->fp_comp_id == 0 ||
2601 param->fp_comp_id > LCME_ID_MAX) {
2602 fprintf(stderr, "error: %s bad "
2603 "component id '%s'\n",
2607 param->fp_check_comp_id = 1;
2610 param->fp_max_depth = 0;
2611 param->fp_verbose |= VERBOSE_COMP_ID;
2615 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2616 param->fp_verbose |= VERBOSE_LAYOUT;
2617 param->fp_max_depth = 0;
2620 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2622 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2623 fprintf(stderr, "warning: '-M' deprecated"
2624 ", use '-m' instead\n");
2628 if (!(param->fp_verbose & VERBOSE_DETAIL))
2629 param->fp_max_depth = 0;
2630 param->fp_verbose |= VERBOSE_MDTINDEX;
2633 if (param->fp_obd_uuid) {
2635 "error: %s: only one obduuid allowed",
2639 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2642 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2643 param->fp_verbose |= VERBOSE_POOL;
2644 param->fp_max_depth = 0;
2651 param->fp_recursive = 1;
2656 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2658 fprintf(stderr, "warning: '--size|-s' deprecated, "
2659 "use '--stripe-size|-S' instead\n");
2660 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2662 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2663 param->fp_verbose |= VERBOSE_SIZE;
2664 param->fp_max_depth = 0;
2668 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2681 if (param->fp_recursive)
2682 param->fp_max_depth = -1;
2683 else if (param->fp_verbose & VERBOSE_DETAIL)
2684 param->fp_max_depth = 1;
2686 if (!param->fp_verbose)
2687 param->fp_verbose = VERBOSE_DEFAULT;
2688 if (param->fp_quiet)
2689 param->fp_verbose = VERBOSE_OBJID;
2692 rc = llapi_getstripe(argv[optind], param);
2693 } while (++optind < argc && !rc);
2696 fprintf(stderr, "error: %s failed for %s.\n",
2697 argv[0], argv[optind - 1]);
2701 static int lfs_tgts(int argc, char **argv)
2703 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2704 struct find_param param;
2705 int index = 0, rc=0;
2710 if (argc == 2 && !realpath(argv[1], path)) {
2712 fprintf(stderr, "error: invalid path '%s': %s\n",
2713 argv[1], strerror(-rc));
2717 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2718 /* Check if we have a mount point */
2719 if (mntdir[0] == '\0')
2722 memset(¶m, 0, sizeof(param));
2723 if (!strcmp(argv[0], "mdts"))
2724 param.fp_get_lmv = 1;
2726 rc = llapi_ostlist(mntdir, ¶m);
2728 fprintf(stderr, "error: %s: failed on %s\n",
2731 if (path[0] != '\0')
2733 memset(mntdir, 0, PATH_MAX);
2739 static int lfs_getstripe(int argc, char **argv)
2741 struct find_param param = { 0 };
2743 param.fp_max_depth = 1;
2744 return lfs_getstripe_internal(argc, argv, ¶m);
2748 static int lfs_getdirstripe(int argc, char **argv)
2750 struct find_param param = { 0 };
2751 struct option long_opts[] = {
2752 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2753 { .val = 'c', .name = "mdt-count", .has_arg = no_argument },
2755 { .val = 'D', .name = "default", .has_arg = no_argument },
2756 { .val = 'H', .name = "mdt-hash", .has_arg = no_argument },
2757 { .val = 'i', .name = "mdt-index", .has_arg = no_argument },
2758 { .val = 'O', .name = "obd", .has_arg = required_argument },
2759 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2760 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2761 { .val = 't', .name = "mdt-hash", .has_arg = no_argument },
2763 { .val = 'T', .name = "mdt-count", .has_arg = no_argument },
2764 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2768 param.fp_get_lmv = 1;
2770 while ((c = getopt_long(argc, argv,
2771 "cDHiO:rtTy", long_opts, NULL)) != -1)
2775 if (param.fp_obd_uuid) {
2777 "error: %s: only one obduuid allowed",
2781 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2783 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2785 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2786 fprintf(stderr, "warning: '-c' deprecated"
2787 ", use '-T' instead\n");
2791 param.fp_verbose |= VERBOSE_COUNT;
2794 param.fp_verbose |= VERBOSE_OFFSET;
2796 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2800 param.fp_verbose |= VERBOSE_HASH_TYPE;
2803 param.fp_get_default_lmv = 1;
2806 param.fp_recursive = 1;
2819 if (param.fp_recursive)
2820 param.fp_max_depth = -1;
2822 if (!param.fp_verbose)
2823 param.fp_verbose = VERBOSE_DEFAULT;
2826 rc = llapi_getstripe(argv[optind], ¶m);
2827 } while (++optind < argc && !rc);
2830 fprintf(stderr, "error: %s failed for %s.\n",
2831 argv[0], argv[optind - 1]);
2836 static int lfs_setdirstripe(int argc, char **argv)
2840 unsigned int stripe_offset = -1;
2841 unsigned int stripe_count = 1;
2842 enum lmv_hash_type hash_type;
2845 char *stripe_offset_opt = NULL;
2846 char *stripe_count_opt = NULL;
2847 char *stripe_hash_opt = NULL;
2848 char *mode_opt = NULL;
2849 bool default_stripe = false;
2850 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2851 mode_t previous_mode = 0;
2852 bool delete = false;
2854 struct option long_opts[] = {
2855 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2856 { .val = 'c', .name = "count", .has_arg = required_argument },
2858 { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
2859 { .val = 'd', .name = "delete", .has_arg = no_argument },
2860 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2861 { .val = 'i', .name = "index", .has_arg = required_argument },
2863 { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
2864 { .val = 'm', .name = "mode", .has_arg = required_argument },
2865 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2866 { .val = 't', .name = "hash-type", .has_arg = required_argument },
2867 { .val = 't', .name = "mdt-hash", .has_arg = required_argument },
2869 {"mdt-hash", required_argument, 0, 'H'},
2870 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2871 { .val = 'D', .name = "default_stripe",
2872 .has_arg = no_argument },
2874 { .val = 'D', .name = "default", .has_arg = no_argument },
2877 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2884 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2885 if (strcmp(argv[optind - 1], "--count") == 0)
2887 "%s %s: warning: '--count' deprecated, use '--mdt-count' instead\n",
2890 stripe_count_opt = optarg;
2894 default_stripe = true;
2897 default_stripe = true;
2900 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2901 if (strcmp(argv[optind - 1], "--index") == 0)
2903 "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
2906 stripe_offset_opt = optarg;
2911 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2915 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2916 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2918 "%s %s: warning: '--hash-type' deprecated, use '--mdt-hash' instead\n",
2921 stripe_hash_opt = optarg;
2924 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
2925 progname, argv[0], argv[optind - 1]);
2930 if (optind == argc) {
2931 fprintf(stderr, "%s %s: DIR must be specified\n",
2936 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2938 "%s %s: stripe offset and count must be specified\n",
2943 if (stripe_offset_opt != NULL) {
2944 /* get the stripe offset */
2945 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2948 "%s %s: bad stripe offset '%s'\n",
2949 progname, argv[0], stripe_offset_opt);
2955 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2957 "%s %s: cannot specify -d with -c or -i options\n",
2966 if (mode_opt != NULL) {
2967 mode = strtoul(mode_opt, &end, 8);
2970 "%s %s: bad MODE '%s'\n",
2971 progname, argv[0], mode_opt);
2974 previous_mode = umask(0);
2977 if (stripe_hash_opt == NULL) {
2978 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2980 hash_type = check_hashtype(stripe_hash_opt);
2981 if (hash_type == 0) {
2982 fprintf(stderr, "%s %s: bad stripe hash type '%s'\n",
2983 progname, argv[0], stripe_hash_opt);
2988 /* get the stripe count */
2989 if (stripe_count_opt != NULL) {
2990 stripe_count = strtoul(stripe_count_opt, &end, 0);
2993 "%s %s: bad stripe count '%s'\n",
2994 progname, argv[0], stripe_count_opt);
2999 dname = argv[optind];
3001 if (default_stripe) {
3002 result = llapi_dir_set_default_lmv_stripe(dname,
3003 stripe_offset, stripe_count,
3006 result = llapi_dir_create_pool(dname, mode,
3008 stripe_count, hash_type,
3014 "%s setdirstripe: cannot create stripe dir '%s': %s\n",
3015 progname, dname, strerror(-result));
3018 dname = argv[++optind];
3019 } while (dname != NULL);
3021 if (mode_opt != NULL)
3022 umask(previous_mode);
3028 static int lfs_rmentry(int argc, char **argv)
3035 fprintf(stderr, "error: %s: missing dirname\n",
3041 dname = argv[index];
3042 while (dname != NULL) {
3043 result = llapi_direntry_remove(dname);
3045 fprintf(stderr, "error: %s: remove dir entry '%s' "
3046 "failed\n", argv[0], dname);
3049 dname = argv[++index];
3054 static int lfs_mv(int argc, char **argv)
3056 struct find_param param = {
3063 struct option long_opts[] = {
3064 { .val = 'M', .name = "mdt-index", .has_arg = required_argument },
3065 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3068 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3071 param.fp_mdt_index = strtoul(optarg, &end, 0);
3073 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3080 param.fp_verbose = VERBOSE_DETAIL;
3084 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3085 argv[0], argv[optind - 1]);
3090 if (param.fp_mdt_index == -1) {
3091 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3095 if (optind >= argc) {
3096 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3100 param.fp_migrate = 1;
3101 rc = llapi_migrate_mdt(argv[optind], ¶m);
3103 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3104 argv[0], argv[optind], param.fp_mdt_index,
3109 static int lfs_osts(int argc, char **argv)
3111 return lfs_tgts(argc, argv);
3114 static int lfs_mdts(int argc, char **argv)
3116 return lfs_tgts(argc, argv);
3119 #define COOK(value) \
3122 while (value > 1024) { \
3130 #define CDF "%11llu"
3131 #define HDF "%8.1f%c"
3136 MNTDF_INODES = 0x0001,
3137 MNTDF_COOKED = 0x0002,
3138 MNTDF_LAZY = 0x0004,
3139 MNTDF_VERBOSE = 0x0008,
3142 static int showdf(char *mntdir, struct obd_statfs *stat,
3143 char *uuid, enum mntdf_flags flags,
3144 char *type, int index, int rc)
3146 long long avail, used, total;
3148 char *suffix = "KMGTPEZY";
3149 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3150 char tbuf[3 * sizeof(__u64)];
3151 char ubuf[3 * sizeof(__u64)];
3152 char abuf[3 * sizeof(__u64)];
3153 char rbuf[3 * sizeof(__u64)];
3160 if (flags & MNTDF_INODES) {
3161 avail = stat->os_ffree;
3162 used = stat->os_files - stat->os_ffree;
3163 total = stat->os_files;
3165 int shift = flags & MNTDF_COOKED ? 0 : 10;
3167 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3168 used = ((stat->os_blocks - stat->os_bfree) *
3169 stat->os_bsize) >> shift;
3170 total = (stat->os_blocks * stat->os_bsize) >> shift;
3173 if ((used + avail) > 0)
3174 ratio = (double)used / (double)(used + avail);
3176 if (flags & MNTDF_COOKED) {
3180 cook_val = (double)total;
3183 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3186 snprintf(tbuf, sizeof(tbuf), CDF, total);
3188 cook_val = (double)used;
3191 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3194 snprintf(ubuf, sizeof(ubuf), CDF, used);
3196 cook_val = (double)avail;
3199 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3202 snprintf(abuf, sizeof(abuf), CDF, avail);
3204 snprintf(tbuf, sizeof(tbuf), CDF, total);
3205 snprintf(ubuf, sizeof(tbuf), CDF, used);
3206 snprintf(abuf, sizeof(tbuf), CDF, avail);
3209 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3210 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3211 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3213 printf("[%s:%d]", type, index);
3215 if (stat->os_state) {
3217 * Each character represents the matching
3220 const char state_names[] = "DRSI";
3225 for (i = 0, state = stat->os_state;
3226 state && i < sizeof(state_names); i++) {
3227 if (!(state & (1 << i)))
3229 printf("%c", state_names[i]);
3237 printf(UUF": inactive device\n", uuid);
3240 printf(UUF": %s\n", uuid, strerror(-rc));
3247 struct ll_stat_type {
3252 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3254 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3255 struct obd_uuid uuid_buf;
3256 char *poolname = NULL;
3257 struct ll_stat_type types[] = {
3258 { .st_op = LL_STATFS_LMV, .st_name = "MDT" },
3259 { .st_op = LL_STATFS_LOV, .st_name = "OST" },
3260 { .st_name = NULL } };
3261 struct ll_stat_type *tp;
3262 __u64 ost_ffree = 0;
3270 poolname = strchr(pool, '.');
3271 if (poolname != NULL) {
3272 if (strncmp(fsname, pool, strlen(fsname))) {
3273 fprintf(stderr, "filesystem name incorrect\n");
3281 fd = open(mntdir, O_RDONLY);
3284 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3289 if (flags & MNTDF_INODES)
3290 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3291 "UUID", "Inodes", "IUsed", "IFree",
3292 "IUse%", "Mounted on");
3294 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3295 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3296 "Used", "Available", "Use%", "Mounted on");
3298 for (tp = types; tp->st_name != NULL; tp++) {
3299 for (index = 0; ; index++) {
3300 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3301 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3302 type = flags & MNTDF_LAZY ?
3303 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3304 rc2 = llapi_obd_fstatfs(fd, type, index,
3305 &stat_buf, &uuid_buf);
3310 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3311 if (!(flags & MNTDF_VERBOSE))
3313 } else if (rc2 < 0 && rc == 0) {
3317 if (poolname && tp->st_op == LL_STATFS_LOV &&
3318 llapi_search_ost(fsname, poolname,
3319 obd_uuid2str(&uuid_buf)) != 1)
3322 /* the llapi_obd_statfs() call may have returned with
3323 * an error, but if it filled in uuid_buf we will at
3324 * lease use that to print out a message for that OBD.
3325 * If we didn't get anything in the uuid_buf, then fill
3326 * it in so that we can print an error message. */
3327 if (uuid_buf.uuid[0] == '\0')
3328 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3329 "%s%04x", tp->st_name, index);
3330 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3331 flags, tp->st_name, index, rc2);
3334 if (tp->st_op == LL_STATFS_LMV) {
3335 sum.os_ffree += stat_buf.os_ffree;
3336 sum.os_files += stat_buf.os_files;
3337 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3338 sum.os_blocks += stat_buf.os_blocks *
3340 sum.os_bfree += stat_buf.os_bfree *
3342 sum.os_bavail += stat_buf.os_bavail *
3344 ost_ffree += stat_buf.os_ffree;
3352 /* If we don't have as many objects free on the OST as inodes
3353 * on the MDS, we reduce the total number of inodes to
3354 * compensate, so that the "inodes in use" number is correct.
3355 * Matches ll_statfs_internal() so the results are consistent. */
3356 if (ost_ffree < sum.os_ffree) {
3357 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3358 sum.os_ffree = ost_ffree;
3361 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3367 static int lfs_df(int argc, char **argv)
3369 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3370 enum mntdf_flags flags = 0;
3371 int c, rc = 0, index = 0;
3372 char fsname[PATH_MAX] = "", *pool_name = NULL;
3373 struct option long_opts[] = {
3374 { .val = 'h', .name = "human-readable",
3375 .has_arg = no_argument },
3376 { .val = 'i', .name = "inodes", .has_arg = no_argument },
3377 { .val = 'l', .name = "lazy", .has_arg = no_argument },
3378 { .val = 'p', .name = "pool", .has_arg = required_argument },
3379 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3382 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3385 flags |= MNTDF_COOKED;
3388 flags |= MNTDF_INODES;
3391 flags |= MNTDF_LAZY;
3397 flags |= MNTDF_VERBOSE;
3403 if (optind < argc && !realpath(argv[optind], path)) {
3405 fprintf(stderr, "error: invalid path '%s': %s\n",
3406 argv[optind], strerror(-rc));
3410 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3411 /* Check if we have a mount point */
3412 if (mntdir[0] == '\0')
3415 rc = mntdf(mntdir, fsname, pool_name, flags);
3416 if (rc || path[0] != '\0')
3418 fsname[0] = '\0'; /* avoid matching in next loop */
3419 mntdir[0] = '\0'; /* avoid matching in next loop */
3425 static int lfs_getname(int argc, char **argv)
3427 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3428 int rc = 0, index = 0, c;
3429 char buf[sizeof(struct obd_uuid)];
3431 while ((c = getopt(argc, argv, "h")) != -1)
3434 if (optind == argc) { /* no paths specified, get all paths. */
3435 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3436 rc = llapi_getname(mntdir, buf, sizeof(buf));
3439 "cannot get name for `%s': %s\n",
3440 mntdir, strerror(-rc));
3444 printf("%s %s\n", buf, mntdir);
3446 path[0] = fsname[0] = mntdir[0] = 0;
3448 } else { /* paths specified, only attempt to search these. */
3449 for (; optind < argc; optind++) {
3450 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3453 "cannot get name for `%s': %s\n",
3454 argv[optind], strerror(-rc));
3458 printf("%s %s\n", buf, argv[optind]);
3464 static int lfs_check(int argc, char **argv)
3467 char mntdir[PATH_MAX] = {'\0'};
3476 obd_types[0] = obd_type1;
3477 obd_types[1] = obd_type2;
3479 if (strcmp(argv[1], "osts") == 0) {
3480 strcpy(obd_types[0], "osc");
3481 } else if (strcmp(argv[1], "mds") == 0) {
3482 strcpy(obd_types[0], "mdc");
3483 } else if (strcmp(argv[1], "servers") == 0) {
3485 strcpy(obd_types[0], "osc");
3486 strcpy(obd_types[1], "mdc");
3488 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3493 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3494 if (rc < 0 || mntdir[0] == '\0') {
3495 fprintf(stderr, "No suitable Lustre mount found\n");
3499 rc = llapi_target_check(num_types, obd_types, mntdir);
3501 fprintf(stderr, "error: %s: %s status failed\n",
3508 #ifdef HAVE_SYS_QUOTA_H
3509 #define ARG2INT(nr, str, msg) \
3512 nr = strtol(str, &endp, 0); \
3514 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3519 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3521 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3522 * returns the value or ULONG_MAX on integer overflow or incorrect format
3524 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3525 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3526 * 3. empty integer value is interpreted as 0
3528 static unsigned long str2sec(const char* timestr)
3530 const char spec[] = "smhdw";
3531 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3532 unsigned long val = 0;
3535 if (strpbrk(timestr, spec) == NULL) {
3536 /* no specifiers inside the time string,
3537 should treat it as an integer value */
3538 val = strtoul(timestr, &tail, 10);
3539 return *tail ? ULONG_MAX : val;
3542 /* format string is XXwXXdXXhXXmXXs */
3548 v = strtoul(timestr, &tail, 10);
3549 if (v == ULONG_MAX || *tail == '\0')
3550 /* value too large (ULONG_MAX or more)
3551 or missing specifier */
3554 ptr = strchr(spec, *tail);
3556 /* unknown specifier */
3561 /* check if product will overflow the type */
3562 if (!(v < ULONG_MAX / mult[ind]))
3565 ADD_OVERFLOW(val, mult[ind] * v);
3566 if (val == ULONG_MAX)
3578 #define ARG2ULL(nr, str, def_units) \
3580 unsigned long long limit, units = def_units; \
3583 rc = llapi_parse_size(str, &limit, &units, 1); \
3585 fprintf(stderr, "error: bad limit value %s\n", str); \
3591 static inline int has_times_option(int argc, char **argv)
3595 for (i = 1; i < argc; i++)
3596 if (!strcmp(argv[i], "-t"))
3602 int lfs_setquota_times(int argc, char **argv)
3605 struct if_quotactl qctl;
3606 char *mnt, *obd_type = (char *)qctl.obd_type;
3607 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3608 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3609 struct option long_opts[] = {
3610 { .val = 'b', .name = "block-grace", .has_arg = required_argument },
3611 { .val = 'g', .name = "group", .has_arg = no_argument },
3612 { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
3613 { .val = 'p', .name = "projid", .has_arg = no_argument },
3614 { .val = 't', .name = "times", .has_arg = no_argument },
3615 { .val = 'u', .name = "user", .has_arg = no_argument },
3619 memset(&qctl, 0, sizeof(qctl));
3620 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3621 qctl.qc_type = ALLQUOTA;
3623 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3624 long_opts, NULL)) != -1) {
3635 if (qctl.qc_type != ALLQUOTA) {
3636 fprintf(stderr, "error: -u/g/p can't be used "
3637 "more than once\n");
3640 qctl.qc_type = qtype;
3643 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3644 fprintf(stderr, "error: bad block-grace: %s\n",
3648 dqb->dqb_valid |= QIF_BTIME;
3651 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3652 fprintf(stderr, "error: bad inode-grace: %s\n",
3656 dqb->dqb_valid |= QIF_ITIME;
3658 case 't': /* Yes, of course! */
3660 default: /* getopt prints error message for us when opterr != 0 */
3665 if (qctl.qc_type == ALLQUOTA) {
3666 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3670 if (optind != argc - 1) {
3671 fprintf(stderr, "error: unexpected parameters encountered\n");
3676 rc = llapi_quotactl(mnt, &qctl);
3679 fprintf(stderr, "%s %s ", obd_type,
3680 obd_uuid2str(&qctl.obd_uuid));
3681 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3688 #define BSLIMIT (1 << 0)
3689 #define BHLIMIT (1 << 1)
3690 #define ISLIMIT (1 << 2)
3691 #define IHLIMIT (1 << 3)
3693 int lfs_setquota(int argc, char **argv)
3696 struct if_quotactl qctl;
3697 char *mnt, *obd_type = (char *)qctl.obd_type;
3698 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3699 struct option long_opts[] = {
3700 { .val = 'b', .name = "block-softlimit",
3701 .has_arg = required_argument },
3702 { .val = 'B', .name = "block-hardlimit",
3703 .has_arg = required_argument },
3704 { .val = 'g', .name = "group", .has_arg = required_argument },
3705 { .val = 'i', .name = "inode-softlimit",
3706 .has_arg = required_argument },
3707 { .val = 'I', .name = "inode-hardlimit",
3708 .has_arg = required_argument },
3709 { .val = 'p', .name = "projid", .has_arg = required_argument },
3710 { .val = 'u', .name = "user", .has_arg = required_argument },
3712 unsigned limit_mask = 0;
3716 if (has_times_option(argc, argv))
3717 return lfs_setquota_times(argc, argv);
3719 memset(&qctl, 0, sizeof(qctl));
3720 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3721 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3722 * so it can be used as a marker that qc_type
3723 * isn't reinitialized from command line */
3725 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3726 long_opts, NULL)) != -1) {
3730 rc = name2uid(&qctl.qc_id, optarg);
3734 rc = name2gid(&qctl.qc_id, optarg);
3738 rc = name2projid(&qctl.qc_id, optarg);
3740 if (qctl.qc_type != ALLQUOTA) {
3741 fprintf(stderr, "error: -u and -g can't be used"
3742 " more than once\n");
3745 qctl.qc_type = qtype;
3747 qctl.qc_id = strtoul(optarg, &endptr, 10);
3748 if (*endptr != '\0') {
3749 fprintf(stderr, "error: can't find id "
3750 "for name %s\n", optarg);
3756 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3757 dqb->dqb_bsoftlimit >>= 10;
3758 limit_mask |= BSLIMIT;
3759 if (dqb->dqb_bsoftlimit &&
3760 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3761 fprintf(stderr, "warning: block softlimit is "
3762 "smaller than the miminal qunit size, "
3763 "please see the help of setquota or "
3764 "Lustre manual for details.\n");
3767 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3768 dqb->dqb_bhardlimit >>= 10;
3769 limit_mask |= BHLIMIT;
3770 if (dqb->dqb_bhardlimit &&
3771 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3772 fprintf(stderr, "warning: block hardlimit is "
3773 "smaller than the miminal qunit size, "
3774 "please see the help of setquota or "
3775 "Lustre manual for details.\n");
3778 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3779 limit_mask |= ISLIMIT;
3780 if (dqb->dqb_isoftlimit &&
3781 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3782 fprintf(stderr, "warning: inode softlimit is "
3783 "smaller than the miminal qunit size, "
3784 "please see the help of setquota or "
3785 "Lustre manual for details.\n");
3788 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3789 limit_mask |= IHLIMIT;
3790 if (dqb->dqb_ihardlimit &&
3791 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3792 fprintf(stderr, "warning: inode hardlimit is "
3793 "smaller than the miminal qunit size, "
3794 "please see the help of setquota or "
3795 "Lustre manual for details.\n");
3797 default: /* getopt prints error message for us when opterr != 0 */
3802 if (qctl.qc_type == ALLQUOTA) {
3803 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3807 if (limit_mask == 0) {
3808 fprintf(stderr, "error: at least one limit must be specified\n");
3812 if (optind != argc - 1) {
3813 fprintf(stderr, "error: unexpected parameters encountered\n");
3819 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3820 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3821 /* sigh, we can't just set blimits/ilimits */
3822 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3823 .qc_type = qctl.qc_type,
3824 .qc_id = qctl.qc_id};
3826 rc = llapi_quotactl(mnt, &tmp_qctl);
3828 fprintf(stderr, "error: setquota failed while retrieving"
3829 " current quota settings (%s)\n",
3834 if (!(limit_mask & BHLIMIT))
3835 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3836 if (!(limit_mask & BSLIMIT))
3837 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3838 if (!(limit_mask & IHLIMIT))
3839 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3840 if (!(limit_mask & ISLIMIT))
3841 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3843 /* Keep grace times if we have got no softlimit arguments */
3844 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3845 dqb->dqb_valid |= QIF_BTIME;
3846 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3849 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3850 dqb->dqb_valid |= QIF_ITIME;
3851 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3855 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3856 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3858 rc = llapi_quotactl(mnt, &qctl);
3861 fprintf(stderr, "%s %s ", obd_type,
3862 obd_uuid2str(&qctl.obd_uuid));
3863 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3870 /* Converts seconds value into format string
3871 * result is returned in buf
3873 * 1. result is in descenting order: 1w2d3h4m5s
3874 * 2. zero fields are not filled (except for p. 3): 5d1s
3875 * 3. zero seconds value is presented as "0s"
3877 static char * __sec2str(time_t seconds, char *buf)
3879 const char spec[] = "smhdw";
3880 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3885 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3886 c = seconds / mult[i];
3888 if (c > 0 || (i == 0 && buf == tail))
3889 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3897 static void sec2str(time_t seconds, char *buf, int rc)
3904 tail = __sec2str(seconds, tail);
3906 if (rc && tail - buf < 39) {
3912 static void diff2str(time_t seconds, char *buf, time_t now)
3918 if (seconds <= now) {
3919 strcpy(buf, "none");
3922 __sec2str(seconds - now, buf);
3925 static void print_quota_title(char *name, struct if_quotactl *qctl,
3926 bool human_readable)
3928 printf("Disk quotas for %s %s (%cid %u):\n",
3929 qtype_name(qctl->qc_type), name,
3930 *qtype_name(qctl->qc_type), qctl->qc_id);
3931 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3932 "Filesystem", human_readable ? "used" : "kbytes",
3933 "quota", "limit", "grace",
3934 "files", "quota", "limit", "grace");
3937 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3940 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3943 snprintf(buf, buflen, "%5.4gP",
3944 (double)num / ((__u64)1 << 40));
3946 snprintf(buf, buflen, "%5.4gT",
3947 (double)num / (1 << 30));
3949 snprintf(buf, buflen, "%5.4gG",
3950 (double)num / (1 << 20));
3952 snprintf(buf, buflen, "%5.4gM",
3953 (double)num / (1 << 10));
3955 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3959 #define STRBUF_LEN 32
3960 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3967 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3968 int bover = 0, iover = 0;
3969 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3970 char numbuf[3][STRBUF_LEN];
3972 char strbuf[STRBUF_LEN];
3974 if (dqb->dqb_bhardlimit &&
3975 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3977 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3978 if (dqb->dqb_btime > now) {
3985 if (dqb->dqb_ihardlimit &&
3986 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3988 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3989 if (dqb->dqb_itime > now) {
3997 if (strlen(mnt) > 15)
3998 printf("%s\n%15s", mnt, "");
4000 printf("%15s", mnt);
4003 diff2str(dqb->dqb_btime, timebuf, now);
4005 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
4006 strbuf, sizeof(strbuf), h);
4007 if (rc == -EREMOTEIO)
4008 sprintf(numbuf[0], "%s*", strbuf);
4010 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
4011 "%s" : "[%s]", strbuf);
4013 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
4014 if (type == QC_GENERAL)
4015 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4016 "%s" : "[%s]", strbuf);
4018 sprintf(numbuf[1], "%s", "-");
4020 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4021 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4022 "%s" : "[%s]", strbuf);
4024 printf(" %7s%c %6s %7s %7s",
4025 numbuf[0], bover ? '*' : ' ', numbuf[1],
4026 numbuf[2], bover > 1 ? timebuf : "-");
4029 diff2str(dqb->dqb_itime, timebuf, now);
4031 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4032 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4034 if (type == QC_GENERAL)
4035 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4037 (uintmax_t)dqb->dqb_isoftlimit);
4039 sprintf(numbuf[1], "%s", "-");
4041 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4042 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4044 if (type != QC_OSTIDX)
4045 printf(" %7s%c %6s %7s %7s",
4046 numbuf[0], iover ? '*' : ' ', numbuf[1],
4047 numbuf[2], iover > 1 ? timebuf : "-");
4049 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4052 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4053 qctl->qc_cmd == Q_GETOINFO) {
4057 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4058 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4059 printf("Block grace time: %s; Inode grace time: %s\n",
4060 bgtimebuf, igtimebuf);
4064 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4065 bool h, __u64 *total)
4067 int rc = 0, rc1 = 0, count = 0;
4068 __u32 valid = qctl->qc_valid;
4070 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4072 fprintf(stderr, "can not get %s count: %s\n",
4073 is_mdt ? "mdt": "ost", strerror(-rc));
4077 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4078 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4079 rc = llapi_quotactl(mnt, qctl);
4081 /* It is remote client case. */
4082 if (rc == -EOPNOTSUPP) {
4089 fprintf(stderr, "quotactl %s%d failed.\n",
4090 is_mdt ? "mdt": "ost", qctl->qc_idx);
4094 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4095 qctl->qc_valid, 0, h);
4096 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4097 qctl->qc_dqblk.dqb_bhardlimit;
4100 qctl->qc_valid = valid;
4104 static int lfs_quota(int argc, char **argv)
4107 char *mnt, *name = NULL;
4108 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4109 .qc_type = ALLQUOTA };
4110 char *obd_type = (char *)qctl.obd_type;
4111 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4112 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4113 verbose = 0, pass = 0, quiet = 0, inacc;
4115 __u32 valid = QC_GENERAL, idx = 0;
4116 __u64 total_ialloc = 0, total_balloc = 0;
4117 bool human_readable = false;
4120 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4131 if (qctl.qc_type != ALLQUOTA) {
4132 fprintf(stderr, "error: use either -u or -g\n");
4135 qctl.qc_type = qtype;
4138 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4141 valid = qctl.qc_valid = QC_UUID;
4142 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4145 valid = qctl.qc_valid = QC_MDTIDX;
4146 idx = qctl.qc_idx = atoi(optarg);
4149 valid = qctl.qc_valid = QC_OSTIDX;
4150 idx = qctl.qc_idx = atoi(optarg);
4159 human_readable = true;
4162 fprintf(stderr, "error: %s: option '-%c' "
4163 "unrecognized\n", argv[0], c);
4168 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4169 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4170 optind == argc - 1) {
4172 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4173 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4174 qctl.qc_valid = valid;
4176 qctl.qc_type = pass;
4177 switch (qctl.qc_type) {
4179 qctl.qc_id = geteuid();
4180 rc = uid2name(&name, qctl.qc_id);
4183 qctl.qc_id = getegid();
4184 rc = gid2name(&name, qctl.qc_id);
4193 /* lfs quota -u username /path/to/lustre/mount */
4194 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4195 /* options should be followed by u/g-name and mntpoint */
4196 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4197 fprintf(stderr, "error: missing quota argument(s)\n");
4201 name = argv[optind++];
4202 switch (qctl.qc_type) {
4204 rc = name2uid(&qctl.qc_id, name);
4207 rc = name2gid(&qctl.qc_id, name);
4210 rc = name2projid(&qctl.qc_id, name);
4217 qctl.qc_id = strtoul(name, &endptr, 10);
4218 if (*endptr != '\0') {
4219 fprintf(stderr, "error: can't find id for name: %s\n",
4224 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4225 fprintf(stderr, "error: missing quota info argument(s)\n");
4230 rc1 = llapi_quotactl(mnt, &qctl);
4234 fprintf(stderr, "%s quotas are not enabled.\n",
4235 qtype_name(qctl.qc_type));
4238 fprintf(stderr, "Permission denied.\n");
4241 /* We already got error message. */
4244 fprintf(stderr, "Unexpected quotactl error: %s\n",
4249 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4250 print_quota_title(name, &qctl, human_readable);
4252 if (rc1 && *obd_type)
4253 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4255 if (qctl.qc_valid != QC_GENERAL)
4258 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4259 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4260 (QIF_LIMITS|QIF_USAGE));
4262 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4264 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4266 char strbuf[STRBUF_LEN];
4268 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4270 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4272 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4274 printf("Total allocated inode limit: %ju, total "
4275 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4279 if (rc1 || rc2 || rc3 || inacc)
4280 printf("Some errors happened when getting quota info. "
4281 "Some devices may be not working or deactivated. "
4282 "The data in \"[]\" is inaccurate.\n");
4285 if (pass > 0 && pass < LL_MAXQUOTAS)
4290 #endif /* HAVE_SYS_QUOTA_H! */
4292 static int flushctx_ioctl(char *mp)
4296 fd = open(mp, O_RDONLY);
4298 fprintf(stderr, "flushctx: error open %s: %s\n",
4299 mp, strerror(errno));
4303 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4305 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4306 mp, strerror(errno));
4312 static int lfs_flushctx(int argc, char **argv)
4314 int kdestroy = 0, c;
4315 char mntdir[PATH_MAX] = {'\0'};
4319 while ((c = getopt(argc, argv, "k")) != -1) {
4325 fprintf(stderr, "error: %s: option '-%c' "
4326 "unrecognized\n", argv[0], c);
4332 if ((rc = system("kdestroy > /dev/null")) != 0) {
4333 rc = WEXITSTATUS(rc);
4334 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4338 if (optind >= argc) {
4339 /* flush for all mounted lustre fs. */
4340 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4341 /* Check if we have a mount point */
4342 if (mntdir[0] == '\0')
4345 if (flushctx_ioctl(mntdir))
4348 mntdir[0] = '\0'; /* avoid matching in next loop */
4351 /* flush fs as specified */
4352 while (optind < argc) {
4353 if (flushctx_ioctl(argv[optind++]))
4360 static int lfs_cp(int argc, char **argv)
4362 fprintf(stderr, "remote client copy file(s).\n"
4363 "obsolete, does not support it anymore.\n");
4367 static int lfs_ls(int argc, char **argv)
4369 fprintf(stderr, "remote client lists directory contents.\n"
4370 "obsolete, does not support it anymore.\n");
4374 static int lfs_changelog(int argc, char **argv)
4376 void *changelog_priv;
4377 struct changelog_rec *rec;
4378 long long startrec = 0, endrec = 0;
4380 struct option long_opts[] = {
4381 { .val = 'f', .name = "follow", .has_arg = no_argument },
4383 char short_opts[] = "f";
4386 while ((rc = getopt_long(argc, argv, short_opts,
4387 long_opts, NULL)) != -1) {
4395 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4396 argv[0], argv[optind - 1]);
4403 mdd = argv[optind++];
4405 startrec = strtoll(argv[optind++], NULL, 10);
4407 endrec = strtoll(argv[optind++], NULL, 10);
4409 rc = llapi_changelog_start(&changelog_priv,
4410 CHANGELOG_FLAG_BLOCK |
4411 CHANGELOG_FLAG_JOBID |
4412 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4415 fprintf(stderr, "Can't start changelog: %s\n",
4416 strerror(errno = -rc));
4420 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4424 if (endrec && rec->cr_index > endrec) {
4425 llapi_changelog_free(&rec);
4428 if (rec->cr_index < startrec) {
4429 llapi_changelog_free(&rec);
4433 secs = rec->cr_time >> 30;
4434 gmtime_r(&secs, &ts);
4435 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4436 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4437 changelog_type2str(rec->cr_type),
4438 ts.tm_hour, ts.tm_min, ts.tm_sec,
4439 (int)(rec->cr_time & ((1 << 30) - 1)),
4440 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4441 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4443 if (rec->cr_flags & CLF_JOBID) {
4444 struct changelog_ext_jobid *jid =
4445 changelog_rec_jobid(rec);
4447 if (jid->cr_jobid[0] != '\0')
4448 printf(" j=%s", jid->cr_jobid);
4451 if (rec->cr_namelen)
4452 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4453 rec->cr_namelen, changelog_rec_name(rec));
4455 if (rec->cr_flags & CLF_RENAME) {
4456 struct changelog_ext_rename *rnm =
4457 changelog_rec_rename(rec);
4459 if (!fid_is_zero(&rnm->cr_sfid))
4460 printf(" s="DFID" sp="DFID" %.*s",
4461 PFID(&rnm->cr_sfid),
4462 PFID(&rnm->cr_spfid),
4463 (int)changelog_rec_snamelen(rec),
4464 changelog_rec_sname(rec));
4468 llapi_changelog_free(&rec);
4471 llapi_changelog_fini(&changelog_priv);
4474 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4476 return (rc == 1 ? 0 : rc);
4479 static int lfs_changelog_clear(int argc, char **argv)
4487 endrec = strtoll(argv[3], NULL, 10);
4489 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4492 fprintf(stderr, "%s: record out of range: %llu\n",
4494 else if (rc == -ENOENT)
4495 fprintf(stderr, "%s: no changelog user: %s\n",
4498 fprintf(stderr, "%s error: %s\n", argv[0],
4507 static int lfs_fid2path(int argc, char **argv)
4509 struct option long_opts[] = {
4510 { .val = 'c', .name = "cur", .has_arg = no_argument },
4511 { .val = 'l', .name = "link", .has_arg = required_argument },
4512 { .val = 'r', .name = "rec", .has_arg = required_argument },
4514 char short_opts[] = "cl:r:";
4515 char *device, *fid, *path;
4516 long long recno = -1;
4522 while ((rc = getopt_long(argc, argv, short_opts,
4523 long_opts, NULL)) != -1) {
4529 linkno = strtol(optarg, NULL, 10);
4532 recno = strtoll(optarg, NULL, 10);
4537 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4538 argv[0], argv[optind - 1]);
4546 device = argv[optind++];
4547 path = calloc(1, PATH_MAX);
4549 fprintf(stderr, "error: Not enough memory\n");
4554 while (optind < argc) {
4555 fid = argv[optind++];
4557 lnktmp = (linkno >= 0) ? linkno : 0;
4559 int oldtmp = lnktmp;
4560 long long rectmp = recno;
4562 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4565 fprintf(stderr, "%s: error on FID %s: %s\n",
4566 argv[0], fid, strerror(errno = -rc2));
4573 fprintf(stdout, "%lld ", rectmp);
4574 if (device[0] == '/') {
4575 fprintf(stdout, "%s", device);
4576 if (device[strlen(device) - 1] != '/')
4577 fprintf(stdout, "/");
4578 } else if (path[0] == '\0') {
4579 fprintf(stdout, "/");
4581 fprintf(stdout, "%s\n", path);
4584 /* specified linkno */
4586 if (oldtmp == lnktmp)
4596 static int lfs_path2fid(int argc, char **argv)
4598 struct option long_opts[] = {
4599 { .val = 'p', .name = "parents", .has_arg = no_argument },
4602 const char short_opts[] = "p";
4603 const char *sep = "";
4606 bool show_parents = false;
4608 while ((rc = getopt_long(argc, argv, short_opts,
4609 long_opts, NULL)) != -1) {
4612 show_parents = true;
4615 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4616 argv[0], argv[optind - 1]);
4621 if (optind > argc - 1)
4623 else if (optind < argc - 1)
4627 for (path = argv + optind; *path != NULL; path++) {
4629 if (!show_parents) {
4630 err = llapi_path2fid(*path, &fid);
4632 printf("%s%s"DFID"\n",
4633 *sep != '\0' ? *path : "", sep,
4636 char name[NAME_MAX + 1];
4637 unsigned int linkno = 0;
4639 while ((err = llapi_path2parent(*path, linkno, &fid,
4640 name, sizeof(name))) == 0) {
4641 if (*sep != '\0' && linkno == 0)
4642 printf("%s%s", *path, sep);
4644 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4649 /* err == -ENODATA is end-of-loop */
4650 if (linkno > 0 && err == -ENODATA) {
4657 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4658 argv[0], show_parents ? "parent " : "", *path,
4670 static int lfs_data_version(int argc, char **argv)
4677 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4682 while ((c = getopt(argc, argv, "nrw")) != -1) {
4685 data_version_flags = 0;
4688 data_version_flags |= LL_DV_RD_FLUSH;
4691 data_version_flags |= LL_DV_WR_FLUSH;
4700 path = argv[optind];
4701 fd = open(path, O_RDONLY);
4703 err(errno, "cannot open file %s", path);
4705 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4707 err(errno, "cannot get version for %s", path);
4709 printf("%ju" "\n", (uintmax_t)data_version);
4715 static int lfs_hsm_state(int argc, char **argv)
4720 struct hsm_user_state hus;
4728 rc = llapi_hsm_state_get(path, &hus);
4730 fprintf(stderr, "can't get hsm state for %s: %s\n",
4731 path, strerror(errno = -rc));
4735 /* Display path name and status flags */
4736 printf("%s: (0x%08x)", path, hus.hus_states);
4738 if (hus.hus_states & HS_RELEASED)
4739 printf(" released");
4740 if (hus.hus_states & HS_EXISTS)
4742 if (hus.hus_states & HS_DIRTY)
4744 if (hus.hus_states & HS_ARCHIVED)
4745 printf(" archived");
4746 /* Display user-settable flags */
4747 if (hus.hus_states & HS_NORELEASE)
4748 printf(" never_release");
4749 if (hus.hus_states & HS_NOARCHIVE)
4750 printf(" never_archive");
4751 if (hus.hus_states & HS_LOST)
4752 printf(" lost_from_hsm");
4754 if (hus.hus_archive_id != 0)
4755 printf(", archive_id:%d", hus.hus_archive_id);
4758 } while (++i < argc);
4763 #define LFS_HSM_SET 0
4764 #define LFS_HSM_CLEAR 1
4767 * Generic function to set or clear HSM flags.
4768 * Used by hsm_set and hsm_clear.
4770 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4772 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4774 struct option long_opts[] = {
4775 { .val = 'A', .name = "archived", .has_arg = no_argument },
4776 { .val = 'a', .name = "noarchive", .has_arg = no_argument },
4777 { .val = 'd', .name = "dirty", .has_arg = no_argument },
4778 { .val = 'e', .name = "exists", .has_arg = no_argument },
4779 { .val = 'l', .name = "lost", .has_arg = no_argument },
4780 { .val = 'r', .name = "norelease", .has_arg = no_argument },
4782 char short_opts[] = "lraAde";
4790 while ((c = getopt_long(argc, argv, short_opts,
4791 long_opts, NULL)) != -1) {
4797 mask |= HS_NOARCHIVE;
4800 mask |= HS_ARCHIVED;
4803 mask |= HS_NORELEASE;
4814 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4815 argv[0], argv[optind - 1]);
4820 /* User should have specified a flag */
4824 while (optind < argc) {
4826 path = argv[optind];
4828 /* If mode == 0, this means we apply the mask. */
4829 if (mode == LFS_HSM_SET)
4830 rc = llapi_hsm_state_set(path, mask, 0, 0);
4832 rc = llapi_hsm_state_set(path, 0, mask, 0);
4835 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4836 path, strerror(errno = -rc));
4845 static int lfs_hsm_action(int argc, char **argv)
4850 struct hsm_current_action hca;
4851 struct hsm_extent he;
4852 enum hsm_user_action hua;
4853 enum hsm_progress_states hps;
4861 rc = llapi_hsm_current_action(path, &hca);
4863 fprintf(stderr, "can't get hsm action for %s: %s\n",
4864 path, strerror(errno = -rc));
4867 he = hca.hca_location;
4868 hua = hca.hca_action;
4869 hps = hca.hca_state;
4871 printf("%s: %s", path, hsm_user_action2name(hua));
4873 /* Skip file without action */
4874 if (hca.hca_action == HUA_NONE) {
4879 printf(" %s ", hsm_progress_state2name(hps));
4881 if ((hps == HPS_RUNNING) &&
4882 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4883 printf("(%llu bytes moved)\n",
4884 (unsigned long long)he.length);
4885 else if ((he.offset + he.length) == LUSTRE_EOF)
4886 printf("(from %llu to EOF)\n",
4887 (unsigned long long)he.offset);
4889 printf("(from %llu to %llu)\n",
4890 (unsigned long long)he.offset,
4891 (unsigned long long)(he.offset + he.length));
4893 } while (++i < argc);
4898 static int lfs_hsm_set(int argc, char **argv)
4900 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4903 static int lfs_hsm_clear(int argc, char **argv)
4905 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4909 * Check file state and return its fid, to be used by lfs_hsm_request().
4911 * \param[in] file Path to file to check
4912 * \param[in,out] fid Pointer to allocated lu_fid struct.
4913 * \param[in,out] last_dev Pointer to last device id used.
4915 * \return 0 on success.
4917 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4923 rc = lstat(file, &st);
4925 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4928 /* Checking for regular file as archiving as posix copytool
4929 * rejects archiving files other than regular files
4931 if (!S_ISREG(st.st_mode)) {
4932 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4935 /* A request should be ... */
4936 if (*last_dev != st.st_dev && *last_dev != 0) {
4937 fprintf(stderr, "All files should be "
4938 "on the same filesystem: %s\n", file);
4941 *last_dev = st.st_dev;
4943 rc = llapi_path2fid(file, fid);
4945 fprintf(stderr, "Cannot read FID of %s: %s\n",
4946 file, strerror(-rc));
4952 /* Fill an HSM HUR item with a given file name.
4954 * If mntpath is set, then the filename is actually a FID, and no
4955 * lookup on the filesystem will be performed.
4957 * \param[in] hur the user request to fill
4958 * \param[in] idx index of the item inside the HUR to fill
4959 * \param[in] mntpath mountpoint of Lustre
4960 * \param[in] fname filename (if mtnpath is NULL)
4961 * or FID (if mntpath is set)
4962 * \param[in] last_dev pointer to last device id used
4964 * \retval 0 on success
4965 * \retval CMD_HELP or a negative errno on error
4967 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4968 const char *mntpath, const char *fname,
4971 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4974 hui->hui_extent.length = -1;
4976 if (mntpath != NULL) {
4979 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4983 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4988 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4992 hur->hur_request.hr_itemcount++;
4997 static int lfs_hsm_request(int argc, char **argv, int action)
4999 struct option long_opts[] = {
5000 { .val = 'a', .name = "archive", .has_arg = required_argument },
5001 { .val = 'D', .name = "data", .has_arg = required_argument },
5002 { .val = 'l', .name = "filelist", .has_arg = required_argument },
5003 { .val = 'm', .name = "mntpath", .has_arg = required_argument },
5006 char short_opts[] = "l:D:a:m:";
5007 struct hsm_user_request *hur, *oldhur;
5012 char *filelist = NULL;
5013 char fullpath[PATH_MAX];
5014 char *opaque = NULL;
5018 int nbfile_alloc = 0;
5019 char *some_file = NULL;
5020 char *mntpath = NULL;
5026 while ((c = getopt_long(argc, argv, short_opts,
5027 long_opts, NULL)) != -1) {
5036 if (action != HUA_ARCHIVE &&
5037 action != HUA_REMOVE) {
5039 "error: -a is supported only "
5040 "when archiving or removing\n");
5043 archive_id = atoi(optarg);
5046 if (some_file == NULL) {
5048 some_file = strdup(optarg);
5054 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5055 argv[0], argv[optind - 1]);
5060 /* All remaining args are files, so we have at least nbfile */
5061 nbfile = argc - optind;
5063 if ((nbfile == 0) && (filelist == NULL))
5067 opaque_len = strlen(opaque);
5069 /* Alloc the request structure with enough place to store all files
5070 * from command line. */
5071 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5073 fprintf(stderr, "Cannot create the request: %s\n",
5077 nbfile_alloc = nbfile;
5079 hur->hur_request.hr_action = action;
5080 hur->hur_request.hr_archive_id = archive_id;
5081 hur->hur_request.hr_flags = 0;
5083 /* All remaining args are files, add them */
5084 if (nbfile != 0 && some_file == NULL)
5085 some_file = strdup(argv[optind]);
5087 for (i = 0; i < nbfile; i++) {
5088 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5094 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5096 /* If a filelist was specified, read the filelist from it. */
5097 if (filelist != NULL) {
5098 fp = fopen(filelist, "r");
5100 fprintf(stderr, "Cannot read the file list %s: %s\n",
5101 filelist, strerror(errno));
5106 while ((rc = getline(&line, &len, fp)) != -1) {
5107 /* If allocated buffer was too small, get something
5109 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5112 nbfile_alloc = nbfile_alloc * 2 + 1;
5114 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5117 fprintf(stderr, "hsm: cannot allocate "
5118 "the request: %s\n",
5125 size = hur_len(oldhur);
5127 fprintf(stderr, "hsm: cannot allocate "
5128 "%u files + %u bytes data\n",
5129 oldhur->hur_request.hr_itemcount,
5130 oldhur->hur_request.hr_data_len);
5137 memcpy(hur, oldhur, size);
5142 if (line[strlen(line) - 1] == '\n')
5143 line[strlen(line) - 1] = '\0';
5145 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5146 mntpath, line, &last_dev);
5152 if (some_file == NULL) {
5162 /* If a --data was used, add it to the request */
5163 hur->hur_request.hr_data_len = opaque_len;
5165 memcpy(hur_data(hur), opaque, opaque_len);
5167 /* Send the HSM request */
5168 if (realpath(some_file, fullpath) == NULL) {
5169 fprintf(stderr, "Could not find path '%s': %s\n",
5170 some_file, strerror(errno));
5172 rc = llapi_hsm_request(fullpath, hur);
5174 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5175 some_file, strerror(-rc));
5185 static int lfs_hsm_archive(int argc, char **argv)
5187 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5190 static int lfs_hsm_restore(int argc, char **argv)
5192 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5195 static int lfs_hsm_release(int argc, char **argv)
5197 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5200 static int lfs_hsm_remove(int argc, char **argv)
5202 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5205 static int lfs_hsm_cancel(int argc, char **argv)
5207 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5210 static int lfs_swap_layouts(int argc, char **argv)
5215 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5216 SWAP_LAYOUTS_KEEP_MTIME |
5217 SWAP_LAYOUTS_KEEP_ATIME);
5220 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5222 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
5224 static const char *const lockahead_results[] = {
5225 [LLA_RESULT_SENT] = "Lock request sent",
5226 [LLA_RESULT_DIFFERENT] = "Different matching lock found",
5227 [LLA_RESULT_SAME] = "Matching lock on identical extent found",
5230 int lfs_get_mode(const char *string)
5232 enum lock_mode_user mode;
5234 for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
5235 if (lock_mode_names[mode] == NULL)
5237 if (strcmp(string, lock_mode_names[mode]) == 0)
5244 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5246 enum lu_ladvise_type advice;
5249 advice < ARRAY_SIZE(ladvise_names); advice++) {
5250 if (ladvise_names[advice] == NULL)
5252 if (strcmp(string, ladvise_names[advice]) == 0)
5256 return LU_LADVISE_INVALID;
5259 static int lfs_ladvise(int argc, char **argv)
5261 struct option long_opts[] = {
5262 { .val = 'a', .name = "advice", .has_arg = required_argument },
5263 { .val = 'b', .name = "background", .has_arg = no_argument },
5264 { .val = 'e', .name = "end", .has_arg = required_argument },
5265 { .val = 'l', .name = "length", .has_arg = required_argument },
5266 { .val = 'm', .name = "mode", .has_arg = required_argument },
5267 { .val = 's', .name = "start", .has_arg = required_argument },
5268 { .val = 'u', .name = "unset", .has_arg = no_argument },
5270 char short_opts[] = "a:be:l:m:s:u";
5275 struct llapi_lu_ladvise advice;
5276 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5277 unsigned long long start = 0;
5278 unsigned long long end = LUSTRE_EOF;
5279 unsigned long long length = 0;
5280 unsigned long long size_units;
5281 unsigned long long flags = 0;
5285 while ((c = getopt_long(argc, argv, short_opts,
5286 long_opts, NULL)) != -1) {
5289 advice_type = lfs_get_ladvice(optarg);
5290 if (advice_type == LU_LADVISE_INVALID) {
5291 fprintf(stderr, "%s: invalid advice type "
5292 "'%s'\n", argv[0], optarg);
5293 fprintf(stderr, "Valid types:");
5295 for (advice_type = 0;
5296 advice_type < ARRAY_SIZE(ladvise_names);
5298 if (ladvise_names[advice_type] == NULL)
5300 fprintf(stderr, " %s",
5301 ladvise_names[advice_type]);
5303 fprintf(stderr, "\n");
5316 rc = llapi_parse_size(optarg, &end,
5319 fprintf(stderr, "%s: bad end offset '%s'\n",
5326 rc = llapi_parse_size(optarg, &start,
5329 fprintf(stderr, "%s: bad start offset "
5330 "'%s'\n", argv[0], optarg);
5336 rc = llapi_parse_size(optarg, &length,
5339 fprintf(stderr, "%s: bad length '%s'\n",
5345 mode = lfs_get_mode(optarg);
5347 fprintf(stderr, "%s: bad mode '%s', valid "
5348 "modes are READ or WRITE\n",
5356 fprintf(stderr, "%s: option '%s' unrecognized\n",
5357 argv[0], argv[optind - 1]);
5362 if (advice_type == LU_LADVISE_INVALID) {
5363 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5364 fprintf(stderr, "Valid types:");
5365 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5367 if (ladvise_names[advice_type] == NULL)
5369 fprintf(stderr, " %s", ladvise_names[advice_type]);
5371 fprintf(stderr, "\n");
5375 if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
5376 fprintf(stderr, "%s: Lock no expand advice is a per file "
5377 "descriptor advice, so when called from lfs, "
5378 "it does nothing.\n", argv[0]);
5382 if (argc <= optind) {
5383 fprintf(stderr, "%s: please give one or more file names\n",
5388 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5389 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5394 if (end == LUSTRE_EOF && length != 0)
5395 end = start + length;
5398 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5399 argv[0], start, end);
5403 if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
5404 fprintf(stderr, "%s: mode is only valid with lockahead\n",
5409 if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
5410 fprintf(stderr, "%s: mode is required with lockahead\n",
5415 while (optind < argc) {
5418 path = argv[optind++];
5420 fd = open(path, O_RDONLY);
5422 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5423 argv[0], path, strerror(errno));
5428 advice.lla_start = start;
5429 advice.lla_end = end;
5430 advice.lla_advice = advice_type;
5431 advice.lla_value1 = 0;
5432 advice.lla_value2 = 0;
5433 advice.lla_value3 = 0;
5434 advice.lla_value4 = 0;
5435 if (advice_type == LU_LADVISE_LOCKAHEAD) {
5436 advice.lla_lockahead_mode = mode;
5437 advice.lla_peradvice_flags = flags;
5440 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5443 fprintf(stderr, "%s: cannot give advice '%s' to file "
5444 "'%s': %s\n", argv[0],
5445 ladvise_names[advice_type],
5446 path, strerror(errno));
5452 if (rc == 0 && rc2 < 0)
5458 static int lfs_list_commands(int argc, char **argv)
5460 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5462 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5467 int main(int argc, char **argv)
5471 /* Ensure that liblustreapi constructor has run */
5472 if (!liblustreapi_initialized)
5473 fprintf(stderr, "liblustreapi was not properly initialized\n");
5477 Parser_init("lfs > ", cmdlist);
5479 progname = argv[0]; /* Used in error messages */
5481 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5483 rc = Parser_commands();
5486 return rc < 0 ? -rc : rc;
5489 #ifdef _LUSTRE_IDL_H_
5490 /* Everything we need here should be included by lustreapi.h. */
5491 # error "lfs should not depend on lustre_idl.h"
5492 #endif /* _LUSTRE_IDL_H_ */