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;
1008 * enum mirror_flags - Flags for extending a mirrored file.
1009 * @NO_VERIFY: Indicates not to verify the mirror(s) from victim file(s)
1010 * in case the victim file(s) contains the same data as the
1011 * original mirrored file.
1013 * Flags for extending a mirrored file.
1020 * mirror_create_sanity_check() - Check mirror list.
1021 * @list: A linked list that stores the mirror arguments.
1023 * This function does a sanity check on @list for creating
1026 * Return: 0 on success or a negative error code on failure.
1028 static int mirror_create_sanity_check(struct mirror_args *list)
1031 bool has_m_file = false;
1032 bool has_m_layout = false;
1037 while (list != NULL) {
1038 uint64_t start, end;
1040 if (list->m_file != NULL) {
1042 llapi_layout_free(list->m_layout);
1045 llapi_layout_get_by_path(list->m_file, 0);
1046 if (list->m_layout == NULL) {
1048 "error: %s: file '%s' has no layout\n",
1049 progname, list->m_file);
1053 if (list->m_layout != NULL)
1054 has_m_layout = true;
1056 fprintf(stderr, "error: %s: no mirror layout\n",
1062 rc = llapi_layout_comp_use(list->m_layout,
1063 LLAPI_LAYOUT_COMP_USE_LAST);
1067 rc = llapi_layout_comp_extent_get(list->m_layout, &start, &end);
1071 if (end != LUSTRE_EOF) {
1073 "error: %s: mirror layout doesn't reach eof\n",
1078 list = list->m_next;
1081 if (has_m_file && has_m_layout) {
1082 fprintf(stderr, "error: %s: -f <victim_file> option should not "
1083 "be specified with setstripe options or "
1084 "--parent option\n", progname);
1092 * mirror_create() - Create a mirrored file.
1093 * @fname: The file to be created.
1094 * @mirror_list: A linked list that stores the mirror arguments.
1096 * This function creates a mirrored file @fname with the mirror(s)
1097 * from @mirror_list.
1099 * Return: 0 on success or a negative error code on failure.
1101 static int mirror_create(char *fname, struct mirror_args *mirror_list)
1103 struct llapi_layout *layout = NULL;
1104 struct mirror_args *cur_mirror = NULL;
1105 uint16_t mirror_count = 0;
1109 rc = mirror_create_sanity_check(mirror_list);
1113 cur_mirror = mirror_list;
1114 while (cur_mirror != NULL) {
1115 for (i = 0; i < cur_mirror->m_count; i++) {
1116 rc = llapi_layout_merge(&layout, cur_mirror->m_layout);
1119 fprintf(stderr, "error: %s: "
1120 "merge layout failed: %s\n",
1121 progname, strerror(errno));
1125 mirror_count += cur_mirror->m_count;
1126 cur_mirror = cur_mirror->m_next;
1129 rc = llapi_layout_mirror_count_set(layout, mirror_count);
1132 fprintf(stderr, "error: %s: set mirror count failed: %s\n",
1133 progname, strerror(errno));
1137 rc = lfs_component_create(fname, O_CREAT | O_WRONLY | O_EXCL, 0644,
1145 llapi_layout_free(layout);
1150 * Compare files and check lease on @fd.
1152 * \retval bytes number of bytes are the same
1154 static ssize_t mirror_file_compare(int fd, int fdv)
1156 const size_t buflen = 4 * 1024 * 1024; /* 4M */
1158 ssize_t bytes_done = 0;
1159 ssize_t bytes_read = 0;
1161 buf = malloc(buflen * 2);
1166 if (!llapi_lease_check(fd)) {
1167 bytes_done = -EBUSY;
1171 bytes_read = read(fd, buf, buflen);
1172 if (bytes_read <= 0)
1175 if (bytes_read != read(fdv, buf + buflen, buflen))
1178 /* XXX: should compute the checksum on each buffer and then
1179 * compare checksum to avoid cache collision */
1180 if (memcmp(buf, buf + buflen, bytes_read))
1183 bytes_done += bytes_read;
1191 static int mirror_extend_file(const char *fname, const char *victim_file,
1192 enum mirror_flags mirror_flags)
1197 struct stat stbuf_v;
1201 fd = open(fname, O_RDWR);
1203 error_loc = "open source file";
1208 fdv = open(victim_file, O_RDWR);
1210 error_loc = "open target file";
1215 if (fstat(fd, &stbuf) || fstat(fdv, &stbuf_v)) {
1216 error_loc = "stat source or target file";
1221 if (stbuf.st_dev != stbuf_v.st_dev) {
1222 error_loc = "stat source and target file";
1227 /* mirrors should be of the same size */
1228 if (stbuf.st_size != stbuf_v.st_size) {
1229 error_loc = "file sizes don't match";
1234 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
1236 error_loc = "cannot get lease";
1240 if (!(mirror_flags & NO_VERIFY)) {
1242 /* mirrors should have the same contents */
1243 ret = mirror_file_compare(fd, fdv);
1244 if (ret != stbuf.st_size) {
1245 error_loc = "file busy or contents don't match";
1246 rc = ret < 0 ? ret : -EINVAL;
1251 /* Get rid of caching pages from clients */
1252 rc = llapi_get_data_version(fd, &dv, LL_DV_WR_FLUSH);
1254 error_loc = "cannot get data version";
1258 rc = llapi_get_data_version(fdv, &dv, LL_DV_WR_FLUSH);
1260 error_loc = "cannot get data version";
1265 /* Make sure we keep original atime/mtime values */
1266 rc = migrate_copy_timestamps(fd, fdv);
1268 /* Atomically put lease, swap layouts and close.
1269 * for a migration we need to check data version on file did
1271 rc = llapi_fswap_layouts(fd, fdv, 0, 0, MERGE_LAYOUTS_CLOSE);
1273 error_loc = "cannot swap layout";
1285 (void) unlink(victim_file);
1288 fprintf(stderr, "error: %s: %s: %s: %s\n",
1289 progname, fname, error_loc, strerror(-rc));
1293 static int mirror_extend(char *fname, struct mirror_args *mirror_list,
1294 enum mirror_flags mirror_flags)
1298 rc = mirror_create_sanity_check(mirror_list);
1302 while (mirror_list) {
1303 if (mirror_list->m_file != NULL) {
1304 rc = mirror_extend_file(fname, mirror_list->m_file,
1307 __u32 mirror_count = mirror_list->m_count;
1309 while (mirror_count > 0) {
1310 rc = lfs_migrate(fname,
1311 MIGRATION_NONBLOCK | MIGRATION_MIRROR,
1312 NULL, mirror_list->m_layout);
1322 mirror_list = mirror_list->m_next;
1329 * Parse a string containing an OST index list into an array of integers.
1331 * The input string contains a comma delimited list of individual
1332 * indices and ranges, for example "1,2-4,7". Add the indices into the
1333 * \a osts array and remove duplicates.
1335 * \param[out] osts array to store indices in
1336 * \param[in] size size of \a osts array
1337 * \param[in] offset starting index in \a osts
1338 * \param[in] arg string containing OST index list
1340 * \retval positive number of indices in \a osts
1341 * \retval -EINVAL unable to parse \a arg
1343 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
1347 int slots = size - offset;
1354 end_of_loop = false;
1355 while (!end_of_loop) {
1359 char *endptr = NULL;
1363 ptr = strchrnul(arg, ',');
1365 end_of_loop = *ptr == '\0';
1368 start_index = strtol(arg, &endptr, 0);
1369 if (endptr == arg) /* no data at all */
1371 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
1373 if (start_index < 0)
1376 end_index = start_index;
1377 if (*endptr == '-') {
1378 end_index = strtol(endptr + 1, &endptr, 0);
1379 if (*endptr != '\0')
1381 if (end_index < start_index)
1385 for (i = start_index; i <= end_index && slots > 0; i++) {
1388 /* remove duplicate */
1389 for (j = 0; j < offset; j++) {
1393 if (j == offset) { /* no duplicate */
1398 if (slots == 0 && i < end_index)
1406 if (!end_of_loop && ptr != NULL)
1409 return rc < 0 ? rc : nr;
1412 struct lfs_setstripe_args {
1413 unsigned long long lsa_comp_end;
1414 unsigned long long lsa_stripe_size;
1415 long long lsa_stripe_count;
1416 long long lsa_stripe_off;
1417 __u32 lsa_comp_flags;
1419 unsigned long long lsa_pattern;
1421 char *lsa_pool_name;
1424 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1426 memset(lsa, 0, sizeof(*lsa));
1428 lsa->lsa_stripe_size = LLAPI_LAYOUT_DEFAULT;
1429 lsa->lsa_stripe_count = LLAPI_LAYOUT_DEFAULT;
1430 lsa->lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
1431 lsa->lsa_pattern = LLAPI_LAYOUT_RAID0;
1432 lsa->lsa_pool_name = NULL;
1436 * setstripe_args_init_inherit() - Initialize and inherit stripe options.
1437 * @lsa: Stripe options to be initialized and inherited.
1439 * This function initializes stripe options in @lsa and inherit
1440 * stripe_size, stripe_count and OST pool_name options.
1444 static inline void setstripe_args_init_inherit(struct lfs_setstripe_args *lsa)
1446 unsigned long long stripe_size;
1447 long long stripe_count;
1448 char *pool_name = NULL;
1450 stripe_size = lsa->lsa_stripe_size;
1451 stripe_count = lsa->lsa_stripe_count;
1452 pool_name = lsa->lsa_pool_name;
1454 setstripe_args_init(lsa);
1456 lsa->lsa_stripe_size = stripe_size;
1457 lsa->lsa_stripe_count = stripe_count;
1458 lsa->lsa_pool_name = pool_name;
1461 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1463 return (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT ||
1464 lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ||
1465 lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
1466 lsa->lsa_pattern != LLAPI_LAYOUT_RAID0 ||
1467 lsa->lsa_pool_name != NULL ||
1468 lsa->lsa_comp_end != 0);
1472 * comp_args_to_layout() - Create or extend a composite layout.
1473 * @composite: Pointer to the composite layout.
1474 * @lsa: Stripe options for the new component.
1476 * This function creates or extends a composite layout by adding a new
1477 * component with stripe options from @lsa.
1479 * Return: 0 on success or an error code on failure.
1481 static int comp_args_to_layout(struct llapi_layout **composite,
1482 struct lfs_setstripe_args *lsa)
1484 struct llapi_layout *layout = *composite;
1485 uint64_t prev_end = 0;
1488 if (layout == NULL) {
1489 layout = llapi_layout_alloc();
1490 if (layout == NULL) {
1491 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1495 *composite = layout;
1499 /* Get current component extent, current component
1500 * must be the tail component. */
1501 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1503 fprintf(stderr, "Get comp extent failed. %s\n",
1508 rc = llapi_layout_comp_add(layout);
1510 fprintf(stderr, "Add component failed. %s\n",
1516 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1518 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1519 prev_end, lsa->lsa_comp_end, strerror(errno));
1523 /* Data-on-MDT component setting */
1524 if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
1525 /* In case of Data-on-MDT patterns the only extra option
1526 * applicable is stripe size option. */
1527 if (lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
1528 fprintf(stderr, "Option 'stripe-count' can't be "
1529 "specified with Data-on-MDT component: %lld\n",
1530 lsa->lsa_stripe_count);
1533 if (lsa->lsa_stripe_size != LLAPI_LAYOUT_DEFAULT) {
1534 fprintf(stderr, "Option 'stripe-size' can't be "
1535 "specified with Data-on-MDT component: %llu\n",
1536 lsa->lsa_stripe_size);
1539 if (lsa->lsa_nr_osts != 0) {
1540 fprintf(stderr, "Option 'ost-list' can't be specified "
1541 "with Data-on-MDT component: '%i'\n",
1545 if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
1546 fprintf(stderr, "Option 'stripe-offset' can't be "
1547 "specified with Data-on-MDT component: %lld\n",
1548 lsa->lsa_stripe_off);
1551 if (lsa->lsa_pool_name != 0) {
1552 fprintf(stderr, "Option 'pool' can't be specified "
1553 "with Data-on-MDT component: '%s'\n",
1554 lsa->lsa_pool_name);
1558 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
1560 fprintf(stderr, "Set stripe pattern %#llx failed. %s\n",
1561 lsa->lsa_pattern, strerror(errno));
1564 /* Data-on-MDT component has always single stripe up to end */
1565 lsa->lsa_stripe_size = lsa->lsa_comp_end;
1568 rc = llapi_layout_stripe_size_set(layout, lsa->lsa_stripe_size);
1570 fprintf(stderr, "Set stripe size %llu failed: %s\n",
1571 lsa->lsa_stripe_size, strerror(errno));
1575 rc = llapi_layout_stripe_count_set(layout, lsa->lsa_stripe_count);
1577 fprintf(stderr, "Set stripe count %lld failed: %s\n",
1578 lsa->lsa_stripe_count, strerror(errno));
1582 if (lsa->lsa_pool_name != NULL) {
1583 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1585 fprintf(stderr, "Set pool name: %s failed. %s\n",
1586 lsa->lsa_pool_name, strerror(errno));
1590 rc = llapi_layout_pool_name_set(layout, "");
1592 fprintf(stderr, "Clear pool name failed: %s\n",
1598 if (lsa->lsa_nr_osts > 0) {
1599 if (lsa->lsa_stripe_count > 0 &&
1600 lsa->lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
1601 lsa->lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
1602 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1603 fprintf(stderr, "stripe_count(%lld) != nr_osts(%d)\n",
1604 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1607 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1608 rc = llapi_layout_ost_index_set(layout, i,
1613 } else if (lsa->lsa_stripe_off != LLAPI_LAYOUT_DEFAULT) {
1614 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1617 fprintf(stderr, "Set ost index %d failed. %s\n",
1618 i, strerror(errno));
1625 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1626 * end of the last component in the existing file, and adjust the
1627 * first extent start of the components to be added accordingly. */
1628 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1630 struct llapi_layout *head;
1631 uint64_t start, end, stripe_size, prev_end = 0;
1638 head = llapi_layout_get_by_path(fname, 0);
1640 fprintf(stderr, "Read layout from %s failed. %s\n",
1641 fname, strerror(errno));
1643 } else if (errno == ENODATA) {
1644 /* file without LOVEA, this component-add will be turned
1645 * into a component-create. */
1646 llapi_layout_free(head);
1648 } else if (!llapi_layout_is_composite(head)) {
1649 fprintf(stderr, "'%s' isn't a composite file.\n",
1651 llapi_layout_free(head);
1655 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1657 fprintf(stderr, "Get prev extent failed. %s\n",
1659 llapi_layout_free(head);
1663 llapi_layout_free(head);
1665 /* Make sure we use the first component of the layout to be added. */
1666 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1668 fprintf(stderr, "Move component cursor failed. %s\n",
1673 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1675 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1679 if (start > prev_end || end <= prev_end) {
1680 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1681 "adjacent with the existing file extent end: %lu\n",
1682 start, end, prev_end);
1686 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1688 fprintf(stderr, "Get stripe size failed. %s\n",
1693 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1694 (prev_end & (stripe_size - 1))) {
1695 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1696 stripe_size, prev_end);
1700 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1702 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1703 prev_end, end, strerror(errno));
1710 static inline bool comp_flags_is_neg(__u32 flags)
1712 return flags & LCME_FL_NEG;
1715 static inline void comp_flags_set_neg(__u32 *flags)
1717 *flags |= LCME_FL_NEG;
1720 static inline void comp_flags_clear_neg(__u32 *flags)
1722 *flags &= ~LCME_FL_NEG;
1725 static int comp_str2flags(__u32 *flags, char *string)
1728 __u32 neg_flags = 0;
1734 for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1738 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1739 __u32 comp_flag = comp_flags_table[i].cfn_flag;
1740 const char *comp_name = comp_flags_table[i].cfn_name;
1742 if (strcmp(name, comp_name) == 0) {
1743 *flags |= comp_flag;
1745 } else if (strncmp(name, "^", 1) == 0 &&
1746 strcmp(name + 1, comp_name) == 0) {
1747 neg_flags |= comp_flag;
1752 llapi_printf(LLAPI_MSG_ERROR,
1753 "%s: component flag '%s' not supported\n",
1759 if (*flags == 0 && neg_flags == 0)
1761 /* don't support mixed flags for now */
1762 if (*flags && neg_flags)
1767 comp_flags_set_neg(flags);
1773 static inline bool arg_is_eof(char *arg)
1775 return !strncmp(arg, "-1", strlen("-1")) ||
1776 !strncmp(arg, "EOF", strlen("EOF")) ||
1777 !strncmp(arg, "eof", strlen("eof"));
1781 * lfs_mirror_alloc() - Allocate a mirror argument structure.
1783 * Return: Valid mirror_args pointer on success and
1784 * NULL if memory allocation fails.
1786 static struct mirror_args *lfs_mirror_alloc(void)
1788 struct mirror_args *mirror = NULL;
1791 mirror = calloc(1, sizeof(*mirror));
1802 * lfs_mirror_free() - Free memory allocated for a mirror argument
1804 * @mirror: Previously allocated mirror argument structure by
1805 * lfs_mirror_alloc().
1807 * Free memory allocated for @mirror.
1811 static void lfs_mirror_free(struct mirror_args *mirror)
1813 if (mirror->m_layout != NULL)
1814 llapi_layout_free(mirror->m_layout);
1819 * lfs_mirror_list_free() - Free memory allocated for a mirror list.
1820 * @mirror_list: Previously allocated mirror list.
1822 * Free memory allocated for @mirror_list.
1826 static void lfs_mirror_list_free(struct mirror_args *mirror_list)
1828 struct mirror_args *next_mirror = NULL;
1830 while (mirror_list != NULL) {
1831 next_mirror = mirror_list->m_next;
1832 lfs_mirror_free(mirror_list);
1833 mirror_list = next_mirror;
1845 LFS_COMP_USE_PARENT_OPT,
1846 LFS_COMP_NO_VERIFY_OPT,
1851 static int lfs_setstripe0(int argc, char **argv, enum setstripe_origin opc)
1853 struct lfs_setstripe_args lsa;
1854 struct llapi_stripe_param *param = NULL;
1855 struct find_param migrate_mdt_param = {
1865 char *mdt_idx_arg = NULL;
1866 unsigned long long size_units = 1;
1867 bool migrate_mode = false;
1868 bool migration_block = false;
1869 __u64 migration_flags = 0;
1870 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1871 int comp_del = 0, comp_set = 0;
1874 struct llapi_layout *layout = NULL;
1875 struct llapi_layout **lpp = &layout;
1876 bool mirror_mode = false;
1877 bool has_m_file = false;
1878 __u32 mirror_count = 0;
1879 enum mirror_flags mirror_flags = 0;
1880 struct mirror_args *mirror_list = NULL;
1881 struct mirror_args *new_mirror = NULL;
1882 struct mirror_args *last_mirror = NULL;
1885 struct option long_opts[] = {
1886 /* --block is only valid in migrate mode */
1887 { .val = 'b', .name = "block", .has_arg = no_argument},
1888 { .val = LFS_COMP_ADD_OPT,
1889 .name = "comp-add", .has_arg = no_argument},
1890 { .val = LFS_COMP_ADD_OPT,
1891 .name = "component-add",
1892 .has_arg = no_argument},
1893 { .val = LFS_COMP_DEL_OPT,
1894 .name = "comp-del", .has_arg = no_argument},
1895 { .val = LFS_COMP_DEL_OPT,
1896 .name = "component-del",
1897 .has_arg = no_argument},
1898 { .val = LFS_COMP_FLAGS_OPT,
1899 .name = "comp-flags", .has_arg = required_argument},
1900 { .val = LFS_COMP_FLAGS_OPT,
1901 .name = "component-flags",
1902 .has_arg = required_argument},
1903 { .val = LFS_COMP_SET_OPT,
1904 .name = "comp-set", .has_arg = no_argument},
1905 { .val = LFS_COMP_SET_OPT,
1906 .name = "component-set",
1907 .has_arg = no_argument},
1908 { .val = LFS_COMP_USE_PARENT_OPT,
1909 .name = "parent", .has_arg = no_argument},
1910 { .val = LFS_COMP_NO_VERIFY_OPT,
1911 .name = "no-verify", .has_arg = no_argument},
1912 { .val = 'c', .name = "stripe-count", .has_arg = required_argument},
1913 { .val = 'c', .name = "stripe_count", .has_arg = required_argument},
1914 { .val = 'd', .name = "delete", .has_arg = no_argument},
1915 { .val = 'E', .name = "comp-end", .has_arg = required_argument},
1916 { .val = 'E', .name = "component-end",
1917 .has_arg = required_argument},
1918 { .val = 'f', .name = "file", .has_arg = required_argument },
1919 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1920 { .val = 'i', .name = "stripe-index", .has_arg = required_argument},
1921 { .val = 'i', .name = "stripe_index", .has_arg = required_argument},
1922 { .val = 'I', .name = "comp-id", .has_arg = required_argument},
1923 { .val = 'I', .name = "component-id", .has_arg = required_argument},
1924 { .val = 'L', .name = "layout", .has_arg = required_argument },
1925 { .val = 'm', .name = "mdt", .has_arg = required_argument},
1926 { .val = 'm', .name = "mdt-index", .has_arg = required_argument},
1927 { .val = 'm', .name = "mdt_index", .has_arg = required_argument},
1928 { .val = 'N', .name = "mirror-count", .has_arg = optional_argument},
1929 /* --non-block is only valid in migrate mode */
1930 { .val = 'n', .name = "non-block", .has_arg = no_argument},
1931 { .val = 'o', .name = "ost", .has_arg = required_argument},
1932 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1933 { .val = 'o', .name = "ost-list", .has_arg = required_argument },
1934 { .val = 'o', .name = "ost_list", .has_arg = required_argument },
1936 { .val = 'p', .name = "pool", .has_arg = required_argument },
1937 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1938 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1939 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1940 /* --verbose is only valid in migrate mode */
1941 { .val = 'v', .name = "verbose", .has_arg = no_argument },
1944 setstripe_args_init(&lsa);
1946 migrate_mode = (opc == SO_MIGRATE);
1947 mirror_mode = (opc == SO_MIRROR_CREATE || opc == SO_MIRROR_EXTEND);
1949 snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
1951 while ((c = getopt_long(argc, argv, "bc:dE:f:i:I:m:N::no:p:L:s:S:v",
1952 long_opts, NULL)) >= 0) {
1957 case LFS_COMP_ADD_OPT:
1960 case LFS_COMP_DEL_OPT:
1963 case LFS_COMP_FLAGS_OPT:
1964 result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
1968 case LFS_COMP_SET_OPT:
1971 case LFS_COMP_USE_PARENT_OPT:
1973 fprintf(stderr, "error: %s: --parent must be "
1974 "specified with --mirror-count|-N "
1975 "option\n", progname);
1978 setstripe_args_init(&lsa);
1980 case LFS_COMP_NO_VERIFY_OPT:
1981 mirror_flags |= NO_VERIFY;
1984 if (!migrate_mode) {
1986 "%s %s: -b|--block valid only for migrate command\n",
1990 migration_block = true;
1993 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1996 "%s %s: invalid stripe count '%s'\n",
1997 progname, argv[0], optarg);
2001 if (lsa.lsa_stripe_count == -1)
2002 lsa.lsa_stripe_count = LLAPI_LAYOUT_WIDE;
2005 /* delete the default striping pattern */
2009 if (lsa.lsa_comp_end != 0) {
2010 result = comp_args_to_layout(lpp, &lsa);
2013 "%s %s: invalid layout\n",
2018 setstripe_args_init_inherit(&lsa);
2021 if (arg_is_eof(optarg)) {
2022 lsa.lsa_comp_end = LUSTRE_EOF;
2024 result = llapi_parse_size(optarg,
2029 "%s %s: invalid component end '%s'\n",
2030 progname, argv[0], optarg);
2036 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
2039 "%s %s: invalid stripe offset '%s'\n",
2040 progname, argv[0], optarg);
2043 if (lsa.lsa_stripe_off == -1)
2044 lsa.lsa_stripe_off = LLAPI_LAYOUT_DEFAULT;
2047 comp_id = strtoul(optarg, &end, 0);
2048 if (*end != '\0' || comp_id == 0 ||
2049 comp_id > LCME_ID_MAX) {
2051 "%s %s: invalid component ID '%s'\n",
2052 progname, argv[0], optarg);
2057 if (opc != SO_MIRROR_EXTEND) {
2059 "error: %s: invalid option: %s\n",
2060 progname, argv[optopt + 1]);
2063 if (last_mirror == NULL) {
2064 fprintf(stderr, "error: %s: '-N' must exist "
2065 "in front of '%s'\n",
2066 progname, argv[optopt + 1]);
2070 last_mirror->m_file = optarg;
2071 last_mirror->m_count = 1;
2075 if (strcmp(argv[optind - 1], "mdt") == 0) {
2076 /* Can be only the first component */
2077 if (layout != NULL) {
2079 fprintf(stderr, "error: 'mdt' layout "
2080 "can be only the first one\n");
2083 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
2085 fprintf(stderr, "error: 'mdt' layout "
2086 "size is too big\n");
2089 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
2090 } else if (strcmp(argv[optind - 1], "raid0") != 0) {
2092 fprintf(stderr, "error: layout '%s' is "
2093 "unknown, supported layouts are: "
2094 "'mdt', 'raid0'\n", argv[optind]);
2099 if (!migrate_mode) {
2101 "%s %s: -m|--mdt-index valid only for migrate command\n",
2105 mdt_idx_arg = optarg;
2108 if (!migrate_mode) {
2110 "%s %s: -n|--non-block valid only for migrate command\n",
2114 migration_flags |= MIGRATION_NONBLOCK;
2117 if (opc == SO_SETSTRIPE) {
2118 opc = SO_MIRROR_CREATE;
2122 if (optarg != NULL) {
2123 mirror_count = strtoul(optarg, &end, 0);
2124 if (*end != '\0' || mirror_count == 0) {
2126 "error: %s: bad mirror count: %s\n",
2133 new_mirror = lfs_mirror_alloc();
2134 new_mirror->m_count = mirror_count;
2136 if (mirror_list == NULL)
2137 mirror_list = new_mirror;
2139 if (last_mirror != NULL) {
2140 /* wrap up last mirror */
2141 if (lsa.lsa_comp_end == 0)
2142 lsa.lsa_comp_end = LUSTRE_EOF;
2144 result = comp_args_to_layout(lpp, &lsa);
2146 lfs_mirror_free(new_mirror);
2150 setstripe_args_init_inherit(&lsa);
2152 last_mirror->m_next = new_mirror;
2155 last_mirror = new_mirror;
2156 lpp = &last_mirror->m_layout;
2159 lsa.lsa_nr_osts = parse_targets(osts,
2160 sizeof(osts) / sizeof(__u32),
2161 lsa.lsa_nr_osts, optarg);
2162 if (lsa.lsa_nr_osts < 0) {
2164 "%s %s: invalid OST target(s) '%s'\n",
2165 progname, argv[0], optarg);
2169 lsa.lsa_osts = osts;
2170 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
2171 lsa.lsa_stripe_off = osts[0];
2176 lsa.lsa_pool_name = optarg;
2179 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
2183 "%s %s: invalid stripe size '%s'\n",
2184 progname, argv[0], optarg);
2189 if (!migrate_mode) {
2191 "%s %s: -v|--verbose valid only for migrate command\n",
2195 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
2198 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
2199 progname, argv[0], argv[optind - 1]);
2204 fname = argv[optind];
2206 if (optind == argc) {
2207 fprintf(stderr, "%s %s: FILE must be specified\n",
2212 if (mirror_mode && mirror_count == 0) {
2214 "error: %s: --mirror-count|-N option is required\n",
2221 if (lsa.lsa_comp_end == 0)
2222 lsa.lsa_comp_end = LUSTRE_EOF;
2225 if (lsa.lsa_comp_end != 0) {
2226 result = comp_args_to_layout(lpp, &lsa);
2231 if (mirror_flags & NO_VERIFY) {
2232 if (opc != SO_MIRROR_EXTEND) {
2234 "error: %s: --no-verify is valid only for lfs mirror extend command\n",
2238 } else if (!has_m_file) {
2240 "error: %s: --no-verify must be specified with -f <victim_file> option\n",
2247 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
2248 * altered by user space tool, so we don't need to support the
2249 * --component-set for this moment. */
2250 if (comp_set != 0) {
2251 fprintf(stderr, "%s %s: --component-set not supported\n",
2256 if ((delete + comp_set + comp_del + comp_add) > 1) {
2258 "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
2263 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
2264 lsa.lsa_comp_flags != 0 || layout != NULL)) {
2266 "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
2271 if ((comp_set || comp_del) &&
2272 (setstripe_args_specified(&lsa) || layout != NULL)) {
2274 "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
2279 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
2281 "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
2286 if (comp_add || comp_del) {
2289 result = lstat(fname, &st);
2290 if (result == 0 && S_ISDIR(st.st_mode)) {
2292 "%s setstripe: cannot use --component-add or --component-del for directory\n",
2298 fprintf(stderr, "error: %s: can't use --component-add "
2299 "or --component-del for mirror operation\n",
2306 if (layout == NULL) {
2308 "%s %s: option -E must be specified with --component-add\n",
2313 result = adjust_first_extent(fname, layout);
2314 if (result == -ENODATA)
2316 else if (result != 0)
2320 if (mdt_idx_arg != NULL && optind > 3) {
2322 "%s %s: option -m cannot be used with other options\n",
2327 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
2329 "%s %s: options --non-block and --block are mutually exclusive\n",
2334 if (!comp_del && !comp_set && comp_id != 0) {
2336 "%s %s: option -I can only be used with --component-del\n",
2341 if (mdt_idx_arg != NULL) {
2342 /* initialize migrate mdt parameters */
2343 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
2345 fprintf(stderr, "%s %s: invalid MDT index '%s'\n",
2346 progname, argv[0], mdt_idx_arg);
2349 migrate_mdt_param.fp_migrate = 1;
2350 } else if (layout == NULL) {
2351 /* initialize stripe parameters */
2352 param = calloc(1, offsetof(typeof(*param),
2353 lsp_osts[lsa.lsa_nr_osts]));
2354 if (param == NULL) {
2356 "%s %s: cannot allocate memory for parameters: %s\n",
2357 progname, argv[0], strerror(ENOMEM));
2362 if (lsa.lsa_stripe_size != LLAPI_LAYOUT_DEFAULT)
2363 param->lsp_stripe_size = lsa.lsa_stripe_size;
2364 if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
2365 if (lsa.lsa_stripe_count == LLAPI_LAYOUT_WIDE)
2366 param->lsp_stripe_count = -1;
2368 param->lsp_stripe_count = lsa.lsa_stripe_count;
2370 if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
2371 param->lsp_stripe_offset = -1;
2373 param->lsp_stripe_offset = lsa.lsa_stripe_off;
2374 param->lsp_pool = lsa.lsa_pool_name;
2375 param->lsp_is_specific = false;
2376 if (lsa.lsa_nr_osts > 0) {
2377 if (lsa.lsa_stripe_count > 0 &&
2378 lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
2379 lsa.lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
2380 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
2381 fprintf(stderr, "error: %s: stripe count %lld "
2382 "doesn't match the number of OSTs: %d\n"
2383 , argv[0], lsa.lsa_stripe_count,
2389 param->lsp_is_specific = true;
2390 param->lsp_stripe_count = lsa.lsa_nr_osts;
2391 memcpy(param->lsp_osts, osts,
2392 sizeof(*osts) * lsa.lsa_nr_osts);
2396 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
2397 if (mdt_idx_arg != NULL) {
2398 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
2399 } else if (migrate_mode) {
2400 result = lfs_migrate(fname, migration_flags, param,
2402 } else if (comp_set != 0) {
2403 result = lfs_component_set(fname, comp_id,
2404 lsa.lsa_comp_flags);
2405 } else if (comp_del != 0) {
2406 result = lfs_component_del(fname, comp_id,
2407 lsa.lsa_comp_flags);
2408 } else if (comp_add != 0) {
2409 result = lfs_component_add(fname, layout);
2410 } else if (opc == SO_MIRROR_CREATE) {
2411 result = mirror_create(fname, mirror_list);
2412 } else if (opc == SO_MIRROR_EXTEND) {
2413 result = mirror_extend(fname, mirror_list,
2415 } else if (layout != NULL) {
2416 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
2423 result = llapi_file_open_param(fname,
2432 /* Save the first error encountered. */
2440 llapi_layout_free(layout);
2441 lfs_mirror_list_free(mirror_list);
2446 llapi_layout_free(layout);
2447 lfs_mirror_list_free(mirror_list);
2451 static int lfs_poollist(int argc, char **argv)
2456 return llapi_poollist(argv[1]);
2459 static int set_time(time_t *time, time_t *set, char *str)
2466 else if (str[0] == '-')
2472 t = strtol(str, NULL, 0);
2473 if (*time < t * 24 * 60 * 60) {
2476 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
2480 *set = *time - t * 24 * 60 * 60;
2483 static int name2uid(unsigned int *id, const char *name)
2485 struct passwd *passwd;
2487 passwd = getpwnam(name);
2490 *id = passwd->pw_uid;
2495 static int name2gid(unsigned int *id, const char *name)
2497 struct group *group;
2499 group = getgrnam(name);
2502 *id = group->gr_gid;
2507 static inline int name2projid(unsigned int *id, const char *name)
2512 static int uid2name(char **name, unsigned int id)
2514 struct passwd *passwd;
2516 passwd = getpwuid(id);
2519 *name = passwd->pw_name;
2524 static inline int gid2name(char **name, unsigned int id)
2526 struct group *group;
2528 group = getgrgid(id);
2531 *name = group->gr_name;
2536 static int name2layout(__u32 *layout, char *name)
2538 char *ptr, *layout_name;
2541 for (ptr = name; ; ptr = NULL) {
2542 layout_name = strtok(ptr, ",");
2543 if (layout_name == NULL)
2545 if (strcmp(layout_name, "released") == 0)
2546 *layout |= LOV_PATTERN_F_RELEASED;
2547 else if (strcmp(layout_name, "raid0") == 0)
2548 *layout |= LOV_PATTERN_RAID0;
2549 else if (strcmp(layout_name, "mdt") == 0)
2550 *layout |= LOV_PATTERN_MDT;
2557 static int lfs_find(int argc, char **argv)
2562 struct find_param param = {
2566 struct option long_opts[] = {
2567 { .val = 'A', .name = "atime", .has_arg = required_argument },
2568 { .val = LFS_COMP_COUNT_OPT,
2569 .name = "comp-count", .has_arg = required_argument },
2570 { .val = LFS_COMP_COUNT_OPT,
2571 .name = "component-count",
2572 .has_arg = required_argument },
2573 { .val = LFS_COMP_FLAGS_OPT,
2574 .name = "comp-flags", .has_arg = required_argument },
2575 { .val = LFS_COMP_FLAGS_OPT,
2576 .name = "component-flags",
2577 .has_arg = required_argument },
2578 { .val = LFS_COMP_START_OPT,
2579 .name = "comp-start", .has_arg = required_argument },
2580 { .val = LFS_COMP_START_OPT,
2581 .name = "component-start",
2582 .has_arg = required_argument },
2583 { .val = 'c', .name = "stripe-count", .has_arg = required_argument },
2584 { .val = 'c', .name = "stripe_count", .has_arg = required_argument },
2585 { .val = 'C', .name = "ctime", .has_arg = required_argument },
2586 { .val = 'D', .name = "maxdepth", .has_arg = required_argument },
2587 { .val = 'E', .name = "comp-end", .has_arg = required_argument },
2588 { .val = 'E', .name = "component-end",
2589 .has_arg = required_argument },
2590 { .val = 'g', .name = "gid", .has_arg = required_argument },
2591 { .val = 'G', .name = "group", .has_arg = required_argument },
2592 { .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
2593 { .val = 'i', .name = "stripe-index", .has_arg = required_argument },
2594 { .val = 'i', .name = "stripe_index", .has_arg = required_argument },
2595 /*{"component-id", required_argument, 0, 'I'},*/
2596 { .val = 'L', .name = "layout", .has_arg = required_argument },
2597 { .val = 'm', .name = "mdt", .has_arg = required_argument },
2598 { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
2599 { .val = 'm', .name = "mdt_index", .has_arg = required_argument },
2600 { .val = 'M', .name = "mtime", .has_arg = required_argument },
2601 { .val = 'n', .name = "name", .has_arg = required_argument },
2602 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
2603 { .val = 'O', .name = "obd", .has_arg = required_argument },
2604 { .val = 'O', .name = "ost", .has_arg = required_argument },
2605 /* no short option for pool, p/P already used */
2606 { .val = LFS_POOL_OPT,
2607 .name = "pool", .has_arg = required_argument },
2608 { .val = 'p', .name = "print0", .has_arg = no_argument },
2609 { .val = 'P', .name = "print", .has_arg = no_argument },
2610 { .val = LFS_PROJID_OPT,
2611 .name = "projid", .has_arg = required_argument },
2612 { .val = 's', .name = "size", .has_arg = required_argument },
2613 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
2614 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
2615 { .val = 't', .name = "type", .has_arg = required_argument },
2616 { .val = 'T', .name = "mdt-count", .has_arg = required_argument },
2617 { .val = 'u', .name = "uid", .has_arg = required_argument },
2618 { .val = 'U', .name = "user", .has_arg = required_argument },
2630 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
2631 while ((c = getopt_long_only(argc, argv,
2632 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
2633 long_opts, NULL)) >= 0) {
2638 /* '!' is part of option */
2639 /* when getopt_long_only() finds a string which is not
2640 * an option nor a known option argument it returns 1
2641 * in that case if we already have found pathstart and pathend
2642 * (i.e. we have the list of pathnames),
2643 * the only supported value is "!"
2645 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
2646 if (!isoption && pathend != -1) {
2647 fprintf(stderr, "err: %s: filename|dirname must either "
2648 "precede options or follow options\n",
2653 if (!isoption && pathstart == -1)
2654 pathstart = optind - 1;
2655 if (isoption && pathstart != -1 && pathend == -1)
2656 pathend = optind - 2;
2662 /* unknown; opt is "!" or path component,
2663 * checking done above.
2665 if (strcmp(optarg, "!") == 0)
2669 xtime = ¶m.fp_atime;
2670 xsign = ¶m.fp_asign;
2671 param.fp_exclude_atime = !!neg_opt;
2672 /* no break, this falls through to 'C' for ctime */
2675 xtime = ¶m.fp_ctime;
2676 xsign = ¶m.fp_csign;
2677 param.fp_exclude_ctime = !!neg_opt;
2679 /* no break, this falls through to 'M' for mtime */
2682 xtime = ¶m.fp_mtime;
2683 xsign = ¶m.fp_msign;
2684 param.fp_exclude_mtime = !!neg_opt;
2686 rc = set_time(&t, xtime, optarg);
2687 if (rc == INT_MAX) {
2694 case LFS_COMP_COUNT_OPT:
2695 if (optarg[0] == '+') {
2696 param.fp_comp_count_sign = -1;
2698 } else if (optarg[0] == '-') {
2699 param.fp_comp_count_sign = 1;
2703 param.fp_comp_count = strtoul(optarg, &endptr, 0);
2704 if (*endptr != '\0') {
2705 fprintf(stderr, "error: bad component count "
2709 param.fp_check_comp_count = 1;
2710 param.fp_exclude_comp_count = !!neg_opt;
2712 case LFS_COMP_FLAGS_OPT:
2713 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
2714 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2715 fprintf(stderr, "error: bad component flags "
2719 param.fp_check_comp_flags = 1;
2720 param.fp_exclude_comp_flags = !!neg_opt;
2722 case LFS_COMP_START_OPT:
2723 if (optarg[0] == '+') {
2724 param.fp_comp_start_sign = -1;
2726 } else if (optarg[0] == '-') {
2727 param.fp_comp_start_sign = 1;
2731 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2732 ¶m.fp_comp_start_units, 0);
2734 fprintf(stderr, "error: bad component start "
2738 param.fp_check_comp_start = 1;
2739 param.fp_exclude_comp_start = !!neg_opt;
2742 if (optarg[0] == '+') {
2743 param.fp_stripe_count_sign = -1;
2745 } else if (optarg[0] == '-') {
2746 param.fp_stripe_count_sign = 1;
2750 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2751 if (*endptr != '\0') {
2752 fprintf(stderr,"error: bad stripe_count '%s'\n",
2757 param.fp_check_stripe_count = 1;
2758 param.fp_exclude_stripe_count = !!neg_opt;
2761 param.fp_max_depth = strtol(optarg, 0, 0);
2764 if (optarg[0] == '+') {
2765 param.fp_comp_end_sign = -1;
2767 } else if (optarg[0] == '-') {
2768 param.fp_comp_end_sign = 1;
2772 if (arg_is_eof(optarg)) {
2773 param.fp_comp_end = LUSTRE_EOF;
2774 param.fp_comp_end_units = 1;
2777 rc = llapi_parse_size(optarg,
2779 ¶m.fp_comp_end_units, 0);
2782 fprintf(stderr, "error: bad component end "
2786 param.fp_check_comp_end = 1;
2787 param.fp_exclude_comp_end = !!neg_opt;
2791 rc = name2gid(¶m.fp_gid, optarg);
2793 param.fp_gid = strtoul(optarg, &endptr, 10);
2794 if (*endptr != '\0') {
2795 fprintf(stderr, "Group/GID: %s cannot "
2796 "be found.\n", optarg);
2801 param.fp_exclude_gid = !!neg_opt;
2802 param.fp_check_gid = 1;
2805 param.fp_hash_type = check_hashtype(optarg);
2806 if (param.fp_hash_type == 0) {
2807 fprintf(stderr, "error: bad hash_type '%s'\n",
2812 param.fp_check_hash_type = 1;
2813 param.fp_exclude_hash_type = !!neg_opt;
2816 ret = name2layout(¶m.fp_layout, optarg);
2819 param.fp_exclude_layout = !!neg_opt;
2820 param.fp_check_layout = 1;
2824 rc = name2uid(¶m.fp_uid, optarg);
2826 param.fp_uid = strtoul(optarg, &endptr, 10);
2827 if (*endptr != '\0') {
2828 fprintf(stderr, "User/UID: %s cannot "
2829 "be found.\n", optarg);
2834 param.fp_exclude_uid = !!neg_opt;
2835 param.fp_check_uid = 1;
2838 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2840 "Pool name %s is too long"
2841 " (max is %d)\n", optarg,
2846 /* we do check for empty pool because empty pool
2847 * is used to find V1 lov attributes */
2848 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2849 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2850 param.fp_exclude_pool = !!neg_opt;
2851 param.fp_check_pool = 1;
2854 param.fp_pattern = (char *)optarg;
2855 param.fp_exclude_pattern = !!neg_opt;
2860 char *buf, *token, *next, *p;
2864 buf = strdup(optarg);
2870 param.fp_exclude_obd = !!neg_opt;
2873 while (token && *token) {
2874 token = strchr(token, ',');
2881 param.fp_exclude_mdt = !!neg_opt;
2882 param.fp_num_alloc_mdts += len;
2883 tmp = realloc(param.fp_mdt_uuid,
2884 param.fp_num_alloc_mdts *
2885 sizeof(*param.fp_mdt_uuid));
2891 param.fp_mdt_uuid = tmp;
2893 param.fp_exclude_obd = !!neg_opt;
2894 param.fp_num_alloc_obds += len;
2895 tmp = realloc(param.fp_obd_uuid,
2896 param.fp_num_alloc_obds *
2897 sizeof(*param.fp_obd_uuid));
2903 param.fp_obd_uuid = tmp;
2905 for (token = buf; token && *token; token = next) {
2906 struct obd_uuid *puuid;
2909 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2912 ¶m.fp_obd_uuid[param.fp_num_obds++];
2914 p = strchr(token, ',');
2921 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2926 strncpy(puuid->uuid, token,
2927 sizeof(puuid->uuid));
2935 param.fp_zero_end = 1;
2939 case LFS_PROJID_OPT:
2940 rc = name2projid(¶m.fp_projid, optarg);
2942 param.fp_projid = strtoul(optarg, &endptr, 10);
2943 if (*endptr != '\0') {
2945 "Invalid project ID: %s",
2951 param.fp_exclude_projid = !!neg_opt;
2952 param.fp_check_projid = 1;
2955 if (optarg[0] == '+') {
2956 param.fp_size_sign = -1;
2958 } else if (optarg[0] == '-') {
2959 param.fp_size_sign = 1;
2963 ret = llapi_parse_size(optarg, ¶m.fp_size,
2964 ¶m.fp_size_units, 0);
2966 fprintf(stderr, "error: bad file size '%s'\n",
2970 param.fp_check_size = 1;
2971 param.fp_exclude_size = !!neg_opt;
2974 if (optarg[0] == '+') {
2975 param.fp_stripe_size_sign = -1;
2977 } else if (optarg[0] == '-') {
2978 param.fp_stripe_size_sign = 1;
2982 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2983 ¶m.fp_stripe_size_units, 0);
2985 fprintf(stderr, "error: bad stripe_size '%s'\n",
2989 param.fp_check_stripe_size = 1;
2990 param.fp_exclude_stripe_size = !!neg_opt;
2993 param.fp_exclude_type = !!neg_opt;
2994 switch (optarg[0]) {
2996 param.fp_type = S_IFBLK;
2999 param.fp_type = S_IFCHR;
3002 param.fp_type = S_IFDIR;
3005 param.fp_type = S_IFREG;
3008 param.fp_type = S_IFLNK;
3011 param.fp_type = S_IFIFO;
3014 param.fp_type = S_IFSOCK;
3017 fprintf(stderr, "error: %s: bad type '%s'\n",
3024 if (optarg[0] == '+') {
3025 param.fp_mdt_count_sign = -1;
3027 } else if (optarg[0] == '-') {
3028 param.fp_mdt_count_sign = 1;
3032 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
3033 if (*endptr != '\0') {
3034 fprintf(stderr, "error: bad mdt_count '%s'\n",
3039 param.fp_check_mdt_count = 1;
3040 param.fp_exclude_mdt_count = !!neg_opt;
3048 if (pathstart == -1) {
3049 fprintf(stderr, "error: %s: no filename|pathname\n",
3053 } else if (pathend == -1) {
3059 rc = llapi_find(argv[pathstart], ¶m);
3060 if (rc != 0 && ret == 0)
3062 } while (++pathstart < pathend);
3065 fprintf(stderr, "error: %s failed for %s.\n",
3066 argv[0], argv[optind - 1]);
3068 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
3069 free(param.fp_obd_uuid);
3071 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
3072 free(param.fp_mdt_uuid);
3077 static int lfs_getstripe_internal(int argc, char **argv,
3078 struct find_param *param)
3080 struct option long_opts[] = {
3081 { .val = LFS_COMP_COUNT_OPT,
3082 .name = "comp-count", .has_arg = no_argument },
3083 { .val = LFS_COMP_COUNT_OPT,
3084 .name = "component-count", .has_arg = no_argument },
3085 { .val = LFS_COMP_FLAGS_OPT,
3086 .name = "comp-flags", .has_arg = optional_argument },
3087 { .val = LFS_COMP_FLAGS_OPT,
3088 .name = "component-flags", .has_arg = optional_argument },
3089 { .val = LFS_COMP_START_OPT,
3090 .name = "comp-start", .has_arg = optional_argument },
3091 { .val = LFS_COMP_START_OPT,
3092 .name = "component-start", .has_arg = optional_argument },
3093 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3094 /* This formerly implied "stripe-count", but was explicitly
3095 * made "stripe-count" for consistency with other options,
3096 * and to separate it from "mdt-count" when DNE arrives. */
3097 { .val = 'c', .name = "count", .has_arg = no_argument },
3099 { .val = 'c', .name = "stripe-count", .has_arg = no_argument },
3100 { .val = 'c', .name = "stripe_count", .has_arg = no_argument },
3101 { .val = 'd', .name = "directory", .has_arg = no_argument },
3102 { .val = 'D', .name = "default", .has_arg = no_argument },
3103 { .val = 'E', .name = "comp-end", .has_arg = optional_argument },
3104 { .val = 'E', .name = "component-end",
3105 .has_arg = optional_argument },
3106 { .val = 'F', .name = "fid", .has_arg = no_argument },
3107 { .val = 'g', .name = "generation", .has_arg = no_argument },
3108 /* dirstripe { .val = 'H', .name = "mdt-hash",
3109 * .has_arg = required_argument }, */
3110 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3111 /* This formerly implied "stripe-index", but was explicitly
3112 * made "stripe-index" for consistency with other options,
3113 * and to separate it from "mdt-index" when DNE arrives. */
3114 { .val = 'i', .name = "index", .has_arg = no_argument },
3116 { .val = 'i', .name = "stripe-index", .has_arg = no_argument },
3117 { .val = 'i', .name = "stripe_index", .has_arg = no_argument },
3118 { .val = 'I', .name = "comp-id", .has_arg = optional_argument },
3119 { .val = 'I', .name = "component-id", .has_arg = optional_argument },
3120 { .val = 'L', .name = "layout", .has_arg = no_argument },
3121 { .val = 'm', .name = "mdt", .has_arg = no_argument },
3122 { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
3123 { .val = 'm', .name = "mdt_index", .has_arg = no_argument },
3124 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3125 { .val = 'M', .name = "mdt-index", .has_arg = no_argument },
3126 { .val = 'M', .name = "mdt_index", .has_arg = no_argument },
3128 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3129 /* This formerly implied "stripe-index", but was confusing
3130 * with "file offset" (which will eventually be needed for
3131 * with different layouts by offset), so deprecate it. */
3132 { .val = 'o', .name = "offset", .has_arg = no_argument },
3134 { .val = 'O', .name = "obd", .has_arg = required_argument },
3135 { .val = 'O', .name = "ost", .has_arg = required_argument },
3136 { .val = 'p', .name = "pool", .has_arg = no_argument },
3137 { .val = 'q', .name = "quiet", .has_arg = no_argument },
3138 { .val = 'r', .name = "recursive", .has_arg = no_argument },
3139 { .val = 'R', .name = "raw", .has_arg = no_argument },
3140 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3141 /* This formerly implied "--stripe-size", but was confusing
3142 * with "lfs find --size|-s", which means "file size", so use
3143 * the consistent "--stripe-size|-S" for all commands. */
3144 { .val = 's', .name = "size", .has_arg = no_argument },
3146 { .val = 'S', .name = "stripe-size", .has_arg = no_argument },
3147 { .val = 'S', .name = "stripe_size", .has_arg = no_argument },
3148 /* dirstripe { .val = 'T', .name = "mdt-count",
3149 * .has_arg = required_argument }, */
3150 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3151 { .val = 'y', .name = "yaml", .has_arg = no_argument },
3156 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
3157 long_opts, NULL)) != -1) {
3160 if (strcmp(argv[optind - 1], "--count") == 0)
3161 fprintf(stderr, "warning: '--count' deprecated,"
3162 " use '--stripe-count' instead\n");
3163 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3164 param->fp_verbose |= VERBOSE_COUNT;
3165 param->fp_max_depth = 0;
3168 case LFS_COMP_COUNT_OPT:
3169 param->fp_verbose |= VERBOSE_COMP_COUNT;
3170 param->fp_max_depth = 0;
3172 case LFS_COMP_FLAGS_OPT:
3173 if (optarg != NULL) {
3174 __u32 *flags = ¶m->fp_comp_flags;
3175 rc = comp_str2flags(flags, optarg);
3177 fprintf(stderr, "error: %s bad "
3178 "component flags '%s'.\n",
3182 param->fp_check_comp_flags = 1;
3183 param->fp_exclude_comp_flags =
3184 comp_flags_is_neg(*flags);
3185 comp_flags_clear_neg(flags);
3188 param->fp_verbose |= VERBOSE_COMP_FLAGS;
3189 param->fp_max_depth = 0;
3192 case LFS_COMP_START_OPT:
3193 if (optarg != NULL) {
3195 if (tmp[0] == '+') {
3196 param->fp_comp_start_sign = -1;
3198 } else if (tmp[0] == '-') {
3199 param->fp_comp_start_sign = 1;
3202 rc = llapi_parse_size(tmp,
3203 ¶m->fp_comp_start,
3204 ¶m->fp_comp_start_units, 0);
3206 fprintf(stderr, "error: %s bad "
3207 "component start '%s'.\n",
3211 param->fp_check_comp_start = 1;
3214 param->fp_verbose |= VERBOSE_COMP_START;
3215 param->fp_max_depth = 0;
3219 param->fp_max_depth = 0;
3222 param->fp_get_default_lmv = 1;
3225 if (optarg != NULL) {
3227 if (tmp[0] == '+') {
3228 param->fp_comp_end_sign = -1;
3230 } else if (tmp[0] == '-') {
3231 param->fp_comp_end_sign = 1;
3235 if (arg_is_eof(tmp)) {
3236 param->fp_comp_end = LUSTRE_EOF;
3237 param->fp_comp_end_units = 1;
3240 rc = llapi_parse_size(tmp,
3241 ¶m->fp_comp_end,
3242 ¶m->fp_comp_end_units, 0);
3245 fprintf(stderr, "error: %s bad "
3246 "component end '%s'.\n",
3250 param->fp_check_comp_end = 1;
3252 param->fp_verbose |= VERBOSE_COMP_END;
3253 param->fp_max_depth = 0;
3257 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3258 param->fp_verbose |= VERBOSE_DFID;
3259 param->fp_max_depth = 0;
3263 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3264 param->fp_verbose |= VERBOSE_GENERATION;
3265 param->fp_max_depth = 0;
3268 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3270 fprintf(stderr, "warning: '--offset|-o' deprecated, "
3271 "use '--stripe-index|-i' instead\n");
3274 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
3275 if (strcmp(argv[optind - 1], "--index") == 0)
3276 fprintf(stderr, "warning: '--index' deprecated"
3277 ", use '--stripe-index' instead\n");
3279 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3280 param->fp_verbose |= VERBOSE_OFFSET;
3281 param->fp_max_depth = 0;
3285 if (optarg != NULL) {
3286 param->fp_comp_id = strtoul(optarg, &end, 0);
3287 if (*end != '\0' || param->fp_comp_id == 0 ||
3288 param->fp_comp_id > LCME_ID_MAX) {
3289 fprintf(stderr, "error: %s bad "
3290 "component id '%s'\n",
3294 param->fp_check_comp_id = 1;
3297 param->fp_max_depth = 0;
3298 param->fp_verbose |= VERBOSE_COMP_ID;
3302 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3303 param->fp_verbose |= VERBOSE_LAYOUT;
3304 param->fp_max_depth = 0;
3307 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3309 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3310 fprintf(stderr, "warning: '-M' deprecated"
3311 ", use '-m' instead\n");
3315 if (!(param->fp_verbose & VERBOSE_DETAIL))
3316 param->fp_max_depth = 0;
3317 param->fp_verbose |= VERBOSE_MDTINDEX;
3320 if (param->fp_obd_uuid) {
3322 "error: %s: only one obduuid allowed",
3326 param->fp_obd_uuid = (struct obd_uuid *)optarg;
3329 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3330 param->fp_verbose |= VERBOSE_POOL;
3331 param->fp_max_depth = 0;
3338 param->fp_recursive = 1;
3343 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
3345 fprintf(stderr, "warning: '--size|-s' deprecated, "
3346 "use '--stripe-size|-S' instead\n");
3347 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
3349 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
3350 param->fp_verbose |= VERBOSE_SIZE;
3351 param->fp_max_depth = 0;
3355 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
3368 if (param->fp_recursive)
3369 param->fp_max_depth = -1;
3370 else if (param->fp_verbose & VERBOSE_DETAIL)
3371 param->fp_max_depth = 1;
3373 if (!param->fp_verbose)
3374 param->fp_verbose = VERBOSE_DEFAULT;
3375 if (param->fp_quiet)
3376 param->fp_verbose = VERBOSE_OBJID;
3379 rc = llapi_getstripe(argv[optind], param);
3380 } while (++optind < argc && !rc);
3383 fprintf(stderr, "error: %s failed for %s.\n",
3384 argv[0], argv[optind - 1]);
3388 static int lfs_tgts(int argc, char **argv)
3390 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3391 struct find_param param;
3392 int index = 0, rc=0;
3397 if (argc == 2 && !realpath(argv[1], path)) {
3399 fprintf(stderr, "error: invalid path '%s': %s\n",
3400 argv[1], strerror(-rc));
3404 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
3405 /* Check if we have a mount point */
3406 if (mntdir[0] == '\0')
3409 memset(¶m, 0, sizeof(param));
3410 if (!strcmp(argv[0], "mdts"))
3411 param.fp_get_lmv = 1;
3413 rc = llapi_ostlist(mntdir, ¶m);
3415 fprintf(stderr, "error: %s: failed on %s\n",
3418 if (path[0] != '\0')
3420 memset(mntdir, 0, PATH_MAX);
3426 static int lfs_getstripe(int argc, char **argv)
3428 struct find_param param = { 0 };
3430 param.fp_max_depth = 1;
3431 return lfs_getstripe_internal(argc, argv, ¶m);
3435 static int lfs_getdirstripe(int argc, char **argv)
3437 struct find_param param = { 0 };
3438 struct option long_opts[] = {
3439 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3440 { .val = 'c', .name = "mdt-count", .has_arg = no_argument },
3442 { .val = 'D', .name = "default", .has_arg = no_argument },
3443 { .val = 'H', .name = "mdt-hash", .has_arg = no_argument },
3444 { .val = 'i', .name = "mdt-index", .has_arg = no_argument },
3445 { .val = 'O', .name = "obd", .has_arg = required_argument },
3446 { .val = 'r', .name = "recursive", .has_arg = no_argument },
3447 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3448 { .val = 't', .name = "mdt-hash", .has_arg = no_argument },
3450 { .val = 'T', .name = "mdt-count", .has_arg = no_argument },
3451 { .val = 'y', .name = "yaml", .has_arg = no_argument },
3455 param.fp_get_lmv = 1;
3457 while ((c = getopt_long(argc, argv,
3458 "cDHiO:rtTy", long_opts, NULL)) != -1)
3462 if (param.fp_obd_uuid) {
3464 "error: %s: only one obduuid allowed",
3468 param.fp_obd_uuid = (struct obd_uuid *)optarg;
3470 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3472 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
3473 fprintf(stderr, "warning: '-c' deprecated"
3474 ", use '-T' instead\n");
3478 param.fp_verbose |= VERBOSE_COUNT;
3481 param.fp_verbose |= VERBOSE_OFFSET;
3483 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3487 param.fp_verbose |= VERBOSE_HASH_TYPE;
3490 param.fp_get_default_lmv = 1;
3493 param.fp_recursive = 1;
3506 if (param.fp_recursive)
3507 param.fp_max_depth = -1;
3509 if (!param.fp_verbose)
3510 param.fp_verbose = VERBOSE_DEFAULT;
3513 rc = llapi_getstripe(argv[optind], ¶m);
3514 } while (++optind < argc && !rc);
3517 fprintf(stderr, "error: %s failed for %s.\n",
3518 argv[0], argv[optind - 1]);
3523 static int lfs_setdirstripe(int argc, char **argv)
3527 unsigned int stripe_offset = -1;
3528 unsigned int stripe_count = 1;
3529 enum lmv_hash_type hash_type;
3532 char *stripe_offset_opt = NULL;
3533 char *stripe_count_opt = NULL;
3534 char *stripe_hash_opt = NULL;
3535 char *mode_opt = NULL;
3536 bool default_stripe = false;
3537 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
3538 mode_t previous_mode = 0;
3539 bool delete = false;
3541 struct option long_opts[] = {
3542 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3543 { .val = 'c', .name = "count", .has_arg = required_argument },
3545 { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
3546 { .val = 'd', .name = "delete", .has_arg = no_argument },
3547 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3548 { .val = 'i', .name = "index", .has_arg = required_argument },
3550 { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
3551 { .val = 'm', .name = "mode", .has_arg = required_argument },
3552 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3553 { .val = 't', .name = "hash-type", .has_arg = required_argument },
3554 { .val = 't', .name = "mdt-hash", .has_arg = required_argument },
3556 {"mdt-hash", required_argument, 0, 'H'},
3557 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3558 { .val = 'D', .name = "default_stripe",
3559 .has_arg = no_argument },
3561 { .val = 'D', .name = "default", .has_arg = no_argument },
3564 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
3571 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3572 if (strcmp(argv[optind - 1], "--count") == 0)
3574 "%s %s: warning: '--count' deprecated, use '--mdt-count' instead\n",
3577 stripe_count_opt = optarg;
3581 default_stripe = true;
3584 default_stripe = true;
3587 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3588 if (strcmp(argv[optind - 1], "--index") == 0)
3590 "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
3593 stripe_offset_opt = optarg;
3598 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3602 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3603 if (strcmp(argv[optind - 1], "--hash-type") == 0)
3605 "%s %s: warning: '--hash-type' deprecated, use '--mdt-hash' instead\n",
3608 stripe_hash_opt = optarg;
3611 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
3612 progname, argv[0], argv[optind - 1]);
3617 if (optind == argc) {
3618 fprintf(stderr, "%s %s: DIR must be specified\n",
3623 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
3625 "%s %s: stripe offset and count must be specified\n",
3630 if (stripe_offset_opt != NULL) {
3631 /* get the stripe offset */
3632 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
3635 "%s %s: bad stripe offset '%s'\n",
3636 progname, argv[0], stripe_offset_opt);
3642 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
3644 "%s %s: cannot specify -d with -c or -i options\n",
3653 if (mode_opt != NULL) {
3654 mode = strtoul(mode_opt, &end, 8);
3657 "%s %s: bad MODE '%s'\n",
3658 progname, argv[0], mode_opt);
3661 previous_mode = umask(0);
3664 if (stripe_hash_opt == NULL) {
3665 hash_type = LMV_HASH_TYPE_FNV_1A_64;
3667 hash_type = check_hashtype(stripe_hash_opt);
3668 if (hash_type == 0) {
3669 fprintf(stderr, "%s %s: bad stripe hash type '%s'\n",
3670 progname, argv[0], stripe_hash_opt);
3675 /* get the stripe count */
3676 if (stripe_count_opt != NULL) {
3677 stripe_count = strtoul(stripe_count_opt, &end, 0);
3680 "%s %s: bad stripe count '%s'\n",
3681 progname, argv[0], stripe_count_opt);
3686 dname = argv[optind];
3688 if (default_stripe) {
3689 result = llapi_dir_set_default_lmv_stripe(dname,
3690 stripe_offset, stripe_count,
3693 result = llapi_dir_create_pool(dname, mode,
3695 stripe_count, hash_type,
3701 "%s setdirstripe: cannot create stripe dir '%s': %s\n",
3702 progname, dname, strerror(-result));
3705 dname = argv[++optind];
3706 } while (dname != NULL);
3708 if (mode_opt != NULL)
3709 umask(previous_mode);
3715 static int lfs_rmentry(int argc, char **argv)
3722 fprintf(stderr, "error: %s: missing dirname\n",
3728 dname = argv[index];
3729 while (dname != NULL) {
3730 result = llapi_direntry_remove(dname);
3732 fprintf(stderr, "error: %s: remove dir entry '%s' "
3733 "failed\n", argv[0], dname);
3736 dname = argv[++index];
3741 static int lfs_mv(int argc, char **argv)
3743 struct find_param param = {
3750 struct option long_opts[] = {
3751 { .val = 'M', .name = "mdt-index", .has_arg = required_argument },
3752 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3755 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3758 param.fp_mdt_index = strtoul(optarg, &end, 0);
3760 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3767 param.fp_verbose = VERBOSE_DETAIL;
3771 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3772 argv[0], argv[optind - 1]);
3777 if (param.fp_mdt_index == -1) {
3778 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3782 if (optind >= argc) {
3783 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3787 param.fp_migrate = 1;
3788 rc = llapi_migrate_mdt(argv[optind], ¶m);
3790 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3791 argv[0], argv[optind], param.fp_mdt_index,
3796 static int lfs_osts(int argc, char **argv)
3798 return lfs_tgts(argc, argv);
3801 static int lfs_mdts(int argc, char **argv)
3803 return lfs_tgts(argc, argv);
3806 #define COOK(value) \
3809 while (value > 1024) { \
3817 #define CDF "%11llu"
3818 #define HDF "%8.1f%c"
3823 MNTDF_INODES = 0x0001,
3824 MNTDF_COOKED = 0x0002,
3825 MNTDF_LAZY = 0x0004,
3826 MNTDF_VERBOSE = 0x0008,
3829 static int showdf(char *mntdir, struct obd_statfs *stat,
3830 char *uuid, enum mntdf_flags flags,
3831 char *type, int index, int rc)
3833 long long avail, used, total;
3835 char *suffix = "KMGTPEZY";
3836 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3837 char tbuf[3 * sizeof(__u64)];
3838 char ubuf[3 * sizeof(__u64)];
3839 char abuf[3 * sizeof(__u64)];
3840 char rbuf[3 * sizeof(__u64)];
3847 if (flags & MNTDF_INODES) {
3848 avail = stat->os_ffree;
3849 used = stat->os_files - stat->os_ffree;
3850 total = stat->os_files;
3852 int shift = flags & MNTDF_COOKED ? 0 : 10;
3854 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3855 used = ((stat->os_blocks - stat->os_bfree) *
3856 stat->os_bsize) >> shift;
3857 total = (stat->os_blocks * stat->os_bsize) >> shift;
3860 if ((used + avail) > 0)
3861 ratio = (double)used / (double)(used + avail);
3863 if (flags & MNTDF_COOKED) {
3867 cook_val = (double)total;
3870 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3873 snprintf(tbuf, sizeof(tbuf), CDF, total);
3875 cook_val = (double)used;
3878 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3881 snprintf(ubuf, sizeof(ubuf), CDF, used);
3883 cook_val = (double)avail;
3886 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3889 snprintf(abuf, sizeof(abuf), CDF, avail);
3891 snprintf(tbuf, sizeof(tbuf), CDF, total);
3892 snprintf(ubuf, sizeof(tbuf), CDF, used);
3893 snprintf(abuf, sizeof(tbuf), CDF, avail);
3896 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3897 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3898 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3900 printf("[%s:%d]", type, index);
3902 if (stat->os_state) {
3904 * Each character represents the matching
3907 const char state_names[] = "DRSI";
3912 for (i = 0, state = stat->os_state;
3913 state && i < sizeof(state_names); i++) {
3914 if (!(state & (1 << i)))
3916 printf("%c", state_names[i]);
3924 printf(UUF": inactive device\n", uuid);
3927 printf(UUF": %s\n", uuid, strerror(-rc));
3934 struct ll_stat_type {
3939 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3941 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3942 struct obd_uuid uuid_buf;
3943 char *poolname = NULL;
3944 struct ll_stat_type types[] = {
3945 { .st_op = LL_STATFS_LMV, .st_name = "MDT" },
3946 { .st_op = LL_STATFS_LOV, .st_name = "OST" },
3947 { .st_name = NULL } };
3948 struct ll_stat_type *tp;
3949 __u64 ost_ffree = 0;
3957 poolname = strchr(pool, '.');
3958 if (poolname != NULL) {
3959 if (strncmp(fsname, pool, strlen(fsname))) {
3960 fprintf(stderr, "filesystem name incorrect\n");
3968 fd = open(mntdir, O_RDONLY);
3971 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3976 if (flags & MNTDF_INODES)
3977 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3978 "UUID", "Inodes", "IUsed", "IFree",
3979 "IUse%", "Mounted on");
3981 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3982 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3983 "Used", "Available", "Use%", "Mounted on");
3985 for (tp = types; tp->st_name != NULL; tp++) {
3986 for (index = 0; ; index++) {
3987 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3988 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3989 type = flags & MNTDF_LAZY ?
3990 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3991 rc2 = llapi_obd_fstatfs(fd, type, index,
3992 &stat_buf, &uuid_buf);
3997 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3998 if (!(flags & MNTDF_VERBOSE))
4000 } else if (rc2 < 0 && rc == 0) {
4004 if (poolname && tp->st_op == LL_STATFS_LOV &&
4005 llapi_search_ost(fsname, poolname,
4006 obd_uuid2str(&uuid_buf)) != 1)
4009 /* the llapi_obd_statfs() call may have returned with
4010 * an error, but if it filled in uuid_buf we will at
4011 * lease use that to print out a message for that OBD.
4012 * If we didn't get anything in the uuid_buf, then fill
4013 * it in so that we can print an error message. */
4014 if (uuid_buf.uuid[0] == '\0')
4015 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
4016 "%s%04x", tp->st_name, index);
4017 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
4018 flags, tp->st_name, index, rc2);
4021 if (tp->st_op == LL_STATFS_LMV) {
4022 sum.os_ffree += stat_buf.os_ffree;
4023 sum.os_files += stat_buf.os_files;
4024 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
4025 sum.os_blocks += stat_buf.os_blocks *
4027 sum.os_bfree += stat_buf.os_bfree *
4029 sum.os_bavail += stat_buf.os_bavail *
4031 ost_ffree += stat_buf.os_ffree;
4039 /* If we don't have as many objects free on the OST as inodes
4040 * on the MDS, we reduce the total number of inodes to
4041 * compensate, so that the "inodes in use" number is correct.
4042 * Matches ll_statfs_internal() so the results are consistent. */
4043 if (ost_ffree < sum.os_ffree) {
4044 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
4045 sum.os_ffree = ost_ffree;
4048 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
4054 static int lfs_df(int argc, char **argv)
4056 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
4057 enum mntdf_flags flags = 0;
4058 int c, rc = 0, index = 0;
4059 char fsname[PATH_MAX] = "", *pool_name = NULL;
4060 struct option long_opts[] = {
4061 { .val = 'h', .name = "human-readable",
4062 .has_arg = no_argument },
4063 { .val = 'i', .name = "inodes", .has_arg = no_argument },
4064 { .val = 'l', .name = "lazy", .has_arg = no_argument },
4065 { .val = 'p', .name = "pool", .has_arg = required_argument },
4066 { .val = 'v', .name = "verbose", .has_arg = no_argument },
4069 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
4072 flags |= MNTDF_COOKED;
4075 flags |= MNTDF_INODES;
4078 flags |= MNTDF_LAZY;
4084 flags |= MNTDF_VERBOSE;
4090 if (optind < argc && !realpath(argv[optind], path)) {
4092 fprintf(stderr, "error: invalid path '%s': %s\n",
4093 argv[optind], strerror(-rc));
4097 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
4098 /* Check if we have a mount point */
4099 if (mntdir[0] == '\0')
4102 rc = mntdf(mntdir, fsname, pool_name, flags);
4103 if (rc || path[0] != '\0')
4105 fsname[0] = '\0'; /* avoid matching in next loop */
4106 mntdir[0] = '\0'; /* avoid matching in next loop */
4112 static int lfs_getname(int argc, char **argv)
4114 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
4115 int rc = 0, index = 0, c;
4116 char buf[sizeof(struct obd_uuid)];
4118 while ((c = getopt(argc, argv, "h")) != -1)
4121 if (optind == argc) { /* no paths specified, get all paths. */
4122 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
4123 rc = llapi_getname(mntdir, buf, sizeof(buf));
4126 "cannot get name for `%s': %s\n",
4127 mntdir, strerror(-rc));
4131 printf("%s %s\n", buf, mntdir);
4133 path[0] = fsname[0] = mntdir[0] = 0;
4135 } else { /* paths specified, only attempt to search these. */
4136 for (; optind < argc; optind++) {
4137 rc = llapi_getname(argv[optind], buf, sizeof(buf));
4140 "cannot get name for `%s': %s\n",
4141 argv[optind], strerror(-rc));
4145 printf("%s %s\n", buf, argv[optind]);
4151 static int lfs_check(int argc, char **argv)
4154 char mntdir[PATH_MAX] = {'\0'};
4163 obd_types[0] = obd_type1;
4164 obd_types[1] = obd_type2;
4166 if (strcmp(argv[1], "osts") == 0) {
4167 strcpy(obd_types[0], "osc");
4168 } else if (strcmp(argv[1], "mds") == 0) {
4169 strcpy(obd_types[0], "mdc");
4170 } else if (strcmp(argv[1], "servers") == 0) {
4172 strcpy(obd_types[0], "osc");
4173 strcpy(obd_types[1], "mdc");
4175 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4180 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
4181 if (rc < 0 || mntdir[0] == '\0') {
4182 fprintf(stderr, "No suitable Lustre mount found\n");
4186 rc = llapi_target_check(num_types, obd_types, mntdir);
4188 fprintf(stderr, "error: %s: %s status failed\n",
4195 #ifdef HAVE_SYS_QUOTA_H
4196 #define ARG2INT(nr, str, msg) \
4199 nr = strtol(str, &endp, 0); \
4201 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
4206 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
4208 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
4209 * returns the value or ULONG_MAX on integer overflow or incorrect format
4211 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
4212 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
4213 * 3. empty integer value is interpreted as 0
4215 static unsigned long str2sec(const char* timestr)
4217 const char spec[] = "smhdw";
4218 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
4219 unsigned long val = 0;
4222 if (strpbrk(timestr, spec) == NULL) {
4223 /* no specifiers inside the time string,
4224 should treat it as an integer value */
4225 val = strtoul(timestr, &tail, 10);
4226 return *tail ? ULONG_MAX : val;
4229 /* format string is XXwXXdXXhXXmXXs */
4235 v = strtoul(timestr, &tail, 10);
4236 if (v == ULONG_MAX || *tail == '\0')
4237 /* value too large (ULONG_MAX or more)
4238 or missing specifier */
4241 ptr = strchr(spec, *tail);
4243 /* unknown specifier */
4248 /* check if product will overflow the type */
4249 if (!(v < ULONG_MAX / mult[ind]))
4252 ADD_OVERFLOW(val, mult[ind] * v);
4253 if (val == ULONG_MAX)
4265 #define ARG2ULL(nr, str, def_units) \
4267 unsigned long long limit, units = def_units; \
4270 rc = llapi_parse_size(str, &limit, &units, 1); \
4272 fprintf(stderr, "error: bad limit value %s\n", str); \
4278 static inline int has_times_option(int argc, char **argv)
4282 for (i = 1; i < argc; i++)
4283 if (!strcmp(argv[i], "-t"))
4289 int lfs_setquota_times(int argc, char **argv)
4292 struct if_quotactl qctl;
4293 char *mnt, *obd_type = (char *)qctl.obd_type;
4294 struct obd_dqblk *dqb = &qctl.qc_dqblk;
4295 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
4296 struct option long_opts[] = {
4297 { .val = 'b', .name = "block-grace", .has_arg = required_argument },
4298 { .val = 'g', .name = "group", .has_arg = no_argument },
4299 { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
4300 { .val = 'p', .name = "projid", .has_arg = no_argument },
4301 { .val = 't', .name = "times", .has_arg = no_argument },
4302 { .val = 'u', .name = "user", .has_arg = no_argument },
4306 memset(&qctl, 0, sizeof(qctl));
4307 qctl.qc_cmd = LUSTRE_Q_SETINFO;
4308 qctl.qc_type = ALLQUOTA;
4310 while ((c = getopt_long(argc, argv, "b:gi:ptu",
4311 long_opts, NULL)) != -1) {
4322 if (qctl.qc_type != ALLQUOTA) {
4323 fprintf(stderr, "error: -u/g/p can't be used "
4324 "more than once\n");
4327 qctl.qc_type = qtype;
4330 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
4331 fprintf(stderr, "error: bad block-grace: %s\n",
4335 dqb->dqb_valid |= QIF_BTIME;
4338 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
4339 fprintf(stderr, "error: bad inode-grace: %s\n",
4343 dqb->dqb_valid |= QIF_ITIME;
4345 case 't': /* Yes, of course! */
4347 default: /* getopt prints error message for us when opterr != 0 */
4352 if (qctl.qc_type == ALLQUOTA) {
4353 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
4357 if (optind != argc - 1) {
4358 fprintf(stderr, "error: unexpected parameters encountered\n");
4363 rc = llapi_quotactl(mnt, &qctl);
4366 fprintf(stderr, "%s %s ", obd_type,
4367 obd_uuid2str(&qctl.obd_uuid));
4368 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
4375 #define BSLIMIT (1 << 0)
4376 #define BHLIMIT (1 << 1)
4377 #define ISLIMIT (1 << 2)
4378 #define IHLIMIT (1 << 3)
4380 int lfs_setquota(int argc, char **argv)
4383 struct if_quotactl qctl;
4384 char *mnt, *obd_type = (char *)qctl.obd_type;
4385 struct obd_dqblk *dqb = &qctl.qc_dqblk;
4386 struct option long_opts[] = {
4387 { .val = 'b', .name = "block-softlimit",
4388 .has_arg = required_argument },
4389 { .val = 'B', .name = "block-hardlimit",
4390 .has_arg = required_argument },
4391 { .val = 'g', .name = "group", .has_arg = required_argument },
4392 { .val = 'i', .name = "inode-softlimit",
4393 .has_arg = required_argument },
4394 { .val = 'I', .name = "inode-hardlimit",
4395 .has_arg = required_argument },
4396 { .val = 'p', .name = "projid", .has_arg = required_argument },
4397 { .val = 'u', .name = "user", .has_arg = required_argument },
4399 unsigned limit_mask = 0;
4403 if (has_times_option(argc, argv))
4404 return lfs_setquota_times(argc, argv);
4406 memset(&qctl, 0, sizeof(qctl));
4407 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
4408 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
4409 * so it can be used as a marker that qc_type
4410 * isn't reinitialized from command line */
4412 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
4413 long_opts, NULL)) != -1) {
4417 rc = name2uid(&qctl.qc_id, optarg);
4421 rc = name2gid(&qctl.qc_id, optarg);
4425 rc = name2projid(&qctl.qc_id, optarg);
4427 if (qctl.qc_type != ALLQUOTA) {
4428 fprintf(stderr, "error: -u and -g can't be used"
4429 " more than once\n");
4432 qctl.qc_type = qtype;
4434 qctl.qc_id = strtoul(optarg, &endptr, 10);
4435 if (*endptr != '\0') {
4436 fprintf(stderr, "error: can't find id "
4437 "for name %s\n", optarg);
4443 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
4444 dqb->dqb_bsoftlimit >>= 10;
4445 limit_mask |= BSLIMIT;
4446 if (dqb->dqb_bsoftlimit &&
4447 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
4448 fprintf(stderr, "warning: block softlimit is "
4449 "smaller than the miminal qunit size, "
4450 "please see the help of setquota or "
4451 "Lustre manual for details.\n");
4454 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
4455 dqb->dqb_bhardlimit >>= 10;
4456 limit_mask |= BHLIMIT;
4457 if (dqb->dqb_bhardlimit &&
4458 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
4459 fprintf(stderr, "warning: block hardlimit is "
4460 "smaller than the miminal qunit size, "
4461 "please see the help of setquota or "
4462 "Lustre manual for details.\n");
4465 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
4466 limit_mask |= ISLIMIT;
4467 if (dqb->dqb_isoftlimit &&
4468 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
4469 fprintf(stderr, "warning: inode softlimit is "
4470 "smaller than the miminal qunit size, "
4471 "please see the help of setquota or "
4472 "Lustre manual for details.\n");
4475 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
4476 limit_mask |= IHLIMIT;
4477 if (dqb->dqb_ihardlimit &&
4478 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
4479 fprintf(stderr, "warning: inode hardlimit is "
4480 "smaller than the miminal qunit size, "
4481 "please see the help of setquota or "
4482 "Lustre manual for details.\n");
4484 default: /* getopt prints error message for us when opterr != 0 */
4489 if (qctl.qc_type == ALLQUOTA) {
4490 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
4494 if (limit_mask == 0) {
4495 fprintf(stderr, "error: at least one limit must be specified\n");
4499 if (optind != argc - 1) {
4500 fprintf(stderr, "error: unexpected parameters encountered\n");
4506 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
4507 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
4508 /* sigh, we can't just set blimits/ilimits */
4509 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
4510 .qc_type = qctl.qc_type,
4511 .qc_id = qctl.qc_id};
4513 rc = llapi_quotactl(mnt, &tmp_qctl);
4515 fprintf(stderr, "error: setquota failed while retrieving"
4516 " current quota settings (%s)\n",
4521 if (!(limit_mask & BHLIMIT))
4522 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
4523 if (!(limit_mask & BSLIMIT))
4524 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
4525 if (!(limit_mask & IHLIMIT))
4526 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
4527 if (!(limit_mask & ISLIMIT))
4528 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
4530 /* Keep grace times if we have got no softlimit arguments */
4531 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
4532 dqb->dqb_valid |= QIF_BTIME;
4533 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
4536 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
4537 dqb->dqb_valid |= QIF_ITIME;
4538 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
4542 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
4543 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
4545 rc = llapi_quotactl(mnt, &qctl);
4548 fprintf(stderr, "%s %s ", obd_type,
4549 obd_uuid2str(&qctl.obd_uuid));
4550 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
4557 /* Converts seconds value into format string
4558 * result is returned in buf
4560 * 1. result is in descenting order: 1w2d3h4m5s
4561 * 2. zero fields are not filled (except for p. 3): 5d1s
4562 * 3. zero seconds value is presented as "0s"
4564 static char * __sec2str(time_t seconds, char *buf)
4566 const char spec[] = "smhdw";
4567 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
4572 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
4573 c = seconds / mult[i];
4575 if (c > 0 || (i == 0 && buf == tail))
4576 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
4584 static void sec2str(time_t seconds, char *buf, int rc)
4591 tail = __sec2str(seconds, tail);
4593 if (rc && tail - buf < 39) {
4599 static void diff2str(time_t seconds, char *buf, time_t now)
4605 if (seconds <= now) {
4606 strcpy(buf, "none");
4609 __sec2str(seconds - now, buf);
4612 static void print_quota_title(char *name, struct if_quotactl *qctl,
4613 bool human_readable)
4615 printf("Disk quotas for %s %s (%cid %u):\n",
4616 qtype_name(qctl->qc_type), name,
4617 *qtype_name(qctl->qc_type), qctl->qc_id);
4618 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
4619 "Filesystem", human_readable ? "used" : "kbytes",
4620 "quota", "limit", "grace",
4621 "files", "quota", "limit", "grace");
4624 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
4627 snprintf(buf, buflen, "%ju", (uintmax_t)num);
4630 snprintf(buf, buflen, "%5.4gP",
4631 (double)num / ((__u64)1 << 40));
4633 snprintf(buf, buflen, "%5.4gT",
4634 (double)num / (1 << 30));
4636 snprintf(buf, buflen, "%5.4gG",
4637 (double)num / (1 << 20));
4639 snprintf(buf, buflen, "%5.4gM",
4640 (double)num / (1 << 10));
4642 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
4646 #define STRBUF_LEN 32
4647 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
4654 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
4655 int bover = 0, iover = 0;
4656 struct obd_dqblk *dqb = &qctl->qc_dqblk;
4657 char numbuf[3][STRBUF_LEN];
4659 char strbuf[STRBUF_LEN];
4661 if (dqb->dqb_bhardlimit &&
4662 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
4664 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
4665 if (dqb->dqb_btime > now) {
4672 if (dqb->dqb_ihardlimit &&
4673 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
4675 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
4676 if (dqb->dqb_itime > now) {
4684 if (strlen(mnt) > 15)
4685 printf("%s\n%15s", mnt, "");
4687 printf("%15s", mnt);
4690 diff2str(dqb->dqb_btime, timebuf, now);
4692 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
4693 strbuf, sizeof(strbuf), h);
4694 if (rc == -EREMOTEIO)
4695 sprintf(numbuf[0], "%s*", strbuf);
4697 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
4698 "%s" : "[%s]", strbuf);
4700 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
4701 if (type == QC_GENERAL)
4702 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4703 "%s" : "[%s]", strbuf);
4705 sprintf(numbuf[1], "%s", "-");
4707 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4708 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4709 "%s" : "[%s]", strbuf);
4711 printf(" %7s%c %6s %7s %7s",
4712 numbuf[0], bover ? '*' : ' ', numbuf[1],
4713 numbuf[2], bover > 1 ? timebuf : "-");
4716 diff2str(dqb->dqb_itime, timebuf, now);
4718 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4719 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4721 if (type == QC_GENERAL)
4722 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4724 (uintmax_t)dqb->dqb_isoftlimit);
4726 sprintf(numbuf[1], "%s", "-");
4728 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4729 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4731 if (type != QC_OSTIDX)
4732 printf(" %7s%c %6s %7s %7s",
4733 numbuf[0], iover ? '*' : ' ', numbuf[1],
4734 numbuf[2], iover > 1 ? timebuf : "-");
4736 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4739 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4740 qctl->qc_cmd == Q_GETOINFO) {
4744 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4745 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4746 printf("Block grace time: %s; Inode grace time: %s\n",
4747 bgtimebuf, igtimebuf);
4751 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4752 bool h, __u64 *total)
4754 int rc = 0, rc1 = 0, count = 0;
4755 __u32 valid = qctl->qc_valid;
4757 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4759 fprintf(stderr, "can not get %s count: %s\n",
4760 is_mdt ? "mdt": "ost", strerror(-rc));
4764 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4765 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4766 rc = llapi_quotactl(mnt, qctl);
4768 /* It is remote client case. */
4769 if (rc == -EOPNOTSUPP) {
4776 fprintf(stderr, "quotactl %s%d failed.\n",
4777 is_mdt ? "mdt": "ost", qctl->qc_idx);
4781 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4782 qctl->qc_valid, 0, h);
4783 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4784 qctl->qc_dqblk.dqb_bhardlimit;
4787 qctl->qc_valid = valid;
4791 static int lfs_quota(int argc, char **argv)
4794 char *mnt, *name = NULL;
4795 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4796 .qc_type = ALLQUOTA };
4797 char *obd_type = (char *)qctl.obd_type;
4798 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4799 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4800 verbose = 0, pass = 0, quiet = 0, inacc;
4802 __u32 valid = QC_GENERAL, idx = 0;
4803 __u64 total_ialloc = 0, total_balloc = 0;
4804 bool human_readable = false;
4807 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4818 if (qctl.qc_type != ALLQUOTA) {
4819 fprintf(stderr, "error: use either -u or -g\n");
4822 qctl.qc_type = qtype;
4825 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4828 valid = qctl.qc_valid = QC_UUID;
4829 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4832 valid = qctl.qc_valid = QC_MDTIDX;
4833 idx = qctl.qc_idx = atoi(optarg);
4836 valid = qctl.qc_valid = QC_OSTIDX;
4837 idx = qctl.qc_idx = atoi(optarg);
4846 human_readable = true;
4849 fprintf(stderr, "error: %s: option '-%c' "
4850 "unrecognized\n", argv[0], c);
4855 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4856 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4857 optind == argc - 1) {
4859 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4860 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4861 qctl.qc_valid = valid;
4863 qctl.qc_type = pass;
4864 switch (qctl.qc_type) {
4866 qctl.qc_id = geteuid();
4867 rc = uid2name(&name, qctl.qc_id);
4870 qctl.qc_id = getegid();
4871 rc = gid2name(&name, qctl.qc_id);
4881 /* lfs quota -u username /path/to/lustre/mount */
4882 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4883 /* options should be followed by u/g-name and mntpoint */
4884 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4885 fprintf(stderr, "error: missing quota argument(s)\n");
4889 name = argv[optind++];
4890 switch (qctl.qc_type) {
4892 rc = name2uid(&qctl.qc_id, name);
4895 rc = name2gid(&qctl.qc_id, name);
4898 rc = name2projid(&qctl.qc_id, name);
4905 qctl.qc_id = strtoul(name, &endptr, 10);
4906 if (*endptr != '\0') {
4907 fprintf(stderr, "error: can't find id for name: %s\n",
4912 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4913 fprintf(stderr, "error: missing quota info argument(s)\n");
4918 rc1 = llapi_quotactl(mnt, &qctl);
4922 fprintf(stderr, "%s quotas are not enabled.\n",
4923 qtype_name(qctl.qc_type));
4926 fprintf(stderr, "Permission denied.\n");
4929 /* We already got error message. */
4932 fprintf(stderr, "Unexpected quotactl error: %s\n",
4937 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4938 print_quota_title(name, &qctl, human_readable);
4940 if (rc1 && *obd_type)
4941 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4943 if (qctl.qc_valid != QC_GENERAL)
4946 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4947 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4948 (QIF_LIMITS|QIF_USAGE));
4950 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4952 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4954 char strbuf[STRBUF_LEN];
4956 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4958 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4960 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4962 printf("Total allocated inode limit: %ju, total "
4963 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4967 if (rc1 || rc2 || rc3 || inacc)
4968 printf("Some errors happened when getting quota info. "
4969 "Some devices may be not working or deactivated. "
4970 "The data in \"[]\" is inaccurate.\n");
4973 if (pass > 0 && pass < LL_MAXQUOTAS)
4978 #endif /* HAVE_SYS_QUOTA_H! */
4980 static int flushctx_ioctl(char *mp)
4984 fd = open(mp, O_RDONLY);
4986 fprintf(stderr, "flushctx: error open %s: %s\n",
4987 mp, strerror(errno));
4991 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4993 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4994 mp, strerror(errno));
5000 static int lfs_flushctx(int argc, char **argv)
5002 int kdestroy = 0, c;
5003 char mntdir[PATH_MAX] = {'\0'};
5007 while ((c = getopt(argc, argv, "k")) != -1) {
5013 fprintf(stderr, "error: %s: option '-%c' "
5014 "unrecognized\n", argv[0], c);
5020 if ((rc = system("kdestroy > /dev/null")) != 0) {
5021 rc = WEXITSTATUS(rc);
5022 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
5026 if (optind >= argc) {
5027 /* flush for all mounted lustre fs. */
5028 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
5029 /* Check if we have a mount point */
5030 if (mntdir[0] == '\0')
5033 if (flushctx_ioctl(mntdir))
5036 mntdir[0] = '\0'; /* avoid matching in next loop */
5039 /* flush fs as specified */
5040 while (optind < argc) {
5041 if (flushctx_ioctl(argv[optind++]))
5048 static int lfs_cp(int argc, char **argv)
5050 fprintf(stderr, "remote client copy file(s).\n"
5051 "obsolete, does not support it anymore.\n");
5055 static int lfs_ls(int argc, char **argv)
5057 fprintf(stderr, "remote client lists directory contents.\n"
5058 "obsolete, does not support it anymore.\n");
5062 static int lfs_changelog(int argc, char **argv)
5064 void *changelog_priv;
5065 struct changelog_rec *rec;
5066 long long startrec = 0, endrec = 0;
5068 struct option long_opts[] = {
5069 { .val = 'f', .name = "follow", .has_arg = no_argument },
5071 char short_opts[] = "f";
5074 while ((rc = getopt_long(argc, argv, short_opts,
5075 long_opts, NULL)) != -1) {
5083 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5084 argv[0], argv[optind - 1]);
5091 mdd = argv[optind++];
5093 startrec = strtoll(argv[optind++], NULL, 10);
5095 endrec = strtoll(argv[optind++], NULL, 10);
5097 rc = llapi_changelog_start(&changelog_priv,
5098 CHANGELOG_FLAG_BLOCK |
5099 CHANGELOG_FLAG_JOBID |
5100 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
5103 fprintf(stderr, "Can't start changelog: %s\n",
5104 strerror(errno = -rc));
5108 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
5112 if (endrec && rec->cr_index > endrec) {
5113 llapi_changelog_free(&rec);
5116 if (rec->cr_index < startrec) {
5117 llapi_changelog_free(&rec);
5121 secs = rec->cr_time >> 30;
5122 gmtime_r(&secs, &ts);
5123 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
5124 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
5125 changelog_type2str(rec->cr_type),
5126 ts.tm_hour, ts.tm_min, ts.tm_sec,
5127 (int)(rec->cr_time & ((1 << 30) - 1)),
5128 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
5129 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
5131 if (rec->cr_flags & CLF_JOBID) {
5132 struct changelog_ext_jobid *jid =
5133 changelog_rec_jobid(rec);
5135 if (jid->cr_jobid[0] != '\0')
5136 printf(" j=%s", jid->cr_jobid);
5139 if (rec->cr_namelen)
5140 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
5141 rec->cr_namelen, changelog_rec_name(rec));
5143 if (rec->cr_flags & CLF_RENAME) {
5144 struct changelog_ext_rename *rnm =
5145 changelog_rec_rename(rec);
5147 if (!fid_is_zero(&rnm->cr_sfid))
5148 printf(" s="DFID" sp="DFID" %.*s",
5149 PFID(&rnm->cr_sfid),
5150 PFID(&rnm->cr_spfid),
5151 (int)changelog_rec_snamelen(rec),
5152 changelog_rec_sname(rec));
5156 llapi_changelog_free(&rec);
5159 llapi_changelog_fini(&changelog_priv);
5162 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
5164 return (rc == 1 ? 0 : rc);
5167 static int lfs_changelog_clear(int argc, char **argv)
5175 endrec = strtoll(argv[3], NULL, 10);
5177 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
5180 fprintf(stderr, "%s: record out of range: %llu\n",
5182 else if (rc == -ENOENT)
5183 fprintf(stderr, "%s: no changelog user: %s\n",
5186 fprintf(stderr, "%s error: %s\n", argv[0],
5195 static int lfs_fid2path(int argc, char **argv)
5197 struct option long_opts[] = {
5198 { .val = 'c', .name = "cur", .has_arg = no_argument },
5199 { .val = 'l', .name = "link", .has_arg = required_argument },
5200 { .val = 'r', .name = "rec", .has_arg = required_argument },
5202 char short_opts[] = "cl:r:";
5203 char *device, *fid, *path;
5204 long long recno = -1;
5210 while ((rc = getopt_long(argc, argv, short_opts,
5211 long_opts, NULL)) != -1) {
5217 linkno = strtol(optarg, NULL, 10);
5220 recno = strtoll(optarg, NULL, 10);
5225 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5226 argv[0], argv[optind - 1]);
5234 device = argv[optind++];
5235 path = calloc(1, PATH_MAX);
5237 fprintf(stderr, "error: Not enough memory\n");
5242 while (optind < argc) {
5243 fid = argv[optind++];
5245 lnktmp = (linkno >= 0) ? linkno : 0;
5247 int oldtmp = lnktmp;
5248 long long rectmp = recno;
5250 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
5253 fprintf(stderr, "%s: error on FID %s: %s\n",
5254 argv[0], fid, strerror(errno = -rc2));
5261 fprintf(stdout, "%lld ", rectmp);
5262 if (device[0] == '/') {
5263 fprintf(stdout, "%s", device);
5264 if (device[strlen(device) - 1] != '/')
5265 fprintf(stdout, "/");
5266 } else if (path[0] == '\0') {
5267 fprintf(stdout, "/");
5269 fprintf(stdout, "%s\n", path);
5272 /* specified linkno */
5274 if (oldtmp == lnktmp)
5284 static int lfs_path2fid(int argc, char **argv)
5286 struct option long_opts[] = {
5287 { .val = 'p', .name = "parents", .has_arg = no_argument },
5290 const char short_opts[] = "p";
5291 const char *sep = "";
5294 bool show_parents = false;
5296 while ((rc = getopt_long(argc, argv, short_opts,
5297 long_opts, NULL)) != -1) {
5300 show_parents = true;
5303 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5304 argv[0], argv[optind - 1]);
5309 if (optind > argc - 1)
5311 else if (optind < argc - 1)
5315 for (path = argv + optind; *path != NULL; path++) {
5317 if (!show_parents) {
5318 err = llapi_path2fid(*path, &fid);
5320 printf("%s%s"DFID"\n",
5321 *sep != '\0' ? *path : "", sep,
5324 char name[NAME_MAX + 1];
5325 unsigned int linkno = 0;
5327 while ((err = llapi_path2parent(*path, linkno, &fid,
5328 name, sizeof(name))) == 0) {
5329 if (*sep != '\0' && linkno == 0)
5330 printf("%s%s", *path, sep);
5332 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
5337 /* err == -ENODATA is end-of-loop */
5338 if (linkno > 0 && err == -ENODATA) {
5345 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
5346 argv[0], show_parents ? "parent " : "", *path,
5358 static int lfs_data_version(int argc, char **argv)
5365 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
5370 while ((c = getopt(argc, argv, "nrw")) != -1) {
5373 data_version_flags = 0;
5376 data_version_flags |= LL_DV_RD_FLUSH;
5379 data_version_flags |= LL_DV_WR_FLUSH;
5388 path = argv[optind];
5389 fd = open(path, O_RDONLY);
5391 err(errno, "cannot open file %s", path);
5393 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
5395 err(errno, "cannot get version for %s", path);
5397 printf("%ju" "\n", (uintmax_t)data_version);
5403 static int lfs_hsm_state(int argc, char **argv)
5408 struct hsm_user_state hus;
5416 rc = llapi_hsm_state_get(path, &hus);
5418 fprintf(stderr, "can't get hsm state for %s: %s\n",
5419 path, strerror(errno = -rc));
5423 /* Display path name and status flags */
5424 printf("%s: (0x%08x)", path, hus.hus_states);
5426 if (hus.hus_states & HS_RELEASED)
5427 printf(" released");
5428 if (hus.hus_states & HS_EXISTS)
5430 if (hus.hus_states & HS_DIRTY)
5432 if (hus.hus_states & HS_ARCHIVED)
5433 printf(" archived");
5434 /* Display user-settable flags */
5435 if (hus.hus_states & HS_NORELEASE)
5436 printf(" never_release");
5437 if (hus.hus_states & HS_NOARCHIVE)
5438 printf(" never_archive");
5439 if (hus.hus_states & HS_LOST)
5440 printf(" lost_from_hsm");
5442 if (hus.hus_archive_id != 0)
5443 printf(", archive_id:%d", hus.hus_archive_id);
5446 } while (++i < argc);
5451 #define LFS_HSM_SET 0
5452 #define LFS_HSM_CLEAR 1
5455 * Generic function to set or clear HSM flags.
5456 * Used by hsm_set and hsm_clear.
5458 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
5460 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
5462 struct option long_opts[] = {
5463 { .val = 'A', .name = "archived", .has_arg = no_argument },
5464 { .val = 'a', .name = "noarchive", .has_arg = no_argument },
5465 { .val = 'd', .name = "dirty", .has_arg = no_argument },
5466 { .val = 'e', .name = "exists", .has_arg = no_argument },
5467 { .val = 'l', .name = "lost", .has_arg = no_argument },
5468 { .val = 'r', .name = "norelease", .has_arg = no_argument },
5470 char short_opts[] = "lraAde";
5478 while ((c = getopt_long(argc, argv, short_opts,
5479 long_opts, NULL)) != -1) {
5485 mask |= HS_NOARCHIVE;
5488 mask |= HS_ARCHIVED;
5491 mask |= HS_NORELEASE;
5502 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5503 argv[0], argv[optind - 1]);
5508 /* User should have specified a flag */
5512 while (optind < argc) {
5514 path = argv[optind];
5516 /* If mode == 0, this means we apply the mask. */
5517 if (mode == LFS_HSM_SET)
5518 rc = llapi_hsm_state_set(path, mask, 0, 0);
5520 rc = llapi_hsm_state_set(path, 0, mask, 0);
5523 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
5524 path, strerror(errno = -rc));
5533 static int lfs_hsm_action(int argc, char **argv)
5538 struct hsm_current_action hca;
5539 struct hsm_extent he;
5540 enum hsm_user_action hua;
5541 enum hsm_progress_states hps;
5549 rc = llapi_hsm_current_action(path, &hca);
5551 fprintf(stderr, "can't get hsm action for %s: %s\n",
5552 path, strerror(errno = -rc));
5555 he = hca.hca_location;
5556 hua = hca.hca_action;
5557 hps = hca.hca_state;
5559 printf("%s: %s", path, hsm_user_action2name(hua));
5561 /* Skip file without action */
5562 if (hca.hca_action == HUA_NONE) {
5567 printf(" %s ", hsm_progress_state2name(hps));
5569 if ((hps == HPS_RUNNING) &&
5570 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
5571 printf("(%llu bytes moved)\n",
5572 (unsigned long long)he.length);
5573 else if ((he.offset + he.length) == LUSTRE_EOF)
5574 printf("(from %llu to EOF)\n",
5575 (unsigned long long)he.offset);
5577 printf("(from %llu to %llu)\n",
5578 (unsigned long long)he.offset,
5579 (unsigned long long)(he.offset + he.length));
5581 } while (++i < argc);
5586 static int lfs_hsm_set(int argc, char **argv)
5588 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
5591 static int lfs_hsm_clear(int argc, char **argv)
5593 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
5597 * Check file state and return its fid, to be used by lfs_hsm_request().
5599 * \param[in] file Path to file to check
5600 * \param[in,out] fid Pointer to allocated lu_fid struct.
5601 * \param[in,out] last_dev Pointer to last device id used.
5603 * \return 0 on success.
5605 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
5611 rc = lstat(file, &st);
5613 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
5616 /* Checking for regular file as archiving as posix copytool
5617 * rejects archiving files other than regular files
5619 if (!S_ISREG(st.st_mode)) {
5620 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
5623 /* A request should be ... */
5624 if (*last_dev != st.st_dev && *last_dev != 0) {
5625 fprintf(stderr, "All files should be "
5626 "on the same filesystem: %s\n", file);
5629 *last_dev = st.st_dev;
5631 rc = llapi_path2fid(file, fid);
5633 fprintf(stderr, "Cannot read FID of %s: %s\n",
5634 file, strerror(-rc));
5640 /* Fill an HSM HUR item with a given file name.
5642 * If mntpath is set, then the filename is actually a FID, and no
5643 * lookup on the filesystem will be performed.
5645 * \param[in] hur the user request to fill
5646 * \param[in] idx index of the item inside the HUR to fill
5647 * \param[in] mntpath mountpoint of Lustre
5648 * \param[in] fname filename (if mtnpath is NULL)
5649 * or FID (if mntpath is set)
5650 * \param[in] last_dev pointer to last device id used
5652 * \retval 0 on success
5653 * \retval CMD_HELP or a negative errno on error
5655 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
5656 const char *mntpath, const char *fname,
5659 struct hsm_user_item *hui = &hur->hur_user_item[idx];
5662 hui->hui_extent.length = -1;
5664 if (mntpath != NULL) {
5667 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
5671 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
5676 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
5680 hur->hur_request.hr_itemcount++;
5685 static int lfs_hsm_request(int argc, char **argv, int action)
5687 struct option long_opts[] = {
5688 { .val = 'a', .name = "archive", .has_arg = required_argument },
5689 { .val = 'D', .name = "data", .has_arg = required_argument },
5690 { .val = 'l', .name = "filelist", .has_arg = required_argument },
5691 { .val = 'm', .name = "mntpath", .has_arg = required_argument },
5694 char short_opts[] = "l:D:a:m:";
5695 struct hsm_user_request *hur, *oldhur;
5700 char *filelist = NULL;
5701 char fullpath[PATH_MAX];
5702 char *opaque = NULL;
5706 int nbfile_alloc = 0;
5707 char *some_file = NULL;
5708 char *mntpath = NULL;
5714 while ((c = getopt_long(argc, argv, short_opts,
5715 long_opts, NULL)) != -1) {
5724 if (action != HUA_ARCHIVE &&
5725 action != HUA_REMOVE) {
5727 "error: -a is supported only "
5728 "when archiving or removing\n");
5731 archive_id = atoi(optarg);
5734 if (some_file == NULL) {
5736 some_file = strdup(optarg);
5742 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5743 argv[0], argv[optind - 1]);
5748 /* All remaining args are files, so we have at least nbfile */
5749 nbfile = argc - optind;
5751 if ((nbfile == 0) && (filelist == NULL))
5755 opaque_len = strlen(opaque);
5757 /* Alloc the request structure with enough place to store all files
5758 * from command line. */
5759 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5761 fprintf(stderr, "Cannot create the request: %s\n",
5765 nbfile_alloc = nbfile;
5767 hur->hur_request.hr_action = action;
5768 hur->hur_request.hr_archive_id = archive_id;
5769 hur->hur_request.hr_flags = 0;
5771 /* All remaining args are files, add them */
5772 if (nbfile != 0 && some_file == NULL)
5773 some_file = strdup(argv[optind]);
5775 for (i = 0; i < nbfile; i++) {
5776 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5782 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5784 /* If a filelist was specified, read the filelist from it. */
5785 if (filelist != NULL) {
5786 fp = fopen(filelist, "r");
5788 fprintf(stderr, "Cannot read the file list %s: %s\n",
5789 filelist, strerror(errno));
5794 while ((rc = getline(&line, &len, fp)) != -1) {
5795 /* If allocated buffer was too small, get something
5797 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5800 nbfile_alloc = nbfile_alloc * 2 + 1;
5802 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5805 fprintf(stderr, "hsm: cannot allocate "
5806 "the request: %s\n",
5813 size = hur_len(oldhur);
5815 fprintf(stderr, "hsm: cannot allocate "
5816 "%u files + %u bytes data\n",
5817 oldhur->hur_request.hr_itemcount,
5818 oldhur->hur_request.hr_data_len);
5825 memcpy(hur, oldhur, size);
5830 if (line[strlen(line) - 1] == '\n')
5831 line[strlen(line) - 1] = '\0';
5833 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5834 mntpath, line, &last_dev);
5840 if (some_file == NULL) {
5850 /* If a --data was used, add it to the request */
5851 hur->hur_request.hr_data_len = opaque_len;
5853 memcpy(hur_data(hur), opaque, opaque_len);
5855 /* Send the HSM request */
5856 if (realpath(some_file, fullpath) == NULL) {
5857 fprintf(stderr, "Could not find path '%s': %s\n",
5858 some_file, strerror(errno));
5860 rc = llapi_hsm_request(fullpath, hur);
5862 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5863 some_file, strerror(-rc));
5873 static int lfs_hsm_archive(int argc, char **argv)
5875 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5878 static int lfs_hsm_restore(int argc, char **argv)
5880 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5883 static int lfs_hsm_release(int argc, char **argv)
5885 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5888 static int lfs_hsm_remove(int argc, char **argv)
5890 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5893 static int lfs_hsm_cancel(int argc, char **argv)
5895 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5898 static int lfs_swap_layouts(int argc, char **argv)
5903 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5904 SWAP_LAYOUTS_KEEP_MTIME |
5905 SWAP_LAYOUTS_KEEP_ATIME);
5908 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5910 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
5912 static const char *const lockahead_results[] = {
5913 [LLA_RESULT_SENT] = "Lock request sent",
5914 [LLA_RESULT_DIFFERENT] = "Different matching lock found",
5915 [LLA_RESULT_SAME] = "Matching lock on identical extent found",
5918 int lfs_get_mode(const char *string)
5920 enum lock_mode_user mode;
5922 for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
5923 if (lock_mode_names[mode] == NULL)
5925 if (strcmp(string, lock_mode_names[mode]) == 0)
5932 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5934 enum lu_ladvise_type advice;
5937 advice < ARRAY_SIZE(ladvise_names); advice++) {
5938 if (ladvise_names[advice] == NULL)
5940 if (strcmp(string, ladvise_names[advice]) == 0)
5944 return LU_LADVISE_INVALID;
5947 static int lfs_ladvise(int argc, char **argv)
5949 struct option long_opts[] = {
5950 { .val = 'a', .name = "advice", .has_arg = required_argument },
5951 { .val = 'b', .name = "background", .has_arg = no_argument },
5952 { .val = 'e', .name = "end", .has_arg = required_argument },
5953 { .val = 'l', .name = "length", .has_arg = required_argument },
5954 { .val = 'm', .name = "mode", .has_arg = required_argument },
5955 { .val = 's', .name = "start", .has_arg = required_argument },
5956 { .val = 'u', .name = "unset", .has_arg = no_argument },
5958 char short_opts[] = "a:be:l:m:s:u";
5963 struct llapi_lu_ladvise advice;
5964 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5965 unsigned long long start = 0;
5966 unsigned long long end = LUSTRE_EOF;
5967 unsigned long long length = 0;
5968 unsigned long long size_units;
5969 unsigned long long flags = 0;
5973 while ((c = getopt_long(argc, argv, short_opts,
5974 long_opts, NULL)) != -1) {
5977 advice_type = lfs_get_ladvice(optarg);
5978 if (advice_type == LU_LADVISE_INVALID) {
5979 fprintf(stderr, "%s: invalid advice type "
5980 "'%s'\n", argv[0], optarg);
5981 fprintf(stderr, "Valid types:");
5983 for (advice_type = 0;
5984 advice_type < ARRAY_SIZE(ladvise_names);
5986 if (ladvise_names[advice_type] == NULL)
5988 fprintf(stderr, " %s",
5989 ladvise_names[advice_type]);
5991 fprintf(stderr, "\n");
6004 rc = llapi_parse_size(optarg, &end,
6007 fprintf(stderr, "%s: bad end offset '%s'\n",
6014 rc = llapi_parse_size(optarg, &start,
6017 fprintf(stderr, "%s: bad start offset "
6018 "'%s'\n", argv[0], optarg);
6024 rc = llapi_parse_size(optarg, &length,
6027 fprintf(stderr, "%s: bad length '%s'\n",
6033 mode = lfs_get_mode(optarg);
6035 fprintf(stderr, "%s: bad mode '%s', valid "
6036 "modes are READ or WRITE\n",
6044 fprintf(stderr, "%s: option '%s' unrecognized\n",
6045 argv[0], argv[optind - 1]);
6050 if (advice_type == LU_LADVISE_INVALID) {
6051 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
6052 fprintf(stderr, "Valid types:");
6053 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
6055 if (ladvise_names[advice_type] == NULL)
6057 fprintf(stderr, " %s", ladvise_names[advice_type]);
6059 fprintf(stderr, "\n");
6063 if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
6064 fprintf(stderr, "%s: Lock no expand advice is a per file "
6065 "descriptor advice, so when called from lfs, "
6066 "it does nothing.\n", argv[0]);
6070 if (argc <= optind) {
6071 fprintf(stderr, "%s: please give one or more file names\n",
6076 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
6077 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
6082 if (end == LUSTRE_EOF && length != 0)
6083 end = start + length;
6086 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
6087 argv[0], start, end);
6091 if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
6092 fprintf(stderr, "%s: mode is only valid with lockahead\n",
6097 if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
6098 fprintf(stderr, "%s: mode is required with lockahead\n",
6103 while (optind < argc) {
6106 path = argv[optind++];
6108 fd = open(path, O_RDONLY);
6110 fprintf(stderr, "%s: cannot open file '%s': %s\n",
6111 argv[0], path, strerror(errno));
6116 advice.lla_start = start;
6117 advice.lla_end = end;
6118 advice.lla_advice = advice_type;
6119 advice.lla_value1 = 0;
6120 advice.lla_value2 = 0;
6121 advice.lla_value3 = 0;
6122 advice.lla_value4 = 0;
6123 if (advice_type == LU_LADVISE_LOCKAHEAD) {
6124 advice.lla_lockahead_mode = mode;
6125 advice.lla_peradvice_flags = flags;
6128 rc2 = llapi_ladvise(fd, flags, 1, &advice);
6131 fprintf(stderr, "%s: cannot give advice '%s' to file "
6132 "'%s': %s\n", argv[0],
6133 ladvise_names[advice_type],
6134 path, strerror(errno));
6140 if (rc == 0 && rc2 < 0)
6146 /** The input string contains a comma delimited list of component ids and
6147 * ranges, for example "1,2-4,7".
6149 static int parse_mirror_ids(__u16 *ids, int size, char *arg)
6151 bool end_of_loop = false;
6159 while (!end_of_loop) {
6163 char *endptr = NULL;
6166 ptr = strchrnul(arg, ',');
6167 end_of_loop = *ptr == '\0';
6170 start_index = strtol(arg, &endptr, 0);
6171 if (endptr == arg) /* no data at all */
6173 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
6175 if (start_index < 0)
6178 end_index = start_index;
6179 if (*endptr == '-') {
6180 end_index = strtol(endptr + 1, &endptr, 0);
6181 if (*endptr != '\0')
6183 if (end_index < start_index)
6187 for (i = start_index; i <= end_index && size > 0; i++) {
6190 /* remove duplicate */
6191 for (j = 0; j < nr; j++) {
6195 if (j == nr) { /* no duplicate */
6201 if (size == 0 && i < end_index)
6208 if (!end_of_loop && ptr != NULL)
6211 return rc < 0 ? rc : nr;
6214 static inline int lfs_mirror_resync(int argc, char **argv)
6223 struct llapi_layout *layout;
6224 struct ll_ioc_lease *ioc = NULL;
6225 struct llapi_resync_comp comp_array[1024] = { { 0 } };
6226 __u16 mirror_ids[128] = { 0 };
6231 struct option long_opts[] = {
6232 { .val = 'o', .name = "only", .has_arg = required_argument },
6235 while ((c = getopt_long(argc, argv, "o:", long_opts, NULL)) >= 0) {
6238 rc = parse_mirror_ids(mirror_ids,
6239 sizeof(mirror_ids) / sizeof(__u16),
6243 "%s: bad mirror ids '%s'.\n",
6250 fprintf(stderr, "%s: options '%s' unrecognized.\n",
6251 argv[0], argv[optind - 1]);
6257 if (argc > optind + 1) {
6258 fprintf(stderr, "%s: too many files.\n", argv[0]);
6262 if (argc == optind) {
6263 fprintf(stderr, "%s: no file name given.\n", argv[0]);
6268 fname = argv[optind];
6269 if (stat(fname, &stbuf) < 0) {
6270 fprintf(stderr, "%s: cannot stat file '%s': %s.\n",
6271 argv[0], fname, strerror(errno));
6275 if (!S_ISREG(stbuf.st_mode)) {
6276 fprintf(stderr, "%s: '%s' is not a regular file.\n",
6282 fd = open(fname, O_DIRECT | O_RDWR);
6284 fprintf(stderr, "%s: cannot open '%s': %s.\n",
6285 argv[0], fname, strerror(errno));
6290 /* set the lease on the file */
6291 ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
6293 fprintf(stderr, "%s: cannot alloc id array for ioc: %s.\n",
6294 argv[0], strerror(errno));
6299 ioc->lil_mode = LL_LEASE_WRLCK;
6300 ioc->lil_flags = LL_LEASE_RESYNC;
6301 rc = llapi_lease_get_ext(fd, ioc);
6303 fprintf(stderr, "%s: llapi_lease_get_ext resync failed: %s.\n",
6304 argv[0], strerror(errno));
6308 layout = llapi_layout_get_by_fd(fd, 0);
6309 if (layout == NULL) {
6310 fprintf(stderr, "%s: llapi_layout_get_by_fd failed: %s.\n",
6311 argv[0], strerror(errno));
6316 rc = llapi_layout_flags_get(layout, &flr_state);
6318 fprintf(stderr, "%s: llapi_layout_flags_get failed: %s.\n",
6319 argv[0], strerror(errno));
6324 flr_state &= LCM_FL_FLR_MASK;
6325 if (flr_state != LCM_FL_WRITE_PENDING &&
6326 flr_state != LCM_FL_SYNC_PENDING) {
6327 fprintf(stderr, "%s: file state error: %s.\n",
6328 argv[0], lcm_flags_string(flr_state));
6333 /* get stale component info */
6334 comp_size = llapi_mirror_find_stale(layout, comp_array,
6335 ARRAY_SIZE(comp_array),
6336 mirror_ids, ids_nr);
6337 if (comp_size < 0) {
6343 while (idx < comp_size) {
6349 rc = llapi_lease_check(fd);
6350 if (rc != LL_LEASE_WRLCK) {
6351 fprintf(stderr, "lost lease lock.\n");
6355 mirror_id = comp_array[idx].lrc_mirror_id;
6356 end = comp_array[idx].lrc_end;
6358 /* try to combine adjacent component */
6359 for (i = idx + 1; i < comp_size; i++) {
6360 if (mirror_id != comp_array[i].lrc_mirror_id ||
6361 end != comp_array[i].lrc_start)
6363 end = comp_array[i].lrc_end;
6366 result = llapi_mirror_resync_one(fd, layout, mirror_id,
6367 comp_array[idx].lrc_start,
6370 fprintf(stderr, "llapi_mirror_resync_one: %ld.\n",
6374 } else if (result > 0) {
6377 /* mark synced components */
6378 for (j = idx; j < i; j++)
6379 comp_array[j].lrc_synced = true;
6385 /* prepare ioc for lease put */
6386 ioc->lil_mode = LL_LEASE_UNLCK;
6387 ioc->lil_flags = LL_LEASE_RESYNC_DONE;
6389 for (idx = 0; idx < comp_size; idx++) {
6390 if (comp_array[idx].lrc_synced) {
6391 ioc->lil_ids[ioc->lil_count] = comp_array[idx].lrc_id;
6396 llapi_layout_free(layout);
6398 rc = llapi_lease_get_ext(fd, ioc);
6400 if (rc == 0) /* lost lease lock */
6402 fprintf(stderr, "%s: resync file '%s' failed: %s.\n",
6403 argv[0], fname, strerror(errno));
6418 * lfs_mirror() - Parse and execute lfs mirror commands.
6419 * @argc: The count of lfs mirror command line arguments.
6420 * @argv: Array of strings for lfs mirror command line arguments.
6422 * This function parses lfs mirror commands and performs the
6423 * corresponding functions specified in mirror_cmdlist[].
6425 * Return: 0 on success or an error code on failure.
6427 static int lfs_mirror(int argc, char **argv)
6434 Parser_init("lfs-mirror > ", mirror_cmdlist);
6436 snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
6438 program_invocation_short_name = cmd;
6440 rc = Parser_execarg(argc - 1, argv + 1, mirror_cmdlist);
6442 rc = Parser_commands();
6444 return rc < 0 ? -rc : rc;
6448 * lfs_mirror_list_commands() - List lfs mirror commands.
6449 * @argc: The count of command line arguments.
6450 * @argv: Array of strings for command line arguments.
6452 * This function lists lfs mirror commands defined in mirror_cmdlist[].
6454 * Return: 0 on success.
6456 static int lfs_mirror_list_commands(int argc, char **argv)
6458 char buffer[81] = "";
6460 Parser_list_commands(mirror_cmdlist, buffer, sizeof(buffer),
6466 static int lfs_list_commands(int argc, char **argv)
6468 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
6470 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
6475 int main(int argc, char **argv)
6479 /* Ensure that liblustreapi constructor has run */
6480 if (!liblustreapi_initialized)
6481 fprintf(stderr, "liblustreapi was not properly initialized\n");
6486 Parser_init("lfs > ", cmdlist);
6488 progname = argv[0]; /* Used in error messages */
6490 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
6492 rc = Parser_commands();
6494 return rc < 0 ? -rc : rc;
6497 #ifdef _LUSTRE_IDL_H_
6498 /* Everything we need here should be included by lustreapi.h. */
6499 # error "lfs should not depend on lustre_idl.h"
6500 #endif /* _LUSTRE_IDL_H_ */