4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
57 #include <sys/types.h>
64 #include <libcfs/util/string.h>
65 #include <libcfs/util/ioctl.h>
66 #include <libcfs/util/parser.h>
67 #include <lustre/lustreapi.h>
68 #include <linux/lustre/lustre_ver.h>
69 #include <linux/lustre/lustre_param.h>
72 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
73 #endif /* !ARRAY_SIZE */
76 static int lfs_setstripe(int argc, char **argv);
77 static int lfs_find(int argc, char **argv);
78 static int lfs_getstripe(int argc, char **argv);
79 static int lfs_getdirstripe(int argc, char **argv);
80 static int lfs_setdirstripe(int argc, char **argv);
81 static int lfs_rmentry(int argc, char **argv);
82 static int lfs_osts(int argc, char **argv);
83 static int lfs_mdts(int argc, char **argv);
84 static int lfs_df(int argc, char **argv);
85 static int lfs_getname(int argc, char **argv);
86 static int lfs_check(int argc, char **argv);
87 #ifdef HAVE_SYS_QUOTA_H
88 static int lfs_setquota(int argc, char **argv);
89 static int lfs_quota(int argc, char **argv);
91 static int lfs_flushctx(int argc, char **argv);
92 static int lfs_cp(int argc, char **argv);
93 static int lfs_ls(int argc, char **argv);
94 static int lfs_poollist(int argc, char **argv);
95 static int lfs_changelog(int argc, char **argv);
96 static int lfs_changelog_clear(int argc, char **argv);
97 static int lfs_fid2path(int argc, char **argv);
98 static int lfs_path2fid(int argc, char **argv);
99 static int lfs_data_version(int argc, char **argv);
100 static int lfs_hsm_state(int argc, char **argv);
101 static int lfs_hsm_set(int argc, char **argv);
102 static int lfs_hsm_clear(int argc, char **argv);
103 static int lfs_hsm_action(int argc, char **argv);
104 static int lfs_hsm_archive(int argc, char **argv);
105 static int lfs_hsm_restore(int argc, char **argv);
106 static int lfs_hsm_release(int argc, char **argv);
107 static int lfs_hsm_remove(int argc, char **argv);
108 static int lfs_hsm_cancel(int argc, char **argv);
109 static int lfs_swap_layouts(int argc, char **argv);
110 static int lfs_mv(int argc, char **argv);
111 static int lfs_ladvise(int argc, char **argv);
112 static int lfs_list_commands(int argc, char **argv);
114 /* Setstripe and migrate share mostly the same parameters */
115 #define SSM_CMD_COMMON(cmd) \
116 "usage: "cmd" [--component-end|-E <comp_end>]\n" \
117 " [--stripe-count|-c <stripe_count>]\n" \
118 " [--stripe-index|-i <start_ost_idx>]\n" \
119 " [--stripe-size|-S <stripe_size>]\n" \
120 " [--layout|-L <pattern>]\n" \
121 " [--pool|-p <pool_name>]\n" \
122 " [--ost|-o <ost_indices>]\n"
124 #define SSM_HELP_COMMON \
125 "\tstripe_count: Number of OSTs to stripe over (0=fs default, -1 all)\n" \
126 "\tstart_ost_idx: OST index of first stripe (-1=default round robin)\n"\
127 "\tstripe_size: Number of bytes on each OST (0=fs default)\n" \
128 "\t Can be specified with K, M or G (for KB, MB, GB\n" \
129 "\t respectively)\n" \
130 "\tpool_name: Name of OST pool to use (default none)\n" \
131 "\tlayout: stripe pattern type: raid0, mdt (default raid0)\n"\
132 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
133 "\t Indices be specified in a format of:\n" \
134 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
136 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
137 "\t If --pool is set with --ost, then the OSTs\n" \
138 "\t must be the members of the pool.\n" \
139 "\tcomp_end: Extent end of component, start after previous end.\n"\
140 "\t Can be specified with K, M or G (for KB, MB, GB\n" \
141 "\t respectively, -1 for EOF). Must be a multiple of\n"\
145 #define MIGRATE_USAGE \
146 SSM_CMD_COMMON("migrate ") \
148 " [--non-block|-n]\n" \
152 "\tblock: Block file access during data migration (default)\n" \
153 "\tnon-block: Abort migrations if concurrent access is detected\n" \
155 #define SETDIRSTRIPE_USAGE \
156 " [--mdt-count|-c stripe_count>\n" \
157 " [--mdt-index|-i mdt_index]\n" \
158 " [--mdt-hash|-H mdt_hash]\n" \
159 " [--default|-D] [--mode|-m mode] <dir>\n" \
160 "\tstripe_count: stripe count of the striped directory\n" \
161 "\tmdt_index: MDT index of first stripe\n" \
162 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
163 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
164 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
165 "\tdefault_stripe: set default dirstripe of the directory\n" \
166 "\tmode: the mode of the directory\n"
168 static const char *progname;
170 /* all available commands */
171 command_t cmdlist[] = {
172 {"setstripe", lfs_setstripe, 0,
173 "To create a file with specified striping/composite layout, or\n"
174 "create/replace the default layout on an existing directory:\n"
175 SSM_CMD_COMMON("setstripe")
176 " <directory|filename>\n"
178 "To add component(s) to an existing composite file:\n"
179 SSM_CMD_COMMON("setstripe --component-add")
181 "To totally delete the default striping from an existing directory:\n"
182 "usage: setstripe -d <directory>\n"
184 "To delete the last component(s) from an existing composite file\n"
185 "(note that this will also delete any data in those components):\n"
186 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
187 " [--component-flags|-F <comp_flags>]\n"
189 "\tcomp_id: Unique component ID to delete\n"
190 "\tcomp_flags: 'init' indicating all instantiated components\n"
191 "\t '^init' indicating all uninstantiated components\n"
192 "\t-I and -F cannot be specified at the same time\n"},
193 {"getstripe", lfs_getstripe, 0,
194 "To list the striping info for a given file or files in a\n"
195 "directory or recursively for all files in a directory tree.\n"
196 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
197 " [--stripe-count|-c] [--stripe-index|-i]\n"
198 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
199 " [--mdt|-m] [--recursive|-r] [--raw|-R] [--yaml|-y]\n"
200 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
201 " [--component-id[=comp_id]|-I[comp_id]]\n"
202 " [--component-flags[=comp_flags]]\n"
203 " [--component-count]\n"
204 " [--component-start[=[+-]comp_start]]\n"
205 " [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
206 " <directory|filename> ..."},
207 {"setdirstripe", lfs_setdirstripe, 0,
208 "To create a striped directory on a specified MDT. This can only\n"
209 "be done on MDT0 with the right of administrator.\n"
210 "usage: setdirstripe [OPTION] <directory>\n"
212 {"getdirstripe", lfs_getdirstripe, 0,
213 "To list the striping info for a given directory\n"
214 "or recursively for all directories in a directory tree.\n"
215 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
216 " [--mdt-index|-i] [--mdt-hash|-t]\n"
217 " [--recursive|-r] [--yaml|-y]\n"
218 " [--default|-D] <dir> ..."},
219 {"mkdir", lfs_setdirstripe, 0,
220 "To create a striped directory on a specified MDT. This can only\n"
221 "be done on MDT0 with the right of administrator.\n"
222 "usage: mkdir [OPTION] <directory>\n"
224 {"rm_entry", lfs_rmentry, 0,
225 "To remove the name entry of the remote directory. Note: This\n"
226 "command will only delete the name entry, i.e. the remote directory\n"
227 "will become inaccessable after this command. This can only be done\n"
228 "by the administrator\n"
229 "usage: rm_entry <dir>\n"},
230 {"pool_list", lfs_poollist, 0,
231 "List pools or pool OSTs\n"
232 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
233 {"find", lfs_find, 0,
234 "find files matching given attributes recursively in directory tree.\n"
235 "usage: find <directory|filename> ...\n"
236 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
237 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
238 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
239 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
240 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
241 " [[!] --stripe-count|-c [+-]<stripes>]\n"
242 " [[!] --stripe-index|-i <index,...>]\n"
243 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
244 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
245 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
246 " [[!] --projid <projid>]\n"
247 " [[!] --layout|-L released,raid0,mdt]\n"
248 " [[!] --component-count [+-]<comp_cnt>]\n"
249 " [[!] --component-start [+-]N[kMGTPE]]\n"
250 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
251 " [[!] --component-flags <comp_flags>]\n"
252 " [[!] --mdt-count|-T [+-]<stripes>]\n"
253 " [[!] --mdt-hash|-H <hashtype>\n"
254 "\t !: used before an option indicates 'NOT' requested attribute\n"
255 "\t -: used before a value indicates less than requested value\n"
256 "\t +: used before a value indicates more than requested value\n"
257 "\tmdt-hash: hash type of the striped directory.\n"
258 "\t fnv_1a_64 FNV-1a hash algorithm\n"
259 "\t all_char sum of characters % MDT_COUNT\n"},
260 {"check", lfs_check, 0,
261 "Display the status of MDS or OSTs (as specified in the command)\n"
262 "or all the servers (MDS and OSTs).\n"
263 "usage: check <osts|mds|servers>"},
264 {"osts", lfs_osts, 0, "list OSTs connected to client "
265 "[for specified path only]\n" "usage: osts [path]"},
266 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
267 "[for specified path only]\n" "usage: mdts [path]"},
269 "report filesystem disk space usage or inodes usage"
270 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
271 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
272 {"getname", lfs_getname, 0, "list instances and specified mount points "
273 "[for specified path only]\n"
274 "Usage: getname [-h]|[path ...] "},
275 #ifdef HAVE_SYS_QUOTA_H
276 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
277 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
278 " -b <block-softlimit> -B <block-hardlimit>\n"
279 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
280 " setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
281 " [--block-softlimit <block-softlimit>]\n"
282 " [--block-hardlimit <block-hardlimit>]\n"
283 " [--inode-softlimit <inode-softlimit>]\n"
284 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
285 " setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
286 " [--block-grace <block-grace>]\n"
287 " [--inode-grace <inode-grace>] <filesystem>\n"
288 " -b can be used instead of --block-softlimit/--block-grace\n"
289 " -B can be used instead of --block-hardlimit\n"
290 " -i can be used instead of --inode-softlimit/--inode-grace\n"
291 " -I can be used instead of --inode-hardlimit\n\n"
292 "Note: The total quota space will be split into many qunits and\n"
293 " balanced over all server targets, the minimal qunit size is\n"
294 " 1M bytes for block space and 1K inodes for inode space.\n\n"
295 " Quota space rebalancing process will stop when this mininum\n"
296 " value is reached. As a result, quota exceeded can be returned\n"
297 " while many targets still have 1MB or 1K inodes of spare\n"
299 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
300 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
302 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
303 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
305 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
306 "usage: flushctx [-k] [mountpoint...]"},
308 "Remote user copy files and directories.\n"
309 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
311 "Remote user list directory contents.\n"
312 "usage: ls [OPTION]... [FILE]..."},
313 {"changelog", lfs_changelog, 0,
314 "Show the metadata changes on an MDT."
315 "\nusage: changelog <mdtname> [startrec [endrec]]"},
316 {"changelog_clear", lfs_changelog_clear, 0,
317 "Indicate that old changelog records up to <endrec> are no longer of "
318 "interest to consumer <id>, allowing the system to free up space.\n"
319 "An <endrec> of 0 means all records.\n"
320 "usage: changelog_clear <mdtname> <id> <endrec>"},
321 {"fid2path", lfs_fid2path, 0,
322 "Resolve the full path(s) for given FID(s). For a specific hardlink "
323 "specify link number <linkno>.\n"
324 /* "For a historical link name, specify changelog record <recno>.\n" */
325 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
326 /* [ --rec <recno> ] */ },
327 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
328 "usage: path2fid [--parents] <path> ..."},
329 {"data_version", lfs_data_version, 0, "Display file data version for "
330 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
331 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
332 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
333 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
334 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
335 "[--archived] [--lost] <file> ..."},
336 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
338 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
339 "[--archived] [--lost] <file> ..."},
340 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
341 "given files.\n" "usage: hsm_action <file> ..."},
342 {"hsm_archive", lfs_hsm_archive, 0,
343 "Archive file to external storage.\n"
344 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
346 {"hsm_restore", lfs_hsm_restore, 0,
347 "Restore file from external storage.\n"
348 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
349 {"hsm_release", lfs_hsm_release, 0,
350 "Release files from Lustre.\n"
351 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
352 {"hsm_remove", lfs_hsm_remove, 0,
353 "Remove file copy from external storage.\n"
354 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
355 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
357 "Note: To remove files from the archive that have been deleted on\n"
358 "Lustre, set mntpath and optionally archive. In that case, all the\n"
359 "positional arguments and entries in the file list must be FIDs."
361 {"hsm_cancel", lfs_hsm_cancel, 0,
362 "Cancel requests related to specified files.\n"
363 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
364 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
365 "usage: swap_layouts <path1> <path2>"},
366 {"migrate", lfs_setstripe, 0,
367 "migrate a directory between MDTs.\n"
368 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
370 "\tmdt_idx: index of the destination MDT\n"
372 "migrate file objects from one OST "
373 "layout\nto another (may be not safe with concurent writes).\n"
375 "[--stripe-count|-c] <stripe_count>\n"
376 " [--stripe-index|-i] <start_ost_index>\n"
377 " [--stripe-size|-S] <stripe_size>\n"
378 " [--pool|-p] <pool_name>\n"
379 " [--ost-list|-o] <ost_indices>\n"
381 " [--non-block|-n]\n"
382 " <file|directory>\n"
383 "\tstripe_count: number of OSTs to stripe a file over\n"
384 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
385 "\tstripe_size: number of bytes to store before moving to the next OST\n"
386 "\tpool_name: name of the predefined pool of OSTs\n"
387 "\tost_indices: OSTs to stripe over, in order\n"
388 "\tblock: wait for the operation to return before continuing\n"
389 "\tnon-block: do not wait for the operation to return.\n"},
391 "To move directories between MDTs. This command is deprecated, "
392 "use \"migrate\" instead.\n"
393 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
395 {"ladvise", lfs_ladvise, 0,
396 "Provide servers with advice about access patterns for a file.\n"
397 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
398 " [--background|-b] [--unset|-u]\n\n"
399 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
400 " {[--mode|-m [READ,WRITE]}\n"
402 {"help", Parser_help, 0, "help"},
403 {"exit", Parser_quit, 0, "quit"},
404 {"quit", Parser_quit, 0, "quit"},
405 {"--version", Parser_version, 0,
406 "output build version of the utility and exit"},
407 {"--list-commands", lfs_list_commands, 0,
408 "list commands supported by the utility and exit"},
413 static int check_hashtype(const char *hashtype)
417 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
418 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
425 static const char *error_loc = "syserror";
428 MIGRATION_NONBLOCK = 1 << 0,
429 MIGRATION_MIRROR = 1 << 1,
432 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
433 struct llapi_layout *layout);
436 migrate_open_files(const char *name, const struct llapi_stripe_param *param,
437 struct llapi_layout *layout, int *fd_src, int *fd_tgt)
443 char parent[PATH_MAX];
444 char volatile_file[PATH_MAX];
450 if (param == NULL && layout == NULL) {
451 error_loc = "layout information";
455 /* search for file directory pathname */
456 if (strlen(name) > sizeof(parent) - 1) {
457 error_loc = "source file name";
461 strncpy(parent, name, sizeof(parent));
462 ptr = strrchr(parent, '/');
464 if (getcwd(parent, sizeof(parent)) == NULL) {
465 error_loc = "getcwd";
469 if (ptr == parent) /* leading '/' */
474 /* open file, direct io */
475 /* even if the file is only read, WR mode is nedeed to allow
476 * layout swap on fd */
477 fd = open(name, O_RDWR | O_DIRECT);
480 error_loc = "cannot open source file";
484 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
486 error_loc = "cannot get MDT index";
491 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
492 mode_t open_mode = S_IRUSR | S_IWUSR;
494 random_value = random();
495 rc = snprintf(volatile_file, sizeof(volatile_file),
496 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
497 mdt_index, random_value);
498 if (rc >= sizeof(volatile_file)) {
503 /* create, open a volatile file, use caching (ie no directio) */
505 fdv = llapi_file_open_param(volatile_file, open_flags,
508 fdv = lfs_component_create(volatile_file, open_flags,
510 } while (fdv < 0 && (rc = fdv) == -EEXIST);
513 error_loc = "cannot create volatile file";
517 /* In case the MDT does not support creation of volatile files
518 * we should try to unlink it. */
519 (void)unlink(volatile_file);
521 /* Not-owner (root?) special case.
522 * Need to set owner/group of volatile file like original.
523 * This will allow to pass related check during layout_swap.
528 error_loc = "cannot stat source file";
532 rc = fstat(fdv, &stv);
535 error_loc = "cannot stat volatile";
539 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
540 rc = fchown(fdv, st.st_uid, st.st_gid);
543 error_loc = "cannot change ownwership of volatile";
562 static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int))
564 struct llapi_layout *layout;
565 size_t buf_size = 4 * 1024 * 1024;
574 layout = llapi_layout_get_by_fd(fd_src, 0);
575 if (layout != NULL) {
576 uint64_t stripe_size;
578 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
580 buf_size = stripe_size;
582 llapi_layout_free(layout);
585 /* Use a page-aligned buffer for direct I/O */
586 rc = posix_memalign(&buf, getpagesize(), buf_size);
591 /* read new data only if we have written all
592 * previously read data */
595 rc = check_file(fd_src);
600 rsize = read(fd_src, buf, buf_size);
612 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
631 static int migrate_copy_timestamps(int fd, int fdv)
635 if (fstat(fd, &st) == 0) {
636 struct timeval tv[2] = {
637 {.tv_sec = st.st_atime},
638 {.tv_sec = st.st_mtime}
641 return futimes(fdv, tv);
647 static int migrate_block(int fd, int fdv)
654 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
656 error_loc = "cannot get dataversion";
664 /* The grouplock blocks all concurrent accesses to the file.
665 * It has to be taken after llapi_get_data_version as it would
667 rc = llapi_group_lock(fd, gid);
669 error_loc = "cannot get group lock";
673 rc = migrate_copy_data(fd, fdv, NULL);
675 error_loc = "data copy failed";
679 /* Make sure we keep original atime/mtime values */
680 rc = migrate_copy_timestamps(fd, fdv);
682 error_loc = "timestamp copy failed";
687 * for a migration we need to check data version on file did
690 * Pass in gid=0 since we already own grouplock. */
691 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
692 SWAP_LAYOUTS_CHECK_DV1);
694 error_loc = "file changed";
697 error_loc = "cannot swap layout";
702 rc2 = llapi_group_unlock(fd, gid);
703 if (rc2 < 0 && rc == 0) {
704 error_loc = "unlock group lock";
712 * Internal helper for migrate_copy_data(). Check lease and report error if
715 * \param[in] fd File descriptor on which to check the lease.
717 * \retval 0 Migration can keep on going.
718 * \retval -errno Error occurred, abort migration.
720 static int check_lease(int fd)
724 rc = llapi_lease_check(fd);
726 return 0; /* llapi_check_lease returns > 0 on success. */
731 static int migrate_nonblock(int fd, int fdv)
737 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
739 error_loc = "cannot get data version";
743 rc = migrate_copy_data(fd, fdv, check_lease);
745 error_loc = "data copy failed";
749 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
751 error_loc = "cannot get data version";
757 error_loc = "source file changed";
761 /* Make sure we keep original atime/mtime values */
762 rc = migrate_copy_timestamps(fd, fdv);
764 error_loc = "timestamp copy failed";
771 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
776 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
780 if (flags != 0 && comp_id != 0)
783 /* LCME_FL_INIT is the only supported flag in PFL */
785 if (flags & ~LCME_KNOWN_FLAGS) {
786 fprintf(stderr, "Invalid component flags %#x\n", flags);
789 } else if (comp_id > LCME_ID_MAX) {
790 fprintf(stderr, "Invalid component id %u\n", comp_id);
794 rc = llapi_layout_file_comp_del(fname, comp_id, flags);
796 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
797 comp_id, fname, strerror(errno));
801 static int lfs_component_add(char *fname, struct llapi_layout *layout)
808 rc = llapi_layout_file_comp_add(fname, layout);
810 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
811 fname, strerror(errno));
815 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
816 struct llapi_layout *layout)
824 fd = lstat(fname, &st);
825 if (fd == 0 && S_ISDIR(st.st_mode))
826 open_flags = O_DIRECTORY | O_RDONLY;
828 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
830 fprintf(stderr, "%s: cannot %s '%s': %s\n", progname,
831 S_ISDIR(st.st_mode) ?
832 "set default composite layout for" :
833 "create composite file",
834 fname, strerror(errno));
838 static int lfs_migrate(char *name, __u64 migration_flags,
839 struct llapi_stripe_param *param,
840 struct llapi_layout *layout)
846 rc = migrate_open_files(name, param, layout, &fd, &fdv);
850 if (!(migration_flags & MIGRATION_NONBLOCK)) {
851 /* Blocking mode (forced if servers do not support file lease).
852 * It is also the default mode, since we cannot distinguish
853 * between a broken lease and a server that does not support
854 * atomic swap/close (LU-6785) */
855 rc = migrate_block(fd, fdv);
859 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
861 error_loc = "cannot get lease";
865 rc = migrate_nonblock(fd, fdv);
871 /* Atomically put lease, swap layouts and close.
872 * for a migration we need to check data version on file did
874 rc = llapi_fswap_layouts(fd, fdv, 0, 0,
875 migration_flags & MIGRATION_MIRROR ?
876 MERGE_LAYOUTS_CLOSE : SWAP_LAYOUTS_CLOSE);
878 error_loc = "cannot swap layout";
890 fprintf(stderr, "error: %s: %s: %s: %s\n",
891 progname, name, error_loc, strerror(-rc));
895 static int lfs_create_mirror(char *fname, struct llapi_layout *layout,
896 const char *mirror_file)
905 if (mirror_file == NULL)
906 return lfs_migrate(fname, MIGRATION_NONBLOCK | MIGRATION_MIRROR,
909 fd = open(fname, O_RDWR);
911 error_loc = "open source file";
916 /* Get rid of caching pages from clients */
917 rc = llapi_get_data_version(fd, &dv, LL_DV_WR_FLUSH);
919 error_loc = "cannot get data version";
923 fdv = open(mirror_file, O_WRONLY);
925 error_loc = "open target file";
930 rc = llapi_get_data_version(fdv, &dv, LL_DV_WR_FLUSH);
932 error_loc = "cannot get data version";
936 if (fstat(fd, &stbuf) || fstat(fdv, &stbuf_v)) {
937 error_loc = "stat source or target file";
942 if (stbuf.st_dev != stbuf_v.st_dev) {
943 error_loc = "stat source and target file";
948 /* mirrors should be of the same size */
949 if (stbuf.st_size != stbuf_v.st_size) {
950 error_loc = "file sizes don't match";
955 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
957 error_loc = "cannot get lease";
961 /* Make sure we keep original atime/mtime values */
962 rc = migrate_copy_timestamps(fd, fdv);
964 /* Atomically put lease, swap layouts and close.
965 * for a migration we need to check data version on file did
967 rc = llapi_fswap_layouts(fd, fdv, 0, 0, MERGE_LAYOUTS_CLOSE);
969 error_loc = "cannot swap layout";
981 fprintf(stderr, "error: %s: %s: %s: %s\n",
982 progname, fname, error_loc, strerror(-rc));
987 * Parse a string containing an OST index list into an array of integers.
989 * The input string contains a comma delimited list of individual
990 * indices and ranges, for example "1,2-4,7". Add the indices into the
991 * \a osts array and remove duplicates.
993 * \param[out] osts array to store indices in
994 * \param[in] size size of \a osts array
995 * \param[in] offset starting index in \a osts
996 * \param[in] arg string containing OST index list
998 * \retval positive number of indices in \a osts
999 * \retval -EINVAL unable to parse \a arg
1001 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
1005 int slots = size - offset;
1012 end_of_loop = false;
1013 while (!end_of_loop) {
1017 char *endptr = NULL;
1021 ptr = strchrnul(arg, ',');
1023 end_of_loop = *ptr == '\0';
1026 start_index = strtol(arg, &endptr, 0);
1027 if (endptr == arg) /* no data at all */
1029 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
1031 if (start_index < 0)
1034 end_index = start_index;
1035 if (*endptr == '-') {
1036 end_index = strtol(endptr + 1, &endptr, 0);
1037 if (*endptr != '\0')
1039 if (end_index < start_index)
1043 for (i = start_index; i <= end_index && slots > 0; i++) {
1046 /* remove duplicate */
1047 for (j = 0; j < offset; j++) {
1051 if (j == offset) { /* no duplicate */
1056 if (slots == 0 && i < end_index)
1064 if (!end_of_loop && ptr != NULL)
1067 return rc < 0 ? rc : nr;
1070 struct lfs_setstripe_args {
1071 unsigned long long lsa_comp_end;
1072 unsigned long long lsa_stripe_size;
1073 int lsa_stripe_count;
1075 __u32 lsa_comp_flags;
1079 char *lsa_pool_name;
1082 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1084 memset(lsa, 0, sizeof(*lsa));
1085 lsa->lsa_stripe_off = -1;
1088 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1090 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1091 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1092 lsa->lsa_comp_end != 0 || lsa->lsa_pattern != 0);
1095 static int comp_args_to_layout(struct llapi_layout **composite,
1096 struct lfs_setstripe_args *lsa)
1098 struct llapi_layout *layout = *composite;
1099 uint64_t prev_end = 0;
1102 if (layout == NULL) {
1103 layout = llapi_layout_alloc();
1104 if (layout == NULL) {
1105 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1109 *composite = layout;
1113 /* Get current component extent, current component
1114 * must be the tail component. */
1115 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1117 fprintf(stderr, "Get comp extent failed. %s\n",
1122 rc = llapi_layout_comp_add(layout);
1124 fprintf(stderr, "Add component failed. %s\n",
1130 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1132 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1133 prev_end, lsa->lsa_comp_end, strerror(errno));
1137 /* Data-on-MDT component setting */
1138 if (lsa->lsa_pattern == LLAPI_LAYOUT_MDT) {
1139 /* In case of Data-on-MDT patterns the only extra option
1140 * applicable is stripe size option. */
1141 if (lsa->lsa_stripe_count) {
1142 fprintf(stderr, "Option 'stripe-count' can't be "
1143 "specified with Data-on-MDT component: %i\n",
1144 lsa->lsa_stripe_count);
1147 if (lsa->lsa_stripe_size) {
1148 fprintf(stderr, "Option 'stripe-size' can't be "
1149 "specified with Data-on-MDT component: %llu\n",
1150 lsa->lsa_stripe_size);
1153 if (lsa->lsa_nr_osts != 0) {
1154 fprintf(stderr, "Option 'ost-list' can't be specified "
1155 "with Data-on-MDT component: '%i'\n",
1159 if (lsa->lsa_stripe_off != -1) {
1160 fprintf(stderr, "Option 'stripe-offset' can't be "
1161 "specified with Data-on-MDT component: %i\n",
1162 lsa->lsa_stripe_off);
1165 if (lsa->lsa_pool_name != 0) {
1166 fprintf(stderr, "Option 'pool' can't be specified "
1167 "with Data-on-MDT component: '%s'\n",
1168 lsa->lsa_pool_name);
1172 rc = llapi_layout_pattern_set(layout, lsa->lsa_pattern);
1174 fprintf(stderr, "Set stripe pattern %#x failed. %s\n",
1175 lsa->lsa_pattern, strerror(errno));
1178 /* Data-on-MDT component has always single stripe up to end */
1179 lsa->lsa_stripe_size = lsa->lsa_comp_end;
1182 if (lsa->lsa_stripe_size != 0) {
1183 rc = llapi_layout_stripe_size_set(layout,
1184 lsa->lsa_stripe_size);
1186 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1187 lsa->lsa_stripe_size, strerror(errno));
1192 if (lsa->lsa_stripe_count != 0) {
1193 rc = llapi_layout_stripe_count_set(layout,
1194 lsa->lsa_stripe_count == -1 ?
1196 lsa->lsa_stripe_count);
1198 fprintf(stderr, "Set stripe count %d failed. %s\n",
1199 lsa->lsa_stripe_count, strerror(errno));
1204 if (lsa->lsa_pool_name != NULL) {
1205 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1207 fprintf(stderr, "Set pool name: %s failed. %s\n",
1208 lsa->lsa_pool_name, strerror(errno));
1213 if (lsa->lsa_nr_osts > 0) {
1214 if (lsa->lsa_stripe_count > 0 &&
1215 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1216 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1217 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1220 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1221 rc = llapi_layout_ost_index_set(layout, i,
1226 } else if (lsa->lsa_stripe_off != -1) {
1227 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1230 fprintf(stderr, "Set ost index %d failed. %s\n",
1231 i, strerror(errno));
1238 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1239 * end of the last component in the existing file, and adjust the
1240 * first extent start of the components to be added accordingly. */
1241 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1243 struct llapi_layout *head;
1244 uint64_t start, end, stripe_size, prev_end = 0;
1251 head = llapi_layout_get_by_path(fname, 0);
1253 fprintf(stderr, "Read layout from %s failed. %s\n",
1254 fname, strerror(errno));
1256 } else if (errno == ENODATA) {
1257 /* file without LOVEA, this component-add will be turned
1258 * into a component-create. */
1259 llapi_layout_free(head);
1261 } else if (!llapi_layout_is_composite(head)) {
1262 fprintf(stderr, "'%s' isn't a composite file.\n",
1264 llapi_layout_free(head);
1268 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1270 fprintf(stderr, "Get prev extent failed. %s\n",
1272 llapi_layout_free(head);
1276 llapi_layout_free(head);
1278 /* Make sure we use the first component of the layout to be added. */
1279 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1281 fprintf(stderr, "Move component cursor failed. %s\n",
1286 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1288 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1292 if (start > prev_end || end <= prev_end) {
1293 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1294 "adjacent with the existing file extent end: %lu\n",
1295 start, end, prev_end);
1299 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1301 fprintf(stderr, "Get stripe size failed. %s\n",
1306 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1307 (prev_end & (stripe_size - 1))) {
1308 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1309 stripe_size, prev_end);
1313 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1315 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1316 prev_end, end, strerror(errno));
1323 static inline bool comp_flags_is_neg(__u32 flags)
1325 return flags & LCME_FL_NEG;
1328 static inline void comp_flags_set_neg(__u32 *flags)
1330 *flags |= LCME_FL_NEG;
1333 static inline void comp_flags_clear_neg(__u32 *flags)
1335 *flags &= ~LCME_FL_NEG;
1338 static int comp_str2flags(__u32 *flags, char *string)
1341 __u32 neg_flags = 0;
1347 for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1351 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1352 __u32 comp_flag = comp_flags_table[i].cfn_flag;
1353 const char *comp_name = comp_flags_table[i].cfn_name;
1355 if (strcmp(name, comp_name) == 0) {
1356 *flags |= comp_flag;
1358 } else if (strncmp(name, "^", 1) == 0 &&
1359 strcmp(name + 1, comp_name) == 0) {
1360 neg_flags |= comp_flag;
1365 llapi_printf(LLAPI_MSG_ERROR,
1366 "%s: component flag '%s' not supported\n",
1372 if (*flags == 0 && neg_flags == 0)
1374 /* don't support mixed flags for now */
1375 if (*flags && neg_flags)
1380 comp_flags_set_neg(flags);
1386 static inline bool arg_is_eof(char *arg)
1388 return !strncmp(arg, "-1", strlen("-1")) ||
1389 !strncmp(arg, "EOF", strlen("EOF")) ||
1390 !strncmp(arg, "eof", strlen("eof"));
1405 static int lfs_setstripe(int argc, char **argv)
1407 struct lfs_setstripe_args lsa;
1408 struct llapi_stripe_param *param = NULL;
1409 struct find_param migrate_mdt_param = {
1419 char *mdt_idx_arg = NULL;
1420 unsigned long long size_units = 1;
1421 bool migrate_mode = false;
1422 bool migration_block = false;
1423 __u64 migration_flags = 0;
1424 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1425 int comp_del = 0, comp_set = 0;
1428 struct llapi_layout *layout = NULL;
1429 bool create_mirror = false;
1430 const char *mirror_file = NULL;
1432 struct option long_opts[] = {
1433 /* --block is only valid in migrate mode */
1434 { .val = 'b', .name = "block", .has_arg = no_argument},
1435 { .val = LFS_COMP_ADD_OPT,
1436 .name = "comp-add", .has_arg = no_argument},
1437 { .val = LFS_COMP_ADD_OPT,
1438 .name = "component-add",
1439 .has_arg = no_argument},
1440 { .val = LFS_COMP_DEL_OPT,
1441 .name = "comp-del", .has_arg = no_argument},
1442 { .val = LFS_COMP_DEL_OPT,
1443 .name = "component-del",
1444 .has_arg = no_argument},
1445 { .val = LFS_COMP_FLAGS_OPT,
1446 .name = "comp-flags", .has_arg = required_argument},
1447 { .val = LFS_COMP_FLAGS_OPT,
1448 .name = "component-flags",
1449 .has_arg = required_argument},
1450 { .val = LFS_COMP_SET_OPT,
1451 .name = "comp-set", .has_arg = no_argument},
1452 { .val = LFS_COMP_SET_OPT,
1453 .name = "component-set",
1454 .has_arg = no_argument},
1455 { .val = 'c', .name = "stripe-count", .has_arg = required_argument},
1456 { .val = 'c', .name = "stripe_count", .has_arg = required_argument},
1457 { .val = 'd', .name = "delete", .has_arg = no_argument},
1458 { .val = 'E', .name = "comp-end", .has_arg = required_argument},
1459 { .val = 'E', .name = "component-end",
1460 .has_arg = required_argument},
1461 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1462 { .val = 'i', .name = "stripe-index", .has_arg = required_argument},
1463 { .val = 'i', .name = "stripe_index", .has_arg = required_argument},
1464 { .val = 'I', .name = "comp-id", .has_arg = required_argument},
1465 { .val = 'I', .name = "component-id", .has_arg = required_argument},
1466 { .val = 'L', .name = "layout", .has_arg = required_argument },
1467 { .val = 'm', .name = "mdt", .has_arg = required_argument},
1468 { .val = 'm', .name = "mdt-index", .has_arg = required_argument},
1469 { .val = 'm', .name = "mdt_index", .has_arg = required_argument},
1470 { .val = 'M', .name = "mirror", .has_arg = optional_argument},
1471 /* --non-block is only valid in migrate mode */
1472 { .val = 'n', .name = "non-block", .has_arg = no_argument},
1473 { .val = 'o', .name = "ost", .has_arg = required_argument},
1474 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1475 { .val = 'o', .name = "ost-list", .has_arg = required_argument },
1476 { .val = 'o', .name = "ost_list", .has_arg = required_argument },
1478 { .val = 'p', .name = "pool", .has_arg = required_argument },
1479 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1480 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1481 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1482 /* --verbose is only valid in migrate mode */
1483 { .val = 'v', .name = "verbose", .has_arg = no_argument },
1484 { .val = LFS_COMP_ADD_OPT,
1485 .name = "component-add",
1486 .has_arg = no_argument },
1487 { .val = LFS_COMP_DEL_OPT,
1488 .name = "component-del",
1489 .has_arg = no_argument },
1490 { .val = LFS_COMP_FLAGS_OPT,
1491 .name = "component-flags",
1492 .has_arg = required_argument },
1493 { .val = LFS_COMP_SET_OPT,
1494 .name = "component-set",
1495 .has_arg = no_argument },
1498 setstripe_args_init(&lsa);
1500 if (strcmp(argv[0], "migrate") == 0)
1501 migrate_mode = true;
1503 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:L:s:S:v",
1504 long_opts, NULL)) >= 0) {
1509 case LFS_COMP_ADD_OPT:
1512 case LFS_COMP_DEL_OPT:
1515 case LFS_COMP_FLAGS_OPT:
1516 result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
1520 case LFS_COMP_SET_OPT:
1524 if (!migrate_mode) {
1526 "%s %s: -b|--block valid only for migrate command\n",
1530 migration_block = true;
1533 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1536 "%s %s: invalid stripe count '%s'\n",
1537 progname, argv[0], optarg);
1542 /* delete the default striping pattern */
1546 if (create_mirror) {
1547 fprintf(stderr, "error: %s: --mirror can only "
1548 "be specfied once", argv[0]);
1551 create_mirror = true;
1552 mirror_file = optarg;
1555 if (lsa.lsa_comp_end != 0) {
1556 result = comp_args_to_layout(&layout, &lsa);
1559 "%s %s: invalid layout\n",
1564 setstripe_args_init(&lsa);
1567 if (arg_is_eof(optarg)) {
1568 lsa.lsa_comp_end = LUSTRE_EOF;
1570 result = llapi_parse_size(optarg,
1575 "%s %s: invalid component end '%s'\n",
1576 progname, argv[0], optarg);
1582 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1585 "%s %s: invalid stripe offset '%s'\n",
1586 progname, argv[0], optarg);
1591 comp_id = strtoul(optarg, &end, 0);
1592 if (*end != '\0' || comp_id == 0 ||
1593 comp_id > LCME_ID_MAX) {
1595 "%s %s: invalid component ID '%s'\n",
1596 progname, argv[0], optarg);
1601 if (strcmp(argv[optind - 1], "mdt") == 0) {
1602 /* Can be only the first component */
1603 if (layout != NULL) {
1605 fprintf(stderr, "error: 'mdt' layout "
1606 "can be only the first one\n");
1609 if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
1611 fprintf(stderr, "error: 'mdt' layout "
1612 "size is too big\n");
1615 lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
1616 } else if (strcmp(argv[optind - 1], "raid0") != 0) {
1618 fprintf(stderr, "error: layout '%s' is "
1619 "unknown, supported layouts are: "
1620 "'mdt', 'raid0'\n", argv[optind]);
1625 if (!migrate_mode) {
1627 "%s %s: -m|--mdt-index valid only for migrate command\n",
1631 mdt_idx_arg = optarg;
1634 if (!migrate_mode) {
1636 "%s %s: -n|--non-block valid only for migrate command\n",
1640 migration_flags |= MIGRATION_NONBLOCK;
1643 lsa.lsa_nr_osts = parse_targets(osts,
1644 sizeof(osts) / sizeof(__u32),
1645 lsa.lsa_nr_osts, optarg);
1646 if (lsa.lsa_nr_osts < 0) {
1648 "%s %s: invalid OST target(s) '%s'\n",
1649 progname, argv[0], optarg);
1653 lsa.lsa_osts = osts;
1654 if (lsa.lsa_stripe_off == -1)
1655 lsa.lsa_stripe_off = osts[0];
1660 lsa.lsa_pool_name = optarg;
1663 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1667 "%s %s: invalid stripe size '%s'\n",
1668 progname, argv[0], optarg);
1673 if (!migrate_mode) {
1675 "%s %s: -v|--verbose valid only for migrate command\n",
1679 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1682 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
1683 progname, argv[0], argv[optind - 1]);
1688 fname = argv[optind];
1690 if (optind == argc) {
1691 fprintf(stderr, "%s %s: FILE must be specified\n",
1696 if (create_mirror) {
1698 fprintf(stderr, "error: %s: --component-add must be "
1699 "specified with --mirror option\n", argv[0]);
1702 if (lsa.lsa_comp_end == 0)
1703 lsa.lsa_comp_end = LUSTRE_EOF;
1704 if (lsa.lsa_comp_end != LUSTRE_EOF) {
1706 "error: %s: creating non-eof ending mirror\n",
1712 if (lsa.lsa_comp_end != 0) {
1713 result = comp_args_to_layout(&layout, &lsa);
1718 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1719 * altered by user space tool, so we don't need to support the
1720 * --component-set for this moment. */
1721 if (comp_set != 0) {
1722 fprintf(stderr, "%s %s: --component-set not supported\n",
1727 if ((delete + comp_set + comp_del + comp_add) > 1) {
1729 "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
1734 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1735 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1737 "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
1742 if ((comp_set || comp_del) &&
1743 (setstripe_args_specified(&lsa) || layout != NULL)) {
1745 "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
1750 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1752 "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
1757 if (comp_add || comp_del) {
1760 result = lstat(fname, &st);
1761 if (result == 0 && S_ISDIR(st.st_mode)) {
1763 "%s setstripe: cannot use --component-add or --component-del for directory\n",
1770 if (layout == NULL) {
1772 "%s %s: option -E must be specified with --component-add\n",
1776 if (!create_mirror) {
1777 result = adjust_first_extent(fname, layout);
1778 if (result == -ENODATA)
1780 else if (result != 0)
1785 if (mdt_idx_arg != NULL && optind > 3) {
1787 "%s %s: option -m cannot be used with other options\n",
1792 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1794 "%s %s: options --non-block and --block are mutually exclusive\n",
1799 if (!comp_del && !comp_set && comp_id != 0) {
1801 "%s %s: option -I can only be used with --component-del\n",
1806 if (mdt_idx_arg != NULL) {
1807 /* initialize migrate mdt parameters */
1808 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1810 fprintf(stderr, "%s %s: invalid MDT index '%s'\n",
1811 progname, argv[0], mdt_idx_arg);
1814 migrate_mdt_param.fp_migrate = 1;
1815 } else if (layout == NULL) {
1816 /* initialize stripe parameters */
1817 param = calloc(1, offsetof(typeof(*param),
1818 lsp_osts[lsa.lsa_nr_osts]));
1819 if (param == NULL) {
1821 "%s %s: cannot allocate memory for parameters: %s\n",
1822 progname, argv[0], strerror(ENOMEM));
1827 param->lsp_stripe_size = lsa.lsa_stripe_size;
1828 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1829 param->lsp_stripe_count = lsa.lsa_stripe_count;
1830 param->lsp_pool = lsa.lsa_pool_name;
1831 param->lsp_is_specific = false;
1832 if (lsa.lsa_nr_osts > 0) {
1833 if (lsa.lsa_stripe_count > 0 &&
1834 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1836 "%s %s: stripe count '%d' does not match number of OSTs: %d\n",
1837 progname, argv[0], lsa.lsa_stripe_count,
1843 param->lsp_is_specific = true;
1844 param->lsp_stripe_count = lsa.lsa_nr_osts;
1845 memcpy(param->lsp_osts, osts,
1846 sizeof(*osts) * lsa.lsa_nr_osts);
1850 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1851 if (mdt_idx_arg != NULL) {
1852 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1853 } else if (migrate_mode) {
1854 result = lfs_migrate(fname, migration_flags, param,
1856 } else if (comp_set != 0) {
1857 result = lfs_component_set(fname, comp_id,
1858 lsa.lsa_comp_flags);
1859 } else if (comp_del != 0) {
1860 result = lfs_component_del(fname, comp_id,
1861 lsa.lsa_comp_flags);
1862 } else if (comp_add != 0) {
1864 result = lfs_create_mirror(fname, layout,
1867 result = lfs_component_add(fname, layout);
1868 } else if (layout != NULL) {
1869 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1876 result = llapi_file_open_param(fname,
1885 /* Save the first error encountered. */
1893 llapi_layout_free(layout);
1898 llapi_layout_free(layout);
1902 static int lfs_poollist(int argc, char **argv)
1907 return llapi_poollist(argv[1]);
1910 static int set_time(time_t *time, time_t *set, char *str)
1917 else if (str[0] == '-')
1923 t = strtol(str, NULL, 0);
1924 if (*time < t * 24 * 60 * 60) {
1927 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1931 *set = *time - t * 24 * 60 * 60;
1934 static int name2uid(unsigned int *id, const char *name)
1936 struct passwd *passwd;
1938 passwd = getpwnam(name);
1941 *id = passwd->pw_uid;
1946 static int name2gid(unsigned int *id, const char *name)
1948 struct group *group;
1950 group = getgrnam(name);
1953 *id = group->gr_gid;
1958 static inline int name2projid(unsigned int *id, const char *name)
1963 static int uid2name(char **name, unsigned int id)
1965 struct passwd *passwd;
1967 passwd = getpwuid(id);
1970 *name = passwd->pw_name;
1975 static inline int gid2name(char **name, unsigned int id)
1977 struct group *group;
1979 group = getgrgid(id);
1982 *name = group->gr_name;
1987 static int name2layout(__u32 *layout, char *name)
1989 char *ptr, *layout_name;
1992 for (ptr = name; ; ptr = NULL) {
1993 layout_name = strtok(ptr, ",");
1994 if (layout_name == NULL)
1996 if (strcmp(layout_name, "released") == 0)
1997 *layout |= LOV_PATTERN_F_RELEASED;
1998 else if (strcmp(layout_name, "raid0") == 0)
1999 *layout |= LOV_PATTERN_RAID0;
2000 else if (strcmp(layout_name, "mdt") == 0)
2001 *layout |= LOV_PATTERN_MDT;
2008 static int lfs_find(int argc, char **argv)
2013 struct find_param param = {
2017 struct option long_opts[] = {
2018 { .val = 'A', .name = "atime", .has_arg = required_argument },
2019 { .val = LFS_COMP_COUNT_OPT,
2020 .name = "comp-count", .has_arg = required_argument },
2021 { .val = LFS_COMP_COUNT_OPT,
2022 .name = "component-count",
2023 .has_arg = required_argument },
2024 { .val = LFS_COMP_FLAGS_OPT,
2025 .name = "comp-flags", .has_arg = required_argument },
2026 { .val = LFS_COMP_FLAGS_OPT,
2027 .name = "component-flags",
2028 .has_arg = required_argument },
2029 { .val = LFS_COMP_START_OPT,
2030 .name = "comp-start", .has_arg = required_argument },
2031 { .val = LFS_COMP_START_OPT,
2032 .name = "component-start",
2033 .has_arg = required_argument },
2034 { .val = 'c', .name = "stripe-count", .has_arg = required_argument },
2035 { .val = 'c', .name = "stripe_count", .has_arg = required_argument },
2036 { .val = 'C', .name = "ctime", .has_arg = required_argument },
2037 { .val = 'D', .name = "maxdepth", .has_arg = required_argument },
2038 { .val = 'E', .name = "comp-end", .has_arg = required_argument },
2039 { .val = 'E', .name = "component-end",
2040 .has_arg = required_argument },
2041 { .val = 'g', .name = "gid", .has_arg = required_argument },
2042 { .val = 'G', .name = "group", .has_arg = required_argument },
2043 { .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
2044 { .val = 'i', .name = "stripe-index", .has_arg = required_argument },
2045 { .val = 'i', .name = "stripe_index", .has_arg = required_argument },
2046 /*{"component-id", required_argument, 0, 'I'},*/
2047 { .val = 'L', .name = "layout", .has_arg = required_argument },
2048 { .val = 'm', .name = "mdt", .has_arg = required_argument },
2049 { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
2050 { .val = 'm', .name = "mdt_index", .has_arg = required_argument },
2051 { .val = 'M', .name = "mtime", .has_arg = required_argument },
2052 { .val = 'n', .name = "name", .has_arg = required_argument },
2053 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
2054 { .val = 'O', .name = "obd", .has_arg = required_argument },
2055 { .val = 'O', .name = "ost", .has_arg = required_argument },
2056 /* no short option for pool, p/P already used */
2057 { .val = LFS_POOL_OPT,
2058 .name = "pool", .has_arg = required_argument },
2059 { .val = 'p', .name = "print0", .has_arg = no_argument },
2060 { .val = 'P', .name = "print", .has_arg = no_argument },
2061 { .val = LFS_PROJID_OPT,
2062 .name = "projid", .has_arg = required_argument },
2063 { .val = 's', .name = "size", .has_arg = required_argument },
2064 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
2065 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
2066 { .val = 't', .name = "type", .has_arg = required_argument },
2067 { .val = 'T', .name = "mdt-count", .has_arg = required_argument },
2068 { .val = 'u', .name = "uid", .has_arg = required_argument },
2069 { .val = 'U', .name = "user", .has_arg = required_argument },
2081 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
2082 while ((c = getopt_long_only(argc, argv,
2083 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
2084 long_opts, NULL)) >= 0) {
2089 /* '!' is part of option */
2090 /* when getopt_long_only() finds a string which is not
2091 * an option nor a known option argument it returns 1
2092 * in that case if we already have found pathstart and pathend
2093 * (i.e. we have the list of pathnames),
2094 * the only supported value is "!"
2096 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
2097 if (!isoption && pathend != -1) {
2098 fprintf(stderr, "err: %s: filename|dirname must either "
2099 "precede options or follow options\n",
2104 if (!isoption && pathstart == -1)
2105 pathstart = optind - 1;
2106 if (isoption && pathstart != -1 && pathend == -1)
2107 pathend = optind - 2;
2113 /* unknown; opt is "!" or path component,
2114 * checking done above.
2116 if (strcmp(optarg, "!") == 0)
2120 xtime = ¶m.fp_atime;
2121 xsign = ¶m.fp_asign;
2122 param.fp_exclude_atime = !!neg_opt;
2123 /* no break, this falls through to 'C' for ctime */
2126 xtime = ¶m.fp_ctime;
2127 xsign = ¶m.fp_csign;
2128 param.fp_exclude_ctime = !!neg_opt;
2130 /* no break, this falls through to 'M' for mtime */
2133 xtime = ¶m.fp_mtime;
2134 xsign = ¶m.fp_msign;
2135 param.fp_exclude_mtime = !!neg_opt;
2137 rc = set_time(&t, xtime, optarg);
2138 if (rc == INT_MAX) {
2145 case LFS_COMP_COUNT_OPT:
2146 if (optarg[0] == '+') {
2147 param.fp_comp_count_sign = -1;
2149 } else if (optarg[0] == '-') {
2150 param.fp_comp_count_sign = 1;
2154 param.fp_comp_count = strtoul(optarg, &endptr, 0);
2155 if (*endptr != '\0') {
2156 fprintf(stderr, "error: bad component count "
2160 param.fp_check_comp_count = 1;
2161 param.fp_exclude_comp_count = !!neg_opt;
2163 case LFS_COMP_FLAGS_OPT:
2164 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
2165 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2166 fprintf(stderr, "error: bad component flags "
2170 param.fp_check_comp_flags = 1;
2171 param.fp_exclude_comp_flags = !!neg_opt;
2173 case LFS_COMP_START_OPT:
2174 if (optarg[0] == '+') {
2175 param.fp_comp_start_sign = -1;
2177 } else if (optarg[0] == '-') {
2178 param.fp_comp_start_sign = 1;
2182 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2183 ¶m.fp_comp_start_units, 0);
2185 fprintf(stderr, "error: bad component start "
2189 param.fp_check_comp_start = 1;
2190 param.fp_exclude_comp_start = !!neg_opt;
2193 if (optarg[0] == '+') {
2194 param.fp_stripe_count_sign = -1;
2196 } else if (optarg[0] == '-') {
2197 param.fp_stripe_count_sign = 1;
2201 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2202 if (*endptr != '\0') {
2203 fprintf(stderr,"error: bad stripe_count '%s'\n",
2208 param.fp_check_stripe_count = 1;
2209 param.fp_exclude_stripe_count = !!neg_opt;
2212 param.fp_max_depth = strtol(optarg, 0, 0);
2215 if (optarg[0] == '+') {
2216 param.fp_comp_end_sign = -1;
2218 } else if (optarg[0] == '-') {
2219 param.fp_comp_end_sign = 1;
2223 if (arg_is_eof(optarg)) {
2224 param.fp_comp_end = LUSTRE_EOF;
2225 param.fp_comp_end_units = 1;
2228 rc = llapi_parse_size(optarg,
2230 ¶m.fp_comp_end_units, 0);
2233 fprintf(stderr, "error: bad component end "
2237 param.fp_check_comp_end = 1;
2238 param.fp_exclude_comp_end = !!neg_opt;
2242 rc = name2gid(¶m.fp_gid, optarg);
2244 param.fp_gid = strtoul(optarg, &endptr, 10);
2245 if (*endptr != '\0') {
2246 fprintf(stderr, "Group/GID: %s cannot "
2247 "be found.\n", optarg);
2252 param.fp_exclude_gid = !!neg_opt;
2253 param.fp_check_gid = 1;
2256 param.fp_hash_type = check_hashtype(optarg);
2257 if (param.fp_hash_type == 0) {
2258 fprintf(stderr, "error: bad hash_type '%s'\n",
2263 param.fp_check_hash_type = 1;
2264 param.fp_exclude_hash_type = !!neg_opt;
2267 ret = name2layout(¶m.fp_layout, optarg);
2270 param.fp_exclude_layout = !!neg_opt;
2271 param.fp_check_layout = 1;
2275 rc = name2uid(¶m.fp_uid, optarg);
2277 param.fp_uid = strtoul(optarg, &endptr, 10);
2278 if (*endptr != '\0') {
2279 fprintf(stderr, "User/UID: %s cannot "
2280 "be found.\n", optarg);
2285 param.fp_exclude_uid = !!neg_opt;
2286 param.fp_check_uid = 1;
2289 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2291 "Pool name %s is too long"
2292 " (max is %d)\n", optarg,
2297 /* we do check for empty pool because empty pool
2298 * is used to find V1 lov attributes */
2299 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2300 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2301 param.fp_exclude_pool = !!neg_opt;
2302 param.fp_check_pool = 1;
2305 param.fp_pattern = (char *)optarg;
2306 param.fp_exclude_pattern = !!neg_opt;
2311 char *buf, *token, *next, *p;
2315 buf = strdup(optarg);
2321 param.fp_exclude_obd = !!neg_opt;
2324 while (token && *token) {
2325 token = strchr(token, ',');
2332 param.fp_exclude_mdt = !!neg_opt;
2333 param.fp_num_alloc_mdts += len;
2334 tmp = realloc(param.fp_mdt_uuid,
2335 param.fp_num_alloc_mdts *
2336 sizeof(*param.fp_mdt_uuid));
2342 param.fp_mdt_uuid = tmp;
2344 param.fp_exclude_obd = !!neg_opt;
2345 param.fp_num_alloc_obds += len;
2346 tmp = realloc(param.fp_obd_uuid,
2347 param.fp_num_alloc_obds *
2348 sizeof(*param.fp_obd_uuid));
2354 param.fp_obd_uuid = tmp;
2356 for (token = buf; token && *token; token = next) {
2357 struct obd_uuid *puuid;
2360 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2363 ¶m.fp_obd_uuid[param.fp_num_obds++];
2365 p = strchr(token, ',');
2372 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2377 strncpy(puuid->uuid, token,
2378 sizeof(puuid->uuid));
2386 param.fp_zero_end = 1;
2390 case LFS_PROJID_OPT:
2391 rc = name2projid(¶m.fp_projid, optarg);
2393 param.fp_projid = strtoul(optarg, &endptr, 10);
2394 if (*endptr != '\0') {
2396 "Invalid project ID: %s",
2402 param.fp_exclude_projid = !!neg_opt;
2403 param.fp_check_projid = 1;
2406 if (optarg[0] == '+') {
2407 param.fp_size_sign = -1;
2409 } else if (optarg[0] == '-') {
2410 param.fp_size_sign = 1;
2414 ret = llapi_parse_size(optarg, ¶m.fp_size,
2415 ¶m.fp_size_units, 0);
2417 fprintf(stderr, "error: bad file size '%s'\n",
2421 param.fp_check_size = 1;
2422 param.fp_exclude_size = !!neg_opt;
2425 if (optarg[0] == '+') {
2426 param.fp_stripe_size_sign = -1;
2428 } else if (optarg[0] == '-') {
2429 param.fp_stripe_size_sign = 1;
2433 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2434 ¶m.fp_stripe_size_units, 0);
2436 fprintf(stderr, "error: bad stripe_size '%s'\n",
2440 param.fp_check_stripe_size = 1;
2441 param.fp_exclude_stripe_size = !!neg_opt;
2444 param.fp_exclude_type = !!neg_opt;
2445 switch (optarg[0]) {
2447 param.fp_type = S_IFBLK;
2450 param.fp_type = S_IFCHR;
2453 param.fp_type = S_IFDIR;
2456 param.fp_type = S_IFREG;
2459 param.fp_type = S_IFLNK;
2462 param.fp_type = S_IFIFO;
2465 param.fp_type = S_IFSOCK;
2468 fprintf(stderr, "error: %s: bad type '%s'\n",
2475 if (optarg[0] == '+') {
2476 param.fp_mdt_count_sign = -1;
2478 } else if (optarg[0] == '-') {
2479 param.fp_mdt_count_sign = 1;
2483 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2484 if (*endptr != '\0') {
2485 fprintf(stderr, "error: bad mdt_count '%s'\n",
2490 param.fp_check_mdt_count = 1;
2491 param.fp_exclude_mdt_count = !!neg_opt;
2499 if (pathstart == -1) {
2500 fprintf(stderr, "error: %s: no filename|pathname\n",
2504 } else if (pathend == -1) {
2510 rc = llapi_find(argv[pathstart], ¶m);
2511 if (rc != 0 && ret == 0)
2513 } while (++pathstart < pathend);
2516 fprintf(stderr, "error: %s failed for %s.\n",
2517 argv[0], argv[optind - 1]);
2519 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2520 free(param.fp_obd_uuid);
2522 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2523 free(param.fp_mdt_uuid);
2528 static int lfs_getstripe_internal(int argc, char **argv,
2529 struct find_param *param)
2531 struct option long_opts[] = {
2532 { .val = LFS_COMP_COUNT_OPT,
2533 .name = "comp-count", .has_arg = no_argument },
2534 { .val = LFS_COMP_COUNT_OPT,
2535 .name = "component-count", .has_arg = no_argument },
2536 { .val = LFS_COMP_FLAGS_OPT,
2537 .name = "comp-flags", .has_arg = optional_argument },
2538 { .val = LFS_COMP_FLAGS_OPT,
2539 .name = "component-flags", .has_arg = optional_argument },
2540 { .val = LFS_COMP_START_OPT,
2541 .name = "comp-start", .has_arg = optional_argument },
2542 { .val = LFS_COMP_START_OPT,
2543 .name = "component-start", .has_arg = optional_argument },
2544 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2545 /* This formerly implied "stripe-count", but was explicitly
2546 * made "stripe-count" for consistency with other options,
2547 * and to separate it from "mdt-count" when DNE arrives. */
2548 { .val = 'c', .name = "count", .has_arg = no_argument },
2550 { .val = 'c', .name = "stripe-count", .has_arg = no_argument },
2551 { .val = 'c', .name = "stripe_count", .has_arg = no_argument },
2552 { .val = 'd', .name = "directory", .has_arg = no_argument },
2553 { .val = 'D', .name = "default", .has_arg = no_argument },
2554 { .val = 'E', .name = "comp-end", .has_arg = optional_argument },
2555 { .val = 'E', .name = "component-end",
2556 .has_arg = optional_argument },
2557 { .val = 'F', .name = "fid", .has_arg = no_argument },
2558 { .val = 'g', .name = "generation", .has_arg = no_argument },
2559 /* dirstripe { .val = 'H', .name = "mdt-hash",
2560 * .has_arg = required_argument }, */
2561 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2562 /* This formerly implied "stripe-index", but was explicitly
2563 * made "stripe-index" for consistency with other options,
2564 * and to separate it from "mdt-index" when DNE arrives. */
2565 { .val = 'i', .name = "index", .has_arg = no_argument },
2567 { .val = 'i', .name = "stripe-index", .has_arg = no_argument },
2568 { .val = 'i', .name = "stripe_index", .has_arg = no_argument },
2569 { .val = 'I', .name = "comp-id", .has_arg = optional_argument },
2570 { .val = 'I', .name = "component-id", .has_arg = optional_argument },
2571 { .val = 'L', .name = "layout", .has_arg = no_argument },
2572 { .val = 'm', .name = "mdt", .has_arg = no_argument },
2573 { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
2574 { .val = 'm', .name = "mdt_index", .has_arg = no_argument },
2575 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2576 { .val = 'M', .name = "mdt-index", .has_arg = no_argument },
2577 { .val = 'M', .name = "mdt_index", .has_arg = no_argument },
2579 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2580 /* This formerly implied "stripe-index", but was confusing
2581 * with "file offset" (which will eventually be needed for
2582 * with different layouts by offset), so deprecate it. */
2583 { .val = 'o', .name = "offset", .has_arg = no_argument },
2585 { .val = 'O', .name = "obd", .has_arg = required_argument },
2586 { .val = 'O', .name = "ost", .has_arg = required_argument },
2587 { .val = 'p', .name = "pool", .has_arg = no_argument },
2588 { .val = 'q', .name = "quiet", .has_arg = no_argument },
2589 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2590 { .val = 'R', .name = "raw", .has_arg = no_argument },
2591 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2592 /* This formerly implied "--stripe-size", but was confusing
2593 * with "lfs find --size|-s", which means "file size", so use
2594 * the consistent "--stripe-size|-S" for all commands. */
2595 { .val = 's', .name = "size", .has_arg = no_argument },
2597 { .val = 'S', .name = "stripe-size", .has_arg = no_argument },
2598 { .val = 'S', .name = "stripe_size", .has_arg = no_argument },
2599 /* dirstripe { .val = 'T', .name = "mdt-count",
2600 * .has_arg = required_argument }, */
2601 { .val = 'v', .name = "verbose", .has_arg = no_argument },
2602 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2607 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2608 long_opts, NULL)) != -1) {
2611 if (strcmp(argv[optind - 1], "--count") == 0)
2612 fprintf(stderr, "warning: '--count' deprecated,"
2613 " use '--stripe-count' instead\n");
2614 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2615 param->fp_verbose |= VERBOSE_COUNT;
2616 param->fp_max_depth = 0;
2619 case LFS_COMP_COUNT_OPT:
2620 param->fp_verbose |= VERBOSE_COMP_COUNT;
2621 param->fp_max_depth = 0;
2623 case LFS_COMP_FLAGS_OPT:
2624 if (optarg != NULL) {
2625 __u32 *flags = ¶m->fp_comp_flags;
2626 rc = comp_str2flags(flags, optarg);
2628 fprintf(stderr, "error: %s bad "
2629 "component flags '%s'.\n",
2633 param->fp_check_comp_flags = 1;
2634 param->fp_exclude_comp_flags =
2635 comp_flags_is_neg(*flags);
2636 comp_flags_clear_neg(flags);
2639 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2640 param->fp_max_depth = 0;
2643 case LFS_COMP_START_OPT:
2644 if (optarg != NULL) {
2646 if (tmp[0] == '+') {
2647 param->fp_comp_start_sign = -1;
2649 } else if (tmp[0] == '-') {
2650 param->fp_comp_start_sign = 1;
2653 rc = llapi_parse_size(tmp,
2654 ¶m->fp_comp_start,
2655 ¶m->fp_comp_start_units, 0);
2657 fprintf(stderr, "error: %s bad "
2658 "component start '%s'.\n",
2662 param->fp_check_comp_start = 1;
2665 param->fp_verbose |= VERBOSE_COMP_START;
2666 param->fp_max_depth = 0;
2670 param->fp_max_depth = 0;
2673 param->fp_get_default_lmv = 1;
2676 if (optarg != NULL) {
2678 if (tmp[0] == '+') {
2679 param->fp_comp_end_sign = -1;
2681 } else if (tmp[0] == '-') {
2682 param->fp_comp_end_sign = 1;
2686 if (arg_is_eof(tmp)) {
2687 param->fp_comp_end = LUSTRE_EOF;
2688 param->fp_comp_end_units = 1;
2691 rc = llapi_parse_size(tmp,
2692 ¶m->fp_comp_end,
2693 ¶m->fp_comp_end_units, 0);
2696 fprintf(stderr, "error: %s bad "
2697 "component end '%s'.\n",
2701 param->fp_check_comp_end = 1;
2703 param->fp_verbose |= VERBOSE_COMP_END;
2704 param->fp_max_depth = 0;
2708 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2709 param->fp_verbose |= VERBOSE_DFID;
2710 param->fp_max_depth = 0;
2714 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2715 param->fp_verbose |= VERBOSE_GENERATION;
2716 param->fp_max_depth = 0;
2719 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2721 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2722 "use '--stripe-index|-i' instead\n");
2725 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2726 if (strcmp(argv[optind - 1], "--index") == 0)
2727 fprintf(stderr, "warning: '--index' deprecated"
2728 ", use '--stripe-index' instead\n");
2730 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2731 param->fp_verbose |= VERBOSE_OFFSET;
2732 param->fp_max_depth = 0;
2736 if (optarg != NULL) {
2737 param->fp_comp_id = strtoul(optarg, &end, 0);
2738 if (*end != '\0' || param->fp_comp_id == 0 ||
2739 param->fp_comp_id > LCME_ID_MAX) {
2740 fprintf(stderr, "error: %s bad "
2741 "component id '%s'\n",
2745 param->fp_check_comp_id = 1;
2748 param->fp_max_depth = 0;
2749 param->fp_verbose |= VERBOSE_COMP_ID;
2753 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2754 param->fp_verbose |= VERBOSE_LAYOUT;
2755 param->fp_max_depth = 0;
2758 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2760 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2761 fprintf(stderr, "warning: '-M' deprecated"
2762 ", use '-m' instead\n");
2766 if (!(param->fp_verbose & VERBOSE_DETAIL))
2767 param->fp_max_depth = 0;
2768 param->fp_verbose |= VERBOSE_MDTINDEX;
2771 if (param->fp_obd_uuid) {
2773 "error: %s: only one obduuid allowed",
2777 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2780 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2781 param->fp_verbose |= VERBOSE_POOL;
2782 param->fp_max_depth = 0;
2789 param->fp_recursive = 1;
2794 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2796 fprintf(stderr, "warning: '--size|-s' deprecated, "
2797 "use '--stripe-size|-S' instead\n");
2798 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2800 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2801 param->fp_verbose |= VERBOSE_SIZE;
2802 param->fp_max_depth = 0;
2806 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2819 if (param->fp_recursive)
2820 param->fp_max_depth = -1;
2821 else if (param->fp_verbose & VERBOSE_DETAIL)
2822 param->fp_max_depth = 1;
2824 if (!param->fp_verbose)
2825 param->fp_verbose = VERBOSE_DEFAULT;
2826 if (param->fp_quiet)
2827 param->fp_verbose = VERBOSE_OBJID;
2830 rc = llapi_getstripe(argv[optind], param);
2831 } while (++optind < argc && !rc);
2834 fprintf(stderr, "error: %s failed for %s.\n",
2835 argv[0], argv[optind - 1]);
2839 static int lfs_tgts(int argc, char **argv)
2841 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2842 struct find_param param;
2843 int index = 0, rc=0;
2848 if (argc == 2 && !realpath(argv[1], path)) {
2850 fprintf(stderr, "error: invalid path '%s': %s\n",
2851 argv[1], strerror(-rc));
2855 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2856 /* Check if we have a mount point */
2857 if (mntdir[0] == '\0')
2860 memset(¶m, 0, sizeof(param));
2861 if (!strcmp(argv[0], "mdts"))
2862 param.fp_get_lmv = 1;
2864 rc = llapi_ostlist(mntdir, ¶m);
2866 fprintf(stderr, "error: %s: failed on %s\n",
2869 if (path[0] != '\0')
2871 memset(mntdir, 0, PATH_MAX);
2877 static int lfs_getstripe(int argc, char **argv)
2879 struct find_param param = { 0 };
2881 param.fp_max_depth = 1;
2882 return lfs_getstripe_internal(argc, argv, ¶m);
2886 static int lfs_getdirstripe(int argc, char **argv)
2888 struct find_param param = { 0 };
2889 struct option long_opts[] = {
2890 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2891 { .val = 'c', .name = "mdt-count", .has_arg = no_argument },
2893 { .val = 'D', .name = "default", .has_arg = no_argument },
2894 { .val = 'H', .name = "mdt-hash", .has_arg = no_argument },
2895 { .val = 'i', .name = "mdt-index", .has_arg = no_argument },
2896 { .val = 'O', .name = "obd", .has_arg = required_argument },
2897 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2898 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2899 { .val = 't', .name = "mdt-hash", .has_arg = no_argument },
2901 { .val = 'T', .name = "mdt-count", .has_arg = no_argument },
2902 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2906 param.fp_get_lmv = 1;
2908 while ((c = getopt_long(argc, argv,
2909 "cDHiO:rtTy", long_opts, NULL)) != -1)
2913 if (param.fp_obd_uuid) {
2915 "error: %s: only one obduuid allowed",
2919 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2921 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2923 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2924 fprintf(stderr, "warning: '-c' deprecated"
2925 ", use '-T' instead\n");
2929 param.fp_verbose |= VERBOSE_COUNT;
2932 param.fp_verbose |= VERBOSE_OFFSET;
2934 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2938 param.fp_verbose |= VERBOSE_HASH_TYPE;
2941 param.fp_get_default_lmv = 1;
2944 param.fp_recursive = 1;
2957 if (param.fp_recursive)
2958 param.fp_max_depth = -1;
2960 if (!param.fp_verbose)
2961 param.fp_verbose = VERBOSE_DEFAULT;
2964 rc = llapi_getstripe(argv[optind], ¶m);
2965 } while (++optind < argc && !rc);
2968 fprintf(stderr, "error: %s failed for %s.\n",
2969 argv[0], argv[optind - 1]);
2974 static int lfs_setdirstripe(int argc, char **argv)
2978 unsigned int stripe_offset = -1;
2979 unsigned int stripe_count = 1;
2980 enum lmv_hash_type hash_type;
2983 char *stripe_offset_opt = NULL;
2984 char *stripe_count_opt = NULL;
2985 char *stripe_hash_opt = NULL;
2986 char *mode_opt = NULL;
2987 bool default_stripe = false;
2988 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2989 mode_t previous_mode = 0;
2990 bool delete = false;
2992 struct option long_opts[] = {
2993 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2994 { .val = 'c', .name = "count", .has_arg = required_argument },
2996 { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
2997 { .val = 'd', .name = "delete", .has_arg = no_argument },
2998 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2999 { .val = 'i', .name = "index", .has_arg = required_argument },
3001 { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
3002 { .val = 'm', .name = "mode", .has_arg = required_argument },
3003 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3004 { .val = 't', .name = "hash-type", .has_arg = required_argument },
3005 { .val = 't', .name = "mdt-hash", .has_arg = required_argument },
3007 {"mdt-hash", required_argument, 0, 'H'},
3008 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3009 { .val = 'D', .name = "default_stripe",
3010 .has_arg = no_argument },
3012 { .val = 'D', .name = "default", .has_arg = no_argument },
3015 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
3022 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3023 if (strcmp(argv[optind - 1], "--count") == 0)
3025 "%s %s: warning: '--count' deprecated, use '--mdt-count' instead\n",
3028 stripe_count_opt = optarg;
3032 default_stripe = true;
3035 default_stripe = true;
3038 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3039 if (strcmp(argv[optind - 1], "--index") == 0)
3041 "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
3044 stripe_offset_opt = optarg;
3049 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
3053 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
3054 if (strcmp(argv[optind - 1], "--hash-type") == 0)
3056 "%s %s: warning: '--hash-type' deprecated, use '--mdt-hash' instead\n",
3059 stripe_hash_opt = optarg;
3062 fprintf(stderr, "%s %s: unrecognized option '%s'\n",
3063 progname, argv[0], argv[optind - 1]);
3068 if (optind == argc) {
3069 fprintf(stderr, "%s %s: DIR must be specified\n",
3074 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
3076 "%s %s: stripe offset and count must be specified\n",
3081 if (stripe_offset_opt != NULL) {
3082 /* get the stripe offset */
3083 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
3086 "%s %s: bad stripe offset '%s'\n",
3087 progname, argv[0], stripe_offset_opt);
3093 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
3095 "%s %s: cannot specify -d with -c or -i options\n",
3104 if (mode_opt != NULL) {
3105 mode = strtoul(mode_opt, &end, 8);
3108 "%s %s: bad MODE '%s'\n",
3109 progname, argv[0], mode_opt);
3112 previous_mode = umask(0);
3115 if (stripe_hash_opt == NULL) {
3116 hash_type = LMV_HASH_TYPE_FNV_1A_64;
3118 hash_type = check_hashtype(stripe_hash_opt);
3119 if (hash_type == 0) {
3120 fprintf(stderr, "%s %s: bad stripe hash type '%s'\n",
3121 progname, argv[0], stripe_hash_opt);
3126 /* get the stripe count */
3127 if (stripe_count_opt != NULL) {
3128 stripe_count = strtoul(stripe_count_opt, &end, 0);
3131 "%s %s: bad stripe count '%s'\n",
3132 progname, argv[0], stripe_count_opt);
3137 dname = argv[optind];
3139 if (default_stripe) {
3140 result = llapi_dir_set_default_lmv_stripe(dname,
3141 stripe_offset, stripe_count,
3144 result = llapi_dir_create_pool(dname, mode,
3146 stripe_count, hash_type,
3152 "%s setdirstripe: cannot create stripe dir '%s': %s\n",
3153 progname, dname, strerror(-result));
3156 dname = argv[++optind];
3157 } while (dname != NULL);
3159 if (mode_opt != NULL)
3160 umask(previous_mode);
3166 static int lfs_rmentry(int argc, char **argv)
3173 fprintf(stderr, "error: %s: missing dirname\n",
3179 dname = argv[index];
3180 while (dname != NULL) {
3181 result = llapi_direntry_remove(dname);
3183 fprintf(stderr, "error: %s: remove dir entry '%s' "
3184 "failed\n", argv[0], dname);
3187 dname = argv[++index];
3192 static int lfs_mv(int argc, char **argv)
3194 struct find_param param = {
3201 struct option long_opts[] = {
3202 { .val = 'M', .name = "mdt-index", .has_arg = required_argument },
3203 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3206 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3209 param.fp_mdt_index = strtoul(optarg, &end, 0);
3211 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3218 param.fp_verbose = VERBOSE_DETAIL;
3222 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3223 argv[0], argv[optind - 1]);
3228 if (param.fp_mdt_index == -1) {
3229 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3233 if (optind >= argc) {
3234 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3238 param.fp_migrate = 1;
3239 rc = llapi_migrate_mdt(argv[optind], ¶m);
3241 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3242 argv[0], argv[optind], param.fp_mdt_index,
3247 static int lfs_osts(int argc, char **argv)
3249 return lfs_tgts(argc, argv);
3252 static int lfs_mdts(int argc, char **argv)
3254 return lfs_tgts(argc, argv);
3257 #define COOK(value) \
3260 while (value > 1024) { \
3268 #define CDF "%11llu"
3269 #define HDF "%8.1f%c"
3274 MNTDF_INODES = 0x0001,
3275 MNTDF_COOKED = 0x0002,
3276 MNTDF_LAZY = 0x0004,
3277 MNTDF_VERBOSE = 0x0008,
3280 static int showdf(char *mntdir, struct obd_statfs *stat,
3281 char *uuid, enum mntdf_flags flags,
3282 char *type, int index, int rc)
3284 long long avail, used, total;
3286 char *suffix = "KMGTPEZY";
3287 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3288 char tbuf[3 * sizeof(__u64)];
3289 char ubuf[3 * sizeof(__u64)];
3290 char abuf[3 * sizeof(__u64)];
3291 char rbuf[3 * sizeof(__u64)];
3298 if (flags & MNTDF_INODES) {
3299 avail = stat->os_ffree;
3300 used = stat->os_files - stat->os_ffree;
3301 total = stat->os_files;
3303 int shift = flags & MNTDF_COOKED ? 0 : 10;
3305 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3306 used = ((stat->os_blocks - stat->os_bfree) *
3307 stat->os_bsize) >> shift;
3308 total = (stat->os_blocks * stat->os_bsize) >> shift;
3311 if ((used + avail) > 0)
3312 ratio = (double)used / (double)(used + avail);
3314 if (flags & MNTDF_COOKED) {
3318 cook_val = (double)total;
3321 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3324 snprintf(tbuf, sizeof(tbuf), CDF, total);
3326 cook_val = (double)used;
3329 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3332 snprintf(ubuf, sizeof(ubuf), CDF, used);
3334 cook_val = (double)avail;
3337 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3340 snprintf(abuf, sizeof(abuf), CDF, avail);
3342 snprintf(tbuf, sizeof(tbuf), CDF, total);
3343 snprintf(ubuf, sizeof(tbuf), CDF, used);
3344 snprintf(abuf, sizeof(tbuf), CDF, avail);
3347 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3348 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3349 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3351 printf("[%s:%d]", type, index);
3353 if (stat->os_state) {
3355 * Each character represents the matching
3358 const char state_names[] = "DRSI";
3363 for (i = 0, state = stat->os_state;
3364 state && i < sizeof(state_names); i++) {
3365 if (!(state & (1 << i)))
3367 printf("%c", state_names[i]);
3375 printf(UUF": inactive device\n", uuid);
3378 printf(UUF": %s\n", uuid, strerror(-rc));
3385 struct ll_stat_type {
3390 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3392 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3393 struct obd_uuid uuid_buf;
3394 char *poolname = NULL;
3395 struct ll_stat_type types[] = {
3396 { .st_op = LL_STATFS_LMV, .st_name = "MDT" },
3397 { .st_op = LL_STATFS_LOV, .st_name = "OST" },
3398 { .st_name = NULL } };
3399 struct ll_stat_type *tp;
3400 __u64 ost_ffree = 0;
3408 poolname = strchr(pool, '.');
3409 if (poolname != NULL) {
3410 if (strncmp(fsname, pool, strlen(fsname))) {
3411 fprintf(stderr, "filesystem name incorrect\n");
3419 fd = open(mntdir, O_RDONLY);
3422 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3427 if (flags & MNTDF_INODES)
3428 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3429 "UUID", "Inodes", "IUsed", "IFree",
3430 "IUse%", "Mounted on");
3432 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3433 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3434 "Used", "Available", "Use%", "Mounted on");
3436 for (tp = types; tp->st_name != NULL; tp++) {
3437 for (index = 0; ; index++) {
3438 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3439 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3440 type = flags & MNTDF_LAZY ?
3441 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3442 rc2 = llapi_obd_fstatfs(fd, type, index,
3443 &stat_buf, &uuid_buf);
3448 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3449 if (!(flags & MNTDF_VERBOSE))
3451 } else if (rc2 < 0 && rc == 0) {
3455 if (poolname && tp->st_op == LL_STATFS_LOV &&
3456 llapi_search_ost(fsname, poolname,
3457 obd_uuid2str(&uuid_buf)) != 1)
3460 /* the llapi_obd_statfs() call may have returned with
3461 * an error, but if it filled in uuid_buf we will at
3462 * lease use that to print out a message for that OBD.
3463 * If we didn't get anything in the uuid_buf, then fill
3464 * it in so that we can print an error message. */
3465 if (uuid_buf.uuid[0] == '\0')
3466 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3467 "%s%04x", tp->st_name, index);
3468 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3469 flags, tp->st_name, index, rc2);
3472 if (tp->st_op == LL_STATFS_LMV) {
3473 sum.os_ffree += stat_buf.os_ffree;
3474 sum.os_files += stat_buf.os_files;
3475 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3476 sum.os_blocks += stat_buf.os_blocks *
3478 sum.os_bfree += stat_buf.os_bfree *
3480 sum.os_bavail += stat_buf.os_bavail *
3482 ost_ffree += stat_buf.os_ffree;
3490 /* If we don't have as many objects free on the OST as inodes
3491 * on the MDS, we reduce the total number of inodes to
3492 * compensate, so that the "inodes in use" number is correct.
3493 * Matches ll_statfs_internal() so the results are consistent. */
3494 if (ost_ffree < sum.os_ffree) {
3495 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3496 sum.os_ffree = ost_ffree;
3499 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3505 static int lfs_df(int argc, char **argv)
3507 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3508 enum mntdf_flags flags = 0;
3509 int c, rc = 0, index = 0;
3510 char fsname[PATH_MAX] = "", *pool_name = NULL;
3511 struct option long_opts[] = {
3512 { .val = 'h', .name = "human-readable",
3513 .has_arg = no_argument },
3514 { .val = 'i', .name = "inodes", .has_arg = no_argument },
3515 { .val = 'l', .name = "lazy", .has_arg = no_argument },
3516 { .val = 'p', .name = "pool", .has_arg = required_argument },
3517 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3520 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3523 flags |= MNTDF_COOKED;
3526 flags |= MNTDF_INODES;
3529 flags |= MNTDF_LAZY;
3535 flags |= MNTDF_VERBOSE;
3541 if (optind < argc && !realpath(argv[optind], path)) {
3543 fprintf(stderr, "error: invalid path '%s': %s\n",
3544 argv[optind], strerror(-rc));
3548 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3549 /* Check if we have a mount point */
3550 if (mntdir[0] == '\0')
3553 rc = mntdf(mntdir, fsname, pool_name, flags);
3554 if (rc || path[0] != '\0')
3556 fsname[0] = '\0'; /* avoid matching in next loop */
3557 mntdir[0] = '\0'; /* avoid matching in next loop */
3563 static int lfs_getname(int argc, char **argv)
3565 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3566 int rc = 0, index = 0, c;
3567 char buf[sizeof(struct obd_uuid)];
3569 while ((c = getopt(argc, argv, "h")) != -1)
3572 if (optind == argc) { /* no paths specified, get all paths. */
3573 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3574 rc = llapi_getname(mntdir, buf, sizeof(buf));
3577 "cannot get name for `%s': %s\n",
3578 mntdir, strerror(-rc));
3582 printf("%s %s\n", buf, mntdir);
3584 path[0] = fsname[0] = mntdir[0] = 0;
3586 } else { /* paths specified, only attempt to search these. */
3587 for (; optind < argc; optind++) {
3588 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3591 "cannot get name for `%s': %s\n",
3592 argv[optind], strerror(-rc));
3596 printf("%s %s\n", buf, argv[optind]);
3602 static int lfs_check(int argc, char **argv)
3605 char mntdir[PATH_MAX] = {'\0'};
3614 obd_types[0] = obd_type1;
3615 obd_types[1] = obd_type2;
3617 if (strcmp(argv[1], "osts") == 0) {
3618 strcpy(obd_types[0], "osc");
3619 } else if (strcmp(argv[1], "mds") == 0) {
3620 strcpy(obd_types[0], "mdc");
3621 } else if (strcmp(argv[1], "servers") == 0) {
3623 strcpy(obd_types[0], "osc");
3624 strcpy(obd_types[1], "mdc");
3626 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3631 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3632 if (rc < 0 || mntdir[0] == '\0') {
3633 fprintf(stderr, "No suitable Lustre mount found\n");
3637 rc = llapi_target_check(num_types, obd_types, mntdir);
3639 fprintf(stderr, "error: %s: %s status failed\n",
3646 #ifdef HAVE_SYS_QUOTA_H
3647 #define ARG2INT(nr, str, msg) \
3650 nr = strtol(str, &endp, 0); \
3652 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3657 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3659 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3660 * returns the value or ULONG_MAX on integer overflow or incorrect format
3662 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3663 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3664 * 3. empty integer value is interpreted as 0
3666 static unsigned long str2sec(const char* timestr)
3668 const char spec[] = "smhdw";
3669 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3670 unsigned long val = 0;
3673 if (strpbrk(timestr, spec) == NULL) {
3674 /* no specifiers inside the time string,
3675 should treat it as an integer value */
3676 val = strtoul(timestr, &tail, 10);
3677 return *tail ? ULONG_MAX : val;
3680 /* format string is XXwXXdXXhXXmXXs */
3686 v = strtoul(timestr, &tail, 10);
3687 if (v == ULONG_MAX || *tail == '\0')
3688 /* value too large (ULONG_MAX or more)
3689 or missing specifier */
3692 ptr = strchr(spec, *tail);
3694 /* unknown specifier */
3699 /* check if product will overflow the type */
3700 if (!(v < ULONG_MAX / mult[ind]))
3703 ADD_OVERFLOW(val, mult[ind] * v);
3704 if (val == ULONG_MAX)
3716 #define ARG2ULL(nr, str, def_units) \
3718 unsigned long long limit, units = def_units; \
3721 rc = llapi_parse_size(str, &limit, &units, 1); \
3723 fprintf(stderr, "error: bad limit value %s\n", str); \
3729 static inline int has_times_option(int argc, char **argv)
3733 for (i = 1; i < argc; i++)
3734 if (!strcmp(argv[i], "-t"))
3740 int lfs_setquota_times(int argc, char **argv)
3743 struct if_quotactl qctl;
3744 char *mnt, *obd_type = (char *)qctl.obd_type;
3745 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3746 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3747 struct option long_opts[] = {
3748 { .val = 'b', .name = "block-grace", .has_arg = required_argument },
3749 { .val = 'g', .name = "group", .has_arg = no_argument },
3750 { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
3751 { .val = 'p', .name = "projid", .has_arg = no_argument },
3752 { .val = 't', .name = "times", .has_arg = no_argument },
3753 { .val = 'u', .name = "user", .has_arg = no_argument },
3757 memset(&qctl, 0, sizeof(qctl));
3758 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3759 qctl.qc_type = ALLQUOTA;
3761 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3762 long_opts, NULL)) != -1) {
3773 if (qctl.qc_type != ALLQUOTA) {
3774 fprintf(stderr, "error: -u/g/p can't be used "
3775 "more than once\n");
3778 qctl.qc_type = qtype;
3781 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3782 fprintf(stderr, "error: bad block-grace: %s\n",
3786 dqb->dqb_valid |= QIF_BTIME;
3789 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3790 fprintf(stderr, "error: bad inode-grace: %s\n",
3794 dqb->dqb_valid |= QIF_ITIME;
3796 case 't': /* Yes, of course! */
3798 default: /* getopt prints error message for us when opterr != 0 */
3803 if (qctl.qc_type == ALLQUOTA) {
3804 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3808 if (optind != argc - 1) {
3809 fprintf(stderr, "error: unexpected parameters encountered\n");
3814 rc = llapi_quotactl(mnt, &qctl);
3817 fprintf(stderr, "%s %s ", obd_type,
3818 obd_uuid2str(&qctl.obd_uuid));
3819 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3826 #define BSLIMIT (1 << 0)
3827 #define BHLIMIT (1 << 1)
3828 #define ISLIMIT (1 << 2)
3829 #define IHLIMIT (1 << 3)
3831 int lfs_setquota(int argc, char **argv)
3834 struct if_quotactl qctl;
3835 char *mnt, *obd_type = (char *)qctl.obd_type;
3836 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3837 struct option long_opts[] = {
3838 { .val = 'b', .name = "block-softlimit",
3839 .has_arg = required_argument },
3840 { .val = 'B', .name = "block-hardlimit",
3841 .has_arg = required_argument },
3842 { .val = 'g', .name = "group", .has_arg = required_argument },
3843 { .val = 'i', .name = "inode-softlimit",
3844 .has_arg = required_argument },
3845 { .val = 'I', .name = "inode-hardlimit",
3846 .has_arg = required_argument },
3847 { .val = 'p', .name = "projid", .has_arg = required_argument },
3848 { .val = 'u', .name = "user", .has_arg = required_argument },
3850 unsigned limit_mask = 0;
3854 if (has_times_option(argc, argv))
3855 return lfs_setquota_times(argc, argv);
3857 memset(&qctl, 0, sizeof(qctl));
3858 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3859 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3860 * so it can be used as a marker that qc_type
3861 * isn't reinitialized from command line */
3863 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3864 long_opts, NULL)) != -1) {
3868 rc = name2uid(&qctl.qc_id, optarg);
3872 rc = name2gid(&qctl.qc_id, optarg);
3876 rc = name2projid(&qctl.qc_id, optarg);
3878 if (qctl.qc_type != ALLQUOTA) {
3879 fprintf(stderr, "error: -u and -g can't be used"
3880 " more than once\n");
3883 qctl.qc_type = qtype;
3885 qctl.qc_id = strtoul(optarg, &endptr, 10);
3886 if (*endptr != '\0') {
3887 fprintf(stderr, "error: can't find id "
3888 "for name %s\n", optarg);
3894 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3895 dqb->dqb_bsoftlimit >>= 10;
3896 limit_mask |= BSLIMIT;
3897 if (dqb->dqb_bsoftlimit &&
3898 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3899 fprintf(stderr, "warning: block softlimit is "
3900 "smaller than the miminal qunit size, "
3901 "please see the help of setquota or "
3902 "Lustre manual for details.\n");
3905 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3906 dqb->dqb_bhardlimit >>= 10;
3907 limit_mask |= BHLIMIT;
3908 if (dqb->dqb_bhardlimit &&
3909 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3910 fprintf(stderr, "warning: block hardlimit is "
3911 "smaller than the miminal qunit size, "
3912 "please see the help of setquota or "
3913 "Lustre manual for details.\n");
3916 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3917 limit_mask |= ISLIMIT;
3918 if (dqb->dqb_isoftlimit &&
3919 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3920 fprintf(stderr, "warning: inode softlimit is "
3921 "smaller than the miminal qunit size, "
3922 "please see the help of setquota or "
3923 "Lustre manual for details.\n");
3926 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3927 limit_mask |= IHLIMIT;
3928 if (dqb->dqb_ihardlimit &&
3929 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3930 fprintf(stderr, "warning: inode hardlimit is "
3931 "smaller than the miminal qunit size, "
3932 "please see the help of setquota or "
3933 "Lustre manual for details.\n");
3935 default: /* getopt prints error message for us when opterr != 0 */
3940 if (qctl.qc_type == ALLQUOTA) {
3941 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3945 if (limit_mask == 0) {
3946 fprintf(stderr, "error: at least one limit must be specified\n");
3950 if (optind != argc - 1) {
3951 fprintf(stderr, "error: unexpected parameters encountered\n");
3957 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3958 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3959 /* sigh, we can't just set blimits/ilimits */
3960 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3961 .qc_type = qctl.qc_type,
3962 .qc_id = qctl.qc_id};
3964 rc = llapi_quotactl(mnt, &tmp_qctl);
3966 fprintf(stderr, "error: setquota failed while retrieving"
3967 " current quota settings (%s)\n",
3972 if (!(limit_mask & BHLIMIT))
3973 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3974 if (!(limit_mask & BSLIMIT))
3975 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3976 if (!(limit_mask & IHLIMIT))
3977 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3978 if (!(limit_mask & ISLIMIT))
3979 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3981 /* Keep grace times if we have got no softlimit arguments */
3982 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3983 dqb->dqb_valid |= QIF_BTIME;
3984 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3987 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3988 dqb->dqb_valid |= QIF_ITIME;
3989 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3993 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3994 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3996 rc = llapi_quotactl(mnt, &qctl);
3999 fprintf(stderr, "%s %s ", obd_type,
4000 obd_uuid2str(&qctl.obd_uuid));
4001 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
4008 /* Converts seconds value into format string
4009 * result is returned in buf
4011 * 1. result is in descenting order: 1w2d3h4m5s
4012 * 2. zero fields are not filled (except for p. 3): 5d1s
4013 * 3. zero seconds value is presented as "0s"
4015 static char * __sec2str(time_t seconds, char *buf)
4017 const char spec[] = "smhdw";
4018 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
4023 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
4024 c = seconds / mult[i];
4026 if (c > 0 || (i == 0 && buf == tail))
4027 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
4035 static void sec2str(time_t seconds, char *buf, int rc)
4042 tail = __sec2str(seconds, tail);
4044 if (rc && tail - buf < 39) {
4050 static void diff2str(time_t seconds, char *buf, time_t now)
4056 if (seconds <= now) {
4057 strcpy(buf, "none");
4060 __sec2str(seconds - now, buf);
4063 static void print_quota_title(char *name, struct if_quotactl *qctl,
4064 bool human_readable)
4066 printf("Disk quotas for %s %s (%cid %u):\n",
4067 qtype_name(qctl->qc_type), name,
4068 *qtype_name(qctl->qc_type), qctl->qc_id);
4069 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
4070 "Filesystem", human_readable ? "used" : "kbytes",
4071 "quota", "limit", "grace",
4072 "files", "quota", "limit", "grace");
4075 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
4078 snprintf(buf, buflen, "%ju", (uintmax_t)num);
4081 snprintf(buf, buflen, "%5.4gP",
4082 (double)num / ((__u64)1 << 40));
4084 snprintf(buf, buflen, "%5.4gT",
4085 (double)num / (1 << 30));
4087 snprintf(buf, buflen, "%5.4gG",
4088 (double)num / (1 << 20));
4090 snprintf(buf, buflen, "%5.4gM",
4091 (double)num / (1 << 10));
4093 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
4097 #define STRBUF_LEN 32
4098 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
4105 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
4106 int bover = 0, iover = 0;
4107 struct obd_dqblk *dqb = &qctl->qc_dqblk;
4108 char numbuf[3][STRBUF_LEN];
4110 char strbuf[STRBUF_LEN];
4112 if (dqb->dqb_bhardlimit &&
4113 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
4115 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
4116 if (dqb->dqb_btime > now) {
4123 if (dqb->dqb_ihardlimit &&
4124 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
4126 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
4127 if (dqb->dqb_itime > now) {
4135 if (strlen(mnt) > 15)
4136 printf("%s\n%15s", mnt, "");
4138 printf("%15s", mnt);
4141 diff2str(dqb->dqb_btime, timebuf, now);
4143 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
4144 strbuf, sizeof(strbuf), h);
4145 if (rc == -EREMOTEIO)
4146 sprintf(numbuf[0], "%s*", strbuf);
4148 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
4149 "%s" : "[%s]", strbuf);
4151 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
4152 if (type == QC_GENERAL)
4153 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4154 "%s" : "[%s]", strbuf);
4156 sprintf(numbuf[1], "%s", "-");
4158 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4159 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4160 "%s" : "[%s]", strbuf);
4162 printf(" %7s%c %6s %7s %7s",
4163 numbuf[0], bover ? '*' : ' ', numbuf[1],
4164 numbuf[2], bover > 1 ? timebuf : "-");
4167 diff2str(dqb->dqb_itime, timebuf, now);
4169 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4170 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4172 if (type == QC_GENERAL)
4173 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4175 (uintmax_t)dqb->dqb_isoftlimit);
4177 sprintf(numbuf[1], "%s", "-");
4179 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4180 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4182 if (type != QC_OSTIDX)
4183 printf(" %7s%c %6s %7s %7s",
4184 numbuf[0], iover ? '*' : ' ', numbuf[1],
4185 numbuf[2], iover > 1 ? timebuf : "-");
4187 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4190 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4191 qctl->qc_cmd == Q_GETOINFO) {
4195 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4196 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4197 printf("Block grace time: %s; Inode grace time: %s\n",
4198 bgtimebuf, igtimebuf);
4202 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4203 bool h, __u64 *total)
4205 int rc = 0, rc1 = 0, count = 0;
4206 __u32 valid = qctl->qc_valid;
4208 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4210 fprintf(stderr, "can not get %s count: %s\n",
4211 is_mdt ? "mdt": "ost", strerror(-rc));
4215 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4216 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4217 rc = llapi_quotactl(mnt, qctl);
4219 /* It is remote client case. */
4220 if (rc == -EOPNOTSUPP) {
4227 fprintf(stderr, "quotactl %s%d failed.\n",
4228 is_mdt ? "mdt": "ost", qctl->qc_idx);
4232 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4233 qctl->qc_valid, 0, h);
4234 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4235 qctl->qc_dqblk.dqb_bhardlimit;
4238 qctl->qc_valid = valid;
4242 static int lfs_quota(int argc, char **argv)
4245 char *mnt, *name = NULL;
4246 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4247 .qc_type = ALLQUOTA };
4248 char *obd_type = (char *)qctl.obd_type;
4249 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4250 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4251 verbose = 0, pass = 0, quiet = 0, inacc;
4253 __u32 valid = QC_GENERAL, idx = 0;
4254 __u64 total_ialloc = 0, total_balloc = 0;
4255 bool human_readable = false;
4258 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4269 if (qctl.qc_type != ALLQUOTA) {
4270 fprintf(stderr, "error: use either -u or -g\n");
4273 qctl.qc_type = qtype;
4276 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4279 valid = qctl.qc_valid = QC_UUID;
4280 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4283 valid = qctl.qc_valid = QC_MDTIDX;
4284 idx = qctl.qc_idx = atoi(optarg);
4287 valid = qctl.qc_valid = QC_OSTIDX;
4288 idx = qctl.qc_idx = atoi(optarg);
4297 human_readable = true;
4300 fprintf(stderr, "error: %s: option '-%c' "
4301 "unrecognized\n", argv[0], c);
4306 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4307 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4308 optind == argc - 1) {
4310 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4311 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4312 qctl.qc_valid = valid;
4314 qctl.qc_type = pass;
4315 switch (qctl.qc_type) {
4317 qctl.qc_id = geteuid();
4318 rc = uid2name(&name, qctl.qc_id);
4321 qctl.qc_id = getegid();
4322 rc = gid2name(&name, qctl.qc_id);
4332 /* lfs quota -u username /path/to/lustre/mount */
4333 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4334 /* options should be followed by u/g-name and mntpoint */
4335 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4336 fprintf(stderr, "error: missing quota argument(s)\n");
4340 name = argv[optind++];
4341 switch (qctl.qc_type) {
4343 rc = name2uid(&qctl.qc_id, name);
4346 rc = name2gid(&qctl.qc_id, name);
4349 rc = name2projid(&qctl.qc_id, name);
4356 qctl.qc_id = strtoul(name, &endptr, 10);
4357 if (*endptr != '\0') {
4358 fprintf(stderr, "error: can't find id for name: %s\n",
4363 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4364 fprintf(stderr, "error: missing quota info argument(s)\n");
4369 rc1 = llapi_quotactl(mnt, &qctl);
4373 fprintf(stderr, "%s quotas are not enabled.\n",
4374 qtype_name(qctl.qc_type));
4377 fprintf(stderr, "Permission denied.\n");
4380 /* We already got error message. */
4383 fprintf(stderr, "Unexpected quotactl error: %s\n",
4388 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4389 print_quota_title(name, &qctl, human_readable);
4391 if (rc1 && *obd_type)
4392 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4394 if (qctl.qc_valid != QC_GENERAL)
4397 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4398 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4399 (QIF_LIMITS|QIF_USAGE));
4401 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4403 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4405 char strbuf[STRBUF_LEN];
4407 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4409 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4411 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4413 printf("Total allocated inode limit: %ju, total "
4414 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4418 if (rc1 || rc2 || rc3 || inacc)
4419 printf("Some errors happened when getting quota info. "
4420 "Some devices may be not working or deactivated. "
4421 "The data in \"[]\" is inaccurate.\n");
4424 if (pass > 0 && pass < LL_MAXQUOTAS)
4429 #endif /* HAVE_SYS_QUOTA_H! */
4431 static int flushctx_ioctl(char *mp)
4435 fd = open(mp, O_RDONLY);
4437 fprintf(stderr, "flushctx: error open %s: %s\n",
4438 mp, strerror(errno));
4442 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4444 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4445 mp, strerror(errno));
4451 static int lfs_flushctx(int argc, char **argv)
4453 int kdestroy = 0, c;
4454 char mntdir[PATH_MAX] = {'\0'};
4458 while ((c = getopt(argc, argv, "k")) != -1) {
4464 fprintf(stderr, "error: %s: option '-%c' "
4465 "unrecognized\n", argv[0], c);
4471 if ((rc = system("kdestroy > /dev/null")) != 0) {
4472 rc = WEXITSTATUS(rc);
4473 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4477 if (optind >= argc) {
4478 /* flush for all mounted lustre fs. */
4479 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4480 /* Check if we have a mount point */
4481 if (mntdir[0] == '\0')
4484 if (flushctx_ioctl(mntdir))
4487 mntdir[0] = '\0'; /* avoid matching in next loop */
4490 /* flush fs as specified */
4491 while (optind < argc) {
4492 if (flushctx_ioctl(argv[optind++]))
4499 static int lfs_cp(int argc, char **argv)
4501 fprintf(stderr, "remote client copy file(s).\n"
4502 "obsolete, does not support it anymore.\n");
4506 static int lfs_ls(int argc, char **argv)
4508 fprintf(stderr, "remote client lists directory contents.\n"
4509 "obsolete, does not support it anymore.\n");
4513 static int lfs_changelog(int argc, char **argv)
4515 void *changelog_priv;
4516 struct changelog_rec *rec;
4517 long long startrec = 0, endrec = 0;
4519 struct option long_opts[] = {
4520 { .val = 'f', .name = "follow", .has_arg = no_argument },
4522 char short_opts[] = "f";
4525 while ((rc = getopt_long(argc, argv, short_opts,
4526 long_opts, NULL)) != -1) {
4534 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4535 argv[0], argv[optind - 1]);
4542 mdd = argv[optind++];
4544 startrec = strtoll(argv[optind++], NULL, 10);
4546 endrec = strtoll(argv[optind++], NULL, 10);
4548 rc = llapi_changelog_start(&changelog_priv,
4549 CHANGELOG_FLAG_BLOCK |
4550 CHANGELOG_FLAG_JOBID |
4551 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4554 fprintf(stderr, "Can't start changelog: %s\n",
4555 strerror(errno = -rc));
4559 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4563 if (endrec && rec->cr_index > endrec) {
4564 llapi_changelog_free(&rec);
4567 if (rec->cr_index < startrec) {
4568 llapi_changelog_free(&rec);
4572 secs = rec->cr_time >> 30;
4573 gmtime_r(&secs, &ts);
4574 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4575 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4576 changelog_type2str(rec->cr_type),
4577 ts.tm_hour, ts.tm_min, ts.tm_sec,
4578 (int)(rec->cr_time & ((1 << 30) - 1)),
4579 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4580 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4582 if (rec->cr_flags & CLF_JOBID) {
4583 struct changelog_ext_jobid *jid =
4584 changelog_rec_jobid(rec);
4586 if (jid->cr_jobid[0] != '\0')
4587 printf(" j=%s", jid->cr_jobid);
4590 if (rec->cr_namelen)
4591 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4592 rec->cr_namelen, changelog_rec_name(rec));
4594 if (rec->cr_flags & CLF_RENAME) {
4595 struct changelog_ext_rename *rnm =
4596 changelog_rec_rename(rec);
4598 if (!fid_is_zero(&rnm->cr_sfid))
4599 printf(" s="DFID" sp="DFID" %.*s",
4600 PFID(&rnm->cr_sfid),
4601 PFID(&rnm->cr_spfid),
4602 (int)changelog_rec_snamelen(rec),
4603 changelog_rec_sname(rec));
4607 llapi_changelog_free(&rec);
4610 llapi_changelog_fini(&changelog_priv);
4613 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4615 return (rc == 1 ? 0 : rc);
4618 static int lfs_changelog_clear(int argc, char **argv)
4626 endrec = strtoll(argv[3], NULL, 10);
4628 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4631 fprintf(stderr, "%s: record out of range: %llu\n",
4633 else if (rc == -ENOENT)
4634 fprintf(stderr, "%s: no changelog user: %s\n",
4637 fprintf(stderr, "%s error: %s\n", argv[0],
4646 static int lfs_fid2path(int argc, char **argv)
4648 struct option long_opts[] = {
4649 { .val = 'c', .name = "cur", .has_arg = no_argument },
4650 { .val = 'l', .name = "link", .has_arg = required_argument },
4651 { .val = 'r', .name = "rec", .has_arg = required_argument },
4653 char short_opts[] = "cl:r:";
4654 char *device, *fid, *path;
4655 long long recno = -1;
4661 while ((rc = getopt_long(argc, argv, short_opts,
4662 long_opts, NULL)) != -1) {
4668 linkno = strtol(optarg, NULL, 10);
4671 recno = strtoll(optarg, NULL, 10);
4676 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4677 argv[0], argv[optind - 1]);
4685 device = argv[optind++];
4686 path = calloc(1, PATH_MAX);
4688 fprintf(stderr, "error: Not enough memory\n");
4693 while (optind < argc) {
4694 fid = argv[optind++];
4696 lnktmp = (linkno >= 0) ? linkno : 0;
4698 int oldtmp = lnktmp;
4699 long long rectmp = recno;
4701 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4704 fprintf(stderr, "%s: error on FID %s: %s\n",
4705 argv[0], fid, strerror(errno = -rc2));
4712 fprintf(stdout, "%lld ", rectmp);
4713 if (device[0] == '/') {
4714 fprintf(stdout, "%s", device);
4715 if (device[strlen(device) - 1] != '/')
4716 fprintf(stdout, "/");
4717 } else if (path[0] == '\0') {
4718 fprintf(stdout, "/");
4720 fprintf(stdout, "%s\n", path);
4723 /* specified linkno */
4725 if (oldtmp == lnktmp)
4735 static int lfs_path2fid(int argc, char **argv)
4737 struct option long_opts[] = {
4738 { .val = 'p', .name = "parents", .has_arg = no_argument },
4741 const char short_opts[] = "p";
4742 const char *sep = "";
4745 bool show_parents = false;
4747 while ((rc = getopt_long(argc, argv, short_opts,
4748 long_opts, NULL)) != -1) {
4751 show_parents = true;
4754 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4755 argv[0], argv[optind - 1]);
4760 if (optind > argc - 1)
4762 else if (optind < argc - 1)
4766 for (path = argv + optind; *path != NULL; path++) {
4768 if (!show_parents) {
4769 err = llapi_path2fid(*path, &fid);
4771 printf("%s%s"DFID"\n",
4772 *sep != '\0' ? *path : "", sep,
4775 char name[NAME_MAX + 1];
4776 unsigned int linkno = 0;
4778 while ((err = llapi_path2parent(*path, linkno, &fid,
4779 name, sizeof(name))) == 0) {
4780 if (*sep != '\0' && linkno == 0)
4781 printf("%s%s", *path, sep);
4783 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4788 /* err == -ENODATA is end-of-loop */
4789 if (linkno > 0 && err == -ENODATA) {
4796 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4797 argv[0], show_parents ? "parent " : "", *path,
4809 static int lfs_data_version(int argc, char **argv)
4816 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4821 while ((c = getopt(argc, argv, "nrw")) != -1) {
4824 data_version_flags = 0;
4827 data_version_flags |= LL_DV_RD_FLUSH;
4830 data_version_flags |= LL_DV_WR_FLUSH;
4839 path = argv[optind];
4840 fd = open(path, O_RDONLY);
4842 err(errno, "cannot open file %s", path);
4844 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4846 err(errno, "cannot get version for %s", path);
4848 printf("%ju" "\n", (uintmax_t)data_version);
4854 static int lfs_hsm_state(int argc, char **argv)
4859 struct hsm_user_state hus;
4867 rc = llapi_hsm_state_get(path, &hus);
4869 fprintf(stderr, "can't get hsm state for %s: %s\n",
4870 path, strerror(errno = -rc));
4874 /* Display path name and status flags */
4875 printf("%s: (0x%08x)", path, hus.hus_states);
4877 if (hus.hus_states & HS_RELEASED)
4878 printf(" released");
4879 if (hus.hus_states & HS_EXISTS)
4881 if (hus.hus_states & HS_DIRTY)
4883 if (hus.hus_states & HS_ARCHIVED)
4884 printf(" archived");
4885 /* Display user-settable flags */
4886 if (hus.hus_states & HS_NORELEASE)
4887 printf(" never_release");
4888 if (hus.hus_states & HS_NOARCHIVE)
4889 printf(" never_archive");
4890 if (hus.hus_states & HS_LOST)
4891 printf(" lost_from_hsm");
4893 if (hus.hus_archive_id != 0)
4894 printf(", archive_id:%d", hus.hus_archive_id);
4897 } while (++i < argc);
4902 #define LFS_HSM_SET 0
4903 #define LFS_HSM_CLEAR 1
4906 * Generic function to set or clear HSM flags.
4907 * Used by hsm_set and hsm_clear.
4909 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4911 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4913 struct option long_opts[] = {
4914 { .val = 'A', .name = "archived", .has_arg = no_argument },
4915 { .val = 'a', .name = "noarchive", .has_arg = no_argument },
4916 { .val = 'd', .name = "dirty", .has_arg = no_argument },
4917 { .val = 'e', .name = "exists", .has_arg = no_argument },
4918 { .val = 'l', .name = "lost", .has_arg = no_argument },
4919 { .val = 'r', .name = "norelease", .has_arg = no_argument },
4921 char short_opts[] = "lraAde";
4929 while ((c = getopt_long(argc, argv, short_opts,
4930 long_opts, NULL)) != -1) {
4936 mask |= HS_NOARCHIVE;
4939 mask |= HS_ARCHIVED;
4942 mask |= HS_NORELEASE;
4953 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4954 argv[0], argv[optind - 1]);
4959 /* User should have specified a flag */
4963 while (optind < argc) {
4965 path = argv[optind];
4967 /* If mode == 0, this means we apply the mask. */
4968 if (mode == LFS_HSM_SET)
4969 rc = llapi_hsm_state_set(path, mask, 0, 0);
4971 rc = llapi_hsm_state_set(path, 0, mask, 0);
4974 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4975 path, strerror(errno = -rc));
4984 static int lfs_hsm_action(int argc, char **argv)
4989 struct hsm_current_action hca;
4990 struct hsm_extent he;
4991 enum hsm_user_action hua;
4992 enum hsm_progress_states hps;
5000 rc = llapi_hsm_current_action(path, &hca);
5002 fprintf(stderr, "can't get hsm action for %s: %s\n",
5003 path, strerror(errno = -rc));
5006 he = hca.hca_location;
5007 hua = hca.hca_action;
5008 hps = hca.hca_state;
5010 printf("%s: %s", path, hsm_user_action2name(hua));
5012 /* Skip file without action */
5013 if (hca.hca_action == HUA_NONE) {
5018 printf(" %s ", hsm_progress_state2name(hps));
5020 if ((hps == HPS_RUNNING) &&
5021 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
5022 printf("(%llu bytes moved)\n",
5023 (unsigned long long)he.length);
5024 else if ((he.offset + he.length) == LUSTRE_EOF)
5025 printf("(from %llu to EOF)\n",
5026 (unsigned long long)he.offset);
5028 printf("(from %llu to %llu)\n",
5029 (unsigned long long)he.offset,
5030 (unsigned long long)(he.offset + he.length));
5032 } while (++i < argc);
5037 static int lfs_hsm_set(int argc, char **argv)
5039 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
5042 static int lfs_hsm_clear(int argc, char **argv)
5044 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
5048 * Check file state and return its fid, to be used by lfs_hsm_request().
5050 * \param[in] file Path to file to check
5051 * \param[in,out] fid Pointer to allocated lu_fid struct.
5052 * \param[in,out] last_dev Pointer to last device id used.
5054 * \return 0 on success.
5056 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
5062 rc = lstat(file, &st);
5064 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
5067 /* Checking for regular file as archiving as posix copytool
5068 * rejects archiving files other than regular files
5070 if (!S_ISREG(st.st_mode)) {
5071 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
5074 /* A request should be ... */
5075 if (*last_dev != st.st_dev && *last_dev != 0) {
5076 fprintf(stderr, "All files should be "
5077 "on the same filesystem: %s\n", file);
5080 *last_dev = st.st_dev;
5082 rc = llapi_path2fid(file, fid);
5084 fprintf(stderr, "Cannot read FID of %s: %s\n",
5085 file, strerror(-rc));
5091 /* Fill an HSM HUR item with a given file name.
5093 * If mntpath is set, then the filename is actually a FID, and no
5094 * lookup on the filesystem will be performed.
5096 * \param[in] hur the user request to fill
5097 * \param[in] idx index of the item inside the HUR to fill
5098 * \param[in] mntpath mountpoint of Lustre
5099 * \param[in] fname filename (if mtnpath is NULL)
5100 * or FID (if mntpath is set)
5101 * \param[in] last_dev pointer to last device id used
5103 * \retval 0 on success
5104 * \retval CMD_HELP or a negative errno on error
5106 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
5107 const char *mntpath, const char *fname,
5110 struct hsm_user_item *hui = &hur->hur_user_item[idx];
5113 hui->hui_extent.length = -1;
5115 if (mntpath != NULL) {
5118 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
5122 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
5127 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
5131 hur->hur_request.hr_itemcount++;
5136 static int lfs_hsm_request(int argc, char **argv, int action)
5138 struct option long_opts[] = {
5139 { .val = 'a', .name = "archive", .has_arg = required_argument },
5140 { .val = 'D', .name = "data", .has_arg = required_argument },
5141 { .val = 'l', .name = "filelist", .has_arg = required_argument },
5142 { .val = 'm', .name = "mntpath", .has_arg = required_argument },
5145 char short_opts[] = "l:D:a:m:";
5146 struct hsm_user_request *hur, *oldhur;
5151 char *filelist = NULL;
5152 char fullpath[PATH_MAX];
5153 char *opaque = NULL;
5157 int nbfile_alloc = 0;
5158 char *some_file = NULL;
5159 char *mntpath = NULL;
5165 while ((c = getopt_long(argc, argv, short_opts,
5166 long_opts, NULL)) != -1) {
5175 if (action != HUA_ARCHIVE &&
5176 action != HUA_REMOVE) {
5178 "error: -a is supported only "
5179 "when archiving or removing\n");
5182 archive_id = atoi(optarg);
5185 if (some_file == NULL) {
5187 some_file = strdup(optarg);
5193 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5194 argv[0], argv[optind - 1]);
5199 /* All remaining args are files, so we have at least nbfile */
5200 nbfile = argc - optind;
5202 if ((nbfile == 0) && (filelist == NULL))
5206 opaque_len = strlen(opaque);
5208 /* Alloc the request structure with enough place to store all files
5209 * from command line. */
5210 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5212 fprintf(stderr, "Cannot create the request: %s\n",
5216 nbfile_alloc = nbfile;
5218 hur->hur_request.hr_action = action;
5219 hur->hur_request.hr_archive_id = archive_id;
5220 hur->hur_request.hr_flags = 0;
5222 /* All remaining args are files, add them */
5223 if (nbfile != 0 && some_file == NULL)
5224 some_file = strdup(argv[optind]);
5226 for (i = 0; i < nbfile; i++) {
5227 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5233 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5235 /* If a filelist was specified, read the filelist from it. */
5236 if (filelist != NULL) {
5237 fp = fopen(filelist, "r");
5239 fprintf(stderr, "Cannot read the file list %s: %s\n",
5240 filelist, strerror(errno));
5245 while ((rc = getline(&line, &len, fp)) != -1) {
5246 /* If allocated buffer was too small, get something
5248 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5251 nbfile_alloc = nbfile_alloc * 2 + 1;
5253 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5256 fprintf(stderr, "hsm: cannot allocate "
5257 "the request: %s\n",
5264 size = hur_len(oldhur);
5266 fprintf(stderr, "hsm: cannot allocate "
5267 "%u files + %u bytes data\n",
5268 oldhur->hur_request.hr_itemcount,
5269 oldhur->hur_request.hr_data_len);
5276 memcpy(hur, oldhur, size);
5281 if (line[strlen(line) - 1] == '\n')
5282 line[strlen(line) - 1] = '\0';
5284 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5285 mntpath, line, &last_dev);
5291 if (some_file == NULL) {
5301 /* If a --data was used, add it to the request */
5302 hur->hur_request.hr_data_len = opaque_len;
5304 memcpy(hur_data(hur), opaque, opaque_len);
5306 /* Send the HSM request */
5307 if (realpath(some_file, fullpath) == NULL) {
5308 fprintf(stderr, "Could not find path '%s': %s\n",
5309 some_file, strerror(errno));
5311 rc = llapi_hsm_request(fullpath, hur);
5313 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5314 some_file, strerror(-rc));
5324 static int lfs_hsm_archive(int argc, char **argv)
5326 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5329 static int lfs_hsm_restore(int argc, char **argv)
5331 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5334 static int lfs_hsm_release(int argc, char **argv)
5336 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5339 static int lfs_hsm_remove(int argc, char **argv)
5341 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5344 static int lfs_hsm_cancel(int argc, char **argv)
5346 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5349 static int lfs_swap_layouts(int argc, char **argv)
5354 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5355 SWAP_LAYOUTS_KEEP_MTIME |
5356 SWAP_LAYOUTS_KEEP_ATIME);
5359 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5361 static const char *const lock_mode_names[] = LOCK_MODE_NAMES;
5363 static const char *const lockahead_results[] = {
5364 [LLA_RESULT_SENT] = "Lock request sent",
5365 [LLA_RESULT_DIFFERENT] = "Different matching lock found",
5366 [LLA_RESULT_SAME] = "Matching lock on identical extent found",
5369 int lfs_get_mode(const char *string)
5371 enum lock_mode_user mode;
5373 for (mode = 0; mode < ARRAY_SIZE(lock_mode_names); mode++) {
5374 if (lock_mode_names[mode] == NULL)
5376 if (strcmp(string, lock_mode_names[mode]) == 0)
5383 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5385 enum lu_ladvise_type advice;
5388 advice < ARRAY_SIZE(ladvise_names); advice++) {
5389 if (ladvise_names[advice] == NULL)
5391 if (strcmp(string, ladvise_names[advice]) == 0)
5395 return LU_LADVISE_INVALID;
5398 static int lfs_ladvise(int argc, char **argv)
5400 struct option long_opts[] = {
5401 { .val = 'a', .name = "advice", .has_arg = required_argument },
5402 { .val = 'b', .name = "background", .has_arg = no_argument },
5403 { .val = 'e', .name = "end", .has_arg = required_argument },
5404 { .val = 'l', .name = "length", .has_arg = required_argument },
5405 { .val = 'm', .name = "mode", .has_arg = required_argument },
5406 { .val = 's', .name = "start", .has_arg = required_argument },
5407 { .val = 'u', .name = "unset", .has_arg = no_argument },
5409 char short_opts[] = "a:be:l:m:s:u";
5414 struct llapi_lu_ladvise advice;
5415 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5416 unsigned long long start = 0;
5417 unsigned long long end = LUSTRE_EOF;
5418 unsigned long long length = 0;
5419 unsigned long long size_units;
5420 unsigned long long flags = 0;
5424 while ((c = getopt_long(argc, argv, short_opts,
5425 long_opts, NULL)) != -1) {
5428 advice_type = lfs_get_ladvice(optarg);
5429 if (advice_type == LU_LADVISE_INVALID) {
5430 fprintf(stderr, "%s: invalid advice type "
5431 "'%s'\n", argv[0], optarg);
5432 fprintf(stderr, "Valid types:");
5434 for (advice_type = 0;
5435 advice_type < ARRAY_SIZE(ladvise_names);
5437 if (ladvise_names[advice_type] == NULL)
5439 fprintf(stderr, " %s",
5440 ladvise_names[advice_type]);
5442 fprintf(stderr, "\n");
5455 rc = llapi_parse_size(optarg, &end,
5458 fprintf(stderr, "%s: bad end offset '%s'\n",
5465 rc = llapi_parse_size(optarg, &start,
5468 fprintf(stderr, "%s: bad start offset "
5469 "'%s'\n", argv[0], optarg);
5475 rc = llapi_parse_size(optarg, &length,
5478 fprintf(stderr, "%s: bad length '%s'\n",
5484 mode = lfs_get_mode(optarg);
5486 fprintf(stderr, "%s: bad mode '%s', valid "
5487 "modes are READ or WRITE\n",
5495 fprintf(stderr, "%s: option '%s' unrecognized\n",
5496 argv[0], argv[optind - 1]);
5501 if (advice_type == LU_LADVISE_INVALID) {
5502 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5503 fprintf(stderr, "Valid types:");
5504 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5506 if (ladvise_names[advice_type] == NULL)
5508 fprintf(stderr, " %s", ladvise_names[advice_type]);
5510 fprintf(stderr, "\n");
5514 if (advice_type == LU_LADVISE_LOCKNOEXPAND) {
5515 fprintf(stderr, "%s: Lock no expand advice is a per file "
5516 "descriptor advice, so when called from lfs, "
5517 "it does nothing.\n", argv[0]);
5521 if (argc <= optind) {
5522 fprintf(stderr, "%s: please give one or more file names\n",
5527 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5528 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5533 if (end == LUSTRE_EOF && length != 0)
5534 end = start + length;
5537 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5538 argv[0], start, end);
5542 if (advice_type != LU_LADVISE_LOCKAHEAD && mode != 0) {
5543 fprintf(stderr, "%s: mode is only valid with lockahead\n",
5548 if (advice_type == LU_LADVISE_LOCKAHEAD && mode == 0) {
5549 fprintf(stderr, "%s: mode is required with lockahead\n",
5554 while (optind < argc) {
5557 path = argv[optind++];
5559 fd = open(path, O_RDONLY);
5561 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5562 argv[0], path, strerror(errno));
5567 advice.lla_start = start;
5568 advice.lla_end = end;
5569 advice.lla_advice = advice_type;
5570 advice.lla_value1 = 0;
5571 advice.lla_value2 = 0;
5572 advice.lla_value3 = 0;
5573 advice.lla_value4 = 0;
5574 if (advice_type == LU_LADVISE_LOCKAHEAD) {
5575 advice.lla_lockahead_mode = mode;
5576 advice.lla_peradvice_flags = flags;
5579 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5582 fprintf(stderr, "%s: cannot give advice '%s' to file "
5583 "'%s': %s\n", argv[0],
5584 ladvise_names[advice_type],
5585 path, strerror(errno));
5591 if (rc == 0 && rc2 < 0)
5597 static int lfs_list_commands(int argc, char **argv)
5599 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5601 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5606 int main(int argc, char **argv)
5610 /* Ensure that liblustreapi constructor has run */
5611 if (!liblustreapi_initialized)
5612 fprintf(stderr, "liblustreapi was not properly initialized\n");
5617 Parser_init("lfs > ", cmdlist);
5619 progname = argv[0]; /* Used in error messages */
5621 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5623 rc = Parser_commands();
5625 return rc < 0 ? -rc : rc;
5628 #ifdef _LUSTRE_IDL_H_
5629 /* Everything we need here should be included by lustreapi.h. */
5630 # error "lfs should not depend on lustre_idl.h"
5631 #endif /* _LUSTRE_IDL_H_ */