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);
114 static inline int lfs_mirror_resync(int argc, char **argv);
116 enum setstripe_origin {
122 static int lfs_setstripe0(int argc, char **argv, enum setstripe_origin opc);
124 static inline int lfs_setstripe(int argc, char **argv)
126 return lfs_setstripe0(argc, argv, SO_SETSTRIPE);
128 static inline int lfs_setstripe_migrate(int argc, char **argv)
130 return lfs_setstripe0(argc, argv, SO_MIGRATE);
132 static inline int lfs_mirror_create(int argc, char **argv)
134 return lfs_setstripe0(argc, argv, SO_MIRROR_CREATE);
136 static inline int lfs_mirror_extend(int argc, char **argv)
138 return lfs_setstripe0(argc, argv, SO_MIRROR_EXTEND);
141 /* Setstripe and migrate share mostly the same parameters */
142 #define SSM_CMD_COMMON(cmd) \
143 "usage: "cmd" [--component-end|-E <comp_end>]\n" \
144 " [--stripe-count|-c <stripe_count>]\n" \
145 " [--stripe-index|-i <start_ost_idx>]\n" \
146 " [--stripe-size|-S <stripe_size>]\n" \
147 " [--layout|-L <pattern>]\n" \
148 " [--pool|-p <pool_name>]\n" \
149 " [--ost|-o <ost_indices>]\n"
151 #define SSM_HELP_COMMON \
152 "\tstripe_count: Number of OSTs to stripe over (0=fs default, -1 all)\n" \
153 "\tstart_ost_idx: OST index of first stripe (-1=default round robin)\n"\
154 "\tstripe_size: Number of bytes on each OST (0=fs default)\n" \
155 "\t Can be specified with K, M or G (for KB, MB, GB\n" \
156 "\t respectively)\n" \
157 "\tpool_name: Name of OST pool to use (default none)\n" \
158 "\tlayout: stripe pattern type: raid0, mdt (default raid0)\n"\
159 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
160 "\t Indices be specified in a format of:\n" \
161 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
163 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
164 "\t If --pool is set with --ost, then the OSTs\n" \
165 "\t must be the members of the pool.\n" \
166 "\tcomp_end: Extent end of component, start after previous end.\n"\
167 "\t Can be specified with K, M or G (for KB, MB, GB\n" \
168 "\t respectively, -1 for EOF). Must be a multiple of\n"\
171 #define MIRROR_CREATE_HELP \
172 "\tmirror_count: Number of mirrors to be created with the upcoming\n" \
173 "\t setstripe layout options\n" \
174 "\t It defaults to 1 if not specified; if specified,\n" \
175 "\t it must follow the option without a space.\n" \
176 "\t The option can also be repeated multiple times to\n" \
177 "\t separate mirrors that have different layouts.\n" \
178 "\tsetstripe options: Mirror layout\n" \
179 "\t It can be a plain layout or a composite layout.\n" \
180 "\t If not specified, the stripe options inherited\n" \
181 "\t from the previous component will be used.\n" \
182 "\tparent: Use default stripe options from parent directory\n"
184 #define MIRROR_EXTEND_HELP \
186 "\tvictim_file: The layout of victim_file will be split and used\n" \
187 "\t as a mirror added to the mirrored file.\n" \
188 "\tno-verify: This option indicates not to verify the mirror(s)\n" \
189 "\t from victim file(s) in case the victim file(s)\n" \
190 "\t contains the same data as the original mirrored\n" \
193 #define MIRROR_EXTEND_USAGE \
194 " <--mirror-count|-N[mirror_count]>\n" \
195 " [setstripe options|--parent|-f <victim_file>]\n" \
198 #define SETSTRIPE_USAGE \
199 SSM_CMD_COMMON("setstripe") \
200 MIRROR_EXTEND_USAGE \
201 " <directory|filename>\n" \
205 #define MIGRATE_USAGE \
206 SSM_CMD_COMMON("migrate ") \
208 " [--non-block|-n]\n" \
212 "\tblock: Block file access during data migration (default)\n" \
213 "\tnon-block: Abort migrations if concurrent access is detected\n" \
215 #define SETDIRSTRIPE_USAGE \
216 " [--mdt-count|-c stripe_count>\n" \
217 " [--mdt-index|-i mdt_index]\n" \
218 " [--mdt-hash|-H mdt_hash]\n" \
219 " [--default|-D] [--mode|-m mode] <dir>\n" \
220 "\tstripe_count: stripe count of the striped directory\n" \
221 "\tmdt_index: MDT index of first stripe\n" \
222 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
223 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
224 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
225 "\tdefault_stripe: set default dirstripe of the directory\n" \
226 "\tmode: the mode of the directory\n"
228 static const char *progname;
231 * command_t mirror_cmdlist - lfs mirror commands.
233 command_t mirror_cmdlist[] = {
234 { .pc_name = "create", .pc_func = lfs_mirror_create,
235 .pc_help = "Create a mirrored file.\n"
236 "usage: lfs mirror create "
237 "<--mirror-count|-N[mirror_count]> "
238 "[setstripe options|--parent] ... <filename|directory>\n"
239 MIRROR_CREATE_HELP },
240 { .pc_name = "extend", .pc_func = lfs_mirror_extend,
241 .pc_help = "Extend a mirrored file.\n"
242 "usage: lfs mirror extend "
243 "<--mirror-count|-N[mirror_count]> [--no-verify] "
244 "[setstripe options|--parent|-f <victim_file>] ... <filename>\n"
245 MIRROR_EXTEND_HELP },
246 { .pc_name = "resync", .pc_func = lfs_mirror_resync,
247 .pc_help = "Resynchronizes an out-of-sync mirrored file.\n"
248 "usage: lfs mirror resync [--only <mirror_id[,...]>] "
249 "<mirrored file>\n"},
250 { .pc_name = "--list-commands", .pc_func = lfs_mirror_list_commands,
251 .pc_help = "list commands supported by lfs mirror"},
252 { .pc_name = "help", .pc_func = Parser_help, .pc_help = "help" },
253 { .pc_name = "exit", .pc_func = Parser_quit, .pc_help = "quit" },
254 { .pc_name = "quit", .pc_func = Parser_quit, .pc_help = "quit" },
258 /* all available commands */
259 command_t cmdlist[] = {
260 {"setstripe", lfs_setstripe, 0,
261 "To create a file with specified striping/composite layout, or\n"
262 "create/replace the default layout on an existing directory:\n"
263 SSM_CMD_COMMON("setstripe")
264 " <directory|filename>\n"
266 "To add component(s) to an existing composite file:\n"
267 SSM_CMD_COMMON("setstripe --component-add")
269 "To totally delete the default striping from an existing directory:\n"
270 "usage: setstripe -d <directory>\n"
272 "To delete the last component(s) from an existing composite file\n"
273 "(note that this will also delete any data in those components):\n"
274 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
275 " [--component-flags|-F <comp_flags>]\n"
277 "\tcomp_id: Unique component ID to delete\n"
278 "\tcomp_flags: 'init' indicating all instantiated components\n"
279 "\t '^init' indicating all uninstantiated components\n"
280 "\t-I and -F cannot be specified at the same time\n"},
281 {"getstripe", lfs_getstripe, 0,
282 "To list the striping info for a given file or files in a\n"
283 "directory or recursively for all files in a directory tree.\n"
284 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
285 " [--stripe-count|-c] [--stripe-index|-i]\n"
286 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
287 " [--mdt|-m] [--recursive|-r] [--raw|-R] [--yaml|-y]\n"
288 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
289 " [--component-id[=comp_id]|-I[comp_id]]\n"
290 " [--component-flags[=comp_flags]]\n"
291 " [--component-count]\n"
292 " [--component-start[=[+-]comp_start]]\n"
293 " [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
294 " <directory|filename> ..."},
295 {"setdirstripe", lfs_setdirstripe, 0,
296 "To create a striped directory on a specified MDT. This can only\n"
297 "be done on MDT0 with the right of administrator.\n"
298 "usage: setdirstripe [OPTION] <directory>\n"
300 {"getdirstripe", lfs_getdirstripe, 0,
301 "To list the striping info for a given directory\n"
302 "or recursively for all directories in a directory tree.\n"
303 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
304 " [--mdt-index|-i] [--mdt-hash|-t]\n"
305 " [--recursive|-r] [--yaml|-y]\n"
306 " [--default|-D] <dir> ..."},
307 {"mkdir", lfs_setdirstripe, 0,
308 "To create a striped directory on a specified MDT. This can only\n"
309 "be done on MDT0 with the right of administrator.\n"
310 "usage: mkdir [OPTION] <directory>\n"
312 {"rm_entry", lfs_rmentry, 0,
313 "To remove the name entry of the remote directory. Note: This\n"
314 "command will only delete the name entry, i.e. the remote directory\n"
315 "will become inaccessable after this command. This can only be done\n"
316 "by the administrator\n"
317 "usage: rm_entry <dir>\n"},
318 {"pool_list", lfs_poollist, 0,
319 "List pools or pool OSTs\n"
320 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
321 {"find", lfs_find, 0,
322 "find files matching given attributes recursively in directory tree.\n"
323 "usage: find <directory|filename> ...\n"
324 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
325 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
326 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
327 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
328 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
329 " [[!] --stripe-count|-c [+-]<stripes>]\n"
330 " [[!] --stripe-index|-i <index,...>]\n"
331 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
332 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
333 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
334 " [[!] --projid <projid>]\n"
335 " [[!] --layout|-L released,raid0,mdt]\n"
336 " [[!] --component-count [+-]<comp_cnt>]\n"
337 " [[!] --component-start [+-]N[kMGTPE]]\n"
338 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
339 " [[!] --component-flags <comp_flags>]\n"
340 " [[!] --mdt-count|-T [+-]<stripes>]\n"
341 " [[!] --mdt-hash|-H <hashtype>\n"
342 "\t !: used before an option indicates 'NOT' requested attribute\n"
343 "\t -: used before a value indicates less than requested value\n"
344 "\t +: used before a value indicates more than requested value\n"
345 "\tmdt-hash: hash type of the striped directory.\n"
346 "\t fnv_1a_64 FNV-1a hash algorithm\n"
347 "\t all_char sum of characters % MDT_COUNT\n"},
348 {"check", lfs_check, 0,
349 "Display the status of MDS or OSTs (as specified in the command)\n"
350 "or all the servers (MDS and OSTs).\n"
351 "usage: check <osts|mds|servers>"},
352 {"osts", lfs_osts, 0, "list OSTs connected to client "
353 "[for specified path only]\n" "usage: osts [path]"},
354 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
355 "[for specified path only]\n" "usage: mdts [path]"},
357 "report filesystem disk space usage or inodes usage"
358 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
359 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
360 {"getname", lfs_getname, 0, "list instances and specified mount points "
361 "[for specified path only]\n"
362 "Usage: getname [-h]|[path ...] "},
363 #ifdef HAVE_SYS_QUOTA_H
364 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
365 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
366 " -b <block-softlimit> -B <block-hardlimit>\n"
367 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
368 " setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
369 " [--block-softlimit <block-softlimit>]\n"
370 " [--block-hardlimit <block-hardlimit>]\n"
371 " [--inode-softlimit <inode-softlimit>]\n"
372 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
373 " setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
374 " [--block-grace <block-grace>]\n"
375 " [--inode-grace <inode-grace>] <filesystem>\n"
376 " -b can be used instead of --block-softlimit/--block-grace\n"
377 " -B can be used instead of --block-hardlimit\n"
378 " -i can be used instead of --inode-softlimit/--inode-grace\n"
379 " -I can be used instead of --inode-hardlimit\n\n"
380 "Note: The total quota space will be split into many qunits and\n"
381 " balanced over all server targets, the minimal qunit size is\n"
382 " 1M bytes for block space and 1K inodes for inode space.\n\n"
383 " Quota space rebalancing process will stop when this mininum\n"
384 " value is reached. As a result, quota exceeded can be returned\n"
385 " while many targets still have 1MB or 1K inodes of spare\n"
387 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
388 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
390 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
391 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
393 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
394 "usage: flushctx [-k] [mountpoint...]"},
396 "Remote user copy files and directories.\n"
397 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
399 "Remote user list directory contents.\n"
400 "usage: ls [OPTION]... [FILE]..."},
401 {"changelog", lfs_changelog, 0,
402 "Show the metadata changes on an MDT."
403 "\nusage: changelog <mdtname> [startrec [endrec]]"},
404 {"changelog_clear", lfs_changelog_clear, 0,
405 "Indicate that old changelog records up to <endrec> are no longer of "
406 "interest to consumer <id>, allowing the system to free up space.\n"
407 "An <endrec> of 0 means all records.\n"
408 "usage: changelog_clear <mdtname> <id> <endrec>"},
409 {"fid2path", lfs_fid2path, 0,
410 "Resolve the full path(s) for given FID(s). For a specific hardlink "
411 "specify link number <linkno>.\n"
412 /* "For a historical link name, specify changelog record <recno>.\n" */
413 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
414 /* [ --rec <recno> ] */ },
415 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
416 "usage: path2fid [--parents] <path> ..."},
417 {"data_version", lfs_data_version, 0, "Display file data version for "
418 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
419 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
420 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
421 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
422 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
423 "[--archived] [--lost] <file> ..."},
424 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
426 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
427 "[--archived] [--lost] <file> ..."},
428 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
429 "given files.\n" "usage: hsm_action <file> ..."},
430 {"hsm_archive", lfs_hsm_archive, 0,
431 "Archive file to external storage.\n"
432 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
434 {"hsm_restore", lfs_hsm_restore, 0,
435 "Restore file from external storage.\n"
436 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
437 {"hsm_release", lfs_hsm_release, 0,
438 "Release files from Lustre.\n"
439 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
440 {"hsm_remove", lfs_hsm_remove, 0,
441 "Remove file copy from external storage.\n"
442 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
443 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
445 "Note: To remove files from the archive that have been deleted on\n"
446 "Lustre, set mntpath and optionally archive. In that case, all the\n"
447 "positional arguments and entries in the file list must be FIDs."
449 {"hsm_cancel", lfs_hsm_cancel, 0,
450 "Cancel requests related to specified files.\n"
451 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
452 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
453 "usage: swap_layouts <path1> <path2>"},
454 {"migrate", lfs_setstripe_migrate, 0,
455 "migrate a directory between MDTs.\n"
456 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
458 "\tmdt_idx: index of the destination MDT\n"
460 "migrate file objects from one OST "
461 "layout\nto another (may be not safe with concurent writes).\n"
463 "[--stripe-count|-c] <stripe_count>\n"
464 " [--stripe-index|-i] <start_ost_index>\n"
465 " [--stripe-size|-S] <stripe_size>\n"
466 " [--pool|-p] <pool_name>\n"
467 " [--ost-list|-o] <ost_indices>\n"
469 " [--non-block|-n]\n"
470 " <file|directory>\n"
471 "\tstripe_count: number of OSTs to stripe a file over\n"
472 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
473 "\tstripe_size: number of bytes to store before moving to the next OST\n"
474 "\tpool_name: name of the predefined pool of OSTs\n"
475 "\tost_indices: OSTs to stripe over, in order\n"
476 "\tblock: wait for the operation to return before continuing\n"
477 "\tnon-block: do not wait for the operation to return.\n"},
479 "To move directories between MDTs. This command is deprecated, "
480 "use \"migrate\" instead.\n"
481 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
483 {"ladvise", lfs_ladvise, 0,
484 "Provide servers with advice about access patterns for a file.\n"
485 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
486 " [--background|-b] [--unset|-u]\n\n"
487 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
488 " {[--mode|-m [READ,WRITE]}\n"
490 {"mirror", lfs_mirror, mirror_cmdlist,
491 "lfs commands used to manage files with mirrored components:\n"
492 "lfs mirror create - create a mirrored file or directory\n"
493 "lfs mirror extend - add mirror(s) to an existing file\n"
494 "lfs mirror split - split a mirror from an existing mirrored file\n"
495 "lfs mirror resync - resynchronize an out-of-sync mirrored file\n"
496 "lfs mirror verify - verify a mirrored file\n"},
497 {"help", Parser_help, 0, "help"},
498 {"exit", Parser_quit, 0, "quit"},
499 {"quit", Parser_quit, 0, "quit"},
500 {"--version", Parser_version, 0,
501 "output build version of the utility and exit"},
502 {"--list-commands", lfs_list_commands, 0,
503 "list commands supported by the utility and exit"},
508 static int check_hashtype(const char *hashtype)
512 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
513 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
520 static const char *error_loc = "syserror";
523 MIGRATION_NONBLOCK = 1 << 0,
524 MIGRATION_MIRROR = 1 << 1,
527 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
528 struct llapi_layout *layout);
531 migrate_open_files(const char *name, const struct llapi_stripe_param *param,
532 struct llapi_layout *layout, int *fd_src, int *fd_tgt)
538 char parent[PATH_MAX];
539 char volatile_file[PATH_MAX];
545 if (param == NULL && layout == NULL) {
546 error_loc = "layout information";
550 /* search for file directory pathname */
551 if (strlen(name) > sizeof(parent) - 1) {
552 error_loc = "source file name";
556 strncpy(parent, name, sizeof(parent));
557 ptr = strrchr(parent, '/');
559 if (getcwd(parent, sizeof(parent)) == NULL) {
560 error_loc = "getcwd";
564 if (ptr == parent) /* leading '/' */
569 /* open file, direct io */
570 /* even if the file is only read, WR mode is nedeed to allow
571 * layout swap on fd */
572 fd = open(name, O_RDWR | O_DIRECT);
575 error_loc = "cannot open source file";
579 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
581 error_loc = "cannot get MDT index";
586 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
587 mode_t open_mode = S_IRUSR | S_IWUSR;
589 random_value = random();
590 rc = snprintf(volatile_file, sizeof(volatile_file),
591 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
592 mdt_index, random_value);
593 if (rc >= sizeof(volatile_file)) {
598 /* create, open a volatile file, use caching (ie no directio) */
600 fdv = llapi_file_open_param(volatile_file, open_flags,
603 fdv = lfs_component_create(volatile_file, open_flags,
605 } while (fdv < 0 && (rc = fdv) == -EEXIST);
608 error_loc = "cannot create volatile file";
612 /* In case the MDT does not support creation of volatile files
613 * we should try to unlink it. */
614 (void)unlink(volatile_file);
616 /* Not-owner (root?) special case.
617 * Need to set owner/group of volatile file like original.
618 * This will allow to pass related check during layout_swap.
623 error_loc = "cannot stat source file";
627 rc = fstat(fdv, &stv);
630 error_loc = "cannot stat volatile";
634 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
635 rc = fchown(fdv, st.st_uid, st.st_gid);
638 error_loc = "cannot change ownwership of volatile";
657 static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int))
659 struct llapi_layout *layout;
660 size_t buf_size = 4 * 1024 * 1024;
669 layout = llapi_layout_get_by_fd(fd_src, 0);
670 if (layout != NULL) {
671 uint64_t stripe_size;
673 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
675 buf_size = stripe_size;
677 llapi_layout_free(layout);
680 /* Use a page-aligned buffer for direct I/O */
681 rc = posix_memalign(&buf, getpagesize(), buf_size);
686 /* read new data only if we have written all
687 * previously read data */
690 rc = check_file(fd_src);
695 rsize = read(fd_src, buf, buf_size);
707 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
726 static int migrate_copy_timestamps(int fd, int fdv)
730 if (fstat(fd, &st) == 0) {
731 struct timeval tv[2] = {
732 {.tv_sec = st.st_atime},
733 {.tv_sec = st.st_mtime}
736 return futimes(fdv, tv);
742 static int migrate_block(int fd, int fdv)
749 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
751 error_loc = "cannot get dataversion";
759 /* The grouplock blocks all concurrent accesses to the file.
760 * It has to be taken after llapi_get_data_version as it would
762 rc = llapi_group_lock(fd, gid);
764 error_loc = "cannot get group lock";
768 rc = migrate_copy_data(fd, fdv, NULL);
770 error_loc = "data copy failed";
774 /* Make sure we keep original atime/mtime values */
775 rc = migrate_copy_timestamps(fd, fdv);
777 error_loc = "timestamp copy failed";
782 * for a migration we need to check data version on file did
785 * Pass in gid=0 since we already own grouplock. */
786 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
787 SWAP_LAYOUTS_CHECK_DV1);
789 error_loc = "file changed";
792 error_loc = "cannot swap layout";
797 rc2 = llapi_group_unlock(fd, gid);
798 if (rc2 < 0 && rc == 0) {
799 error_loc = "unlock group lock";
807 * Internal helper for migrate_copy_data(). Check lease and report error if
810 * \param[in] fd File descriptor on which to check the lease.
812 * \retval 0 Migration can keep on going.
813 * \retval -errno Error occurred, abort migration.
815 static int check_lease(int fd)
819 rc = llapi_lease_check(fd);
821 return 0; /* llapi_check_lease returns > 0 on success. */
826 static int migrate_nonblock(int fd, int fdv)
832 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
834 error_loc = "cannot get data version";
838 rc = migrate_copy_data(fd, fdv, check_lease);
840 error_loc = "data copy failed";
844 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
846 error_loc = "cannot get data version";
852 error_loc = "source file changed";
856 /* Make sure we keep original atime/mtime values */
857 rc = migrate_copy_timestamps(fd, fdv);
859 error_loc = "timestamp copy failed";
866 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
871 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
875 if (flags != 0 && comp_id != 0)
878 /* LCME_FL_INIT is the only supported flag in PFL */
880 if (flags & ~LCME_KNOWN_FLAGS) {
881 fprintf(stderr, "Invalid component flags %#x\n", flags);
884 } else if (comp_id > LCME_ID_MAX) {
885 fprintf(stderr, "Invalid component id %u\n", comp_id);
889 rc = llapi_layout_file_comp_del(fname, comp_id, flags);
891 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
892 comp_id, fname, strerror(errno));
896 static int lfs_component_add(char *fname, struct llapi_layout *layout)
903 rc = llapi_layout_file_comp_add(fname, layout);
905 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
906 fname, strerror(errno));
910 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
911 struct llapi_layout *layout)
919 fd = lstat(fname, &st);
920 if (fd == 0 && S_ISDIR(st.st_mode))
921 open_flags = O_DIRECTORY | O_RDONLY;
923 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
925 fprintf(stderr, "%s: cannot %s '%s': %s\n", progname,
926 S_ISDIR(st.st_mode) ?
927 "set default composite layout for" :
928 "create composite file",
929 fname, strerror(errno));
933 static int lfs_migrate(char *name, __u64 migration_flags,
934 struct llapi_stripe_param *param,
935 struct llapi_layout *layout)
941 rc = migrate_open_files(name, param, layout, &fd, &fdv);
945 if (!(migration_flags & MIGRATION_NONBLOCK)) {
946 /* Blocking mode (forced if servers do not support file lease).
947 * It is also the default mode, since we cannot distinguish
948 * between a broken lease and a server that does not support
949 * atomic swap/close (LU-6785) */
950 rc = migrate_block(fd, fdv);
954 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
956 error_loc = "cannot get lease";
960 rc = migrate_nonblock(fd, fdv);
966 /* Atomically put lease, swap layouts and close.
967 * for a migration we need to check data version on file did
969 rc = llapi_fswap_layouts(fd, fdv, 0, 0,
970 migration_flags & MIGRATION_MIRROR ?
971 MERGE_LAYOUTS_CLOSE : SWAP_LAYOUTS_CLOSE);
973 error_loc = "cannot swap layout";
985 fprintf(stderr, "error: %s: %s: %s: %s\n",
986 progname, name, error_loc, strerror(-rc));
991 * struct mirror_args - Command-line arguments for mirror(s).
992 * @m_count: Number of mirrors to be created with this layout.
993 * @m_layout: Mirror layout.
994 * @m_file: A victim file. Its layout will be split and used as a mirror.
995 * @m_next: Point to the next node of the list.
997 * Command-line arguments for mirror(s) will be parsed and stored in
998 * a linked list that consists of this structure.
1000 struct mirror_args {
1002 struct llapi_layout *m_layout;
1004 struct mirror_args *m_next;
1007 static inline int mirror_sanity_check_one(struct llapi_layout *layout)
1009 uint64_t start, end;
1013 /* LU-10112: do not support dom+flr in phase 1 */
1014 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1018 rc = llapi_layout_pattern_get(layout, &pattern);
1022 if (pattern == LOV_PATTERN_MDT || pattern == LLAPI_LAYOUT_MDT) {
1023 fprintf(stderr, "error: %s: doesn't support dom+flr for now\n",
1028 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_LAST);
1032 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1036 if (end != LUSTRE_EOF) {
1037 fprintf(stderr, "error: %s: mirror layout doesn't reach eof\n",
1046 * enum mirror_flags - Flags for extending a mirrored file.
1047 * @NO_VERIFY: Indicates not to verify the mirror(s) from victim file(s)
1048 * in case the victim file(s) contains the same data as the
1049 * original mirrored file.
1051 * Flags for extending a mirrored file.
1058 * mirror_create_sanity_check() - Check mirror list.
1059 * @list: A linked list that stores the mirror arguments.
1061 * This function does a sanity check on @list for creating
1064 * Return: 0 on success or a negative error code on failure.
1066 static int mirror_create_sanity_check(const char *fname,
1067 struct mirror_args *list)
1070 bool has_m_file = false;
1071 bool has_m_layout = false;
1077 struct llapi_layout *layout;
1079 layout = llapi_layout_get_by_path(fname, 0);
1082 "error: %s: file '%s' couldn't get layout\n",
1087 rc = mirror_sanity_check_one(layout);
1088 llapi_layout_free(layout);
1094 while (list != NULL) {
1095 if (list->m_file != NULL) {
1097 llapi_layout_free(list->m_layout);
1100 llapi_layout_get_by_path(list->m_file, 0);
1101 if (list->m_layout == NULL) {
1103 "error: %s: file '%s' has no layout\n",
1104 progname, list->m_file);
1108 if (list->m_layout != NULL)
1109 has_m_layout = true;
1111 fprintf(stderr, "error: %s: no mirror layout\n",
1117 rc = mirror_sanity_check_one(list->m_layout);
1121 list = list->m_next;
1124 if (has_m_file && has_m_layout) {
1125 fprintf(stderr, "error: %s: -f <victim_file> option should not "
1126 "be specified with setstripe options or "
1127 "--parent option\n", progname);
1135 * mirror_create() - Create a mirrored file.
1136 * @fname: The file to be created.
1137 * @mirror_list: A linked list that stores the mirror arguments.
1139 * This function creates a mirrored file @fname with the mirror(s)
1140 * from @mirror_list.
1142 * Return: 0 on success or a negative error code on failure.
1144 static int mirror_create(char *fname, struct mirror_args *mirror_list)
1146 struct llapi_layout *layout = NULL;
1147 struct mirror_args *cur_mirror = NULL;
1148 uint16_t mirror_count = 0;
1152 rc = mirror_create_sanity_check(NULL, mirror_list);
1156 cur_mirror = mirror_list;
1157 while (cur_mirror != NULL) {
1158 for (i = 0; i < cur_mirror->m_count; i++) {
1159 rc = llapi_layout_merge(&layout, cur_mirror->m_layout);
1162 fprintf(stderr, "error: %s: "
1163 "merge layout failed: %s\n",
1164 progname, strerror(errno));
1168 mirror_count += cur_mirror->m_count;
1169 cur_mirror = cur_mirror->m_next;
1172 rc = llapi_layout_mirror_count_set(layout, mirror_count);
1175 fprintf(stderr, "error: %s: set mirror count failed: %s\n",
1176 progname, strerror(errno));
1180 rc = lfs_component_create(fname, O_CREAT | O_WRONLY, 0644,
1188 llapi_layout_free(layout);
1193 * Compare files and check lease on @fd.
1195 * \retval bytes number of bytes are the same
1197 static ssize_t mirror_file_compare(int fd, int fdv)
1199 const size_t buflen = 4 * 1024 * 1024; /* 4M */
1201 ssize_t bytes_done = 0;
1202 ssize_t bytes_read = 0;
1204 buf = malloc(buflen * 2);
1209 if (!llapi_lease_check(fd)) {
1210 bytes_done = -EBUSY;
1214 bytes_read = read(fd, buf, buflen);
1215 if (bytes_read <= 0)
1218 if (bytes_read != read(fdv, buf + buflen, buflen))
1221 /* XXX: should compute the checksum on each buffer and then
1222 * compare checksum to avoid cache collision */
1223 if (memcmp(buf, buf + buflen, bytes_read))
1226 bytes_done += bytes_read;
1234 static int mirror_extend_file(const char *fname, const char *victim_file,
1235 enum mirror_flags mirror_flags)
1240 struct stat stbuf_v;
1244 fd = open(fname, O_RDWR);
1246 error_loc = "open source file";
1251 fdv = open(victim_file, O_RDWR);
1253 error_loc = "open target file";
1258 if (fstat(fd, &stbuf) || fstat(fdv, &stbuf_v)) {
1259 error_loc = "stat source or target file";
1264 if (stbuf.st_dev != stbuf_v.st_dev) {
1265 error_loc = "stat source and target file";
1270 /* mirrors should be of the same size */
1271 if (stbuf.st_size != stbuf_v.st_size) {
1272 error_loc = "file sizes don't match";
1277 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
1279 error_loc = "cannot get lease";
1283 if (!(mirror_flags & NO_VERIFY)) {
1285 /* mirrors should have the same contents */
1286 ret = mirror_file_compare(fd, fdv);
1287 if (ret != stbuf.st_size) {
1288 error_loc = "file busy or contents don't match";
1289 rc = ret < 0 ? ret : -EINVAL;
1294 /* Get rid of caching pages from clients */
1295 rc = llapi_get_data_version(fd, &dv, LL_DV_WR_FLUSH);
1297 error_loc = "cannot get data version";
1301 rc = llapi_get_data_version(fdv, &dv, LL_DV_WR_FLUSH);
1303 error_loc = "cannot get data version";
1308 /* Make sure we keep original atime/mtime values */
1309 rc = migrate_copy_timestamps(fd, fdv);
1311 /* Atomically put lease, swap layouts and close.
1312 * for a migration we need to check data version on file did
1314 rc = llapi_fswap_layouts(fd, fdv, 0, 0, MERGE_LAYOUTS_CLOSE);
1316 error_loc = "cannot swap layout";
1328 (void) unlink(victim_file);
1331 fprintf(stderr, "error: %s: %s: %s: %s\n",
1332 progname, fname, error_loc, strerror(-rc));
1336 static int mirror_extend(char *fname, struct mirror_args *mirror_list,
1337 enum mirror_flags mirror_flags)
1341 rc = mirror_create_sanity_check(fname, mirror_list);
1345 while (mirror_list) {
1346 if (mirror_list->m_file != NULL) {
1347 rc = mirror_extend_file(fname, mirror_list->m_file,
1350 __u32 mirror_count = mirror_list->m_count;
1352 while (mirror_count > 0) {
1353 rc = lfs_migrate(fname,
1354 MIGRATION_NONBLOCK | MIGRATION_MIRROR,
1355 NULL, mirror_list->m_layout);
1365 mirror_list = mirror_list->m_next;
1372 * Parse a string containing an OST index list into an array of integers.
1374 * The input string contains a comma delimited list of individual
1375 * indices and ranges, for example "1,2-4,7". Add the indices into the
1376 * \a osts array and remove duplicates.
1378 * \param[out] osts array to store indices in
1379 * \param[in] size size of \a osts array
1380 * \param[in] offset starting index in \a osts
1381 * \param[in] arg string containing OST index list
1383 * \retval positive number of indices in \a osts
1384 * \retval -EINVAL unable to parse \a arg
1386 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
1390 int slots = size - offset;
1397 end_of_loop = false;
1398 while (!end_of_loop) {
1402 char *endptr = NULL;
1406 ptr = strchrnul(arg, ',');
1408 end_of_loop = *ptr == '\0';
1411 start_index = strtol(arg, &endptr, 0);
1412 if (endptr == arg) /* no data at all */
1414 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
1416 if (start_index < 0)
1419 end_index = start_index;
1420 if (*endptr == '-') {
1421 end_index = strtol(endptr + 1, &endptr, 0);
1422 if (*endptr != '\0')
1424 if (end_index < start_index)
1428 for (i = start_index; i <= end_index && slots > 0; i++) {
1431 /* remove duplicate */
1432 for (j = 0; j < offset; j++) {
1436 if (j == offset) { /* no duplicate */
1441 if (slots == 0 && i < end_index)
1449 if (!end_of_loop && ptr != NULL)
1452 return rc < 0 ? rc : nr;
1455 struct lfs_setstripe_args {
1456 unsigned long long lsa_comp_end;
1457 unsigned long long lsa_stripe_size;
1458 long long lsa_stripe_count;
1459 long long lsa_stripe_off;
1460 __u32 lsa_comp_flags;
1462 unsigned long long lsa_pattern;
1464 char *lsa_pool_name;
1467 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1469 memset(lsa, 0, sizeof(*lsa));
1471 lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
1472 lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
1473 lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
1474 lsa->lsa_pattern = LLAPI_LAYOUT_RAID0;
1475 lsa->lsa_pool_name = NULL;
1479 * setstripe_args_init_inherit() - Initialize and inherit stripe options.
1480 * @lsa: Stripe options to be initialized and inherited.
1482 * This function initializes stripe options in @lsa and inherit
1483 * stripe_size, stripe_count and OST pool_name options.
1487 static inline void setstripe_args_init_inherit(struct lfs_setstripe_args *lsa)
1489 unsigned long long stripe_size;
1490 long long stripe_count;
1491 char *pool_name = NULL;
1493 stripe_size = lsa->lsa_stripe_size;
1494 stripe_count = lsa->lsa_stripe_count;
1495 pool_name = lsa->lsa_pool_name;
1497 setstripe_args_init(lsa);
1499 lsa->lsa_stripe_size = stripe_size;
1500 lsa->lsa_stripe_count = stripe_count;
1501 lsa->lsa_pool_name = pool_name;
1504 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1506 return (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT ||
1507 lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ||
1508 lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
1509 lsa->lsa_pattern != LLAPI_LAYOUT_RAID0 ||
1510 lsa->lsa_pool_name != NULL ||
1511 lsa->lsa_comp_end != 0);
1515 * comp_args_to_layout() - Create or extend a composite layout.
1516 * @composite: Pointer to the composite layout.
1517 * @lsa: Stripe options for the new component.
1519 * This function creates or extends a composite layout by adding a new
1520 * component with stripe options from @lsa.
1522 * Return: 0 on success or an error code on failure.
1524 static int comp_args_to_layout(struct llapi_layout **composite,
1525 struct lfs_setstripe_args *lsa)
1527 struct llapi_layout *layout = *composite;
1528 uint64_t prev_end = 0;
1531 if (layout == NULL) {
1532 layout = llapi_layout_alloc();
1533 if (layout == NULL) {
1534 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1538 *composite = layout;
1542 /* Get current component extent, current component
1543 * must be the tail component. */
1544 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1546 fprintf(stderr, "Get comp extent failed. %s\n",
1551 rc = llapi_layout_comp_add(layout);
1553 fprintf(stderr, "Add component failed. %s\n",
1559 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1561 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1562 prev_end, lsa->lsa_comp_end, strerror(errno));
1566 /* Data-on-MDT component setting */
1567 if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
1568 /* In case of Data-on-MDT patterns the only extra option
1569 * applicable is stripe size option. */
1570 if (lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
1571 fprintf(stderr, "Option 'stripe-count' can't be "
1572 "specified with Data-on-MDT component: %lld\n",
1573 lsa->lsa_stripe_count);
1576 if (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT) {
1577 fprintf(stderr, "Option 'stripe-size' can't be "
1578 "specified with Data-on-MDT component: %llu\n",
1579 lsa->lsa_stripe_size);
1582 if (lsa->lsa_nr_osts != 0) {
1583 fprintf(stderr, "Option 'ost-list' can't be specified "
1584 "with Data-on-MDT component: '%i'\n",
1588 if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
1589 fprintf(stderr, "Option 'stripe-offset' can't be "
1590 "specified with Data-on-MDT component: %lld\n",
1591 lsa->lsa_stripe_off);
1594 if (lsa->lsa_pool_name != 0) {
1595 fprintf(stderr, "Option 'pool' can't be specified "
1596 "with Data-on-MDT component: '%s'\n",
1597 lsa->lsa_pool_name);
1601 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
1603 fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
1604 lsa->lsa_pattern, strerror(errno));
1607 /* Data-on-MDT component has always single stripe up to end */
1608 lsa->lsa_stripe_size = lsa->lsa_comp_end;
1611 rc = llapi_layout_stripe_size_set(layout, lsa->lsa_stripe_size);
1613 fprintf(stderr, "Set stripe size %llu failed: %s\n",
1614 lsa->lsa_stripe_size, strerror(errno));
1618 rc = llapi_layout_stripe_count_set(layout, lsa->lsa_stripe_count);
1620 fprintf(stderr, "Set stripe count %lld failed: %s\n",
1621 lsa->lsa_stripe_count, strerror(errno));
1625 if (lsa->lsa_pool_name != NULL) {
1626 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1628 fprintf(stderr, "Set pool name: %s failed. %s\n",
1629 lsa->lsa_pool_name, strerror(errno));
1633 rc = llapi_layout_pool_name_set(layout, "");
1635 fprintf(stderr, "Clear pool name failed: %s\n",
1641 if (lsa->lsa_nr_osts > 0) {
1642 if (lsa->lsa_stripe_count > 0 &&
1643 lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
1644 lsa->lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
1645 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1646 fprintf(stderr, "stripe_count(%lld) != nr_osts(%d)\n",
1647 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1650 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1651 rc = llapi_layout_ost_index_set(layout, i,
1656 } else if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
1657 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1660 fprintf(stderr, "Set ost index %d failed. %s\n",
1661 i, strerror(errno));
1668 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1669 * end of the last component in the existing file, and adjust the
1670 * first extent start of the components to be added accordingly. */
1671 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1673 struct llapi_layout *head;
1674 uint64_t start, end, stripe_size, prev_end = 0;
1681 head = llapi_layout_get_by_path(fname, 0);
1683 fprintf(stderr, "Read layout from %s failed. %s\n",
1684 fname, strerror(errno));
1686 } else if (errno == ENODATA) {
1687 /* file without LOVEA, this component-add will be turned
1688 * into a component-create. */
1689 llapi_layout_free(head);
1691 } else if (!llapi_layout_is_composite(head)) {
1692 fprintf(stderr, "'%s' isn't a composite file.\n",
1694 llapi_layout_free(head);
1698 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1700 fprintf(stderr, "Get prev extent failed. %s\n",
1702 llapi_layout_free(head);
1706 llapi_layout_free(head);
1708 /* Make sure we use the first component of the layout to be added. */
1709 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1711 fprintf(stderr, "Move component cursor failed. %s\n",
1716 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1718 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1722 if (start > prev_end || end <= prev_end) {
1723 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1724 "adjacent with the existing file extent end: %lu\n",
1725 start, end, prev_end);
1729 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1731 fprintf(stderr, "Get stripe size failed. %s\n",
1736 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1737 (prev_end & (stripe_size - 1))) {
1738 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1739 stripe_size, prev_end);
1743 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1745 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1746 prev_end, end, strerror(errno));
1753 static inline bool comp_flags_is_neg(__u32 flags)
1755 return flags & LCME_FL_NEG;
1758 static inline void comp_flags_set_neg(__u32 *flags)
1760 *flags |= LCME_FL_NEG;
1763 static inline void comp_flags_clear_neg(__u32 *flags)
1765 *flags &= ~LCME_FL_NEG;
1768 static int comp_str2flags(__u32 *flags, char *string)
1771 __u32 neg_flags = 0;
1777 for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1781 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1782 __u32 comp_flag = comp_flags_table[i].cfn_flag;
1783 const char *comp_name = comp_flags_table[i].cfn_name;
1785 if (strcmp(name, comp_name) == 0) {
1786 *flags |= comp_flag;
1788 } else if (strncmp(name, "^", 1) == 0 &&
1789 strcmp(name + 1, comp_name) == 0) {
1790 neg_flags |= comp_flag;
1795 llapi_printf(LLAPI_MSG_ERROR,
1796 "%s: component flag '%s' not supported\n",
1802 if (*flags == 0 && neg_flags == 0)
1804 /* don't support mixed flags for now */
1805 if (*flags && neg_flags)
1810 comp_flags_set_neg(flags);
1816 static inline bool arg_is_eof(char *arg)
1818 return !strncmp(arg, "-1", strlen("-1")) ||
1819 !strncmp(arg, "EOF", strlen("EOF")) ||
1820 !strncmp(arg, "eof", strlen("eof"));
1824 * lfs_mirror_alloc() - Allocate a mirror argument structure.
1826 * Return: Valid mirror_args pointer on success and
1827 * NULL if memory allocation fails.
1829 static struct mirror_args *lfs_mirror_alloc(void)
1831 struct mirror_args *mirror = NULL;
1834 mirror = calloc(1, sizeof(*mirror));
1845 * lfs_mirror_free() - Free memory allocated for a mirror argument
1847 * @mirror: Previously allocated mirror argument structure by
1848 * lfs_mirror_alloc().
1850 * Free memory allocated for @mirror.
1854 static void lfs_mirror_free(struct mirror_args *mirror)
1856 if (mirror->m_layout != NULL)
1857 llapi_layout_free(mirror->m_layout);
1862 * lfs_mirror_list_free() - Free memory allocated for a mirror list.
1863 * @mirror_list: Previously allocated mirror list.
1865 * Free memory allocated for @mirror_list.
1869 static void lfs_mirror_list_free(struct mirror_args *mirror_list)
1871 struct mirror_args *next_mirror = NULL;
1873 while (mirror_list != NULL) {
1874 next_mirror = mirror_list->m_next;
1875 lfs_mirror_free(mirror_list);
1876 mirror_list = next_mirror;
1888 LFS_COMP_USE_PARENT_OPT,
1889 LFS_COMP_NO_VERIFY_OPT,
1894 static int lfs_setstripe0(int argc, char **argv, enum setstripe_origin opc)
1896 struct lfs_setstripe_args lsa;
1897 struct llapi_stripe_param *param = NULL;
1898 struct find_param migrate_mdt_param = {
1908 char *mdt_idx_arg = NULL;
1909 unsigned long long size_units = 1;
1910 bool migrate_mode = false;
1911 bool migration_block = false;
1912 __u64 migration_flags = 0;
1913 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1914 int comp_del = 0, comp_set = 0;
1917 struct llapi_layout *layout = NULL;
1918 struct llapi_layout **lpp = &layout;
1919 bool mirror_mode = false;
1920 bool has_m_file = false;
1921 __u32 mirror_count = 0;
1922 enum mirror_flags mirror_flags = 0;
1923 struct mirror_args *mirror_list = NULL;
1924 struct mirror_args *new_mirror = NULL;
1925 struct mirror_args *last_mirror = NULL;
1928 struct option long_opts[] = {
1929 /* --block is only valid in migrate mode */
1930 { .val = 'b', .name = "block", .has_arg = no_argument},
1931 { .val = LFS_COMP_ADD_OPT,
1932 .name = "comp-add", .has_arg = no_argument},
1933 { .val = LFS_COMP_ADD_OPT,
1934 .name = "component-add",
1935 .has_arg = no_argument},
1936 { .val = LFS_COMP_DEL_OPT,
1937 .name = "comp-del", .has_arg = no_argument},
1938 { .val = LFS_COMP_DEL_OPT,
1939 .name = "component-del",
1940 .has_arg = no_argument},
1941 { .val = LFS_COMP_FLAGS_OPT,
1942 .name = "comp-flags", .has_arg = required_argument},
1943 { .val = LFS_COMP_FLAGS_OPT,
1944 .name = "component-flags",
1945 .has_arg = required_argument},
1946 { .val = LFS_COMP_SET_OPT,
1947 .name = "comp-set", .has_arg = no_argument},
1948 { .val = LFS_COMP_SET_OPT,
1949 .name = "component-set",
1950 .has_arg = no_argument},
1951 { .val = LFS_COMP_USE_PARENT_OPT,
1952 .name = "parent", .has_arg = no_argument},
1953 { .val = LFS_COMP_NO_VERIFY_OPT,
1954 .name = "no-verify", .has_arg = no_argument},
1955 { .val = 'c', .name = "stripe-count", .has_arg = required_argument},
1956 { .val = 'c', .name = "stripe_count", .has_arg = required_argument},
1957 { .val = 'd', .name = "delete", .has_arg = no_argument},
1958 { .val = 'E', .name = "comp-end", .has_arg = required_argument},
1959 { .val = 'E', .name = "component-end",
1960 .has_arg = required_argument},
1961 { .val = 'f', .name = "file", .has_arg = required_argument },
1962 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1963 { .val = 'i', .name = "stripe-index", .has_arg = required_argument},
1964 { .val = 'i', .name = "stripe_index", .has_arg = required_argument},
1965 { .val = 'I', .name = "comp-id", .has_arg = required_argument},
1966 { .val = 'I', .name = "component-id", .has_arg = required_argument},
1967 { .val = 'L', .name = "layout", .has_arg = required_argument },
1968 { .val = 'm', .name = "mdt", .has_arg = required_argument},
1969 { .val = 'm', .name = "mdt-index", .has_arg = required_argument},
1970 { .val = 'm', .name = "mdt_index", .has_arg = required_argument},
1971 { .val = 'N', .name = "mirror-count", .has_arg = optional_argument},
1972 /* --non-block is only valid in migrate mode */
1973 { .val = 'n', .name = "non-block", .has_arg = no_argument},
1974 { .val = 'o', .name = "ost", .has_arg = required_argument},
1975 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1976 { .val = 'o', .name = "ost-list", .has_arg = required_argument },
1977 { .val = 'o', .name = "ost_list", .has_arg = required_argument },
1979 { .val = 'p', .name = "pool", .has_arg = required_argument },
1980 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1981 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1982 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1983 /* --verbose is only valid in migrate mode */
1984 { .val = 'v', .name = "verbose", .has_arg = no_argument },
1987 setstripe_args_init(&lsa);
1989 migrate_mode = (opc == SO_MIGRATE);
1990 mirror_mode = (opc == SO_MIRROR_CREATE || opc == SO_MIRROR_EXTEND);
1992 snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
1994 while ((c = getopt_long(argc, argv, "bc:dE:f:i:I:m:N::no:p:L:s:S:v",
1995 long_opts, NULL)) >= 0) {
2000 case LFS_COMP_ADD_OPT:
2003 case LFS_COMP_DEL_OPT:
2006 case LFS_COMP_FLAGS_OPT:
2007 result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
2011 case LFS_COMP_SET_OPT:
2014 case LFS_COMP_USE_PARENT_OPT:
2016 fprintf(stderr, "error: %s: --parent must be "
2017 "specified with --mirror-count|-N "
2018 "option\n", progname);
2021 setstripe_args_init(&lsa);
2023 case LFS_COMP_NO_VERIFY_OPT:
2024 mirror_flags |= NO_VERIFY;
2027 if (!migrate_mode) {
2029 "%s %s: -b|--block valid only for migrate command\n",
2033 migration_block = true;
2036 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
2039 "%s %s: invalid stripe count '%s'\n",
2040 progname, argv[0], optarg);
2044 if (lsa.lsa_stripe_count == -1)
2045 lsa.lsa_stripe_count = LLAPI_LAYOUT_WIDE;
2048 /* delete the default striping pattern */
2052 if (lsa.lsa_comp_end != 0) {
2053 result = comp_args_to_layout(lpp, &lsa);
2056 "%s %s: invalid layout\n",
2061 setstripe_args_init_inherit(&lsa);
2064 if (arg_is_eof(optarg)) {
2065 lsa.lsa_comp_end = LUSTRE_EOF;
2067 result = llapi_parse_size(optarg,
2072 "%s %s: invalid component end '%s'\n",
2073 progname, argv[0], optarg);
2079 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
2082 "%s %s: invalid stripe offset '%s'\n",
2083 progname, argv[0], optarg);
2086 if (lsa.lsa_stripe_off == -1)
2087 lsa.lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2090 comp_id = strtoul(optarg, &end, 0);
2091 if (*end != '\0' || comp_id == 0 ||
2092 comp_id > LCME_ID_MAX) {
2094 "%s %s: invalid component ID '%s'\n",
2095 progname, argv[0], optarg);
2100 if (opc != SO_MIRROR_EXTEND) {
2102 "error: %s: invalid option: %s\n",
2103 progname, argv[optopt + 1]);
2106 if (last_mirror == NULL) {
2107 fprintf(stderr, "error: %s: '-N' must exist "
2108 "in front of '%s'\n",
2109 progname, argv[optopt + 1]);
2113 last_mirror->m_file = optarg;
2114 last_mirror->m_count = 1;
2118 if (strcmp(argv[optind - 1], "mdt") == 0) {
2119 /* Can be only the first component */
2120 if (layout != NULL) {
2122 fprintf(stderr, "error: 'mdt' layout "
2123 "can be only the first one\n");
2126 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
2128 fprintf(stderr, "error: 'mdt' layout "
2129 "size is too big\n");
2132 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
2133 } else if (strcmp(argv[optind - 1], "raid0") != 0) {
2135 fprintf(stderr, "error: layout '%s' is "
2136 "unknown, supported layouts are: "
2137 "'mdt', 'raid0'\n", argv[optind]);
2142 if (!migrate_mode) {
2144 "%s %s: -m|--mdt-index valid only for migrate command\n",
2148 mdt_idx_arg = optarg;
2151 if (!migrate_mode) {
2153 "%s %s: -n|--non-block valid only for migrate command\n",
2157 migration_flags |= MIGRATION_NONBLOCK;
2160 if (opc == SO_SETSTRIPE) {
2161 opc = SO_MIRROR_CREATE;
2165 if (optarg != NULL) {
2166 mirror_count = strtoul(optarg, &end, 0);
2167 if (*end != '\0' || mirror_count == 0) {
2169 "error: %s: bad mirror count: %s\n",
2176 new_mirror = lfs_mirror_alloc();
2177 new_mirror->m_count = mirror_count;
2179 if (mirror_list == NULL)
2180 mirror_list = new_mirror;
2182 if (last_mirror != NULL) {
2183 /* wrap up last mirror */
2184 if (lsa.lsa_comp_end == 0)
2185 lsa.lsa_comp_end = LUSTRE_EOF;
2187 result = comp_args_to_layout(lpp, &lsa);
2189 lfs_mirror_free(new_mirror);
2193 setstripe_args_init_inherit(&lsa);
2195 last_mirror->m_next = new_mirror;
2198 last_mirror = new_mirror;
2199 lpp = &last_mirror->m_layout;
2202 lsa.lsa_nr_osts = parse_targets(osts,
2203 sizeof(osts) / sizeof(__u32),
2204 lsa.lsa_nr_osts, optarg);
2205 if (lsa.lsa_nr_osts < 0) {
2207 "%s %s: invalid OST target(s) '%s'\n",
2208 progname, argv[0], optarg);
2212 lsa.lsa_osts = osts;
2213 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
2214 lsa.lsa_stripe_off = osts[0];
2219 lsa.lsa_pool_name = optarg;
2222 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
2226 "%s %s: invalid stripe size '%s'\n",
2227 progname, argv[0], optarg);
2232 if (!migrate_mode) {
2234 "%s %s: -v|--verbose valid only for migrate command\n",
2238 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
2241 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
2242 progname, argv[0], argv[optind - 1]);
2247 fname = argv[optind];
2249 if (optind == argc) {
2250 fprintf(stderr, "%s %s: FILE must be specified\n",
2255 if (mirror_mode && mirror_count == 0) {
2257 "error: %s: --mirror-count|-N option is required\n",
2264 if (lsa.lsa_comp_end == 0)
2265 lsa.lsa_comp_end = LUSTRE_EOF;
2268 if (lsa.lsa_comp_end != 0) {
2269 result = comp_args_to_layout(lpp, &lsa);
2274 if (mirror_flags & NO_VERIFY) {
2275 if (opc != SO_MIRROR_EXTEND) {
2277 "error: %s: --no-verify is valid only for lfs mirror extend command\n",
2281 } else if (!has_m_file) {
2283 "error: %s: --no-verify must be specified with -f <victim_file> option\n",
2290 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
2291 * altered by user space tool, so we don't need to support the
2292 * --component-set for this moment. */
2293 if (comp_set != 0) {
2294 fprintf(stderr, "%s %s: --component-set not supported\n",
2299 if ((delete + comp_set + comp_del + comp_add) > 1) {
2301 "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
2306 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
2307 lsa.lsa_comp_flags != 0 || layout != NULL)) {
2309 "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
2314 if ((comp_set || comp_del) &&
2315 (setstripe_args_specified(&lsa) || layout != NULL)) {
2317 "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
2322 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
2324 "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
2329 if (comp_add || comp_del) {
2332 result = lstat(fname, &st);
2333 if (result == 0 && S_ISDIR(st.st_mode)) {
2335 "%s setstripe: cannot use --component-add or --component-del for directory\n",
2341 fprintf(stderr, "error: %s: can't use --component-add "
2342 "or --component-del for mirror operation\n",
2349 if (layout == NULL) {
2351 "%s %s: option -E must be specified with --component-add\n",
2356 result = adjust_first_extent(fname, layout);
2357 if (result == -ENODATA)
2359 else if (result != 0)
2363 if (mdt_idx_arg != NULL && optind > 3) {
2365 "%s %s: option -m cannot be used with other options\n",
2370 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
2372 "%s %s: options --non-block and --block are mutually exclusive\n",
2377 if (!comp_del && !comp_set && comp_id != 0) {
2379 "%s %s: option -I can only be used with --component-del\n",
2384 if (mdt_idx_arg != NULL) {
2385 /* initialize migrate mdt parameters */
2386 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
2388 fprintf(stderr, "%s %s: invalid MDT index '%s'\n",
2389 progname, argv[0], mdt_idx_arg);
2392 migrate_mdt_param.fp_migrate = 1;
2393 } else if (layout == NULL) {
2394 /* initialize stripe parameters */
2395 param = calloc(1, offsetof(typeof(*param),
2396 lsp_osts[lsa.lsa_nr_osts]));
2397 if (param == NULL) {
2399 "%s %s: cannot allocate memory for parameters: %s\n",
2400 progname, argv[0], strerror(ENOMEM));
2405 if (lsa.lsa_stripe_size != LLAPI_LAYOUT_DEFAULT)
2406 param->lsp_stripe_size = lsa.lsa_stripe_size;
2407 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
2408 if (lsa.lsa_stripe_count == LLAPI_LAYOUT_WIDE)
2409 param->lsp_stripe_count = -1;
2411 param->lsp_stripe_count = lsa.lsa_stripe_count;
2413 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
2414 param->lsp_stripe_offset = -1;
2416 param->lsp_stripe_offset = lsa.lsa_stripe_off;
2417 param->lsp_pool = lsa.lsa_pool_name;
2418 param->lsp_is_specific = false;
2419 if (lsa.lsa_nr_osts > 0) {
2420 if (lsa.lsa_stripe_count > 0 &&
2421 lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
2422 lsa.lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
2423 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
2424 fprintf(stderr, "error: %s: stripe count %lld "
2425 "doesn't match the number of OSTs: %d\n"
2426 , argv[0], lsa.lsa_stripe_count,
2432 param->lsp_is_specific = true;
2433 param->lsp_stripe_count = lsa.lsa_nr_osts;
2434 memcpy(param->lsp_osts, osts,
2435 sizeof(*osts) * lsa.lsa_nr_osts);
2439 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
2440 if (mdt_idx_arg != NULL) {
2441 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
2442 } else if (migrate_mode) {
2443 result = lfs_migrate(fname, migration_flags, param,
2445 } else if (comp_set != 0) {
2446 result = lfs_component_set(fname, comp_id,
2447 lsa.lsa_comp_flags);
2448 } else if (comp_del != 0) {
2449 result = lfs_component_del(fname, comp_id,
2450 lsa.lsa_comp_flags);
2451 } else if (comp_add != 0) {
2452 result = lfs_component_add(fname, layout);
2453 } else if (opc == SO_MIRROR_CREATE) {
2454 result = mirror_create(fname, mirror_list);
2455 } else if (opc == SO_MIRROR_EXTEND) {
2456 result = mirror_extend(fname, mirror_list,
2458 } else if (layout != NULL) {
2459 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
2466 result = llapi_file_open_param(fname,
2475 /* Save the first error encountered. */
2483 llapi_layout_free(layout);
2484 lfs_mirror_list_free(mirror_list);
2489 llapi_layout_free(layout);
2490 lfs_mirror_list_free(mirror_list);
2494 static int lfs_poollist(int argc, char **argv)
2499 return llapi_poollist(argv[1]);
2502 static int set_time(time_t *time, time_t *set, char *str)
2509 else if (str[0] == '-')
2515 t = strtol(str, NULL, 0);
2516 if (*time < t * 24 * 60 * 60) {
2519 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
2523 *set = *time - t * 24 * 60 * 60;
2526 static int name2uid(unsigned int *id, const char *name)
2528 struct passwd *passwd;
2530 passwd = getpwnam(name);
2533 *id = passwd->pw_uid;
2538 static int name2gid(unsigned int *id, const char *name)
2540 struct group *group;
2542 group = getgrnam(name);
2545 *id = group->gr_gid;
2550 static inline int name2projid(unsigned int *id, const char *name)
2555 static int uid2name(char **name, unsigned int id)
2557 struct passwd *passwd;
2559 passwd = getpwuid(id);
2562 *name = passwd->pw_name;
2567 static inline int gid2name(char **name, unsigned int id)
2569 struct group *group;
2571 group = getgrgid(id);
2574 *name = group->gr_name;
2579 static int name2layout(__u32 *layout, char *name)
2581 char *ptr, *layout_name;
2584 for (ptr = name; ; ptr = NULL) {
2585 layout_name = strtok(ptr, ",");
2586 if (layout_name == NULL)
2588 if (strcmp(layout_name, "released") == 0)
2589 *layout |= LOV_PATTERN_F_RELEASED;
2590 else if (strcmp(layout_name, "raid0") == 0)
2591 *layout |= LOV_PATTERN_RAID0;
2592 else if (strcmp(layout_name, "mdt") == 0)
2593 *layout |= LOV_PATTERN_MDT;
2600 static int lfs_find(int argc, char **argv)
2605 struct find_param param = {
2609 struct option long_opts[] = {
2610 { .val = 'A', .name = "atime", .has_arg = required_argument },
2611 { .val = LFS_COMP_COUNT_OPT,
2612 .name = "comp-count", .has_arg = required_argument },
2613 { .val = LFS_COMP_COUNT_OPT,
2614 .name = "component-count",
2615 .has_arg = required_argument },
2616 { .val = LFS_COMP_FLAGS_OPT,
2617 .name = "comp-flags", .has_arg = required_argument },
2618 { .val = LFS_COMP_FLAGS_OPT,
2619 .name = "component-flags",
2620 .has_arg = required_argument },
2621 { .val = LFS_COMP_START_OPT,
2622 .name = "comp-start", .has_arg = required_argument },
2623 { .val = LFS_COMP_START_OPT,
2624 .name = "component-start",
2625 .has_arg = required_argument },
2626 { .val = 'c', .name = "stripe-count", .has_arg = required_argument },
2627 { .val = 'c', .name = "stripe_count", .has_arg = required_argument },
2628 { .val = 'C', .name = "ctime", .has_arg = required_argument },
2629 { .val = 'D', .name = "maxdepth", .has_arg = required_argument },
2630 { .val = 'E', .name = "comp-end", .has_arg = required_argument },
2631 { .val = 'E', .name = "component-end",
2632 .has_arg = required_argument },
2633 { .val = 'g', .name = "gid", .has_arg = required_argument },
2634 { .val = 'G', .name = "group", .has_arg = required_argument },
2635 { .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
2636 { .val = 'i', .name = "stripe-index", .has_arg = required_argument },
2637 { .val = 'i', .name = "stripe_index", .has_arg = required_argument },
2638 /*{"component-id", required_argument, 0, 'I'},*/
2639 { .val = 'L', .name = "layout", .has_arg = required_argument },
2640 { .val = 'm', .name = "mdt", .has_arg = required_argument },
2641 { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
2642 { .val = 'm', .name = "mdt_index", .has_arg = required_argument },
2643 { .val = 'M', .name = "mtime", .has_arg = required_argument },
2644 { .val = 'n', .name = "name", .has_arg = required_argument },
2645 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
2646 { .val = 'O', .name = "obd", .has_arg = required_argument },
2647 { .val = 'O', .name = "ost", .has_arg = required_argument },
2648 /* no short option for pool, p/P already used */
2649 { .val = LFS_POOL_OPT,
2650 .name = "pool", .has_arg = required_argument },
2651 { .val = 'p', .name = "print0", .has_arg = no_argument },
2652 { .val = 'P', .name = "print", .has_arg = no_argument },
2653 { .val = LFS_PROJID_OPT,
2654 .name = "projid", .has_arg = required_argument },
2655 { .val = 's', .name = "size", .has_arg = required_argument },
2656 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
2657 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
2658 { .val = 't', .name = "type", .has_arg = required_argument },
2659 { .val = 'T', .name = "mdt-count", .has_arg = required_argument },
2660 { .val = 'u', .name = "uid", .has_arg = required_argument },
2661 { .val = 'U', .name = "user", .has_arg = required_argument },
2673 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
2674 while ((c = getopt_long_only(argc, argv,
2675 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
2676 long_opts, NULL)) >= 0) {
2681 /* '!' is part of option */
2682 /* when getopt_long_only() finds a string which is not
2683 * an option nor a known option argument it returns 1
2684 * in that case if we already have found pathstart and pathend
2685 * (i.e. we have the list of pathnames),
2686 * the only supported value is "!"
2688 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
2689 if (!isoption && pathend != -1) {
2690 fprintf(stderr, "err: %s: filename|dirname must either "
2691 "precede options or follow options\n",
2696 if (!isoption && pathstart == -1)
2697 pathstart = optind - 1;
2698 if (isoption && pathstart != -1 && pathend == -1)
2699 pathend = optind - 2;
2705 /* unknown; opt is "!" or path component,
2706 * checking done above.
2708 if (strcmp(optarg, "!") == 0)
2712 xtime = ¶m.fp_atime;
2713 xsign = ¶m.fp_asign;
2714 param.fp_exclude_atime = !!neg_opt;
2715 /* no break, this falls through to 'C' for ctime */
2718 xtime = ¶m.fp_ctime;
2719 xsign = ¶m.fp_csign;
2720 param.fp_exclude_ctime = !!neg_opt;
2722 /* no break, this falls through to 'M' for mtime */
2725 xtime = ¶m.fp_mtime;
2726 xsign = ¶m.fp_msign;
2727 param.fp_exclude_mtime = !!neg_opt;
2729 rc = set_time(&t, xtime, optarg);
2730 if (rc == INT_MAX) {
2737 case LFS_COMP_COUNT_OPT:
2738 if (optarg[0] == '+') {
2739 param.fp_comp_count_sign = -1;
2741 } else if (optarg[0] == '-') {
2742 param.fp_comp_count_sign = 1;
2746 param.fp_comp_count = strtoul(optarg, &endptr, 0);
2747 if (*endptr != '\0') {
2748 fprintf(stderr, "error: bad component count "
2752 param.fp_check_comp_count = 1;
2753 param.fp_exclude_comp_count = !!neg_opt;
2755 case LFS_COMP_FLAGS_OPT:
2756 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
2757 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2758 fprintf(stderr, "error: bad component flags "
2762 param.fp_check_comp_flags = 1;
2763 param.fp_exclude_comp_flags = !!neg_opt;
2765 case LFS_COMP_START_OPT:
2766 if (optarg[0] == '+') {
2767 param.fp_comp_start_sign = -1;
2769 } else if (optarg[0] == '-') {
2770 param.fp_comp_start_sign = 1;
2774 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2775 ¶m.fp_comp_start_units, 0);
2777 fprintf(stderr, "error: bad component start "
2781 param.fp_check_comp_start = 1;
2782 param.fp_exclude_comp_start = !!neg_opt;
2785 if (optarg[0] == '+') {
2786 param.fp_stripe_count_sign = -1;
2788 } else if (optarg[0] == '-') {
2789 param.fp_stripe_count_sign = 1;
2793 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2794 if (*endptr != '\0') {
2795 fprintf(stderr,"error: bad stripe_count '%s'\n",
2800 param.fp_check_stripe_count = 1;
2801 param.fp_exclude_stripe_count = !!neg_opt;
2804 param.fp_max_depth = strtol(optarg, 0, 0);
2807 if (optarg[0] == '+') {
2808 param.fp_comp_end_sign = -1;
2810 } else if (optarg[0] == '-') {
2811 param.fp_comp_end_sign = 1;
2815 if (arg_is_eof(optarg)) {
2816 param.fp_comp_end = LUSTRE_EOF;
2817 param.fp_comp_end_units = 1;
2820 rc = llapi_parse_size(optarg,
2822 ¶m.fp_comp_end_units, 0);
2825 fprintf(stderr, "error: bad component end "
2829 param.fp_check_comp_end = 1;
2830 param.fp_exclude_comp_end = !!neg_opt;
2834 rc = name2gid(¶m.fp_gid, optarg);
2836 param.fp_gid = strtoul(optarg, &endptr, 10);
2837 if (*endptr != '\0') {
2838 fprintf(stderr, "Group/GID: %s cannot "
2839 "be found.\n", optarg);
2844 param.fp_exclude_gid = !!neg_opt;
2845 param.fp_check_gid = 1;
2848 param.fp_hash_type = check_hashtype(optarg);
2849 if (param.fp_hash_type == 0) {
2850 fprintf(stderr, "error: bad hash_type '%s'\n",
2855 param.fp_check_hash_type = 1;
2856 param.fp_exclude_hash_type = !!neg_opt;
2859 ret = name2layout(¶m.fp_layout, optarg);
2862 param.fp_exclude_layout = !!neg_opt;
2863 param.fp_check_layout = 1;
2867 rc = name2uid(¶m.fp_uid, optarg);
2869 param.fp_uid = strtoul(optarg, &endptr, 10);
2870 if (*endptr != '\0') {
2871 fprintf(stderr, "User/UID: %s cannot "
2872 "be found.\n", optarg);
2877 param.fp_exclude_uid = !!neg_opt;
2878 param.fp_check_uid = 1;
2881 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2883 "Pool name %s is too long"
2884 " (max is %d)\n", optarg,
2889 /* we do check for empty pool because empty pool
2890 * is used to find V1 lov attributes */
2891 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2892 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2893 param.fp_exclude_pool = !!neg_opt;
2894 param.fp_check_pool = 1;
2897 param.fp_pattern = (char *)optarg;
2898 param.fp_exclude_pattern = !!neg_opt;
2903 char *buf, *token, *next, *p;
2907 buf = strdup(optarg);
2913 param.fp_exclude_obd = !!neg_opt;
2916 while (token && *token) {
2917 token = strchr(token, ',');
2924 param.fp_exclude_mdt = !!neg_opt;
2925 param.fp_num_alloc_mdts += len;
2926 tmp = realloc(param.fp_mdt_uuid,
2927 param.fp_num_alloc_mdts *
2928 sizeof(*param.fp_mdt_uuid));
2934 param.fp_mdt_uuid = tmp;
2936 param.fp_exclude_obd = !!neg_opt;
2937 param.fp_num_alloc_obds += len;
2938 tmp = realloc(param.fp_obd_uuid,
2939 param.fp_num_alloc_obds *
2940 sizeof(*param.fp_obd_uuid));
2946 param.fp_obd_uuid = tmp;
2948 for (token = buf; token && *token; token = next) {
2949 struct obd_uuid *puuid;
2952 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2955 ¶m.fp_obd_uuid[param.fp_num_obds++];
2957 p = strchr(token, ',');
2964 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2969 strncpy(puuid->uuid, token,
2970 sizeof(puuid->uuid));
2978 param.fp_zero_end = 1;
2982 case LFS_PROJID_OPT:
2983 rc = name2projid(¶m.fp_projid, optarg);
2985 param.fp_projid = strtoul(optarg, &endptr, 10);
2986 if (*endptr != '\0') {
2988 "Invalid project ID: %s",
2994 param.fp_exclude_projid = !!neg_opt;
2995 param.fp_check_projid = 1;
2998 if (optarg[0] == '+') {
2999 param.fp_size_sign = -1;
3001 } else if (optarg[0] == '-') {
3002 param.fp_size_sign = 1;
3006 ret = llapi_parse_size(optarg, ¶m.fp_size,
3007 ¶m.fp_size_units, 0);
3009 fprintf(stderr, "error: bad file size '%s'\n",
3013 param.fp_check_size = 1;
3014 param.fp_exclude_size = !!neg_opt;
3017 if (optarg[0] == '+') {
3018 param.fp_stripe_size_sign = -1;
3020 } else if (optarg[0] == '-') {
3021 param.fp_stripe_size_sign = 1;
3025 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
3026 ¶m.fp_stripe_size_units, 0);
3028 fprintf(stderr, "error: bad stripe_size '%s'\n",
3032 param.fp_check_stripe_size = 1;
3033 param.fp_exclude_stripe_size = !!neg_opt;
3036 param.fp_exclude_type = !!neg_opt;
3037 switch (optarg[0]) {
3039 param.fp_type = S_IFBLK;
3042 param.fp_type = S_IFCHR;
3045 param.fp_type = S_IFDIR;
3048 param.fp_type = S_IFREG;
3051 param.fp_type = S_IFLNK;
3054 param.fp_type = S_IFIFO;
3057 param.fp_type = S_IFSOCK;
3060 fprintf(stderr, "error: %s: bad type '%s'\n",
3067 if (optarg[0] == '+') {
3068 param.fp_mdt_count_sign = -1;
3070 } else if (optarg[0] == '-') {
3071 param.fp_mdt_count_sign = 1;
3075 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
3076 if (*endptr != '\0') {
3077 fprintf(stderr, "error: bad mdt_count '%s'\n",
3082 param.fp_check_mdt_count = 1;
3083 param.fp_exclude_mdt_count = !!neg_opt;
3091 if (pathstart == -1) {
3092 fprintf(stderr, "error: %s: no filename|pathname\n",
3096 } else if (pathend == -1) {
3102 rc = llapi_find(argv[pathstart], ¶m);
3103 if (rc != 0 && ret == 0)
3105 } while (++pathstart < pathend);
3108 fprintf(stderr, "error: %s failed for %s.\n",
3109 argv[0], argv[optind - 1]);
3111 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
3112 free(param.fp_obd_uuid);
3114 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
3115 free(param.fp_mdt_uuid);
3120 static int lfs_getstripe_internal(int argc, char **argv,
3121 struct find_param *param)
3123 struct option long_opts[] = {
3124 { .val = LFS_COMP_COUNT_OPT,
3125 .name = "comp-count", .has_arg = no_argument },
3126 { .val = LFS_COMP_COUNT_OPT,
3127 .name = "component-count", .has_arg = no_argument },
3128 { .val = LFS_COMP_FLAGS_OPT,
3129 .name = "comp-flags", .has_arg = optional_argument },
3130 { .val = LFS_COMP_FLAGS_OPT,
3131 .name = "component-flags", .has_arg = optional_argument },
3132 { .val = LFS_COMP_START_OPT,
3133 .name = "comp-start", .has_arg = optional_argument },
3134 { .val = LFS_COMP_START_OPT,
3135 .name = "component-start", .has_arg = optional_argument },
3136 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3137 /* This formerly implied "stripe-count", but was explicitly
3138 * made "stripe-count" for consistency with other options,
3139 * and to separate it from "mdt-count" when DNE arrives. */
3140 { .val = 'c', .name = "count", .has_arg = no_argument },
3142 { .val = 'c', .name = "stripe-count", .has_arg = no_argument },
3143 { .val = 'c', .name = "stripe_count", .has_arg = no_argument },
3144 { .val = 'd', .name = "directory", .has_arg = no_argument },
3145 { .val = 'D', .name = "default", .has_arg = no_argument },
3146 { .val = 'E', .name = "comp-end", .has_arg = optional_argument },
3147 { .val = 'E', .name = "component-end",
3148 .has_arg = optional_argument },
3149 { .val = 'F', .name = "fid", .has_arg = no_argument },
3150 { .val = 'g', .name = "generation", .has_arg = no_argument },
3151 /* dirstripe { .val = 'H', .name = "mdt-hash",
3152 * .has_arg = required_argument }, */
3153 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3154 /* This formerly implied "stripe-index", but was explicitly
3155 * made "stripe-index" for consistency with other options,
3156 * and to separate it from "mdt-index" when DNE arrives. */
3157 { .val = 'i', .name = "index", .has_arg = no_argument },
3159 { .val = 'i', .name = "stripe-index", .has_arg = no_argument },
3160 { .val = 'i', .name = "stripe_index", .has_arg = no_argument },
3161 { .val = 'I', .name = "comp-id", .has_arg = optional_argument },
3162 { .val = 'I', .name = "component-id", .has_arg = optional_argument },
3163 { .val = 'L', .name = "layout", .has_arg = no_argument },
3164 { .val = 'm', .name = "mdt", .has_arg = no_argument },
3165 { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
3166 { .val = 'm', .name = "mdt_index", .has_arg = no_argument },
3167 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3168 { .val = 'M', .name = "mdt-index", .has_arg = no_argument },
3169 { .val = 'M', .name = "mdt_index", .has_arg = no_argument },
3171 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3172 /* This formerly implied "stripe-index", but was confusing
3173 * with "file offset" (which will eventually be needed for
3174 * with different layouts by offset), so deprecate it. */
3175 { .val = 'o', .name = "offset", .has_arg = no_argument },
3177 { .val = 'O', .name = "obd", .has_arg = required_argument },
3178 { .val = 'O', .name = "ost", .has_arg = required_argument },
3179 { .val = 'p', .name = "pool", .has_arg = no_argument },
3180 { .val = 'q', .name = "quiet", .has_arg = no_argument },
3181 { .val = 'r', .name = "recursive", .has_arg = no_argument },
3182 { .val = 'R', .name = "raw", .has_arg = no_argument },
3183 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3184 /* This formerly implied "--stripe-size", but was confusing
3185 * with "lfs find --size|-s", which means "file size", so use
3186 * the consistent "--stripe-size|-S" for all commands. */
3187 { .val = 's', .name = "size", .has_arg = no_argument },
3189 { .val = 'S', .name = "stripe-size", .has_arg = no_argument },
3190 { .val = 'S', .name = "stripe_size", .has_arg = no_argument },
3191 /* dirstripe { .val = 'T', .name = "mdt-count",
3192 * .has_arg = required_argument }, */
3193 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3194 { .val = 'y', .name = "yaml", .has_arg = no_argument },
3199 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
3200 long_opts, NULL)) != -1) {
3203 if (strcmp(argv[optind - 1], "--count") == 0)
3204 fprintf(stderr, "warning: '--count' deprecated,"
3205 " use '--stripe-count' instead\n");
3206 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3207 param->fp_verbose |= VERBOSE_COUNT;
3208 param->fp_max_depth = 0;
3211 case LFS_COMP_COUNT_OPT:
3212 param->fp_verbose |= VERBOSE_COMP_COUNT;
3213 param->fp_max_depth = 0;
3215 case LFS_COMP_FLAGS_OPT:
3216 if (optarg != NULL) {
3217 __u32 *flags = ¶m->fp_comp_flags;
3218 rc = comp_str2flags(flags, optarg);
3220 fprintf(stderr, "error: %s bad "
3221 "component flags '%s'.\n",
3225 param->fp_check_comp_flags = 1;
3226 param->fp_exclude_comp_flags =
3227 comp_flags_is_neg(*flags);
3228 comp_flags_clear_neg(flags);
3231 param->fp_verbose |= VERBOSE_COMP_FLAGS;
3232 param->fp_max_depth = 0;
3235 case LFS_COMP_START_OPT:
3236 if (optarg != NULL) {
3238 if (tmp[0] == '+') {
3239 param->fp_comp_start_sign = -1;
3241 } else if (tmp[0] == '-') {
3242 param->fp_comp_start_sign = 1;
3245 rc = llapi_parse_size(tmp,
3246 ¶m->fp_comp_start,
3247 ¶m->fp_comp_start_units, 0);
3249 fprintf(stderr, "error: %s bad "
3250 "component start '%s'.\n",
3254 param->fp_check_comp_start = 1;
3257 param->fp_verbose |= VERBOSE_COMP_START;
3258 param->fp_max_depth = 0;
3262 param->fp_max_depth = 0;
3265 param->fp_get_default_lmv = 1;
3268 if (optarg != NULL) {
3270 if (tmp[0] == '+') {
3271 param->fp_comp_end_sign = -1;
3273 } else if (tmp[0] == '-') {
3274 param->fp_comp_end_sign = 1;
3278 if (arg_is_eof(tmp)) {
3279 param->fp_comp_end = LUSTRE_EOF;
3280 param->fp_comp_end_units = 1;
3283 rc = llapi_parse_size(tmp,
3284 ¶m->fp_comp_end,
3285 ¶m->fp_comp_end_units, 0);
3288 fprintf(stderr, "error: %s bad "
3289 "component end '%s'.\n",
3293 param->fp_check_comp_end = 1;
3295 param->fp_verbose |= VERBOSE_COMP_END;
3296 param->fp_max_depth = 0;
3300 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3301 param->fp_verbose |= VERBOSE_DFID;
3302 param->fp_max_depth = 0;
3306 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3307 param->fp_verbose |= VERBOSE_GENERATION;
3308 param->fp_max_depth = 0;
3311 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3313 fprintf(stderr, "warning: '--offset|-o' deprecated, "
3314 "use '--stripe-index|-i' instead\n");
3317 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
3318 if (strcmp(argv[optind - 1], "--index") == 0)
3319 fprintf(stderr, "warning: '--index' deprecated"
3320 ", use '--stripe-index' instead\n");
3322 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3323 param->fp_verbose |= VERBOSE_OFFSET;
3324 param->fp_max_depth = 0;
3328 if (optarg != NULL) {
3329 param->fp_comp_id = strtoul(optarg, &end, 0);
3330 if (*end != '\0' || param->fp_comp_id == 0 ||
3331 param->fp_comp_id > LCME_ID_MAX) {
3332 fprintf(stderr, "error: %s bad "
3333 "component id '%s'\n",
3337 param->fp_check_comp_id = 1;
3340 param->fp_max_depth = 0;
3341 param->fp_verbose |= VERBOSE_COMP_ID;
3345 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3346 param->fp_verbose |= VERBOSE_LAYOUT;
3347 param->fp_max_depth = 0;
3350 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3352 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3353 fprintf(stderr, "warning: '-M' deprecated"
3354 ", use '-m' instead\n");
3358 if (!(param->fp_verbose & VERBOSE_DETAIL))
3359 param->fp_max_depth = 0;
3360 param->fp_verbose |= VERBOSE_MDTINDEX;
3363 if (param->fp_obd_uuid) {
3365 "error: %s: only one obduuid allowed",
3369 param->fp_obd_uuid = (struct obd_uuid *)optarg;
3372 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3373 param->fp_verbose |= VERBOSE_POOL;
3374 param->fp_max_depth = 0;
3381 param->fp_recursive = 1;
3386 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3388 fprintf(stderr, "warning: '--size|-s' deprecated, "
3389 "use '--stripe-size|-S' instead\n");
3390 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
3392 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3393 param->fp_verbose |= VERBOSE_SIZE;
3394 param->fp_max_depth = 0;
3398 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
3411 if (param->fp_recursive)
3412 param->fp_max_depth = -1;
3413 else if (param->fp_verbose & VERBOSE_DETAIL)
3414 param->fp_max_depth = 1;
3416 if (!param->fp_verbose)
3417 param->fp_verbose = VERBOSE_DEFAULT;
3418 if (param->fp_quiet)
3419 param->fp_verbose = VERBOSE_OBJID;
3422 rc = llapi_getstripe(argv[optind], param);
3423 } while (++optind < argc && !rc);
3426 fprintf(stderr, "error: %s failed for %s.\n",
3427 argv[0], argv[optind - 1]);
3431 static int lfs_tgts(int argc, char **argv)
3433 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3434 struct find_param param;
3435 int index = 0, rc=0;
3440 if (argc == 2 && !realpath(argv[1], path)) {
3442 fprintf(stderr, "error: invalid path '%s': %s\n",
3443 argv[1], strerror(-rc));
3447 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
3448 /* Check if we have a mount point */
3449 if (mntdir[0] == '\0')
3452 memset(¶m, 0, sizeof(param));
3453 if (!strcmp(argv[0], "mdts"))
3454 param.fp_get_lmv = 1;
3456 rc = llapi_ostlist(mntdir, ¶m);
3458 fprintf(stderr, "error: %s: failed on %s\n",
3461 if (path[0] != '\0')
3463 memset(mntdir, 0, PATH_MAX);
3469 static int lfs_getstripe(int argc, char **argv)
3471 struct find_param param = { 0 };
3473 param.fp_max_depth = 1;
3474 return lfs_getstripe_internal(argc, argv, ¶m);
3478 static int lfs_getdirstripe(int argc, char **argv)
3480 struct find_param param = { 0 };
3481 struct option long_opts[] = {
3482 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3483 { .val = 'c', .name = "mdt-count", .has_arg = no_argument },
3485 { .val = 'D', .name = "default", .has_arg = no_argument },
3486 { .val = 'H', .name = "mdt-hash", .has_arg = no_argument },
3487 { .val = 'i', .name = "mdt-index", .has_arg = no_argument },
3488 { .val = 'O', .name = "obd", .has_arg = required_argument },
3489 { .val = 'r', .name = "recursive", .has_arg = no_argument },
3490 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3491 { .val = 't', .name = "mdt-hash", .has_arg = no_argument },
3493 { .val = 'T', .name = "mdt-count", .has_arg = no_argument },
3494 { .val = 'y', .name = "yaml", .has_arg = no_argument },
3498 param.fp_get_lmv = 1;
3500 while ((c = getopt_long(argc, argv,
3501 "cDHiO:rtTy", long_opts, NULL)) != -1)
3505 if (param.fp_obd_uuid) {
3507 "error: %s: only one obduuid allowed",
3511 param.fp_obd_uuid = (struct obd_uuid *)optarg;
3513 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3515 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
3516 fprintf(stderr, "warning: '-c' deprecated"
3517 ", use '-T' instead\n");
3521 param.fp_verbose |= VERBOSE_COUNT;
3524 param.fp_verbose |= VERBOSE_OFFSET;
3526 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3530 param.fp_verbose |= VERBOSE_HASH_TYPE;
3533 param.fp_get_default_lmv = 1;
3536 param.fp_recursive = 1;
3549 if (param.fp_recursive)
3550 param.fp_max_depth = -1;
3552 if (!param.fp_verbose)
3553 param.fp_verbose = VERBOSE_DEFAULT;
3556 rc = llapi_getstripe(argv[optind], ¶m);
3557 } while (++optind < argc && !rc);
3560 fprintf(stderr, "error: %s failed for %s.\n",
3561 argv[0], argv[optind - 1]);
3566 static int lfs_setdirstripe(int argc, char **argv)
3570 unsigned int stripe_offset = -1;
3571 unsigned int stripe_count = 1;
3572 enum lmv_hash_type hash_type;
3575 char *stripe_offset_opt = NULL;
3576 char *stripe_count_opt = NULL;
3577 char *stripe_hash_opt = NULL;
3578 char *mode_opt = NULL;
3579 bool default_stripe = false;
3580 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
3581 mode_t previous_mode = 0;
3582 bool delete = false;
3584 struct option long_opts[] = {
3585 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3586 { .val = 'c', .name = "count", .has_arg = required_argument },
3588 { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
3589 { .val = 'd', .name = "delete", .has_arg = no_argument },
3590 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3591 { .val = 'i', .name = "index", .has_arg = required_argument },
3593 { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
3594 { .val = 'm', .name = "mode", .has_arg = required_argument },
3595 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3596 { .val = 't', .name = "hash-type", .has_arg = required_argument },
3597 { .val = 't', .name = "mdt-hash", .has_arg = required_argument },
3599 {"mdt-hash", required_argument, 0, 'H'},
3600 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3601 { .val = 'D', .name = "default_stripe",
3602 .has_arg = no_argument },
3604 { .val = 'D', .name = "default", .has_arg = no_argument },
3607 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
3614 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3615 if (strcmp(argv[optind - 1], "--count") == 0)
3617 "%s %s: warning: '--count' deprecated, use '--mdt-count' instead\n",
3620 stripe_count_opt = optarg;
3624 default_stripe = true;
3627 default_stripe = true;
3630 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3631 if (strcmp(argv[optind - 1], "--index") == 0)
3633 "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
3636 stripe_offset_opt = optarg;
3641 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3645 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3646 if (strcmp(argv[optind - 1], "--hash-type") == 0)
3648 "%s %s: warning: '--hash-type' deprecated, use '--mdt-hash' instead\n",
3651 stripe_hash_opt = optarg;
3654 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
3655 progname, argv[0], argv[optind - 1]);
3660 if (optind == argc) {
3661 fprintf(stderr, "%s %s: DIR must be specified\n",
3666 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
3668 "%s %s: stripe offset and count must be specified\n",
3673 if (stripe_offset_opt != NULL) {
3674 /* get the stripe offset */
3675 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
3678 "%s %s: bad stripe offset '%s'\n",
3679 progname, argv[0], stripe_offset_opt);
3685 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
3687 "%s %s: cannot specify -d with -c or -i options\n",
3696 if (mode_opt != NULL) {
3697 mode = strtoul(mode_opt, &end, 8);
3700 "%s %s: bad MODE '%s'\n",
3701 progname, argv[0], mode_opt);
3704 previous_mode = umask(0);
3707 if (stripe_hash_opt == NULL) {
3708 hash_type = LMV_HASH_TYPE_FNV_1A_64;
3710 hash_type = check_hashtype(stripe_hash_opt);
3711 if (hash_type == 0) {
3712 fprintf(stderr, "%s %s: bad stripe hash type '%s'\n",
3713 progname, argv[0], stripe_hash_opt);
3718 /* get the stripe count */
3719 if (stripe_count_opt != NULL) {
3720 stripe_count = strtoul(stripe_count_opt, &end, 0);
3723 "%s %s: bad stripe count '%s'\n",
3724 progname, argv[0], stripe_count_opt);
3729 dname = argv[optind];
3731 if (default_stripe) {
3732 result = llapi_dir_set_default_lmv_stripe(dname,
3733 stripe_offset, stripe_count,
3736 result = llapi_dir_create_pool(dname, mode,
3738 stripe_count, hash_type,
3744 "%s setdirstripe: cannot create stripe dir '%s': %s\n",
3745 progname, dname, strerror(-result));
3748 dname = argv[++optind];
3749 } while (dname != NULL);
3751 if (mode_opt != NULL)
3752 umask(previous_mode);
3758 static int lfs_rmentry(int argc, char **argv)
3765 fprintf(stderr, "error: %s: missing dirname\n",
3771 dname = argv[index];
3772 while (dname != NULL) {
3773 result = llapi_direntry_remove(dname);
3775 fprintf(stderr, "error: %s: remove dir entry '%s' "
3776 "failed\n", argv[0], dname);
3779 dname = argv[++index];
3784 static int lfs_mv(int argc, char **argv)
3786 struct find_param param = {
3793 struct option long_opts[] = {
3794 { .val = 'M', .name = "mdt-index", .has_arg = required_argument },
3795 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3798 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3801 param.fp_mdt_index = strtoul(optarg, &end, 0);
3803 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3810 param.fp_verbose = VERBOSE_DETAIL;
3814 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3815 argv[0], argv[optind - 1]);
3820 if (param.fp_mdt_index == -1) {
3821 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3825 if (optind >= argc) {
3826 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3830 param.fp_migrate = 1;
3831 rc = llapi_migrate_mdt(argv[optind], ¶m);
3833 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3834 argv[0], argv[optind], param.fp_mdt_index,
3839 static int lfs_osts(int argc, char **argv)
3841 return lfs_tgts(argc, argv);
3844 static int lfs_mdts(int argc, char **argv)
3846 return lfs_tgts(argc, argv);
3849 #define COOK(value) \
3852 while (value > 1024) { \
3860 #define CDF "%11llu"
3861 #define HDF "%8.1f%c"
3866 MNTDF_INODES = 0x0001,
3867 MNTDF_COOKED = 0x0002,
3868 MNTDF_LAZY = 0x0004,
3869 MNTDF_VERBOSE = 0x0008,
3872 static int showdf(char *mntdir, struct obd_statfs *stat,
3873 char *uuid, enum mntdf_flags flags,
3874 char *type, int index, int rc)
3876 long long avail, used, total;
3878 char *suffix = "KMGTPEZY";
3879 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3880 char tbuf[3 * sizeof(__u64)];
3881 char ubuf[3 * sizeof(__u64)];
3882 char abuf[3 * sizeof(__u64)];
3883 char rbuf[3 * sizeof(__u64)];
3890 if (flags & MNTDF_INODES) {
3891 avail = stat->os_ffree;
3892 used = stat->os_files - stat->os_ffree;
3893 total = stat->os_files;
3895 int shift = flags & MNTDF_COOKED ? 0 : 10;
3897 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3898 used = ((stat->os_blocks - stat->os_bfree) *
3899 stat->os_bsize) >> shift;
3900 total = (stat->os_blocks * stat->os_bsize) >> shift;
3903 if ((used + avail) > 0)
3904 ratio = (double)used / (double)(used + avail);
3906 if (flags & MNTDF_COOKED) {
3910 cook_val = (double)total;
3913 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3916 snprintf(tbuf, sizeof(tbuf), CDF, total);
3918 cook_val = (double)used;
3921 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3924 snprintf(ubuf, sizeof(ubuf), CDF, used);
3926 cook_val = (double)avail;
3929 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3932 snprintf(abuf, sizeof(abuf), CDF, avail);
3934 snprintf(tbuf, sizeof(tbuf), CDF, total);
3935 snprintf(ubuf, sizeof(tbuf), CDF, used);
3936 snprintf(abuf, sizeof(tbuf), CDF, avail);
3939 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3940 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3941 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3943 printf("[%s:%d]", type, index);
3945 if (stat->os_state) {
3947 * Each character represents the matching
3950 const char state_names[] = "DRSI";
3955 for (i = 0, state = stat->os_state;
3956 state && i < sizeof(state_names); i++) {
3957 if (!(state & (1 << i)))
3959 printf("%c", state_names[i]);
3967 printf(UUF": inactive device\n", uuid);
3970 printf(UUF": %s\n", uuid, strerror(-rc));
3977 struct ll_stat_type {
3982 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3984 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3985 struct obd_uuid uuid_buf;
3986 char *poolname = NULL;
3987 struct ll_stat_type types[] = {
3988 { .st_op = LL_STATFS_LMV, .st_name = "MDT" },
3989 { .st_op = LL_STATFS_LOV, .st_name = "OST" },
3990 { .st_name = NULL } };
3991 struct ll_stat_type *tp;
3992 __u64 ost_ffree = 0;
4000 poolname = strchr(pool, '.');
4001 if (poolname != NULL) {
4002 if (strncmp(fsname, pool, strlen(fsname))) {
4003 fprintf(stderr, "filesystem name incorrect\n");
4011 fd = open(mntdir, O_RDONLY);
4014 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
4019 if (flags & MNTDF_INODES)
4020 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
4021 "UUID", "Inodes", "IUsed", "IFree",
4022 "IUse%", "Mounted on");
4024 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
4025 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
4026 "Used", "Available", "Use%", "Mounted on");
4028 for (tp = types; tp->st_name != NULL; tp++) {
4029 for (index = 0; ; index++) {
4030 memset(&stat_buf, 0, sizeof(struct obd_statfs));
4031 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
4032 type = flags & MNTDF_LAZY ?
4033 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
4034 rc2 = llapi_obd_fstatfs(fd, type, index,
4035 &stat_buf, &uuid_buf);
4040 if (rc2 == -ENODATA) { /* Inactive device, OK. */
4041 if (!(flags & MNTDF_VERBOSE))
4043 } else if (rc2 < 0 && rc == 0) {
4047 if (poolname && tp->st_op == LL_STATFS_LOV &&
4048 llapi_search_ost(fsname, poolname,
4049 obd_uuid2str(&uuid_buf)) != 1)
4052 /* the llapi_obd_statfs() call may have returned with
4053 * an error, but if it filled in uuid_buf we will at
4054 * lease use that to print out a message for that OBD.
4055 * If we didn't get anything in the uuid_buf, then fill
4056 * it in so that we can print an error message. */
4057 if (uuid_buf.uuid[0] == '\0')
4058 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
4059 "%s%04x", tp->st_name, index);
4060 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
4061 flags, tp->st_name, index, rc2);
4064 if (tp->st_op == LL_STATFS_LMV) {
4065 sum.os_ffree += stat_buf.os_ffree;
4066 sum.os_files += stat_buf.os_files;
4067 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
4068 sum.os_blocks += stat_buf.os_blocks *
4070 sum.os_bfree += stat_buf.os_bfree *
4072 sum.os_bavail += stat_buf.os_bavail *
4074 ost_ffree += stat_buf.os_ffree;
4082 /* If we don't have as many objects free on the OST as inodes
4083 * on the MDS, we reduce the total number of inodes to
4084 * compensate, so that the "inodes in use" number is correct.
4085 * Matches ll_statfs_internal() so the results are consistent. */
4086 if (ost_ffree < sum.os_ffree) {
4087 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
4088 sum.os_ffree = ost_ffree;
4091 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
4097 static int lfs_df(int argc, char **argv)
4099 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
4100 enum mntdf_flags flags = 0;
4101 int c, rc = 0, index = 0;
4102 char fsname[PATH_MAX] = "", *pool_name = NULL;
4103 struct option long_opts[] = {
4104 { .val = 'h', .name = "human-readable",
4105 .has_arg = no_argument },
4106 { .val = 'i', .name = "inodes", .has_arg = no_argument },
4107 { .val = 'l', .name = "lazy", .has_arg = no_argument },
4108 { .val = 'p', .name = "pool", .has_arg = required_argument },
4109 { .val = 'v', .name = "verbose", .has_arg = no_argument },
4112 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
4115 flags |= MNTDF_COOKED;
4118 flags |= MNTDF_INODES;
4121 flags |= MNTDF_LAZY;
4127 flags |= MNTDF_VERBOSE;
4133 if (optind < argc && !realpath(argv[optind], path)) {
4135 fprintf(stderr, "error: invalid path '%s': %s\n",
4136 argv[optind], strerror(-rc));
4140 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
4141 /* Check if we have a mount point */
4142 if (mntdir[0] == '\0')
4145 rc = mntdf(mntdir, fsname, pool_name, flags);
4146 if (rc || path[0] != '\0')
4148 fsname[0] = '\0'; /* avoid matching in next loop */
4149 mntdir[0] = '\0'; /* avoid matching in next loop */
4155 static int lfs_getname(int argc, char **argv)
4157 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
4158 int rc = 0, index = 0, c;
4159 char buf[sizeof(struct obd_uuid)];
4161 while ((c = getopt(argc, argv, "h")) != -1)
4164 if (optind == argc) { /* no paths specified, get all paths. */
4165 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
4166 rc = llapi_getname(mntdir, buf, sizeof(buf));
4169 "cannot get name for `%s': %s\n",
4170 mntdir, strerror(-rc));
4174 printf("%s %s\n", buf, mntdir);
4176 path[0] = fsname[0] = mntdir[0] = 0;
4178 } else { /* paths specified, only attempt to search these. */
4179 for (; optind < argc; optind++) {
4180 rc = llapi_getname(argv[optind], buf, sizeof(buf));
4183 "cannot get name for `%s': %s\n",
4184 argv[optind], strerror(-rc));
4188 printf("%s %s\n", buf, argv[optind]);
4194 static int lfs_check(int argc, char **argv)
4197 char mntdir[PATH_MAX] = {'\0'};
4206 obd_types[0] = obd_type1;
4207 obd_types[1] = obd_type2;
4209 if (strcmp(argv[1], "osts") == 0) {
4210 strcpy(obd_types[0], "osc");
4211 } else if (strcmp(argv[1], "mds") == 0) {
4212 strcpy(obd_types[0], "mdc");
4213 } else if (strcmp(argv[1], "servers") == 0) {
4215 strcpy(obd_types[0], "osc");
4216 strcpy(obd_types[1], "mdc");
4218 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4223 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
4224 if (rc < 0 || mntdir[0] == '\0') {
4225 fprintf(stderr, "No suitable Lustre mount found\n");
4229 rc = llapi_target_check(num_types, obd_types, mntdir);
4231 fprintf(stderr, "error: %s: %s status failed\n",
4238 #ifdef HAVE_SYS_QUOTA_H
4239 #define ARG2INT(nr, str, msg) \
4242 nr = strtol(str, &endp, 0); \
4244 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
4249 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
4251 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
4252 * returns the value or ULONG_MAX on integer overflow or incorrect format
4254 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
4255 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
4256 * 3. empty integer value is interpreted as 0
4258 static unsigned long str2sec(const char* timestr)
4260 const char spec[] = "smhdw";
4261 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
4262 unsigned long val = 0;
4265 if (strpbrk(timestr, spec) == NULL) {
4266 /* no specifiers inside the time string,
4267 should treat it as an integer value */
4268 val = strtoul(timestr, &tail, 10);
4269 return *tail ? ULONG_MAX : val;
4272 /* format string is XXwXXdXXhXXmXXs */
4278 v = strtoul(timestr, &tail, 10);
4279 if (v == ULONG_MAX || *tail == '\0')
4280 /* value too large (ULONG_MAX or more)
4281 or missing specifier */
4284 ptr = strchr(spec, *tail);
4286 /* unknown specifier */
4291 /* check if product will overflow the type */
4292 if (!(v < ULONG_MAX / mult[ind]))
4295 ADD_OVERFLOW(val, mult[ind] * v);
4296 if (val == ULONG_MAX)
4308 #define ARG2ULL(nr, str, def_units) \
4310 unsigned long long limit, units = def_units; \
4313 rc = llapi_parse_size(str, &limit, &units, 1); \
4315 fprintf(stderr, "error: bad limit value %s\n", str); \
4321 static inline int has_times_option(int argc, char **argv)
4325 for (i = 1; i < argc; i++)
4326 if (!strcmp(argv[i], "-t"))
4332 int lfs_setquota_times(int argc, char **argv)
4335 struct if_quotactl qctl;
4336 char *mnt, *obd_type = (char *)qctl.obd_type;
4337 struct obd_dqblk *dqb = &qctl.qc_dqblk;
4338 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
4339 struct option long_opts[] = {
4340 { .val = 'b', .name = "block-grace", .has_arg = required_argument },
4341 { .val = 'g', .name = "group", .has_arg = no_argument },
4342 { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
4343 { .val = 'p', .name = "projid", .has_arg = no_argument },
4344 { .val = 't', .name = "times", .has_arg = no_argument },
4345 { .val = 'u', .name = "user", .has_arg = no_argument },
4349 memset(&qctl, 0, sizeof(qctl));
4350 qctl.qc_cmd = LUSTRE_Q_SETINFO;
4351 qctl.qc_type = ALLQUOTA;
4353 while ((c = getopt_long(argc, argv, "b:gi:ptu",
4354 long_opts, NULL)) != -1) {
4365 if (qctl.qc_type != ALLQUOTA) {
4366 fprintf(stderr, "error: -u/g/p can't be used "
4367 "more than once\n");
4370 qctl.qc_type = qtype;
4373 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
4374 fprintf(stderr, "error: bad block-grace: %s\n",
4378 dqb->dqb_valid |= QIF_BTIME;
4381 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
4382 fprintf(stderr, "error: bad inode-grace: %s\n",
4386 dqb->dqb_valid |= QIF_ITIME;
4388 case 't': /* Yes, of course! */
4390 default: /* getopt prints error message for us when opterr != 0 */
4395 if (qctl.qc_type == ALLQUOTA) {
4396 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
4400 if (optind != argc - 1) {
4401 fprintf(stderr, "error: unexpected parameters encountered\n");
4406 rc = llapi_quotactl(mnt, &qctl);
4409 fprintf(stderr, "%s %s ", obd_type,
4410 obd_uuid2str(&qctl.obd_uuid));
4411 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
4418 #define BSLIMIT (1 << 0)
4419 #define BHLIMIT (1 << 1)
4420 #define ISLIMIT (1 << 2)
4421 #define IHLIMIT (1 << 3)
4423 int lfs_setquota(int argc, char **argv)
4426 struct if_quotactl qctl;
4427 char *mnt, *obd_type = (char *)qctl.obd_type;
4428 struct obd_dqblk *dqb = &qctl.qc_dqblk;
4429 struct option long_opts[] = {
4430 { .val = 'b', .name = "block-softlimit",
4431 .has_arg = required_argument },
4432 { .val = 'B', .name = "block-hardlimit",
4433 .has_arg = required_argument },
4434 { .val = 'g', .name = "group", .has_arg = required_argument },
4435 { .val = 'i', .name = "inode-softlimit",
4436 .has_arg = required_argument },
4437 { .val = 'I', .name = "inode-hardlimit",
4438 .has_arg = required_argument },
4439 { .val = 'p', .name = "projid", .has_arg = required_argument },
4440 { .val = 'u', .name = "user", .has_arg = required_argument },
4442 unsigned limit_mask = 0;
4446 if (has_times_option(argc, argv))
4447 return lfs_setquota_times(argc, argv);
4449 memset(&qctl, 0, sizeof(qctl));
4450 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
4451 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
4452 * so it can be used as a marker that qc_type
4453 * isn't reinitialized from command line */
4455 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
4456 long_opts, NULL)) != -1) {
4460 rc = name2uid(&qctl.qc_id, optarg);
4464 rc = name2gid(&qctl.qc_id, optarg);
4468 rc = name2projid(&qctl.qc_id, optarg);
4470 if (qctl.qc_type != ALLQUOTA) {
4471 fprintf(stderr, "error: -u and -g can't be used"
4472 " more than once\n");
4475 qctl.qc_type = qtype;
4477 qctl.qc_id = strtoul(optarg, &endptr, 10);
4478 if (*endptr != '\0') {
4479 fprintf(stderr, "error: can't find id "
4480 "for name %s\n", optarg);
4486 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
4487 dqb->dqb_bsoftlimit >>= 10;
4488 limit_mask |= BSLIMIT;
4489 if (dqb->dqb_bsoftlimit &&
4490 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
4491 fprintf(stderr, "warning: block softlimit is "
4492 "smaller than the miminal qunit size, "
4493 "please see the help of setquota or "
4494 "Lustre manual for details.\n");
4497 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
4498 dqb->dqb_bhardlimit >>= 10;
4499 limit_mask |= BHLIMIT;
4500 if (dqb->dqb_bhardlimit &&
4501 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
4502 fprintf(stderr, "warning: block hardlimit is "
4503 "smaller than the miminal qunit size, "
4504 "please see the help of setquota or "
4505 "Lustre manual for details.\n");
4508 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
4509 limit_mask |= ISLIMIT;
4510 if (dqb->dqb_isoftlimit &&
4511 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
4512 fprintf(stderr, "warning: inode softlimit is "
4513 "smaller than the miminal qunit size, "
4514 "please see the help of setquota or "
4515 "Lustre manual for details.\n");
4518 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
4519 limit_mask |= IHLIMIT;
4520 if (dqb->dqb_ihardlimit &&
4521 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
4522 fprintf(stderr, "warning: inode hardlimit is "
4523 "smaller than the miminal qunit size, "
4524 "please see the help of setquota or "
4525 "Lustre manual for details.\n");
4527 default: /* getopt prints error message for us when opterr != 0 */
4532 if (qctl.qc_type == ALLQUOTA) {
4533 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
4537 if (limit_mask == 0) {
4538 fprintf(stderr, "error: at least one limit must be specified\n");
4542 if (optind != argc - 1) {
4543 fprintf(stderr, "error: unexpected parameters encountered\n");
4549 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
4550 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
4551 /* sigh, we can't just set blimits/ilimits */
4552 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
4553 .qc_type = qctl.qc_type,
4554 .qc_id = qctl.qc_id};
4556 rc = llapi_quotactl(mnt, &tmp_qctl);
4558 fprintf(stderr, "error: setquota failed while retrieving"
4559 " current quota settings (%s)\n",
4564 if (!(limit_mask & BHLIMIT))
4565 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
4566 if (!(limit_mask & BSLIMIT))
4567 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
4568 if (!(limit_mask & IHLIMIT))
4569 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
4570 if (!(limit_mask & ISLIMIT))
4571 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
4573 /* Keep grace times if we have got no softlimit arguments */
4574 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
4575 dqb->dqb_valid |= QIF_BTIME;
4576 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
4579 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
4580 dqb->dqb_valid |= QIF_ITIME;
4581 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
4585 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
4586 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
4588 rc = llapi_quotactl(mnt, &qctl);
4591 fprintf(stderr, "%s %s ", obd_type,
4592 obd_uuid2str(&qctl.obd_uuid));
4593 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
4600 /* Converts seconds value into format string
4601 * result is returned in buf
4603 * 1. result is in descenting order: 1w2d3h4m5s
4604 * 2. zero fields are not filled (except for p. 3): 5d1s
4605 * 3. zero seconds value is presented as "0s"
4607 static char * __sec2str(time_t seconds, char *buf)
4609 const char spec[] = "smhdw";
4610 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
4615 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
4616 c = seconds / mult[i];
4618 if (c > 0 || (i == 0 && buf == tail))
4619 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
4627 static void sec2str(time_t seconds, char *buf, int rc)
4634 tail = __sec2str(seconds, tail);
4636 if (rc && tail - buf < 39) {
4642 static void diff2str(time_t seconds, char *buf, time_t now)
4648 if (seconds <= now) {
4649 strcpy(buf, "none");
4652 __sec2str(seconds - now, buf);
4655 static void print_quota_title(char *name, struct if_quotactl *qctl,
4656 bool human_readable)
4658 printf("Disk quotas for %s %s (%cid %u):\n",
4659 qtype_name(qctl->qc_type), name,
4660 *qtype_name(qctl->qc_type), qctl->qc_id);
4661 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
4662 "Filesystem", human_readable ? "used" : "kbytes",
4663 "quota", "limit", "grace",
4664 "files", "quota", "limit", "grace");
4667 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
4670 snprintf(buf, buflen, "%ju", (uintmax_t)num);
4673 snprintf(buf, buflen, "%5.4gP",
4674 (double)num / ((__u64)1 << 40));
4676 snprintf(buf, buflen, "%5.4gT",
4677 (double)num / (1 << 30));
4679 snprintf(buf, buflen, "%5.4gG",
4680 (double)num / (1 << 20));
4682 snprintf(buf, buflen, "%5.4gM",
4683 (double)num / (1 << 10));
4685 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
4689 #define STRBUF_LEN 32
4690 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
4697 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
4698 int bover = 0, iover = 0;
4699 struct obd_dqblk *dqb = &qctl->qc_dqblk;
4700 char numbuf[3][STRBUF_LEN];
4702 char strbuf[STRBUF_LEN];
4704 if (dqb->dqb_bhardlimit &&
4705 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
4707 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
4708 if (dqb->dqb_btime > now) {
4715 if (dqb->dqb_ihardlimit &&
4716 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
4718 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
4719 if (dqb->dqb_itime > now) {
4727 if (strlen(mnt) > 15)
4728 printf("%s\n%15s", mnt, "");
4730 printf("%15s", mnt);
4733 diff2str(dqb->dqb_btime, timebuf, now);
4735 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
4736 strbuf, sizeof(strbuf), h);
4737 if (rc == -EREMOTEIO)
4738 sprintf(numbuf[0], "%s*", strbuf);
4740 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
4741 "%s" : "[%s]", strbuf);
4743 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
4744 if (type == QC_GENERAL)
4745 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4746 "%s" : "[%s]", strbuf);
4748 sprintf(numbuf[1], "%s", "-");
4750 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4751 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4752 "%s" : "[%s]", strbuf);
4754 printf(" %7s%c %6s %7s %7s",
4755 numbuf[0], bover ? '*' : ' ', numbuf[1],
4756 numbuf[2], bover > 1 ? timebuf : "-");
4759 diff2str(dqb->dqb_itime, timebuf, now);
4761 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4762 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4764 if (type == QC_GENERAL)
4765 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4767 (uintmax_t)dqb->dqb_isoftlimit);
4769 sprintf(numbuf[1], "%s", "-");
4771 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4772 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4774 if (type != QC_OSTIDX)
4775 printf(" %7s%c %6s %7s %7s",
4776 numbuf[0], iover ? '*' : ' ', numbuf[1],
4777 numbuf[2], iover > 1 ? timebuf : "-");
4779 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4782 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4783 qctl->qc_cmd == Q_GETOINFO) {
4787 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4788 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4789 printf("Block grace time: %s; Inode grace time: %s\n",
4790 bgtimebuf, igtimebuf);
4794 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4795 bool h, __u64 *total)
4797 int rc = 0, rc1 = 0, count = 0;
4798 __u32 valid = qctl->qc_valid;
4800 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4802 fprintf(stderr, "can not get %s count: %s\n",
4803 is_mdt ? "mdt": "ost", strerror(-rc));
4807 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4808 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4809 rc = llapi_quotactl(mnt, qctl);
4811 /* It is remote client case. */
4812 if (rc == -EOPNOTSUPP) {
4819 fprintf(stderr, "quotactl %s%d failed.\n",
4820 is_mdt ? "mdt": "ost", qctl->qc_idx);
4824 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4825 qctl->qc_valid, 0, h);
4826 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4827 qctl->qc_dqblk.dqb_bhardlimit;
4830 qctl->qc_valid = valid;
4834 static int lfs_quota(int argc, char **argv)
4837 char *mnt, *name = NULL;
4838 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4839 .qc_type = ALLQUOTA };
4840 char *obd_type = (char *)qctl.obd_type;
4841 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4842 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4843 verbose = 0, pass = 0, quiet = 0, inacc;
4845 __u32 valid = QC_GENERAL, idx = 0;
4846 __u64 total_ialloc = 0, total_balloc = 0;
4847 bool human_readable = false;
4850 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4861 if (qctl.qc_type != ALLQUOTA) {
4862 fprintf(stderr, "error: use either -u or -g\n");
4865 qctl.qc_type = qtype;
4868 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4871 valid = qctl.qc_valid = QC_UUID;
4872 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4875 valid = qctl.qc_valid = QC_MDTIDX;
4876 idx = qctl.qc_idx = atoi(optarg);
4879 valid = qctl.qc_valid = QC_OSTIDX;
4880 idx = qctl.qc_idx = atoi(optarg);
4889 human_readable = true;
4892 fprintf(stderr, "error: %s: option '-%c' "
4893 "unrecognized\n", argv[0], c);
4898 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4899 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4900 optind == argc - 1) {
4902 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4903 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4904 qctl.qc_valid = valid;
4906 qctl.qc_type = pass;
4907 switch (qctl.qc_type) {
4909 qctl.qc_id = geteuid();
4910 rc = uid2name(&name, qctl.qc_id);
4913 qctl.qc_id = getegid();
4914 rc = gid2name(&name, qctl.qc_id);
4924 /* lfs quota -u username /path/to/lustre/mount */
4925 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4926 /* options should be followed by u/g-name and mntpoint */
4927 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4928 fprintf(stderr, "error: missing quota argument(s)\n");
4932 name = argv[optind++];
4933 switch (qctl.qc_type) {
4935 rc = name2uid(&qctl.qc_id, name);
4938 rc = name2gid(&qctl.qc_id, name);
4941 rc = name2projid(&qctl.qc_id, name);
4948 qctl.qc_id = strtoul(name, &endptr, 10);
4949 if (*endptr != '\0') {
4950 fprintf(stderr, "error: can't find id for name: %s\n",
4955 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4956 fprintf(stderr, "error: missing quota info argument(s)\n");
4961 rc1 = llapi_quotactl(mnt, &qctl);
4965 fprintf(stderr, "%s quotas are not enabled.\n",
4966 qtype_name(qctl.qc_type));
4969 fprintf(stderr, "Permission denied.\n");
4972 /* We already got error message. */
4975 fprintf(stderr, "Unexpected quotactl error: %s\n",
4980 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4981 print_quota_title(name, &qctl, human_readable);
4983 if (rc1 && *obd_type)
4984 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4986 if (qctl.qc_valid != QC_GENERAL)
4989 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4990 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4991 (QIF_LIMITS|QIF_USAGE));
4993 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4995 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4997 char strbuf[STRBUF_LEN];
4999 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
5001 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
5003 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
5005 printf("Total allocated inode limit: %ju, total "
5006 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
5010 if (rc1 || rc2 || rc3 || inacc)
5011 printf("Some errors happened when getting quota info. "
5012 "Some devices may be not working or deactivated. "
5013 "The data in \"[]\" is inaccurate.\n");
5016 if (pass > 0 && pass < LL_MAXQUOTAS)
5021 #endif /* HAVE_SYS_QUOTA_H! */
5023 static int flushctx_ioctl(char *mp)
5027 fd = open(mp, O_RDONLY);
5029 fprintf(stderr, "flushctx: error open %s: %s\n",
5030 mp, strerror(errno));
5034 rc = ioctl(fd, LL_IOC_FLUSHCTX);
5036 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
5037 mp, strerror(errno));
5043 static int lfs_flushctx(int argc, char **argv)
5045 int kdestroy = 0, c;
5046 char mntdir[PATH_MAX] = {'\0'};
5050 while ((c = getopt(argc, argv, "k")) != -1) {
5056 fprintf(stderr, "error: %s: option '-%c' "
5057 "unrecognized\n", argv[0], c);
5063 if ((rc = system("kdestroy > /dev/null")) != 0) {
5064 rc = WEXITSTATUS(rc);
5065 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
5069 if (optind >= argc) {
5070 /* flush for all mounted lustre fs. */
5071 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
5072 /* Check if we have a mount point */
5073 if (mntdir[0] == '\0')
5076 if (flushctx_ioctl(mntdir))
5079 mntdir[0] = '\0'; /* avoid matching in next loop */
5082 /* flush fs as specified */
5083 while (optind < argc) {
5084 if (flushctx_ioctl(argv[optind++]))
5091 static int lfs_cp(int argc, char **argv)
5093 fprintf(stderr, "remote client copy file(s).\n"
5094 "obsolete, does not support it anymore.\n");
5098 static int lfs_ls(int argc, char **argv)
5100 fprintf(stderr, "remote client lists directory contents.\n"
5101 "obsolete, does not support it anymore.\n");
5105 static int lfs_changelog(int argc, char **argv)
5107 void *changelog_priv;
5108 struct changelog_rec *rec;
5109 long long startrec = 0, endrec = 0;
5111 struct option long_opts[] = {
5112 { .val = 'f', .name = "follow", .has_arg = no_argument },
5114 char short_opts[] = "f";
5117 while ((rc = getopt_long(argc, argv, short_opts,
5118 long_opts, NULL)) != -1) {
5126 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5127 argv[0], argv[optind - 1]);
5134 mdd = argv[optind++];
5136 startrec = strtoll(argv[optind++], NULL, 10);
5138 endrec = strtoll(argv[optind++], NULL, 10);
5140 rc = llapi_changelog_start(&changelog_priv,
5141 CHANGELOG_FLAG_BLOCK |
5142 CHANGELOG_FLAG_JOBID |
5143 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
5146 fprintf(stderr, "Can't start changelog: %s\n",
5147 strerror(errno = -rc));
5151 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
5155 if (endrec && rec->cr_index > endrec) {
5156 llapi_changelog_free(&rec);
5159 if (rec->cr_index < startrec) {
5160 llapi_changelog_free(&rec);
5164 secs = rec->cr_time >> 30;
5165 gmtime_r(&secs, &ts);
5166 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
5167 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
5168 changelog_type2str(rec->cr_type),
5169 ts.tm_hour, ts.tm_min, ts.tm_sec,
5170 (int)(rec->cr_time & ((1 << 30) - 1)),
5171 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
5172 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
5174 if (rec->cr_flags & CLF_JOBID) {
5175 struct changelog_ext_jobid *jid =
5176 changelog_rec_jobid(rec);
5178 if (jid->cr_jobid[0] != '\0')
5179 printf(" j=%s", jid->cr_jobid);
5182 if (rec->cr_namelen)
5183 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
5184 rec->cr_namelen, changelog_rec_name(rec));
5186 if (rec->cr_flags & CLF_RENAME) {
5187 struct changelog_ext_rename *rnm =
5188 changelog_rec_rename(rec);
5190 if (!fid_is_zero(&rnm->cr_sfid))
5191 printf(" s="DFID" sp="DFID" %.*s",
5192 PFID(&rnm->cr_sfid),
5193 PFID(&rnm->cr_spfid),
5194 (int)changelog_rec_snamelen(rec),
5195 changelog_rec_sname(rec));
5199 llapi_changelog_free(&rec);
5202 llapi_changelog_fini(&changelog_priv);
5205 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
5207 return (rc == 1 ? 0 : rc);
5210 static int lfs_changelog_clear(int argc, char **argv)
5218 endrec = strtoll(argv[3], NULL, 10);
5220 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
5223 fprintf(stderr, "%s: record out of range: %llu\n",
5225 else if (rc == -ENOENT)
5226 fprintf(stderr, "%s: no changelog user: %s\n",
5229 fprintf(stderr, "%s error: %s\n", argv[0],
5238 static int lfs_fid2path(int argc, char **argv)
5240 struct option long_opts[] = {
5241 { .val = 'c', .name = "cur", .has_arg = no_argument },
5242 { .val = 'l', .name = "link", .has_arg = required_argument },
5243 { .val = 'r', .name = "rec", .has_arg = required_argument },
5245 char short_opts[] = "cl:r:";
5246 char *device, *fid, *path;
5247 long long recno = -1;
5253 while ((rc = getopt_long(argc, argv, short_opts,
5254 long_opts, NULL)) != -1) {
5260 linkno = strtol(optarg, NULL, 10);
5263 recno = strtoll(optarg, NULL, 10);
5268 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5269 argv[0], argv[optind - 1]);
5277 device = argv[optind++];
5278 path = calloc(1, PATH_MAX);
5280 fprintf(stderr, "error: Not enough memory\n");
5285 while (optind < argc) {
5286 fid = argv[optind++];
5288 lnktmp = (linkno >= 0) ? linkno : 0;
5290 int oldtmp = lnktmp;
5291 long long rectmp = recno;
5293 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
5296 fprintf(stderr, "%s: error on FID %s: %s\n",
5297 argv[0], fid, strerror(errno = -rc2));
5304 fprintf(stdout, "%lld ", rectmp);
5305 if (device[0] == '/') {
5306 fprintf(stdout, "%s", device);
5307 if (device[strlen(device) - 1] != '/')
5308 fprintf(stdout, "/");
5309 } else if (path[0] == '\0') {
5310 fprintf(stdout, "/");
5312 fprintf(stdout, "%s\n", path);
5315 /* specified linkno */
5317 if (oldtmp == lnktmp)
5327 static int lfs_path2fid(int argc, char **argv)
5329 struct option long_opts[] = {
5330 { .val = 'p', .name = "parents", .has_arg = no_argument },
5333 const char short_opts[] = "p";
5334 const char *sep = "";
5337 bool show_parents = false;
5339 while ((rc = getopt_long(argc, argv, short_opts,
5340 long_opts, NULL)) != -1) {
5343 show_parents = true;
5346 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5347 argv[0], argv[optind - 1]);
5352 if (optind > argc - 1)
5354 else if (optind < argc - 1)
5358 for (path = argv + optind; *path != NULL; path++) {
5360 if (!show_parents) {
5361 err = llapi_path2fid(*path, &fid);
5363 printf("%s%s"DFID"\n",
5364 *sep != '\0' ? *path : "", sep,
5367 char name[NAME_MAX + 1];
5368 unsigned int linkno = 0;
5370 while ((err = llapi_path2parent(*path, linkno, &fid,
5371 name, sizeof(name))) == 0) {
5372 if (*sep != '\0' && linkno == 0)
5373 printf("%s%s", *path, sep);
5375 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
5380 /* err == -ENODATA is end-of-loop */
5381 if (linkno > 0 && err == -ENODATA) {
5388 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
5389 argv[0], show_parents ? "parent " : "", *path,
5401 static int lfs_data_version(int argc, char **argv)
5408 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
5413 while ((c = getopt(argc, argv, "nrw")) != -1) {
5416 data_version_flags = 0;
5419 data_version_flags |= LL_DV_RD_FLUSH;
5422 data_version_flags |= LL_DV_WR_FLUSH;
5431 path = argv[optind];
5432 fd = open(path, O_RDONLY);
5434 err(errno, "cannot open file %s", path);
5436 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
5438 err(errno, "cannot get version for %s", path);
5440 printf("%ju" "\n", (uintmax_t)data_version);
5446 static int lfs_hsm_state(int argc, char **argv)
5451 struct hsm_user_state hus;
5459 rc = llapi_hsm_state_get(path, &hus);
5461 fprintf(stderr, "can't get hsm state for %s: %s\n",
5462 path, strerror(errno = -rc));
5466 /* Display path name and status flags */
5467 printf("%s: (0x%08x)", path, hus.hus_states);
5469 if (hus.hus_states & HS_RELEASED)
5470 printf(" released");
5471 if (hus.hus_states & HS_EXISTS)
5473 if (hus.hus_states & HS_DIRTY)
5475 if (hus.hus_states & HS_ARCHIVED)
5476 printf(" archived");
5477 /* Display user-settable flags */
5478 if (hus.hus_states & HS_NORELEASE)
5479 printf(" never_release");
5480 if (hus.hus_states & HS_NOARCHIVE)
5481 printf(" never_archive");
5482 if (hus.hus_states & HS_LOST)
5483 printf(" lost_from_hsm");
5485 if (hus.hus_archive_id != 0)
5486 printf(", archive_id:%d", hus.hus_archive_id);
5489 } while (++i < argc);
5494 #define LFS_HSM_SET 0
5495 #define LFS_HSM_CLEAR 1
5498 * Generic function to set or clear HSM flags.
5499 * Used by hsm_set and hsm_clear.
5501 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
5503 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
5505 struct option long_opts[] = {
5506 { .val = 'A', .name = "archived", .has_arg = no_argument },
5507 { .val = 'a', .name = "noarchive", .has_arg = no_argument },
5508 { .val = 'd', .name = "dirty", .has_arg = no_argument },
5509 { .val = 'e', .name = "exists", .has_arg = no_argument },
5510 { .val = 'l', .name = "lost", .has_arg = no_argument },
5511 { .val = 'r', .name = "norelease", .has_arg = no_argument },
5513 char short_opts[] = "lraAde";
5521 while ((c = getopt_long(argc, argv, short_opts,
5522 long_opts, NULL)) != -1) {
5528 mask |= HS_NOARCHIVE;
5531 mask |= HS_ARCHIVED;
5534 mask |= HS_NORELEASE;
5545 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5546 argv[0], argv[optind - 1]);
5551 /* User should have specified a flag */
5555 while (optind < argc) {
5557 path = argv[optind];
5559 /* If mode == 0, this means we apply the mask. */
5560 if (mode == LFS_HSM_SET)
5561 rc = llapi_hsm_state_set(path, mask, 0, 0);
5563 rc = llapi_hsm_state_set(path, 0, mask, 0);
5566 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
5567 path, strerror(errno = -rc));
5576 static int lfs_hsm_action(int argc, char **argv)
5581 struct hsm_current_action hca;
5582 struct hsm_extent he;
5583 enum hsm_user_action hua;
5584 enum hsm_progress_states hps;
5592 rc = llapi_hsm_current_action(path, &hca);
5594 fprintf(stderr, "can't get hsm action for %s: %s\n",
5595 path, strerror(errno = -rc));
5598 he = hca.hca_location;
5599 hua = hca.hca_action;
5600 hps = hca.hca_state;
5602 printf("%s: %s", path, hsm_user_action2name(hua));
5604 /* Skip file without action */
5605 if (hca.hca_action == HUA_NONE) {
5610 printf(" %s ", hsm_progress_state2name(hps));
5612 if ((hps == HPS_RUNNING) &&
5613 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
5614 printf("(%llu bytes moved)\n",
5615 (unsigned long long)he.length);
5616 else if ((he.offset + he.length) == LUSTRE_EOF)
5617 printf("(from %llu to EOF)\n",
5618 (unsigned long long)he.offset);
5620 printf("(from %llu to %llu)\n",
5621 (unsigned long long)he.offset,
5622 (unsigned long long)(he.offset + he.length));
5624 } while (++i < argc);
5629 static int lfs_hsm_set(int argc, char **argv)
5631 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
5634 static int lfs_hsm_clear(int argc, char **argv)
5636 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
5640 * Check file state and return its fid, to be used by lfs_hsm_request().
5642 * \param[in] file Path to file to check
5643 * \param[in,out] fid Pointer to allocated lu_fid struct.
5644 * \param[in,out] last_dev Pointer to last device id used.
5646 * \return 0 on success.
5648 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
5654 rc = lstat(file, &st);
5656 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
5659 /* Checking for regular file as archiving as posix copytool
5660 * rejects archiving files other than regular files
5662 if (!S_ISREG(st.st_mode)) {
5663 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
5666 /* A request should be ... */
5667 if (*last_dev != st.st_dev && *last_dev != 0) {
5668 fprintf(stderr, "All files should be "
5669 "on the same filesystem: %s\n", file);
5672 *last_dev = st.st_dev;
5674 rc = llapi_path2fid(file, fid);
5676 fprintf(stderr, "Cannot read FID of %s: %s\n",
5677 file, strerror(-rc));
5683 /* Fill an HSM HUR item with a given file name.
5685 * If mntpath is set, then the filename is actually a FID, and no
5686 * lookup on the filesystem will be performed.
5688 * \param[in] hur the user request to fill
5689 * \param[in] idx index of the item inside the HUR to fill
5690 * \param[in] mntpath mountpoint of Lustre
5691 * \param[in] fname filename (if mtnpath is NULL)
5692 * or FID (if mntpath is set)
5693 * \param[in] last_dev pointer to last device id used
5695 * \retval 0 on success
5696 * \retval CMD_HELP or a negative errno on error
5698 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
5699 const char *mntpath, const char *fname,
5702 struct hsm_user_item *hui = &hur->hur_user_item[idx];
5705 hui->hui_extent.length = -1;
5707 if (mntpath != NULL) {
5710 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
5714 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
5719 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
5723 hur->hur_request.hr_itemcount++;
5728 static int lfs_hsm_request(int argc, char **argv, int action)
5730 struct option long_opts[] = {
5731 { .val = 'a', .name = "archive", .has_arg = required_argument },
5732 { .val = 'D', .name = "data", .has_arg = required_argument },
5733 { .val = 'l', .name = "filelist", .has_arg = required_argument },
5734 { .val = 'm', .name = "mntpath", .has_arg = required_argument },
5737 char short_opts[] = "l:D:a:m:";
5738 struct hsm_user_request *hur, *oldhur;
5743 char *filelist = NULL;
5744 char fullpath[PATH_MAX];
5745 char *opaque = NULL;
5749 int nbfile_alloc = 0;
5750 char *some_file = NULL;
5751 char *mntpath = NULL;
5757 while ((c = getopt_long(argc, argv, short_opts,
5758 long_opts, NULL)) != -1) {
5767 if (action != HUA_ARCHIVE &&
5768 action != HUA_REMOVE) {
5770 "error: -a is supported only "
5771 "when archiving or removing\n");
5774 archive_id = atoi(optarg);
5777 if (some_file == NULL) {
5779 some_file = strdup(optarg);
5785 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5786 argv[0], argv[optind - 1]);
5791 /* All remaining args are files, so we have at least nbfile */
5792 nbfile = argc - optind;
5794 if ((nbfile == 0) && (filelist == NULL))
5798 opaque_len = strlen(opaque);
5800 /* Alloc the request structure with enough place to store all files
5801 * from command line. */
5802 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5804 fprintf(stderr, "Cannot create the request: %s\n",
5808 nbfile_alloc = nbfile;
5810 hur->hur_request.hr_action = action;
5811 hur->hur_request.hr_archive_id = archive_id;
5812 hur->hur_request.hr_flags = 0;
5814 /* All remaining args are files, add them */
5815 if (nbfile != 0 && some_file == NULL)
5816 some_file = strdup(argv[optind]);
5818 for (i = 0; i < nbfile; i++) {
5819 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5825 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5827 /* If a filelist was specified, read the filelist from it. */
5828 if (filelist != NULL) {
5829 fp = fopen(filelist, "r");
5831 fprintf(stderr, "Cannot read the file list %s: %s\n",
5832 filelist, strerror(errno));
5837 while ((rc = getline(&line, &len, fp)) != -1) {
5838 /* If allocated buffer was too small, get something
5840 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5843 nbfile_alloc = nbfile_alloc * 2 + 1;
5845 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5848 fprintf(stderr, "hsm: cannot allocate "
5849 "the request: %s\n",
5856 size = hur_len(oldhur);
5858 fprintf(stderr, "hsm: cannot allocate "
5859 "%u files + %u bytes data\n",
5860 oldhur->hur_request.hr_itemcount,
5861 oldhur->hur_request.hr_data_len);
5868 memcpy(hur, oldhur, size);
5873 if (line[strlen(line) - 1] == '\n')
5874 line[strlen(line) - 1] = '\0';
5876 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5877 mntpath, line, &last_dev);
5883 if (some_file == NULL) {
5893 /* If a --data was used, add it to the request */
5894 hur->hur_request.hr_data_len = opaque_len;
5896 memcpy(hur_data(hur), opaque, opaque_len);
5898 /* Send the HSM request */
5899 if (realpath(some_file, fullpath) == NULL) {
5900 fprintf(stderr, "Could not find path '%s': %s\n",
5901 some_file, strerror(errno));
5903 rc = llapi_hsm_request(fullpath, hur);
5905 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5906 some_file, strerror(-rc));
5916 static int lfs_hsm_archive(int argc, char **argv)
5918 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5921 static int lfs_hsm_restore(int argc, char **argv)
5923 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5926 static int lfs_hsm_release(int argc, char **argv)
5928 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5931 static int lfs_hsm_remove(int argc, char **argv)
5933 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5936 static int lfs_hsm_cancel(int argc, char **argv)
5938 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5941 static int lfs_swap_layouts(int argc, char **argv)
5946 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5947 SWAP_LAYOUTS_KEEP_MTIME |
5948 SWAP_LAYOUTS_KEEP_ATIME);
5951 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5953 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
5955 static const char *const lockahead_results[] = {
5956 [LLA_RESULT_SENT] = "Lock request sent",
5957 [LLA_RESULT_DIFFERENT] = "Different matching lock found",
5958 [LLA_RESULT_SAME] = "Matching lock on identical extent found",
5961 int lfs_get_mode(const char *string)
5963 enum lock_mode_user mode;
5965 for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
5966 if (lock_mode_names[mode] == NULL)
5968 if (strcmp(string, lock_mode_names[mode]) == 0)
5975 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5977 enum lu_ladvise_type advice;
5980 advice < ARRAY_SIZE(ladvise_names); advice++) {
5981 if (ladvise_names[advice] == NULL)
5983 if (strcmp(string, ladvise_names[advice]) == 0)
5987 return LU_LADVISE_INVALID;
5990 static int lfs_ladvise(int argc, char **argv)
5992 struct option long_opts[] = {
5993 { .val = 'a', .name = "advice", .has_arg = required_argument },
5994 { .val = 'b', .name = "background", .has_arg = no_argument },
5995 { .val = 'e', .name = "end", .has_arg = required_argument },
5996 { .val = 'l', .name = "length", .has_arg = required_argument },
5997 { .val = 'm', .name = "mode", .has_arg = required_argument },
5998 { .val = 's', .name = "start", .has_arg = required_argument },
5999 { .val = 'u', .name = "unset", .has_arg = no_argument },
6001 char short_opts[] = "a:be:l:m:s:u";
6006 struct llapi_lu_ladvise advice;
6007 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
6008 unsigned long long start = 0;
6009 unsigned long long end = LUSTRE_EOF;
6010 unsigned long long length = 0;
6011 unsigned long long size_units;
6012 unsigned long long flags = 0;
6016 while ((c = getopt_long(argc, argv, short_opts,
6017 long_opts, NULL)) != -1) {
6020 advice_type = lfs_get_ladvice(optarg);
6021 if (advice_type == LU_LADVISE_INVALID) {
6022 fprintf(stderr, "%s: invalid advice type "
6023 "'%s'\n", argv[0], optarg);
6024 fprintf(stderr, "Valid types:");
6026 for (advice_type = 0;
6027 advice_type < ARRAY_SIZE(ladvise_names);
6029 if (ladvise_names[advice_type] == NULL)
6031 fprintf(stderr, " %s",
6032 ladvise_names[advice_type]);
6034 fprintf(stderr, "\n");
6047 rc = llapi_parse_size(optarg, &end,
6050 fprintf(stderr, "%s: bad end offset '%s'\n",
6057 rc = llapi_parse_size(optarg, &start,
6060 fprintf(stderr, "%s: bad start offset "
6061 "'%s'\n", argv[0], optarg);
6067 rc = llapi_parse_size(optarg, &length,
6070 fprintf(stderr, "%s: bad length '%s'\n",
6076 mode = lfs_get_mode(optarg);
6078 fprintf(stderr, "%s: bad mode '%s', valid "
6079 "modes are READ or WRITE\n",
6087 fprintf(stderr, "%s: option '%s' unrecognized\n",
6088 argv[0], argv[optind - 1]);
6093 if (advice_type == LU_LADVISE_INVALID) {
6094 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
6095 fprintf(stderr, "Valid types:");
6096 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
6098 if (ladvise_names[advice_type] == NULL)
6100 fprintf(stderr, " %s", ladvise_names[advice_type]);
6102 fprintf(stderr, "\n");
6106 if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
6107 fprintf(stderr, "%s: Lock no expand advice is a per file "
6108 "descriptor advice, so when called from lfs, "
6109 "it does nothing.\n", argv[0]);
6113 if (argc <= optind) {
6114 fprintf(stderr, "%s: please give one or more file names\n",
6119 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
6120 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
6125 if (end == LUSTRE_EOF && length != 0)
6126 end = start + length;
6129 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
6130 argv[0], start, end);
6134 if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
6135 fprintf(stderr, "%s: mode is only valid with lockahead\n",
6140 if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
6141 fprintf(stderr, "%s: mode is required with lockahead\n",
6146 while (optind < argc) {
6149 path = argv[optind++];
6151 fd = open(path, O_RDONLY);
6153 fprintf(stderr, "%s: cannot open file '%s': %s\n",
6154 argv[0], path, strerror(errno));
6159 advice.lla_start = start;
6160 advice.lla_end = end;
6161 advice.lla_advice = advice_type;
6162 advice.lla_value1 = 0;
6163 advice.lla_value2 = 0;
6164 advice.lla_value3 = 0;
6165 advice.lla_value4 = 0;
6166 if (advice_type == LU_LADVISE_LOCKAHEAD) {
6167 advice.lla_lockahead_mode = mode;
6168 advice.lla_peradvice_flags = flags;
6171 rc2 = llapi_ladvise(fd, flags, 1, &advice);
6174 fprintf(stderr, "%s: cannot give advice '%s' to file "
6175 "'%s': %s\n", argv[0],
6176 ladvise_names[advice_type],
6177 path, strerror(errno));
6183 if (rc == 0 && rc2 < 0)
6189 /** The input string contains a comma delimited list of component ids and
6190 * ranges, for example "1,2-4,7".
6192 static int parse_mirror_ids(__u16 *ids, int size, char *arg)
6194 bool end_of_loop = false;
6202 while (!end_of_loop) {
6206 char *endptr = NULL;
6209 ptr = strchrnul(arg, ',');
6210 end_of_loop = *ptr == '\0';
6213 start_index = strtol(arg, &endptr, 0);
6214 if (endptr == arg) /* no data at all */
6216 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
6218 if (start_index < 0)
6221 end_index = start_index;
6222 if (*endptr == '-') {
6223 end_index = strtol(endptr + 1, &endptr, 0);
6224 if (*endptr != '\0')
6226 if (end_index < start_index)
6230 for (i = start_index; i <= end_index && size > 0; i++) {
6233 /* remove duplicate */
6234 for (j = 0; j < nr; j++) {
6238 if (j == nr) { /* no duplicate */
6244 if (size == 0 && i < end_index)
6251 if (!end_of_loop && ptr != NULL)
6254 return rc < 0 ? rc : nr;
6257 static inline int lfs_mirror_resync(int argc, char **argv)
6266 struct llapi_layout *layout;
6267 struct ll_ioc_lease *ioc = NULL;
6268 struct llapi_resync_comp comp_array[1024] = { { 0 } };
6269 __u16 mirror_ids[128] = { 0 };
6274 struct option long_opts[] = {
6275 { .val = 'o', .name = "only", .has_arg = required_argument },
6278 while ((c = getopt_long(argc, argv, "o:", long_opts, NULL)) >= 0) {
6281 rc = parse_mirror_ids(mirror_ids,
6282 sizeof(mirror_ids) / sizeof(__u16),
6286 "%s: bad mirror ids '%s'.\n",
6293 fprintf(stderr, "%s: options '%s' unrecognized.\n",
6294 argv[0], argv[optind - 1]);
6300 if (argc > optind + 1) {
6301 fprintf(stderr, "%s: too many files.\n", argv[0]);
6305 if (argc == optind) {
6306 fprintf(stderr, "%s: no file name given.\n", argv[0]);
6311 fname = argv[optind];
6312 if (stat(fname, &stbuf) < 0) {
6313 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
6314 argv[0], fname, strerror(errno));
6318 if (!S_ISREG(stbuf.st_mode)) {
6319 fprintf(stderr, "%s: '%s' is not a regular file.\n",
6325 fd = open(fname, O_DIRECT | O_RDWR);
6327 fprintf(stderr, "%s: cannot open '%s': %s.\n",
6328 argv[0], fname, strerror(errno));
6333 /* set the lease on the file */
6334 ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
6336 fprintf(stderr, "%s: cannot alloc id array for ioc: %s.\n",
6337 argv[0], strerror(errno));
6342 ioc->lil_mode = LL_LEASE_WRLCK;
6343 ioc->lil_flags = LL_LEASE_RESYNC;
6344 rc = llapi_lease_get_ext(fd, ioc);
6346 fprintf(stderr, "%s: llapi_lease_get_ext resync failed: %s.\n",
6347 argv[0], strerror(errno));
6351 layout = llapi_layout_get_by_fd(fd, 0);
6352 if (layout == NULL) {
6353 fprintf(stderr, "%s: llapi_layout_get_by_fd failed: %s.\n",
6354 argv[0], strerror(errno));
6359 rc = llapi_layout_flags_get(layout, &flr_state);
6361 fprintf(stderr, "%s: llapi_layout_flags_get failed: %s.\n",
6362 argv[0], strerror(errno));
6367 flr_state &= LCM_FL_FLR_MASK;
6368 if (flr_state != LCM_FL_WRITE_PENDING &&
6369 flr_state != LCM_FL_SYNC_PENDING) {
6370 fprintf(stderr, "%s: file state error: %s.\n",
6371 argv[0], lcm_flags_string(flr_state));
6376 /* get stale component info */
6377 comp_size = llapi_mirror_find_stale(layout, comp_array,
6378 ARRAY_SIZE(comp_array),
6379 mirror_ids, ids_nr);
6380 if (comp_size < 0) {
6386 while (idx < comp_size) {
6392 rc = llapi_lease_check(fd);
6393 if (rc != LL_LEASE_WRLCK) {
6394 fprintf(stderr, "lost lease lock.\n");
6398 mirror_id = comp_array[idx].lrc_mirror_id;
6399 end = comp_array[idx].lrc_end;
6401 /* try to combine adjacent component */
6402 for (i = idx + 1; i < comp_size; i++) {
6403 if (mirror_id != comp_array[i].lrc_mirror_id ||
6404 end != comp_array[i].lrc_start)
6406 end = comp_array[i].lrc_end;
6409 result = llapi_mirror_resync_one(fd, layout, mirror_id,
6410 comp_array[idx].lrc_start,
6413 fprintf(stderr, "llapi_mirror_resync_one: %ld.\n",
6417 } else if (result > 0) {
6420 /* mark synced components */
6421 for (j = idx; j < i; j++)
6422 comp_array[j].lrc_synced = true;
6428 /* prepare ioc for lease put */
6429 ioc->lil_mode = LL_LEASE_UNLCK;
6430 ioc->lil_flags = LL_LEASE_RESYNC_DONE;
6432 for (idx = 0; idx < comp_size; idx++) {
6433 if (comp_array[idx].lrc_synced) {
6434 ioc->lil_ids[ioc->lil_count] = comp_array[idx].lrc_id;
6439 llapi_layout_free(layout);
6441 rc = llapi_lease_get_ext(fd, ioc);
6443 if (rc == 0) /* lost lease lock */
6445 fprintf(stderr, "%s: resync file '%s' failed: %s.\n",
6446 argv[0], fname, strerror(errno));
6461 * lfs_mirror() - Parse and execute lfs mirror commands.
6462 * @argc: The count of lfs mirror command line arguments.
6463 * @argv: Array of strings for lfs mirror command line arguments.
6465 * This function parses lfs mirror commands and performs the
6466 * corresponding functions specified in mirror_cmdlist[].
6468 * Return: 0 on success or an error code on failure.
6470 static int lfs_mirror(int argc, char **argv)
6477 Parser_init("lfs-mirror > ", mirror_cmdlist);
6479 snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
6481 program_invocation_short_name = cmd;
6483 rc = Parser_execarg(argc - 1, argv + 1, mirror_cmdlist);
6485 rc = Parser_commands();
6487 return rc < 0 ? -rc : rc;
6491 * lfs_mirror_list_commands() - List lfs mirror commands.
6492 * @argc: The count of command line arguments.
6493 * @argv: Array of strings for command line arguments.
6495 * This function lists lfs mirror commands defined in mirror_cmdlist[].
6497 * Return: 0 on success.
6499 static int lfs_mirror_list_commands(int argc, char **argv)
6501 char buffer[81] = "";
6503 Parser_list_commands(mirror_cmdlist, buffer, sizeof(buffer),
6509 static int lfs_list_commands(int argc, char **argv)
6511 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
6513 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
6518 int main(int argc, char **argv)
6522 /* Ensure that liblustreapi constructor has run */
6523 if (!liblustreapi_initialized)
6524 fprintf(stderr, "liblustreapi was not properly initialized\n");
6529 Parser_init("lfs > ", cmdlist);
6531 progname = argv[0]; /* Used in error messages */
6533 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
6535 rc = Parser_commands();
6537 return rc < 0 ? -rc : rc;
6540 #ifdef _LUSTRE_IDL_H_
6541 /* Everything we need here should be included by lustreapi.h. */
6542 # error "lfs should not depend on lustre_idl.h"
6543 #endif /* _LUSTRE_IDL_H_ */