4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
57 #include <sys/types.h>
64 #include <libcfs/util/string.h>
65 #include <libcfs/util/ioctl.h>
66 #include <libcfs/util/parser.h>
67 #include <lustre/lustreapi.h>
68 #include <linux/lustre/lustre_ver.h>
69 #include <linux/lustre/lustre_param.h>
72 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
73 #endif /* !ARRAY_SIZE */
76 static int lfs_setstripe(int argc, char **argv);
77 static int lfs_find(int argc, char **argv);
78 static int lfs_getstripe(int argc, char **argv);
79 static int lfs_getdirstripe(int argc, char **argv);
80 static int lfs_setdirstripe(int argc, char **argv);
81 static int lfs_rmentry(int argc, char **argv);
82 static int lfs_osts(int argc, char **argv);
83 static int lfs_mdts(int argc, char **argv);
84 static int lfs_df(int argc, char **argv);
85 static int lfs_getname(int argc, char **argv);
86 static int lfs_check(int argc, char **argv);
87 #ifdef HAVE_SYS_QUOTA_H
88 static int lfs_setquota(int argc, char **argv);
89 static int lfs_quota(int argc, char **argv);
91 static int lfs_flushctx(int argc, char **argv);
92 static int lfs_cp(int argc, char **argv);
93 static int lfs_ls(int argc, char **argv);
94 static int lfs_poollist(int argc, char **argv);
95 static int lfs_changelog(int argc, char **argv);
96 static int lfs_changelog_clear(int argc, char **argv);
97 static int lfs_fid2path(int argc, char **argv);
98 static int lfs_path2fid(int argc, char **argv);
99 static int lfs_data_version(int argc, char **argv);
100 static int lfs_hsm_state(int argc, char **argv);
101 static int lfs_hsm_set(int argc, char **argv);
102 static int lfs_hsm_clear(int argc, char **argv);
103 static int lfs_hsm_action(int argc, char **argv);
104 static int lfs_hsm_archive(int argc, char **argv);
105 static int lfs_hsm_restore(int argc, char **argv);
106 static int lfs_hsm_release(int argc, char **argv);
107 static int lfs_hsm_remove(int argc, char **argv);
108 static int lfs_hsm_cancel(int argc, char **argv);
109 static int lfs_swap_layouts(int argc, char **argv);
110 static int lfs_mv(int argc, char **argv);
111 static int lfs_ladvise(int argc, char **argv);
112 static int lfs_list_commands(int argc, char **argv);
114 /* Setstripe and migrate share mostly the same parameters */
115 #define SSM_CMD_COMMON(cmd) \
116 "usage: "cmd" [--stripe-count|-c <stripe_count>]\n" \
117 " [--stripe-index|-i <start_ost_idx>]\n" \
118 " [--stripe-size|-S <stripe_size>]\n" \
119 " [--pool|-p <pool_name>]\n" \
120 " [--ost|-o <ost_indices>]\n" \
121 " [--component-end|-E <comp_end>]\n"
123 #define SSM_HELP_COMMON \
124 "\tstripe_size: Number of bytes on each OST (0 filesystem default)\n" \
125 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
126 "\t respectively)\n" \
127 "\tstart_ost_idx: OST index of first stripe (-1 default)\n" \
128 "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
129 "\tpool_name: Name of OST pool to use (default none)\n" \
130 "\tost_indices: List of OST indices, can be repeated multiple times\n"\
131 "\t Indices be specified in a format of:\n" \
132 "\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
134 "\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
135 "\t If --pool is set with --ost, then the OSTs\n" \
136 "\t must be the members of the pool." \
137 "\tcomp_end: Extent end of the component\n" \
138 "\t Can be specified with k, m or g (in KB, MB and GB\n" \
139 "\t respectively, -1 for EOF), it must be aligned with\n"\
140 "\t the stripe_size\n"
142 #define SETSTRIPE_USAGE \
143 SSM_CMD_COMMON("setstripe") \
144 " <directory|filename>\n" \
147 #define MIGRATE_USAGE \
148 SSM_CMD_COMMON("migrate ") \
150 " [--non-block|-n]\n" \
154 "\tblock: Block file access during data migration (default)\n" \
155 "\tnon-block: Abort migrations if concurrent access is detected\n" \
157 #define SETDIRSTRIPE_USAGE \
158 " [--mdt-count|-c stripe_count>\n" \
159 " [--mdt-index|-i mdt_index]\n" \
160 " [--mdt-hash|-H mdt_hash]\n" \
161 " [--default|-D] [--mode|-m mode] <dir>\n" \
162 "\tstripe_count: stripe count of the striped directory\n" \
163 "\tmdt_index: MDT index of first stripe\n" \
164 "\tmdt_hash: hash type of the striped directory. mdt types:\n" \
165 " fnv_1a_64 FNV-1a hash algorithm (default)\n" \
166 " all_char sum of characters % MDT_COUNT (not recommended)\n" \
167 "\tdefault_stripe: set default dirstripe of the directory\n" \
168 "\tmode: the mode of the directory\n"
170 static const char *progname;
171 static bool file_lease_supported = true;
173 /* all available commands */
174 command_t cmdlist[] = {
175 {"setstripe", lfs_setstripe, 0,
176 "Create a new file with a specific striping pattern or\n"
177 "set the default striping pattern on an existing directory or\n"
178 "delete the default striping pattern from an existing directory or\n"
179 "add layout component(s) to an existing composite file or\n"
180 "delete specified component(s) from an existing composite file\n\n"
181 "To delete default striping from an existing directory:\n"
182 "usage: setstripe -d <directory>\n"
184 "To delete component(s) from an existing composite file:\n"
185 "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
186 " [--component-flags|-F <comp_flags>]\n"
188 "\tcomp_id: Unique component ID\n"
189 "\tcomp_flags: 'init' indicating all instantiated components\n"
190 "\t '^init' indicating all uninstantiated components\n"
191 "\t-I and -F can't be specified at the same time\n"
193 "To add component(s) to an existing composite file:\n"
194 SSM_CMD_COMMON("setstripe --component-add")
196 "To create a file with specified striping/composite layout:\n"
198 {"getstripe", lfs_getstripe, 0,
199 "To list the striping info for a given file or files in a\n"
200 "directory or recursively for all files in a directory tree.\n"
201 "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
202 " [--stripe-count|-c] [--stripe-index|-i]\n"
203 " [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
204 " [--mdt|-m] [--recursive|-r] [--raw|-R] [--yaml|-y]\n"
205 " [--layout|-L] [--fid|-F] [--generation|-g]\n"
206 " [--component-id[=comp_id]|-I[comp_id]]\n"
207 " [--component-flags[=comp_flags]]\n"
208 " [--component-count]\n"
209 " [--component-start[=[+-]comp_start]]\n"
210 " [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
211 " <directory|filename> ..."},
212 {"setdirstripe", lfs_setdirstripe, 0,
213 "To create a striped directory on a specified MDT. This can only\n"
214 "be done on MDT0 with the right of administrator.\n"
215 "usage: setdirstripe [OPTION] <directory>\n"
217 {"getdirstripe", lfs_getdirstripe, 0,
218 "To list the striping info for a given directory\n"
219 "or recursively for all directories in a directory tree.\n"
220 "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
221 " [--mdt-index|-i] [--mdt-hash|-t]\n"
222 " [--recursive|-r] [--yaml|-y]\n"
223 " [--default|-D] <dir> ..."},
224 {"mkdir", lfs_setdirstripe, 0,
225 "To create a striped directory on a specified MDT. This can only\n"
226 "be done on MDT0 with the right of administrator.\n"
227 "usage: mkdir [OPTION] <directory>\n"
229 {"rm_entry", lfs_rmentry, 0,
230 "To remove the name entry of the remote directory. Note: This\n"
231 "command will only delete the name entry, i.e. the remote directory\n"
232 "will become inaccessable after this command. This can only be done\n"
233 "by the administrator\n"
234 "usage: rm_entry <dir>\n"},
235 {"pool_list", lfs_poollist, 0,
236 "List pools or pool OSTs\n"
237 "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
238 {"find", lfs_find, 0,
239 "find files matching given attributes recursively in directory tree.\n"
240 "usage: find <directory|filename> ...\n"
241 " [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
242 " [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
243 " [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
244 " [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
245 " [[!] --size|-s [+-]N[bkMGTPE]]\n"
246 " [[!] --stripe-count|-c [+-]<stripes>]\n"
247 " [[!] --stripe-index|-i <index,...>]\n"
248 " [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
249 " [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
250 " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
251 " [[!] --projid <projid>]\n"
252 " [[!] --layout|-L released,raid0]\n"
253 " [[!] --component-count [+-]<comp_cnt>]\n"
254 " [[!] --component-start [+-]N[kMGTPE]]\n"
255 " [[!] --component-end|-E [+-]N[kMGTPE]]\n"
256 " [[!] --component-flags <comp_flags>]\n"
257 " [[!] --mdt-count|-T [+-]<stripes>]\n"
258 " [[!] --mdt-hash|-H <hashtype>\n"
259 "\t !: used before an option indicates 'NOT' requested attribute\n"
260 "\t -: used before a value indicates less than requested value\n"
261 "\t +: used before a value indicates more than requested value\n"
262 "\tmdt-hash: hash type of the striped directory.\n"
263 "\t fnv_1a_64 FNV-1a hash algorithm\n"
264 "\t all_char sum of characters % MDT_COUNT\n"},
265 {"check", lfs_check, 0,
266 "Display the status of MDS or OSTs (as specified in the command)\n"
267 "or all the servers (MDS and OSTs).\n"
268 "usage: check <osts|mds|servers>"},
269 {"osts", lfs_osts, 0, "list OSTs connected to client "
270 "[for specified path only]\n" "usage: osts [path]"},
271 {"mdts", lfs_mdts, 0, "list MDTs connected to client "
272 "[for specified path only]\n" "usage: mdts [path]"},
274 "report filesystem disk space usage or inodes usage"
275 "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
276 "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
277 {"getname", lfs_getname, 0, "list instances and specified mount points "
278 "[for specified path only]\n"
279 "Usage: getname [-h]|[path ...] "},
280 #ifdef HAVE_SYS_QUOTA_H
281 {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
282 "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
283 " -b <block-softlimit> -B <block-hardlimit>\n"
284 " -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
285 " setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
286 " [--block-softlimit <block-softlimit>]\n"
287 " [--block-hardlimit <block-hardlimit>]\n"
288 " [--inode-softlimit <inode-softlimit>]\n"
289 " [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
290 " setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
291 " [--block-grace <block-grace>]\n"
292 " [--inode-grace <inode-grace>] <filesystem>\n"
293 " -b can be used instead of --block-softlimit/--block-grace\n"
294 " -B can be used instead of --block-hardlimit\n"
295 " -i can be used instead of --inode-softlimit/--inode-grace\n"
296 " -I can be used instead of --inode-hardlimit\n\n"
297 "Note: The total quota space will be split into many qunits and\n"
298 " balanced over all server targets, the minimal qunit size is\n"
299 " 1M bytes for block space and 1K inodes for inode space.\n\n"
300 " Quota space rebalancing process will stop when this mininum\n"
301 " value is reached. As a result, quota exceeded can be returned\n"
302 " while many targets still have 1MB or 1K inodes of spare\n"
304 {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
305 "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
307 " [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
308 " quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
310 {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
311 "usage: flushctx [-k] [mountpoint...]"},
313 "Remote user copy files and directories.\n"
314 "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
316 "Remote user list directory contents.\n"
317 "usage: ls [OPTION]... [FILE]..."},
318 {"changelog", lfs_changelog, 0,
319 "Show the metadata changes on an MDT."
320 "\nusage: changelog <mdtname> [startrec [endrec]]"},
321 {"changelog_clear", lfs_changelog_clear, 0,
322 "Indicate that old changelog records up to <endrec> are no longer of "
323 "interest to consumer <id>, allowing the system to free up space.\n"
324 "An <endrec> of 0 means all records.\n"
325 "usage: changelog_clear <mdtname> <id> <endrec>"},
326 {"fid2path", lfs_fid2path, 0,
327 "Resolve the full path(s) for given FID(s). For a specific hardlink "
328 "specify link number <linkno>.\n"
329 /* "For a historical link name, specify changelog record <recno>.\n" */
330 "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
331 /* [ --rec <recno> ] */ },
332 {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
333 "usage: path2fid [--parents] <path> ..."},
334 {"data_version", lfs_data_version, 0, "Display file data version for "
335 "a given path.\n" "usage: data_version -[n|r|w] <path>"},
336 {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
337 "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
338 {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
339 "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
340 "[--archived] [--lost] <file> ..."},
341 {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
343 "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
344 "[--archived] [--lost] <file> ..."},
345 {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
346 "given files.\n" "usage: hsm_action <file> ..."},
347 {"hsm_archive", lfs_hsm_archive, 0,
348 "Archive file to external storage.\n"
349 "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
351 {"hsm_restore", lfs_hsm_restore, 0,
352 "Restore file from external storage.\n"
353 "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
354 {"hsm_release", lfs_hsm_release, 0,
355 "Release files from Lustre.\n"
356 "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
357 {"hsm_remove", lfs_hsm_remove, 0,
358 "Remove file copy from external storage.\n"
359 "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
360 " [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
362 "Note: To remove files from the archive that have been deleted on\n"
363 "Lustre, set mntpath and optionally archive. In that case, all the\n"
364 "positional arguments and entries in the file list must be FIDs."
366 {"hsm_cancel", lfs_hsm_cancel, 0,
367 "Cancel requests related to specified files.\n"
368 "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
369 {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
370 "usage: swap_layouts <path1> <path2>"},
371 {"migrate", lfs_setstripe, 0,
372 "migrate a directory between MDTs.\n"
373 "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
375 "\tmdt_idx: index of the destination MDT\n"
377 "migrate file objects from one OST "
378 "layout\nto another (may be not safe with concurent writes).\n"
380 "[--stripe-count|-c] <stripe_count>\n"
381 " [--stripe-index|-i] <start_ost_index>\n"
382 " [--stripe-size|-S] <stripe_size>\n"
383 " [--pool|-p] <pool_name>\n"
384 " [--ost-list|-o] <ost_indices>\n"
386 " [--non-block|-n]\n"
387 " <file|directory>\n"
388 "\tstripe_count: number of OSTs to stripe a file over\n"
389 "\tstripe_ost_index: index of the first OST to stripe a file over\n"
390 "\tstripe_size: number of bytes to store before moving to the next OST\n"
391 "\tpool_name: name of the predefined pool of OSTs\n"
392 "\tost_indices: OSTs to stripe over, in order\n"
393 "\tblock: wait for the operation to return before continuing\n"
394 "\tnon-block: do not wait for the operation to return.\n"},
396 "To move directories between MDTs. This command is deprecated, "
397 "use \"migrate\" instead.\n"
398 "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
400 {"ladvise", lfs_ladvise, 0,
401 "Provide servers with advice about access patterns for a file.\n"
402 "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
403 " [--background|-b]\n"
404 " {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
406 {"help", Parser_help, 0, "help"},
407 {"exit", Parser_quit, 0, "quit"},
408 {"quit", Parser_quit, 0, "quit"},
409 {"--version", Parser_version, 0,
410 "output build version of the utility and exit"},
411 {"--list-commands", lfs_list_commands, 0,
412 "list commands supported by the utility and exit"},
417 #define MIGRATION_NONBLOCK 1
419 static int check_hashtype(const char *hashtype)
423 for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
424 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
431 * Internal helper for migrate_copy_data(). Check lease and report error if
434 * \param[in] fd File descriptor on which to check the lease.
435 * \param[out] lease_broken Set to true if the lease was broken.
436 * \param[in] group_locked Whether a group lock was taken or not.
437 * \param[in] path Name of the file being processed, for error
440 * \retval 0 Migration can keep on going.
441 * \retval -errno Error occurred, abort migration.
443 static int check_lease(int fd, bool *lease_broken, bool group_locked,
448 if (!file_lease_supported)
451 rc = llapi_lease_check(fd);
453 return 0; /* llapi_check_lease returns > 0 on success. */
456 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
458 rc = rc ? rc : -EAGAIN;
460 fprintf(stderr, "%s: external attempt to access file '%s' "
461 "blocked until migration ends.\n", progname, path);
464 *lease_broken = true;
468 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
469 bool group_locked, const char *fname)
478 bool lease_broken = false;
480 /* Use a page-aligned buffer for direct I/O */
481 rc = posix_memalign(&buf, getpagesize(), buf_size);
486 /* read new data only if we have written all
487 * previously read data */
490 rc = check_lease(fd_src, &lease_broken,
491 group_locked, fname);
495 rsize = read(fd_src, buf, buf_size);
498 fprintf(stderr, "%s: %s: read failed: %s\n",
499 progname, fname, strerror(-rc));
509 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
513 "%s: %s: write failed on volatile: %s\n",
514 progname, fname, strerror(-rc));
524 fprintf(stderr, "%s: %s: fsync failed: %s\n",
525 progname, fname, strerror(-rc));
533 static int migrate_copy_timestamps(int fdv, const struct stat *st)
535 struct timeval tv[2] = {
536 {.tv_sec = st->st_atime},
537 {.tv_sec = st->st_mtime}
540 return futimes(fdv, tv);
543 static int migrate_block(int fd, int fdv, const struct stat *st,
544 size_t buf_size, const char *name)
551 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
553 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
554 progname, name, strerror(-rc));
562 /* The grouplock blocks all concurrent accesses to the file.
563 * It has to be taken after llapi_get_data_version as it would
565 rc = llapi_group_lock(fd, gid);
567 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
568 progname, name, strerror(-rc));
572 rc = migrate_copy_data(fd, fdv, buf_size, true, name);
574 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
578 /* Make sure we keep original atime/mtime values */
579 rc = migrate_copy_timestamps(fdv, st);
581 fprintf(stderr, "%s: %s: timestamp copy failed\n",
587 * for a migration we need to check data version on file did
590 * Pass in gid=0 since we already own grouplock. */
591 rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
592 SWAP_LAYOUTS_CHECK_DV1);
594 fprintf(stderr, "%s: %s: dataversion changed during copy, "
595 "migration aborted\n", progname, name);
598 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
599 name, strerror(-rc));
604 rc2 = llapi_group_unlock(fd, gid);
605 if (rc2 < 0 && rc == 0) {
606 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
607 progname, name, strerror(-rc2));
614 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
615 size_t buf_size, const char *name)
621 rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
623 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
624 progname, name, strerror(-rc));
628 rc = migrate_copy_data(fd, fdv, buf_size, false, name);
630 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
634 rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
636 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
637 progname, name, strerror(-rc));
643 fprintf(stderr, "%s: %s: data version changed during "
649 /* Make sure we keep original atime/mtime values */
650 rc = migrate_copy_timestamps(fdv, st);
652 fprintf(stderr, "%s: %s: timestamp copy failed\n",
657 /* Atomically put lease, swap layouts and close.
658 * for a migration we need to check data version on file did
660 rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
662 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
663 progname, name, strerror(-rc));
670 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
675 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
679 if (flags != 0 && comp_id != 0)
682 /* LCME_FL_INIT is the only supported flag in PFL */
684 if (flags & ~LCME_KNOWN_FLAGS) {
685 fprintf(stderr, "Invalid component flags %#x\n", flags);
688 } else if (comp_id > LCME_ID_MAX) {
689 fprintf(stderr, "Invalid component id %u\n", comp_id);
693 rc = llapi_layout_file_comp_del(fname, comp_id, flags);
695 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
696 comp_id, fname, strerror(errno));
700 static int lfs_component_add(char *fname, struct llapi_layout *layout)
707 rc = llapi_layout_file_comp_add(fname, layout);
709 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
710 fname, strerror(errno));
714 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
715 struct llapi_layout *layout)
723 fd = lstat(fname, &st);
724 if (fd == 0 && S_ISDIR(st.st_mode))
725 open_flags = O_DIRECTORY | O_RDONLY;
727 fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
729 fprintf(stderr, "%s %s failed. %s\n",
730 S_ISDIR(st.st_mode) ?
731 "Set default composite layout to " :
732 "Create composite file",
733 fname, strerror(errno));
737 static int lfs_migrate(char *name, __u64 migration_flags,
738 struct llapi_stripe_param *param,
739 struct llapi_layout *layout)
743 char parent[PATH_MAX];
746 char volatile_file[sizeof(parent) +
747 LUSTRE_VOLATILE_HDR_LEN +
748 2 * sizeof(mdt_index) +
749 2 * sizeof(random_value) + 4];
752 struct lov_user_md *lum = NULL;
754 int buf_size = 1024 * 1024 * 4;
755 bool have_lease_rdlck = false;
759 /* find the right size for the IO and allocate the buffer */
760 lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
761 lum = malloc(lum_size);
767 rc = llapi_file_get_stripe(name, lum);
768 /* failure can happen for many reasons and some may be not real errors
770 * in case of a real error, a later call will fail with better
771 * error management */
773 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
774 lum->lmm_magic == LOV_USER_MAGIC_V3) &&
775 lum->lmm_stripe_size != 0)
776 buf_size = lum->lmm_stripe_size;
779 /* open file, direct io */
780 /* even if the file is only read, WR mode is nedeed to allow
781 * layout swap on fd */
782 fd = open(name, O_RDWR | O_DIRECT);
785 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
790 if (file_lease_supported) {
791 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
792 if (rc == -EOPNOTSUPP) {
793 /* Older servers do not support file lease.
794 * Disable related checks. This opens race conditions
795 * as explained in LU-4840 */
796 file_lease_supported = false;
798 fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
799 progname, name, strerror(-rc));
802 have_lease_rdlck = true;
806 /* search for file directory pathname */
807 if (strlen(name) > sizeof(parent)-1) {
811 strncpy(parent, name, sizeof(parent));
812 ptr = strrchr(parent, '/');
814 if (getcwd(parent, sizeof(parent)) == NULL) {
825 rc = llapi_file_fget_mdtidx(fd, &mdt_index);
827 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
828 progname, name, strerror(-rc));
833 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
834 mode_t open_mode = S_IRUSR | S_IWUSR;
836 random_value = random();
837 rc = snprintf(volatile_file, sizeof(volatile_file),
838 "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
839 mdt_index, random_value);
840 if (rc >= sizeof(volatile_file)) {
845 /* create, open a volatile file, use caching (ie no directio) */
847 fdv = llapi_file_open_param(volatile_file, open_flags,
849 else if (layout != NULL)
850 fdv = lfs_component_create(volatile_file, open_flags,
854 } while (fdv == -EEXIST);
858 fprintf(stderr, "%s: %s: cannot create volatile file in"
860 progname, parent, strerror(-rc));
864 /* In case the MDT does not support creation of volatile files
865 * we should try to unlink it. */
866 (void)unlink(volatile_file);
868 /* Not-owner (root?) special case.
869 * Need to set owner/group of volatile file like original.
870 * This will allow to pass related check during layout_swap.
875 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
879 rc = fstat(fdv, &stv);
882 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
883 volatile_file, strerror(errno));
886 if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
887 rc = fchown(fdv, st.st_uid, st.st_gid);
890 fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
891 name, strerror(errno));
896 if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
897 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
899 have_lease_rdlck = false;
900 fdv = -1; /* The volatile file is closed as we put the
901 * lease in non-blocking mode. */
904 /* Blocking mode (forced if servers do not support file lease).
905 * It is also the default mode, since we cannot distinguish
906 * between a broken lease and a server that does not support
907 * atomic swap/close (LU-6785) */
908 rc = migrate_block(fd, fdv, &st, buf_size, name);
912 if (have_lease_rdlck)
929 * Parse a string containing an OST index list into an array of integers.
931 * The input string contains a comma delimited list of individual
932 * indices and ranges, for example "1,2-4,7". Add the indices into the
933 * \a osts array and remove duplicates.
935 * \param[out] osts array to store indices in
936 * \param[in] size size of \a osts array
937 * \param[in] offset starting index in \a osts
938 * \param[in] arg string containing OST index list
940 * \retval positive number of indices in \a osts
941 * \retval -EINVAL unable to parse \a arg
943 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
947 int slots = size - offset;
955 while (!end_of_loop) {
963 ptr = strchrnul(arg, ',');
965 end_of_loop = *ptr == '\0';
968 start_index = strtol(arg, &endptr, 0);
969 if (endptr == arg) /* no data at all */
971 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
976 end_index = start_index;
977 if (*endptr == '-') {
978 end_index = strtol(endptr + 1, &endptr, 0);
981 if (end_index < start_index)
985 for (i = start_index; i <= end_index && slots > 0; i++) {
988 /* remove duplicate */
989 for (j = 0; j < offset; j++) {
993 if (j == offset) { /* no duplicate */
998 if (slots == 0 && i < end_index)
1006 if (!end_of_loop && ptr != NULL)
1009 return rc < 0 ? rc : nr;
1012 struct lfs_setstripe_args {
1013 unsigned long long lsa_comp_end;
1014 unsigned long long lsa_stripe_size;
1015 int lsa_stripe_count;
1017 __u32 lsa_comp_flags;
1020 char *lsa_pool_name;
1023 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1025 memset(lsa, 0, sizeof(*lsa));
1026 lsa->lsa_stripe_off = -1;
1029 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1031 return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1032 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1033 lsa->lsa_comp_end != 0);
1036 static int comp_args_to_layout(struct llapi_layout **composite,
1037 struct lfs_setstripe_args *lsa)
1039 struct llapi_layout *layout = *composite;
1040 uint64_t prev_end = 0;
1043 if (layout == NULL) {
1044 layout = llapi_layout_alloc();
1045 if (layout == NULL) {
1046 fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1050 *composite = layout;
1054 /* Get current component extent, current component
1055 * must be the tail component. */
1056 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1058 fprintf(stderr, "Get comp extent failed. %s\n",
1063 rc = llapi_layout_comp_add(layout);
1065 fprintf(stderr, "Add component failed. %s\n",
1071 rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1073 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1074 prev_end, lsa->lsa_comp_end, strerror(errno));
1078 if (lsa->lsa_stripe_size != 0) {
1079 rc = llapi_layout_stripe_size_set(layout,
1080 lsa->lsa_stripe_size);
1082 fprintf(stderr, "Set stripe size %llu failed. %s\n",
1083 lsa->lsa_stripe_size, strerror(errno));
1088 if (lsa->lsa_stripe_count != 0) {
1089 rc = llapi_layout_stripe_count_set(layout,
1090 lsa->lsa_stripe_count == -1 ?
1092 lsa->lsa_stripe_count);
1094 fprintf(stderr, "Set stripe count %d failed. %s\n",
1095 lsa->lsa_stripe_count, strerror(errno));
1100 if (lsa->lsa_pool_name != NULL) {
1101 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1103 fprintf(stderr, "Set pool name: %s failed. %s\n",
1104 lsa->lsa_pool_name, strerror(errno));
1109 if (lsa->lsa_nr_osts > 0) {
1110 if (lsa->lsa_stripe_count > 0 &&
1111 lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1112 fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1113 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1116 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1117 rc = llapi_layout_ost_index_set(layout, i,
1122 } else if (lsa->lsa_stripe_off != -1) {
1123 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1126 fprintf(stderr, "Set ost index %d failed. %s\n",
1127 i, strerror(errno));
1134 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1135 * end of the last component in the existing file, and adjust the
1136 * first extent start of the components to be added accordingly. */
1137 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1139 struct llapi_layout *head;
1140 uint64_t start, end, stripe_size, prev_end = 0;
1147 head = llapi_layout_get_by_path(fname, 0);
1149 fprintf(stderr, "Read layout from %s failed. %s\n",
1150 fname, strerror(errno));
1152 } else if (errno == ENODATA) {
1153 /* file without LOVEA, this component-add will be turned
1154 * into a component-create. */
1155 llapi_layout_free(head);
1157 } else if (!llapi_layout_is_composite(head)) {
1158 fprintf(stderr, "'%s' isn't a composite file.\n",
1160 llapi_layout_free(head);
1164 rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1166 fprintf(stderr, "Get prev extent failed. %s\n",
1168 llapi_layout_free(head);
1172 llapi_layout_free(head);
1174 /* Make sure we use the first component of the layout to be added. */
1175 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1177 fprintf(stderr, "Move component cursor failed. %s\n",
1182 rc = llapi_layout_comp_extent_get(layout, &start, &end);
1184 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1188 if (start > prev_end || end <= prev_end) {
1189 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1190 "adjacent with the existing file extent end: %lu\n",
1191 start, end, prev_end);
1195 rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1197 fprintf(stderr, "Get stripe size failed. %s\n",
1202 if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1203 (prev_end & (stripe_size - 1))) {
1204 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1205 stripe_size, prev_end);
1209 rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1211 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1212 prev_end, end, strerror(errno));
1219 static inline bool comp_flags_is_neg(__u32 flags)
1221 return flags & LCME_FL_NEG;
1224 static inline void comp_flags_set_neg(__u32 *flags)
1226 *flags |= LCME_FL_NEG;
1229 static inline void comp_flags_clear_neg(__u32 *flags)
1231 *flags &= ~LCME_FL_NEG;
1234 static int comp_str2flags(__u32 *flags, char *string)
1237 __u32 neg_flags = 0;
1243 for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1247 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1248 __u32 comp_flag = comp_flags_table[i].cfn_flag;
1249 const char *comp_name = comp_flags_table[i].cfn_name;
1251 if (strcmp(name, comp_name) == 0) {
1252 *flags |= comp_flag;
1254 } else if (strncmp(name, "^", 1) == 0 &&
1255 strcmp(name + 1, comp_name) == 0) {
1256 neg_flags |= comp_flag;
1261 llapi_printf(LLAPI_MSG_ERROR, "Component flag "
1262 "'%s' is not supported.\n", name);
1267 if (*flags == 0 && neg_flags == 0)
1269 /* don't support mixed flags for now */
1270 if (*flags && neg_flags)
1275 comp_flags_set_neg(flags);
1281 static inline bool arg_is_eof(char *arg)
1283 return !strncmp(arg, "-1", strlen("-1")) ||
1284 !strncmp(arg, "EOF", strlen("EOF")) ||
1285 !strncmp(arg, "eof", strlen("eof"));
1300 static int lfs_setstripe(int argc, char **argv)
1302 struct lfs_setstripe_args lsa;
1303 struct llapi_stripe_param *param = NULL;
1304 struct find_param migrate_mdt_param = {
1314 char *mdt_idx_arg = NULL;
1315 unsigned long long size_units = 1;
1316 bool migrate_mode = false;
1317 bool migration_block = false;
1318 __u64 migration_flags = 0;
1319 __u32 osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1320 int comp_del = 0, comp_set = 0;
1323 struct llapi_layout *layout = NULL;
1325 struct option long_opts[] = {
1326 /* --block is only valid in migrate mode */
1327 { .val = 'b', .name = "block", .has_arg = no_argument},
1328 { .val = LFS_COMP_ADD_OPT,
1329 .name = "comp-add", .has_arg = no_argument},
1330 { .val = LFS_COMP_ADD_OPT,
1331 .name = "component-add",
1332 .has_arg = no_argument},
1333 { .val = LFS_COMP_DEL_OPT,
1334 .name = "comp-del", .has_arg = no_argument},
1335 { .val = LFS_COMP_DEL_OPT,
1336 .name = "component-del",
1337 .has_arg = no_argument},
1338 { .val = LFS_COMP_FLAGS_OPT,
1339 .name = "comp-flags", .has_arg = required_argument},
1340 { .val = LFS_COMP_FLAGS_OPT,
1341 .name = "component-flags",
1342 .has_arg = required_argument},
1343 { .val = LFS_COMP_SET_OPT,
1344 .name = "comp-set", .has_arg = no_argument},
1345 { .val = LFS_COMP_SET_OPT,
1346 .name = "component-set",
1347 .has_arg = no_argument},
1348 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1349 /* This formerly implied "stripe-count", but was explicitly
1350 * made "stripe-count" for consistency with other options,
1351 * and to separate it from "mdt-count" when DNE arrives. */
1352 { .val = 'c', .name = "count", .has_arg = required_argument },
1354 { .val = 'c', .name = "stripe-count", .has_arg = required_argument},
1355 { .val = 'c', .name = "stripe_count", .has_arg = required_argument},
1356 { .val = 'd', .name = "delete", .has_arg = no_argument},
1357 { .val = 'E', .name = "comp-end", .has_arg = required_argument},
1358 { .val = 'E', .name = "component-end",
1359 .has_arg = required_argument},
1360 /* dirstripe {"mdt-hash", required_argument, 0, 'H'}, */
1361 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1362 /* This formerly implied "stripe-index", but was explicitly
1363 * made "stripe-index" for consistency with other options,
1364 * and to separate it from "mdt-index" when DNE arrives. */
1365 { .val = 'i', .name = "index", .has_arg = required_argument },
1367 { .val = 'i', .name = "stripe-index", .has_arg = required_argument},
1368 { .val = 'i', .name = "stripe_index", .has_arg = required_argument},
1369 { .val = 'I', .name = "comp-id", .has_arg = required_argument},
1370 { .val = 'I', .name = "component-id", .has_arg = required_argument},
1371 { .val = 'm', .name = "mdt", .has_arg = required_argument},
1372 { .val = 'm', .name = "mdt-index", .has_arg = required_argument},
1373 { .val = 'm', .name = "mdt_index", .has_arg = required_argument},
1374 /* --non-block is only valid in migrate mode */
1375 { .val = 'n', .name = "non-block", .has_arg = no_argument},
1376 { .val = 'o', .name = "ost", .has_arg = required_argument},
1377 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1378 { .val = 'o', .name = "ost-list", .has_arg = required_argument },
1379 { .val = 'o', .name = "ost_list", .has_arg = required_argument },
1381 { .val = 'p', .name = "pool", .has_arg = required_argument },
1382 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1383 /* This formerly implied "--stripe-size", but was confusing
1384 * with "lfs find --size|-s", which means "file size", so use
1385 * the consistent "--stripe-size|-S" for all commands. */
1386 { .val = 's', .name = "size", .has_arg = required_argument },
1388 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1389 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1390 /* dirstripe {"mdt-count", required_argument, 0, 'T'}, */
1391 /* --verbose is only valid in migrate mode */
1392 { .val = 'v', .name = "verbose", .has_arg = no_argument },
1393 { .val = LFS_COMP_ADD_OPT,
1394 .name = "component-add",
1395 .has_arg = no_argument },
1396 { .val = LFS_COMP_DEL_OPT,
1397 .name = "component-del",
1398 .has_arg = no_argument },
1399 { .val = LFS_COMP_FLAGS_OPT,
1400 .name = "component-flags",
1401 .has_arg = required_argument },
1402 { .val = LFS_COMP_SET_OPT,
1403 .name = "component-set",
1404 .has_arg = no_argument },
1407 setstripe_args_init(&lsa);
1409 if (strcmp(argv[0], "migrate") == 0)
1410 migrate_mode = true;
1412 while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1413 long_opts, NULL)) >= 0) {
1418 case LFS_COMP_ADD_OPT:
1421 case LFS_COMP_DEL_OPT:
1424 case LFS_COMP_FLAGS_OPT:
1425 result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
1427 fprintf(stderr, "error: %s: bad comp flags "
1428 "'%s'\n", argv[0], optarg);
1432 case LFS_COMP_SET_OPT:
1436 if (!migrate_mode) {
1437 fprintf(stderr, "--block is valid only for"
1441 migration_block = true;
1444 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1445 if (strcmp(argv[optind - 1], "--count") == 0)
1446 fprintf(stderr, "warning: '--count' deprecated"
1447 ", use '--stripe-count' instead\n");
1449 lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1451 fprintf(stderr, "error: %s: bad stripe count "
1452 "'%s'\n", argv[0], optarg);
1457 /* delete the default striping pattern */
1461 if (lsa.lsa_comp_end != 0) {
1462 result = comp_args_to_layout(&layout, &lsa);
1466 setstripe_args_init(&lsa);
1469 if (arg_is_eof(optarg)) {
1470 lsa.lsa_comp_end = LUSTRE_EOF;
1472 result = llapi_parse_size(optarg,
1476 fprintf(stderr, "error: %s: "
1477 "bad component end '%s'\n",
1484 if (strcmp(argv[optind - 1], "--index") == 0)
1485 fprintf(stderr, "warning: '--index' deprecated"
1486 ", use '--stripe-index' instead\n");
1487 lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1489 fprintf(stderr, "error: %s: bad stripe offset "
1490 "'%s'\n", argv[0], optarg);
1495 comp_id = strtoul(optarg, &end, 0);
1496 if (*end != '\0' || comp_id == 0 ||
1497 comp_id > LCME_ID_MAX) {
1498 fprintf(stderr, "error: %s: bad comp ID "
1499 "'%s'\n", argv[0], optarg);
1504 if (!migrate_mode) {
1505 fprintf(stderr, "--mdt-index is valid only for"
1509 mdt_idx_arg = optarg;
1512 if (!migrate_mode) {
1513 fprintf(stderr, "--non-block is valid only for"
1517 migration_flags |= MIGRATION_NONBLOCK;
1520 lsa.lsa_nr_osts = parse_targets(osts,
1521 sizeof(osts) / sizeof(__u32),
1522 lsa.lsa_nr_osts, optarg);
1523 if (lsa.lsa_nr_osts < 0) {
1525 "error: %s: bad OST indices '%s'\n",
1530 lsa.lsa_osts = osts;
1531 if (lsa.lsa_stripe_off == -1)
1532 lsa.lsa_stripe_off = osts[0];
1537 lsa.lsa_pool_name = optarg;
1539 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1541 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1542 fprintf(stderr, "warning: '--size|-s' deprecated, "
1543 "use '--stripe-size|-S' instead\n");
1545 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1547 result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1550 fprintf(stderr, "error: %s: bad stripe size "
1551 "'%s'\n", argv[0], optarg);
1556 if (!migrate_mode) {
1557 fprintf(stderr, "--verbose is valid only for"
1561 migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1568 fname = argv[optind];
1570 if (lsa.lsa_comp_end != 0) {
1571 result = comp_args_to_layout(&layout, &lsa);
1576 if (optind == argc) {
1577 fprintf(stderr, "error: %s: missing filename|dirname\n",
1582 /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1583 * altered by user space tool, so we don't need to support the
1584 * --component-set for this moment. */
1585 if (comp_set != 0) {
1586 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1591 if ((delete + comp_set + comp_del + comp_add) > 1) {
1592 fprintf(stderr, "error: %s: can't specify --component-set, "
1593 "--component-del, --component-add or -d together\n",
1598 if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1599 lsa.lsa_comp_flags != 0 || layout != NULL)) {
1600 fprintf(stderr, "error: %s: can't specify -d with "
1601 "-s, -c, -o, -p, -I, -F or -E options\n",
1606 if ((comp_set || comp_del) &&
1607 (setstripe_args_specified(&lsa) || layout != NULL)) {
1608 fprintf(stderr, "error: %s: can't specify --component-del or "
1609 "--component-set with -s, -c, -o, -p or -E options.\n",
1614 if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1615 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1616 "--component-del option.\n", argv[0]);
1620 if (comp_add || comp_del) {
1623 result = lstat(fname, &st);
1624 if (result == 0 && S_ISDIR(st.st_mode)) {
1625 fprintf(stderr, "error: %s: can't use --component-add "
1626 "or --component-del for directory.\n",
1633 if (layout == NULL) {
1634 fprintf(stderr, "error: %s: -E option must be present"
1635 "in --component-add mode.\n", argv[0]);
1638 result = adjust_first_extent(fname, layout);
1639 if (result == -ENODATA)
1641 else if (result != 0)
1645 if (mdt_idx_arg != NULL && optind > 3) {
1646 fprintf(stderr, "error: %s: cannot specify -m with other "
1647 "options\n", argv[0]);
1651 if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1653 "error: %s: cannot specify --non-block and --block\n",
1658 if (!comp_del && !comp_set && comp_id != 0) {
1659 fprintf(stderr, "error: %s: -I can only be used with "
1660 "--component-del.\n", argv[0]);
1664 if (mdt_idx_arg != NULL) {
1665 /* initialize migrate mdt parameters */
1666 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1668 fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1669 argv[0], mdt_idx_arg);
1672 migrate_mdt_param.fp_migrate = 1;
1673 } else if (layout == NULL) {
1674 /* initialize stripe parameters */
1675 param = calloc(1, offsetof(typeof(*param),
1676 lsp_osts[lsa.lsa_nr_osts]));
1677 if (param == NULL) {
1678 fprintf(stderr, "error: %s: %s\n", argv[0],
1683 param->lsp_stripe_size = lsa.lsa_stripe_size;
1684 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1685 param->lsp_stripe_count = lsa.lsa_stripe_count;
1686 param->lsp_stripe_pattern = 0;
1687 param->lsp_pool = lsa.lsa_pool_name;
1688 param->lsp_is_specific = false;
1689 if (lsa.lsa_nr_osts > 0) {
1690 if (lsa.lsa_stripe_count > 0 &&
1691 lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1692 fprintf(stderr, "error: %s: stripe count '%d' "
1693 "doesn't match the number of OSTs: %d\n"
1694 , argv[0], lsa.lsa_stripe_count,
1700 param->lsp_is_specific = true;
1701 param->lsp_stripe_count = lsa.lsa_nr_osts;
1702 memcpy(param->lsp_osts, osts,
1703 sizeof(*osts) * lsa.lsa_nr_osts);
1707 for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1709 if (mdt_idx_arg != NULL) {
1710 result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1711 op = "migrate mdt objects of";
1712 } else if (migrate_mode) {
1713 result = lfs_migrate(fname, migration_flags, param,
1715 op = "migrate ost objects of";
1716 } else if (comp_set != 0) {
1717 result = lfs_component_set(fname, comp_id,
1718 lsa.lsa_comp_flags);
1719 op = "modify component flags of";
1720 } else if (comp_del != 0) {
1721 result = lfs_component_del(fname, comp_id,
1722 lsa.lsa_comp_flags);
1723 op = "delete component of";
1724 } else if (comp_add != 0) {
1725 result = lfs_component_add(fname, layout);
1726 op = "add component to";
1727 } else if (layout != NULL) {
1728 result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1734 op = "create composite";
1736 result = llapi_file_open_param(fname,
1743 op = "create striped";
1746 /* Save the first error encountered. */
1749 fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1751 lsa.lsa_pool_name != NULL && result == EINVAL ?
1752 "OST not in pool?" : strerror(errno));
1758 llapi_layout_free(layout);
1761 llapi_layout_free(layout);
1765 static int lfs_poollist(int argc, char **argv)
1770 return llapi_poollist(argv[1]);
1773 static int set_time(time_t *time, time_t *set, char *str)
1780 else if (str[0] == '-')
1786 t = strtol(str, NULL, 0);
1787 if (*time < t * 24 * 60 * 60) {
1790 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1794 *set = *time - t * 24 * 60 * 60;
1797 static int name2uid(unsigned int *id, const char *name)
1799 struct passwd *passwd;
1801 passwd = getpwnam(name);
1804 *id = passwd->pw_uid;
1809 static int name2gid(unsigned int *id, const char *name)
1811 struct group *group;
1813 group = getgrnam(name);
1816 *id = group->gr_gid;
1821 static inline int name2projid(unsigned int *id, const char *name)
1826 static int uid2name(char **name, unsigned int id)
1828 struct passwd *passwd;
1830 passwd = getpwuid(id);
1833 *name = passwd->pw_name;
1838 static inline int gid2name(char **name, unsigned int id)
1840 struct group *group;
1842 group = getgrgid(id);
1845 *name = group->gr_name;
1850 static int name2layout(__u32 *layout, char *name)
1855 for (ptr = name; ; ptr = NULL) {
1856 lyt = strtok(ptr, ",");
1859 if (strcmp(lyt, "released") == 0)
1860 *layout |= LOV_PATTERN_F_RELEASED;
1861 else if (strcmp(lyt, "raid0") == 0)
1862 *layout |= LOV_PATTERN_RAID0;
1869 static int lfs_find(int argc, char **argv)
1874 struct find_param param = {
1878 struct option long_opts[] = {
1879 { .val = 'A', .name = "atime", .has_arg = required_argument },
1880 { .val = LFS_COMP_COUNT_OPT,
1881 .name = "comp-count", .has_arg = required_argument },
1882 { .val = LFS_COMP_COUNT_OPT,
1883 .name = "component-count",
1884 .has_arg = required_argument },
1885 { .val = LFS_COMP_FLAGS_OPT,
1886 .name = "comp-flags", .has_arg = required_argument },
1887 { .val = LFS_COMP_FLAGS_OPT,
1888 .name = "component-flags",
1889 .has_arg = required_argument },
1890 { .val = LFS_COMP_START_OPT,
1891 .name = "comp-start", .has_arg = required_argument },
1892 { .val = LFS_COMP_START_OPT,
1893 .name = "component-start",
1894 .has_arg = required_argument },
1895 { .val = 'c', .name = "stripe-count", .has_arg = required_argument },
1896 { .val = 'c', .name = "stripe_count", .has_arg = required_argument },
1897 { .val = 'C', .name = "ctime", .has_arg = required_argument },
1898 { .val = 'D', .name = "maxdepth", .has_arg = required_argument },
1899 { .val = 'E', .name = "comp-end", .has_arg = required_argument },
1900 { .val = 'E', .name = "component-end",
1901 .has_arg = required_argument },
1902 { .val = 'g', .name = "gid", .has_arg = required_argument },
1903 { .val = 'G', .name = "group", .has_arg = required_argument },
1904 { .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
1905 { .val = 'i', .name = "stripe-index", .has_arg = required_argument },
1906 { .val = 'i', .name = "stripe_index", .has_arg = required_argument },
1907 /*{"component-id", required_argument, 0, 'I'},*/
1908 { .val = 'L', .name = "layout", .has_arg = required_argument },
1909 { .val = 'm', .name = "mdt", .has_arg = required_argument },
1910 { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
1911 { .val = 'm', .name = "mdt_index", .has_arg = required_argument },
1912 { .val = 'M', .name = "mtime", .has_arg = required_argument },
1913 { .val = 'n', .name = "name", .has_arg = required_argument },
1914 /* reserve {"or", no_argument, , 0, 'o'}, to match find(1) */
1915 { .val = 'O', .name = "obd", .has_arg = required_argument },
1916 { .val = 'O', .name = "ost", .has_arg = required_argument },
1917 /* no short option for pool, p/P already used */
1918 { .val = LFS_POOL_OPT,
1919 .name = "pool", .has_arg = required_argument },
1920 { .val = 'p', .name = "print0", .has_arg = no_argument },
1921 { .val = 'P', .name = "print", .has_arg = no_argument },
1922 { .val = LFS_PROJID_OPT,
1923 .name = "projid", .has_arg = required_argument },
1924 { .val = 's', .name = "size", .has_arg = required_argument },
1925 { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
1926 { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
1927 { .val = 't', .name = "type", .has_arg = required_argument },
1928 { .val = 'T', .name = "mdt-count", .has_arg = required_argument },
1929 { .val = 'u', .name = "uid", .has_arg = required_argument },
1930 { .val = 'U', .name = "user", .has_arg = required_argument },
1942 /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1943 while ((c = getopt_long_only(argc, argv,
1944 "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1945 long_opts, NULL)) >= 0) {
1950 /* '!' is part of option */
1951 /* when getopt_long_only() finds a string which is not
1952 * an option nor a known option argument it returns 1
1953 * in that case if we already have found pathstart and pathend
1954 * (i.e. we have the list of pathnames),
1955 * the only supported value is "!"
1957 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1958 if (!isoption && pathend != -1) {
1959 fprintf(stderr, "err: %s: filename|dirname must either "
1960 "precede options or follow options\n",
1965 if (!isoption && pathstart == -1)
1966 pathstart = optind - 1;
1967 if (isoption && pathstart != -1 && pathend == -1)
1968 pathend = optind - 2;
1974 /* unknown; opt is "!" or path component,
1975 * checking done above.
1977 if (strcmp(optarg, "!") == 0)
1981 xtime = ¶m.fp_atime;
1982 xsign = ¶m.fp_asign;
1983 param.fp_exclude_atime = !!neg_opt;
1984 /* no break, this falls through to 'C' for ctime */
1987 xtime = ¶m.fp_ctime;
1988 xsign = ¶m.fp_csign;
1989 param.fp_exclude_ctime = !!neg_opt;
1991 /* no break, this falls through to 'M' for mtime */
1994 xtime = ¶m.fp_mtime;
1995 xsign = ¶m.fp_msign;
1996 param.fp_exclude_mtime = !!neg_opt;
1998 rc = set_time(&t, xtime, optarg);
1999 if (rc == INT_MAX) {
2006 case LFS_COMP_COUNT_OPT:
2007 if (optarg[0] == '+') {
2008 param.fp_comp_count_sign = -1;
2010 } else if (optarg[0] == '-') {
2011 param.fp_comp_count_sign = 1;
2015 param.fp_comp_count = strtoul(optarg, &endptr, 0);
2016 if (*endptr != '\0') {
2017 fprintf(stderr, "error: bad component count "
2021 param.fp_check_comp_count = 1;
2022 param.fp_exclude_comp_count = !!neg_opt;
2024 case LFS_COMP_FLAGS_OPT:
2025 rc = comp_str2flags(¶m.fp_comp_flags, optarg);
2026 if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2027 fprintf(stderr, "error: bad component flags "
2031 param.fp_check_comp_flags = 1;
2032 param.fp_exclude_comp_flags = !!neg_opt;
2034 case LFS_COMP_START_OPT:
2035 if (optarg[0] == '+') {
2036 param.fp_comp_start_sign = -1;
2038 } else if (optarg[0] == '-') {
2039 param.fp_comp_start_sign = 1;
2043 rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
2044 ¶m.fp_comp_start_units, 0);
2046 fprintf(stderr, "error: bad component start "
2050 param.fp_check_comp_start = 1;
2051 param.fp_exclude_comp_start = !!neg_opt;
2054 if (optarg[0] == '+') {
2055 param.fp_stripe_count_sign = -1;
2057 } else if (optarg[0] == '-') {
2058 param.fp_stripe_count_sign = 1;
2062 param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2063 if (*endptr != '\0') {
2064 fprintf(stderr,"error: bad stripe_count '%s'\n",
2069 param.fp_check_stripe_count = 1;
2070 param.fp_exclude_stripe_count = !!neg_opt;
2073 param.fp_max_depth = strtol(optarg, 0, 0);
2076 if (optarg[0] == '+') {
2077 param.fp_comp_end_sign = -1;
2079 } else if (optarg[0] == '-') {
2080 param.fp_comp_end_sign = 1;
2084 if (arg_is_eof(optarg)) {
2085 param.fp_comp_end = LUSTRE_EOF;
2086 param.fp_comp_end_units = 1;
2089 rc = llapi_parse_size(optarg,
2091 ¶m.fp_comp_end_units, 0);
2094 fprintf(stderr, "error: bad component end "
2098 param.fp_check_comp_end = 1;
2099 param.fp_exclude_comp_end = !!neg_opt;
2103 rc = name2gid(¶m.fp_gid, optarg);
2105 param.fp_gid = strtoul(optarg, &endptr, 10);
2106 if (*endptr != '\0') {
2107 fprintf(stderr, "Group/GID: %s cannot "
2108 "be found.\n", optarg);
2113 param.fp_exclude_gid = !!neg_opt;
2114 param.fp_check_gid = 1;
2117 param.fp_hash_type = check_hashtype(optarg);
2118 if (param.fp_hash_type == 0) {
2119 fprintf(stderr, "error: bad hash_type '%s'\n",
2124 param.fp_check_hash_type = 1;
2125 param.fp_exclude_hash_type = !!neg_opt;
2128 ret = name2layout(¶m.fp_layout, optarg);
2131 param.fp_exclude_layout = !!neg_opt;
2132 param.fp_check_layout = 1;
2136 rc = name2uid(¶m.fp_uid, optarg);
2138 param.fp_uid = strtoul(optarg, &endptr, 10);
2139 if (*endptr != '\0') {
2140 fprintf(stderr, "User/UID: %s cannot "
2141 "be found.\n", optarg);
2146 param.fp_exclude_uid = !!neg_opt;
2147 param.fp_check_uid = 1;
2150 if (strlen(optarg) > LOV_MAXPOOLNAME) {
2152 "Pool name %s is too long"
2153 " (max is %d)\n", optarg,
2158 /* we do check for empty pool because empty pool
2159 * is used to find V1 lov attributes */
2160 strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2161 param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2162 param.fp_exclude_pool = !!neg_opt;
2163 param.fp_check_pool = 1;
2166 param.fp_pattern = (char *)optarg;
2167 param.fp_exclude_pattern = !!neg_opt;
2172 char *buf, *token, *next, *p;
2176 buf = strdup(optarg);
2182 param.fp_exclude_obd = !!neg_opt;
2185 while (token && *token) {
2186 token = strchr(token, ',');
2193 param.fp_exclude_mdt = !!neg_opt;
2194 param.fp_num_alloc_mdts += len;
2195 tmp = realloc(param.fp_mdt_uuid,
2196 param.fp_num_alloc_mdts *
2197 sizeof(*param.fp_mdt_uuid));
2203 param.fp_mdt_uuid = tmp;
2205 param.fp_exclude_obd = !!neg_opt;
2206 param.fp_num_alloc_obds += len;
2207 tmp = realloc(param.fp_obd_uuid,
2208 param.fp_num_alloc_obds *
2209 sizeof(*param.fp_obd_uuid));
2215 param.fp_obd_uuid = tmp;
2217 for (token = buf; token && *token; token = next) {
2218 struct obd_uuid *puuid;
2221 ¶m.fp_mdt_uuid[param.fp_num_mdts++];
2224 ¶m.fp_obd_uuid[param.fp_num_obds++];
2226 p = strchr(token, ',');
2233 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2238 strncpy(puuid->uuid, token,
2239 sizeof(puuid->uuid));
2247 param.fp_zero_end = 1;
2251 case LFS_PROJID_OPT:
2252 rc = name2projid(¶m.fp_projid, optarg);
2254 param.fp_projid = strtoul(optarg, &endptr, 10);
2255 if (*endptr != '\0') {
2257 "Invalid project ID: %s",
2263 param.fp_exclude_projid = !!neg_opt;
2264 param.fp_check_projid = 1;
2267 if (optarg[0] == '+') {
2268 param.fp_size_sign = -1;
2270 } else if (optarg[0] == '-') {
2271 param.fp_size_sign = 1;
2275 ret = llapi_parse_size(optarg, ¶m.fp_size,
2276 ¶m.fp_size_units, 0);
2278 fprintf(stderr, "error: bad file size '%s'\n",
2282 param.fp_check_size = 1;
2283 param.fp_exclude_size = !!neg_opt;
2286 if (optarg[0] == '+') {
2287 param.fp_stripe_size_sign = -1;
2289 } else if (optarg[0] == '-') {
2290 param.fp_stripe_size_sign = 1;
2294 ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
2295 ¶m.fp_stripe_size_units, 0);
2297 fprintf(stderr, "error: bad stripe_size '%s'\n",
2301 param.fp_check_stripe_size = 1;
2302 param.fp_exclude_stripe_size = !!neg_opt;
2305 param.fp_exclude_type = !!neg_opt;
2306 switch (optarg[0]) {
2308 param.fp_type = S_IFBLK;
2311 param.fp_type = S_IFCHR;
2314 param.fp_type = S_IFDIR;
2317 param.fp_type = S_IFREG;
2320 param.fp_type = S_IFLNK;
2323 param.fp_type = S_IFIFO;
2326 param.fp_type = S_IFSOCK;
2329 fprintf(stderr, "error: %s: bad type '%s'\n",
2336 if (optarg[0] == '+') {
2337 param.fp_mdt_count_sign = -1;
2339 } else if (optarg[0] == '-') {
2340 param.fp_mdt_count_sign = 1;
2344 param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2345 if (*endptr != '\0') {
2346 fprintf(stderr, "error: bad mdt_count '%s'\n",
2351 param.fp_check_mdt_count = 1;
2352 param.fp_exclude_mdt_count = !!neg_opt;
2360 if (pathstart == -1) {
2361 fprintf(stderr, "error: %s: no filename|pathname\n",
2365 } else if (pathend == -1) {
2371 rc = llapi_find(argv[pathstart], ¶m);
2372 if (rc != 0 && ret == 0)
2374 } while (++pathstart < pathend);
2377 fprintf(stderr, "error: %s failed for %s.\n",
2378 argv[0], argv[optind - 1]);
2380 if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2381 free(param.fp_obd_uuid);
2383 if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2384 free(param.fp_mdt_uuid);
2389 static int lfs_getstripe_internal(int argc, char **argv,
2390 struct find_param *param)
2392 struct option long_opts[] = {
2393 { .val = LFS_COMP_COUNT_OPT,
2394 .name = "comp-count", .has_arg = no_argument },
2395 { .val = LFS_COMP_COUNT_OPT,
2396 .name = "component-count", .has_arg = no_argument },
2397 { .val = LFS_COMP_FLAGS_OPT,
2398 .name = "comp-flags", .has_arg = optional_argument },
2399 { .val = LFS_COMP_FLAGS_OPT,
2400 .name = "component-flags", .has_arg = optional_argument },
2401 { .val = LFS_COMP_START_OPT,
2402 .name = "comp-start", .has_arg = optional_argument },
2403 { .val = LFS_COMP_START_OPT,
2404 .name = "component-start", .has_arg = optional_argument },
2405 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2406 /* This formerly implied "stripe-count", but was explicitly
2407 * made "stripe-count" for consistency with other options,
2408 * and to separate it from "mdt-count" when DNE arrives. */
2409 { .val = 'c', .name = "count", .has_arg = no_argument },
2411 { .val = 'c', .name = "stripe-count", .has_arg = no_argument },
2412 { .val = 'c', .name = "stripe_count", .has_arg = no_argument },
2413 { .val = 'd', .name = "directory", .has_arg = no_argument },
2414 { .val = 'D', .name = "default", .has_arg = no_argument },
2415 { .val = 'E', .name = "comp-end", .has_arg = optional_argument },
2416 { .val = 'E', .name = "component-end",
2417 .has_arg = optional_argument },
2418 { .val = 'F', .name = "fid", .has_arg = no_argument },
2419 { .val = 'g', .name = "generation", .has_arg = no_argument },
2420 /* dirstripe { .val = 'H', .name = "mdt-hash",
2421 * .has_arg = required_argument }, */
2422 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2423 /* This formerly implied "stripe-index", but was explicitly
2424 * made "stripe-index" for consistency with other options,
2425 * and to separate it from "mdt-index" when DNE arrives. */
2426 { .val = 'i', .name = "index", .has_arg = no_argument },
2428 { .val = 'i', .name = "stripe-index", .has_arg = no_argument },
2429 { .val = 'i', .name = "stripe_index", .has_arg = no_argument },
2430 { .val = 'I', .name = "comp-id", .has_arg = optional_argument },
2431 { .val = 'I', .name = "component-id", .has_arg = optional_argument },
2432 { .val = 'L', .name = "layout", .has_arg = no_argument },
2433 { .val = 'm', .name = "mdt", .has_arg = no_argument },
2434 { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
2435 { .val = 'm', .name = "mdt_index", .has_arg = no_argument },
2436 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2437 { .val = 'M', .name = "mdt-index", .has_arg = no_argument },
2438 { .val = 'M', .name = "mdt_index", .has_arg = no_argument },
2440 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2441 /* This formerly implied "stripe-index", but was confusing
2442 * with "file offset" (which will eventually be needed for
2443 * with different layouts by offset), so deprecate it. */
2444 { .val = 'o', .name = "offset", .has_arg = no_argument },
2446 { .val = 'O', .name = "obd", .has_arg = required_argument },
2447 { .val = 'O', .name = "ost", .has_arg = required_argument },
2448 { .val = 'p', .name = "pool", .has_arg = no_argument },
2449 { .val = 'q', .name = "quiet", .has_arg = no_argument },
2450 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2451 { .val = 'R', .name = "raw", .has_arg = no_argument },
2452 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2453 /* This formerly implied "--stripe-size", but was confusing
2454 * with "lfs find --size|-s", which means "file size", so use
2455 * the consistent "--stripe-size|-S" for all commands. */
2456 { .val = 's', .name = "size", .has_arg = no_argument },
2458 { .val = 'S', .name = "stripe-size", .has_arg = no_argument },
2459 { .val = 'S', .name = "stripe_size", .has_arg = no_argument },
2460 /* dirstripe { .val = 'T', .name = "mdt-count",
2461 * .has_arg = required_argument }, */
2462 { .val = 'v', .name = "verbose", .has_arg = no_argument },
2463 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2468 while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2469 long_opts, NULL)) != -1) {
2472 if (strcmp(argv[optind - 1], "--count") == 0)
2473 fprintf(stderr, "warning: '--count' deprecated,"
2474 " use '--stripe-count' instead\n");
2475 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2476 param->fp_verbose |= VERBOSE_COUNT;
2477 param->fp_max_depth = 0;
2480 case LFS_COMP_COUNT_OPT:
2481 param->fp_verbose |= VERBOSE_COMP_COUNT;
2482 param->fp_max_depth = 0;
2484 case LFS_COMP_FLAGS_OPT:
2485 if (optarg != NULL) {
2486 __u32 *flags = ¶m->fp_comp_flags;
2487 rc = comp_str2flags(flags, optarg);
2489 fprintf(stderr, "error: %s bad "
2490 "component flags '%s'.\n",
2494 param->fp_check_comp_flags = 1;
2495 param->fp_exclude_comp_flags =
2496 comp_flags_is_neg(*flags);
2497 comp_flags_clear_neg(flags);
2500 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2501 param->fp_max_depth = 0;
2504 case LFS_COMP_START_OPT:
2505 if (optarg != NULL) {
2507 if (tmp[0] == '+') {
2508 param->fp_comp_start_sign = -1;
2510 } else if (tmp[0] == '-') {
2511 param->fp_comp_start_sign = 1;
2514 rc = llapi_parse_size(tmp,
2515 ¶m->fp_comp_start,
2516 ¶m->fp_comp_start_units, 0);
2518 fprintf(stderr, "error: %s bad "
2519 "component start '%s'.\n",
2523 param->fp_check_comp_start = 1;
2526 param->fp_verbose |= VERBOSE_COMP_START;
2527 param->fp_max_depth = 0;
2531 param->fp_max_depth = 0;
2534 param->fp_get_default_lmv = 1;
2537 if (optarg != NULL) {
2539 if (tmp[0] == '+') {
2540 param->fp_comp_end_sign = -1;
2542 } else if (tmp[0] == '-') {
2543 param->fp_comp_end_sign = 1;
2547 if (arg_is_eof(tmp)) {
2548 param->fp_comp_end = LUSTRE_EOF;
2549 param->fp_comp_end_units = 1;
2552 rc = llapi_parse_size(tmp,
2553 ¶m->fp_comp_end,
2554 ¶m->fp_comp_end_units, 0);
2557 fprintf(stderr, "error: %s bad "
2558 "component end '%s'.\n",
2562 param->fp_check_comp_end = 1;
2564 param->fp_verbose |= VERBOSE_COMP_END;
2565 param->fp_max_depth = 0;
2569 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2570 param->fp_verbose |= VERBOSE_DFID;
2571 param->fp_max_depth = 0;
2575 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2576 param->fp_verbose |= VERBOSE_GENERATION;
2577 param->fp_max_depth = 0;
2580 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2582 fprintf(stderr, "warning: '--offset|-o' deprecated, "
2583 "use '--stripe-index|-i' instead\n");
2586 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2587 if (strcmp(argv[optind - 1], "--index") == 0)
2588 fprintf(stderr, "warning: '--index' deprecated"
2589 ", use '--stripe-index' instead\n");
2591 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2592 param->fp_verbose |= VERBOSE_OFFSET;
2593 param->fp_max_depth = 0;
2597 if (optarg != NULL) {
2598 param->fp_comp_id = strtoul(optarg, &end, 0);
2599 if (*end != '\0' || param->fp_comp_id == 0 ||
2600 param->fp_comp_id > LCME_ID_MAX) {
2601 fprintf(stderr, "error: %s bad "
2602 "component id '%s'\n",
2606 param->fp_check_comp_id = 1;
2609 param->fp_max_depth = 0;
2610 param->fp_verbose |= VERBOSE_COMP_ID;
2614 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2615 param->fp_verbose |= VERBOSE_LAYOUT;
2616 param->fp_max_depth = 0;
2619 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2621 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2622 fprintf(stderr, "warning: '-M' deprecated"
2623 ", use '-m' instead\n");
2627 if (!(param->fp_verbose & VERBOSE_DETAIL))
2628 param->fp_max_depth = 0;
2629 param->fp_verbose |= VERBOSE_MDTINDEX;
2632 if (param->fp_obd_uuid) {
2634 "error: %s: only one obduuid allowed",
2638 param->fp_obd_uuid = (struct obd_uuid *)optarg;
2641 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2642 param->fp_verbose |= VERBOSE_POOL;
2643 param->fp_max_depth = 0;
2650 param->fp_recursive = 1;
2655 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2657 fprintf(stderr, "warning: '--size|-s' deprecated, "
2658 "use '--stripe-size|-S' instead\n");
2659 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2661 if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2662 param->fp_verbose |= VERBOSE_SIZE;
2663 param->fp_max_depth = 0;
2667 param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2680 if (param->fp_recursive)
2681 param->fp_max_depth = -1;
2682 else if (param->fp_verbose & VERBOSE_DETAIL)
2683 param->fp_max_depth = 1;
2685 if (!param->fp_verbose)
2686 param->fp_verbose = VERBOSE_DEFAULT;
2687 if (param->fp_quiet)
2688 param->fp_verbose = VERBOSE_OBJID;
2691 rc = llapi_getstripe(argv[optind], param);
2692 } while (++optind < argc && !rc);
2695 fprintf(stderr, "error: %s failed for %s.\n",
2696 argv[0], argv[optind - 1]);
2700 static int lfs_tgts(int argc, char **argv)
2702 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2703 struct find_param param;
2704 int index = 0, rc=0;
2709 if (argc == 2 && !realpath(argv[1], path)) {
2711 fprintf(stderr, "error: invalid path '%s': %s\n",
2712 argv[1], strerror(-rc));
2716 while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2717 /* Check if we have a mount point */
2718 if (mntdir[0] == '\0')
2721 memset(¶m, 0, sizeof(param));
2722 if (!strcmp(argv[0], "mdts"))
2723 param.fp_get_lmv = 1;
2725 rc = llapi_ostlist(mntdir, ¶m);
2727 fprintf(stderr, "error: %s: failed on %s\n",
2730 if (path[0] != '\0')
2732 memset(mntdir, 0, PATH_MAX);
2738 static int lfs_getstripe(int argc, char **argv)
2740 struct find_param param = { 0 };
2742 param.fp_max_depth = 1;
2743 return lfs_getstripe_internal(argc, argv, ¶m);
2747 static int lfs_getdirstripe(int argc, char **argv)
2749 struct find_param param = { 0 };
2750 struct option long_opts[] = {
2751 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2752 { .val = 'c', .name = "mdt-count", .has_arg = no_argument },
2754 { .val = 'D', .name = "default", .has_arg = no_argument },
2755 { .val = 'H', .name = "mdt-hash", .has_arg = no_argument },
2756 { .val = 'i', .name = "mdt-index", .has_arg = no_argument },
2757 { .val = 'O', .name = "obd", .has_arg = required_argument },
2758 { .val = 'r', .name = "recursive", .has_arg = no_argument },
2759 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2760 { .val = 't', .name = "mdt-hash", .has_arg = no_argument },
2762 { .val = 'T', .name = "mdt-count", .has_arg = no_argument },
2763 { .val = 'y', .name = "yaml", .has_arg = no_argument },
2767 param.fp_get_lmv = 1;
2769 while ((c = getopt_long(argc, argv,
2770 "cDHiO:rtTy", long_opts, NULL)) != -1)
2774 if (param.fp_obd_uuid) {
2776 "error: %s: only one obduuid allowed",
2780 param.fp_obd_uuid = (struct obd_uuid *)optarg;
2782 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2784 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2785 fprintf(stderr, "warning: '-c' deprecated"
2786 ", use '-T' instead\n");
2790 param.fp_verbose |= VERBOSE_COUNT;
2793 param.fp_verbose |= VERBOSE_OFFSET;
2795 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2799 param.fp_verbose |= VERBOSE_HASH_TYPE;
2802 param.fp_get_default_lmv = 1;
2805 param.fp_recursive = 1;
2818 if (param.fp_recursive)
2819 param.fp_max_depth = -1;
2821 if (!param.fp_verbose)
2822 param.fp_verbose = VERBOSE_DEFAULT;
2825 rc = llapi_getstripe(argv[optind], ¶m);
2826 } while (++optind < argc && !rc);
2829 fprintf(stderr, "error: %s failed for %s.\n",
2830 argv[0], argv[optind - 1]);
2835 static int lfs_setdirstripe(int argc, char **argv)
2839 unsigned int stripe_offset = -1;
2840 unsigned int stripe_count = 1;
2841 enum lmv_hash_type hash_type;
2844 char *stripe_offset_opt = NULL;
2845 char *stripe_count_opt = NULL;
2846 char *stripe_hash_opt = NULL;
2847 char *mode_opt = NULL;
2848 bool default_stripe = false;
2849 mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
2850 mode_t previous_mode = 0;
2851 bool delete = false;
2853 struct option long_opts[] = {
2854 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2855 { .val = 'c', .name = "count", .has_arg = required_argument },
2857 { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
2858 { .val = 'd', .name = "delete", .has_arg = no_argument },
2859 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2860 { .val = 'i', .name = "index", .has_arg = required_argument },
2862 { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
2863 { .val = 'm', .name = "mode", .has_arg = required_argument },
2864 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2865 { .val = 't', .name = "hash-type", .has_arg = required_argument },
2866 { .val = 't', .name = "mdt-hash", .has_arg = required_argument },
2868 {"mdt-hash", required_argument, 0, 'H'},
2869 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2870 { .val = 'D', .name = "default_stripe",
2871 .has_arg = no_argument },
2873 { .val = 'D', .name = "default", .has_arg = no_argument },
2876 while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2883 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2884 if (strcmp(argv[optind - 1], "--count") == 0)
2885 fprintf(stderr, "warning: '--count' deprecated"
2886 ", use '--mdt-count' instead\n");
2888 stripe_count_opt = optarg;
2892 default_stripe = true;
2895 default_stripe = true;
2898 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2899 if (strcmp(argv[optind - 1], "--index") == 0)
2900 fprintf(stderr, "warning: '--index' deprecated"
2901 ", use '--mdt-index' instead\n");
2903 stripe_offset_opt = optarg;
2908 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2912 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2913 if (strcmp(argv[optind - 1], "--hash-type") == 0)
2914 fprintf(stderr, "warning: '--hash-type' "
2915 "deprecated, use '--mdt-hash' "
2918 stripe_hash_opt = optarg;
2921 fprintf(stderr, "error: %s: option '%s' "
2923 argv[0], argv[optind - 1]);
2928 if (optind == argc) {
2929 fprintf(stderr, "error: %s: missing dirname\n",
2934 if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2935 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2940 if (stripe_offset_opt != NULL) {
2941 /* get the stripe offset */
2942 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2944 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2945 argv[0], stripe_offset_opt);
2951 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2952 fprintf(stderr, "error: %s: cannot specify -d with -s,"
2953 " or -i options.\n", argv[0]);
2961 if (mode_opt != NULL) {
2962 mode = strtoul(mode_opt, &end, 8);
2964 fprintf(stderr, "error: %s: bad mode '%s'\n",
2968 previous_mode = umask(0);
2971 if (stripe_hash_opt == NULL) {
2972 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2974 hash_type = check_hashtype(stripe_hash_opt);
2975 if (hash_type == 0) {
2977 "error: %s: bad stripe hash type '%s'\n",
2978 argv[0], stripe_hash_opt);
2983 /* get the stripe count */
2984 if (stripe_count_opt != NULL) {
2985 stripe_count = strtoul(stripe_count_opt, &end, 0);
2987 fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2988 argv[0], stripe_count_opt);
2993 dname = argv[optind];
2995 if (default_stripe) {
2996 result = llapi_dir_set_default_lmv_stripe(dname,
2997 stripe_offset, stripe_count,
3000 result = llapi_dir_create_pool(dname, mode,
3002 stripe_count, hash_type,
3007 fprintf(stderr, "error: %s: create stripe dir '%s' "
3008 "failed\n", argv[0], dname);
3011 dname = argv[++optind];
3012 } while (dname != NULL);
3014 if (mode_opt != NULL)
3015 umask(previous_mode);
3021 static int lfs_rmentry(int argc, char **argv)
3028 fprintf(stderr, "error: %s: missing dirname\n",
3034 dname = argv[index];
3035 while (dname != NULL) {
3036 result = llapi_direntry_remove(dname);
3038 fprintf(stderr, "error: %s: remove dir entry '%s' "
3039 "failed\n", argv[0], dname);
3042 dname = argv[++index];
3047 static int lfs_mv(int argc, char **argv)
3049 struct find_param param = {
3056 struct option long_opts[] = {
3057 { .val = 'M', .name = "mdt-index", .has_arg = required_argument },
3058 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3061 while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3064 param.fp_mdt_index = strtoul(optarg, &end, 0);
3066 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3073 param.fp_verbose = VERBOSE_DETAIL;
3077 fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3078 argv[0], argv[optind - 1]);
3083 if (param.fp_mdt_index == -1) {
3084 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3088 if (optind >= argc) {
3089 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3093 param.fp_migrate = 1;
3094 rc = llapi_migrate_mdt(argv[optind], ¶m);
3096 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3097 argv[0], argv[optind], param.fp_mdt_index,
3102 static int lfs_osts(int argc, char **argv)
3104 return lfs_tgts(argc, argv);
3107 static int lfs_mdts(int argc, char **argv)
3109 return lfs_tgts(argc, argv);
3112 #define COOK(value) \
3115 while (value > 1024) { \
3123 #define CDF "%11llu"
3124 #define HDF "%8.1f%c"
3129 MNTDF_INODES = 0x0001,
3130 MNTDF_COOKED = 0x0002,
3131 MNTDF_LAZY = 0x0004,
3132 MNTDF_VERBOSE = 0x0008,
3135 static int showdf(char *mntdir, struct obd_statfs *stat,
3136 char *uuid, enum mntdf_flags flags,
3137 char *type, int index, int rc)
3139 long long avail, used, total;
3141 char *suffix = "KMGTPEZY";
3142 /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3143 char tbuf[3 * sizeof(__u64)];
3144 char ubuf[3 * sizeof(__u64)];
3145 char abuf[3 * sizeof(__u64)];
3146 char rbuf[3 * sizeof(__u64)];
3153 if (flags & MNTDF_INODES) {
3154 avail = stat->os_ffree;
3155 used = stat->os_files - stat->os_ffree;
3156 total = stat->os_files;
3158 int shift = flags & MNTDF_COOKED ? 0 : 10;
3160 avail = (stat->os_bavail * stat->os_bsize) >> shift;
3161 used = ((stat->os_blocks - stat->os_bfree) *
3162 stat->os_bsize) >> shift;
3163 total = (stat->os_blocks * stat->os_bsize) >> shift;
3166 if ((used + avail) > 0)
3167 ratio = (double)used / (double)(used + avail);
3169 if (flags & MNTDF_COOKED) {
3173 cook_val = (double)total;
3176 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3179 snprintf(tbuf, sizeof(tbuf), CDF, total);
3181 cook_val = (double)used;
3184 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3187 snprintf(ubuf, sizeof(ubuf), CDF, used);
3189 cook_val = (double)avail;
3192 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3195 snprintf(abuf, sizeof(abuf), CDF, avail);
3197 snprintf(tbuf, sizeof(tbuf), CDF, total);
3198 snprintf(ubuf, sizeof(tbuf), CDF, used);
3199 snprintf(abuf, sizeof(tbuf), CDF, avail);
3202 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3203 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3204 uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3206 printf("[%s:%d]", type, index);
3208 if (stat->os_state) {
3210 * Each character represents the matching
3213 const char state_names[] = "DRSI";
3218 for (i = 0, state = stat->os_state;
3219 state && i < sizeof(state_names); i++) {
3220 if (!(state & (1 << i)))
3222 printf("%c", state_names[i]);
3230 printf(UUF": inactive device\n", uuid);
3233 printf(UUF": %s\n", uuid, strerror(-rc));
3240 struct ll_stat_type {
3245 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3247 struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3248 struct obd_uuid uuid_buf;
3249 char *poolname = NULL;
3250 struct ll_stat_type types[] = {
3251 { .st_op = LL_STATFS_LMV, .st_name = "MDT" },
3252 { .st_op = LL_STATFS_LOV, .st_name = "OST" },
3253 { .st_name = NULL } };
3254 struct ll_stat_type *tp;
3255 __u64 ost_ffree = 0;
3263 poolname = strchr(pool, '.');
3264 if (poolname != NULL) {
3265 if (strncmp(fsname, pool, strlen(fsname))) {
3266 fprintf(stderr, "filesystem name incorrect\n");
3274 fd = open(mntdir, O_RDONLY);
3277 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3282 if (flags & MNTDF_INODES)
3283 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3284 "UUID", "Inodes", "IUsed", "IFree",
3285 "IUse%", "Mounted on");
3287 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3288 "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3289 "Used", "Available", "Use%", "Mounted on");
3291 for (tp = types; tp->st_name != NULL; tp++) {
3292 for (index = 0; ; index++) {
3293 memset(&stat_buf, 0, sizeof(struct obd_statfs));
3294 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3295 type = flags & MNTDF_LAZY ?
3296 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3297 rc2 = llapi_obd_fstatfs(fd, type, index,
3298 &stat_buf, &uuid_buf);
3303 if (rc2 == -ENODATA) { /* Inactive device, OK. */
3304 if (!(flags & MNTDF_VERBOSE))
3306 } else if (rc2 < 0 && rc == 0) {
3310 if (poolname && tp->st_op == LL_STATFS_LOV &&
3311 llapi_search_ost(fsname, poolname,
3312 obd_uuid2str(&uuid_buf)) != 1)
3315 /* the llapi_obd_statfs() call may have returned with
3316 * an error, but if it filled in uuid_buf we will at
3317 * lease use that to print out a message for that OBD.
3318 * If we didn't get anything in the uuid_buf, then fill
3319 * it in so that we can print an error message. */
3320 if (uuid_buf.uuid[0] == '\0')
3321 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3322 "%s%04x", tp->st_name, index);
3323 showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3324 flags, tp->st_name, index, rc2);
3327 if (tp->st_op == LL_STATFS_LMV) {
3328 sum.os_ffree += stat_buf.os_ffree;
3329 sum.os_files += stat_buf.os_files;
3330 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3331 sum.os_blocks += stat_buf.os_blocks *
3333 sum.os_bfree += stat_buf.os_bfree *
3335 sum.os_bavail += stat_buf.os_bavail *
3337 ost_ffree += stat_buf.os_ffree;
3345 /* If we don't have as many objects free on the OST as inodes
3346 * on the MDS, we reduce the total number of inodes to
3347 * compensate, so that the "inodes in use" number is correct.
3348 * Matches ll_statfs_internal() so the results are consistent. */
3349 if (ost_ffree < sum.os_ffree) {
3350 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3351 sum.os_ffree = ost_ffree;
3354 showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3360 static int lfs_df(int argc, char **argv)
3362 char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3363 enum mntdf_flags flags = 0;
3364 int c, rc = 0, index = 0;
3365 char fsname[PATH_MAX] = "", *pool_name = NULL;
3366 struct option long_opts[] = {
3367 { .val = 'h', .name = "human-readable",
3368 .has_arg = no_argument },
3369 { .val = 'i', .name = "inodes", .has_arg = no_argument },
3370 { .val = 'l', .name = "lazy", .has_arg = no_argument },
3371 { .val = 'p', .name = "pool", .has_arg = required_argument },
3372 { .val = 'v', .name = "verbose", .has_arg = no_argument },
3375 while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3378 flags |= MNTDF_COOKED;
3381 flags |= MNTDF_INODES;
3384 flags |= MNTDF_LAZY;
3390 flags |= MNTDF_VERBOSE;
3396 if (optind < argc && !realpath(argv[optind], path)) {
3398 fprintf(stderr, "error: invalid path '%s': %s\n",
3399 argv[optind], strerror(-rc));
3403 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3404 /* Check if we have a mount point */
3405 if (mntdir[0] == '\0')
3408 rc = mntdf(mntdir, fsname, pool_name, flags);
3409 if (rc || path[0] != '\0')
3411 fsname[0] = '\0'; /* avoid matching in next loop */
3412 mntdir[0] = '\0'; /* avoid matching in next loop */
3418 static int lfs_getname(int argc, char **argv)
3420 char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3421 int rc = 0, index = 0, c;
3422 char buf[sizeof(struct obd_uuid)];
3424 while ((c = getopt(argc, argv, "h")) != -1)
3427 if (optind == argc) { /* no paths specified, get all paths. */
3428 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3429 rc = llapi_getname(mntdir, buf, sizeof(buf));
3432 "cannot get name for `%s': %s\n",
3433 mntdir, strerror(-rc));
3437 printf("%s %s\n", buf, mntdir);
3439 path[0] = fsname[0] = mntdir[0] = 0;
3441 } else { /* paths specified, only attempt to search these. */
3442 for (; optind < argc; optind++) {
3443 rc = llapi_getname(argv[optind], buf, sizeof(buf));
3446 "cannot get name for `%s': %s\n",
3447 argv[optind], strerror(-rc));
3451 printf("%s %s\n", buf, argv[optind]);
3457 static int lfs_check(int argc, char **argv)
3460 char mntdir[PATH_MAX] = {'\0'};
3469 obd_types[0] = obd_type1;
3470 obd_types[1] = obd_type2;
3472 if (strcmp(argv[1], "osts") == 0) {
3473 strcpy(obd_types[0], "osc");
3474 } else if (strcmp(argv[1], "mds") == 0) {
3475 strcpy(obd_types[0], "mdc");
3476 } else if (strcmp(argv[1], "servers") == 0) {
3478 strcpy(obd_types[0], "osc");
3479 strcpy(obd_types[1], "mdc");
3481 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3486 rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3487 if (rc < 0 || mntdir[0] == '\0') {
3488 fprintf(stderr, "No suitable Lustre mount found\n");
3492 rc = llapi_target_check(num_types, obd_types, mntdir);
3494 fprintf(stderr, "error: %s: %s status failed\n",
3501 #ifdef HAVE_SYS_QUOTA_H
3502 #define ARG2INT(nr, str, msg) \
3505 nr = strtol(str, &endp, 0); \
3507 fprintf(stderr, "error: bad %s: %s\n", msg, str); \
3512 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3514 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3515 * returns the value or ULONG_MAX on integer overflow or incorrect format
3517 * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3518 * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3519 * 3. empty integer value is interpreted as 0
3521 static unsigned long str2sec(const char* timestr)
3523 const char spec[] = "smhdw";
3524 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3525 unsigned long val = 0;
3528 if (strpbrk(timestr, spec) == NULL) {
3529 /* no specifiers inside the time string,
3530 should treat it as an integer value */
3531 val = strtoul(timestr, &tail, 10);
3532 return *tail ? ULONG_MAX : val;
3535 /* format string is XXwXXdXXhXXmXXs */
3541 v = strtoul(timestr, &tail, 10);
3542 if (v == ULONG_MAX || *tail == '\0')
3543 /* value too large (ULONG_MAX or more)
3544 or missing specifier */
3547 ptr = strchr(spec, *tail);
3549 /* unknown specifier */
3554 /* check if product will overflow the type */
3555 if (!(v < ULONG_MAX / mult[ind]))
3558 ADD_OVERFLOW(val, mult[ind] * v);
3559 if (val == ULONG_MAX)
3571 #define ARG2ULL(nr, str, def_units) \
3573 unsigned long long limit, units = def_units; \
3576 rc = llapi_parse_size(str, &limit, &units, 1); \
3578 fprintf(stderr, "error: bad limit value %s\n", str); \
3584 static inline int has_times_option(int argc, char **argv)
3588 for (i = 1; i < argc; i++)
3589 if (!strcmp(argv[i], "-t"))
3595 int lfs_setquota_times(int argc, char **argv)
3598 struct if_quotactl qctl;
3599 char *mnt, *obd_type = (char *)qctl.obd_type;
3600 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3601 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3602 struct option long_opts[] = {
3603 { .val = 'b', .name = "block-grace", .has_arg = required_argument },
3604 { .val = 'g', .name = "group", .has_arg = no_argument },
3605 { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
3606 { .val = 'p', .name = "projid", .has_arg = no_argument },
3607 { .val = 't', .name = "times", .has_arg = no_argument },
3608 { .val = 'u', .name = "user", .has_arg = no_argument },
3612 memset(&qctl, 0, sizeof(qctl));
3613 qctl.qc_cmd = LUSTRE_Q_SETINFO;
3614 qctl.qc_type = ALLQUOTA;
3616 while ((c = getopt_long(argc, argv, "b:gi:ptu",
3617 long_opts, NULL)) != -1) {
3628 if (qctl.qc_type != ALLQUOTA) {
3629 fprintf(stderr, "error: -u/g/p can't be used "
3630 "more than once\n");
3633 qctl.qc_type = qtype;
3636 if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3637 fprintf(stderr, "error: bad block-grace: %s\n",
3641 dqb->dqb_valid |= QIF_BTIME;
3644 if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3645 fprintf(stderr, "error: bad inode-grace: %s\n",
3649 dqb->dqb_valid |= QIF_ITIME;
3651 case 't': /* Yes, of course! */
3653 default: /* getopt prints error message for us when opterr != 0 */
3658 if (qctl.qc_type == ALLQUOTA) {
3659 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3663 if (optind != argc - 1) {
3664 fprintf(stderr, "error: unexpected parameters encountered\n");
3669 rc = llapi_quotactl(mnt, &qctl);
3672 fprintf(stderr, "%s %s ", obd_type,
3673 obd_uuid2str(&qctl.obd_uuid));
3674 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3681 #define BSLIMIT (1 << 0)
3682 #define BHLIMIT (1 << 1)
3683 #define ISLIMIT (1 << 2)
3684 #define IHLIMIT (1 << 3)
3686 int lfs_setquota(int argc, char **argv)
3689 struct if_quotactl qctl;
3690 char *mnt, *obd_type = (char *)qctl.obd_type;
3691 struct obd_dqblk *dqb = &qctl.qc_dqblk;
3692 struct option long_opts[] = {
3693 { .val = 'b', .name = "block-softlimit",
3694 .has_arg = required_argument },
3695 { .val = 'B', .name = "block-hardlimit",
3696 .has_arg = required_argument },
3697 { .val = 'g', .name = "group", .has_arg = required_argument },
3698 { .val = 'i', .name = "inode-softlimit",
3699 .has_arg = required_argument },
3700 { .val = 'I', .name = "inode-hardlimit",
3701 .has_arg = required_argument },
3702 { .val = 'p', .name = "projid", .has_arg = required_argument },
3703 { .val = 'u', .name = "user", .has_arg = required_argument },
3705 unsigned limit_mask = 0;
3709 if (has_times_option(argc, argv))
3710 return lfs_setquota_times(argc, argv);
3712 memset(&qctl, 0, sizeof(qctl));
3713 qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
3714 qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3715 * so it can be used as a marker that qc_type
3716 * isn't reinitialized from command line */
3718 while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3719 long_opts, NULL)) != -1) {
3723 rc = name2uid(&qctl.qc_id, optarg);
3727 rc = name2gid(&qctl.qc_id, optarg);
3731 rc = name2projid(&qctl.qc_id, optarg);
3733 if (qctl.qc_type != ALLQUOTA) {
3734 fprintf(stderr, "error: -u and -g can't be used"
3735 " more than once\n");
3738 qctl.qc_type = qtype;
3740 qctl.qc_id = strtoul(optarg, &endptr, 10);
3741 if (*endptr != '\0') {
3742 fprintf(stderr, "error: can't find id "
3743 "for name %s\n", optarg);
3749 ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3750 dqb->dqb_bsoftlimit >>= 10;
3751 limit_mask |= BSLIMIT;
3752 if (dqb->dqb_bsoftlimit &&
3753 dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3754 fprintf(stderr, "warning: block softlimit is "
3755 "smaller than the miminal qunit size, "
3756 "please see the help of setquota or "
3757 "Lustre manual for details.\n");
3760 ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3761 dqb->dqb_bhardlimit >>= 10;
3762 limit_mask |= BHLIMIT;
3763 if (dqb->dqb_bhardlimit &&
3764 dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3765 fprintf(stderr, "warning: block hardlimit is "
3766 "smaller than the miminal qunit size, "
3767 "please see the help of setquota or "
3768 "Lustre manual for details.\n");
3771 ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3772 limit_mask |= ISLIMIT;
3773 if (dqb->dqb_isoftlimit &&
3774 dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3775 fprintf(stderr, "warning: inode softlimit is "
3776 "smaller than the miminal qunit size, "
3777 "please see the help of setquota or "
3778 "Lustre manual for details.\n");
3781 ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3782 limit_mask |= IHLIMIT;
3783 if (dqb->dqb_ihardlimit &&
3784 dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3785 fprintf(stderr, "warning: inode hardlimit is "
3786 "smaller than the miminal qunit size, "
3787 "please see the help of setquota or "
3788 "Lustre manual for details.\n");
3790 default: /* getopt prints error message for us when opterr != 0 */
3795 if (qctl.qc_type == ALLQUOTA) {
3796 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3800 if (limit_mask == 0) {
3801 fprintf(stderr, "error: at least one limit must be specified\n");
3805 if (optind != argc - 1) {
3806 fprintf(stderr, "error: unexpected parameters encountered\n");
3812 if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3813 (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3814 /* sigh, we can't just set blimits/ilimits */
3815 struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
3816 .qc_type = qctl.qc_type,
3817 .qc_id = qctl.qc_id};
3819 rc = llapi_quotactl(mnt, &tmp_qctl);
3821 fprintf(stderr, "error: setquota failed while retrieving"
3822 " current quota settings (%s)\n",
3827 if (!(limit_mask & BHLIMIT))
3828 dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3829 if (!(limit_mask & BSLIMIT))
3830 dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3831 if (!(limit_mask & IHLIMIT))
3832 dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3833 if (!(limit_mask & ISLIMIT))
3834 dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3836 /* Keep grace times if we have got no softlimit arguments */
3837 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3838 dqb->dqb_valid |= QIF_BTIME;
3839 dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3842 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3843 dqb->dqb_valid |= QIF_ITIME;
3844 dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3848 dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3849 dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3851 rc = llapi_quotactl(mnt, &qctl);
3854 fprintf(stderr, "%s %s ", obd_type,
3855 obd_uuid2str(&qctl.obd_uuid));
3856 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3863 /* Converts seconds value into format string
3864 * result is returned in buf
3866 * 1. result is in descenting order: 1w2d3h4m5s
3867 * 2. zero fields are not filled (except for p. 3): 5d1s
3868 * 3. zero seconds value is presented as "0s"
3870 static char * __sec2str(time_t seconds, char *buf)
3872 const char spec[] = "smhdw";
3873 const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3878 for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3879 c = seconds / mult[i];
3881 if (c > 0 || (i == 0 && buf == tail))
3882 tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3890 static void sec2str(time_t seconds, char *buf, int rc)
3897 tail = __sec2str(seconds, tail);
3899 if (rc && tail - buf < 39) {
3905 static void diff2str(time_t seconds, char *buf, time_t now)
3911 if (seconds <= now) {
3912 strcpy(buf, "none");
3915 __sec2str(seconds - now, buf);
3918 static void print_quota_title(char *name, struct if_quotactl *qctl,
3919 bool human_readable)
3921 printf("Disk quotas for %s %s (%cid %u):\n",
3922 qtype_name(qctl->qc_type), name,
3923 *qtype_name(qctl->qc_type), qctl->qc_id);
3924 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3925 "Filesystem", human_readable ? "used" : "kbytes",
3926 "quota", "limit", "grace",
3927 "files", "quota", "limit", "grace");
3930 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3933 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3936 snprintf(buf, buflen, "%5.4gP",
3937 (double)num / ((__u64)1 << 40));
3939 snprintf(buf, buflen, "%5.4gT",
3940 (double)num / (1 << 30));
3942 snprintf(buf, buflen, "%5.4gG",
3943 (double)num / (1 << 20));
3945 snprintf(buf, buflen, "%5.4gM",
3946 (double)num / (1 << 10));
3948 snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3952 #define STRBUF_LEN 32
3953 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3960 if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3961 int bover = 0, iover = 0;
3962 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3963 char numbuf[3][STRBUF_LEN];
3965 char strbuf[STRBUF_LEN];
3967 if (dqb->dqb_bhardlimit &&
3968 lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3970 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3971 if (dqb->dqb_btime > now) {
3978 if (dqb->dqb_ihardlimit &&
3979 dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3981 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3982 if (dqb->dqb_itime > now) {
3990 if (strlen(mnt) > 15)
3991 printf("%s\n%15s", mnt, "");
3993 printf("%15s", mnt);
3996 diff2str(dqb->dqb_btime, timebuf, now);
3998 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3999 strbuf, sizeof(strbuf), h);
4000 if (rc == -EREMOTEIO)
4001 sprintf(numbuf[0], "%s*", strbuf);
4003 sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
4004 "%s" : "[%s]", strbuf);
4006 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
4007 if (type == QC_GENERAL)
4008 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4009 "%s" : "[%s]", strbuf);
4011 sprintf(numbuf[1], "%s", "-");
4013 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4014 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4015 "%s" : "[%s]", strbuf);
4017 printf(" %7s%c %6s %7s %7s",
4018 numbuf[0], bover ? '*' : ' ', numbuf[1],
4019 numbuf[2], bover > 1 ? timebuf : "-");
4022 diff2str(dqb->dqb_itime, timebuf, now);
4024 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4025 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4027 if (type == QC_GENERAL)
4028 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4030 (uintmax_t)dqb->dqb_isoftlimit);
4032 sprintf(numbuf[1], "%s", "-");
4034 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4035 "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4037 if (type != QC_OSTIDX)
4038 printf(" %7s%c %6s %7s %7s",
4039 numbuf[0], iover ? '*' : ' ', numbuf[1],
4040 numbuf[2], iover > 1 ? timebuf : "-");
4042 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4045 } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4046 qctl->qc_cmd == Q_GETOINFO) {
4050 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4051 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4052 printf("Block grace time: %s; Inode grace time: %s\n",
4053 bgtimebuf, igtimebuf);
4057 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4058 bool h, __u64 *total)
4060 int rc = 0, rc1 = 0, count = 0;
4061 __u32 valid = qctl->qc_valid;
4063 rc = llapi_get_obd_count(mnt, &count, is_mdt);
4065 fprintf(stderr, "can not get %s count: %s\n",
4066 is_mdt ? "mdt": "ost", strerror(-rc));
4070 for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4071 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4072 rc = llapi_quotactl(mnt, qctl);
4074 /* It is remote client case. */
4075 if (rc == -EOPNOTSUPP) {
4082 fprintf(stderr, "quotactl %s%d failed.\n",
4083 is_mdt ? "mdt": "ost", qctl->qc_idx);
4087 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4088 qctl->qc_valid, 0, h);
4089 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4090 qctl->qc_dqblk.dqb_bhardlimit;
4093 qctl->qc_valid = valid;
4097 static int lfs_quota(int argc, char **argv)
4100 char *mnt, *name = NULL;
4101 struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4102 .qc_type = ALLQUOTA };
4103 char *obd_type = (char *)qctl.obd_type;
4104 char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4105 int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4106 verbose = 0, pass = 0, quiet = 0, inacc;
4108 __u32 valid = QC_GENERAL, idx = 0;
4109 __u64 total_ialloc = 0, total_balloc = 0;
4110 bool human_readable = false;
4113 while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4124 if (qctl.qc_type != ALLQUOTA) {
4125 fprintf(stderr, "error: use either -u or -g\n");
4128 qctl.qc_type = qtype;
4131 qctl.qc_cmd = LUSTRE_Q_GETINFO;
4134 valid = qctl.qc_valid = QC_UUID;
4135 strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4138 valid = qctl.qc_valid = QC_MDTIDX;
4139 idx = qctl.qc_idx = atoi(optarg);
4142 valid = qctl.qc_valid = QC_OSTIDX;
4143 idx = qctl.qc_idx = atoi(optarg);
4152 human_readable = true;
4155 fprintf(stderr, "error: %s: option '-%c' "
4156 "unrecognized\n", argv[0], c);
4161 /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4162 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4163 optind == argc - 1) {
4165 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4166 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4167 qctl.qc_valid = valid;
4169 qctl.qc_type = pass;
4170 switch (qctl.qc_type) {
4172 qctl.qc_id = geteuid();
4173 rc = uid2name(&name, qctl.qc_id);
4176 qctl.qc_id = getegid();
4177 rc = gid2name(&name, qctl.qc_id);
4186 /* lfs quota -u username /path/to/lustre/mount */
4187 } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4188 /* options should be followed by u/g-name and mntpoint */
4189 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4190 fprintf(stderr, "error: missing quota argument(s)\n");
4194 name = argv[optind++];
4195 switch (qctl.qc_type) {
4197 rc = name2uid(&qctl.qc_id, name);
4200 rc = name2gid(&qctl.qc_id, name);
4203 rc = name2projid(&qctl.qc_id, name);
4210 qctl.qc_id = strtoul(name, &endptr, 10);
4211 if (*endptr != '\0') {
4212 fprintf(stderr, "error: can't find id for name: %s\n",
4217 } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4218 fprintf(stderr, "error: missing quota info argument(s)\n");
4223 rc1 = llapi_quotactl(mnt, &qctl);
4227 fprintf(stderr, "%s quotas are not enabled.\n",
4228 qtype_name(qctl.qc_type));
4231 fprintf(stderr, "Permission denied.\n");
4234 /* We already got error message. */
4237 fprintf(stderr, "Unexpected quotactl error: %s\n",
4242 if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4243 print_quota_title(name, &qctl, human_readable);
4245 if (rc1 && *obd_type)
4246 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4248 if (qctl.qc_valid != QC_GENERAL)
4251 inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4252 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4253 (QIF_LIMITS|QIF_USAGE));
4255 print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4257 if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4259 char strbuf[STRBUF_LEN];
4261 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4263 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4265 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4267 printf("Total allocated inode limit: %ju, total "
4268 "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4272 if (rc1 || rc2 || rc3 || inacc)
4273 printf("Some errors happened when getting quota info. "
4274 "Some devices may be not working or deactivated. "
4275 "The data in \"[]\" is inaccurate.\n");
4278 if (pass > 0 && pass < LL_MAXQUOTAS)
4283 #endif /* HAVE_SYS_QUOTA_H! */
4285 static int flushctx_ioctl(char *mp)
4289 fd = open(mp, O_RDONLY);
4291 fprintf(stderr, "flushctx: error open %s: %s\n",
4292 mp, strerror(errno));
4296 rc = ioctl(fd, LL_IOC_FLUSHCTX);
4298 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4299 mp, strerror(errno));
4305 static int lfs_flushctx(int argc, char **argv)
4307 int kdestroy = 0, c;
4308 char mntdir[PATH_MAX] = {'\0'};
4312 while ((c = getopt(argc, argv, "k")) != -1) {
4318 fprintf(stderr, "error: %s: option '-%c' "
4319 "unrecognized\n", argv[0], c);
4325 if ((rc = system("kdestroy > /dev/null")) != 0) {
4326 rc = WEXITSTATUS(rc);
4327 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4331 if (optind >= argc) {
4332 /* flush for all mounted lustre fs. */
4333 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4334 /* Check if we have a mount point */
4335 if (mntdir[0] == '\0')
4338 if (flushctx_ioctl(mntdir))
4341 mntdir[0] = '\0'; /* avoid matching in next loop */
4344 /* flush fs as specified */
4345 while (optind < argc) {
4346 if (flushctx_ioctl(argv[optind++]))
4353 static int lfs_cp(int argc, char **argv)
4355 fprintf(stderr, "remote client copy file(s).\n"
4356 "obsolete, does not support it anymore.\n");
4360 static int lfs_ls(int argc, char **argv)
4362 fprintf(stderr, "remote client lists directory contents.\n"
4363 "obsolete, does not support it anymore.\n");
4367 static int lfs_changelog(int argc, char **argv)
4369 void *changelog_priv;
4370 struct changelog_rec *rec;
4371 long long startrec = 0, endrec = 0;
4373 struct option long_opts[] = {
4374 { .val = 'f', .name = "follow", .has_arg = no_argument },
4376 char short_opts[] = "f";
4379 while ((rc = getopt_long(argc, argv, short_opts,
4380 long_opts, NULL)) != -1) {
4388 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4389 argv[0], argv[optind - 1]);
4396 mdd = argv[optind++];
4398 startrec = strtoll(argv[optind++], NULL, 10);
4400 endrec = strtoll(argv[optind++], NULL, 10);
4402 rc = llapi_changelog_start(&changelog_priv,
4403 CHANGELOG_FLAG_BLOCK |
4404 CHANGELOG_FLAG_JOBID |
4405 (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4408 fprintf(stderr, "Can't start changelog: %s\n",
4409 strerror(errno = -rc));
4413 while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4417 if (endrec && rec->cr_index > endrec) {
4418 llapi_changelog_free(&rec);
4421 if (rec->cr_index < startrec) {
4422 llapi_changelog_free(&rec);
4426 secs = rec->cr_time >> 30;
4427 gmtime_r(&secs, &ts);
4428 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4429 "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4430 changelog_type2str(rec->cr_type),
4431 ts.tm_hour, ts.tm_min, ts.tm_sec,
4432 (int)(rec->cr_time & ((1 << 30) - 1)),
4433 ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4434 rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4436 if (rec->cr_flags & CLF_JOBID) {
4437 struct changelog_ext_jobid *jid =
4438 changelog_rec_jobid(rec);
4440 if (jid->cr_jobid[0] != '\0')
4441 printf(" j=%s", jid->cr_jobid);
4444 if (rec->cr_namelen)
4445 printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4446 rec->cr_namelen, changelog_rec_name(rec));
4448 if (rec->cr_flags & CLF_RENAME) {
4449 struct changelog_ext_rename *rnm =
4450 changelog_rec_rename(rec);
4452 if (!fid_is_zero(&rnm->cr_sfid))
4453 printf(" s="DFID" sp="DFID" %.*s",
4454 PFID(&rnm->cr_sfid),
4455 PFID(&rnm->cr_spfid),
4456 (int)changelog_rec_snamelen(rec),
4457 changelog_rec_sname(rec));
4461 llapi_changelog_free(&rec);
4464 llapi_changelog_fini(&changelog_priv);
4467 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4469 return (rc == 1 ? 0 : rc);
4472 static int lfs_changelog_clear(int argc, char **argv)
4480 endrec = strtoll(argv[3], NULL, 10);
4482 rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4485 fprintf(stderr, "%s: record out of range: %llu\n",
4487 else if (rc == -ENOENT)
4488 fprintf(stderr, "%s: no changelog user: %s\n",
4491 fprintf(stderr, "%s error: %s\n", argv[0],
4500 static int lfs_fid2path(int argc, char **argv)
4502 struct option long_opts[] = {
4503 { .val = 'c', .name = "cur", .has_arg = no_argument },
4504 { .val = 'l', .name = "link", .has_arg = required_argument },
4505 { .val = 'r', .name = "rec", .has_arg = required_argument },
4507 char short_opts[] = "cl:r:";
4508 char *device, *fid, *path;
4509 long long recno = -1;
4515 while ((rc = getopt_long(argc, argv, short_opts,
4516 long_opts, NULL)) != -1) {
4522 linkno = strtol(optarg, NULL, 10);
4525 recno = strtoll(optarg, NULL, 10);
4530 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4531 argv[0], argv[optind - 1]);
4539 device = argv[optind++];
4540 path = calloc(1, PATH_MAX);
4542 fprintf(stderr, "error: Not enough memory\n");
4547 while (optind < argc) {
4548 fid = argv[optind++];
4550 lnktmp = (linkno >= 0) ? linkno : 0;
4552 int oldtmp = lnktmp;
4553 long long rectmp = recno;
4555 rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4558 fprintf(stderr, "%s: error on FID %s: %s\n",
4559 argv[0], fid, strerror(errno = -rc2));
4566 fprintf(stdout, "%lld ", rectmp);
4567 if (device[0] == '/') {
4568 fprintf(stdout, "%s", device);
4569 if (device[strlen(device) - 1] != '/')
4570 fprintf(stdout, "/");
4571 } else if (path[0] == '\0') {
4572 fprintf(stdout, "/");
4574 fprintf(stdout, "%s\n", path);
4577 /* specified linkno */
4579 if (oldtmp == lnktmp)
4589 static int lfs_path2fid(int argc, char **argv)
4591 struct option long_opts[] = {
4592 { .val = 'p', .name = "parents", .has_arg = no_argument },
4595 const char short_opts[] = "p";
4596 const char *sep = "";
4599 bool show_parents = false;
4601 while ((rc = getopt_long(argc, argv, short_opts,
4602 long_opts, NULL)) != -1) {
4605 show_parents = true;
4608 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4609 argv[0], argv[optind - 1]);
4614 if (optind > argc - 1)
4616 else if (optind < argc - 1)
4620 for (path = argv + optind; *path != NULL; path++) {
4622 if (!show_parents) {
4623 err = llapi_path2fid(*path, &fid);
4625 printf("%s%s"DFID"\n",
4626 *sep != '\0' ? *path : "", sep,
4629 char name[NAME_MAX + 1];
4630 unsigned int linkno = 0;
4632 while ((err = llapi_path2parent(*path, linkno, &fid,
4633 name, sizeof(name))) == 0) {
4634 if (*sep != '\0' && linkno == 0)
4635 printf("%s%s", *path, sep);
4637 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4642 /* err == -ENODATA is end-of-loop */
4643 if (linkno > 0 && err == -ENODATA) {
4650 fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4651 argv[0], show_parents ? "parent " : "", *path,
4663 static int lfs_data_version(int argc, char **argv)
4670 int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4675 while ((c = getopt(argc, argv, "nrw")) != -1) {
4678 data_version_flags = 0;
4681 data_version_flags |= LL_DV_RD_FLUSH;
4684 data_version_flags |= LL_DV_WR_FLUSH;
4693 path = argv[optind];
4694 fd = open(path, O_RDONLY);
4696 err(errno, "cannot open file %s", path);
4698 rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4700 err(errno, "cannot get version for %s", path);
4702 printf("%ju" "\n", (uintmax_t)data_version);
4708 static int lfs_hsm_state(int argc, char **argv)
4713 struct hsm_user_state hus;
4721 rc = llapi_hsm_state_get(path, &hus);
4723 fprintf(stderr, "can't get hsm state for %s: %s\n",
4724 path, strerror(errno = -rc));
4728 /* Display path name and status flags */
4729 printf("%s: (0x%08x)", path, hus.hus_states);
4731 if (hus.hus_states & HS_RELEASED)
4732 printf(" released");
4733 if (hus.hus_states & HS_EXISTS)
4735 if (hus.hus_states & HS_DIRTY)
4737 if (hus.hus_states & HS_ARCHIVED)
4738 printf(" archived");
4739 /* Display user-settable flags */
4740 if (hus.hus_states & HS_NORELEASE)
4741 printf(" never_release");
4742 if (hus.hus_states & HS_NOARCHIVE)
4743 printf(" never_archive");
4744 if (hus.hus_states & HS_LOST)
4745 printf(" lost_from_hsm");
4747 if (hus.hus_archive_id != 0)
4748 printf(", archive_id:%d", hus.hus_archive_id);
4751 } while (++i < argc);
4756 #define LFS_HSM_SET 0
4757 #define LFS_HSM_CLEAR 1
4760 * Generic function to set or clear HSM flags.
4761 * Used by hsm_set and hsm_clear.
4763 * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4765 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4767 struct option long_opts[] = {
4768 { .val = 'A', .name = "archived", .has_arg = no_argument },
4769 { .val = 'a', .name = "noarchive", .has_arg = no_argument },
4770 { .val = 'd', .name = "dirty", .has_arg = no_argument },
4771 { .val = 'e', .name = "exists", .has_arg = no_argument },
4772 { .val = 'l', .name = "lost", .has_arg = no_argument },
4773 { .val = 'r', .name = "norelease", .has_arg = no_argument },
4775 char short_opts[] = "lraAde";
4783 while ((c = getopt_long(argc, argv, short_opts,
4784 long_opts, NULL)) != -1) {
4790 mask |= HS_NOARCHIVE;
4793 mask |= HS_ARCHIVED;
4796 mask |= HS_NORELEASE;
4807 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4808 argv[0], argv[optind - 1]);
4813 /* User should have specified a flag */
4817 while (optind < argc) {
4819 path = argv[optind];
4821 /* If mode == 0, this means we apply the mask. */
4822 if (mode == LFS_HSM_SET)
4823 rc = llapi_hsm_state_set(path, mask, 0, 0);
4825 rc = llapi_hsm_state_set(path, 0, mask, 0);
4828 fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4829 path, strerror(errno = -rc));
4838 static int lfs_hsm_action(int argc, char **argv)
4843 struct hsm_current_action hca;
4844 struct hsm_extent he;
4845 enum hsm_user_action hua;
4846 enum hsm_progress_states hps;
4854 rc = llapi_hsm_current_action(path, &hca);
4856 fprintf(stderr, "can't get hsm action for %s: %s\n",
4857 path, strerror(errno = -rc));
4860 he = hca.hca_location;
4861 hua = hca.hca_action;
4862 hps = hca.hca_state;
4864 printf("%s: %s", path, hsm_user_action2name(hua));
4866 /* Skip file without action */
4867 if (hca.hca_action == HUA_NONE) {
4872 printf(" %s ", hsm_progress_state2name(hps));
4874 if ((hps == HPS_RUNNING) &&
4875 (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4876 printf("(%llu bytes moved)\n",
4877 (unsigned long long)he.length);
4878 else if ((he.offset + he.length) == LUSTRE_EOF)
4879 printf("(from %llu to EOF)\n",
4880 (unsigned long long)he.offset);
4882 printf("(from %llu to %llu)\n",
4883 (unsigned long long)he.offset,
4884 (unsigned long long)(he.offset + he.length));
4886 } while (++i < argc);
4891 static int lfs_hsm_set(int argc, char **argv)
4893 return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4896 static int lfs_hsm_clear(int argc, char **argv)
4898 return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4902 * Check file state and return its fid, to be used by lfs_hsm_request().
4904 * \param[in] file Path to file to check
4905 * \param[in,out] fid Pointer to allocated lu_fid struct.
4906 * \param[in,out] last_dev Pointer to last device id used.
4908 * \return 0 on success.
4910 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4916 rc = lstat(file, &st);
4918 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4921 /* Checking for regular file as archiving as posix copytool
4922 * rejects archiving files other than regular files
4924 if (!S_ISREG(st.st_mode)) {
4925 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4928 /* A request should be ... */
4929 if (*last_dev != st.st_dev && *last_dev != 0) {
4930 fprintf(stderr, "All files should be "
4931 "on the same filesystem: %s\n", file);
4934 *last_dev = st.st_dev;
4936 rc = llapi_path2fid(file, fid);
4938 fprintf(stderr, "Cannot read FID of %s: %s\n",
4939 file, strerror(-rc));
4945 /* Fill an HSM HUR item with a given file name.
4947 * If mntpath is set, then the filename is actually a FID, and no
4948 * lookup on the filesystem will be performed.
4950 * \param[in] hur the user request to fill
4951 * \param[in] idx index of the item inside the HUR to fill
4952 * \param[in] mntpath mountpoint of Lustre
4953 * \param[in] fname filename (if mtnpath is NULL)
4954 * or FID (if mntpath is set)
4955 * \param[in] last_dev pointer to last device id used
4957 * \retval 0 on success
4958 * \retval CMD_HELP or a negative errno on error
4960 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4961 const char *mntpath, const char *fname,
4964 struct hsm_user_item *hui = &hur->hur_user_item[idx];
4967 hui->hui_extent.length = -1;
4969 if (mntpath != NULL) {
4972 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4976 fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4981 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4985 hur->hur_request.hr_itemcount++;
4990 static int lfs_hsm_request(int argc, char **argv, int action)
4992 struct option long_opts[] = {
4993 { .val = 'a', .name = "archive", .has_arg = required_argument },
4994 { .val = 'D', .name = "data", .has_arg = required_argument },
4995 { .val = 'l', .name = "filelist", .has_arg = required_argument },
4996 { .val = 'm', .name = "mntpath", .has_arg = required_argument },
4999 char short_opts[] = "l:D:a:m:";
5000 struct hsm_user_request *hur, *oldhur;
5005 char *filelist = NULL;
5006 char fullpath[PATH_MAX];
5007 char *opaque = NULL;
5011 int nbfile_alloc = 0;
5012 char *some_file = NULL;
5013 char *mntpath = NULL;
5019 while ((c = getopt_long(argc, argv, short_opts,
5020 long_opts, NULL)) != -1) {
5029 if (action != HUA_ARCHIVE &&
5030 action != HUA_REMOVE) {
5032 "error: -a is supported only "
5033 "when archiving or removing\n");
5036 archive_id = atoi(optarg);
5039 if (some_file == NULL) {
5041 some_file = strdup(optarg);
5047 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5048 argv[0], argv[optind - 1]);
5053 /* All remaining args are files, so we have at least nbfile */
5054 nbfile = argc - optind;
5056 if ((nbfile == 0) && (filelist == NULL))
5060 opaque_len = strlen(opaque);
5062 /* Alloc the request structure with enough place to store all files
5063 * from command line. */
5064 hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5066 fprintf(stderr, "Cannot create the request: %s\n",
5070 nbfile_alloc = nbfile;
5072 hur->hur_request.hr_action = action;
5073 hur->hur_request.hr_archive_id = archive_id;
5074 hur->hur_request.hr_flags = 0;
5076 /* All remaining args are files, add them */
5077 if (nbfile != 0 && some_file == NULL)
5078 some_file = strdup(argv[optind]);
5080 for (i = 0; i < nbfile; i++) {
5081 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5087 /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5089 /* If a filelist was specified, read the filelist from it. */
5090 if (filelist != NULL) {
5091 fp = fopen(filelist, "r");
5093 fprintf(stderr, "Cannot read the file list %s: %s\n",
5094 filelist, strerror(errno));
5099 while ((rc = getline(&line, &len, fp)) != -1) {
5100 /* If allocated buffer was too small, get something
5102 if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5105 nbfile_alloc = nbfile_alloc * 2 + 1;
5107 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5110 fprintf(stderr, "hsm: cannot allocate "
5111 "the request: %s\n",
5118 size = hur_len(oldhur);
5120 fprintf(stderr, "hsm: cannot allocate "
5121 "%u files + %u bytes data\n",
5122 oldhur->hur_request.hr_itemcount,
5123 oldhur->hur_request.hr_data_len);
5130 memcpy(hur, oldhur, size);
5135 if (line[strlen(line) - 1] == '\n')
5136 line[strlen(line) - 1] = '\0';
5138 rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5139 mntpath, line, &last_dev);
5145 if (some_file == NULL) {
5155 /* If a --data was used, add it to the request */
5156 hur->hur_request.hr_data_len = opaque_len;
5158 memcpy(hur_data(hur), opaque, opaque_len);
5160 /* Send the HSM request */
5161 if (realpath(some_file, fullpath) == NULL) {
5162 fprintf(stderr, "Could not find path '%s': %s\n",
5163 some_file, strerror(errno));
5165 rc = llapi_hsm_request(fullpath, hur);
5167 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5168 some_file, strerror(-rc));
5178 static int lfs_hsm_archive(int argc, char **argv)
5180 return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5183 static int lfs_hsm_restore(int argc, char **argv)
5185 return lfs_hsm_request(argc, argv, HUA_RESTORE);
5188 static int lfs_hsm_release(int argc, char **argv)
5190 return lfs_hsm_request(argc, argv, HUA_RELEASE);
5193 static int lfs_hsm_remove(int argc, char **argv)
5195 return lfs_hsm_request(argc, argv, HUA_REMOVE);
5198 static int lfs_hsm_cancel(int argc, char **argv)
5200 return lfs_hsm_request(argc, argv, HUA_CANCEL);
5203 static int lfs_swap_layouts(int argc, char **argv)
5208 return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5209 SWAP_LAYOUTS_KEEP_MTIME |
5210 SWAP_LAYOUTS_KEEP_ATIME);
5213 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5215 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5217 enum lu_ladvise_type advice;
5220 advice < ARRAY_SIZE(ladvise_names); advice++) {
5221 if (ladvise_names[advice] == NULL)
5223 if (strcmp(string, ladvise_names[advice]) == 0)
5227 return LU_LADVISE_INVALID;
5230 static int lfs_ladvise(int argc, char **argv)
5232 struct option long_opts[] = {
5233 { .val = 'a', .name = "advice", .has_arg = required_argument },
5234 { .val = 'b', .name = "background", .has_arg = no_argument },
5235 { .val = 'e', .name = "end", .has_arg = required_argument },
5236 { .val = 'l', .name = "length", .has_arg = required_argument },
5237 { .val = 's', .name = "start", .has_arg = required_argument },
5239 char short_opts[] = "a:be:l:s:";
5244 struct llapi_lu_ladvise advice;
5245 enum lu_ladvise_type advice_type = LU_LADVISE_INVALID;
5246 unsigned long long start = 0;
5247 unsigned long long end = LUSTRE_EOF;
5248 unsigned long long length = 0;
5249 unsigned long long size_units;
5250 unsigned long long flags = 0;
5253 while ((c = getopt_long(argc, argv, short_opts,
5254 long_opts, NULL)) != -1) {
5257 advice_type = lfs_get_ladvice(optarg);
5258 if (advice_type == LU_LADVISE_INVALID) {
5259 fprintf(stderr, "%s: invalid advice type "
5260 "'%s'\n", argv[0], optarg);
5261 fprintf(stderr, "Valid types:");
5263 for (advice_type = 0;
5264 advice_type < ARRAY_SIZE(ladvise_names);
5266 if (ladvise_names[advice_type] == NULL)
5268 fprintf(stderr, " %s",
5269 ladvise_names[advice_type]);
5271 fprintf(stderr, "\n");
5281 rc = llapi_parse_size(optarg, &end,
5284 fprintf(stderr, "%s: bad end offset '%s'\n",
5291 rc = llapi_parse_size(optarg, &start,
5294 fprintf(stderr, "%s: bad start offset "
5295 "'%s'\n", argv[0], optarg);
5301 rc = llapi_parse_size(optarg, &length,
5304 fprintf(stderr, "%s: bad length '%s'\n",
5312 fprintf(stderr, "%s: option '%s' unrecognized\n",
5313 argv[0], argv[optind - 1]);
5318 if (advice_type == LU_LADVISE_INVALID) {
5319 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5320 fprintf(stderr, "Valid types:");
5321 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5323 if (ladvise_names[advice_type] == NULL)
5325 fprintf(stderr, " %s", ladvise_names[advice_type]);
5327 fprintf(stderr, "\n");
5331 if (argc <= optind) {
5332 fprintf(stderr, "%s: please give one or more file names\n",
5337 if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5338 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5343 if (end == LUSTRE_EOF && length != 0)
5344 end = start + length;
5347 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5348 argv[0], start, end);
5352 while (optind < argc) {
5355 path = argv[optind++];
5357 fd = open(path, O_RDONLY);
5359 fprintf(stderr, "%s: cannot open file '%s': %s\n",
5360 argv[0], path, strerror(errno));
5365 advice.lla_start = start;
5366 advice.lla_end = end;
5367 advice.lla_advice = advice_type;
5368 advice.lla_value1 = 0;
5369 advice.lla_value2 = 0;
5370 advice.lla_value3 = 0;
5371 advice.lla_value4 = 0;
5372 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5375 fprintf(stderr, "%s: cannot give advice '%s' to file "
5376 "'%s': %s\n", argv[0],
5377 ladvise_names[advice_type],
5378 path, strerror(errno));
5381 if (rc == 0 && rc2 < 0)
5387 static int lfs_list_commands(int argc, char **argv)
5389 char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5391 Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5396 int main(int argc, char **argv)
5400 /* Ensure that liblustreapi constructor has run */
5401 if (!llapi_liblustreapi_initialized())
5402 fprintf(stderr, "liblustreapi was not properly initialized\n");
5406 Parser_init("lfs > ", cmdlist);
5408 progname = argv[0]; /* Used in error messages */
5410 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5412 rc = Parser_commands();
5415 return rc < 0 ? -rc : rc;
5418 #ifdef _LUSTRE_IDL_H_
5419 /* Everything we need here should be included by lustreapi.h. */
5420 # error "lfs should not depend on lustre_idl.h"
5421 #endif /* _LUSTRE_IDL_H_ */