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_find(int argc, char **argv);
77 static int lfs_getstripe(int argc, char **argv);
78 static int lfs_getdirstripe(int argc, char **argv);
79 static int lfs_setdirstripe(int argc, char **argv);
80 static int lfs_rmentry(int argc, char **argv);
81 static int lfs_osts(int argc, char **argv);
82 static int lfs_mdts(int argc, char **argv);
83 static int lfs_df(int argc, char **argv);
84 static int lfs_getname(int argc, char **argv);
85 static int lfs_check(int argc, char **argv);
86 #ifdef HAVE_SYS_QUOTA_H
87 static int lfs_setquota(int argc, char **argv);
88 static int lfs_quota(int argc, char **argv);
90 static int lfs_flushctx(int argc, char **argv);
91 static int lfs_cp(int argc, char **argv);
92 static int lfs_ls(int argc, char **argv);
93 static int lfs_poollist(int argc, char **argv);
94 static int lfs_changelog(int argc, char **argv);
95 static int lfs_changelog_clear(int argc, char **argv);
96 static int lfs_fid2path(int argc, char **argv);
97 static int lfs_path2fid(int argc, char **argv);
98 static int lfs_data_version(int argc, char **argv);
99 static int lfs_hsm_state(int argc, char **argv);
100 static int lfs_hsm_set(int argc, char **argv);
101 static int lfs_hsm_clear(int argc, char **argv);
102 static int lfs_hsm_action(int argc, char **argv);
103 static int lfs_hsm_archive(int argc, char **argv);
104 static int lfs_hsm_restore(int argc, char **argv);
105 static int lfs_hsm_release(int argc, char **argv);
106 static int lfs_hsm_remove(int argc, char **argv);
107 static int lfs_hsm_cancel(int argc, char **argv);
108 static int lfs_swap_layouts(int argc, char **argv);
109 static int lfs_mv(int argc, char **argv);
110 static int lfs_ladvise(int argc, char **argv);
111 static int lfs_mirror(int argc, char **argv);
112 static int lfs_mirror_list_commands(int argc, char **argv);
113 static int lfs_list_commands(int argc, char **argv);
115 enum setstripe_origin {
121 static int lfs_setstripe0(int argc, char **argv, enum setstripe_origin opc);
123 static inline int lfs_setstripe(int argc, char **argv)
125 return lfs_setstripe0(argc, argv, SO_SETSTRIPE);
127 static inline int lfs_setstripe_migrate(int argc, char **argv)
129 return lfs_setstripe0(argc, argv, SO_MIGRATE);
131 static inline int lfs_mirror_create(int argc, char **argv)
133 return lfs_setstripe0(argc, argv, SO_MIRROR_CREATE);
135 static inline int lfs_mirror_extend(int argc, char **argv)
137 return lfs_setstripe0(argc, argv, SO_MIRROR_EXTEND);
140 /* Setstripe and migrate share mostly the same parameters */
141 #define SSM_CMD_COMMON(cmd) \
142 "usage: "cmd" [--component-end|-E <comp_end>]\n" \
143 " [--stripe-count|-c <stripe_count>]\n" \
144 " [--stripe-index|-i <start_ost_idx>]\n" \
145 " [--stripe-size|-S <stripe_size>]\n" \
146 " [--layout|-L <pattern>]\n" \
147 " [--pool|-p <pool_name>]\n" \
148 " [--ost|-o <ost_indices>]\n"
150 #define SSM_HELP_COMMON \
151 "\tstripe_count: Number of OSTs to stripe over (0=fs default, -1 all)\n" \
152 "\tstart_ost_idx: OST index of first stripe (-1=default round robin)\n"\
153 "\tstripe_size: Number of bytes on each OST (0=fs default)\n" \
154 "\t Can be specified with K, M or G (for KB, MB, GB\n" \
155 "\t respectively)\n" \
156 "\tpool_name: Name of OST pool to use (default none)\n" \
157 "\tlayout: stripe pattern type: raid0, mdt (default raid0)\n"\
158 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
159 "\t Indices be specified in a format of:\n" \
160 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
162 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
163 "\t If --pool is set with --ost, then the OSTs\n" \
164 "\t must be the members of the pool.\n" \
165 "\tcomp_end: Extent end of component, start after previous end.\n"\
166 "\t Can be specified with K, M or G (for KB, MB, GB\n" \
167 "\t respectively, -1 for EOF). Must be a multiple of\n"\
170 #define MIRROR_CREATE_HELP \
171 "\tmirror_count: Number of mirrors to be created with the upcoming\n" \
172 "\t setstripe layout options\n" \
173 "\t It defaults to 1 if not specified; if specified,\n" \
174 "\t it must follow the option without a space.\n" \
175 "\t The option can also be repeated multiple times to\n" \
176 "\t separate mirrors that have different layouts.\n" \
177 "\tsetstripe options: Mirror layout\n" \
178 "\t It can be a plain layout or a composite layout.\n" \
179 "\t If not specified, the stripe options inherited\n" \
180 "\t from the previous component will be used.\n" \
181 "\tparent: Use default stripe options from parent directory\n"
183 #define MIRROR_EXTEND_HELP \
185 "\tvictim_file: The layout of victim_file will be split and used\n" \
186 "\t as a mirror added to the mirrored file.\n" \
187 "\tno-verify: This option indicates not to verify the mirror(s)\n" \
188 "\t from victim file(s) in case the victim file(s)\n" \
189 "\t contains the same data as the original mirrored\n" \
192 #define MIRROR_EXTEND_USAGE \
193 " <--mirror-count|-N[mirror_count]>\n" \
194 " [setstripe options|--parent|-f <victim_file>]\n" \
197 #define SETSTRIPE_USAGE \
198 SSM_CMD_COMMON("setstripe") \
199 MIRROR_EXTEND_USAGE \
200 " <directory|filename>\n" \
204 #define MIGRATE_USAGE \
205 SSM_CMD_COMMON("migrate ") \
207 " [--non-block|-n]\n" \
211 "\tblock: Block file access during data migration (default)\n" \
212 "\tnon-block: Abort migrations if concurrent access is detected\n" \
214 #define SETDIRSTRIPE_USAGE \
215 " [--mdt-count|-c stripe_count>\n" \
216 " [--mdt-index|-i mdt_index]\n" \
217 " [--mdt-hash|-H mdt_hash]\n" \
218 " [--default|-D] [--mode|-m mode] <dir>\n" \
219 "\tstripe_count: stripe count of the striped directory\n" \
220 "\tmdt_index: MDT index of first stripe\n" \
221 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
222 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
223 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
224 "\tdefault_stripe: set default dirstripe of the directory\n" \
225 "\tmode: the mode of the directory\n"
227 static const char *progname;
230 * command_t mirror_cmdlist - lfs mirror commands.
232 command_t mirror_cmdlist[] = {
233 { .pc_name = "create", .pc_func = lfs_mirror_create,
234 .pc_help = "Create a mirrored file.\n"
235 "usage: lfs mirror create "
236 "<--mirror-count|-N[mirror_count]> "
237 "[setstripe options|--parent] ... <filename|directory>\n"
238 MIRROR_CREATE_HELP },
239 { .pc_name = "extend", .pc_func = lfs_mirror_extend,
240 .pc_help = "Extend a mirrored file.\n"
241 "usage: lfs mirror extend "
242 "<--mirror-count|-N[mirror_count]> [--no-verify] "
243 "[setstripe options|--parent|-f <victim_file>] ... <filename>\n"
244 MIRROR_EXTEND_HELP },
245 { .pc_name = "--list-commands", .pc_func = lfs_mirror_list_commands,
246 .pc_help = "list commands supported by lfs mirror"},
247 { .pc_name = "help", .pc_func = Parser_help, .pc_help = "help" },
248 { .pc_name = "exit", .pc_func = Parser_quit, .pc_help = "quit" },
249 { .pc_name = "quit", .pc_func = Parser_quit, .pc_help = "quit" },
253 /* all available commands */
254 command_t cmdlist[] = {
255 {"setstripe", lfs_setstripe, 0,
256 "To create a file with specified striping/composite layout, or\n"
257 "create/replace the default layout on an existing directory:\n"
258 SSM_CMD_COMMON("setstripe")
259 " <directory|filename>\n"
261 "To add component(s) to an existing composite file:\n"
262 SSM_CMD_COMMON("setstripe --component-add")
264 "To totally delete the default striping from an existing directory:\n"
265 "usage: setstripe -d <directory>\n"
267 "To delete the last component(s) from an existing composite file\n"
268 "(note that this will also delete any data in those components):\n"
269 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
270 " [--component-flags|-F <comp_flags>]\n"
272 "\tcomp_id: Unique component ID to delete\n"
273 "\tcomp_flags: 'init' indicating all instantiated components\n"
274 "\t '^init' indicating all uninstantiated components\n"
275 "\t-I and -F cannot be specified at the same time\n"},
276 {"getstripe", lfs_getstripe, 0,
277 "To list the striping info for a given file or files in a\n"
278 "directory or recursively for all files in a directory tree.\n"
279 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
280 " [--stripe-count|-c] [--stripe-index|-i]\n"
281 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
282 " [--mdt|-m] [--recursive|-r] [--raw|-R] [--yaml|-y]\n"
283 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
284 " [--component-id[=comp_id]|-I[comp_id]]\n"
285 " [--component-flags[=comp_flags]]\n"
286 " [--component-count]\n"
287 " [--component-start[=[+-]comp_start]]\n"
288 " [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
289 " <directory|filename> ..."},
290 {"setdirstripe", lfs_setdirstripe, 0,
291 "To create a striped directory on a specified MDT. This can only\n"
292 "be done on MDT0 with the right of administrator.\n"
293 "usage: setdirstripe [OPTION] <directory>\n"
295 {"getdirstripe", lfs_getdirstripe, 0,
296 "To list the striping info for a given directory\n"
297 "or recursively for all directories in a directory tree.\n"
298 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
299 " [--mdt-index|-i] [--mdt-hash|-t]\n"
300 " [--recursive|-r] [--yaml|-y]\n"
301 " [--default|-D] <dir> ..."},
302 {"mkdir", lfs_setdirstripe, 0,
303 "To create a striped directory on a specified MDT. This can only\n"
304 "be done on MDT0 with the right of administrator.\n"
305 "usage: mkdir [OPTION] <directory>\n"
307 {"rm_entry", lfs_rmentry, 0,
308 "To remove the name entry of the remote directory. Note: This\n"
309 "command will only delete the name entry, i.e. the remote directory\n"
310 "will become inaccessable after this command. This can only be done\n"
311 "by the administrator\n"
312 "usage: rm_entry <dir>\n"},
313 {"pool_list", lfs_poollist, 0,
314 "List pools or pool OSTs\n"
315 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
316 {"find", lfs_find, 0,
317 "find files matching given attributes recursively in directory tree.\n"
318 "usage: find <directory|filename> ...\n"
319 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
320 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
321 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
322 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
323 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
324 " [[!] --stripe-count|-c [+-]<stripes>]\n"
325 " [[!] --stripe-index|-i <index,...>]\n"
326 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
327 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
328 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
329 " [[!] --projid <projid>]\n"
330 " [[!] --layout|-L released,raid0,mdt]\n"
331 " [[!] --component-count [+-]<comp_cnt>]\n"
332 " [[!] --component-start [+-]N[kMGTPE]]\n"
333 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
334 " [[!] --component-flags <comp_flags>]\n"
335 " [[!] --mdt-count|-T [+-]<stripes>]\n"
336 " [[!] --mdt-hash|-H <hashtype>\n"
337 "\t !: used before an option indicates 'NOT' requested attribute\n"
338 "\t -: used before a value indicates less than requested value\n"
339 "\t +: used before a value indicates more than requested value\n"
340 "\tmdt-hash: hash type of the striped directory.\n"
341 "\t fnv_1a_64 FNV-1a hash algorithm\n"
342 "\t all_char sum of characters % MDT_COUNT\n"},
343 {"check", lfs_check, 0,
344 "Display the status of MDS or OSTs (as specified in the command)\n"
345 "or all the servers (MDS and OSTs).\n"
346 "usage: check <osts|mds|servers>"},
347 {"osts", lfs_osts, 0, "list OSTs connected to client "
348 "[for specified path only]\n" "usage: osts [path]"},
349 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
350 "[for specified path only]\n" "usage: mdts [path]"},
352 "report filesystem disk space usage or inodes usage"
353 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
354 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
355 {"getname", lfs_getname, 0, "list instances and specified mount points "
356 "[for specified path only]\n"
357 "Usage: getname [-h]|[path ...] "},
358 #ifdef HAVE_SYS_QUOTA_H
359 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
360 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
361 " -b <block-softlimit> -B <block-hardlimit>\n"
362 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
363 " setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
364 " [--block-softlimit <block-softlimit>]\n"
365 " [--block-hardlimit <block-hardlimit>]\n"
366 " [--inode-softlimit <inode-softlimit>]\n"
367 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
368 " setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
369 " [--block-grace <block-grace>]\n"
370 " [--inode-grace <inode-grace>] <filesystem>\n"
371 " -b can be used instead of --block-softlimit/--block-grace\n"
372 " -B can be used instead of --block-hardlimit\n"
373 " -i can be used instead of --inode-softlimit/--inode-grace\n"
374 " -I can be used instead of --inode-hardlimit\n\n"
375 "Note: The total quota space will be split into many qunits and\n"
376 " balanced over all server targets, the minimal qunit size is\n"
377 " 1M bytes for block space and 1K inodes for inode space.\n\n"
378 " Quota space rebalancing process will stop when this mininum\n"
379 " value is reached. As a result, quota exceeded can be returned\n"
380 " while many targets still have 1MB or 1K inodes of spare\n"
382 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
383 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
385 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
386 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
388 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
389 "usage: flushctx [-k] [mountpoint...]"},
391 "Remote user copy files and directories.\n"
392 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
394 "Remote user list directory contents.\n"
395 "usage: ls [OPTION]... [FILE]..."},
396 {"changelog", lfs_changelog, 0,
397 "Show the metadata changes on an MDT."
398 "\nusage: changelog <mdtname> [startrec [endrec]]"},
399 {"changelog_clear", lfs_changelog_clear, 0,
400 "Indicate that old changelog records up to <endrec> are no longer of "
401 "interest to consumer <id>, allowing the system to free up space.\n"
402 "An <endrec> of 0 means all records.\n"
403 "usage: changelog_clear <mdtname> <id> <endrec>"},
404 {"fid2path", lfs_fid2path, 0,
405 "Resolve the full path(s) for given FID(s). For a specific hardlink "
406 "specify link number <linkno>.\n"
407 /* "For a historical link name, specify changelog record <recno>.\n" */
408 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
409 /* [ --rec <recno> ] */ },
410 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
411 "usage: path2fid [--parents] <path> ..."},
412 {"data_version", lfs_data_version, 0, "Display file data version for "
413 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
414 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
415 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
416 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
417 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
418 "[--archived] [--lost] <file> ..."},
419 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
421 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
422 "[--archived] [--lost] <file> ..."},
423 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
424 "given files.\n" "usage: hsm_action <file> ..."},
425 {"hsm_archive", lfs_hsm_archive, 0,
426 "Archive file to external storage.\n"
427 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
429 {"hsm_restore", lfs_hsm_restore, 0,
430 "Restore file from external storage.\n"
431 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
432 {"hsm_release", lfs_hsm_release, 0,
433 "Release files from Lustre.\n"
434 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
435 {"hsm_remove", lfs_hsm_remove, 0,
436 "Remove file copy from external storage.\n"
437 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
438 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
440 "Note: To remove files from the archive that have been deleted on\n"
441 "Lustre, set mntpath and optionally archive. In that case, all the\n"
442 "positional arguments and entries in the file list must be FIDs."
444 {"hsm_cancel", lfs_hsm_cancel, 0,
445 "Cancel requests related to specified files.\n"
446 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
447 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
448 "usage: swap_layouts <path1> <path2>"},
449 {"migrate", lfs_setstripe_migrate, 0,
450 "migrate a directory between MDTs.\n"
451 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
453 "\tmdt_idx: index of the destination MDT\n"
455 "migrate file objects from one OST "
456 "layout\nto another (may be not safe with concurent writes).\n"
458 "[--stripe-count|-c] <stripe_count>\n"
459 " [--stripe-index|-i] <start_ost_index>\n"
460 " [--stripe-size|-S] <stripe_size>\n"
461 " [--pool|-p] <pool_name>\n"
462 " [--ost-list|-o] <ost_indices>\n"
464 " [--non-block|-n]\n"
465 " <file|directory>\n"
466 "\tstripe_count: number of OSTs to stripe a file over\n"
467 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
468 "\tstripe_size: number of bytes to store before moving to the next OST\n"
469 "\tpool_name: name of the predefined pool of OSTs\n"
470 "\tost_indices: OSTs to stripe over, in order\n"
471 "\tblock: wait for the operation to return before continuing\n"
472 "\tnon-block: do not wait for the operation to return.\n"},
474 "To move directories between MDTs. This command is deprecated, "
475 "use \"migrate\" instead.\n"
476 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
478 {"ladvise", lfs_ladvise, 0,
479 "Provide servers with advice about access patterns for a file.\n"
480 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
481 " [--background|-b] [--unset|-u]\n\n"
482 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
483 " {[--mode|-m [READ,WRITE]}\n"
485 {"mirror", lfs_mirror, mirror_cmdlist,
486 "lfs commands used to manage files with mirrored components:\n"
487 "lfs mirror create - create a mirrored file or directory\n"
488 "lfs mirror extend - add mirror(s) to an existing file\n"
489 "lfs mirror split - split a mirror from an existing mirrored file\n"
490 "lfs mirror resync - resynchronize an out-of-sync mirrored file\n"
491 "lfs mirror verify - verify a mirrored file\n"},
492 {"help", Parser_help, 0, "help"},
493 {"exit", Parser_quit, 0, "quit"},
494 {"quit", Parser_quit, 0, "quit"},
495 {"--version", Parser_version, 0,
496 "output build version of the utility and exit"},
497 {"--list-commands", lfs_list_commands, 0,
498 "list commands supported by the utility and exit"},
503 static int check_hashtype(const char *hashtype)
507 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
508 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
515 static const char *error_loc = "syserror";
518 MIGRATION_NONBLOCK = 1 << 0,
519 MIGRATION_MIRROR = 1 << 1,
522 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
523 struct llapi_layout *layout);
526 migrate_open_files(const char *name, const struct llapi_stripe_param *param,
527 struct llapi_layout *layout, int *fd_src, int *fd_tgt)
533 char parent[PATH_MAX];
534 char volatile_file[PATH_MAX];
540 if (param == NULL && layout == NULL) {
541 error_loc = "layout information";
545 /* search for file directory pathname */
546 if (strlen(name) > sizeof(parent) - 1) {
547 error_loc = "source file name";
551 strncpy(parent, name, sizeof(parent));
552 ptr = strrchr(parent, '/');
554 if (getcwd(parent, sizeof(parent)) == NULL) {
555 error_loc = "getcwd";
559 if (ptr == parent) /* leading '/' */
564 /* open file, direct io */
565 /* even if the file is only read, WR mode is nedeed to allow
566 * layout swap on fd */
567 fd = open(name, O_RDWR | O_DIRECT);
570 error_loc = "cannot open source file";
574 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
576 error_loc = "cannot get MDT index";
581 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
582 mode_t open_mode = S_IRUSR | S_IWUSR;
584 random_value = random();
585 rc = snprintf(volatile_file, sizeof(volatile_file),
586 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
587 mdt_index, random_value);
588 if (rc >= sizeof(volatile_file)) {
593 /* create, open a volatile file, use caching (ie no directio) */
595 fdv = llapi_file_open_param(volatile_file, open_flags,
598 fdv = lfs_component_create(volatile_file, open_flags,
600 } while (fdv < 0 && (rc = fdv) == -EEXIST);
603 error_loc = "cannot create volatile file";
607 /* In case the MDT does not support creation of volatile files
608 * we should try to unlink it. */
609 (void)unlink(volatile_file);
611 /* Not-owner (root?) special case.
612 * Need to set owner/group of volatile file like original.
613 * This will allow to pass related check during layout_swap.
618 error_loc = "cannot stat source file";
622 rc = fstat(fdv, &stv);
625 error_loc = "cannot stat volatile";
629 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
630 rc = fchown(fdv, st.st_uid, st.st_gid);
633 error_loc = "cannot change ownwership of volatile";
652 static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int))
654 struct llapi_layout *layout;
655 size_t buf_size = 4 * 1024 * 1024;
664 layout = llapi_layout_get_by_fd(fd_src, 0);
665 if (layout != NULL) {
666 uint64_t stripe_size;
668 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
670 buf_size = stripe_size;
672 llapi_layout_free(layout);
675 /* Use a page-aligned buffer for direct I/O */
676 rc = posix_memalign(&buf, getpagesize(), buf_size);
681 /* read new data only if we have written all
682 * previously read data */
685 rc = check_file(fd_src);
690 rsize = read(fd_src, buf, buf_size);
702 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
721 static int migrate_copy_timestamps(int fd, int fdv)
725 if (fstat(fd, &st) == 0) {
726 struct timeval tv[2] = {
727 {.tv_sec = st.st_atime},
728 {.tv_sec = st.st_mtime}
731 return futimes(fdv, tv);
737 static int migrate_block(int fd, int fdv)
744 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
746 error_loc = "cannot get dataversion";
754 /* The grouplock blocks all concurrent accesses to the file.
755 * It has to be taken after llapi_get_data_version as it would
757 rc = llapi_group_lock(fd, gid);
759 error_loc = "cannot get group lock";
763 rc = migrate_copy_data(fd, fdv, NULL);
765 error_loc = "data copy failed";
769 /* Make sure we keep original atime/mtime values */
770 rc = migrate_copy_timestamps(fd, fdv);
772 error_loc = "timestamp copy failed";
777 * for a migration we need to check data version on file did
780 * Pass in gid=0 since we already own grouplock. */
781 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
782 SWAP_LAYOUTS_CHECK_DV1);
784 error_loc = "file changed";
787 error_loc = "cannot swap layout";
792 rc2 = llapi_group_unlock(fd, gid);
793 if (rc2 < 0 && rc == 0) {
794 error_loc = "unlock group lock";
802 * Internal helper for migrate_copy_data(). Check lease and report error if
805 * \param[in] fd File descriptor on which to check the lease.
807 * \retval 0 Migration can keep on going.
808 * \retval -errno Error occurred, abort migration.
810 static int check_lease(int fd)
814 rc = llapi_lease_check(fd);
816 return 0; /* llapi_check_lease returns > 0 on success. */
821 static int migrate_nonblock(int fd, int fdv)
827 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
829 error_loc = "cannot get data version";
833 rc = migrate_copy_data(fd, fdv, check_lease);
835 error_loc = "data copy failed";
839 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
841 error_loc = "cannot get data version";
847 error_loc = "source file changed";
851 /* Make sure we keep original atime/mtime values */
852 rc = migrate_copy_timestamps(fd, fdv);
854 error_loc = "timestamp copy failed";
861 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
866 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
870 if (flags != 0 && comp_id != 0)
873 /* LCME_FL_INIT is the only supported flag in PFL */
875 if (flags & ~LCME_KNOWN_FLAGS) {
876 fprintf(stderr, "Invalid component flags %#x\n", flags);
879 } else if (comp_id > LCME_ID_MAX) {
880 fprintf(stderr, "Invalid component id %u\n", comp_id);
884 rc = llapi_layout_file_comp_del(fname, comp_id, flags);
886 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
887 comp_id, fname, strerror(errno));
891 static int lfs_component_add(char *fname, struct llapi_layout *layout)
898 rc = llapi_layout_file_comp_add(fname, layout);
900 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
901 fname, strerror(errno));
905 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
906 struct llapi_layout *layout)
914 fd = lstat(fname, &st);
915 if (fd == 0 && S_ISDIR(st.st_mode))
916 open_flags = O_DIRECTORY | O_RDONLY;
918 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
920 fprintf(stderr, "%s: cannot %s '%s': %s\n", progname,
921 S_ISDIR(st.st_mode) ?
922 "set default composite layout for" :
923 "create composite file",
924 fname, strerror(errno));
928 static int lfs_migrate(char *name, __u64 migration_flags,
929 struct llapi_stripe_param *param,
930 struct llapi_layout *layout)
936 rc = migrate_open_files(name, param, layout, &fd, &fdv);
940 if (!(migration_flags & MIGRATION_NONBLOCK)) {
941 /* Blocking mode (forced if servers do not support file lease).
942 * It is also the default mode, since we cannot distinguish
943 * between a broken lease and a server that does not support
944 * atomic swap/close (LU-6785) */
945 rc = migrate_block(fd, fdv);
949 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
951 error_loc = "cannot get lease";
955 rc = migrate_nonblock(fd, fdv);
961 /* Atomically put lease, swap layouts and close.
962 * for a migration we need to check data version on file did
964 rc = llapi_fswap_layouts(fd, fdv, 0, 0,
965 migration_flags & MIGRATION_MIRROR ?
966 MERGE_LAYOUTS_CLOSE : SWAP_LAYOUTS_CLOSE);
968 error_loc = "cannot swap layout";
980 fprintf(stderr, "error: %s: %s: %s: %s\n",
981 progname, name, error_loc, strerror(-rc));
986 * struct mirror_args - Command-line arguments for mirror(s).
987 * @m_count: Number of mirrors to be created with this layout.
988 * @m_layout: Mirror layout.
989 * @m_file: A victim file. Its layout will be split and used as a mirror.
990 * @m_next: Point to the next node of the list.
992 * Command-line arguments for mirror(s) will be parsed and stored in
993 * a linked list that consists of this structure.
997 struct llapi_layout *m_layout;
999 struct mirror_args *m_next;
1003 * enum mirror_flags - Flags for extending a mirrored file.
1004 * @NO_VERIFY: Indicates not to verify the mirror(s) from victim file(s)
1005 * in case the victim file(s) contains the same data as the
1006 * original mirrored file.
1008 * Flags for extending a mirrored file.
1015 * mirror_create_sanity_check() - Check mirror list.
1016 * @list: A linked list that stores the mirror arguments.
1018 * This function does a sanity check on @list for creating
1021 * Return: 0 on success or a negative error code on failure.
1023 static int mirror_create_sanity_check(struct mirror_args *list)
1026 bool has_m_file = false;
1027 bool has_m_layout = false;
1032 while (list != NULL) {
1033 uint64_t start, end;
1035 if (list->m_file != NULL) {
1037 llapi_layout_free(list->m_layout);
1040 llapi_layout_get_by_path(list->m_file, 0);
1041 if (list->m_layout == NULL) {
1043 "error: %s: file '%s' has no layout\n",
1044 progname, list->m_file);
1048 if (list->m_layout != NULL)
1049 has_m_layout = true;
1051 fprintf(stderr, "error: %s: no mirror layout\n",
1057 rc = llapi_layout_comp_use(list->m_layout,
1058 LLAPI_LAYOUT_COMP_USE_LAST);
1062 rc = llapi_layout_comp_extent_get(list->m_layout, &start, &end);
1066 if (end != LUSTRE_EOF) {
1068 "error: %s: mirror layout doesn't reach eof\n",
1073 list = list->m_next;
1076 if (has_m_file && has_m_layout) {
1077 fprintf(stderr, "error: %s: -f <victim_file> option should not "
1078 "be specified with setstripe options or "
1079 "--parent option\n", progname);
1087 * mirror_create() - Create a mirrored file.
1088 * @fname: The file to be created.
1089 * @mirror_list: A linked list that stores the mirror arguments.
1091 * This function creates a mirrored file @fname with the mirror(s)
1092 * from @mirror_list.
1094 * Return: 0 on success or a negative error code on failure.
1096 static int mirror_create(char *fname, struct mirror_args *mirror_list)
1098 struct llapi_layout *layout = NULL;
1099 struct mirror_args *cur_mirror = NULL;
1100 uint16_t mirror_count = 0;
1104 rc = mirror_create_sanity_check(mirror_list);
1108 cur_mirror = mirror_list;
1109 while (cur_mirror != NULL) {
1110 for (i = 0; i < cur_mirror->m_count; i++) {
1111 rc = llapi_layout_merge(&layout, cur_mirror->m_layout);
1114 fprintf(stderr, "error: %s: "
1115 "merge layout failed: %s\n",
1116 progname, strerror(errno));
1120 mirror_count += cur_mirror->m_count;
1121 cur_mirror = cur_mirror->m_next;
1124 rc = llapi_layout_mirror_count_set(layout, mirror_count);
1127 fprintf(stderr, "error: %s: set mirror count failed: %s\n",
1128 progname, strerror(errno));
1132 rc = lfs_component_create(fname, O_CREAT | O_WRONLY | O_EXCL, 0644,
1140 llapi_layout_free(layout);
1145 * Compare files and check lease on @fd.
1147 * \retval bytes number of bytes are the same
1149 static ssize_t mirror_file_compare(int fd, int fdv)
1151 const size_t buflen = 4 * 1024 * 1024; /* 4M */
1153 ssize_t bytes_done = 0;
1154 ssize_t bytes_read = 0;
1156 buf = malloc(buflen * 2);
1161 if (!llapi_lease_check(fd)) {
1162 bytes_done = -EBUSY;
1166 bytes_read = read(fd, buf, buflen);
1167 if (bytes_read <= 0)
1170 if (bytes_read != read(fdv, buf + buflen, buflen))
1173 /* XXX: should compute the checksum on each buffer and then
1174 * compare checksum to avoid cache collision */
1175 if (memcmp(buf, buf + buflen, bytes_read))
1178 bytes_done += bytes_read;
1186 static int mirror_extend_file(const char *fname, const char *victim_file,
1187 enum mirror_flags mirror_flags)
1192 struct stat stbuf_v;
1196 fd = open(fname, O_RDWR);
1198 error_loc = "open source file";
1203 fdv = open(victim_file, O_RDWR);
1205 error_loc = "open target file";
1210 if (fstat(fd, &stbuf) || fstat(fdv, &stbuf_v)) {
1211 error_loc = "stat source or target file";
1216 if (stbuf.st_dev != stbuf_v.st_dev) {
1217 error_loc = "stat source and target file";
1222 /* mirrors should be of the same size */
1223 if (stbuf.st_size != stbuf_v.st_size) {
1224 error_loc = "file sizes don't match";
1229 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
1231 error_loc = "cannot get lease";
1235 if (!(mirror_flags & NO_VERIFY)) {
1237 /* mirrors should have the same contents */
1238 ret = mirror_file_compare(fd, fdv);
1239 if (ret != stbuf.st_size) {
1240 error_loc = "file busy or contents don't match";
1241 rc = ret < 0 ? ret : -EINVAL;
1246 /* Get rid of caching pages from clients */
1247 rc = llapi_get_data_version(fd, &dv, LL_DV_WR_FLUSH);
1249 error_loc = "cannot get data version";
1253 rc = llapi_get_data_version(fdv, &dv, LL_DV_WR_FLUSH);
1255 error_loc = "cannot get data version";
1260 /* Make sure we keep original atime/mtime values */
1261 rc = migrate_copy_timestamps(fd, fdv);
1263 /* Atomically put lease, swap layouts and close.
1264 * for a migration we need to check data version on file did
1266 rc = llapi_fswap_layouts(fd, fdv, 0, 0, MERGE_LAYOUTS_CLOSE);
1268 error_loc = "cannot swap layout";
1280 (void) unlink(victim_file);
1283 fprintf(stderr, "error: %s: %s: %s: %s\n",
1284 progname, fname, error_loc, strerror(-rc));
1288 static int mirror_extend(char *fname, struct mirror_args *mirror_list,
1289 enum mirror_flags mirror_flags)
1293 rc = mirror_create_sanity_check(mirror_list);
1297 while (mirror_list) {
1298 if (mirror_list->m_file != NULL) {
1299 rc = mirror_extend_file(fname, mirror_list->m_file,
1302 __u32 mirror_count = mirror_list->m_count;
1304 while (mirror_count > 0) {
1305 rc = lfs_migrate(fname,
1306 MIGRATION_NONBLOCK | MIGRATION_MIRROR,
1307 NULL, mirror_list->m_layout);
1317 mirror_list = mirror_list->m_next;
1324 * Parse a string containing an OST index list into an array of integers.
1326 * The input string contains a comma delimited list of individual
1327 * indices and ranges, for example "1,2-4,7". Add the indices into the
1328 * \a osts array and remove duplicates.
1330 * \param[out] osts array to store indices in
1331 * \param[in] size size of \a osts array
1332 * \param[in] offset starting index in \a osts
1333 * \param[in] arg string containing OST index list
1335 * \retval positive number of indices in \a osts
1336 * \retval -EINVAL unable to parse \a arg
1338 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
1342 int slots = size - offset;
1349 end_of_loop = false;
1350 while (!end_of_loop) {
1354 char *endptr = NULL;
1358 ptr = strchrnul(arg, ',');
1360 end_of_loop = *ptr == '\0';
1363 start_index = strtol(arg, &endptr, 0);
1364 if (endptr == arg) /* no data at all */
1366 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
1368 if (start_index < 0)
1371 end_index = start_index;
1372 if (*endptr == '-') {
1373 end_index = strtol(endptr + 1, &endptr, 0);
1374 if (*endptr != '\0')
1376 if (end_index < start_index)
1380 for (i = start_index; i <= end_index && slots > 0; i++) {
1383 /* remove duplicate */
1384 for (j = 0; j < offset; j++) {
1388 if (j == offset) { /* no duplicate */
1393 if (slots == 0 && i < end_index)
1401 if (!end_of_loop && ptr != NULL)
1404 return rc < 0 ? rc : nr;
1407 struct lfs_setstripe_args {
1408 unsigned long long lsa_comp_end;
1409 unsigned long long lsa_stripe_size;
1410 long long lsa_stripe_count;
1411 long long lsa_stripe_off;
1412 __u32 lsa_comp_flags;
1414 unsigned long long lsa_pattern;
1416 char *lsa_pool_name;
1419 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1421 memset(lsa, 0, sizeof(*lsa));
1423 lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
1424 lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
1425 lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
1426 lsa->lsa_pattern = LLAPI_LAYOUT_RAID0;
1427 lsa->lsa_pool_name = NULL;
1431 * setstripe_args_init_inherit() - Initialize and inherit stripe options.
1432 * @lsa: Stripe options to be initialized and inherited.
1434 * This function initializes stripe options in @lsa and inherit
1435 * stripe_size, stripe_count and OST pool_name options.
1439 static inline void setstripe_args_init_inherit(struct lfs_setstripe_args *lsa)
1441 unsigned long long stripe_size;
1442 long long stripe_count;
1443 char *pool_name = NULL;
1445 stripe_size = lsa->lsa_stripe_size;
1446 stripe_count = lsa->lsa_stripe_count;
1447 pool_name = lsa->lsa_pool_name;
1449 setstripe_args_init(lsa);
1451 lsa->lsa_stripe_size = stripe_size;
1452 lsa->lsa_stripe_count = stripe_count;
1453 lsa->lsa_pool_name = pool_name;
1456 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1458 return (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT ||
1459 lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ||
1460 lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
1461 lsa->lsa_pattern != LLAPI_LAYOUT_RAID0 ||
1462 lsa->lsa_pool_name != NULL ||
1463 lsa->lsa_comp_end != 0);
1467 * comp_args_to_layout() - Create or extend a composite layout.
1468 * @composite: Pointer to the composite layout.
1469 * @lsa: Stripe options for the new component.
1471 * This function creates or extends a composite layout by adding a new
1472 * component with stripe options from @lsa.
1474 * Return: 0 on success or an error code on failure.
1476 static int comp_args_to_layout(struct llapi_layout **composite,
1477 struct lfs_setstripe_args *lsa)
1479 struct llapi_layout *layout = *composite;
1480 uint64_t prev_end = 0;
1483 if (layout == NULL) {
1484 layout = llapi_layout_alloc();
1485 if (layout == NULL) {
1486 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1490 *composite = layout;
1494 /* Get current component extent, current component
1495 * must be the tail component. */
1496 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1498 fprintf(stderr, "Get comp extent failed. %s\n",
1503 rc = llapi_layout_comp_add(layout);
1505 fprintf(stderr, "Add component failed. %s\n",
1511 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1513 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1514 prev_end, lsa->lsa_comp_end, strerror(errno));
1518 /* Data-on-MDT component setting */
1519 if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
1520 /* In case of Data-on-MDT patterns the only extra option
1521 * applicable is stripe size option. */
1522 if (lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
1523 fprintf(stderr, "Option 'stripe-count' can't be "
1524 "specified with Data-on-MDT component: %lld\n",
1525 lsa->lsa_stripe_count);
1528 if (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT) {
1529 fprintf(stderr, "Option 'stripe-size' can't be "
1530 "specified with Data-on-MDT component: %llu\n",
1531 lsa->lsa_stripe_size);
1534 if (lsa->lsa_nr_osts != 0) {
1535 fprintf(stderr, "Option 'ost-list' can't be specified "
1536 "with Data-on-MDT component: '%i'\n",
1540 if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
1541 fprintf(stderr, "Option 'stripe-offset' can't be "
1542 "specified with Data-on-MDT component: %lld\n",
1543 lsa->lsa_stripe_off);
1546 if (lsa->lsa_pool_name != 0) {
1547 fprintf(stderr, "Option 'pool' can't be specified "
1548 "with Data-on-MDT component: '%s'\n",
1549 lsa->lsa_pool_name);
1553 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
1555 fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
1556 lsa->lsa_pattern, strerror(errno));
1559 /* Data-on-MDT component has always single stripe up to end */
1560 lsa->lsa_stripe_size = lsa->lsa_comp_end;
1563 rc = llapi_layout_stripe_size_set(layout, lsa->lsa_stripe_size);
1565 fprintf(stderr, "Set stripe size %llu failed: %s\n",
1566 lsa->lsa_stripe_size, strerror(errno));
1570 rc = llapi_layout_stripe_count_set(layout, lsa->lsa_stripe_count);
1572 fprintf(stderr, "Set stripe count %lld failed: %s\n",
1573 lsa->lsa_stripe_count, strerror(errno));
1577 if (lsa->lsa_pool_name != NULL) {
1578 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1580 fprintf(stderr, "Set pool name: %s failed. %s\n",
1581 lsa->lsa_pool_name, strerror(errno));
1585 rc = llapi_layout_pool_name_set(layout, "");
1587 fprintf(stderr, "Clear pool name failed: %s\n",
1593 if (lsa->lsa_nr_osts > 0) {
1594 if (lsa->lsa_stripe_count > 0 &&
1595 lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
1596 lsa->lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
1597 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1598 fprintf(stderr, "stripe_count(%lld) != nr_osts(%d)\n",
1599 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1602 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1603 rc = llapi_layout_ost_index_set(layout, i,
1608 } else if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
1609 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1612 fprintf(stderr, "Set ost index %d failed. %s\n",
1613 i, strerror(errno));
1620 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1621 * end of the last component in the existing file, and adjust the
1622 * first extent start of the components to be added accordingly. */
1623 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1625 struct llapi_layout *head;
1626 uint64_t start, end, stripe_size, prev_end = 0;
1633 head = llapi_layout_get_by_path(fname, 0);
1635 fprintf(stderr, "Read layout from %s failed. %s\n",
1636 fname, strerror(errno));
1638 } else if (errno == ENODATA) {
1639 /* file without LOVEA, this component-add will be turned
1640 * into a component-create. */
1641 llapi_layout_free(head);
1643 } else if (!llapi_layout_is_composite(head)) {
1644 fprintf(stderr, "'%s' isn't a composite file.\n",
1646 llapi_layout_free(head);
1650 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1652 fprintf(stderr, "Get prev extent failed. %s\n",
1654 llapi_layout_free(head);
1658 llapi_layout_free(head);
1660 /* Make sure we use the first component of the layout to be added. */
1661 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1663 fprintf(stderr, "Move component cursor failed. %s\n",
1668 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1670 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1674 if (start > prev_end || end <= prev_end) {
1675 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1676 "adjacent with the existing file extent end: %lu\n",
1677 start, end, prev_end);
1681 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1683 fprintf(stderr, "Get stripe size failed. %s\n",
1688 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1689 (prev_end & (stripe_size - 1))) {
1690 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1691 stripe_size, prev_end);
1695 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1697 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1698 prev_end, end, strerror(errno));
1705 static inline bool comp_flags_is_neg(__u32 flags)
1707 return flags & LCME_FL_NEG;
1710 static inline void comp_flags_set_neg(__u32 *flags)
1712 *flags |= LCME_FL_NEG;
1715 static inline void comp_flags_clear_neg(__u32 *flags)
1717 *flags &= ~LCME_FL_NEG;
1720 static int comp_str2flags(__u32 *flags, char *string)
1723 __u32 neg_flags = 0;
1729 for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1733 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1734 __u32 comp_flag = comp_flags_table[i].cfn_flag;
1735 const char *comp_name = comp_flags_table[i].cfn_name;
1737 if (strcmp(name, comp_name) == 0) {
1738 *flags |= comp_flag;
1740 } else if (strncmp(name, "^", 1) == 0 &&
1741 strcmp(name + 1, comp_name) == 0) {
1742 neg_flags |= comp_flag;
1747 llapi_printf(LLAPI_MSG_ERROR,
1748 "%s: component flag '%s' not supported\n",
1754 if (*flags == 0 && neg_flags == 0)
1756 /* don't support mixed flags for now */
1757 if (*flags && neg_flags)
1762 comp_flags_set_neg(flags);
1768 static inline bool arg_is_eof(char *arg)
1770 return !strncmp(arg, "-1", strlen("-1")) ||
1771 !strncmp(arg, "EOF", strlen("EOF")) ||
1772 !strncmp(arg, "eof", strlen("eof"));
1776 * lfs_mirror_alloc() - Allocate a mirror argument structure.
1778 * Return: Valid mirror_args pointer on success and
1779 * NULL if memory allocation fails.
1781 static struct mirror_args *lfs_mirror_alloc(void)
1783 struct mirror_args *mirror = NULL;
1786 mirror = calloc(1, sizeof(*mirror));
1797 * lfs_mirror_free() - Free memory allocated for a mirror argument
1799 * @mirror: Previously allocated mirror argument structure by
1800 * lfs_mirror_alloc().
1802 * Free memory allocated for @mirror.
1806 static void lfs_mirror_free(struct mirror_args *mirror)
1808 if (mirror->m_layout != NULL)
1809 llapi_layout_free(mirror->m_layout);
1814 * lfs_mirror_list_free() - Free memory allocated for a mirror list.
1815 * @mirror_list: Previously allocated mirror list.
1817 * Free memory allocated for @mirror_list.
1821 static void lfs_mirror_list_free(struct mirror_args *mirror_list)
1823 struct mirror_args *next_mirror = NULL;
1825 while (mirror_list != NULL) {
1826 next_mirror = mirror_list->m_next;
1827 lfs_mirror_free(mirror_list);
1828 mirror_list = next_mirror;
1840 LFS_COMP_USE_PARENT_OPT,
1841 LFS_COMP_NO_VERIFY_OPT,
1846 static int lfs_setstripe0(int argc, char **argv, enum setstripe_origin opc)
1848 struct lfs_setstripe_args lsa;
1849 struct llapi_stripe_param *param = NULL;
1850 struct find_param migrate_mdt_param = {
1860 char *mdt_idx_arg = NULL;
1861 unsigned long long size_units = 1;
1862 bool migrate_mode = false;
1863 bool migration_block = false;
1864 __u64 migration_flags = 0;
1865 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1866 int comp_del = 0, comp_set = 0;
1869 struct llapi_layout *layout = NULL;
1870 struct llapi_layout **lpp = &layout;
1871 bool mirror_mode = false;
1872 bool has_m_file = false;
1873 __u32 mirror_count = 0;
1874 enum mirror_flags mirror_flags = 0;
1875 struct mirror_args *mirror_list = NULL;
1876 struct mirror_args *new_mirror = NULL;
1877 struct mirror_args *last_mirror = NULL;
1880 struct option long_opts[] = {
1881 /* --block is only valid in migrate mode */
1882 { .val = 'b', .name = "block", .has_arg = no_argument},
1883 { .val = LFS_COMP_ADD_OPT,
1884 .name = "comp-add", .has_arg = no_argument},
1885 { .val = LFS_COMP_ADD_OPT,
1886 .name = "component-add",
1887 .has_arg = no_argument},
1888 { .val = LFS_COMP_DEL_OPT,
1889 .name = "comp-del", .has_arg = no_argument},
1890 { .val = LFS_COMP_DEL_OPT,
1891 .name = "component-del",
1892 .has_arg = no_argument},
1893 { .val = LFS_COMP_FLAGS_OPT,
1894 .name = "comp-flags", .has_arg = required_argument},
1895 { .val = LFS_COMP_FLAGS_OPT,
1896 .name = "component-flags",
1897 .has_arg = required_argument},
1898 { .val = LFS_COMP_SET_OPT,
1899 .name = "comp-set", .has_arg = no_argument},
1900 { .val = LFS_COMP_SET_OPT,
1901 .name = "component-set",
1902 .has_arg = no_argument},
1903 { .val = LFS_COMP_USE_PARENT_OPT,
1904 .name = "parent", .has_arg = no_argument},
1905 { .val = LFS_COMP_NO_VERIFY_OPT,
1906 .name = "no-verify", .has_arg = no_argument},
1907 { .val = 'c', .name = "stripe-count", .has_arg = required_argument},
1908 { .val = 'c', .name = "stripe_count", .has_arg = required_argument},
1909 { .val = 'd', .name = "delete", .has_arg = no_argument},
1910 { .val = 'E', .name = "comp-end", .has_arg = required_argument},
1911 { .val = 'E', .name = "component-end",
1912 .has_arg = required_argument},
1913 { .val = 'f', .name = "file", .has_arg = required_argument },
1914 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1915 { .val = 'i', .name = "stripe-index", .has_arg = required_argument},
1916 { .val = 'i', .name = "stripe_index", .has_arg = required_argument},
1917 { .val = 'I', .name = "comp-id", .has_arg = required_argument},
1918 { .val = 'I', .name = "component-id", .has_arg = required_argument},
1919 { .val = 'L', .name = "layout", .has_arg = required_argument },
1920 { .val = 'm', .name = "mdt", .has_arg = required_argument},
1921 { .val = 'm', .name = "mdt-index", .has_arg = required_argument},
1922 { .val = 'm', .name = "mdt_index", .has_arg = required_argument},
1923 { .val = 'N', .name = "mirror-count", .has_arg = optional_argument},
1924 /* --non-block is only valid in migrate mode */
1925 { .val = 'n', .name = "non-block", .has_arg = no_argument},
1926 { .val = 'o', .name = "ost", .has_arg = required_argument},
1927 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1928 { .val = 'o', .name = "ost-list", .has_arg = required_argument },
1929 { .val = 'o', .name = "ost_list", .has_arg = required_argument },
1931 { .val = 'p', .name = "pool", .has_arg = required_argument },
1932 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1933 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1934 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1935 /* --verbose is only valid in migrate mode */
1936 { .val = 'v', .name = "verbose", .has_arg = no_argument },
1939 setstripe_args_init(&lsa);
1941 migrate_mode = (opc == SO_MIGRATE);
1942 mirror_mode = (opc == SO_MIRROR_CREATE || opc == SO_MIRROR_EXTEND);
1944 snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
1946 while ((c = getopt_long(argc, argv, "bc:dE:f:i:I:m:N::no:p:L:s:S:v",
1947 long_opts, NULL)) >= 0) {
1952 case LFS_COMP_ADD_OPT:
1955 case LFS_COMP_DEL_OPT:
1958 case LFS_COMP_FLAGS_OPT:
1959 result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
1963 case LFS_COMP_SET_OPT:
1966 case LFS_COMP_USE_PARENT_OPT:
1968 fprintf(stderr, "error: %s: --parent must be "
1969 "specified with --mirror-count|-N "
1970 "option\n", progname);
1973 setstripe_args_init(&lsa);
1975 case LFS_COMP_NO_VERIFY_OPT:
1976 mirror_flags |= NO_VERIFY;
1979 if (!migrate_mode) {
1981 "%s %s: -b|--block valid only for migrate command\n",
1985 migration_block = true;
1988 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1991 "%s %s: invalid stripe count '%s'\n",
1992 progname, argv[0], optarg);
1996 if (lsa.lsa_stripe_count == -1)
1997 lsa.lsa_stripe_count = LLAPI_LAYOUT_WIDE;
2000 /* delete the default striping pattern */
2004 if (lsa.lsa_comp_end != 0) {
2005 result = comp_args_to_layout(lpp, &lsa);
2008 "%s %s: invalid layout\n",
2013 setstripe_args_init_inherit(&lsa);
2016 if (arg_is_eof(optarg)) {
2017 lsa.lsa_comp_end = LUSTRE_EOF;
2019 result = llapi_parse_size(optarg,
2024 "%s %s: invalid component end '%s'\n",
2025 progname, argv[0], optarg);
2031 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
2034 "%s %s: invalid stripe offset '%s'\n",
2035 progname, argv[0], optarg);
2038 if (lsa.lsa_stripe_off == -1)
2039 lsa.lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2042 comp_id = strtoul(optarg, &end, 0);
2043 if (*end != '\0' || comp_id == 0 ||
2044 comp_id > LCME_ID_MAX) {
2046 "%s %s: invalid component ID '%s'\n",
2047 progname, argv[0], optarg);
2052 if (opc != SO_MIRROR_EXTEND) {
2054 "error: %s: invalid option: %s\n",
2055 progname, argv[optopt + 1]);
2058 if (last_mirror == NULL) {
2059 fprintf(stderr, "error: %s: '-N' must exist "
2060 "in front of '%s'\n",
2061 progname, argv[optopt + 1]);
2065 last_mirror->m_file = optarg;
2066 last_mirror->m_count = 1;
2070 if (strcmp(argv[optind - 1], "mdt") == 0) {
2071 /* Can be only the first component */
2072 if (layout != NULL) {
2074 fprintf(stderr, "error: 'mdt' layout "
2075 "can be only the first one\n");
2078 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
2080 fprintf(stderr, "error: 'mdt' layout "
2081 "size is too big\n");
2084 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
2085 } else if (strcmp(argv[optind - 1], "raid0") != 0) {
2087 fprintf(stderr, "error: layout '%s' is "
2088 "unknown, supported layouts are: "
2089 "'mdt', 'raid0'\n", argv[optind]);
2094 if (!migrate_mode) {
2096 "%s %s: -m|--mdt-index valid only for migrate command\n",
2100 mdt_idx_arg = optarg;
2103 if (!migrate_mode) {
2105 "%s %s: -n|--non-block valid only for migrate command\n",
2109 migration_flags |= MIGRATION_NONBLOCK;
2112 if (opc == SO_SETSTRIPE) {
2113 opc = SO_MIRROR_CREATE;
2117 if (optarg != NULL) {
2118 mirror_count = strtoul(optarg, &end, 0);
2119 if (*end != '\0' || mirror_count == 0) {
2121 "error: %s: bad mirror count: %s\n",
2128 new_mirror = lfs_mirror_alloc();
2129 new_mirror->m_count = mirror_count;
2131 if (mirror_list == NULL)
2132 mirror_list = new_mirror;
2134 if (last_mirror != NULL) {
2135 /* wrap up last mirror */
2136 if (lsa.lsa_comp_end == 0)
2137 lsa.lsa_comp_end = LUSTRE_EOF;
2139 result = comp_args_to_layout(lpp, &lsa);
2141 lfs_mirror_free(new_mirror);
2145 setstripe_args_init_inherit(&lsa);
2147 last_mirror->m_next = new_mirror;
2150 last_mirror = new_mirror;
2151 lpp = &last_mirror->m_layout;
2154 lsa.lsa_nr_osts = parse_targets(osts,
2155 sizeof(osts) / sizeof(__u32),
2156 lsa.lsa_nr_osts, optarg);
2157 if (lsa.lsa_nr_osts < 0) {
2159 "%s %s: invalid OST target(s) '%s'\n",
2160 progname, argv[0], optarg);
2164 lsa.lsa_osts = osts;
2165 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
2166 lsa.lsa_stripe_off = osts[0];
2171 lsa.lsa_pool_name = optarg;
2174 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
2178 "%s %s: invalid stripe size '%s'\n",
2179 progname, argv[0], optarg);
2184 if (!migrate_mode) {
2186 "%s %s: -v|--verbose valid only for migrate command\n",
2190 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
2193 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
2194 progname, argv[0], argv[optind - 1]);
2199 fname = argv[optind];
2201 if (optind == argc) {
2202 fprintf(stderr, "%s %s: FILE must be specified\n",
2207 if (mirror_mode && mirror_count == 0) {
2209 "error: %s: --mirror-count|-N option is required\n",
2216 if (lsa.lsa_comp_end == 0)
2217 lsa.lsa_comp_end = LUSTRE_EOF;
2220 if (lsa.lsa_comp_end != 0) {
2221 result = comp_args_to_layout(lpp, &lsa);
2226 if (mirror_flags & NO_VERIFY) {
2227 if (opc != SO_MIRROR_EXTEND) {
2229 "error: %s: --no-verify is valid only for lfs mirror extend command\n",
2233 } else if (!has_m_file) {
2235 "error: %s: --no-verify must be specified with -f <victim_file> option\n",
2242 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
2243 * altered by user space tool, so we don't need to support the
2244 * --component-set for this moment. */
2245 if (comp_set != 0) {
2246 fprintf(stderr, "%s %s: --component-set not supported\n",
2251 if ((delete + comp_set + comp_del + comp_add) > 1) {
2253 "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
2258 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
2259 lsa.lsa_comp_flags != 0 || layout != NULL)) {
2261 "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
2266 if ((comp_set || comp_del) &&
2267 (setstripe_args_specified(&lsa) || layout != NULL)) {
2269 "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
2274 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
2276 "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
2281 if (comp_add || comp_del) {
2284 result = lstat(fname, &st);
2285 if (result == 0 && S_ISDIR(st.st_mode)) {
2287 "%s setstripe: cannot use --component-add or --component-del for directory\n",
2293 fprintf(stderr, "error: %s: can't use --component-add "
2294 "or --component-del for mirror operation\n",
2301 if (layout == NULL) {
2303 "%s %s: option -E must be specified with --component-add\n",
2308 result = adjust_first_extent(fname, layout);
2309 if (result == -ENODATA)
2311 else if (result != 0)
2315 if (mdt_idx_arg != NULL && optind > 3) {
2317 "%s %s: option -m cannot be used with other options\n",
2322 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
2324 "%s %s: options --non-block and --block are mutually exclusive\n",
2329 if (!comp_del && !comp_set && comp_id != 0) {
2331 "%s %s: option -I can only be used with --component-del\n",
2336 if (mdt_idx_arg != NULL) {
2337 /* initialize migrate mdt parameters */
2338 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
2340 fprintf(stderr, "%s %s: invalid MDT index '%s'\n",
2341 progname, argv[0], mdt_idx_arg);
2344 migrate_mdt_param.fp_migrate = 1;
2345 } else if (layout == NULL) {
2346 /* initialize stripe parameters */
2347 param = calloc(1, offsetof(typeof(*param),
2348 lsp_osts[lsa.lsa_nr_osts]));
2349 if (param == NULL) {
2351 "%s %s: cannot allocate memory for parameters: %s\n",
2352 progname, argv[0], strerror(ENOMEM));
2357 if (lsa.lsa_stripe_size != LLAPI_LAYOUT_DEFAULT)
2358 param->lsp_stripe_size = lsa.lsa_stripe_size;
2359 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
2360 if (lsa.lsa_stripe_count == LLAPI_LAYOUT_WIDE)
2361 param->lsp_stripe_count = -1;
2363 param->lsp_stripe_count = lsa.lsa_stripe_count;
2365 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
2366 param->lsp_stripe_offset = -1;
2368 param->lsp_stripe_offset = lsa.lsa_stripe_off;
2369 param->lsp_pool = lsa.lsa_pool_name;
2370 param->lsp_is_specific = false;
2371 if (lsa.lsa_nr_osts > 0) {
2372 if (lsa.lsa_stripe_count > 0 &&
2373 lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
2374 lsa.lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
2375 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
2376 fprintf(stderr, "error: %s: stripe count %lld "
2377 "doesn't match the number of OSTs: %d\n"
2378 , argv[0], lsa.lsa_stripe_count,
2384 param->lsp_is_specific = true;
2385 param->lsp_stripe_count = lsa.lsa_nr_osts;
2386 memcpy(param->lsp_osts, osts,
2387 sizeof(*osts) * lsa.lsa_nr_osts);
2391 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
2392 if (mdt_idx_arg != NULL) {
2393 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
2394 } else if (migrate_mode) {
2395 result = lfs_migrate(fname, migration_flags, param,
2397 } else if (comp_set != 0) {
2398 result = lfs_component_set(fname, comp_id,
2399 lsa.lsa_comp_flags);
2400 } else if (comp_del != 0) {
2401 result = lfs_component_del(fname, comp_id,
2402 lsa.lsa_comp_flags);
2403 } else if (comp_add != 0) {
2404 result = lfs_component_add(fname, layout);
2405 } else if (opc == SO_MIRROR_CREATE) {
2406 result = mirror_create(fname, mirror_list);
2407 } else if (opc == SO_MIRROR_EXTEND) {
2408 result = mirror_extend(fname, mirror_list,
2410 } else if (layout != NULL) {
2411 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
2418 result = llapi_file_open_param(fname,
2427 /* Save the first error encountered. */
2435 llapi_layout_free(layout);
2436 lfs_mirror_list_free(mirror_list);
2441 llapi_layout_free(layout);
2442 lfs_mirror_list_free(mirror_list);
2446 static int lfs_poollist(int argc, char **argv)
2451 return llapi_poollist(argv[1]);
2454 static int set_time(time_t *time, time_t *set, char *str)
2461 else if (str[0] == '-')
2467 t = strtol(str, NULL, 0);
2468 if (*time < t * 24 * 60 * 60) {
2471 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
2475 *set = *time - t * 24 * 60 * 60;
2478 static int name2uid(unsigned int *id, const char *name)
2480 struct passwd *passwd;
2482 passwd = getpwnam(name);
2485 *id = passwd->pw_uid;
2490 static int name2gid(unsigned int *id, const char *name)
2492 struct group *group;
2494 group = getgrnam(name);
2497 *id = group->gr_gid;
2502 static inline int name2projid(unsigned int *id, const char *name)
2507 static int uid2name(char **name, unsigned int id)
2509 struct passwd *passwd;
2511 passwd = getpwuid(id);
2514 *name = passwd->pw_name;
2519 static inline int gid2name(char **name, unsigned int id)
2521 struct group *group;
2523 group = getgrgid(id);
2526 *name = group->gr_name;
2531 static int name2layout(__u32 *layout, char *name)
2533 char *ptr, *layout_name;
2536 for (ptr = name; ; ptr = NULL) {
2537 layout_name = strtok(ptr, ",");
2538 if (layout_name == NULL)
2540 if (strcmp(layout_name, "released") == 0)
2541 *layout |= LOV_PATTERN_F_RELEASED;
2542 else if (strcmp(layout_name, "raid0") == 0)
2543 *layout |= LOV_PATTERN_RAID0;
2544 else if (strcmp(layout_name, "mdt") == 0)
2545 *layout |= LOV_PATTERN_MDT;
2552 static int lfs_find(int argc, char **argv)
2557 struct find_param param = {
2561 struct option long_opts[] = {
2562 { .val = 'A', .name = "atime", .has_arg = required_argument },
2563 { .val = LFS_COMP_COUNT_OPT,
2564 .name = "comp-count", .has_arg = required_argument },
2565 { .val = LFS_COMP_COUNT_OPT,
2566 .name = "component-count",
2567 .has_arg = required_argument },
2568 { .val = LFS_COMP_FLAGS_OPT,
2569 .name = "comp-flags", .has_arg = required_argument },
2570 { .val = LFS_COMP_FLAGS_OPT,
2571 .name = "component-flags",
2572 .has_arg = required_argument },
2573 { .val = LFS_COMP_START_OPT,
2574 .name = "comp-start", .has_arg = required_argument },
2575 { .val = LFS_COMP_START_OPT,
2576 .name = "component-start",
2577 .has_arg = required_argument },
2578 { .val = 'c', .name = "stripe-count", .has_arg = required_argument },
2579 { .val = 'c', .name = "stripe_count", .has_arg = required_argument },
2580 { .val = 'C', .name = "ctime", .has_arg = required_argument },
2581 { .val = 'D', .name = "maxdepth", .has_arg = required_argument },
2582 { .val = 'E', .name = "comp-end", .has_arg = required_argument },
2583 { .val = 'E', .name = "component-end",
2584 .has_arg = required_argument },
2585 { .val = 'g', .name = "gid", .has_arg = required_argument },
2586 { .val = 'G', .name = "group", .has_arg = required_argument },
2587 { .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
2588 { .val = 'i', .name = "stripe-index", .has_arg = required_argument },
2589 { .val = 'i', .name = "stripe_index", .has_arg = required_argument },
2590 /*{"component-id", required_argument, 0, 'I'},*/
2591 { .val = 'L', .name = "layout", .has_arg = required_argument },
2592 { .val = 'm', .name = "mdt", .has_arg = required_argument },
2593 { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
2594 { .val = 'm', .name = "mdt_index", .has_arg = required_argument },
2595 { .val = 'M', .name = "mtime", .has_arg = required_argument },
2596 { .val = 'n', .name = "name", .has_arg = required_argument },
2597 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
2598 { .val = 'O', .name = "obd", .has_arg = required_argument },
2599 { .val = 'O', .name = "ost", .has_arg = required_argument },
2600 /* no short option for pool, p/P already used */
2601 { .val = LFS_POOL_OPT,
2602 .name = "pool", .has_arg = required_argument },
2603 { .val = 'p', .name = "print0", .has_arg = no_argument },
2604 { .val = 'P', .name = "print", .has_arg = no_argument },
2605 { .val = LFS_PROJID_OPT,
2606 .name = "projid", .has_arg = required_argument },
2607 { .val = 's', .name = "size", .has_arg = required_argument },
2608 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
2609 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
2610 { .val = 't', .name = "type", .has_arg = required_argument },
2611 { .val = 'T', .name = "mdt-count", .has_arg = required_argument },
2612 { .val = 'u', .name = "uid", .has_arg = required_argument },
2613 { .val = 'U', .name = "user", .has_arg = required_argument },
2625 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
2626 while ((c = getopt_long_only(argc, argv,
2627 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
2628 long_opts, NULL)) >= 0) {
2633 /* '!' is part of option */
2634 /* when getopt_long_only() finds a string which is not
2635 * an option nor a known option argument it returns 1
2636 * in that case if we already have found pathstart and pathend
2637 * (i.e. we have the list of pathnames),
2638 * the only supported value is "!"
2640 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
2641 if (!isoption && pathend != -1) {
2642 fprintf(stderr, "err: %s: filename|dirname must either "
2643 "precede options or follow options\n",
2648 if (!isoption && pathstart == -1)
2649 pathstart = optind - 1;
2650 if (isoption && pathstart != -1 && pathend == -1)
2651 pathend = optind - 2;
2657 /* unknown; opt is "!" or path component,
2658 * checking done above.
2660 if (strcmp(optarg, "!") == 0)
2664 xtime = ¶m.fp_atime;
2665 xsign = ¶m.fp_asign;
2666 param.fp_exclude_atime = !!neg_opt;
2667 /* no break, this falls through to 'C' for ctime */
2670 xtime = ¶m.fp_ctime;
2671 xsign = ¶m.fp_csign;
2672 param.fp_exclude_ctime = !!neg_opt;
2674 /* no break, this falls through to 'M' for mtime */
2677 xtime = ¶m.fp_mtime;
2678 xsign = ¶m.fp_msign;
2679 param.fp_exclude_mtime = !!neg_opt;
2681 rc = set_time(&t, xtime, optarg);
2682 if (rc == INT_MAX) {
2689 case LFS_COMP_COUNT_OPT:
2690 if (optarg[0] == '+') {
2691 param.fp_comp_count_sign = -1;
2693 } else if (optarg[0] == '-') {
2694 param.fp_comp_count_sign = 1;
2698 param.fp_comp_count = strtoul(optarg, &endptr, 0);
2699 if (*endptr != '\0') {
2700 fprintf(stderr, "error: bad component count "
2704 param.fp_check_comp_count = 1;
2705 param.fp_exclude_comp_count = !!neg_opt;
2707 case LFS_COMP_FLAGS_OPT:
2708 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
2709 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2710 fprintf(stderr, "error: bad component flags "
2714 param.fp_check_comp_flags = 1;
2715 param.fp_exclude_comp_flags = !!neg_opt;
2717 case LFS_COMP_START_OPT:
2718 if (optarg[0] == '+') {
2719 param.fp_comp_start_sign = -1;
2721 } else if (optarg[0] == '-') {
2722 param.fp_comp_start_sign = 1;
2726 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2727 ¶m.fp_comp_start_units, 0);
2729 fprintf(stderr, "error: bad component start "
2733 param.fp_check_comp_start = 1;
2734 param.fp_exclude_comp_start = !!neg_opt;
2737 if (optarg[0] == '+') {
2738 param.fp_stripe_count_sign = -1;
2740 } else if (optarg[0] == '-') {
2741 param.fp_stripe_count_sign = 1;
2745 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2746 if (*endptr != '\0') {
2747 fprintf(stderr,"error: bad stripe_count '%s'\n",
2752 param.fp_check_stripe_count = 1;
2753 param.fp_exclude_stripe_count = !!neg_opt;
2756 param.fp_max_depth = strtol(optarg, 0, 0);
2759 if (optarg[0] == '+') {
2760 param.fp_comp_end_sign = -1;
2762 } else if (optarg[0] == '-') {
2763 param.fp_comp_end_sign = 1;
2767 if (arg_is_eof(optarg)) {
2768 param.fp_comp_end = LUSTRE_EOF;
2769 param.fp_comp_end_units = 1;
2772 rc = llapi_parse_size(optarg,
2774 ¶m.fp_comp_end_units, 0);
2777 fprintf(stderr, "error: bad component end "
2781 param.fp_check_comp_end = 1;
2782 param.fp_exclude_comp_end = !!neg_opt;
2786 rc = name2gid(¶m.fp_gid, optarg);
2788 param.fp_gid = strtoul(optarg, &endptr, 10);
2789 if (*endptr != '\0') {
2790 fprintf(stderr, "Group/GID: %s cannot "
2791 "be found.\n", optarg);
2796 param.fp_exclude_gid = !!neg_opt;
2797 param.fp_check_gid = 1;
2800 param.fp_hash_type = check_hashtype(optarg);
2801 if (param.fp_hash_type == 0) {
2802 fprintf(stderr, "error: bad hash_type '%s'\n",
2807 param.fp_check_hash_type = 1;
2808 param.fp_exclude_hash_type = !!neg_opt;
2811 ret = name2layout(¶m.fp_layout, optarg);
2814 param.fp_exclude_layout = !!neg_opt;
2815 param.fp_check_layout = 1;
2819 rc = name2uid(¶m.fp_uid, optarg);
2821 param.fp_uid = strtoul(optarg, &endptr, 10);
2822 if (*endptr != '\0') {
2823 fprintf(stderr, "User/UID: %s cannot "
2824 "be found.\n", optarg);
2829 param.fp_exclude_uid = !!neg_opt;
2830 param.fp_check_uid = 1;
2833 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2835 "Pool name %s is too long"
2836 " (max is %d)\n", optarg,
2841 /* we do check for empty pool because empty pool
2842 * is used to find V1 lov attributes */
2843 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2844 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2845 param.fp_exclude_pool = !!neg_opt;
2846 param.fp_check_pool = 1;
2849 param.fp_pattern = (char *)optarg;
2850 param.fp_exclude_pattern = !!neg_opt;
2855 char *buf, *token, *next, *p;
2859 buf = strdup(optarg);
2865 param.fp_exclude_obd = !!neg_opt;
2868 while (token && *token) {
2869 token = strchr(token, ',');
2876 param.fp_exclude_mdt = !!neg_opt;
2877 param.fp_num_alloc_mdts += len;
2878 tmp = realloc(param.fp_mdt_uuid,
2879 param.fp_num_alloc_mdts *
2880 sizeof(*param.fp_mdt_uuid));
2886 param.fp_mdt_uuid = tmp;
2888 param.fp_exclude_obd = !!neg_opt;
2889 param.fp_num_alloc_obds += len;
2890 tmp = realloc(param.fp_obd_uuid,
2891 param.fp_num_alloc_obds *
2892 sizeof(*param.fp_obd_uuid));
2898 param.fp_obd_uuid = tmp;
2900 for (token = buf; token && *token; token = next) {
2901 struct obd_uuid *puuid;
2904 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2907 ¶m.fp_obd_uuid[param.fp_num_obds++];
2909 p = strchr(token, ',');
2916 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2921 strncpy(puuid->uuid, token,
2922 sizeof(puuid->uuid));
2930 param.fp_zero_end = 1;
2934 case LFS_PROJID_OPT:
2935 rc = name2projid(¶m.fp_projid, optarg);
2937 param.fp_projid = strtoul(optarg, &endptr, 10);
2938 if (*endptr != '\0') {
2940 "Invalid project ID: %s",
2946 param.fp_exclude_projid = !!neg_opt;
2947 param.fp_check_projid = 1;
2950 if (optarg[0] == '+') {
2951 param.fp_size_sign = -1;
2953 } else if (optarg[0] == '-') {
2954 param.fp_size_sign = 1;
2958 ret = llapi_parse_size(optarg, ¶m.fp_size,
2959 ¶m.fp_size_units, 0);
2961 fprintf(stderr, "error: bad file size '%s'\n",
2965 param.fp_check_size = 1;
2966 param.fp_exclude_size = !!neg_opt;
2969 if (optarg[0] == '+') {
2970 param.fp_stripe_size_sign = -1;
2972 } else if (optarg[0] == '-') {
2973 param.fp_stripe_size_sign = 1;
2977 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2978 ¶m.fp_stripe_size_units, 0);
2980 fprintf(stderr, "error: bad stripe_size '%s'\n",
2984 param.fp_check_stripe_size = 1;
2985 param.fp_exclude_stripe_size = !!neg_opt;
2988 param.fp_exclude_type = !!neg_opt;
2989 switch (optarg[0]) {
2991 param.fp_type = S_IFBLK;
2994 param.fp_type = S_IFCHR;
2997 param.fp_type = S_IFDIR;
3000 param.fp_type = S_IFREG;
3003 param.fp_type = S_IFLNK;
3006 param.fp_type = S_IFIFO;
3009 param.fp_type = S_IFSOCK;
3012 fprintf(stderr, "error: %s: bad type '%s'\n",
3019 if (optarg[0] == '+') {
3020 param.fp_mdt_count_sign = -1;
3022 } else if (optarg[0] == '-') {
3023 param.fp_mdt_count_sign = 1;
3027 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
3028 if (*endptr != '\0') {
3029 fprintf(stderr, "error: bad mdt_count '%s'\n",
3034 param.fp_check_mdt_count = 1;
3035 param.fp_exclude_mdt_count = !!neg_opt;
3043 if (pathstart == -1) {
3044 fprintf(stderr, "error: %s: no filename|pathname\n",
3048 } else if (pathend == -1) {
3054 rc = llapi_find(argv[pathstart], ¶m);
3055 if (rc != 0 && ret == 0)
3057 } while (++pathstart < pathend);
3060 fprintf(stderr, "error: %s failed for %s.\n",
3061 argv[0], argv[optind - 1]);
3063 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
3064 free(param.fp_obd_uuid);
3066 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
3067 free(param.fp_mdt_uuid);
3072 static int lfs_getstripe_internal(int argc, char **argv,
3073 struct find_param *param)
3075 struct option long_opts[] = {
3076 { .val = LFS_COMP_COUNT_OPT,
3077 .name = "comp-count", .has_arg = no_argument },
3078 { .val = LFS_COMP_COUNT_OPT,
3079 .name = "component-count", .has_arg = no_argument },
3080 { .val = LFS_COMP_FLAGS_OPT,
3081 .name = "comp-flags", .has_arg = optional_argument },
3082 { .val = LFS_COMP_FLAGS_OPT,
3083 .name = "component-flags", .has_arg = optional_argument },
3084 { .val = LFS_COMP_START_OPT,
3085 .name = "comp-start", .has_arg = optional_argument },
3086 { .val = LFS_COMP_START_OPT,
3087 .name = "component-start", .has_arg = optional_argument },
3088 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3089 /* This formerly implied "stripe-count", but was explicitly
3090 * made "stripe-count" for consistency with other options,
3091 * and to separate it from "mdt-count" when DNE arrives. */
3092 { .val = 'c', .name = "count", .has_arg = no_argument },
3094 { .val = 'c', .name = "stripe-count", .has_arg = no_argument },
3095 { .val = 'c', .name = "stripe_count", .has_arg = no_argument },
3096 { .val = 'd', .name = "directory", .has_arg = no_argument },
3097 { .val = 'D', .name = "default", .has_arg = no_argument },
3098 { .val = 'E', .name = "comp-end", .has_arg = optional_argument },
3099 { .val = 'E', .name = "component-end",
3100 .has_arg = optional_argument },
3101 { .val = 'F', .name = "fid", .has_arg = no_argument },
3102 { .val = 'g', .name = "generation", .has_arg = no_argument },
3103 /* dirstripe { .val = 'H', .name = "mdt-hash",
3104 * .has_arg = required_argument }, */
3105 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3106 /* This formerly implied "stripe-index", but was explicitly
3107 * made "stripe-index" for consistency with other options,
3108 * and to separate it from "mdt-index" when DNE arrives. */
3109 { .val = 'i', .name = "index", .has_arg = no_argument },
3111 { .val = 'i', .name = "stripe-index", .has_arg = no_argument },
3112 { .val = 'i', .name = "stripe_index", .has_arg = no_argument },
3113 { .val = 'I', .name = "comp-id", .has_arg = optional_argument },
3114 { .val = 'I', .name = "component-id", .has_arg = optional_argument },
3115 { .val = 'L', .name = "layout", .has_arg = no_argument },
3116 { .val = 'm', .name = "mdt", .has_arg = no_argument },
3117 { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
3118 { .val = 'm', .name = "mdt_index", .has_arg = no_argument },
3119 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3120 { .val = 'M', .name = "mdt-index", .has_arg = no_argument },
3121 { .val = 'M', .name = "mdt_index", .has_arg = no_argument },
3123 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3124 /* This formerly implied "stripe-index", but was confusing
3125 * with "file offset" (which will eventually be needed for
3126 * with different layouts by offset), so deprecate it. */
3127 { .val = 'o', .name = "offset", .has_arg = no_argument },
3129 { .val = 'O', .name = "obd", .has_arg = required_argument },
3130 { .val = 'O', .name = "ost", .has_arg = required_argument },
3131 { .val = 'p', .name = "pool", .has_arg = no_argument },
3132 { .val = 'q', .name = "quiet", .has_arg = no_argument },
3133 { .val = 'r', .name = "recursive", .has_arg = no_argument },
3134 { .val = 'R', .name = "raw", .has_arg = no_argument },
3135 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3136 /* This formerly implied "--stripe-size", but was confusing
3137 * with "lfs find --size|-s", which means "file size", so use
3138 * the consistent "--stripe-size|-S" for all commands. */
3139 { .val = 's', .name = "size", .has_arg = no_argument },
3141 { .val = 'S', .name = "stripe-size", .has_arg = no_argument },
3142 { .val = 'S', .name = "stripe_size", .has_arg = no_argument },
3143 /* dirstripe { .val = 'T', .name = "mdt-count",
3144 * .has_arg = required_argument }, */
3145 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3146 { .val = 'y', .name = "yaml", .has_arg = no_argument },
3151 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
3152 long_opts, NULL)) != -1) {
3155 if (strcmp(argv[optind - 1], "--count") == 0)
3156 fprintf(stderr, "warning: '--count' deprecated,"
3157 " use '--stripe-count' instead\n");
3158 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3159 param->fp_verbose |= VERBOSE_COUNT;
3160 param->fp_max_depth = 0;
3163 case LFS_COMP_COUNT_OPT:
3164 param->fp_verbose |= VERBOSE_COMP_COUNT;
3165 param->fp_max_depth = 0;
3167 case LFS_COMP_FLAGS_OPT:
3168 if (optarg != NULL) {
3169 __u32 *flags = ¶m->fp_comp_flags;
3170 rc = comp_str2flags(flags, optarg);
3172 fprintf(stderr, "error: %s bad "
3173 "component flags '%s'.\n",
3177 param->fp_check_comp_flags = 1;
3178 param->fp_exclude_comp_flags =
3179 comp_flags_is_neg(*flags);
3180 comp_flags_clear_neg(flags);
3183 param->fp_verbose |= VERBOSE_COMP_FLAGS;
3184 param->fp_max_depth = 0;
3187 case LFS_COMP_START_OPT:
3188 if (optarg != NULL) {
3190 if (tmp[0] == '+') {
3191 param->fp_comp_start_sign = -1;
3193 } else if (tmp[0] == '-') {
3194 param->fp_comp_start_sign = 1;
3197 rc = llapi_parse_size(tmp,
3198 ¶m->fp_comp_start,
3199 ¶m->fp_comp_start_units, 0);
3201 fprintf(stderr, "error: %s bad "
3202 "component start '%s'.\n",
3206 param->fp_check_comp_start = 1;
3209 param->fp_verbose |= VERBOSE_COMP_START;
3210 param->fp_max_depth = 0;
3214 param->fp_max_depth = 0;
3217 param->fp_get_default_lmv = 1;
3220 if (optarg != NULL) {
3222 if (tmp[0] == '+') {
3223 param->fp_comp_end_sign = -1;
3225 } else if (tmp[0] == '-') {
3226 param->fp_comp_end_sign = 1;
3230 if (arg_is_eof(tmp)) {
3231 param->fp_comp_end = LUSTRE_EOF;
3232 param->fp_comp_end_units = 1;
3235 rc = llapi_parse_size(tmp,
3236 ¶m->fp_comp_end,
3237 ¶m->fp_comp_end_units, 0);
3240 fprintf(stderr, "error: %s bad "
3241 "component end '%s'.\n",
3245 param->fp_check_comp_end = 1;
3247 param->fp_verbose |= VERBOSE_COMP_END;
3248 param->fp_max_depth = 0;
3252 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3253 param->fp_verbose |= VERBOSE_DFID;
3254 param->fp_max_depth = 0;
3258 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3259 param->fp_verbose |= VERBOSE_GENERATION;
3260 param->fp_max_depth = 0;
3263 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3265 fprintf(stderr, "warning: '--offset|-o' deprecated, "
3266 "use '--stripe-index|-i' instead\n");
3269 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
3270 if (strcmp(argv[optind - 1], "--index") == 0)
3271 fprintf(stderr, "warning: '--index' deprecated"
3272 ", use '--stripe-index' instead\n");
3274 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3275 param->fp_verbose |= VERBOSE_OFFSET;
3276 param->fp_max_depth = 0;
3280 if (optarg != NULL) {
3281 param->fp_comp_id = strtoul(optarg, &end, 0);
3282 if (*end != '\0' || param->fp_comp_id == 0 ||
3283 param->fp_comp_id > LCME_ID_MAX) {
3284 fprintf(stderr, "error: %s bad "
3285 "component id '%s'\n",
3289 param->fp_check_comp_id = 1;
3292 param->fp_max_depth = 0;
3293 param->fp_verbose |= VERBOSE_COMP_ID;
3297 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3298 param->fp_verbose |= VERBOSE_LAYOUT;
3299 param->fp_max_depth = 0;
3302 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3304 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3305 fprintf(stderr, "warning: '-M' deprecated"
3306 ", use '-m' instead\n");
3310 if (!(param->fp_verbose & VERBOSE_DETAIL))
3311 param->fp_max_depth = 0;
3312 param->fp_verbose |= VERBOSE_MDTINDEX;
3315 if (param->fp_obd_uuid) {
3317 "error: %s: only one obduuid allowed",
3321 param->fp_obd_uuid = (struct obd_uuid *)optarg;
3324 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3325 param->fp_verbose |= VERBOSE_POOL;
3326 param->fp_max_depth = 0;
3333 param->fp_recursive = 1;
3338 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3340 fprintf(stderr, "warning: '--size|-s' deprecated, "
3341 "use '--stripe-size|-S' instead\n");
3342 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
3344 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3345 param->fp_verbose |= VERBOSE_SIZE;
3346 param->fp_max_depth = 0;
3350 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
3363 if (param->fp_recursive)
3364 param->fp_max_depth = -1;
3365 else if (param->fp_verbose & VERBOSE_DETAIL)
3366 param->fp_max_depth = 1;
3368 if (!param->fp_verbose)
3369 param->fp_verbose = VERBOSE_DEFAULT;
3370 if (param->fp_quiet)
3371 param->fp_verbose = VERBOSE_OBJID;
3374 rc = llapi_getstripe(argv[optind], param);
3375 } while (++optind < argc && !rc);
3378 fprintf(stderr, "error: %s failed for %s.\n",
3379 argv[0], argv[optind - 1]);
3383 static int lfs_tgts(int argc, char **argv)
3385 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3386 struct find_param param;
3387 int index = 0, rc=0;
3392 if (argc == 2 && !realpath(argv[1], path)) {
3394 fprintf(stderr, "error: invalid path '%s': %s\n",
3395 argv[1], strerror(-rc));
3399 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
3400 /* Check if we have a mount point */
3401 if (mntdir[0] == '\0')
3404 memset(¶m, 0, sizeof(param));
3405 if (!strcmp(argv[0], "mdts"))
3406 param.fp_get_lmv = 1;
3408 rc = llapi_ostlist(mntdir, ¶m);
3410 fprintf(stderr, "error: %s: failed on %s\n",
3413 if (path[0] != '\0')
3415 memset(mntdir, 0, PATH_MAX);
3421 static int lfs_getstripe(int argc, char **argv)
3423 struct find_param param = { 0 };
3425 param.fp_max_depth = 1;
3426 return lfs_getstripe_internal(argc, argv, ¶m);
3430 static int lfs_getdirstripe(int argc, char **argv)
3432 struct find_param param = { 0 };
3433 struct option long_opts[] = {
3434 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3435 { .val = 'c', .name = "mdt-count", .has_arg = no_argument },
3437 { .val = 'D', .name = "default", .has_arg = no_argument },
3438 { .val = 'H', .name = "mdt-hash", .has_arg = no_argument },
3439 { .val = 'i', .name = "mdt-index", .has_arg = no_argument },
3440 { .val = 'O', .name = "obd", .has_arg = required_argument },
3441 { .val = 'r', .name = "recursive", .has_arg = no_argument },
3442 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3443 { .val = 't', .name = "mdt-hash", .has_arg = no_argument },
3445 { .val = 'T', .name = "mdt-count", .has_arg = no_argument },
3446 { .val = 'y', .name = "yaml", .has_arg = no_argument },
3450 param.fp_get_lmv = 1;
3452 while ((c = getopt_long(argc, argv,
3453 "cDHiO:rtTy", long_opts, NULL)) != -1)
3457 if (param.fp_obd_uuid) {
3459 "error: %s: only one obduuid allowed",
3463 param.fp_obd_uuid = (struct obd_uuid *)optarg;
3465 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3467 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
3468 fprintf(stderr, "warning: '-c' deprecated"
3469 ", use '-T' instead\n");
3473 param.fp_verbose |= VERBOSE_COUNT;
3476 param.fp_verbose |= VERBOSE_OFFSET;
3478 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3482 param.fp_verbose |= VERBOSE_HASH_TYPE;
3485 param.fp_get_default_lmv = 1;
3488 param.fp_recursive = 1;
3501 if (param.fp_recursive)
3502 param.fp_max_depth = -1;
3504 if (!param.fp_verbose)
3505 param.fp_verbose = VERBOSE_DEFAULT;
3508 rc = llapi_getstripe(argv[optind], ¶m);
3509 } while (++optind < argc && !rc);
3512 fprintf(stderr, "error: %s failed for %s.\n",
3513 argv[0], argv[optind - 1]);
3518 static int lfs_setdirstripe(int argc, char **argv)
3522 unsigned int stripe_offset = -1;
3523 unsigned int stripe_count = 1;
3524 enum lmv_hash_type hash_type;
3527 char *stripe_offset_opt = NULL;
3528 char *stripe_count_opt = NULL;
3529 char *stripe_hash_opt = NULL;
3530 char *mode_opt = NULL;
3531 bool default_stripe = false;
3532 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
3533 mode_t previous_mode = 0;
3534 bool delete = false;
3536 struct option long_opts[] = {
3537 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3538 { .val = 'c', .name = "count", .has_arg = required_argument },
3540 { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
3541 { .val = 'd', .name = "delete", .has_arg = no_argument },
3542 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3543 { .val = 'i', .name = "index", .has_arg = required_argument },
3545 { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
3546 { .val = 'm', .name = "mode", .has_arg = required_argument },
3547 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3548 { .val = 't', .name = "hash-type", .has_arg = required_argument },
3549 { .val = 't', .name = "mdt-hash", .has_arg = required_argument },
3551 {"mdt-hash", required_argument, 0, 'H'},
3552 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3553 { .val = 'D', .name = "default_stripe",
3554 .has_arg = no_argument },
3556 { .val = 'D', .name = "default", .has_arg = no_argument },
3559 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
3566 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3567 if (strcmp(argv[optind - 1], "--count") == 0)
3569 "%s %s: warning: '--count' deprecated, use '--mdt-count' instead\n",
3572 stripe_count_opt = optarg;
3576 default_stripe = true;
3579 default_stripe = true;
3582 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3583 if (strcmp(argv[optind - 1], "--index") == 0)
3585 "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
3588 stripe_offset_opt = optarg;
3593 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3597 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3598 if (strcmp(argv[optind - 1], "--hash-type") == 0)
3600 "%s %s: warning: '--hash-type' deprecated, use '--mdt-hash' instead\n",
3603 stripe_hash_opt = optarg;
3606 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
3607 progname, argv[0], argv[optind - 1]);
3612 if (optind == argc) {
3613 fprintf(stderr, "%s %s: DIR must be specified\n",
3618 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
3620 "%s %s: stripe offset and count must be specified\n",
3625 if (stripe_offset_opt != NULL) {
3626 /* get the stripe offset */
3627 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
3630 "%s %s: bad stripe offset '%s'\n",
3631 progname, argv[0], stripe_offset_opt);
3637 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
3639 "%s %s: cannot specify -d with -c or -i options\n",
3648 if (mode_opt != NULL) {
3649 mode = strtoul(mode_opt, &end, 8);
3652 "%s %s: bad MODE '%s'\n",
3653 progname, argv[0], mode_opt);
3656 previous_mode = umask(0);
3659 if (stripe_hash_opt == NULL) {
3660 hash_type = LMV_HASH_TYPE_FNV_1A_64;
3662 hash_type = check_hashtype(stripe_hash_opt);
3663 if (hash_type == 0) {
3664 fprintf(stderr, "%s %s: bad stripe hash type '%s'\n",
3665 progname, argv[0], stripe_hash_opt);
3670 /* get the stripe count */
3671 if (stripe_count_opt != NULL) {
3672 stripe_count = strtoul(stripe_count_opt, &end, 0);
3675 "%s %s: bad stripe count '%s'\n",
3676 progname, argv[0], stripe_count_opt);
3681 dname = argv[optind];
3683 if (default_stripe) {
3684 result = llapi_dir_set_default_lmv_stripe(dname,
3685 stripe_offset, stripe_count,
3688 result = llapi_dir_create_pool(dname, mode,
3690 stripe_count, hash_type,
3696 "%s setdirstripe: cannot create stripe dir '%s': %s\n",
3697 progname, dname, strerror(-result));
3700 dname = argv[++optind];
3701 } while (dname != NULL);
3703 if (mode_opt != NULL)
3704 umask(previous_mode);
3710 static int lfs_rmentry(int argc, char **argv)
3717 fprintf(stderr, "error: %s: missing dirname\n",
3723 dname = argv[index];
3724 while (dname != NULL) {
3725 result = llapi_direntry_remove(dname);
3727 fprintf(stderr, "error: %s: remove dir entry '%s' "
3728 "failed\n", argv[0], dname);
3731 dname = argv[++index];
3736 static int lfs_mv(int argc, char **argv)
3738 struct find_param param = {
3745 struct option long_opts[] = {
3746 { .val = 'M', .name = "mdt-index", .has_arg = required_argument },
3747 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3750 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3753 param.fp_mdt_index = strtoul(optarg, &end, 0);
3755 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3762 param.fp_verbose = VERBOSE_DETAIL;
3766 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3767 argv[0], argv[optind - 1]);
3772 if (param.fp_mdt_index == -1) {
3773 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3777 if (optind >= argc) {
3778 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3782 param.fp_migrate = 1;
3783 rc = llapi_migrate_mdt(argv[optind], ¶m);
3785 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3786 argv[0], argv[optind], param.fp_mdt_index,
3791 static int lfs_osts(int argc, char **argv)
3793 return lfs_tgts(argc, argv);
3796 static int lfs_mdts(int argc, char **argv)
3798 return lfs_tgts(argc, argv);
3801 #define COOK(value) \
3804 while (value > 1024) { \
3812 #define CDF "%11llu"
3813 #define HDF "%8.1f%c"
3818 MNTDF_INODES = 0x0001,
3819 MNTDF_COOKED = 0x0002,
3820 MNTDF_LAZY = 0x0004,
3821 MNTDF_VERBOSE = 0x0008,
3824 static int showdf(char *mntdir, struct obd_statfs *stat,
3825 char *uuid, enum mntdf_flags flags,
3826 char *type, int index, int rc)
3828 long long avail, used, total;
3830 char *suffix = "KMGTPEZY";
3831 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3832 char tbuf[3 * sizeof(__u64)];
3833 char ubuf[3 * sizeof(__u64)];
3834 char abuf[3 * sizeof(__u64)];
3835 char rbuf[3 * sizeof(__u64)];
3842 if (flags & MNTDF_INODES) {
3843 avail = stat->os_ffree;
3844 used = stat->os_files - stat->os_ffree;
3845 total = stat->os_files;
3847 int shift = flags & MNTDF_COOKED ? 0 : 10;
3849 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3850 used = ((stat->os_blocks - stat->os_bfree) *
3851 stat->os_bsize) >> shift;
3852 total = (stat->os_blocks * stat->os_bsize) >> shift;
3855 if ((used + avail) > 0)
3856 ratio = (double)used / (double)(used + avail);
3858 if (flags & MNTDF_COOKED) {
3862 cook_val = (double)total;
3865 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3868 snprintf(tbuf, sizeof(tbuf), CDF, total);
3870 cook_val = (double)used;
3873 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3876 snprintf(ubuf, sizeof(ubuf), CDF, used);
3878 cook_val = (double)avail;
3881 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3884 snprintf(abuf, sizeof(abuf), CDF, avail);
3886 snprintf(tbuf, sizeof(tbuf), CDF, total);
3887 snprintf(ubuf, sizeof(tbuf), CDF, used);
3888 snprintf(abuf, sizeof(tbuf), CDF, avail);
3891 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3892 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3893 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3895 printf("[%s:%d]", type, index);
3897 if (stat->os_state) {
3899 * Each character represents the matching
3902 const char state_names[] = "DRSI";
3907 for (i = 0, state = stat->os_state;
3908 state && i < sizeof(state_names); i++) {
3909 if (!(state & (1 << i)))
3911 printf("%c", state_names[i]);
3919 printf(UUF": inactive device\n", uuid);
3922 printf(UUF": %s\n", uuid, strerror(-rc));
3929 struct ll_stat_type {
3934 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3936 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3937 struct obd_uuid uuid_buf;
3938 char *poolname = NULL;
3939 struct ll_stat_type types[] = {
3940 { .st_op = LL_STATFS_LMV, .st_name = "MDT" },
3941 { .st_op = LL_STATFS_LOV, .st_name = "OST" },
3942 { .st_name = NULL } };
3943 struct ll_stat_type *tp;
3944 __u64 ost_ffree = 0;
3952 poolname = strchr(pool, '.');
3953 if (poolname != NULL) {
3954 if (strncmp(fsname, pool, strlen(fsname))) {
3955 fprintf(stderr, "filesystem name incorrect\n");
3963 fd = open(mntdir, O_RDONLY);
3966 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3971 if (flags & MNTDF_INODES)
3972 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3973 "UUID", "Inodes", "IUsed", "IFree",
3974 "IUse%", "Mounted on");
3976 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3977 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3978 "Used", "Available", "Use%", "Mounted on");
3980 for (tp = types; tp->st_name != NULL; tp++) {
3981 for (index = 0; ; index++) {
3982 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3983 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3984 type = flags & MNTDF_LAZY ?
3985 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3986 rc2 = llapi_obd_fstatfs(fd, type, index,
3987 &stat_buf, &uuid_buf);
3992 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3993 if (!(flags & MNTDF_VERBOSE))
3995 } else if (rc2 < 0 && rc == 0) {
3999 if (poolname && tp->st_op == LL_STATFS_LOV &&
4000 llapi_search_ost(fsname, poolname,
4001 obd_uuid2str(&uuid_buf)) != 1)
4004 /* the llapi_obd_statfs() call may have returned with
4005 * an error, but if it filled in uuid_buf we will at
4006 * lease use that to print out a message for that OBD.
4007 * If we didn't get anything in the uuid_buf, then fill
4008 * it in so that we can print an error message. */
4009 if (uuid_buf.uuid[0] == '\0')
4010 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
4011 "%s%04x", tp->st_name, index);
4012 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
4013 flags, tp->st_name, index, rc2);
4016 if (tp->st_op == LL_STATFS_LMV) {
4017 sum.os_ffree += stat_buf.os_ffree;
4018 sum.os_files += stat_buf.os_files;
4019 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
4020 sum.os_blocks += stat_buf.os_blocks *
4022 sum.os_bfree += stat_buf.os_bfree *
4024 sum.os_bavail += stat_buf.os_bavail *
4026 ost_ffree += stat_buf.os_ffree;
4034 /* If we don't have as many objects free on the OST as inodes
4035 * on the MDS, we reduce the total number of inodes to
4036 * compensate, so that the "inodes in use" number is correct.
4037 * Matches ll_statfs_internal() so the results are consistent. */
4038 if (ost_ffree < sum.os_ffree) {
4039 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
4040 sum.os_ffree = ost_ffree;
4043 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
4049 static int lfs_df(int argc, char **argv)
4051 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
4052 enum mntdf_flags flags = 0;
4053 int c, rc = 0, index = 0;
4054 char fsname[PATH_MAX] = "", *pool_name = NULL;
4055 struct option long_opts[] = {
4056 { .val = 'h', .name = "human-readable",
4057 .has_arg = no_argument },
4058 { .val = 'i', .name = "inodes", .has_arg = no_argument },
4059 { .val = 'l', .name = "lazy", .has_arg = no_argument },
4060 { .val = 'p', .name = "pool", .has_arg = required_argument },
4061 { .val = 'v', .name = "verbose", .has_arg = no_argument },
4064 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
4067 flags |= MNTDF_COOKED;
4070 flags |= MNTDF_INODES;
4073 flags |= MNTDF_LAZY;
4079 flags |= MNTDF_VERBOSE;
4085 if (optind < argc && !realpath(argv[optind], path)) {
4087 fprintf(stderr, "error: invalid path '%s': %s\n",
4088 argv[optind], strerror(-rc));
4092 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
4093 /* Check if we have a mount point */
4094 if (mntdir[0] == '\0')
4097 rc = mntdf(mntdir, fsname, pool_name, flags);
4098 if (rc || path[0] != '\0')
4100 fsname[0] = '\0'; /* avoid matching in next loop */
4101 mntdir[0] = '\0'; /* avoid matching in next loop */
4107 static int lfs_getname(int argc, char **argv)
4109 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
4110 int rc = 0, index = 0, c;
4111 char buf[sizeof(struct obd_uuid)];
4113 while ((c = getopt(argc, argv, "h")) != -1)
4116 if (optind == argc) { /* no paths specified, get all paths. */
4117 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
4118 rc = llapi_getname(mntdir, buf, sizeof(buf));
4121 "cannot get name for `%s': %s\n",
4122 mntdir, strerror(-rc));
4126 printf("%s %s\n", buf, mntdir);
4128 path[0] = fsname[0] = mntdir[0] = 0;
4130 } else { /* paths specified, only attempt to search these. */
4131 for (; optind < argc; optind++) {
4132 rc = llapi_getname(argv[optind], buf, sizeof(buf));
4135 "cannot get name for `%s': %s\n",
4136 argv[optind], strerror(-rc));
4140 printf("%s %s\n", buf, argv[optind]);
4146 static int lfs_check(int argc, char **argv)
4149 char mntdir[PATH_MAX] = {'\0'};
4158 obd_types[0] = obd_type1;
4159 obd_types[1] = obd_type2;
4161 if (strcmp(argv[1], "osts") == 0) {
4162 strcpy(obd_types[0], "osc");
4163 } else if (strcmp(argv[1], "mds") == 0) {
4164 strcpy(obd_types[0], "mdc");
4165 } else if (strcmp(argv[1], "servers") == 0) {
4167 strcpy(obd_types[0], "osc");
4168 strcpy(obd_types[1], "mdc");
4170 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4175 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
4176 if (rc < 0 || mntdir[0] == '\0') {
4177 fprintf(stderr, "No suitable Lustre mount found\n");
4181 rc = llapi_target_check(num_types, obd_types, mntdir);
4183 fprintf(stderr, "error: %s: %s status failed\n",
4190 #ifdef HAVE_SYS_QUOTA_H
4191 #define ARG2INT(nr, str, msg) \
4194 nr = strtol(str, &endp, 0); \
4196 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
4201 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
4203 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
4204 * returns the value or ULONG_MAX on integer overflow or incorrect format
4206 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
4207 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
4208 * 3. empty integer value is interpreted as 0
4210 static unsigned long str2sec(const char* timestr)
4212 const char spec[] = "smhdw";
4213 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
4214 unsigned long val = 0;
4217 if (strpbrk(timestr, spec) == NULL) {
4218 /* no specifiers inside the time string,
4219 should treat it as an integer value */
4220 val = strtoul(timestr, &tail, 10);
4221 return *tail ? ULONG_MAX : val;
4224 /* format string is XXwXXdXXhXXmXXs */
4230 v = strtoul(timestr, &tail, 10);
4231 if (v == ULONG_MAX || *tail == '\0')
4232 /* value too large (ULONG_MAX or more)
4233 or missing specifier */
4236 ptr = strchr(spec, *tail);
4238 /* unknown specifier */
4243 /* check if product will overflow the type */
4244 if (!(v < ULONG_MAX / mult[ind]))
4247 ADD_OVERFLOW(val, mult[ind] * v);
4248 if (val == ULONG_MAX)
4260 #define ARG2ULL(nr, str, def_units) \
4262 unsigned long long limit, units = def_units; \
4265 rc = llapi_parse_size(str, &limit, &units, 1); \
4267 fprintf(stderr, "error: bad limit value %s\n", str); \
4273 static inline int has_times_option(int argc, char **argv)
4277 for (i = 1; i < argc; i++)
4278 if (!strcmp(argv[i], "-t"))
4284 int lfs_setquota_times(int argc, char **argv)
4287 struct if_quotactl qctl;
4288 char *mnt, *obd_type = (char *)qctl.obd_type;
4289 struct obd_dqblk *dqb = &qctl.qc_dqblk;
4290 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
4291 struct option long_opts[] = {
4292 { .val = 'b', .name = "block-grace", .has_arg = required_argument },
4293 { .val = 'g', .name = "group", .has_arg = no_argument },
4294 { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
4295 { .val = 'p', .name = "projid", .has_arg = no_argument },
4296 { .val = 't', .name = "times", .has_arg = no_argument },
4297 { .val = 'u', .name = "user", .has_arg = no_argument },
4301 memset(&qctl, 0, sizeof(qctl));
4302 qctl.qc_cmd = LUSTRE_Q_SETINFO;
4303 qctl.qc_type = ALLQUOTA;
4305 while ((c = getopt_long(argc, argv, "b:gi:ptu",
4306 long_opts, NULL)) != -1) {
4317 if (qctl.qc_type != ALLQUOTA) {
4318 fprintf(stderr, "error: -u/g/p can't be used "
4319 "more than once\n");
4322 qctl.qc_type = qtype;
4325 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
4326 fprintf(stderr, "error: bad block-grace: %s\n",
4330 dqb->dqb_valid |= QIF_BTIME;
4333 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
4334 fprintf(stderr, "error: bad inode-grace: %s\n",
4338 dqb->dqb_valid |= QIF_ITIME;
4340 case 't': /* Yes, of course! */
4342 default: /* getopt prints error message for us when opterr != 0 */
4347 if (qctl.qc_type == ALLQUOTA) {
4348 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
4352 if (optind != argc - 1) {
4353 fprintf(stderr, "error: unexpected parameters encountered\n");
4358 rc = llapi_quotactl(mnt, &qctl);
4361 fprintf(stderr, "%s %s ", obd_type,
4362 obd_uuid2str(&qctl.obd_uuid));
4363 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
4370 #define BSLIMIT (1 << 0)
4371 #define BHLIMIT (1 << 1)
4372 #define ISLIMIT (1 << 2)
4373 #define IHLIMIT (1 << 3)
4375 int lfs_setquota(int argc, char **argv)
4378 struct if_quotactl qctl;
4379 char *mnt, *obd_type = (char *)qctl.obd_type;
4380 struct obd_dqblk *dqb = &qctl.qc_dqblk;
4381 struct option long_opts[] = {
4382 { .val = 'b', .name = "block-softlimit",
4383 .has_arg = required_argument },
4384 { .val = 'B', .name = "block-hardlimit",
4385 .has_arg = required_argument },
4386 { .val = 'g', .name = "group", .has_arg = required_argument },
4387 { .val = 'i', .name = "inode-softlimit",
4388 .has_arg = required_argument },
4389 { .val = 'I', .name = "inode-hardlimit",
4390 .has_arg = required_argument },
4391 { .val = 'p', .name = "projid", .has_arg = required_argument },
4392 { .val = 'u', .name = "user", .has_arg = required_argument },
4394 unsigned limit_mask = 0;
4398 if (has_times_option(argc, argv))
4399 return lfs_setquota_times(argc, argv);
4401 memset(&qctl, 0, sizeof(qctl));
4402 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
4403 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
4404 * so it can be used as a marker that qc_type
4405 * isn't reinitialized from command line */
4407 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
4408 long_opts, NULL)) != -1) {
4412 rc = name2uid(&qctl.qc_id, optarg);
4416 rc = name2gid(&qctl.qc_id, optarg);
4420 rc = name2projid(&qctl.qc_id, optarg);
4422 if (qctl.qc_type != ALLQUOTA) {
4423 fprintf(stderr, "error: -u and -g can't be used"
4424 " more than once\n");
4427 qctl.qc_type = qtype;
4429 qctl.qc_id = strtoul(optarg, &endptr, 10);
4430 if (*endptr != '\0') {
4431 fprintf(stderr, "error: can't find id "
4432 "for name %s\n", optarg);
4438 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
4439 dqb->dqb_bsoftlimit >>= 10;
4440 limit_mask |= BSLIMIT;
4441 if (dqb->dqb_bsoftlimit &&
4442 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
4443 fprintf(stderr, "warning: block softlimit is "
4444 "smaller than the miminal qunit size, "
4445 "please see the help of setquota or "
4446 "Lustre manual for details.\n");
4449 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
4450 dqb->dqb_bhardlimit >>= 10;
4451 limit_mask |= BHLIMIT;
4452 if (dqb->dqb_bhardlimit &&
4453 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
4454 fprintf(stderr, "warning: block hardlimit is "
4455 "smaller than the miminal qunit size, "
4456 "please see the help of setquota or "
4457 "Lustre manual for details.\n");
4460 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
4461 limit_mask |= ISLIMIT;
4462 if (dqb->dqb_isoftlimit &&
4463 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
4464 fprintf(stderr, "warning: inode softlimit is "
4465 "smaller than the miminal qunit size, "
4466 "please see the help of setquota or "
4467 "Lustre manual for details.\n");
4470 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
4471 limit_mask |= IHLIMIT;
4472 if (dqb->dqb_ihardlimit &&
4473 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
4474 fprintf(stderr, "warning: inode hardlimit is "
4475 "smaller than the miminal qunit size, "
4476 "please see the help of setquota or "
4477 "Lustre manual for details.\n");
4479 default: /* getopt prints error message for us when opterr != 0 */
4484 if (qctl.qc_type == ALLQUOTA) {
4485 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
4489 if (limit_mask == 0) {
4490 fprintf(stderr, "error: at least one limit must be specified\n");
4494 if (optind != argc - 1) {
4495 fprintf(stderr, "error: unexpected parameters encountered\n");
4501 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
4502 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
4503 /* sigh, we can't just set blimits/ilimits */
4504 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
4505 .qc_type = qctl.qc_type,
4506 .qc_id = qctl.qc_id};
4508 rc = llapi_quotactl(mnt, &tmp_qctl);
4510 fprintf(stderr, "error: setquota failed while retrieving"
4511 " current quota settings (%s)\n",
4516 if (!(limit_mask & BHLIMIT))
4517 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
4518 if (!(limit_mask & BSLIMIT))
4519 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
4520 if (!(limit_mask & IHLIMIT))
4521 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
4522 if (!(limit_mask & ISLIMIT))
4523 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
4525 /* Keep grace times if we have got no softlimit arguments */
4526 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
4527 dqb->dqb_valid |= QIF_BTIME;
4528 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
4531 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
4532 dqb->dqb_valid |= QIF_ITIME;
4533 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
4537 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
4538 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
4540 rc = llapi_quotactl(mnt, &qctl);
4543 fprintf(stderr, "%s %s ", obd_type,
4544 obd_uuid2str(&qctl.obd_uuid));
4545 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
4552 /* Converts seconds value into format string
4553 * result is returned in buf
4555 * 1. result is in descenting order: 1w2d3h4m5s
4556 * 2. zero fields are not filled (except for p. 3): 5d1s
4557 * 3. zero seconds value is presented as "0s"
4559 static char * __sec2str(time_t seconds, char *buf)
4561 const char spec[] = "smhdw";
4562 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
4567 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
4568 c = seconds / mult[i];
4570 if (c > 0 || (i == 0 && buf == tail))
4571 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
4579 static void sec2str(time_t seconds, char *buf, int rc)
4586 tail = __sec2str(seconds, tail);
4588 if (rc && tail - buf < 39) {
4594 static void diff2str(time_t seconds, char *buf, time_t now)
4600 if (seconds <= now) {
4601 strcpy(buf, "none");
4604 __sec2str(seconds - now, buf);
4607 static void print_quota_title(char *name, struct if_quotactl *qctl,
4608 bool human_readable)
4610 printf("Disk quotas for %s %s (%cid %u):\n",
4611 qtype_name(qctl->qc_type), name,
4612 *qtype_name(qctl->qc_type), qctl->qc_id);
4613 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
4614 "Filesystem", human_readable ? "used" : "kbytes",
4615 "quota", "limit", "grace",
4616 "files", "quota", "limit", "grace");
4619 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
4622 snprintf(buf, buflen, "%ju", (uintmax_t)num);
4625 snprintf(buf, buflen, "%5.4gP",
4626 (double)num / ((__u64)1 << 40));
4628 snprintf(buf, buflen, "%5.4gT",
4629 (double)num / (1 << 30));
4631 snprintf(buf, buflen, "%5.4gG",
4632 (double)num / (1 << 20));
4634 snprintf(buf, buflen, "%5.4gM",
4635 (double)num / (1 << 10));
4637 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
4641 #define STRBUF_LEN 32
4642 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
4649 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
4650 int bover = 0, iover = 0;
4651 struct obd_dqblk *dqb = &qctl->qc_dqblk;
4652 char numbuf[3][STRBUF_LEN];
4654 char strbuf[STRBUF_LEN];
4656 if (dqb->dqb_bhardlimit &&
4657 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
4659 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
4660 if (dqb->dqb_btime > now) {
4667 if (dqb->dqb_ihardlimit &&
4668 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
4670 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
4671 if (dqb->dqb_itime > now) {
4679 if (strlen(mnt) > 15)
4680 printf("%s\n%15s", mnt, "");
4682 printf("%15s", mnt);
4685 diff2str(dqb->dqb_btime, timebuf, now);
4687 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
4688 strbuf, sizeof(strbuf), h);
4689 if (rc == -EREMOTEIO)
4690 sprintf(numbuf[0], "%s*", strbuf);
4692 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
4693 "%s" : "[%s]", strbuf);
4695 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
4696 if (type == QC_GENERAL)
4697 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4698 "%s" : "[%s]", strbuf);
4700 sprintf(numbuf[1], "%s", "-");
4702 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4703 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4704 "%s" : "[%s]", strbuf);
4706 printf(" %7s%c %6s %7s %7s",
4707 numbuf[0], bover ? '*' : ' ', numbuf[1],
4708 numbuf[2], bover > 1 ? timebuf : "-");
4711 diff2str(dqb->dqb_itime, timebuf, now);
4713 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4714 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4716 if (type == QC_GENERAL)
4717 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4719 (uintmax_t)dqb->dqb_isoftlimit);
4721 sprintf(numbuf[1], "%s", "-");
4723 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4724 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4726 if (type != QC_OSTIDX)
4727 printf(" %7s%c %6s %7s %7s",
4728 numbuf[0], iover ? '*' : ' ', numbuf[1],
4729 numbuf[2], iover > 1 ? timebuf : "-");
4731 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4734 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4735 qctl->qc_cmd == Q_GETOINFO) {
4739 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4740 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4741 printf("Block grace time: %s; Inode grace time: %s\n",
4742 bgtimebuf, igtimebuf);
4746 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4747 bool h, __u64 *total)
4749 int rc = 0, rc1 = 0, count = 0;
4750 __u32 valid = qctl->qc_valid;
4752 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4754 fprintf(stderr, "can not get %s count: %s\n",
4755 is_mdt ? "mdt": "ost", strerror(-rc));
4759 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4760 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4761 rc = llapi_quotactl(mnt, qctl);
4763 /* It is remote client case. */
4764 if (rc == -EOPNOTSUPP) {
4771 fprintf(stderr, "quotactl %s%d failed.\n",
4772 is_mdt ? "mdt": "ost", qctl->qc_idx);
4776 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4777 qctl->qc_valid, 0, h);
4778 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4779 qctl->qc_dqblk.dqb_bhardlimit;
4782 qctl->qc_valid = valid;
4786 static int lfs_quota(int argc, char **argv)
4789 char *mnt, *name = NULL;
4790 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4791 .qc_type = ALLQUOTA };
4792 char *obd_type = (char *)qctl.obd_type;
4793 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4794 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4795 verbose = 0, pass = 0, quiet = 0, inacc;
4797 __u32 valid = QC_GENERAL, idx = 0;
4798 __u64 total_ialloc = 0, total_balloc = 0;
4799 bool human_readable = false;
4802 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4813 if (qctl.qc_type != ALLQUOTA) {
4814 fprintf(stderr, "error: use either -u or -g\n");
4817 qctl.qc_type = qtype;
4820 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4823 valid = qctl.qc_valid = QC_UUID;
4824 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4827 valid = qctl.qc_valid = QC_MDTIDX;
4828 idx = qctl.qc_idx = atoi(optarg);
4831 valid = qctl.qc_valid = QC_OSTIDX;
4832 idx = qctl.qc_idx = atoi(optarg);
4841 human_readable = true;
4844 fprintf(stderr, "error: %s: option '-%c' "
4845 "unrecognized\n", argv[0], c);
4850 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4851 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4852 optind == argc - 1) {
4854 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4855 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4856 qctl.qc_valid = valid;
4858 qctl.qc_type = pass;
4859 switch (qctl.qc_type) {
4861 qctl.qc_id = geteuid();
4862 rc = uid2name(&name, qctl.qc_id);
4865 qctl.qc_id = getegid();
4866 rc = gid2name(&name, qctl.qc_id);
4876 /* lfs quota -u username /path/to/lustre/mount */
4877 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4878 /* options should be followed by u/g-name and mntpoint */
4879 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4880 fprintf(stderr, "error: missing quota argument(s)\n");
4884 name = argv[optind++];
4885 switch (qctl.qc_type) {
4887 rc = name2uid(&qctl.qc_id, name);
4890 rc = name2gid(&qctl.qc_id, name);
4893 rc = name2projid(&qctl.qc_id, name);
4900 qctl.qc_id = strtoul(name, &endptr, 10);
4901 if (*endptr != '\0') {
4902 fprintf(stderr, "error: can't find id for name: %s\n",
4907 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4908 fprintf(stderr, "error: missing quota info argument(s)\n");
4913 rc1 = llapi_quotactl(mnt, &qctl);
4917 fprintf(stderr, "%s quotas are not enabled.\n",
4918 qtype_name(qctl.qc_type));
4921 fprintf(stderr, "Permission denied.\n");
4924 /* We already got error message. */
4927 fprintf(stderr, "Unexpected quotactl error: %s\n",
4932 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4933 print_quota_title(name, &qctl, human_readable);
4935 if (rc1 && *obd_type)
4936 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4938 if (qctl.qc_valid != QC_GENERAL)
4941 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4942 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4943 (QIF_LIMITS|QIF_USAGE));
4945 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4947 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4949 char strbuf[STRBUF_LEN];
4951 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4953 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4955 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4957 printf("Total allocated inode limit: %ju, total "
4958 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4962 if (rc1 || rc2 || rc3 || inacc)
4963 printf("Some errors happened when getting quota info. "
4964 "Some devices may be not working or deactivated. "
4965 "The data in \"[]\" is inaccurate.\n");
4968 if (pass > 0 && pass < LL_MAXQUOTAS)
4973 #endif /* HAVE_SYS_QUOTA_H! */
4975 static int flushctx_ioctl(char *mp)
4979 fd = open(mp, O_RDONLY);
4981 fprintf(stderr, "flushctx: error open %s: %s\n",
4982 mp, strerror(errno));
4986 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4988 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4989 mp, strerror(errno));
4995 static int lfs_flushctx(int argc, char **argv)
4997 int kdestroy = 0, c;
4998 char mntdir[PATH_MAX] = {'\0'};
5002 while ((c = getopt(argc, argv, "k")) != -1) {
5008 fprintf(stderr, "error: %s: option '-%c' "
5009 "unrecognized\n", argv[0], c);
5015 if ((rc = system("kdestroy > /dev/null")) != 0) {
5016 rc = WEXITSTATUS(rc);
5017 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
5021 if (optind >= argc) {
5022 /* flush for all mounted lustre fs. */
5023 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
5024 /* Check if we have a mount point */
5025 if (mntdir[0] == '\0')
5028 if (flushctx_ioctl(mntdir))
5031 mntdir[0] = '\0'; /* avoid matching in next loop */
5034 /* flush fs as specified */
5035 while (optind < argc) {
5036 if (flushctx_ioctl(argv[optind++]))
5043 static int lfs_cp(int argc, char **argv)
5045 fprintf(stderr, "remote client copy file(s).\n"
5046 "obsolete, does not support it anymore.\n");
5050 static int lfs_ls(int argc, char **argv)
5052 fprintf(stderr, "remote client lists directory contents.\n"
5053 "obsolete, does not support it anymore.\n");
5057 static int lfs_changelog(int argc, char **argv)
5059 void *changelog_priv;
5060 struct changelog_rec *rec;
5061 long long startrec = 0, endrec = 0;
5063 struct option long_opts[] = {
5064 { .val = 'f', .name = "follow", .has_arg = no_argument },
5066 char short_opts[] = "f";
5069 while ((rc = getopt_long(argc, argv, short_opts,
5070 long_opts, NULL)) != -1) {
5078 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5079 argv[0], argv[optind - 1]);
5086 mdd = argv[optind++];
5088 startrec = strtoll(argv[optind++], NULL, 10);
5090 endrec = strtoll(argv[optind++], NULL, 10);
5092 rc = llapi_changelog_start(&changelog_priv,
5093 CHANGELOG_FLAG_BLOCK |
5094 CHANGELOG_FLAG_JOBID |
5095 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
5098 fprintf(stderr, "Can't start changelog: %s\n",
5099 strerror(errno = -rc));
5103 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
5107 if (endrec && rec->cr_index > endrec) {
5108 llapi_changelog_free(&rec);
5111 if (rec->cr_index < startrec) {
5112 llapi_changelog_free(&rec);
5116 secs = rec->cr_time >> 30;
5117 gmtime_r(&secs, &ts);
5118 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
5119 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
5120 changelog_type2str(rec->cr_type),
5121 ts.tm_hour, ts.tm_min, ts.tm_sec,
5122 (int)(rec->cr_time & ((1 << 30) - 1)),
5123 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
5124 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
5126 if (rec->cr_flags & CLF_JOBID) {
5127 struct changelog_ext_jobid *jid =
5128 changelog_rec_jobid(rec);
5130 if (jid->cr_jobid[0] != '\0')
5131 printf(" j=%s", jid->cr_jobid);
5134 if (rec->cr_namelen)
5135 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
5136 rec->cr_namelen, changelog_rec_name(rec));
5138 if (rec->cr_flags & CLF_RENAME) {
5139 struct changelog_ext_rename *rnm =
5140 changelog_rec_rename(rec);
5142 if (!fid_is_zero(&rnm->cr_sfid))
5143 printf(" s="DFID" sp="DFID" %.*s",
5144 PFID(&rnm->cr_sfid),
5145 PFID(&rnm->cr_spfid),
5146 (int)changelog_rec_snamelen(rec),
5147 changelog_rec_sname(rec));
5151 llapi_changelog_free(&rec);
5154 llapi_changelog_fini(&changelog_priv);
5157 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
5159 return (rc == 1 ? 0 : rc);
5162 static int lfs_changelog_clear(int argc, char **argv)
5170 endrec = strtoll(argv[3], NULL, 10);
5172 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
5175 fprintf(stderr, "%s: record out of range: %llu\n",
5177 else if (rc == -ENOENT)
5178 fprintf(stderr, "%s: no changelog user: %s\n",
5181 fprintf(stderr, "%s error: %s\n", argv[0],
5190 static int lfs_fid2path(int argc, char **argv)
5192 struct option long_opts[] = {
5193 { .val = 'c', .name = "cur", .has_arg = no_argument },
5194 { .val = 'l', .name = "link", .has_arg = required_argument },
5195 { .val = 'r', .name = "rec", .has_arg = required_argument },
5197 char short_opts[] = "cl:r:";
5198 char *device, *fid, *path;
5199 long long recno = -1;
5205 while ((rc = getopt_long(argc, argv, short_opts,
5206 long_opts, NULL)) != -1) {
5212 linkno = strtol(optarg, NULL, 10);
5215 recno = strtoll(optarg, NULL, 10);
5220 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5221 argv[0], argv[optind - 1]);
5229 device = argv[optind++];
5230 path = calloc(1, PATH_MAX);
5232 fprintf(stderr, "error: Not enough memory\n");
5237 while (optind < argc) {
5238 fid = argv[optind++];
5240 lnktmp = (linkno >= 0) ? linkno : 0;
5242 int oldtmp = lnktmp;
5243 long long rectmp = recno;
5245 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
5248 fprintf(stderr, "%s: error on FID %s: %s\n",
5249 argv[0], fid, strerror(errno = -rc2));
5256 fprintf(stdout, "%lld ", rectmp);
5257 if (device[0] == '/') {
5258 fprintf(stdout, "%s", device);
5259 if (device[strlen(device) - 1] != '/')
5260 fprintf(stdout, "/");
5261 } else if (path[0] == '\0') {
5262 fprintf(stdout, "/");
5264 fprintf(stdout, "%s\n", path);
5267 /* specified linkno */
5269 if (oldtmp == lnktmp)
5279 static int lfs_path2fid(int argc, char **argv)
5281 struct option long_opts[] = {
5282 { .val = 'p', .name = "parents", .has_arg = no_argument },
5285 const char short_opts[] = "p";
5286 const char *sep = "";
5289 bool show_parents = false;
5291 while ((rc = getopt_long(argc, argv, short_opts,
5292 long_opts, NULL)) != -1) {
5295 show_parents = true;
5298 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5299 argv[0], argv[optind - 1]);
5304 if (optind > argc - 1)
5306 else if (optind < argc - 1)
5310 for (path = argv + optind; *path != NULL; path++) {
5312 if (!show_parents) {
5313 err = llapi_path2fid(*path, &fid);
5315 printf("%s%s"DFID"\n",
5316 *sep != '\0' ? *path : "", sep,
5319 char name[NAME_MAX + 1];
5320 unsigned int linkno = 0;
5322 while ((err = llapi_path2parent(*path, linkno, &fid,
5323 name, sizeof(name))) == 0) {
5324 if (*sep != '\0' && linkno == 0)
5325 printf("%s%s", *path, sep);
5327 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
5332 /* err == -ENODATA is end-of-loop */
5333 if (linkno > 0 && err == -ENODATA) {
5340 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
5341 argv[0], show_parents ? "parent " : "", *path,
5353 static int lfs_data_version(int argc, char **argv)
5360 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
5365 while ((c = getopt(argc, argv, "nrw")) != -1) {
5368 data_version_flags = 0;
5371 data_version_flags |= LL_DV_RD_FLUSH;
5374 data_version_flags |= LL_DV_WR_FLUSH;
5383 path = argv[optind];
5384 fd = open(path, O_RDONLY);
5386 err(errno, "cannot open file %s", path);
5388 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
5390 err(errno, "cannot get version for %s", path);
5392 printf("%ju" "\n", (uintmax_t)data_version);
5398 static int lfs_hsm_state(int argc, char **argv)
5403 struct hsm_user_state hus;
5411 rc = llapi_hsm_state_get(path, &hus);
5413 fprintf(stderr, "can't get hsm state for %s: %s\n",
5414 path, strerror(errno = -rc));
5418 /* Display path name and status flags */
5419 printf("%s: (0x%08x)", path, hus.hus_states);
5421 if (hus.hus_states & HS_RELEASED)
5422 printf(" released");
5423 if (hus.hus_states & HS_EXISTS)
5425 if (hus.hus_states & HS_DIRTY)
5427 if (hus.hus_states & HS_ARCHIVED)
5428 printf(" archived");
5429 /* Display user-settable flags */
5430 if (hus.hus_states & HS_NORELEASE)
5431 printf(" never_release");
5432 if (hus.hus_states & HS_NOARCHIVE)
5433 printf(" never_archive");
5434 if (hus.hus_states & HS_LOST)
5435 printf(" lost_from_hsm");
5437 if (hus.hus_archive_id != 0)
5438 printf(", archive_id:%d", hus.hus_archive_id);
5441 } while (++i < argc);
5446 #define LFS_HSM_SET 0
5447 #define LFS_HSM_CLEAR 1
5450 * Generic function to set or clear HSM flags.
5451 * Used by hsm_set and hsm_clear.
5453 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
5455 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
5457 struct option long_opts[] = {
5458 { .val = 'A', .name = "archived", .has_arg = no_argument },
5459 { .val = 'a', .name = "noarchive", .has_arg = no_argument },
5460 { .val = 'd', .name = "dirty", .has_arg = no_argument },
5461 { .val = 'e', .name = "exists", .has_arg = no_argument },
5462 { .val = 'l', .name = "lost", .has_arg = no_argument },
5463 { .val = 'r', .name = "norelease", .has_arg = no_argument },
5465 char short_opts[] = "lraAde";
5473 while ((c = getopt_long(argc, argv, short_opts,
5474 long_opts, NULL)) != -1) {
5480 mask |= HS_NOARCHIVE;
5483 mask |= HS_ARCHIVED;
5486 mask |= HS_NORELEASE;
5497 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5498 argv[0], argv[optind - 1]);
5503 /* User should have specified a flag */
5507 while (optind < argc) {
5509 path = argv[optind];
5511 /* If mode == 0, this means we apply the mask. */
5512 if (mode == LFS_HSM_SET)
5513 rc = llapi_hsm_state_set(path, mask, 0, 0);
5515 rc = llapi_hsm_state_set(path, 0, mask, 0);
5518 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
5519 path, strerror(errno = -rc));
5528 static int lfs_hsm_action(int argc, char **argv)
5533 struct hsm_current_action hca;
5534 struct hsm_extent he;
5535 enum hsm_user_action hua;
5536 enum hsm_progress_states hps;
5544 rc = llapi_hsm_current_action(path, &hca);
5546 fprintf(stderr, "can't get hsm action for %s: %s\n",
5547 path, strerror(errno = -rc));
5550 he = hca.hca_location;
5551 hua = hca.hca_action;
5552 hps = hca.hca_state;
5554 printf("%s: %s", path, hsm_user_action2name(hua));
5556 /* Skip file without action */
5557 if (hca.hca_action == HUA_NONE) {
5562 printf(" %s ", hsm_progress_state2name(hps));
5564 if ((hps == HPS_RUNNING) &&
5565 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
5566 printf("(%llu bytes moved)\n",
5567 (unsigned long long)he.length);
5568 else if ((he.offset + he.length) == LUSTRE_EOF)
5569 printf("(from %llu to EOF)\n",
5570 (unsigned long long)he.offset);
5572 printf("(from %llu to %llu)\n",
5573 (unsigned long long)he.offset,
5574 (unsigned long long)(he.offset + he.length));
5576 } while (++i < argc);
5581 static int lfs_hsm_set(int argc, char **argv)
5583 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
5586 static int lfs_hsm_clear(int argc, char **argv)
5588 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
5592 * Check file state and return its fid, to be used by lfs_hsm_request().
5594 * \param[in] file Path to file to check
5595 * \param[in,out] fid Pointer to allocated lu_fid struct.
5596 * \param[in,out] last_dev Pointer to last device id used.
5598 * \return 0 on success.
5600 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
5606 rc = lstat(file, &st);
5608 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
5611 /* Checking for regular file as archiving as posix copytool
5612 * rejects archiving files other than regular files
5614 if (!S_ISREG(st.st_mode)) {
5615 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
5618 /* A request should be ... */
5619 if (*last_dev != st.st_dev && *last_dev != 0) {
5620 fprintf(stderr, "All files should be "
5621 "on the same filesystem: %s\n", file);
5624 *last_dev = st.st_dev;
5626 rc = llapi_path2fid(file, fid);
5628 fprintf(stderr, "Cannot read FID of %s: %s\n",
5629 file, strerror(-rc));
5635 /* Fill an HSM HUR item with a given file name.
5637 * If mntpath is set, then the filename is actually a FID, and no
5638 * lookup on the filesystem will be performed.
5640 * \param[in] hur the user request to fill
5641 * \param[in] idx index of the item inside the HUR to fill
5642 * \param[in] mntpath mountpoint of Lustre
5643 * \param[in] fname filename (if mtnpath is NULL)
5644 * or FID (if mntpath is set)
5645 * \param[in] last_dev pointer to last device id used
5647 * \retval 0 on success
5648 * \retval CMD_HELP or a negative errno on error
5650 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
5651 const char *mntpath, const char *fname,
5654 struct hsm_user_item *hui = &hur->hur_user_item[idx];
5657 hui->hui_extent.length = -1;
5659 if (mntpath != NULL) {
5662 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
5666 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
5671 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
5675 hur->hur_request.hr_itemcount++;
5680 static int lfs_hsm_request(int argc, char **argv, int action)
5682 struct option long_opts[] = {
5683 { .val = 'a', .name = "archive", .has_arg = required_argument },
5684 { .val = 'D', .name = "data", .has_arg = required_argument },
5685 { .val = 'l', .name = "filelist", .has_arg = required_argument },
5686 { .val = 'm', .name = "mntpath", .has_arg = required_argument },
5689 char short_opts[] = "l:D:a:m:";
5690 struct hsm_user_request *hur, *oldhur;
5695 char *filelist = NULL;
5696 char fullpath[PATH_MAX];
5697 char *opaque = NULL;
5701 int nbfile_alloc = 0;
5702 char *some_file = NULL;
5703 char *mntpath = NULL;
5709 while ((c = getopt_long(argc, argv, short_opts,
5710 long_opts, NULL)) != -1) {
5719 if (action != HUA_ARCHIVE &&
5720 action != HUA_REMOVE) {
5722 "error: -a is supported only "
5723 "when archiving or removing\n");
5726 archive_id = atoi(optarg);
5729 if (some_file == NULL) {
5731 some_file = strdup(optarg);
5737 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5738 argv[0], argv[optind - 1]);
5743 /* All remaining args are files, so we have at least nbfile */
5744 nbfile = argc - optind;
5746 if ((nbfile == 0) && (filelist == NULL))
5750 opaque_len = strlen(opaque);
5752 /* Alloc the request structure with enough place to store all files
5753 * from command line. */
5754 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5756 fprintf(stderr, "Cannot create the request: %s\n",
5760 nbfile_alloc = nbfile;
5762 hur->hur_request.hr_action = action;
5763 hur->hur_request.hr_archive_id = archive_id;
5764 hur->hur_request.hr_flags = 0;
5766 /* All remaining args are files, add them */
5767 if (nbfile != 0 && some_file == NULL)
5768 some_file = strdup(argv[optind]);
5770 for (i = 0; i < nbfile; i++) {
5771 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5777 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5779 /* If a filelist was specified, read the filelist from it. */
5780 if (filelist != NULL) {
5781 fp = fopen(filelist, "r");
5783 fprintf(stderr, "Cannot read the file list %s: %s\n",
5784 filelist, strerror(errno));
5789 while ((rc = getline(&line, &len, fp)) != -1) {
5790 /* If allocated buffer was too small, get something
5792 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5795 nbfile_alloc = nbfile_alloc * 2 + 1;
5797 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5800 fprintf(stderr, "hsm: cannot allocate "
5801 "the request: %s\n",
5808 size = hur_len(oldhur);
5810 fprintf(stderr, "hsm: cannot allocate "
5811 "%u files + %u bytes data\n",
5812 oldhur->hur_request.hr_itemcount,
5813 oldhur->hur_request.hr_data_len);
5820 memcpy(hur, oldhur, size);
5825 if (line[strlen(line) - 1] == '\n')
5826 line[strlen(line) - 1] = '\0';
5828 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5829 mntpath, line, &last_dev);
5835 if (some_file == NULL) {
5845 /* If a --data was used, add it to the request */
5846 hur->hur_request.hr_data_len = opaque_len;
5848 memcpy(hur_data(hur), opaque, opaque_len);
5850 /* Send the HSM request */
5851 if (realpath(some_file, fullpath) == NULL) {
5852 fprintf(stderr, "Could not find path '%s': %s\n",
5853 some_file, strerror(errno));
5855 rc = llapi_hsm_request(fullpath, hur);
5857 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5858 some_file, strerror(-rc));
5868 static int lfs_hsm_archive(int argc, char **argv)
5870 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5873 static int lfs_hsm_restore(int argc, char **argv)
5875 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5878 static int lfs_hsm_release(int argc, char **argv)
5880 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5883 static int lfs_hsm_remove(int argc, char **argv)
5885 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5888 static int lfs_hsm_cancel(int argc, char **argv)
5890 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5893 static int lfs_swap_layouts(int argc, char **argv)
5898 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5899 SWAP_LAYOUTS_KEEP_MTIME |
5900 SWAP_LAYOUTS_KEEP_ATIME);
5903 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5905 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
5907 static const char *const lockahead_results[] = {
5908 [LLA_RESULT_SENT] = "Lock request sent",
5909 [LLA_RESULT_DIFFERENT] = "Different matching lock found",
5910 [LLA_RESULT_SAME] = "Matching lock on identical extent found",
5913 int lfs_get_mode(const char *string)
5915 enum lock_mode_user mode;
5917 for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
5918 if (lock_mode_names[mode] == NULL)
5920 if (strcmp(string, lock_mode_names[mode]) == 0)
5927 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5929 enum lu_ladvise_type advice;
5932 advice < ARRAY_SIZE(ladvise_names); advice++) {
5933 if (ladvise_names[advice] == NULL)
5935 if (strcmp(string, ladvise_names[advice]) == 0)
5939 return LU_LADVISE_INVALID;
5942 static int lfs_ladvise(int argc, char **argv)
5944 struct option long_opts[] = {
5945 { .val = 'a', .name = "advice", .has_arg = required_argument },
5946 { .val = 'b', .name = "background", .has_arg = no_argument },
5947 { .val = 'e', .name = "end", .has_arg = required_argument },
5948 { .val = 'l', .name = "length", .has_arg = required_argument },
5949 { .val = 'm', .name = "mode", .has_arg = required_argument },
5950 { .val = 's', .name = "start", .has_arg = required_argument },
5951 { .val = 'u', .name = "unset", .has_arg = no_argument },
5953 char short_opts[] = "a:be:l:m:s:u";
5958 struct llapi_lu_ladvise advice;
5959 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5960 unsigned long long start = 0;
5961 unsigned long long end = LUSTRE_EOF;
5962 unsigned long long length = 0;
5963 unsigned long long size_units;
5964 unsigned long long flags = 0;
5968 while ((c = getopt_long(argc, argv, short_opts,
5969 long_opts, NULL)) != -1) {
5972 advice_type = lfs_get_ladvice(optarg);
5973 if (advice_type == LU_LADVISE_INVALID) {
5974 fprintf(stderr, "%s: invalid advice type "
5975 "'%s'\n", argv[0], optarg);
5976 fprintf(stderr, "Valid types:");
5978 for (advice_type = 0;
5979 advice_type < ARRAY_SIZE(ladvise_names);
5981 if (ladvise_names[advice_type] == NULL)
5983 fprintf(stderr, " %s",
5984 ladvise_names[advice_type]);
5986 fprintf(stderr, "\n");
5999 rc = llapi_parse_size(optarg, &end,
6002 fprintf(stderr, "%s: bad end offset '%s'\n",
6009 rc = llapi_parse_size(optarg, &start,
6012 fprintf(stderr, "%s: bad start offset "
6013 "'%s'\n", argv[0], optarg);
6019 rc = llapi_parse_size(optarg, &length,
6022 fprintf(stderr, "%s: bad length '%s'\n",
6028 mode = lfs_get_mode(optarg);
6030 fprintf(stderr, "%s: bad mode '%s', valid "
6031 "modes are READ or WRITE\n",
6039 fprintf(stderr, "%s: option '%s' unrecognized\n",
6040 argv[0], argv[optind - 1]);
6045 if (advice_type == LU_LADVISE_INVALID) {
6046 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
6047 fprintf(stderr, "Valid types:");
6048 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
6050 if (ladvise_names[advice_type] == NULL)
6052 fprintf(stderr, " %s", ladvise_names[advice_type]);
6054 fprintf(stderr, "\n");
6058 if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
6059 fprintf(stderr, "%s: Lock no expand advice is a per file "
6060 "descriptor advice, so when called from lfs, "
6061 "it does nothing.\n", argv[0]);
6065 if (argc <= optind) {
6066 fprintf(stderr, "%s: please give one or more file names\n",
6071 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
6072 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
6077 if (end == LUSTRE_EOF && length != 0)
6078 end = start + length;
6081 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
6082 argv[0], start, end);
6086 if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
6087 fprintf(stderr, "%s: mode is only valid with lockahead\n",
6092 if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
6093 fprintf(stderr, "%s: mode is required with lockahead\n",
6098 while (optind < argc) {
6101 path = argv[optind++];
6103 fd = open(path, O_RDONLY);
6105 fprintf(stderr, "%s: cannot open file '%s': %s\n",
6106 argv[0], path, strerror(errno));
6111 advice.lla_start = start;
6112 advice.lla_end = end;
6113 advice.lla_advice = advice_type;
6114 advice.lla_value1 = 0;
6115 advice.lla_value2 = 0;
6116 advice.lla_value3 = 0;
6117 advice.lla_value4 = 0;
6118 if (advice_type == LU_LADVISE_LOCKAHEAD) {
6119 advice.lla_lockahead_mode = mode;
6120 advice.lla_peradvice_flags = flags;
6123 rc2 = llapi_ladvise(fd, flags, 1, &advice);
6126 fprintf(stderr, "%s: cannot give advice '%s' to file "
6127 "'%s': %s\n", argv[0],
6128 ladvise_names[advice_type],
6129 path, strerror(errno));
6135 if (rc == 0 && rc2 < 0)
6142 * lfs_mirror() - Parse and execute lfs mirror commands.
6143 * @argc: The count of lfs mirror command line arguments.
6144 * @argv: Array of strings for lfs mirror command line arguments.
6146 * This function parses lfs mirror commands and performs the
6147 * corresponding functions specified in mirror_cmdlist[].
6149 * Return: 0 on success or an error code on failure.
6151 static int lfs_mirror(int argc, char **argv)
6158 Parser_init("lfs-mirror > ", mirror_cmdlist);
6160 snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
6162 program_invocation_short_name = cmd;
6164 rc = Parser_execarg(argc - 1, argv + 1, mirror_cmdlist);
6166 rc = Parser_commands();
6168 return rc < 0 ? -rc : rc;
6172 * lfs_mirror_list_commands() - List lfs mirror commands.
6173 * @argc: The count of command line arguments.
6174 * @argv: Array of strings for command line arguments.
6176 * This function lists lfs mirror commands defined in mirror_cmdlist[].
6178 * Return: 0 on success.
6180 static int lfs_mirror_list_commands(int argc, char **argv)
6182 char buffer[81] = "";
6184 Parser_list_commands(mirror_cmdlist, buffer, sizeof(buffer),
6190 static int lfs_list_commands(int argc, char **argv)
6192 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
6194 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
6199 int main(int argc, char **argv)
6203 /* Ensure that liblustreapi constructor has run */
6204 if (!liblustreapi_initialized)
6205 fprintf(stderr, "liblustreapi was not properly initialized\n");
6210 Parser_init("lfs > ", cmdlist);
6212 progname = argv[0]; /* Used in error messages */
6214 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
6216 rc = Parser_commands();
6218 return rc < 0 ? -rc : rc;
6221 #ifdef _LUSTRE_IDL_H_
6222 /* Everything we need here should be included by lustreapi.h. */
6223 # error "lfs should not depend on lustre_idl.h"
6224 #endif /* _LUSTRE_IDL_H_ */